Fixed unity terrain generation bug.

This commit is contained in:
Tiberiu Chibici 2015-03-19 12:34:58 +02:00
parent 8f9f935796
commit 68140b11a7
40 changed files with 326 additions and 245 deletions

6
.gitignore vendored
View File

@ -1,5 +1,7 @@
## Ignore Visual Studio temporary files, build results, and # Logs
## files generated by popular Visual Studio add-ons. Game/Logs/
Game/[Oo]bj/
Game/[Tt]emp/
# User-specific files # User-specific files
*.suo *.suo

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<biome> <biome>
<name>Grassland</name> <name>Grassland</name>
<heightRange min="0" max="10" /> <height>100</height>
<moisture min=".1" max=".5"/> <moisture min=".1" max=".5"/>
<vegetationDensity min=".2" max=".5" /> <vegetationDensity min=".2" max=".5" />
</biome> </biome>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<biome> <biome>
<name>Mountain</name> <name>Mountain</name>
<heightRange min="0" max="500" /> <height>500</height>
<moisture min=".1" max=".3"/> <moisture min=".1" max=".3"/>
<vegetationDensity min=".5" max=".9" /> <vegetationDensity min=".5" max=".9" />
</biome> </biome>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<terrgenConfig> <terrgenConfig>
<noiseOctaves>8</noiseOctaves> <noiseOctaves>9</noiseOctaves>
<noiseNonLinearPower>2</noiseNonLinearPower> <noiseNonLinearPower>2.4</noiseNonLinearPower>
<waterNonLinearPower>1.3</waterNonLinearPower> <waterNonLinearPower>1.9</waterNonLinearPower>
<elevationScale>0.01</elevationScale> <elevationScale>0.0005</elevationScale>
</terrgenConfig> </terrgenConfig>

Binary file not shown.

View File

@ -45,10 +45,14 @@ namespace TransportGame.Generator
// Generate water level // Generate water level
float waterAmount = random.NextSingle(map.Biome.Moisture.Minimum, map.Biome.Moisture.Maximum); float waterAmount = random.NextSingle(map.Biome.Moisture.Minimum, map.Biome.Moisture.Maximum);
map.WaterLevel = Mathf.Pow(waterAmount, ConfigurationManager.TerrGenConfig.WaterNonLinearPower) map.WaterLevel = Mathf.Pow(waterAmount, ConfigurationManager.TerrGenConfig.WaterNonLinearPower) * map.Biome.Height;
* (map.Biome.HeightRange.Maximum - map.Biome.HeightRange.Minimum) + map.Biome.HeightRange.Minimum;
DumpData(map, "1generated.map");
// Simulate water erosion
//Erode(map);
//DumpData(map, "2eroded.map");
DumpData(map);
return map; return map;
} }
@ -64,14 +68,21 @@ namespace TransportGame.Generator
{ {
for (int x = 0; x < map.Width; ++x) for (int x = 0; x < map.Width; ++x)
for (int y = 0; y < map.Height; ++y) for (int y = 0; y < map.Height; ++y)
map[x, y] = Noise.Generate(x, y, map.Biome.HeightRange.Minimum, map.Biome.HeightRange.Maximum); map[x, y] = Noise.Generate(x, y, 0, 1);
} }
private void DumpData(Map map) //private void Erode(Map map)
//{
// float[,] water = new float[map.Width, map.Height];
//}
private void DumpData(Map map, string filename)
{ {
XmlSerializer serializer = new XmlSerializer(typeof(Map)); XmlSerializer serializer = new XmlSerializer(typeof(Map));
using (StreamWriter writer = new StreamWriter(Path.Combine(Logger.LogsDirectory, "mapdump.map"))) using (StreamWriter writer = new StreamWriter(Path.Combine(Logger.LogsDirectory, filename)))
{ {
serializer.Serialize(writer, map); serializer.Serialize(writer, map);
writer.Close(); writer.Close();

View File

@ -1,44 +1,44 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Xml.Serialization; using System.Xml.Serialization;
using TransportGame.Utils; using TransportGame.Utils;
namespace TransportGame.Model namespace TransportGame.Model
{ {
[XmlRoot("biome")] [XmlRoot("biome")]
public class Biome public class Biome
{ {
/// <summary> /// <summary>
/// Gets or sets the name of the biome /// Gets or sets the name of the biome
/// </summary> /// </summary>
[XmlElement("name")] [XmlElement("name")]
public string Name { get; set; } public string Name { get; set; }
/// <summary> /// <summary>
/// Gets or sets the height range of the biome. /// Gets or sets the maximum height of the biome.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// 1 unit = 100 meters. /// 1 unit = 100 meters.
/// </remarks> /// </remarks>
[XmlElement("heightRange")] [XmlElement("height")]
public Range HeightRange { get; set; } public float Height { get; set; }
/// <summary> /// <summary>
/// Gets or sets the moisture range. /// Gets or sets the moisture range.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Moisture is the amount of water on a map. /// Moisture is the amount of water on a map.
/// Value is a probability, should be between 0 and 1. /// Value is a probability, should be between 0 and 1.
/// </remarks> /// </remarks>
[XmlElement("moisture")] [XmlElement("moisture")]
public Range Moisture { get; set; } public Range Moisture { get; set; }
/// <summary> /// <summary>
/// Gets or sets the vegetation density of the biome /// Gets or sets the vegetation density of the biome
/// </summary> /// </summary>
[XmlElement("vegetationDensity")] [XmlElement("vegetationDensity")]
public Range VegetationDensity { get; set; } public Range VegetationDensity { get; set; }
} }
} }

View File

@ -140,7 +140,7 @@ namespace TransportGame.Model
/// <returns></returns> /// <returns></returns>
public bool IsWater(int x, int y) public bool IsWater(int x, int y)
{ {
return grid[x, y] <= WaterLevel; return grid[x, y] * Biome.Height <= WaterLevel;
} }
} }
} }

View File

@ -1,87 +1,87 @@
using UnityEngine; using UnityEngine;
using System.Collections; using System.Collections;
using TransportGame.Utils; using TransportGame.Utils;
using System.Threading; using System.Threading;
using TransportGame.Generator; using TransportGame.Generator;
using TransportGame.Model; using TransportGame.Model;
using TransportGame.Business; using TransportGame.Business;
public class TerrainGeneratorScript : MonoBehaviour public class TerrainGeneratorScript : MonoBehaviour
{ {
private Map map = null; private Map map = null;
public int TerrainWidth = 256; public int TerrainWidth = 256;
public int TerrainHeight = 256; public int TerrainHeight = 256;
public GameObject WaterObject; public GameObject WaterObject;
// Use this for initialization // Use this for initialization
void Start() void Start()
{ {
StartCoroutine(GenerateMap()); StartCoroutine(GenerateMap());
} }
private void GenerateMapThread() private void GenerateMapThread()
{ {
TerrainGenerator generator = new TerrainGenerator(); TerrainGenerator generator = new TerrainGenerator();
map = generator.Generate(TerrainWidth, TerrainHeight); map = generator.Generate(TerrainWidth, TerrainHeight);
} }
private Mesh GenerateWater() private Mesh GenerateWater()
{ {
Mesh water = new Mesh(); Mesh water = new Mesh();
water.name = "water"; water.name = "water";
water.vertices = new[] { water.vertices = new[] {
new Vector3(0, map.WaterLevel, 0), new Vector3(0, map.WaterLevel, 0),
new Vector3(0, map.WaterLevel, map.Height), new Vector3(0, map.WaterLevel, map.Height),
new Vector3(map.Width, map.WaterLevel, 0), new Vector3(map.Width, map.WaterLevel, 0),
new Vector3(map.Width, map.WaterLevel, map.Height) new Vector3(map.Width, map.WaterLevel, map.Height)
}; };
water.triangles = new[] { 0, 1, 2, 2, 1, 3 }; water.triangles = new[] { 0, 1, 2, 2, 1, 3 };
water.uv = new[] { water.uv = new[] {
new Vector2(0, 0), new Vector2(0, 0),
new Vector2(0, 1), new Vector2(0, 1),
new Vector2(1, 0), new Vector2(1, 0),
new Vector2(1, 1) new Vector2(1, 1)
}; };
water.RecalculateNormals(); water.RecalculateNormals();
return water; return water;
} }
private IEnumerator GenerateMap() private IEnumerator GenerateMap()
{ {
// Wait for the map generation thread // Wait for the map generation thread
foreach (var i in Task.RunAsync(GenerateMapThread)) foreach (var i in Task.RunAsync(GenerateMapThread))
yield return i; yield return i;
// Generate terrain data // Generate terrain data
TerrainData terrainData = new TerrainData(); TerrainData terrainData = new TerrainData();
terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width); terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width) + 1;
terrainData.size = new Vector3(map.Width, map.Biome.HeightRange.Maximum, map.Height); terrainData.size = new Vector3(map.Width, map.Biome.Height, map.Height);
terrainData.SetDetailResolution(1024, 8); terrainData.SetDetailResolution(1024, 8);
terrainData.SetHeights(0, 0, map.Heights); terrainData.SetHeights(0, 0, map.Heights);
terrainData.name = "Generated Terrain Data"; terrainData.name = "Generated Terrain Data";
yield return null; yield return null;
// Create terrain object // Create terrain object
GameObject terrain = Terrain.CreateTerrainGameObject(terrainData); GameObject terrain = Terrain.CreateTerrainGameObject(terrainData);
terrain.name = "Generated Terrain"; terrain.name = "Generated Terrain";
yield return null; yield return null;
Terrain terrainComp = terrain.GetComponent<Terrain>(); Terrain terrainComp = terrain.GetComponent<Terrain>();
terrainComp.heightmapPixelError = 1; terrainComp.heightmapPixelError = 1;
yield return null; yield return null;
// Set water // Set water
if (WaterObject != null) if (WaterObject != null)
{ {
MeshFilter waterMesh = WaterObject.GetComponent<MeshFilter>(); MeshFilter waterMesh = WaterObject.GetComponent<MeshFilter>();
waterMesh.mesh = GenerateWater(); waterMesh.mesh = GenerateWater();
} }
} }
// Update is called once per frame // Update is called once per frame
void Update() void Update()
{ {
} }
} }

View File

@ -23,7 +23,7 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = Assembly-CSharp.csproj StartupItem = Assembly-CSharp.csproj
Policies = $0 Policies = $0
$0.TextStylePolicy = $1 $0.TextStylePolicy = $1

View File

@ -29,7 +29,7 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = Assembly-CSharp.csproj StartupItem = Assembly-CSharp.csproj
Policies = $0 Policies = $0
$0.TextStylePolicy = $1 $0.TextStylePolicy = $1

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +1,3 @@
Base path: E:/SDKs/Unity/Editor/Data Base path: E:/SDKs/Unity/Editor/Data
Pipe name: \\.\pipe\UnityShaderCompiler-32bit-1-3856 Pipe name: \\.\pipe\UnityShaderCompiler-32bit-1-4308
Cmd: getPlatforms Cmd: getPlatforms
Unhandled exception: Readfile from pipe failed. GLE=The pipe has been ended.
Quitting shader compiler process
Crashed!

View File

@ -1,3 +1,7 @@
Base path: E:/SDKs/Unity/Editor/Data Base path: E:/SDKs/Unity/Editor/Data
Pipe name: \\.\pipe\UnityShaderCompiler-64bit-1-3856 Pipe name: \\.\pipe\UnityShaderCompiler-64bit-1-4308
Cmd: getPlatforms Cmd: getPlatforms
Cmd: compileSnippet
api=4 type=0 insize=14871 outsize=3492 kw=DIRECTIONAL SHADOWS_OFF LIGHTMAP_OFF DIRLIGHTMAP_OFF DYNAMICLIGHTMAP_OFF ok=1
Cmd: compileSnippet
api=4 type=1 insize=14871 outsize=10090 kw=DIRECTIONAL SHADOWS_OFF LIGHTMAP_OFF DIRLIGHTMAP_OFF DYNAMICLIGHTMAP_OFF ok=1

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,13 +1,13 @@
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\Assembly-CSharp.dll E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\Assembly-CSharp.dll
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\Assembly-CSharp.pdb E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\Assembly-CSharp.pdb
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEditor.dll E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEditor.dll
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEngine.dll E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEngine.dll
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEngine.UI.dll E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEngine.UI.dll
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEditor.xml E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEditor.xml
E:\Facultate\$ Licenta\Game\obj\Debug\UnityVS.Game.CSharp.csprojResolveAssemblyReference.cache E:\Facultate\$ Licenta\Game\obj\Debug\UnityVS.Game.CSharp.csprojResolveAssemblyReference.cache
E:\Facultate\$ Licenta\Game\obj\Debug\Assembly-CSharp.dll E:\Facultate\$ Licenta\Game\obj\Debug\Assembly-CSharp.dll
E:\Facultate\$ Licenta\Game\obj\Debug\Assembly-CSharp.pdb E:\Facultate\$ Licenta\Game\obj\Debug\Assembly-CSharp.pdb
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEngine.xml E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEngine.xml
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEngine.UI.xml E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\UnityEngine.UI.xml
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\Assembly-CSharp-firstpass.pdb E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\Assembly-CSharp-firstpass.pdb
E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\Assembly-UnityScript-firstpass.dll E:\Facultate\$ Licenta\Game\Temp\UnityVS_bin\Debug\Assembly-UnityScript-firstpass.dll

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using TransportGame.MapViewer.Model;
namespace TransportGame.MapViewer.Business
{
public static class BitmapExtensions
{
/// <summary>
/// Gets a wpf bitmap source from a bitmap.
/// </summary>
/// <param name="this">The bitmap</param>
/// <returns>The bitmap source</returns>
public static BitmapSource ToBitmapSource(this Bitmap24 @this)
{
return BitmapSource.Create(@this.Width, @this.Height,
96, 96, PixelFormats.Rgb24, null, @this.Raw, @this.Width * 3);
}
}
}

View File

@ -1,11 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using TransportGame.MapViewer.Model;
using TransportGame.Model; using TransportGame.Model;
namespace TransportGame.MapViewer namespace TransportGame.MapViewer
@ -23,8 +18,8 @@ namespace TransportGame.MapViewer
/// <summary> /// <summary>
/// Gets or sets the scale /// Gets or sets the scale
/// </summary> /// </summary>
private int _scale; private float _scale;
public int Scale public float Scale
{ {
get get
{ {
@ -45,7 +40,7 @@ namespace TransportGame.MapViewer
public MapRenderer() public MapRenderer()
{ {
Scale = 4; Scale = 1;
} }
///<summary> ///<summary>
@ -54,72 +49,46 @@ namespace TransportGame.MapViewer
///<param name="file"></param> ///<param name="file"></param>
///<param name="map"></param> ///<param name="map"></param>
///<param name="layers"></param> ///<param name="layers"></param>
public Color[,] Render(Map map, Layers layers = Layers.All) public Bitmap24 Render(Map map, Layers layers = Layers.All)
{ {
lock (this) lock (this)
{ {
// Create texture on which to draw // Create texture on which to draw
Color[,] pixels = new Color[map.Width * Scale, map.Height * Scale]; Bitmap24 bitmap = new Bitmap24(Convert.ToInt32(map.Width * Scale), Convert.ToInt32(map.Height * Scale));
// First layer - cells // First layer - cells
DrawCells(pixels, map, (layers & Layers.Elevation) > 0); DrawCells(bitmap, map, (layers & Layers.Elevation) > 0);
// Done // Done
return pixels; return bitmap;
} }
} }
private void DrawCells(Color[,] pixels, Map map, bool elevation) private void DrawCells(Bitmap24 bitmap, Map map, bool elevation)
{ {
for (int x = 0; x < pixels.GetLength(0); x++) for (int x = 0; x < bitmap.Width; x++)
for (int y = 0; y < pixels.GetLength(1); y++) for (int y = 0; y < bitmap.Height; y++)
{ {
int mapX = x / Scale; int mapX = Convert.ToInt32(x / Scale);
int mapY = y / Scale; int mapY = Convert.ToInt32(y / Scale);
// Draw water // Draw water
if (map.IsWater(mapX, mapY)) if (map.IsWater(mapX, mapY))
pixels[x, y] = WaterColor; bitmap[x, y] = WaterColor;
// Draw elevation // Draw elevation
else if (elevation) else if (elevation)
{ {
float alpha = (map[mapX, mapY] - map.Biome.HeightRange.Minimum) / (map.Biome.HeightRange.Maximum - map.Biome.HeightRange.Minimum); float alpha = map[mapX, mapY]; // map height range is [0,1]
pixels[x, y] = Color.Multiply(ElevationTerrainColor, alpha); bitmap[x, y] = Color.Multiply(ElevationTerrainColor, alpha);
} }
// Draw terrain // Draw terrain
else else
{ {
pixels[x, y] = TerrainColor; bitmap[x, y] = TerrainColor;
} }
} }
} }
public async Task<BitmapSource> RenderToImageSource(Map map, Layers layers = Layers.All)
{
var colors = await Task.Run(() => Render(map, layers));
colors[0, 0] = Colors.Red;
colors[colors.GetLength(0) - 1, 0] = Colors.Red;
// Convert to raw pixels
byte[] raw = new byte[colors.GetLength(0) * colors.GetLength(1) * 3];
for (int x = 0; x < colors.GetLength(0); x++)
for (int y = 0; y < colors.GetLength(1); y++)
{
int pixelIndex = x + y * colors.GetLength(0);
raw[3 * pixelIndex] = colors[x, y].R;
raw[3 * pixelIndex + 1] = colors[x, y].G;
raw[3 * pixelIndex + 2] = colors[x, y].B;
}
// Create bitmap source
BitmapSource bmp = BitmapSource.Create(colors.GetLength(0), colors.GetLength(1),
96, 96, PixelFormats.Rgb24, null, raw, colors.GetLength(0) * 3);
return bmp;
}
} }
} }

View File

@ -21,6 +21,7 @@
<Button Name="buttonSave" ToolTip="Saves as image" Click="buttonSave_Click"> <Button Name="buttonSave" ToolTip="Saves as image" Click="buttonSave_Click">
<Image Source="pack://application:,,,/Resources/picture_save.png" /> <Image Source="pack://application:,,,/Resources/picture_save.png" />
</Button> </Button>
<Separator /> <Separator />
<Button Name="buttonZoomIn" ToolTip="Zoom in" Click="buttonZoomIn_Click"> <Button Name="buttonZoomIn" ToolTip="Zoom in" Click="buttonZoomIn_Click">
@ -31,7 +32,7 @@
</Button> </Button>
<TextBlock VerticalAlignment="Center"> <TextBlock VerticalAlignment="Center">
<Run Text="{Binding ZoomLevel}" /><Run>00%</Run> <Run Text="{Binding ZoomLevel}" /><Run>%</Run>
</TextBlock> </TextBlock>
</ToolBar> </ToolBar>
@ -114,8 +115,8 @@
<TextBlock Grid.Row="0" Grid.Column="0" >Name:</TextBlock> <TextBlock Grid.Row="0" Grid.Column="0" >Name:</TextBlock>
<TextBox Grid.Row="0" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Name,Mode=OneWay}" /> <TextBox Grid.Row="0" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Name,Mode=OneWay}" />
<TextBlock Grid.Row="1" Grid.Column="0" >Height range:</TextBlock> <TextBlock Grid.Row="1" Grid.Column="0" >Height:</TextBlock>
<TextBox Grid.Row="1" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.HeightRange,Mode=OneWay}" /> <TextBox Grid.Row="1" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Height,Mode=OneWay}" />
<TextBlock Grid.Row="2" Grid.Column="0" >Moisture:</TextBlock> <TextBlock Grid.Row="2" Grid.Column="0" >Moisture:</TextBlock>
<TextBox Grid.Row="2" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Moisture,Mode=OneWay}" /> <TextBox Grid.Row="2" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Moisture,Mode=OneWay}" />

View File

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Microsoft.Win32; using Microsoft.Win32;
using TransportGame.MapViewer.Business;
using TransportGame.MapViewer.Storage; using TransportGame.MapViewer.Storage;
using TransportGame.Model; using TransportGame.Model;
@ -152,15 +153,15 @@ namespace TransportGame.MapViewer
/// <summary> /// <summary>
/// Gets or sets the zoom level /// Gets or sets the zoom level
/// </summary> /// </summary>
public int ZoomLevel public float ZoomLevel
{ {
get get
{ {
return Renderer.Scale; return Renderer.Scale * 100f;
} }
set set
{ {
Renderer.Scale = value; Renderer.Scale = value / 100f;
if (PropertyChanged != null) if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("ZoomLevel")); PropertyChanged(this, new PropertyChangedEventArgs("ZoomLevel"));
} }
@ -215,7 +216,8 @@ namespace TransportGame.MapViewer
try try
{ {
RenderedMap = await Renderer.RenderToImageSource(Map, _layers); var renderResult = await Task.Run(() => Renderer.Render(Map, _layers));
RenderedMap = renderResult.ToBitmapSource();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -260,10 +262,10 @@ namespace TransportGame.MapViewer
private async void buttonZoomIn_Click(object sender, RoutedEventArgs e) private async void buttonZoomIn_Click(object sender, RoutedEventArgs e)
{ {
// Zoom // Zoom
ZoomLevel++; ZoomLevel *= 2;
// Update IsEnabled // Update IsEnabled
if (ZoomLevel >= 10) if (ZoomLevel >= 400)
buttonZoomIn.IsEnabled = false; buttonZoomIn.IsEnabled = false;
buttonZoomOut.IsEnabled = true; buttonZoomOut.IsEnabled = true;
@ -275,10 +277,10 @@ namespace TransportGame.MapViewer
private async void buttonZoomOut_Click(object sender, RoutedEventArgs e) private async void buttonZoomOut_Click(object sender, RoutedEventArgs e)
{ {
// Zoom // Zoom
ZoomLevel--; ZoomLevel /=2;
// Update IsEnabled // Update IsEnabled
if (ZoomLevel <= 1) if (ZoomLevel <= 10)
buttonZoomOut.IsEnabled = false; buttonZoomOut.IsEnabled = false;
buttonZoomIn.IsEnabled = true; buttonZoomIn.IsEnabled = true;
@ -332,8 +334,7 @@ namespace TransportGame.MapViewer
filename = dialog.FileName; filename = dialog.FileName;
return true; return true;
} }
#endregion #endregion
} }
} }

View File

@ -59,6 +59,8 @@
<Compile Include="..\..\..\Game\Assets\Scripts\Model\Map.cs"> <Compile Include="..\..\..\Game\Assets\Scripts\Model\Map.cs">
<Link>Model\Map.cs</Link> <Link>Model\Map.cs</Link>
</Compile> </Compile>
<Compile Include="Business\BitmapExtensions.cs" />
<Compile Include="Model\Bitmap24.cs" />
<Compile Include="Storage\MapStorage.cs" /> <Compile Include="Storage\MapStorage.cs" />
<Page Include="MainWindow.xaml"> <Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>

View File

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace TransportGame.MapViewer.Model
{
public class Bitmap24
{
/// <summary>
/// Gets the width of the bitmap
/// </summary>
public int Width { get; private set; }
/// <summary>
/// Gets the height of the bitmap
/// </summary>
public int Height { get; private set; }
/// <summary>
/// Gets the raw bytes of the bitmap
/// </summary>
public byte[] Raw { get; private set; }
/// <summary>
/// Initializes a bitmap
/// </summary>
/// <param name="w"></param>
/// <param name="h"></param>
public Bitmap24(int w, int h)
{
Width = w;
Height = h;
Raw = new byte[w * h * 3];
}
/// <summary>
/// Gets or sets a pixel
/// </summary>
/// <param name="x">x coordinate of pixel</param>
/// <param name="y">y coordinate of pixel</param>
public Color this[int x, int y]
{
get
{
int index = RawIndexOf(x, y);
return Color.FromRgb(Raw[index], Raw[index + 1], Raw[index + 2]);
}
set
{
int index = RawIndexOf(x, y);
Raw[index] = value.R;
Raw[index + 1] = value.G;
Raw[index + 2] = value.B;
}
}
private int RawIndexOf(int x, int y)
{
if (x < 0 || x >= Width)
throw new ArgumentOutOfRangeException("x is out of range");
if (y < 0 || y >= Height)
throw new ArgumentOutOfRangeException("x is out of range");
return 3 * (x + y * Width);
}
}
}