public Init ( |
||
options | ||
return | void |
public void Init( TerrainOptions options )
{
this.options = options;
numMipMaps = options.maxMipmap;
size = options.size;
terrain = new VertexData();
terrain.vertexStart = 0;
terrain.vertexCount = options.size * options.size;
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.Clone( POSITION ), terrain.vertexCount, BufferUsage.StaticWriteOnly, true );
binding.SetBinding( POSITION, buffer );
buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( NORMAL ), terrain.vertexCount, BufferUsage.StaticWriteOnly, true );
binding.SetBinding( NORMAL, buffer );
buffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( TEXCOORD ), 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++ ] = 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();
box.SetExtents(
new Vector3( options.startx * options.scalex, min, options.startz * options.scalez ),
new Vector3( ( endx - 1 ) * options.scalex, max, ( 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(); } } } }