public void Init( TerrainOptions options ) { this.options = options; this.numMipMaps = options.maxMipmap; this.size = options.size; this.terrain = new VertexData(); this.terrain.vertexStart = 0; this.terrain.vertexCount = options.size*options.size; VertexDeclaration decl = this.terrain.vertexDeclaration; VertexBufferBinding binding = this.terrain.vertexBufferBinding; int offset = 0; // Position/Normal decl.AddElement( POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position ); decl.AddElement( NORMAL, 0, VertexElementType.Float3, VertexElementSemantic.Normal ); // TexCoords decl.AddElement( TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 ); offset += VertexElement.GetTypeSize( VertexElementType.Float2 ); decl.AddElement( TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1 ); offset += VertexElement.GetTypeSize( VertexElementType.Float2 ); // TODO: Color HardwareVertexBuffer buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( POSITION ), this.terrain.vertexCount, BufferUsage.StaticWriteOnly, true ); binding.SetBinding( POSITION, buffer ); buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( NORMAL ), this.terrain.vertexCount, BufferUsage.StaticWriteOnly, true ); binding.SetBinding( NORMAL, buffer ); buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( TEXCOORD ), this.terrain.vertexCount, BufferUsage.StaticWriteOnly, true ); binding.SetBinding( TEXCOORD, buffer ); this.minLevelDistSqr = new float[this.numMipMaps]; int endx = options.startx + options.size; int endz = options.startz + options.size; // TODO: name buffers different so we can unlock HardwareVertexBuffer posBuffer = binding.GetBuffer( POSITION ); var pos = posBuffer.Lock( BufferLocking.Discard ); HardwareVertexBuffer texBuffer = binding.GetBuffer( TEXCOORD ); var tex = texBuffer.Lock( BufferLocking.Discard ); float min = 99999999, max = 0; #if !AXIOM_SAFE_ONLY unsafe #endif { var posPtr = pos.ToFloatPointer(); var texPtr = tex.ToFloatPointer(); int posCount = 0; int texCount = 0; for ( int j = options.startz; j < endz; j++ ) { for ( int i = options.startx; i < endx; i++ ) { float height = options.GetWorldHeight( i, j )*options.scaley; posPtr[ posCount++ ] = i*options.scalex; posPtr[ posCount++ ] = height; posPtr[ posCount++ ] = j*options.scalez; texPtr[ texCount++ ] = (float)i/options.worldSize; texPtr[ texCount++ ] = (float)j/options.worldSize; texPtr[ texCount++ ] = ( (float)i/options.size )*options.detailTile; texPtr[ texCount++ ] = ( (float)j/options.size )*options.detailTile; if ( height < min ) { min = height; } if ( height > max ) { max = height; } } // for i } // for j } // unsafe // unlock the buffers posBuffer.Unlock(); texBuffer.Unlock(); this.box.SetExtents( new Vector3( options.startx*options.scalex, min, options.startz*options.scalez ), new Vector3( ( endx - 1 )*options.scalex, max, ( endz - 1 )*options.scalez ) ); this.center = new Vector3( ( options.startx*options.scalex + endx - 1 )/2, ( min + max )/2, ( options.startz*options.scalez + endz - 1 )/2 ); float C = CalculateCFactor(); CalculateMinLevelDist2( C ); }
public void Init(TerrainOptions options) { this.options = options; numMipMaps = options.maxMipmap; size = options.size; terrain = new VertexData(); terrain.vertexStart = 0; // Turbo: appended factor 3 // Not sure about that, but without that the terrain manager seems // to mess up memory because of buffer overruns //terrain.vertexCount = options.size * options.size; terrain.vertexCount = options.size * options.size * 3; VertexDeclaration decl = terrain.vertexDeclaration; VertexBufferBinding binding = terrain.vertexBufferBinding; int offset = 0; // Position/Normal decl.AddElement(POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position); decl.AddElement(NORMAL, 0, VertexElementType.Float3, VertexElementSemantic.Normal); // TexCoords decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); offset += VertexElement.GetTypeSize(VertexElementType.Float2); decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1); offset += VertexElement.GetTypeSize(VertexElementType.Float2); // TODO: Color HardwareVertexBuffer buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.GetVertexSize(POSITION), terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(POSITION, buffer); buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.GetVertexSize(NORMAL), terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(NORMAL, buffer); buffer = HardwareBufferManager.Instance.CreateVertexBuffer( offset, terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(TEXCOORD, buffer); minLevelDistSqr = new float[numMipMaps]; int endx = options.startx + options.size; int endz = options.startz + options.size; // TODO: name buffers different so we can unlock HardwareVertexBuffer posBuffer = binding.GetBuffer(POSITION); IntPtr pos = posBuffer.Lock(BufferLocking.Discard); HardwareVertexBuffer texBuffer = binding.GetBuffer(TEXCOORD); IntPtr tex = texBuffer.Lock(BufferLocking.Discard); float min = 99999999, max = 0; unsafe { float *posPtr = (float *)pos.ToPointer(); float *texPtr = (float *)tex.ToPointer(); int posCount = 0; int texCount = 0; for (int j = options.startz; j < endz; j++) { for (int i = options.startx; i < endx; i++) { float height = options.GetWorldHeight(i, j) * options.scaley; posPtr[posCount++] = (float)i * options.scalex; posPtr[posCount++] = height; posPtr[posCount++] = (float)j * options.scalez; texPtr[texCount++] = (float)i / (float)options.worldSize; texPtr[texCount++] = (float)j / (float)options.worldSize; texPtr[texCount++] = ((float)i / (float)options.size) * (float)options.detailTile; texPtr[texCount++] = ((float)j / (float)options.size) * (float)options.detailTile; if (height < min) { min = height; } if (height > max) { max = height; } } // for i } // for j } // unsafe // unlock the buffers posBuffer.Unlock(); texBuffer.Unlock(); box.SetExtents( new Vector3((float)options.startx * options.scalex, min, (float)options.startz * options.scalez), new Vector3((float)(endx - 1) * options.scalex, max, (float)(endz - 1) * options.scalez)); center = new Vector3((options.startx * options.scalex + endx - 1) / 2, (min + max) / 2, (options.startz * options.scalez + endz - 1) / 2); float C = CalculateCFactor(); CalculateMinLevelDist2(C); }
public override void LoadWorldGeometry(string fileName) { var serializer = new XmlSerializer(typeof(TerrainOptions)); this.options = (TerrainOptions)serializer.Deserialize(ResourceGroupManager.Instance.OpenResource(fileName)); this.scale = new Vector3(this.options.scalex, this.options.scaley, this.options.scalez); this.tileSize = this.options.size; // load the heightmap { Image image = Image.FromStream(ResourceGroupManager.Instance.OpenResource(this.options.Terrain), this.options.Terrain.Split('.')[1]); worldSize = this.options.worldSize = image.Width; var dest = new Real[(int)worldSize * (int)worldSize]; byte[] src = image.Data; Real invScale; //if ( image.Format != PixelFormat.L8 && image.Format != PixelFormat.L16 ) // throw new AxiomException( "Heightmap is not a grey scale image!" ); bool is16bit = (image.Format == PixelFormat.L16); // Determine mapping from fixed to floating ulong rowSize; if (is16bit) { invScale = 1.0f / 65535.0f; rowSize = (ulong)worldSize * 2; } else { invScale = 1.0f; // / 255.0f; rowSize = (ulong)worldSize; } // Read the data int srcIndex = 0; int dstIndex = 0; for (ulong j = 0; j < (ulong)worldSize; ++j) { for (ulong i = 0; i < (ulong)worldSize; ++i) { if (is16bit) { #if AXIOM_BIG_ENDIAN ushort val = (ushort)(src[srcIndex++] << 8); val += src[srcIndex++]; #else ushort val = src[srcIndex++]; val += (ushort)(src[srcIndex++] << 8); #endif dest[dstIndex++] = new Real(val) * invScale; } else { dest[dstIndex++] = new Real(src[srcIndex++]); // *invScale; #if (XBOX || XBOX360) srcIndex += 3; #endif } } } // get the data from the heightmap this.options.data = dest; } float maxx = this.options.scalex * this.options.worldSize; float maxy = 255 * this.options.scaley; float maxz = this.options.scalez * this.options.worldSize; Resize(new AxisAlignedBox(Vector3.Zero, new Vector3(maxx, maxy, maxz))); this.terrainMaterial = (Material) (MaterialManager.Instance.CreateOrRetrieve( !String.IsNullOrEmpty(this.options.MaterialName) ? this.options.MaterialName : "Terrain", ResourceGroupManager.Instance.WorldResourceGroupName).First); if (this.options.WorldTexture != "") { this.terrainMaterial.GetTechnique(0).GetPass(0).CreateTextureUnitState(this.options.WorldTexture, 0); } if (this.options.DetailTexture != "") { this.terrainMaterial.GetTechnique(0).GetPass(0).CreateTextureUnitState(this.options.DetailTexture, 1); } this.terrainMaterial.Lighting = this.options.isLit; this.terrainMaterial.Load(); this.terrainRoot = (SceneNode)RootSceneNode.CreateChild("TerrainRoot"); this.numTiles = (this.options.worldSize - 1) / (this.options.size - 1); this.tiles = new TerrainRenderable[this.numTiles, this.numTiles]; int p = 0, q = 0; for (int j = 0; j < this.options.worldSize - 1; j += (this.options.size - 1)) { p = 0; for (int i = 0; i < this.options.worldSize - 1; i += (this.options.size - 1)) { this.options.startx = i; this.options.startz = j; string name = string.Format("Tile[{0},{1}]", p, q); var node = (SceneNode)this.terrainRoot.CreateChild(name); var tile = new TerrainRenderable(); tile.Name = name; tile.RenderQueueGroup = WorldGeometryRenderQueueId; tile.SetMaterial(this.terrainMaterial); tile.Init(this.options); this.tiles[p, q] = tile; node.AttachObject(tile); p++; } q++; } int size1 = this.tiles.GetLength(0); int size2 = this.tiles.GetLength(1); for (int j = 0; j < size1; j++) { for (int i = 0; i < size2; i++) { if (j != size1 - 1) { this.tiles[i, j].SetNeighbor(Neighbor.South, this.tiles[i, j + 1]); this.tiles[i, j + 1].SetNeighbor(Neighbor.North, this.tiles[i, j]); } if (i != size2 - 1) { this.tiles[i, j].SetNeighbor(Neighbor.East, this.tiles[i + 1, j]); this.tiles[i + 1, j].SetNeighbor(Neighbor.West, this.tiles[i, j]); } } } if (this.options.isLit) { for (int j = 0; j < size1; j++) { for (int i = 0; i < size2; i++) { this.tiles[i, j].CalculateNormals(); } } } }
public override void LoadWorldGeometry( string fileName ) { var serializer = new XmlSerializer( typeof ( TerrainOptions ) ); this.options = (TerrainOptions)serializer.Deserialize( ResourceGroupManager.Instance.OpenResource( fileName ) ); this.scale = new Vector3( this.options.scalex, this.options.scaley, this.options.scalez ); this.tileSize = this.options.size; // load the heightmap { Image image = Image.FromStream( ResourceGroupManager.Instance.OpenResource( this.options.Terrain ), this.options.Terrain.Split( '.' )[ 1 ] ); worldSize = this.options.worldSize = image.Width; var dest = new Real[(int)worldSize*(int)worldSize]; byte[] src = image.Data; Real invScale; //if ( image.Format != PixelFormat.L8 && image.Format != PixelFormat.L16 ) // throw new AxiomException( "Heightmap is not a grey scale image!" ); bool is16bit = ( image.Format == PixelFormat.L16 ); // Determine mapping from fixed to floating ulong rowSize; if ( is16bit ) { invScale = 1.0f/65535.0f; rowSize = (ulong)worldSize*2; } else { invScale = 1.0f; // / 255.0f; rowSize = (ulong)worldSize; } // Read the data int srcIndex = 0; int dstIndex = 0; for ( ulong j = 0; j < (ulong)worldSize; ++j ) { for ( ulong i = 0; i < (ulong)worldSize; ++i ) { if ( is16bit ) { #if AXIOM_BIG_ENDIAN ushort val = (ushort)(src[srcIndex++] << 8); val += src[srcIndex++]; #else ushort val = src[ srcIndex++ ]; val += (ushort)( src[ srcIndex++ ] << 8 ); #endif dest[ dstIndex++ ] = new Real( val )*invScale; } else { dest[ dstIndex++ ] = new Real( src[ srcIndex++ ] ); // *invScale; #if (XBOX || XBOX360 ) srcIndex += 3; #endif } } } // get the data from the heightmap this.options.data = dest; } float maxx = this.options.scalex*this.options.worldSize; float maxy = 255*this.options.scaley; float maxz = this.options.scalez*this.options.worldSize; Resize( new AxisAlignedBox( Vector3.Zero, new Vector3( maxx, maxy, maxz ) ) ); this.terrainMaterial = (Material) ( MaterialManager.Instance.CreateOrRetrieve( !String.IsNullOrEmpty( this.options.MaterialName ) ? this.options.MaterialName : "Terrain", ResourceGroupManager.Instance.WorldResourceGroupName ).First ); if ( this.options.WorldTexture != "" ) { this.terrainMaterial.GetTechnique( 0 ).GetPass( 0 ).CreateTextureUnitState( this.options.WorldTexture, 0 ); } if ( this.options.DetailTexture != "" ) { this.terrainMaterial.GetTechnique( 0 ).GetPass( 0 ).CreateTextureUnitState( this.options.DetailTexture, 1 ); } this.terrainMaterial.Lighting = this.options.isLit; this.terrainMaterial.Load(); this.terrainRoot = (SceneNode)RootSceneNode.CreateChild( "TerrainRoot" ); this.numTiles = ( this.options.worldSize - 1 )/( this.options.size - 1 ); this.tiles = new TerrainRenderable[this.numTiles,this.numTiles]; int p = 0, q = 0; for ( int j = 0; j < this.options.worldSize - 1; j += ( this.options.size - 1 ) ) { p = 0; for ( int i = 0; i < this.options.worldSize - 1; i += ( this.options.size - 1 ) ) { this.options.startx = i; this.options.startz = j; string name = string.Format( "Tile[{0},{1}]", p, q ); var node = (SceneNode)this.terrainRoot.CreateChild( name ); var tile = new TerrainRenderable(); tile.Name = name; tile.RenderQueueGroup = WorldGeometryRenderQueueId; tile.SetMaterial( this.terrainMaterial ); tile.Init( this.options ); this.tiles[ p, q ] = tile; node.AttachObject( tile ); p++; } q++; } int size1 = this.tiles.GetLength( 0 ); int size2 = this.tiles.GetLength( 1 ); for ( int j = 0; j < size1; j++ ) { for ( int i = 0; i < size2; i++ ) { if ( j != size1 - 1 ) { this.tiles[ i, j ].SetNeighbor( Neighbor.South, this.tiles[ i, j + 1 ] ); this.tiles[ i, j + 1 ].SetNeighbor( Neighbor.North, this.tiles[ i, j ] ); } if ( i != size2 - 1 ) { this.tiles[ i, j ].SetNeighbor( Neighbor.East, this.tiles[ i + 1, j ] ); this.tiles[ i + 1, j ].SetNeighbor( Neighbor.West, this.tiles[ i, j ] ); } } } if ( this.options.isLit ) { for ( int j = 0; j < size1; j++ ) { for ( int i = 0; i < size2; i++ ) { this.tiles[ i, j ].CalculateNormals(); } } } }
public override void LoadWorldGeometry(string fileName) { TerrainOptions options = new TerrainOptions(); DataSet optionData = new DataSet(); optionData.ReadXml(fileName); DataTable table = optionData.Tables[0]; DataRow row = table.Rows[0]; string terrainFileName = ""; string detailTexture = ""; string worldTexture = ""; if (table.Columns["Terrain"] != null) { terrainFileName = (string)row["Terrain"]; } if (table.Columns["DetailTexture"] != null) { detailTexture = (string)row["DetailTexture"]; } if (table.Columns["WorldTexture"] != null) { worldTexture = (string)row["WorldTexture"]; } if (table.Columns["MaxMipMapLevel"] != null) { options.maxMipmap = Convert.ToInt32(row["MaxMipMapLevel"]); } if (table.Columns["DetailTile"] != null) { options.detailTile = Convert.ToInt32(row["DetailTile"]); } if (table.Columns["MaxPixelError"] != null) { options.maxPixelError = Convert.ToInt32(row["MaxPixelError"]); } if (table.Columns["TileSize"] != null) { options.size = Convert.ToInt32(row["TileSize"]); } if (table.Columns["ScaleX"] != null) { options.scalex = StringConverter.ParseFloat((string)row["ScaleX"]); } if (table.Columns["ScaleY"] != null) { options.scaley = StringConverter.ParseFloat((string)row["ScaleY"]); } if (table.Columns["ScaleZ"] != null) { options.scalez = StringConverter.ParseFloat((string)row["ScaleZ"]); } if (table.Columns["VertexNormals"] != null) { options.isLit = ((string)row["VertexNormals"]) == "yes" ? true : false; } scale = new Vector3(options.scalex, options.scaley, options.scalez); tileSize = options.size; // load the heightmap Image image = Image.FromFile(terrainFileName); // TODO: Check terrain size for 2^n + 1 // get the data from the heightmap options.data = image.Data; options.worldSize = image.Width; float maxx = options.scalex * options.worldSize; float maxy = 255 * options.scaley; float maxz = options.scalez * options.worldSize; Resize(new AxisAlignedBox(Vector3.Zero, new Vector3(maxx, maxy, maxz))); terrainMaterial = CreateMaterial("Terrain"); if (worldTexture != "") { terrainMaterial.GetTechnique(0).GetPass(0).CreateTextureUnitState(worldTexture, 0); } if (detailTexture != "") { terrainMaterial.GetTechnique(0).GetPass(0).CreateTextureUnitState(detailTexture, 1); } terrainMaterial.Lighting = options.isLit; terrainMaterial.Load(); terrainRoot = (SceneNode)RootSceneNode.CreateChild("TerrainRoot"); numTiles = (options.worldSize - 1) / (options.size - 1); tiles = new TerrainRenderable[numTiles, numTiles]; int p = 0, q = 0; for (int j = 0; j < options.worldSize - 1; j += (options.size - 1)) { p = 0; for (int i = 0; i < options.worldSize - 1; i += (options.size - 1)) { options.startx = i; options.startz = j; string name = string.Format("Tile[{0},{1}]", p, q); SceneNode node = (SceneNode)terrainRoot.CreateChild(name); TerrainRenderable tile = new TerrainRenderable(); tile.Name = name; tile.SetMaterial(terrainMaterial); tile.Init(options); tiles[p, q] = tile; node.AttachObject(tile); p++; } q++; } int size1 = tiles.GetLength(0); int size2 = tiles.GetLength(1); for (int j = 0; j < size1; j++) { for (int i = 0; i < size2; i++) { if (j != size1 - 1) { ((TerrainRenderable)tiles[i, j]).SetNeighbor(Neighbor.South, (TerrainRenderable)tiles[i, j + 1]); ((TerrainRenderable)tiles[i, j + 1]).SetNeighbor(Neighbor.North, (TerrainRenderable)tiles[i, j]); } if (i != size2 - 1) { ((TerrainRenderable)tiles[i, j]).SetNeighbor(Neighbor.East, (TerrainRenderable)tiles[i + 1, j]); ((TerrainRenderable)tiles[i + 1, j]).SetNeighbor(Neighbor.West, (TerrainRenderable)tiles[i, j]); } } } #if NOT_USED if (false) // && options.isLit) //TODO: Fix { for (int j = 0; j < size1; j++) { for (int i = 0; i < size2; i++) { ((TerrainRenderable)tiles[i, j]).CalculateNormals(); } } } #endif this.terrainOptions = options; //we need these later for GetHeightAt, so make them a member variable }
public void Init(TerrainOptions options) { this.options = options; this.numMipMaps = options.maxMipmap; this.size = options.size; this.terrain = new VertexData(); this.terrain.vertexStart = 0; this.terrain.vertexCount = options.size * options.size; VertexDeclaration decl = this.terrain.vertexDeclaration; VertexBufferBinding binding = this.terrain.vertexBufferBinding; int offset = 0; // Position/Normal decl.AddElement(POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position); decl.AddElement(NORMAL, 0, VertexElementType.Float3, VertexElementSemantic.Normal); // TexCoords decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); offset += VertexElement.GetTypeSize(VertexElementType.Float2); decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1); offset += VertexElement.GetTypeSize(VertexElementType.Float2); // TODO: Color HardwareVertexBuffer buffer = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(POSITION), this.terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(POSITION, buffer); buffer = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(NORMAL), this.terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(NORMAL, buffer); buffer = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(TEXCOORD), this.terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(TEXCOORD, buffer); this.minLevelDistSqr = new float[this.numMipMaps]; int endx = options.startx + options.size; int endz = options.startz + options.size; // TODO: name buffers different so we can unlock HardwareVertexBuffer posBuffer = binding.GetBuffer(POSITION); var pos = posBuffer.Lock(BufferLocking.Discard); HardwareVertexBuffer texBuffer = binding.GetBuffer(TEXCOORD); var tex = texBuffer.Lock(BufferLocking.Discard); float min = 99999999, max = 0; #if !AXIOM_SAFE_ONLY unsafe #endif { var posPtr = pos.ToFloatPointer(); var texPtr = tex.ToFloatPointer(); int posCount = 0; int texCount = 0; for (int j = options.startz; j < endz; j++) { for (int i = options.startx; i < endx; i++) { float height = options.GetWorldHeight(i, j) * options.scaley; posPtr[posCount++] = i * options.scalex; posPtr[posCount++] = height; posPtr[posCount++] = j * options.scalez; texPtr[texCount++] = (float)i / options.worldSize; texPtr[texCount++] = (float)j / options.worldSize; texPtr[texCount++] = ((float)i / options.size) * options.detailTile; texPtr[texCount++] = ((float)j / options.size) * options.detailTile; if (height < min) { min = height; } if (height > max) { max = height; } } // for i } // for j } // unsafe // unlock the buffers posBuffer.Unlock(); texBuffer.Unlock(); this.box.SetExtents(new Vector3(options.startx * options.scalex, min, options.startz * options.scalez), new Vector3((endx - 1) * options.scalex, max, (endz - 1) * options.scalez)); this.center = new Vector3((options.startx * options.scalex + endx - 1) / 2, (min + max) / 2, (options.startz * options.scalez + endz - 1) / 2); float C = CalculateCFactor(); CalculateMinLevelDist2(C); }
public override void LoadWorldGeometry(string fileName) { TerrainOptions options = new TerrainOptions(); DataSet optionData = new DataSet(); optionData.ReadXml(fileName); DataTable table = optionData.Tables[0]; DataRow row = table.Rows[0]; string terrainFileName = ""; string detailTexture = ""; string worldTexture = ""; if(table.Columns["Terrain"] != null) { terrainFileName = (string)row["Terrain"]; } if(table.Columns["DetailTexture"] != null) { detailTexture = (string)row["DetailTexture"]; } if(table.Columns["WorldTexture"] != null) { worldTexture = (string)row["WorldTexture"]; } if(table.Columns["MaxMipMapLevel"] != null) { options.maxMipmap = Convert.ToInt32(row["MaxMipMapLevel"]); } if(table.Columns["DetailTile"] != null) { options.detailTile = Convert.ToInt32(row["DetailTile"]); } if(table.Columns["MaxPixelError"] != null) { options.maxPixelError = Convert.ToInt32(row["MaxPixelError"]); } if(table.Columns["TileSize"] != null) { options.size = Convert.ToInt32(row["TileSize"]); } if(table.Columns["ScaleX"] != null) { options.scalex = StringConverter.ParseFloat((string)row["ScaleX"]); } if(table.Columns["ScaleY"] != null) { options.scaley = StringConverter.ParseFloat((string)row["ScaleY"]); } if(table.Columns["ScaleZ"] != null) { options.scalez = StringConverter.ParseFloat((string)row["ScaleZ"]); } if(table.Columns["VertexNormals"] != null) { options.isLit = ((string)row["VertexNormals"]) == "yes" ? true : false; } scale = new Vector3(options.scalex, options.scaley, options.scalez); tileSize = options.size; // load the heightmap Image image = Image.FromFile(terrainFileName); // TODO: Check terrain size for 2^n + 1 // get the data from the heightmap options.data = image.Data; options.worldSize = image.Width; float maxx = options.scalex * options.worldSize; float maxy = 255 * options.scaley; float maxz = options.scalez * options.worldSize; Resize(new AxisAlignedBox(Vector3.Zero, new Vector3(maxx, maxy, maxz))); terrainMaterial = CreateMaterial("Terrain"); if(worldTexture != "") { terrainMaterial.GetTechnique(0).GetPass(0).CreateTextureUnitState(worldTexture, 0); } if(detailTexture != "") { terrainMaterial.GetTechnique(0).GetPass(0).CreateTextureUnitState(detailTexture, 1); } terrainMaterial.Lighting = options.isLit; terrainMaterial.Load(); terrainRoot = (SceneNode)RootSceneNode.CreateChild("TerrainRoot"); numTiles = (options.worldSize - 1) / (options.size - 1); tiles = new TerrainRenderable[numTiles, numTiles]; int p = 0, q = 0; for(int j = 0; j < options.worldSize - 1; j += (options.size - 1)) { p = 0; for(int i = 0; i < options.worldSize - 1; i += (options.size - 1)) { options.startx = i; options.startz = j; string name = string.Format("Tile[{0},{1}]", p, q); SceneNode node = (SceneNode)terrainRoot.CreateChild(name); TerrainRenderable tile = new TerrainRenderable(); tile.Name = name; tile.SetMaterial(terrainMaterial); tile.Init(options); tiles[p,q] = tile; node.AttachObject(tile); p++; } q++; } int size1 = tiles.GetLength(0); int size2 = tiles.GetLength(1); for(int j = 0; j < size1; j++) { for(int i = 0; i < size2; i++) { if(j != size1 - 1) { ((TerrainRenderable)tiles[i,j]).SetNeighbor(Neighbor.South, (TerrainRenderable)tiles[i, j + 1]); ((TerrainRenderable)tiles[i,j + 1]).SetNeighbor(Neighbor.North, (TerrainRenderable)tiles[i, j]); } if(i != size2 - 1) { ((TerrainRenderable)tiles[i,j]).SetNeighbor(Neighbor.East, (TerrainRenderable)tiles[i + 1, j]); ((TerrainRenderable)tiles[i + 1,j]).SetNeighbor(Neighbor.West, (TerrainRenderable)tiles[i, j]); } } } #if NOT_USED if(false) // && options.isLit) //TODO: Fix { for(int j = 0; j < size1; j++) { for(int i = 0; i < size2; i++) { ((TerrainRenderable)tiles[i,j]).CalculateNormals(); } } } #endif this.terrainOptions = options; //we need these later for GetHeightAt, so make them a member variable }
public void Init(TerrainOptions options) { this.options = options; numMipMaps = options.maxMipmap; size = options.size; terrain = new VertexData(); terrain.vertexStart = 0; // Turbo: appended factor 3 // Not sure about that, but without that the terrain manager seems // to mess up memory because of buffer overruns //terrain.vertexCount = options.size * options.size; terrain.vertexCount = options.size * options.size * 3; VertexDeclaration decl = terrain.vertexDeclaration; VertexBufferBinding binding = terrain.vertexBufferBinding; int offset = 0; // Position/Normal decl.AddElement(POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position); decl.AddElement(NORMAL, 0, VertexElementType.Float3, VertexElementSemantic.Normal); // TexCoords decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); offset += VertexElement.GetTypeSize(VertexElementType.Float2); decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1); offset += VertexElement.GetTypeSize(VertexElementType.Float2); // TODO: Color HardwareVertexBuffer buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.GetVertexSize(POSITION), terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(POSITION, buffer); buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.GetVertexSize(NORMAL), terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(NORMAL, buffer); buffer = HardwareBufferManager.Instance.CreateVertexBuffer( offset, terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(TEXCOORD, buffer); minLevelDistSqr = new float[numMipMaps]; int endx = options.startx + options.size; int endz = options.startz + options.size; // TODO: name buffers different so we can unlock HardwareVertexBuffer posBuffer = binding.GetBuffer(POSITION); IntPtr pos = posBuffer.Lock(BufferLocking.Discard); HardwareVertexBuffer texBuffer = binding.GetBuffer(TEXCOORD); IntPtr tex = texBuffer.Lock(BufferLocking.Discard); float min = 99999999, max = 0; unsafe { float* posPtr = (float*)pos.ToPointer(); float* texPtr = (float*)tex.ToPointer(); int posCount = 0; int texCount = 0; for(int j = options.startz; j < endz; j++) { for(int i = options.startx; i < endx; i++) { float height = options.GetWorldHeight(i, j) * options.scaley; posPtr[posCount++] = (float)i * options.scalex; posPtr[posCount++] = height; posPtr[posCount++] = (float)j * options.scalez; texPtr[texCount++] = (float)i / (float)options.worldSize; texPtr[texCount++] = (float)j / (float)options.worldSize; texPtr[texCount++] = ((float)i / (float)options.size) * (float)options.detailTile; texPtr[texCount++] = ((float)j / (float)options.size) * (float)options.detailTile; if(height < min) { min = height; } if(height > max) { max = height; } } // for i } // for j } // unsafe // unlock the buffers posBuffer.Unlock(); texBuffer.Unlock(); box.SetExtents( new Vector3((float) options.startx * options.scalex, min, (float)options.startz * options.scalez), new Vector3((float)(endx - 1) * options.scalex, max, (float)(endz - 1) * options.scalez)); center = new Vector3((options.startx * options.scalex + endx - 1) / 2, (min + max) / 2, (options.startz * options.scalez + endz - 1) / 2); float C = CalculateCFactor(); CalculateMinLevelDist2(C); }