public void LoadNode(EntryTreeNode node) { foreach (EntryTreeNode child in node.Nodes) { DataGridViewRow row = new DataGridViewRow(); DataGridViewTextBoxCell type = new DataGridViewTextBoxCell { Value = Helpers.FormatNicely(child.ResourceIdentifier) }; row.Cells.Add(type); DataGridViewTextBoxCell offset = new DataGridViewTextBoxCell { Value = child.ResourceOffset }; row.Cells.Add(offset); dataGridView.Rows.Add(row); } }
public static Submesh[] ExtractModel(string fileName, EntryTreeNode node, Action completionAction) { Submesh[] submeshes; using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (stream.Length == 0) { return(null); } using (BinaryReader reader = new BinaryReader(stream)) { // header DatafileHeader header = new DatafileHeader { ResourceType = reader.ReadInt32(), FileSize = reader.ReadInt32(), FileNameSize = reader.ReadInt32() }; header.FileName = reader.ReadChars(header.FileNameSize); // ignore the 2 bytes, file ID, and resource type reader.BaseStream.Seek(0x1d, SeekOrigin.Current); // block A - 1 uint aCount = reader.ReadUInt32(); Block blockA = new Block(); blockA.Bytes = new byte[aCount][]; for (int i = 0; i < aCount; i++) { blockA.Bytes[i] = reader.ReadBytes(0x51); } // block B - 1-0 Block blockB = new Block(); blockB.Bytes = new byte[2][]; for (int i = 0; i < 2; i++) { blockB.Bytes[i] = reader.ReadBytes(0x10); } // block C - 1-1 reader.BaseStream.Seek(1, SeekOrigin.Current); Block blockC = new Block(); blockC.Bytes = new byte[2][]; for (int i = 0; i < 2; i++) { blockC.Bytes[i] = reader.ReadBytes(0x11); } // block D - 1-2 reader.BaseStream.Seek(0x29, SeekOrigin.Current); uint dCount = reader.ReadUInt32(); Block blockD = new Block(); blockD.Bytes = new byte[dCount][]; for (int i = 0; i < dCount; i++) { blockD.Bytes[i] = reader.ReadBytes(0x18); } // internal/external UVs (block E) - 20 uint eCount = reader.ReadUInt32(); reader.BaseStream.Seek(eCount, SeekOrigin.Current); // vertices (block F) - 30 uint fCount = reader.ReadUInt32() / 12; long verticesOffset = reader.BaseStream.Position; Block blockF = new Block(); blockF.Bytes = new byte[fCount][]; for (int i = 0; i < fCount; i++) { blockF.Bytes[i] = reader.ReadBytes(0x0c); } // block G - 40 uint gSize = reader.ReadUInt32(); Block blockG = new Block(); blockG.Bytes = new byte[gSize][]; reader.BaseStream.Seek(gSize, SeekOrigin.Current); // faces (block) H - 50 uint hCount = reader.ReadUInt32() / 6; long facesOffset = reader.BaseStream.Position; Block blockH = new Block(); blockH.Bytes = new byte[hCount][]; for (int i = 0; i < hCount; i++) { blockH.Bytes[i] = reader.ReadBytes(0x06); } // block I - 60 uint iSize = reader.ReadUInt32(); Block blockI = new Block(); blockI.Bytes = new byte[iSize][]; reader.BaseStream.Seek(iSize, SeekOrigin.Current); // block J - 70 uint jSize = reader.ReadUInt32(); Block blockJ = new Block(); blockJ.Bytes = new byte[jSize][]; reader.BaseStream.Seek(jSize, SeekOrigin.Current); // block K - 80 uint kSize = reader.ReadUInt32(); Block blockK = new Block(); blockK.Bytes = new byte[kSize][]; reader.BaseStream.Seek(kSize, SeekOrigin.Current); // block L Block blockL = new Block(); blockL.Bytes = new byte[1][]; for (int i = 0; i < 1; i++) { blockL.Bytes[i] = reader.ReadBytes(0x12); } // block M - 90 uint mSize = reader.ReadUInt32(); // number of submeshes // create submeshes submeshes = new Submesh[mSize]; for (int i = 0; i < mSize; i++) { submeshes[i] = new Submesh(); reader.BaseStream.Seek(0x14, SeekOrigin.Current); submeshes[i].VertexCount = reader.ReadUInt32(); reader.BaseStream.Seek(0x04, SeekOrigin.Current); submeshes[i].FaceCount = reader.ReadUInt32(); reader.BaseStream.Seek(0x04, SeekOrigin.Current); } /*reader.BaseStream.Seek(0x10, SeekOrigin.Current); * * // block N - 100 * uint nSize = reader.ReadUInt32(); * Block blockN = new Block(); * blockN.Bytes = new byte[nSize][]; * for (int i = 0; i < nSize; i++) * { * blockN.Bytes[i] = reader.ReadBytes(0x1e); * } * * // block O - 110 * reader.BaseStream.Seek(0x16, SeekOrigin.Current); * uint oSize = reader.ReadUInt32(); * Block blockO = new Block(); * blockO.Bytes = new byte[nSize][]; * for (int i = 0; i < oSize; i++) * { * blockO.Bytes[i] = reader.ReadBytes(0x0a); * }*/ // get faces reader.BaseStream.Seek(facesOffset, SeekOrigin.Begin); for (int i = 0; i < submeshes.Length; i++) { submeshes[i].Faces = new Face[submeshes[i].FaceCount]; for (int j = 0; j < submeshes[i].FaceCount; j++) { submeshes[i].Faces[j] = new Face { X = reader.ReadUInt16(), Y = reader.ReadUInt16(), Z = reader.ReadUInt16() }; /*ObjParser.Types.Face f = new ObjParser.Types.Face * { * X = submeshes[i].Vertices[j].X, * Y = submeshes[i].Vertices[j].Y, * Z = submeshes[i].Vertices[j].Z * }; * faces.Add(f);*/ } } // get vertices reader.BaseStream.Seek(verticesOffset, SeekOrigin.Begin); List <ObjParser.Types.Vertex> verts = new List <ObjParser.Types.Vertex>(); for (int i = 0; i < submeshes.Length; i++) { submeshes[i].Vertices = new Vertex[submeshes[i].VertexCount]; for (int j = 0; j < submeshes[i].VertexCount; j++) { submeshes[i].Vertices[j] = new Vertex { X = reader.ReadInt16(), Y = reader.ReadInt16(), Z = reader.ReadInt16(), U = reader.ReadInt16(), V = reader.ReadInt16(), Dummy = reader.ReadInt16() }; ObjParser.Types.Vertex v = new ObjParser.Types.Vertex { X = submeshes[i].Vertices[j].X, Y = submeshes[i].Vertices[j].Y, Z = submeshes[i].Vertices[j].Z }; verts.Add(v); } } Obj obj = new Obj(); obj.VertexList = verts; obj.WriteObjFile(@"C:\Users\pinea\bag-new.obj", new string[] { "" }); completionAction(); } } return(submeshes); }
private void modelButton_Click(object sender, EventArgs e) { // get the entry node, not subentry node node = node.Type == EntryTreeNodeType.SUBENTRY ? (EntryTreeNode)node.Parent : node; string item = (string)modelComboBox.SelectedItem; saveFileDialog.FileName = node.Text; saveFileDialog.Filter = $"{item}|All Files|*.*"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { if (combineMeshesCheckBox.Checked) { switch (modelComboBox.SelectedIndex) { /*case 0: //dae * DAE.Export(saveFileDialog.FileName, model, false, false); * break;*/ case 0: //obj File.WriteAllText(saveFileDialog.FileName, OBJ.Export(model, (NormalExportMode)normalsComboBox.SelectedIndex)); break; /*case 2: //smd * File.WriteAllText(saveFileDialog.FileName, SMD.Export(model, calculateNormals)); * break; * case 3: //stl * STL.ExportBinary(saveFileDialog.FileName, model, calculateNormals); * break;*/ default: break; } Message.Success("Saved the model into a single file."); } else { for (int i = 0; i < model.Meshes.Count; i++) { string fileName = string.Concat(Path.Combine(Path.GetDirectoryName(saveFileDialog.FileName), Path.GetFileNameWithoutExtension(saveFileDialog.FileName)), "-", i, Path.GetExtension(saveFileDialog.FileName)); Model mdl = Model.CreateFromMesh(model.Meshes[i]); switch (modelComboBox.SelectedIndex) { /*case 0: //dae * DAE.Export(fileName, mdl, false, false); * break;*/ case 0: //obj File.WriteAllText(fileName, OBJ.Export(mdl, (NormalExportMode)normalsComboBox.SelectedIndex, true)); break; /*case 2: //smd * File.WriteAllText(fileName, SMD.Export(mdl, true)); * break; * case 3: //stl * STL.ExportBinary(fileName, mdl, true); * break; * default: * break;*/ } } Message.Success("Saved the model into separate files."); } } }
public void SetValues(int selectedTab, EntryTreeNode node, Model model = null) { tabControl1.SelectedIndex = selectedTab; this.node = node; this.model = model; }
public static void ExtractTextureMap(string fileName, EntryTreeNode node, Action <string> completionAction) { string name = Path.GetFileNameWithoutExtension(fileName); using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (stream.Length == 0) { return; } using (BinaryReader reader = new BinaryReader(stream)) { DatafileHeader header = new DatafileHeader { ResourceIdentifier = reader.ReadUInt32(), FileSize = reader.ReadInt32(), FileNameSize = reader.ReadInt32() }; header.FileName = reader.ReadChars(header.FileNameSize); reader.BaseStream.Seek(9, SeekOrigin.Current); // fileID + 1 skipped bytes if (header.ResourceIdentifier != (uint)ResourceIdentifier.TEXTURE_MAP) { Message.Fail("This is not proper Texture Map data."); } /*// mip 0 * TextureMap mip0 = new TextureMap * { * Width = reader.ReadInt32(), * Height = reader.ReadInt32() * }; * reader.BaseStream.Seek(4, SeekOrigin.Current); * mip0.DXT = DXTExtensions.GetDXT(reader.ReadInt32()); * reader.BaseStream.Seek(8, SeekOrigin.Current); * mip0.Mipmaps = reader.ReadInt32(); * * reader.BaseStream.Seek(39, SeekOrigin.Current); // go to next mip * * // ignore mip 1 * reader.BaseStream.Seek(28, SeekOrigin.Current); * * // locate the two mips, if they exist * if (node.GetForge().FileEntries.Where(x => x.NameTable.Name.Contains(Path.GetFileNameWithoutExtension(fileName) + "_Mip")).Count() > 0) * { * Forge.FileEntry[] mipEntries = node.GetForge().FileEntries.Where(x => x.NameTable.Name == Path.GetFileNameWithoutExtension(fileName) + "_Mip0").ToArray(); * if (mipEntries != null && mipEntries.Length > 0) * { * Forge.FileEntry mipEntry = mipEntries[0]; * * // extract, read, and create a DDS image with the first mip * byte[] rawTopMipData = node.GetForge().GetRawData(mipEntry); * * // read * byte[] topMipData = ReadFile(rawTopMipData); * File.WriteAllBytes(Helpers.GetTempPath(mipEntry.NameTable.Name + "." + Helpers.GameToExtension(node.Game)), topMipData); * * // extract * //ExtractTopMip(topMipData, mipEntry.NameTable.Name, mip0, completionAction); * } * } * else // mips do not exist. fear not! there is still image data found here. let us use that. * { * reader.BaseStream.Seek(12, SeekOrigin.Current); * * /*TextureMap map = new TextureMap(); * map.DataSize = reader.ReadInt32(); * * // test if this dataSize is too big * bool correctSize = true; * if (map.DataSize > reader.BaseStream.Length || map.DataSize < reader.BaseStream.Length - 300) // if the dataSize lies within a reasonable range * { * correctSize = false; * } * * // test again, 14 bytes later * if (!correctSize) * { * reader.BaseStream.Seek(14, SeekOrigin.Current); * map.DataSize = reader.ReadInt32(); * } * * byte[] mipmapData = reader.ReadBytes(map.DataSize); * * // write DDS file * TopMip mip = mip0; * Helpers.WriteTempDDS(name, mipmapData, mip.Width, mip.Height, mip.Mipmaps, mip.DXTType, () => * { * Helpers.ConvertDDS($"{Helpers.GetTempPath(name)}.dds", fixNormals: name.Contains("NormalMap"), completionAction: (error) => { * if (error) * completionAction("FAILED"); * else * completionAction($"{Helpers.GetTempPath(name)}.png"); * }); * });* * }*/ // TextureMap reader.BaseStream.Seek(5, SeekOrigin.Current); // identifier + 1 skipped byte TextureMap textureMap = new TextureMap { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(4, SeekOrigin.Current); // 4 skipped bytes textureMap.DXT = (DXT)reader.ReadInt32(); reader.BaseStream.Seek(8, SeekOrigin.Current); // 8 skipped bytes textureMap.Mipmaps = reader.ReadInt32(); reader.BaseStream.Seek(12, SeekOrigin.Current); // 3 skipped ints reader.BaseStream.Seek(2, SeekOrigin.Current); // CompiledTopMip CompiledTopMip[] compiledTopMips = new CompiledTopMip[reader.ReadInt32()]; reader.BaseStream.Seek(1, SeekOrigin.Current); // read CompiledTopMips for (int i = 0; i < compiledTopMips.Length; i++) { compiledTopMips[i].FileID = reader.ReadInt64(); reader.BaseStream.Seek(1, SeekOrigin.Current); // 1 skipped byte } reader.BaseStream.Seek(8, SeekOrigin.Current); // CompiledTextureMap reader.BaseStream.Seek(12, SeekOrigin.Current); // identifier + two skipped ints CompiledTextureMap compiledTextureMap = new CompiledTextureMap { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(4, SeekOrigin.Current); // 1 skipped int compiledTextureMap.Mipmaps = reader.ReadInt32(); reader.BaseStream.Seek(4, SeekOrigin.Current); // 1 skipped int compiledTextureMap.DXT = (DXT)reader.ReadInt32(); reader.BaseStream.Seek(16, SeekOrigin.Current); // 4 skipped ints // locate the parent forge tree node EntryTreeNode forgeNode = (EntryTreeNode)node.Parent.Parent; if (forgeNode.Type != EntryTreeNodeType.FORGE) { Message.Fail("Failed to locate the forge node."); return; } // check to see if there is a topmip if (compiledTopMips.Select(x => x.FileID).Count() > 0 && compiledTopMips.Select(x => x.FileID).First() != 0) { // search for file IDs from the CompiledTextureMaps if (forgeNode.Nodes.Cast <EntryTreeNode>().Where(x => x.FileID == compiledTopMips[0].FileID).Count() == 0) { if (Message.Show("Failed to locate the Mip0. Would you like to try extracting the TextureMap's internal image data?", "Failed", MessageBoxButtons.YesNo) == DialogResult.Yes) { ExtractInternalTexture(reader, textureMap, name, completionAction); return; } else { return; } } EntryTreeNode mip0Node = forgeNode.Nodes.Cast <EntryTreeNode>().Where(x => x.FileID == compiledTopMips[0].FileID).First(); if (node.GetForge().FileEntries.Where(x => x.IndexTable.FileDataID == compiledTopMips[0].FileID).Count() == 0) { Message.Fail("Failed to locate the Mip0 in the forge."); return; } Forge.FileEntry mip0Entry = node.GetForge().FileEntries.Where(x => x.IndexTable.FileDataID == compiledTopMips[0].FileID).First(); // read byte[] rawMip0Data = node.GetForge().GetRawData(mip0Entry); byte[] mip0Data = ReadFile(rawMip0Data); // save for future use File.WriteAllBytes(Helpers.GetTempPath($"{mip0Entry.NameTable.Name}.{Helpers.GameToExtension(node.Game)}"), mip0Data); // extract Odyssey.ExtractTopMip(mip0Data, mip0Entry.NameTable.Name, compiledTextureMap, completionAction); } else { // use the image data within this file ExtractInternalTexture(reader, textureMap, name, completionAction); } } } }
public static void ExtractTextureMap(string fileName, EntryTreeNode node, Action <string> completionAction) { string name = Path.GetFileNameWithoutExtension(fileName); using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (stream.Length == 0) { return; } using (BinaryReader reader = new BinaryReader(stream)) { DatafileHeader header = new DatafileHeader { ResourceType = reader.ReadInt32(), FileSize = reader.ReadInt32(), FileNameSize = reader.ReadInt32() }; header.FileName = reader.ReadChars(header.FileNameSize); // ignore the 1 byte, file ID, resource type, and 1 extra byte reader.BaseStream.Seek(14, SeekOrigin.Current); // mip 0 Mip mip0 = new Mip { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(8, SeekOrigin.Current); mip0.DXTType = DXTExtensions.GetDXT(reader.ReadInt32()); reader.BaseStream.Seek(4, SeekOrigin.Current); mip0.Mipmaps = reader.ReadInt32(); reader.BaseStream.Seek(39, SeekOrigin.Current); // go to next mip // mip 1 Mip mip1 = new Mip { Width = reader.ReadInt32(), Height = reader.ReadInt32() }; reader.BaseStream.Seek(8, SeekOrigin.Current); mip1.DXTType = DXTExtensions.GetDXT(reader.ReadInt32()); reader.BaseStream.Seek(4, SeekOrigin.Current); mip1.Mipmaps = reader.ReadInt32(); // locate the two mips, if they exist if (node.GetForge().FileEntries.Where(x => x.NameTable.Name.Contains(Path.GetFileNameWithoutExtension(fileName) + "_Mip")).Count() == 2) { Forge.FileEntry[] mipEntries = node.GetForge().FileEntries.Where(x => x.NameTable.Name == Path.GetFileNameWithoutExtension(fileName) + "_Mip0").ToArray(); if (mipEntries.Length > 0) { Forge.FileEntry mipEntry = mipEntries[0]; // extract, read, and create a DDS image with the first mip byte[] rawTopMipData = node.GetForge().GetRawData(mipEntry); //Helpers.WriteToFile(mipEntry.NameTable.Name, rawData, true); // read //ReadFile(Helpers.GetTempPath(mipEntry.NameTable.Name)); byte[] topMipData = ReadFile(rawTopMipData); // extract //ExtractTopMip(Helpers.GetTempPath(mipEntry.NameTable.Name), mip0, completionAction); ExtractTopMip(topMipData, mipEntry.NameTable.Name, mip0, completionAction); } } else // mips do not exist. fear not! there is still image data found here. let us use that. { reader.BaseStream.Seek(12, SeekOrigin.Current); TextureMap map = new TextureMap { DataSize = reader.ReadInt32() }; byte[] mipmapData = reader.ReadBytes(map.DataSize); // write DDS file Helpers.WriteTempDDS(name, mipmapData, mip1.Width, mip1.Height, mip1.Mipmaps, mip1.DXTType, () => { Helpers.ConvertDDS($"{Helpers.GetTempPath(name)}.dds", (bool error) => { if (error) { completionAction("FAILED"); } else { completionAction($"{Helpers.GetTempPath(name)}.png"); } }); }); } } } }