public static void ExportTextures(ForgelightGame forgelightGame, CnkLOD chunk, string directory) { string name = Path.GetFileNameWithoutExtension(chunk.Name); if (name == null) { return; } directory += "/" + name.Split('_')[0]; if (!Directory.Exists(directory + @"/Textures")) { Directory.CreateDirectory(directory + @"/Textures"); } MontageSettings montageSettings = new MontageSettings(); montageSettings.TileGeometry = new MagickGeometry(2, 2); montageSettings.Geometry = new MagickGeometry(512, 512); montageSettings.BackgroundColor = MagickColor.FromRgba(0, 0, 0, 0); montageSettings.BorderColor = MagickColor.FromRgba(0, 0, 0, 0); montageSettings.BorderWidth = 0; //TODO Code Duplication //Color Map string colorMapPath = directory + @"/Textures/" + name + "_colornx" + ".dds"; if (!File.Exists(colorMapPath)) { using (MagickImageCollection stitchedColorMap = new MagickImageCollection()) { foreach (CnkLOD.Texture texture in chunk.Textures) { MagickImage textureQuad = new MagickImage(texture.ColorNXMap.ToArray()); stitchedColorMap.Add(textureQuad); } using (MagickImage result = stitchedColorMap.Montage(montageSettings)) { result.Write(colorMapPath); } } } //TODO code duplication //Specular map string specMapPath = directory + @"/Textures/" + name + "_specny" + ".dds"; if (!File.Exists(specMapPath)) { using (MagickImageCollection stitchedSpecMap = new MagickImageCollection()) { foreach (CnkLOD.Texture texture in chunk.Textures) { MagickImage textureQuad = new MagickImage(texture.SpecNyMap.ToArray()); stitchedSpecMap.Add(textureQuad); } using (MagickImage result = stitchedSpecMap.Montage(montageSettings)) { result.Write(specMapPath); } } } }
public static CnkLOD LoadFromStream(string name, string displayName, MemoryStream stream) { CnkLOD chunk = new CnkLOD(); BinaryReader binaryReader = new BinaryReader(stream); chunk.Name = name; chunk.DisplayName = displayName; //Header byte[] magic = binaryReader.ReadBytes(4); if (magic[0] != 'C' || magic[1] != 'N' || magic[2] != 'K' /* || * magic[3] != '1'*/) { return(null); } chunk.Version = binaryReader.ReadUInt32(); if (!Enum.IsDefined(typeof(ChunkType), (int)chunk.Version)) { Debug.LogWarning("Could not decode chunk " + name + ". Unknown cnk version " + chunk.Version); return(null); } chunk.ChunkType = (ChunkType)chunk.Version; chunk.DecompressedSize = binaryReader.ReadUInt32(); chunk.CompressedSize = binaryReader.ReadUInt32(); //Decompression byte[] compressedBuffer = binaryReader.ReadBytes((int)chunk.CompressedSize); byte[] decompressedBuffer = new byte[chunk.DecompressedSize]; InflateReturnCode result = LzhamInterop.DecompressForgelightData(compressedBuffer, chunk.CompressedSize, decompressedBuffer, chunk.DecompressedSize); if (result != InflateReturnCode.LZHAM_Z_STREAM_END && result != InflateReturnCode.LZHAM_Z_OK) { //This chunk is invalid. return(null); } using (MemoryStream decompressedStream = new MemoryStream(decompressedBuffer)) { binaryReader = new BinaryReader(decompressedStream); //Textures uint textureCount = binaryReader.ReadUInt32(); chunk.Textures = new List <Texture>((int)textureCount); for (int i = 0; i < textureCount; i++) { Texture texture = new Texture(); uint colorNxMapSize = binaryReader.ReadUInt32(); if (colorNxMapSize > 0) { texture.ColorNXMap = binaryReader.ReadBytes((int)colorNxMapSize).ToList(); } uint specNyMapSize = binaryReader.ReadUInt32(); if (specNyMapSize > 0) { texture.SpecNyMap = binaryReader.ReadBytes((int)specNyMapSize).ToList(); } uint extraData1Size = binaryReader.ReadUInt32(); if (extraData1Size > 0) { texture.ExtraData1 = binaryReader.ReadBytes((int)extraData1Size).ToList(); } uint extraData2Size = binaryReader.ReadUInt32(); if (extraData2Size > 0) { texture.ExtraData2 = binaryReader.ReadBytes((int)extraData2Size).ToList(); } uint extraData3Size = binaryReader.ReadUInt32(); if (extraData3Size > 0) { texture.ExtraData3 = binaryReader.ReadBytes((int)extraData3Size).ToList(); } uint extraData4Size = binaryReader.ReadUInt32(); if (extraData4Size > 0) { texture.ExtraData4 = binaryReader.ReadBytes((int)extraData4Size).ToList(); } chunk.Textures.Add(texture); } //Verts Per Side chunk.VertsPerSide = binaryReader.ReadUInt32(); //Height Maps uint heightMapCount = binaryReader.ReadUInt32(); int n = (int)(heightMapCount / 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < n; j++) { Dictionary <int, HeightMap> entry; if (!chunk.HeightMaps.ContainsKey(i)) { entry = new Dictionary <int, HeightMap>(); chunk.HeightMaps[i] = entry; } else { entry = chunk.HeightMaps[i]; } HeightMap heightMapData = new HeightMap(); heightMapData.Val1 = binaryReader.ReadInt16(); heightMapData.Val2 = binaryReader.ReadByte(); heightMapData.Val3 = binaryReader.ReadByte(); entry[j] = heightMapData; } } //Indices uint indexCount = binaryReader.ReadUInt32(); chunk.Indices = new List <ushort>((int)indexCount); for (int i = 0; i < indexCount; i++) { chunk.Indices.Add(binaryReader.ReadUInt16()); } //Verts uint vertCount = binaryReader.ReadUInt32(); chunk.Vertices = new List <Vertex>((int)vertCount); for (int i = 0; i < vertCount; i++) { Vertex vertex = new Vertex(); vertex.X = binaryReader.ReadInt16(); vertex.Y = binaryReader.ReadInt16(); vertex.HeightFar = binaryReader.ReadInt16(); vertex.HeightNear = binaryReader.ReadInt16(); vertex.Color = binaryReader.ReadUInt32(); chunk.Vertices.Add(vertex); } //TODO HACK - Daybreak, why are some chunks (that have a version 2 header) actually version 1? long offset = binaryReader.BaseStream.Position; try { //Render Batches uint renderBatchCount = binaryReader.ReadUInt32(); chunk.RenderBatches = new List <RenderBatch>((int)renderBatchCount); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); if (chunk.ChunkType == ChunkType.H1Z1_Planetside2V2) { renderBatch.Unknown = binaryReader.ReadUInt32(); } renderBatch.IndexOffset = binaryReader.ReadUInt32(); renderBatch.IndexCount = binaryReader.ReadUInt32(); renderBatch.VertexOffset = binaryReader.ReadUInt32(); renderBatch.VertexCount = binaryReader.ReadUInt32(); chunk.RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = binaryReader.ReadUInt32(); chunk.OptimizedDraws = new List <OptimizedDraw>((int)optimizedDrawCount); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = binaryReader.ReadBytes(320).ToList(); chunk.OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = binaryReader.ReadUInt32(); chunk.UnknownShorts1 = new List <ushort>((int)unknownShort1Count); for (int i = 0; i < unknownShort1Count; i++) { chunk.UnknownShorts1.Add(binaryReader.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = binaryReader.ReadUInt32(); chunk.UnknownVectors1 = new List <Vector3>((int)unknownVectors1Count); for (int i = 0; i < unknownVectors1Count; i++) { chunk.UnknownVectors1.Add(new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = binaryReader.ReadUInt32(); chunk.TileOccluderInfos = new List <TileOccluderInfo>((int)tileOccluderCount); for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = binaryReader.ReadBytes(64).ToList(); chunk.TileOccluderInfos.Add(tileOccluderInfo); } } catch (Exception) { binaryReader.BaseStream.Position = offset; //Render Batches uint renderBatchCount = binaryReader.ReadUInt32(); chunk.RenderBatches = new List <RenderBatch>((int)renderBatchCount); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); renderBatch.IndexOffset = binaryReader.ReadUInt32(); renderBatch.IndexCount = binaryReader.ReadUInt32(); renderBatch.VertexOffset = binaryReader.ReadUInt32(); renderBatch.VertexCount = binaryReader.ReadUInt32(); chunk.RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = binaryReader.ReadUInt32(); chunk.OptimizedDraws = new List <OptimizedDraw>((int)optimizedDrawCount); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = binaryReader.ReadBytes(320).ToList(); chunk.OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = binaryReader.ReadUInt32(); chunk.UnknownShorts1 = new List <ushort>((int)unknownShort1Count); for (int i = 0; i < unknownShort1Count; i++) { chunk.UnknownShorts1.Add(binaryReader.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = binaryReader.ReadUInt32(); chunk.UnknownVectors1 = new List <Vector3>((int)unknownVectors1Count); for (int i = 0; i < unknownVectors1Count; i++) { chunk.UnknownVectors1.Add(new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = binaryReader.ReadUInt32(); chunk.TileOccluderInfos = new List <TileOccluderInfo>((int)tileOccluderCount); for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = binaryReader.ReadBytes(64).ToList(); chunk.TileOccluderInfos.Add(tileOccluderInfo); } } } return(chunk); }
public static void ExportChunk(ForgelightGame forgelightGame, CnkLOD chunk, string directory) { string name = Path.GetFileNameWithoutExtension(chunk.Name); if (name == null) { return; } directory += "/" + name.Split('_')[0]; if (!Directory.Exists(directory + "/Textures")) { Directory.CreateDirectory(directory + "/Textures"); } //Textures try { //Material if (!File.Exists(directory + @"\" + name + @".mtl")) { string[] mtl = { "newmtl " + name, "Ka 1.000000 1.000000 1.000000", "Kd 1.000000 1.000000 1.000000", "Ks 0.000000 0.000000 0.000000", "d 1.0", "illum 1", "map_Ka " + name + "_colornx" + ".dds", "map_Kd " + name + "_colornx" + ".dds", "map_d " + name + "_colornx" + ".dds", "map_Ks " + name + "_colornx" + ".dds", "map_Ns " + name + "_specny" + ".dds" }; File.WriteAllLines(directory + @"\" + name + @".mtl", mtl); } } catch (IOException) {} //Heighmaps //Texture2D image = new Texture2D((int) chunk.VertsPerSide, (int) chunk.VertsPerSide); //byte[] imageData = image.GetRawTextureData(); //for (int i = 0; i < chunk.HeightMaps.Count; i++) //{ // Dictionary<int, CnkLOD.HeightMap> heightmap = chunk.HeightMaps[i]; // uint n = chunk.VertsPerSide*chunk.VertsPerSide; // for (int j = 0; j < n; j++) // { // int height = heightmap[j].Val1 + 4096; // imageData[j*4] = (byte) (height >> 8); // imageData[j*4 + 1] = (byte) (height & 0xFF); // imageData[j*4 + 2] = 0; // imageData[j*4 + 3] = 255; // } // image.LoadRawTextureData(imageData); //} //Geometry string path = directory + @"\" + name + ".obj"; if (!File.Exists(path)) { using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write)) { using (StreamWriter streamWriter = new StreamWriter(fileStream)) { try { List <string> vertices = new List <string>(); List <string> uvs = new List <string>(); List <string> faces = new List <string>(); streamWriter.WriteLine("mtllib " + name + ".mtl"); streamWriter.WriteLine("o " + name); streamWriter.WriteLine("g " + name); for (int i = 0; i < 4; i++) { uint vertexOffset = chunk.RenderBatches[i].VertexOffset; uint vertextCount = chunk.RenderBatches[i].VertexCount; for (uint j = 0; j < vertextCount; j++) { int k = (int)(vertexOffset + j); double x = chunk.Vertices[k].X + (i >> 1) * 64; double y = chunk.Vertices[k].Y + (i % 2) * 64; double heightNear = (double)chunk.Vertices[k].HeightNear / 64; vertices.Add("v " + x + " " + heightNear + " " + y); uvs.Add("vt " + (y / 128) + " " + (1 - x / 128)); } } for (int i = 0; i < 4; i++) { int indexOffset = (int)chunk.RenderBatches[i].IndexOffset; uint indexCount = chunk.RenderBatches[i].IndexCount; uint vertexOffset = chunk.RenderBatches[i].VertexOffset; for (int j = 0; j < indexCount; j += 3) { uint v0 = chunk.Indices[j + indexOffset] + vertexOffset; uint v1 = chunk.Indices[j + indexOffset + 1] + vertexOffset; uint v2 = chunk.Indices[j + indexOffset + 2] + vertexOffset; faces.Add("f " + (v2 + 1) + "/" + (v2 + 1) + " " + (v1 + 1) + "/" + (v1 + 1) + " " + (v0 + 1) + "/" + (v0 + 1)); } } foreach (string vertex in vertices) { streamWriter.WriteLine(vertex); } foreach (string uv in uvs) { streamWriter.WriteLine(uv); } streamWriter.WriteLine("usemtl " + name); foreach (string face in faces) { streamWriter.WriteLine(face); } return; } catch (Exception e) { Debug.LogError("Chunk export failed for: " + name + "\n" + e.Message + "\n" + e.StackTrace); } } } } }