/// <summary> /// Whether this generator can generate a material for a given declaration. /// By default this only returns true if the declaration is equal to the /// standard one returned from getLayerDeclaration, but if a subclass wants /// to be flexible to generate materials for other declarations too, it /// can specify here. /// </summary> /// <param name="decl"></param> /// <returns></returns> public virtual bool CanGenerateUsingDeclaration(TerrainLayerDeclaration decl) { return(decl == this.mLayerDecl); }
/// <summary> /// Whether this generator can generate a material for a given declaration. /// By default this only returns true if the declaration is equal to the /// standard one returned from getLayerDeclaration, but if a subclass wants /// to be flexible to generate materials for other declarations too, it /// can specify here. /// </summary> /// <param name="decl"></param> /// <returns></returns> public virtual bool CanGenerateUsingDeclaration( TerrainLayerDeclaration decl ) { return decl == this.mLayerDecl; }
protected void CheckDeclaration() { if ( this.mMaterialGenerator == null ) { this.mMaterialGenerator = TerrainGlobalOptions.DefaultMaterialGenerator; } if ( this.mLayerDecl.Elements == null || this.mLayerDecl.Elements.Count == 0 ) { //default the declaration this.mLayerDecl = this.mMaterialGenerator.LayerDeclaration; } }
public bool Prepare( ImportData importData ) { FreeTemporaryResources(); FreeCPUResources(); CopyGlobalOptions(); //validate if ( !( Bitwise.IsPow2( importData.TerrainSize - 1 ) && Bitwise.IsPow2( importData.MinBatchSize - 1 ) && Bitwise.IsPow2( importData.MaxBatchSize - 1 ) ) ) { throw new AxiomException( "terrainSize, minBatchSize and maxBatchSize must all be n^2 + 1. Terrain.Prepare" ); } if ( importData.MinBatchSize > importData.MaxBatchSize ) { throw new AxiomException( "MinBatchSize must be less then or equal to MaxBatchSize. Terrain.Prepare" ); } if ( importData.MaxBatchSize > TERRAIN_MAX_BATCH_SIZE ) { throw new AxiomException( "MaxBatchSize must be not larger then {0} . Terrain.Prepare", TERRAIN_MAX_BATCH_SIZE ); } Alignment = importData.TerrainAlign; this.mSize = importData.TerrainSize; this.mWorldSize = importData.WorldSize; this.mLayerDecl = importData.LayerDeclaration; CheckDeclaration(); this.mLayers = importData.LayerList; CheckLayers( false ); DeriveUVMultipliers(); this.mMaxBatchSize = importData.MaxBatchSize; this.mMinBatchSize = importData.MinBatchSize; this.mPos = importData.Pos; UpdateBaseScale(); DetermineLodLevels(); int numVertices = this.mSize*this.mSize; this.mHeightData = new float[numVertices]; if ( importData.InputFloat != null ) { if ( Utility.RealEqual( importData.InputBias, 0.0f ) && Utility.RealEqual( importData.InputScale, 1.0f ) ) { //straigt copy this.mHeightData = new float[numVertices]; Array.Copy( importData.InputFloat, this.mHeightData, this.mHeightData.Length ); } else { // scale & bias, lets do it unsafe, should be faster :) var src = importData.InputFloat; for ( var i = 0; i < numVertices; ++i ) { this.mHeightData[ i ] = ( src[ i ]*importData.InputScale ) + importData.InputBias; } } } else if ( importData.InputImage != null ) { var img = importData.InputImage; if ( img.Width != this.mSize || img.Height != this.mSize ) { img.Resize( this.mSize, this.mSize ); } // convert image data to floats // Do this on a row-by-row basis, because we describe the terrain in // a bottom-up fashion (ie ascending world coords), while Image is top-down var pSrcBaseF = BufferBase.Wrap( img.Data ); var pHeightDataF = BufferBase.Wrap( this.mHeightData, mHeightData.Length * sizeof(float) ); for ( var i = 0; i < this.mSize; ++i ) { var srcy = this.mSize - i - 1; using ( var pSrc = pSrcBaseF + srcy*img.RowSpan ) { using ( var pDest = pHeightDataF + i*this.mSize*sizeof ( float ) ) { PixelConverter.BulkPixelConversion( pSrc, img.Format, pDest, PixelFormat.FLOAT32_R, this.mSize ); } } } pSrcBaseF.Dispose(); pHeightDataF.Dispose(); if ( !Utility.RealEqual( importData.InputBias, 0.0f ) || !Utility.RealEqual( importData.InputScale, 1.0f ) ) { for ( int i = 0; i < numVertices; ++i ) { this.mHeightData[ i ] = ( this.mHeightData[ i ]*importData.InputScale ) + importData.InputBias; } } } else { // start with flat terrain this.mHeightData = new float[this.mSize*this.mSize]; } var deltaData = new float[numVertices]; this.mHeightDataPtr = BufferBase.Wrap( this.mHeightData,mHeightData.Length * sizeof(float) ); this.mDeltaDataPtr = BufferBase.Wrap( deltaData, deltaData.Length * sizeof(float) ); var numLevel = (ushort)(int)( NumLodLevels - 1 ); QuadTree = new TerrainQuadTreeNode( this, null, 0, 0, this.mSize, (ushort)( NumLodLevels - 1 ), 0, 0 ); QuadTree.Prepare(); //calculate entire terrain var rect = new Rectangle(); rect.Top = 0; rect.Bottom = this.mSize; rect.Left = 0; rect.Right = this.mSize; CalculateHeightDeltas( rect ); FinalizeHeightDeltas( rect, true ); DistributeVertexData(); // Imported data is treated as modified because it's not saved IsModified = true; IsHeightDataModified = true; return true; }
public static bool ReadLayerDeclaration( ref StreamSerializer stream, ref TerrainLayerDeclaration targetDecl ) { if ( stream.ReadChunkBegin( TERRAINLAYERDECLARATION_CHUNK_ID, TERRAINLAYERDECLARATION_CHUNK_VERSION ) == null ) { return false; } // samplers byte numSamplers; stream.Read( out numSamplers ); targetDecl.Samplers = new List<TerrainLayerSampler>( numSamplers ); for ( var s = 0; s < numSamplers; ++s ) { if ( stream.ReadChunkBegin( TERRAINLAYERSAMPLER_CHUNK_ID, TERRAINLAYERSAMPLER_CHUNK_VERSION ) == null ) { return false; } var sampler = new TerrainLayerSampler(); stream.Read( out sampler.Alias ); byte pixFmt; stream.Read( out pixFmt ); sampler.Format = (PixelFormat)pixFmt; stream.ReadChunkEnd( TERRAINLAYERSAMPLER_CHUNK_ID ); targetDecl.Samplers.Add( sampler ); } // elements byte numElems; stream.Read( out numElems ); targetDecl.Elements = new List<TerrainLayerSamplerElement>( numElems ); for ( var e = 0; e < numElems; ++e ) { if ( stream.ReadChunkBegin( TERRAINLAYERSAMPLERELEMENT_CHUNK_ID, TERRAINLAYERSAMPLERELEMENT_CHUNK_VERSION ) == null ) { return false; } var samplerElem = new TerrainLayerSamplerElement(); stream.Read( out samplerElem.Source ); byte sem; stream.Read( out sem ); samplerElem.Semantic = (TerrainLayerSamplerSemantic)sem; stream.Read( out samplerElem.ElementStart ); stream.Read( out samplerElem.ElementCount ); stream.ReadChunkEnd( TERRAINLAYERSAMPLERELEMENT_CHUNK_ID ); targetDecl.Elements.Add( samplerElem ); } stream.ReadChunkEnd( TERRAINLAYERDECLARATION_CHUNK_ID ); return true; }
public static void WriteLayerDeclaration( TerrainLayerDeclaration decl, ref StreamSerializer stream ) { // Layer declaration stream.WriteChunkBegin( TERRAINLAYERDECLARATION_CHUNK_ID, TERRAINLAYERDECLARATION_CHUNK_VERSION ); // samplers var numSamplers = (byte)decl.Samplers.Count; stream.Write( numSamplers ); foreach ( var sampler in decl.Samplers ) { stream.WriteChunkBegin( TERRAINLAYERSAMPLER_CHUNK_ID, TERRAINLAYERSAMPLER_CHUNK_VERSION ); stream.Write( sampler.Alias ); var pixFmt = (byte)sampler.Format; stream.Write( pixFmt ); stream.WriteChunkEnd( TERRAINLAYERSAMPLER_CHUNK_ID ); } // elements var numElems = (byte)decl.Elements.Count; stream.Write( numElems ); foreach ( var elem in decl.Elements ) { stream.WriteChunkBegin( TERRAINLAYERSAMPLERELEMENT_CHUNK_ID, TERRAINLAYERSAMPLERELEMENT_CHUNK_VERSION ); stream.Write( elem.Source ); var sem = (byte)elem.Semantic; stream.Write( sem ); stream.Write( elem.ElementStart ); stream.Write( elem.ElementCount ); stream.WriteChunkEnd( TERRAINLAYERSAMPLERELEMENT_CHUNK_ID ); } stream.WriteChunkEnd( TERRAINLAYERDECLARATION_CHUNK_ID ); }