//----------------------------------------------------------------------------------- void heightFieldToChunk(HeightsGen hg, ref ExportResults results) { ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); binWriter.Write(Xbox_EndianSwap.endSwapI32((int)hg.mHeightFieldAttributes.mWidth)); binWriter.Write(Xbox_EndianSwap.endSwapI32((int)hg.mHeightFieldAttributes.mHeight)); binWriter.Write(Xbox_EndianSwap.endSwapF32(hg.mHeightFieldAttributes.mWorldMinY)); binWriter.Write(Xbox_EndianSwap.endSwapF32(hg.mHeightFieldAttributes.mWorldMaxY)); binWriter.Write(Xbox_EndianSwap.endSwapF32(hg.mHeightFieldAttributes.mWorldRangeY)); binWriter.Write(Xbox_EndianSwap.endSwapF32(hg.mHeightFieldAttributes.mBounds.min.X)); binWriter.Write(Xbox_EndianSwap.endSwapF32(hg.mHeightFieldAttributes.mBounds.min.Y)); binWriter.Write(Xbox_EndianSwap.endSwapF32(hg.mHeightFieldAttributes.mBounds.min.Z)); binWriter.Write(Xbox_EndianSwap.endSwapF32(hg.mHeightFieldAttributes.mBounds.max.X)); binWriter.Write(Xbox_EndianSwap.endSwapF32(hg.mHeightFieldAttributes.mBounds.max.Y)); binWriter.Write(Xbox_EndianSwap.endSwapF32(hg.mHeightFieldAttributes.mBounds.max.Z)); binWriteMatrix(binWriter, hg.mHeightFieldAttributes.mNormZToWorld); binWriteMatrix(binWriter, hg.mHeightFieldAttributes.mWorldToNormZ); binWriter.Write(Xbox_EndianSwap.endSwapI32(hg.mHeightFieldAttributes.mpTexelsHI.Length)); int memSize = hg.mHeightFieldAttributes.mpTexelsHI.Length * 2 * sizeof(short); binWriter.Write(Xbox_EndianSwap.endSwapI32(memSize)); //expect the texture as G16R16, NON FLOAT! Just 16 bits of short. int numShorts = hg.mHeightFieldAttributes.mpTexelsHI.Length * 2; short[] sArray = new short[numShorts]; for (int i = 0; i < hg.mHeightFieldAttributes.mpTexelsHI.Length; i++) { sArray[i * 2 + 0] = (short)Xbox_EndianSwap.endSwapI16((ushort)hg.mHeightFieldAttributes.mpTexelsHI[i]); sArray[i * 2 + 1] = (short)Xbox_EndianSwap.endSwapI16((ushort)hg.mHeightFieldAttributes.mpTexelsLO[i]); } //tileswap short[] tempbytearray = new short[sArray.Length]; sArray.CopyTo(tempbytearray, 0); ExportTo360.tileCopy(ref tempbytearray, tempbytearray, (int)hg.mHeightFieldAttributes.mWidth, (int)hg.mHeightFieldAttributes.mHeight, ExportTo360.eTileCopyFormats.cTCFMT_G16R16); // tempbytearray.CopyTo(sArray, 0); for (int i = 0; i < tempbytearray.Length; i++) { binWriter.Write(tempbytearray[i]); } ExportTo360.mECF.addChunk((int)eXTH_ChunkID.cXTH_TerrainHeightfield, chunkHolder, binWriter.BaseStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; results.terrainGPUHeighfieldMemory = memSize; }
public void exportFoliage(ref ExportResults results) { if (FoliageManager.getNumChunks() == 0) { return; } FoliageManager.removeUnusedSets(); //write our headers.. writeHeaderToChunk(); writeQNsToChunk(ref results); }
public void writeAOData(ref ExportResults results) { //WRITE THE CHUNK ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); byte[] data = packAOToDXT5A(TerrainGlobals.getEditor().getAmbientOcclusionValues(), TerrainGlobals.getTerrain().getNumXVerts()); for (int i = 0; i < data.Length; i++) { binWriter.Write(data[i]); } results.terrainAOMemorySize = data.Length; data = null; ExportTo360.mECF.addChunk((int)eXTD_ChunkID.cXTD_AOChunk, chunkHolder, binWriter.BaseStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; }
//----------------------------------------------------------------------------------- public bool export_XTH(string filename, ExportSettings expSettings, ref ExportResults results) { DateTime n = DateTime.Now; HeightsGen hg = new HeightsGen(); hg.computeHeightField(256, 256, true, BMathLib.unitZ, 8); headerToChunk(); heightFieldToChunk(hg, ref results); //turn our data into a ECF chunk heightFieldAlphaToChunk(ref results); bool exportOK = ExportTo360.safeECFFileWrite(filename, ".XTH"); hg.destroy(); TimeSpan ts = DateTime.Now - n; results.terrainGPUHeighfieldTime = ts.TotalMinutes; return(exportOK); }
void writeAlpha(ref ExportResults results) { //WRITE THE CHUNK ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); #region DXT5Alpha byte[] dataAlpha = packAlphaToDXT5A(TerrainGlobals.getEditor().getAlphaValues(), TerrainGlobals.getTerrain().getNumXVerts()); for (int i = 0; i < dataAlpha.Length; i++) { binWriter.Write(dataAlpha[i]); } results.terrainAlphaMemorySize = dataAlpha.Length; dataAlpha = null; #endregion ExportTo360.mECF.addChunk((int)eXTD_ChunkID.cXTD_AlphaChunk, chunkHolder, binWriter.BaseStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; }
void heightFieldAlphaToChunk(ref ExportResults results) { //i think for visual reasons, the resolution of this alpha data needs to match //the density of the terrain alpha.. BTerrainSimRep simRep = TerrainGlobals.getEditor().getSimRep(); int width = TerrainGlobals.getTerrain().getNumXVerts(); int height = TerrainGlobals.getTerrain().getNumXVerts(); if (width < 256 || height < 256) { return; //don't write for small maps.. } byte[] AlphaVals = TerrainGlobals.getEditor().getAlphaValues(); DXT3_1111 img = new DXT3_1111(width, height); //walk through all the terrain alpha values, for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = x * width + y; bool visible = AlphaVals[index] > 0;// if it's invisible, so are we. //walk through the sim rep. If it's passable, we're visible. float normalizedX = x / (float)width; float normalizedZ = y / (float)height; bool obstructsLand = simRep.getDataTiles().isLandObstructedComposite(normalizedX, normalizedZ); visible |= !obstructsLand; img.setValue(x, y, visible); } } ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); int packedWidth = width >> 2; binWriter.Write(Xbox_EndianSwap.endSwapI32(packedWidth)); binWriter.Write(Xbox_EndianSwap.endSwapI32(height)); int numBlocks = img.getNumBlocks(); //numXBlocks-1 + numXBlocks * numYBlocks int texelMemSize = numBlocks * sizeof(Int64);// (((width >> 4) - 1) + (width >> 4) * ((height >> 2) - 1)) * sizeof(Int64); binWriter.Write(Xbox_EndianSwap.endSwapI32(texelMemSize)); for (int i = 0; i < numBlocks; i++) { binWriter.Write(img.getBlock(i)); } ExportTo360.mECF.addChunk((int)eXTH_ChunkID.cXTH_TerrainHeightfieldAlpha, chunkHolder, binWriter.BaseStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; results.terrainGPUHeighfieldMemory += texelMemSize; img = null; }
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; }
public void exportRoads(ref ExportResults results) { DateTime n = DateTime.Now; //for each road, for (int roadIndex = 0; roadIndex < RoadManager.giveNumRoads(); roadIndex++) { List <RoadTriangle> triList = new List <RoadTriangle>(); Road rd = RoadManager.giveRoad(roadIndex); if (rd.getNumControlPoints() == 0) //don't export roads w/o points on the map { continue; } //Step 1, generate polygon lists//////////////////////////////////////////////////// for (int rcpIndex = 0; rcpIndex < rd.getNumControlPoints(); rcpIndex++) { roadControlPoint rcp = rd.getPoint(rcpIndex); int numTris = (int)(rcp.mVerts.Count / 3); for (int triIndex = 0; triIndex < numTris; triIndex++) { RoadTriangle rt = new RoadTriangle(); rt.mVerts[0] = new RoadVert(); rt.mVerts[0].mPos = new Vector3(rcp.mVerts[triIndex * 3 + 0].x, rcp.mVerts[triIndex * 3 + 0].y, rcp.mVerts[triIndex * 3 + 0].z); rt.mVerts[0].mUv0 = new Vector2(rcp.mVerts[triIndex * 3 + 0].u0, rcp.mVerts[triIndex * 3 + 0].v0); rt.mVerts[1] = new RoadVert(); rt.mVerts[1].mPos = new Vector3(rcp.mVerts[triIndex * 3 + 1].x, rcp.mVerts[triIndex * 3 + 1].y, rcp.mVerts[triIndex * 3 + 1].z); rt.mVerts[1].mUv0 = new Vector2(rcp.mVerts[triIndex * 3 + 1].u0, rcp.mVerts[triIndex * 3 + 1].v0); rt.mVerts[2] = new RoadVert(); rt.mVerts[2].mPos = new Vector3(rcp.mVerts[triIndex * 3 + 2].x, rcp.mVerts[triIndex * 3 + 2].y, rcp.mVerts[triIndex * 3 + 2].z); rt.mVerts[2].mUv0 = new Vector2(rcp.mVerts[triIndex * 3 + 2].u0, rcp.mVerts[triIndex * 3 + 2].v0); triList.Add(rt); } } //now add our triStrip segments (into triLists) for (int segIndex = 0; segIndex < rd.getNumRoadSegments(); segIndex++) { roadSegment rs = rd.getRoadSegment(segIndex); int numTris = rs.mNumVerts - 2; int vertIndex = rs.mStartVertInParentSegment + 2; for (int i = 0; i < numTris; i++) { RoadTriangle rt = new RoadTriangle(); rt.mVerts[0] = new RoadVert(); rt.mVerts[0].mPos = new Vector3(rd.mVerts[vertIndex - 2].x, rd.mVerts[vertIndex - 2].y, rd.mVerts[vertIndex - 2].z); rt.mVerts[0].mUv0 = new Vector2(rd.mVerts[vertIndex - 2].u0, rd.mVerts[vertIndex - 2].v0); rt.mVerts[1] = new RoadVert(); rt.mVerts[1].mPos = new Vector3(rd.mVerts[vertIndex - 1].x, rd.mVerts[vertIndex - 1].y, rd.mVerts[vertIndex - 1].z); rt.mVerts[1].mUv0 = new Vector2(rd.mVerts[vertIndex - 1].u0, rd.mVerts[vertIndex - 1].v0); rt.mVerts[2] = new RoadVert(); rt.mVerts[2].mPos = new Vector3(rd.mVerts[vertIndex].x, rd.mVerts[vertIndex].y, rd.mVerts[vertIndex].z); rt.mVerts[2].mUv0 = new Vector2(rd.mVerts[vertIndex].u0, rd.mVerts[vertIndex].v0); triList.Add(rt); vertIndex++; } } //Step 2, split Polygons//////////////////////////////////////////////////// int width = (int)(BTerrainQuadNode.cMaxWidth); int numPlanes = (int)(TerrainGlobals.getTerrain().getNumXVerts() / width); //Split along XPlane for (int planeIndex = 0; planeIndex < numPlanes; planeIndex++) { Plane pl = Plane.FromPointNormal(new Vector3(planeIndex * width * TerrainGlobals.getTerrain().getTileScale(), 0, 0), BMathLib.unitX); splitPolyListAgainstPlane(pl, triList); } //split along ZPlane for (int planeIndex = 0; planeIndex < numPlanes; planeIndex++) { Plane pl = Plane.FromPointNormal(new Vector3(0, 0, planeIndex * width * TerrainGlobals.getTerrain().getTileScale()), BMathLib.unitZ); splitPolyListAgainstPlane(pl, triList); } //Step 3, add polies to qn.///////////////////////////////////////////////// List <RoadQN> roadQNs = new List <RoadQN>(); int numQNs = (int)(TerrainGlobals.getTerrain().getNumXVerts() / width); int qnWidth = (int)(width * TerrainGlobals.getTerrain().getTileScale()); for (int qnX = 0; qnX < numQNs; qnX++) { for (int qnZ = 0; qnZ < numQNs; qnZ++) { float x = qnX * qnWidth; float z = qnZ * qnWidth; RoadQN rqn = new RoadQN(); for (int triIndex = 0; triIndex < triList.Count; triIndex++) { if (triContainedInBox(triList[triIndex], x, z, x + qnWidth, z + qnWidth)) { triList[triIndex].ensureWinding(); rqn.mTris.Add(triList[triIndex]); rqn.mOwnerQNIndex = qnX * numQNs + qnZ; } } if (rqn.mTris.Count != 0) { roadQNs.Add(rqn); } } } //Step 4, write road chunk to disk.///////////////////////////////////////////// ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); //Filename string fName = CoreGlobals.getWorkPaths().mRoadsPath + "\\" + rd.getRoadTextureName(); fName = fName.Remove(0, CoreGlobals.getWorkPaths().mGameArtDirectory.Length + 1); char[] filename = new char[32]; fName.CopyTo(0, filename, 0, fName.Length); binWriter.Write(filename); ExportTo360.addTextureChannelDependencies(CoreGlobals.getWorkPaths().mRoadsPath + "\\" + rd.getRoadTextureName()); float zero = 0; int totalMemory = 0; //write our chunks binWriter.Write(Xbox_EndianSwap.endSwapI32(roadQNs.Count)); for (int qnI = 0; qnI < roadQNs.Count; qnI++) { binWriter.Write(Xbox_EndianSwap.endSwapI32(roadQNs[qnI].mOwnerQNIndex)); binWriter.Write(Xbox_EndianSwap.endSwapI32(roadQNs[qnI].mTris.Count)); int memSize = roadQNs[qnI].mTris.Count * (3 * (sizeof(short) * 6)); binWriter.Write(Xbox_EndianSwap.endSwapI32(memSize)); List <float> vList = new List <float>(); for (int c = 0; c < roadQNs[qnI].mTris.Count; c++) { for (int i = 0; i < 3; i++) { vList.Add(roadQNs[qnI].mTris[c].mVerts[i].mPos.X); vList.Add(roadQNs[qnI].mTris[c].mVerts[i].mPos.Y); vList.Add(roadQNs[qnI].mTris[c].mVerts[i].mPos.Z); vList.Add(zero); //padd; vList.Add(roadQNs[qnI].mTris[c].mVerts[i].mUv0.X); vList.Add(roadQNs[qnI].mTris[c].mVerts[i].mUv0.Y); } } float16[] sList = BMathLib.Float32To16Array(vList.ToArray()); for (int c = 0; c < vList.Count; c++) { ushort s = ((ushort)sList[c].getInternalDat()); binWriter.Write(Xbox_EndianSwap.endSwapI16(s)); } totalMemory += memSize; } ExportTo360.mECF.addChunk((int)eXTT_ChunkID.cXTT_RoadsChunk, chunkHolder, binWriter.BaseStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; roadQNs.Clear(); triList.Clear(); TimeSpan ts = DateTime.Now - n; results.terrainRoadTime = ts.TotalMinutes; results.terrainRoadMemory = totalMemory; } }
static public bool doExport(String terrainFileName, String scenarioFileName, String outputOverrideDir, ref ExportSettings expSettings, ref ExportResults results, bool doXTD, bool doXTT, bool doXTH, bool doXSD, bool doLRP, bool doDEP, bool doTAG, bool doXMB) { //This is now done outside using work topics //if (CoreGlobals.UsingPerforce == true) //{ // if (!checkPerforceFileAlloances(terrainFileName, scenarioFileName, // doXTD, doXTT, doXTH, doXSD, doLRP, doDEP, doTAG, doXMB)) // return false; //} init(); int maxValues = (doXTD?1:0) + (doXTT?1:0) + (doXTH?1:0) + (doXSD?1:0) + (doLRP?1:0) + (doDEP?1:0) + (doTAG?1:0) + (doXMB?1:0) + (expSettings.AmbientOcclusion != AmbientOcclusion.eAOQuality.cAO_Off?1:0) ; initOverrideDir(outputOverrideDir); mEPB.Init(maxValues); mEPB.setName(Path.GetFileNameWithoutExtension(terrainFileName)); mEPB.Show(); DateTime start = DateTime.Now; GC.Collect(); GC.WaitForPendingFinalizers(); mECF.clear(); mDEP.clear(); bool sofarSoGood = true; if (sofarSoGood && doXTT) { XTTExporter XTTexporter = new XTTExporter(); sofarSoGood &= XTTexporter.export_XTT(terrainFileName, expSettings, ref results); XTTexporter.destroy(); XTTexporter = null; ExportTo360.mECF.clear(); ExportProgressDialog.Increase(); } //From here on out we don't need textures in memory.. if (sofarSoGood && (expSettings.AmbientOcclusion != AmbientOcclusion.eAOQuality.cAO_Off || doXTH)) { BRenderDevice.getTextureManager().freeAllD3DTextureHandles(); } if (sofarSoGood && doXTD) { XTDExporter XTDexporter = new XTDExporter(); sofarSoGood &= XTDexporter.export_XTD(terrainFileName, expSettings, ref results); XTDexporter.destroy(); XTDexporter = null; ExportTo360.mECF.clear(); ExportProgressDialog.Increase(); } if (sofarSoGood && doXSD) { XSDExporter XSDexporter = new XSDExporter(); sofarSoGood &= XSDexporter.export_XSD(scenarioFileName, expSettings, ref results); XSDexporter.destroy(); if (sofarSoGood && doLRP) { sofarSoGood &= XSDexporter.CreateLRP(spliceFilenameWithOverride(scenarioFileName)); } XSDexporter = null; ExportTo360.mECF.clear(); ExportProgressDialog.Increase(); } if (sofarSoGood && doXTH) { XTHExporter XTHexporter = new XTHExporter(); sofarSoGood &= XTHexporter.export_XTH(terrainFileName, expSettings, ref results); XTHexporter.destroy(); XTHexporter = null; ExportTo360.mECF.clear(); ExportProgressDialog.Increase(); } // OVERRIDE! if ANY terrain files are changed, then generate a .TAG if (sofarSoGood && doTAG && (doXTT | doXTD | doXTH | doXSD)) { TAG mTAG = new TAG(); String[] extentions = new String[] { ".XTD", ".XTT", ".XTH", ".XSD", ".LRP" }; String desiredFilename = ""; for (int i = 0; i < extentions.Length - 1; i++) { desiredFilename = spliceFilenameWithOverride(Path.ChangeExtension(terrainFileName, extentions[i])); mTAG.addFile(desiredFilename); } //XSD desiredFilename = spliceFilenameWithOverride(Path.ChangeExtension(scenarioFileName, extentions[extentions.Length - 2])); mTAG.addFile(desiredFilename); desiredFilename = spliceFilenameWithOverride(Path.ChangeExtension(scenarioFileName, extentions[extentions.Length - 1])); mTAG.addFile(desiredFilename); mTAG.writeToFile(spliceFilenameWithOverride(Path.ChangeExtension(scenarioFileName, ".TAG"))); mTAG = null; ExportProgressDialog.Increase(); } if (sofarSoGood && doXTT && doDEP) //CLM XTT is the only one that marks dependents currently... { mDEP.writeToFile(spliceFilenameWithOverride(terrainFileName)); } if (sofarSoGood && doXMB) { string outputDir = null; if (mOutputOverrideDir != null) { outputDir = spliceFilenameWithOverride(terrainFileName); outputDir = Path.GetDirectoryName(outputDir); } if (File.Exists(Path.ChangeExtension(scenarioFileName, ".SCN"))) { XMBProcessor.CreateXMB(Path.ChangeExtension(scenarioFileName, ".SCN"), outputDir, false); } if (File.Exists(Path.ChangeExtension(scenarioFileName, ".GLS"))) { XMBProcessor.CreateXMB(Path.ChangeExtension(scenarioFileName, ".GLS"), outputDir, false); } if (File.Exists(Path.ChangeExtension(scenarioFileName, ".DEP"))) { XMBProcessor.CreateXMB(spliceFilenameWithOverride(Path.ChangeExtension(scenarioFileName, ".DEP")), false); } ExportProgressDialog.Increase(); } TimeSpan ts = DateTime.Now - start; results.totalTime = ts.TotalMinutes; destroy(); GC.Collect(); GC.WaitForPendingFinalizers(); //if we've cleared the textures, force them to reload.. if (expSettings.AmbientOcclusion != AmbientOcclusion.eAOQuality.cAO_Off || doXTH) { BRenderDevice.getTextureManager().reloadTexturesIfNeeded(true); } mOutputOverrideDir = null; return(sofarSoGood); }
static public bool doExport(String baseFilename, ref ExportSettings expSettings, ref ExportResults results, bool doXTD, bool doXTT, bool doXTH, bool doXSD, bool doLRP, bool doDEP, bool doTAG, bool doXMB) { return(doExport(baseFilename, baseFilename, null, ref expSettings, ref results, doXTD, doXTT, doXTH, doXSD, doLRP, doDEP, doTAG, doXMB)); }
static public bool doExport(String terrainFileName, string scenarioFileName, ref ExportSettings expSettings, ref ExportResults results) { return(doExport(terrainFileName, scenarioFileName, null, ref expSettings, ref results, true, true, true, true, true, true, true, false)); }
//functions static public bool doExport(String baseFilename, ref ExportSettings expSettings, ref ExportResults results) { return(doExport(baseFilename, baseFilename, null, ref expSettings, ref results, true, true, true, true, true, true, true, false)); }
public bool export_XTD(string filename, ExportSettings expSettings, ref ExportResults results) { DateTime start = DateTime.Now; //write the header for the entire XTD file XTDVisualHeader header = new XTDVisualHeader(); header.version = (int)eFileVersions.cXTDVersion; header.numXVerts = TerrainGlobals.getTerrain().getNumXVerts(); header.numXChunks = (int)(TerrainGlobals.getTerrain().getNumXVerts() / BTerrainQuadNode.cMaxWidth); header.tileScale = TerrainGlobals.getTerrain().getTileScale(); BBoundingBox simRepBB = SimGlobals.getSimMain().getBBoxForDecalObjects(); Vector3 visRepMin = TerrainGlobals.getTerrain().getQuadNodeRoot().getDesc().m_min - new Vector3(0, header.tileScale, 0); Vector3 visRepMax = TerrainGlobals.getTerrain().getQuadNodeRoot().getDesc().m_max + new Vector3(0, header.tileScale, 0); if (!CoreGlobals.mbLoadTerrainVisRep) { visRepMin = simRepBB.min; visRepMax = simRepBB.max; } header.worldMin = visRepMin; header.worldMax = visRepMax; header.endianSwap(); //write our header first. ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); binWriter.Write(ExportTo360.StructToByteArray(header)); ExportTo360.mECF.addChunk((int)eXTD_ChunkID.cXTD_XTDHeader, chunkHolder, (int)chunkHolder.mDataMemStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; header.endianSwap(); generateGridChunks(ref header); writeAtlasToMemory(ref results); writeAOData(ref results); writeAlpha(ref results); writeTessData(expSettings.RefineTerrain, expSettings.RefineEpsilon, expSettings.RefineMinorityBias, ref results); writeLightData(ref expSettings, ref results); bool exportOK = ExportTo360.safeECFFileWrite(filename, ".XTD"); TimeSpan ts = DateTime.Now - start; results.totalTime = ts.TotalMinutes; return(exportOK); }
public void writeAtlasToMemory(ref ExportResults results) { int len = TerrainGlobals.getTerrain().getNumZVerts() * TerrainGlobals.getTerrain().getNumXVerts(); ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); #region 32bit pos Vector3 min = new Vector3(9000, 9000, 9000); Vector3 max = new Vector3(-9000, -9000, -9000); Vector3 range = new Vector3(0, 0, 0); findMaxsMinsRange(ref max, ref min, ref range); Vector3 adjustedMidValue = calcAdjustedMidValue(min); //write our mins & ranges (shoudl use XTDAtlasVisual here..) binWriter.Write(Xbox_EndianSwap.endSwapF32(adjustedMidValue.X)); binWriter.Write(Xbox_EndianSwap.endSwapF32(adjustedMidValue.Y)); binWriter.Write(Xbox_EndianSwap.endSwapF32(adjustedMidValue.Z)); binWriter.Write(0); //padd to allow 360 to read XMVECTOR from disk binWriter.Write(Xbox_EndianSwap.endSwapF32(range.X)); binWriter.Write(Xbox_EndianSwap.endSwapF32(range.Y)); binWriter.Write(Xbox_EndianSwap.endSwapF32(range.Z)); binWriter.Write(0); //padd to allow 360 to read XMVECTOR from disk //CLM i'm trying this out... long currLen = binWriter.BaseStream.Position; binWriter.BaseStream.SetLength(currLen + ((sizeof(int) * len) * 2)); //make sure we swizzle it... Vector3[] detail = TerrainGlobals.getEditor().getDetailPoints(); Int32[] tmpArray = new Int32[len]; for (int i = 0; i < len; i++) { tmpArray[i] = (int)packPosTo32Bits(detail[i], min, range); } ExportTo360.tileCopy(ref tmpArray, tmpArray, TerrainGlobals.getTerrain().getNumXVerts(), TerrainGlobals.getTerrain().getNumZVerts()); for (int i = 0; i < len; i++) { binWriter.Write(Xbox_EndianSwap.endSwapI32((int)tmpArray[i]));//(int)packPosTo32Bits(expData.mTerrainPoints[i],min,range))); } #endregion #region 32bit normal Vector3[] normals = TerrainGlobals.getEditor().getNormals(); for (int i = 0; i < len; i++) { tmpArray[i] = (int)packNormTo32Bits(normals[i]); } ExportTo360.tileCopy(ref tmpArray, tmpArray, TerrainGlobals.getTerrain().getNumXVerts(), TerrainGlobals.getTerrain().getNumZVerts()); for (int i = 0; i < len; i++) { binWriter.Write(Xbox_EndianSwap.endSwapI32((int)tmpArray[i]));//(int)packPosTo32Bits(expData.mTerrainPoints[i],min,range))); } #endregion tmpArray = null; ExportTo360.mECF.addChunk((int)eXTD_ChunkID.cXTD_AtlasChunk, chunkHolder, binWriter.BaseStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; results.terrainPositionMemorySize = len * sizeof(UInt32); results.terrainNormalsMemorySize = len * sizeof(UInt32); normals = null; detail = null; }
private void writeLightData(ref ExportSettings settings, ref ExportResults results) { if (!LightManager.hasTerrainLightData()) { return; } DateTime n = DateTime.Now; int width = TerrainGlobals.getTerrain().getNumXVerts(); int height = TerrainGlobals.getTerrain().getNumZVerts(); Vector3 [] lht = new Vector3[width * height]; //CLM this needs to be changed for batch exporting! LightManager.rasterTerrainLightsToExportGrid(lht); //convert our data to a DXT1 texture! //CLM this is swapped all to shit... WTF!? byte[] inData = new byte[width * height * 4]; int c = 0; //for (int i = 0; i < lht.Length; i++) for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { //as an encoding step, divide by our overbright (2) //now convert back to srgb int i = x * width + y; Vector3 v = lht[i]; v.X = (float)Math.Sqrt(BMathLib.Clamp((float)(v.X * 0.5), 0, 1)); v.Y = (float)Math.Sqrt(BMathLib.Clamp((float)(v.Y * 0.5), 0, 1)); v.Z = (float)Math.Sqrt(BMathLib.Clamp((float)(v.Z * 0.5), 0, 1)); inData[c++] = (byte)(BMathLib.Clamp(v.Z * 255 + 0.5f, 0, 255)); inData[c++] = (byte)(BMathLib.Clamp(v.Y * 255 + 0.5f, 0, 255)); inData[c++] = (byte)(BMathLib.Clamp(v.X * 255 + 0.5f, 0, 255)); inData[c++] = 0; } } byte[] outDat = null; int outMemSize = 0; ExportTo360.toCompressedFormat(inData, width, height, sizeof(UInt32), BDXTFormat.cDXT1, settings.ExportTextureCompressionQuality, ref outDat, ref outMemSize); //endianswap this data... int count = outMemSize; for (int i = 0; i < count - 1; i += 2) { byte a = outDat[i]; outDat[i] = outDat[i + 1]; outDat[i + 1] = a; } //tileswap byte[] tempbytearray = new byte[outDat.Length]; outDat.CopyTo(tempbytearray, 0); ExportTo360.tileCopy(ref tempbytearray, tempbytearray, (int)width, (int)height, (int)ExportTo360.eTileCopyFormats.cTCFMT_DXT1); tempbytearray.CopyTo(outDat, 0); tempbytearray = null; //WRITE THE CHUNK ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); //just write the DXT1 texture binWriter.Write(Xbox_EndianSwap.endSwapI32(outMemSize)); binWriter.Write(outDat); ExportTo360.mECF.addChunk((int)eXTD_ChunkID.cXTD_LightingChunk, chunkHolder, binWriter.BaseStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; results.terrainLightingMemorySize = outMemSize; TimeSpan ts = DateTime.Now - n; results.terrainLightingTime = ts.TotalMinutes; lht = null; inData = null; outDat = null; }
private void writeTessData(bool refineTerrain, float eLOD, float minorityBias, ref ExportResults results) { ECF.ECFChunkHolder chunkHolder = new ECF.ECFChunkHolder(); chunkHolder.mDataMemStream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(chunkHolder.mDataMemStream); //write the 'header' int nodeWidth = 16; int numXPatches = (int)(TerrainGlobals.getTerrain().getNumXVerts() / (float)nodeWidth); int numZPatches = (int)(TerrainGlobals.getTerrain().getNumXVerts() / (float)nodeWidth); int numXChunks = (int)(TerrainGlobals.getTerrain().getNumXVerts() / (float)BTerrainQuadNode.getMaxNodeDepth()); int numPatches = numXPatches * numZPatches; binWriter.Write(Xbox_EndianSwap.endSwapI32(numXPatches)); binWriter.Write(Xbox_EndianSwap.endSwapI32(numZPatches)); //do this for each patch byte[] tDat = new byte[numPatches]; Vector4[] bbDat = new Vector4[numPatches * 2]; //CLM - instead of writing floating point values (and taking up more memory) //write indexes into our discrete step array if (refineTerrain) { ErrorMetricRefine refiner = null; refiner = new ErrorMetricRefine(); refiner.init(TerrainGlobals.getTerrain().getNumXVerts(), TerrainGlobals.getTerrain().getNumZVerts()); refiner.refine(eLOD);//, nodeWidth + 1); markOverrideTessellations(refiner); for (int x = 0; x < numXPatches; x++) { for (int z = 0; z < numZPatches; z++) { int xMinVert = x * nodeWidth; int zMinVert = z * nodeWidth; tDat[x + z * numXPatches] = giveMaxTesselation(ref refiner, xMinVert, zMinVert, nodeWidth, minorityBias); } } refiner.destroy(); refiner = null; smoothTessNeighbors(tDat, numXPatches, numZPatches); } else { for (int i = 0; i < numPatches; i++) { tDat[i] = 0; } } //write to the disk for (int i = 0; i < tDat.Length; i++) { binWriter.Write(tDat[i]); } //generate and write our bounding boxes for (int x = 0; x < numXPatches; x++) { for (int z = 0; z < numZPatches; z++) { Vector4 min = new Vector4(9000, 9000, 9000, 0); Vector4 max = new Vector4(-9000, -9000, -9000, 0); for (int i = 0; i < nodeWidth + 1; i++) { for (int j = 0; j < nodeWidth + 1; j++) { int xVal = x * nodeWidth + i; int zVal = z * nodeWidth + j; if (xVal >= TerrainGlobals.getTerrain().getNumXVerts() || zVal >= TerrainGlobals.getTerrain().getNumXVerts()) { continue; } long kIndex = xVal + TerrainGlobals.getTerrain().getNumXVerts() * zVal; Vector3 v = TerrainGlobals.getTerrain().getPos(xVal, zVal); if (v.X < min.X) { min.X = v.X; } if (v.Y < min.Y) { min.Y = v.Y; } if (v.Z < min.Z) { min.Z = v.Z; } if (v.X > max.X) { max.X = v.X; } if (v.Y > max.Y) { max.Y = v.Y; } if (v.Z > max.Z) { max.Z = v.Z; } } } //NOTE: THE GAME EXPECTS THIS DATA IN NON-SWIZZLED FORM int q = x + z * numZPatches; q *= 2; bbDat[q] = min; bbDat[q + 1] = max; } } for (int i = 0; i < bbDat.Length; i++) { binWriter.Write(Xbox_EndianSwap.endSwapF32(bbDat[i].X)); binWriter.Write(Xbox_EndianSwap.endSwapF32(bbDat[i].Y)); binWriter.Write(Xbox_EndianSwap.endSwapF32(bbDat[i].Z)); binWriter.Write(Xbox_EndianSwap.endSwapF32(bbDat[i].W)); } ExportTo360.mECF.addChunk((int)eXTD_ChunkID.cXTD_TessChunk, chunkHolder, binWriter.BaseStream.Length); binWriter.Close(); binWriter = null; chunkHolder.Close(); chunkHolder = null; results.terrainTessValuesMemorySize = tDat.Length + (bbDat.Length * sizeof(float) * 4); tDat = null; bbDat = null; }