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 bool Prepare( StreamSerializer stream ) { FreeTemporaryResources(); FreeCPUResources(); CopyGlobalOptions(); if ( stream.ReadChunkBegin( TERRAIN_CHUNK_ID, TERRAIN_CHUNK_VERSION ) == null ) { return false; } byte align; stream.Read( out align ); Alignment = (Alignment)align; stream.Read( out this.mSize ); stream.Read( out this.mWorldSize ); stream.Read( out this.mMaxBatchSize ); stream.Read( out this.mMinBatchSize ); stream.Read( out this.mPos ); RootSceneNode.Position = this.mPos; UpdateBaseScale(); DetermineLodLevels(); int numVertices = this.mSize*this.mSize; this.mHeightData = new float[numVertices]; stream.Read( out this.mHeightData ); // layer declaration if ( !ReadLayerDeclaration( ref stream, ref this.mLayerDecl ) ) { return false; } CheckDeclaration(); // Layers if ( !ReadLayerInstanceList( ref stream, this.mLayerDecl.Elements.Count, ref this.mLayers ) ) { return false; } DeriveUVMultipliers(); // Packed layer blend data var numLayers = (byte)this.mLayers.Count; stream.Read( out this.mLayerBlendMapSize ); this.mLayerBlendSizeActual = this.mLayerBlendMapSize; // for now, until we check //load packed CPU data var numBlendTex = GetBlendTextureCount( numLayers ); for ( var i = 0; i < numBlendTex; ++i ) { var fmt = GetBlendTextureFormat( (byte)i, numLayers ); var channels = PixelUtil.GetNumElemBytes( fmt ); var dataSz = channels*this.mLayerBlendMapSize*this.mLayerBlendMapSize; var data = new byte[dataSz]; stream.Read( out data ); this.mCpuBlendMapStorage.AddRange( data ); } //derived data while ( !stream.IsEndOfChunk( TERRAIN_CHUNK_ID ) && stream.NextChunkId == TERRAINDERIVEDDATA_CHUNK_ID ) { stream.ReadChunkBegin( TERRAINDERIVEDDATA_CHUNK_ID, TERRAINDERIVEDDATA_CHUNK_VERSION ); //name var name = string.Empty; stream.Read( out name ); ushort sz; stream.Read( out sz ); if ( name == "normalmap" ) { this.mNormalMapRequired = true; var data = new byte[sz*sz*3]; stream.Read( out data ); using ( var pDataF = BufferBase.Wrap( data ) ) { this.mCpuTerrainNormalMap = new PixelBox( sz, sz, 1, PixelFormat.BYTE_RGB, pDataF ); } } else if ( name == "colormap" ) { IsGlobalColorMapEnabled = true; GlobalColorMapSize = sz; this.mCpuColorMapStorage = new byte[sz*sz*3]; stream.Read( out this.mCpuColorMapStorage ); } else if ( name == "lightmap" ) { this.mLightMapRequired = true; LightMapSize = sz; this.mCpuLightmapStorage = new byte[sz*sz]; stream.Read( out this.mCpuLightmapStorage ); } else if ( name == "compositemap" ) { this.mCompositeMapRequired = true; this.mCompositeMapSize = sz; this.mCpuCompositeMapStorage = new byte[sz*sz*4]; stream.Read( out this.mCpuCompositeMapStorage ); } stream.ReadChunkEnd( TERRAINDERIVEDDATA_CHUNK_ID ); } //Load delta data var deltaData = new byte[ sizeof( float ) * numVertices ]; stream.Read( out deltaData ); this.mDeltaDataPtr = BufferBase.Wrap( deltaData ); //Create and load quadtree QuadTree = new TerrainQuadTreeNode( this, null, 0, 0, this.mSize, (ushort)( NumLodLevels - 1 ), 0, 0 ); QuadTree.Prepare(); stream.ReadChunkEnd( TERRAIN_CHUNK_ID ); DistributeVertexData(); IsModified = false; IsHeightDataModified = false; return true; }