public void writeQNsToChunk(ref ExportResults results) { DateTime n = DateTime.Now; int totalMemory = 0; int width = TerrainGlobals.getTerrain().getNumXVerts(); for (int qi = 0; qi < FoliageManager.getNumChunks(); qi++) { FoliageQNChunk chunk = FoliageManager.getChunk(qi); List <int> setIndexes = new List <int>(); List <int> setPolyCounts = new List <int>(); int totalPhysicalMemory = 0; List <int> indMemSizes = new List <int>(); List <int> bladeIBs = new List <int>(); for (int setI = 0; setI < chunk.mSetsUsed.Count; setI++) { int numBlades = 0; int startIndex = bladeIBs.Count; FoliageSet fs = FoliageManager.giveSet(chunk.mSetsUsed[setI]); //walk through the main grid for our current chunk //pack the data into proper inds.. for (int x = 0; x < BTerrainQuadNode.cMaxWidth; x++) { for (int z = 0; z < BTerrainQuadNode.cMaxWidth; z++) { int index = (x + chunk.mOwnerNodeDesc.mMinXVert) + width * (z + chunk.mOwnerNodeDesc.mMinZVert); FoliageVertData fvd = FoliageManager.mVertData.GetValue(index); if (fvd.compare(FoliageManager.cEmptyVertData)) { continue; } if (FoliageManager.giveIndexOfSet(fvd.mFoliageSetName) == FoliageManager.giveIndexOfSet(chunk.mSetsUsed[setI])) { numBlades++; //our local blade index is transposed on the 360 int localIndex = x * FoliageManager.cNumXBladesPerChunk + z; int bladeIndex = fvd.mFoliageSetBladeIndex << 16; for (short t = 0; t < fs.mNumVertsPerBlade; t++) { int packedID = bladeIndex | (0xFFFF & (localIndex * fs.mNumVertsPerBlade) + t); bladeIBs.Add(packedID); } bladeIBs.Add(0xFFFF); //360 specific tag to stop a strip. } } } int numVerts = bladeIBs.Count - startIndex; if (numVerts == 0) { continue; } setIndexes.Add(FoliageManager.giveIndexOfSet(chunk.mSetsUsed[setI])); setPolyCounts.Add(numBlades * (fs.mNumVertsPerBlade + 1) - 2); indMemSizes.Add(numVerts * sizeof(int)); totalPhysicalMemory += indMemSizes[indMemSizes.Count - 1]; } //now write this chunk.. ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); //our chunk index is transposed in the game int minQNX = (int)(chunk.mOwnerNodeDesc.mMinXVert / BTerrainQuadNode.cMaxWidth); int minQNZ = (int)(chunk.mOwnerNodeDesc.mMinZVert / BTerrainQuadNode.cMaxHeight); int numXChunks = (int)(TerrainGlobals.getTerrain().getNumXVerts() / BTerrainQuadNode.cMaxWidth); int transposedOwnerIndex = minQNX * numXChunks + minQNZ; binWriter.Write(Xbox_EndianSwap.endSwapI32(transposedOwnerIndex));//chunk.mOwnerQNIndex)); binWriter.Write(Xbox_EndianSwap.endSwapI32(setIndexes.Count)); int numSets = setIndexes.Count; for (int i = 0; i < numSets; i++) { binWriter.Write(Xbox_EndianSwap.endSwapI32(setIndexes[i])); } for (int i = 0; i < numSets; i++) { binWriter.Write(Xbox_EndianSwap.endSwapI32(setPolyCounts[i])); } binWriter.Write(Xbox_EndianSwap.endSwapI32(totalPhysicalMemory)); totalMemory += totalPhysicalMemory; for (int i = 0; i < numSets; i++) { binWriter.Write(Xbox_EndianSwap.endSwapI32(indMemSizes[i])); } for (int i = 0; i < bladeIBs.Count; i++) { binWriter.Write(Xbox_EndianSwap.endSwapI32(bladeIBs[i])); } ExportTo360.mECF.addChunk((int)eXTT_ChunkID.cXTT_FoliageQNChunk, chunkHolder, binWriter.BaseStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; } TimeSpan ts = DateTime.Now - n; results.terrainFoliageTime = ts.TotalMinutes; results.terrainFoliageMemory = totalMemory; }
static void estimateTerrainMemory() { using (PerfSection p3 = new PerfSection("estimateTerrainMemory")) { int width = TerrainGlobals.getTerrain().getNumXVerts(); //CLM THESE ESTIMATES ARE VALID AS OF [07.24.07] ///XTD //positions & normals - each component is 32bit mMemoryUsageItems.Add(new memoryElement("Terrain Positions & Normals", (width * width * 8), eMainCatagory.eCat_Terrain)); //ALPHA - DXT5A mMemoryUsageItems.Add(new memoryElement("Terrain Alpha", ((width >> 2) * (width >> 2) * 8), eMainCatagory.eCat_Terrain)); //AO - DXT5A mMemoryUsageItems.Add(new memoryElement("Terrain AO", ((width >> 2) * (width >> 2) * 8), eMainCatagory.eCat_Terrain)); //TessData int nodeWidth = 16; int numXPatches = (int)(TerrainGlobals.getTerrain().getNumXVerts() / (float)nodeWidth); int tessMem = numXPatches * numXPatches; tessMem += (numXPatches * numXPatches * 2) * (sizeof(float) * 4); mMemoryUsageItems.Add(new memoryElement("Terrain Tessellation", tessMem, eMainCatagory.eCat_Terrain)); //light data - DXT1 if (LightManager.hasTerrainLightData()) { mMemoryUsageItems.Add(new memoryElement("Terrain Precomputed Lighting", ((width * width) >> 2), eMainCatagory.eCat_Terrain)); } //////XTT //texture alpha data int texAlphaMem = 0; BTerrainQuadNode[] nodes = TerrainGlobals.getTerrain().getQuadNodeLeafArray(); for (int i = 0; i < nodes.Length; i++) { int numAlignedSplatLayers = 4 * (((nodes[i].mLayerContainer.getNumSplatLayers() - 1) >> 2) + 1); int numAlignedDecalLayers = 4 * (((nodes[i].mLayerContainer.getNumDecalLayers() - 1) >> 2) + 1); texAlphaMem += numAlignedSplatLayers * ((64 * 64) >> 2); } mMemoryUsageItems.Add(new memoryElement("Terrain Texture Blends", texAlphaMem, eMainCatagory.eCat_Terrain)); //unique Albedo int uniqueTextureRes = 128; int uniqueWidth = (int)((width / BTerrainQuadNode.cMaxWidth) * uniqueTextureRes); int uniqueMemSize = (int)(uniqueWidth * uniqueWidth); if (BMathLib.isPow2(uniqueWidth)) { uniqueMemSize += (uniqueWidth >> 1) * (uniqueWidth >> 1); } mMemoryUsageItems.Add(new memoryElement("Terrain Unique Albedo Texture", (uniqueMemSize >> 1), eMainCatagory.eCat_Terrain)); //FOLIAGE int totalPhysicalMemory = 0; for (int qi = 0; qi < FoliageManager.getNumChunks(); qi++) { FoliageQNChunk chunk = FoliageManager.getChunk(qi); for (int setI = 0; setI < chunk.mSetsUsed.Count; setI++) { int numBlades = 0; FoliageSet fs = FoliageManager.giveSet(chunk.mSetsUsed[setI]); //walk through the main grid for our current chunk //pack the data into proper inds.. for (int x = 0; x < BTerrainQuadNode.cMaxWidth; x++) { for (int z = 0; z < BTerrainQuadNode.cMaxWidth; z++) { int index = (x + chunk.mOwnerNodeDesc.mMinXVert) + width * (z + chunk.mOwnerNodeDesc.mMinZVert); FoliageVertData fvd = FoliageManager.mVertData.GetValue(index); if (fvd.compare(FoliageManager.cEmptyVertData)) { continue; } if (FoliageManager.giveIndexOfSet(fvd.mFoliageSetName) == FoliageManager.giveIndexOfSet(chunk.mSetsUsed[setI])) { numBlades++; totalPhysicalMemory += (fs.mNumVertsPerBlade + 1) * sizeof(int); } } } } } mMemoryUsageItems.Add(new memoryElement("Terrain Foliage", totalPhysicalMemory, eMainCatagory.eCat_Terrain)); //ROADS /////XTH mMemoryUsageItems.Add(new memoryElement("Terrain Decal Rep", 256 * 256 * sizeof(short) * 2, eMainCatagory.eCat_Terrain)); //CACHES //add in our 360 cache data int cacheMemCount = 0; const int numCachePages = 20; const int cachePageSize = 512; const int numMips = 2; bool albedoCache = true; bool normalCache = true; bool specCache = false; bool selfCache = false; bool envCache = false; for (int i = 0; i < TerrainGlobals.getTexturing().getActiveTextureCount(); i++) { BTerrainActiveTextureContainer ActTex = TerrainGlobals.getTexturing().getActiveTexture(i); String fname = ActTex.mFilename; String ext = ".ddx";// Path.GetExtension(fname); string sname = fname.Substring(0, fname.LastIndexOf("_df")) + "_em" + ext; selfCache |= File.Exists(sname); sname = fname.Substring(0, fname.LastIndexOf("_df")) + "_rm" + ext; envCache |= File.Exists(sname); sname = fname.Substring(0, fname.LastIndexOf("_df")) + "_sp" + ext; specCache |= File.Exists(sname); } for (int i = 0; i < TerrainGlobals.getTexturing().getActiveDecalCount(); i++) { BTerrainActiveDecalContainer ActTex = TerrainGlobals.getTexturing().getActiveDecal(i); String fname = ActTex.mFilename; String ext = ".ddx";// Path.GetExtension(fname); string sname = fname.Substring(0, fname.LastIndexOf("_df")) + "_em" + ext; selfCache |= File.Exists(sname); sname = fname.Substring(0, fname.LastIndexOf("_df")) + "_rm" + ext; envCache |= File.Exists(sname); sname = fname.Substring(0, fname.LastIndexOf("_df")) + "_sp" + ext; specCache |= File.Exists(sname); } if (albedoCache) { cacheMemCount += giveTextureCacheMemoryRequirement(numCachePages, cachePageSize, numMips, 0); //DXT1 * numCachePages (mip0 & mip1) } if (normalCache) { cacheMemCount += giveTextureCacheMemoryRequirement(numCachePages, cachePageSize, numMips, 1); } ; //DXN if (specCache) { cacheMemCount += giveTextureCacheMemoryRequirement(numCachePages, cachePageSize, numMips, 0); //DXT1 } if (envCache) { cacheMemCount += giveTextureCacheMemoryRequirement(numCachePages, cachePageSize, numMips, 0); //DXT1 } if (selfCache) { cacheMemCount += giveTextureCacheMemoryRequirement(numCachePages, cachePageSize, numMips, 1); //DXT5 } mMemoryUsageItems.Add(new memoryElement("Terrain Texture Cache", cacheMemCount, eMainCatagory.eCat_Terrain)); //ARTIST TERRAIN TEXTURES int totalMemTT = 0; for (int i = 0; i < TerrainGlobals.getTexturing().getActiveTextureCount(); i++) { totalMemTT += TerrainGlobals.getTexturing().getActiveTexture(i).m360MemoryFootprint; } for (int i = 0; i < TerrainGlobals.getTexturing().getActiveDecalCount(); i++) { totalMemTT += TerrainGlobals.getTexturing().getActiveDecal(i).m360MemoryFootprint; } mMemoryUsageItems.Add(new memoryElement("Terrain Artist Textures", totalMemTT, eMainCatagory.eCat_Terrain)); } }