diff --git a/DS_Map/BuildingEditor.cs b/DS_Map/BuildingEditor.cs index f36c737..474c9e3 100644 --- a/DS_Map/BuildingEditor.cs +++ b/DS_Map/BuildingEditor.cs @@ -51,29 +51,14 @@ namespace DSPRE { string writingPath = Path.GetTempPath() + "BLDtexture.nsbtx"; byte[] txFile = File.ReadAllBytes(readingPath); - using (BinaryReader reader = new BinaryReader(new MemoryStream(txFile))) { - - reader.BaseStream.Position = 0x8; - int nsbmdSize = reader.ReadInt32(); // Read size of NSBMD file - - reader.BaseStream.Position = 0x14; - int texturesOffset = reader.ReadInt32(); // Read starting offset of embedded textures sections - - int texturesSize = nsbmdSize - texturesOffset + 0x14; // Calculate size of embedded textures section - reader.BaseStream.Position = texturesOffset; - - int lastReadPos; - using (BinaryWriter writer = new BinaryWriter(new FileStream(writingPath, FileMode.Create))) { - writer.Write(DSUtils.BuildNSBTXHeader(texturesSize)); - lastReadPos = (int)reader.BaseStream.Position; - writer.Write(txFile, lastReadPos, txFile.Length - lastReadPos); - } - } + DSUtils.WriteToFile(writingPath, DSUtils.GetTexturesFromTexturedNSBMD(txFile), fromScratch: true); } private void FillListBox(bool interior) { int modelCount = Directory.GetFiles(folder + rom.GetBuildingModelsDirPath(interior)).Length; for (int currentIndex = 0; currentIndex < modelCount; currentIndex++) { - using (BinaryReader reader = new BinaryReader(File.OpenRead(folder + rom.GetBuildingModelsDirPath(interior) + "\\" + currentIndex.ToString("D4")))) { + string filePath = folder + rom.GetBuildingModelsDirPath(interior) + "\\" + currentIndex.ToString("D4"); + + using (BinaryReader reader = new BinaryReader(File.OpenRead(filePath))) { string nsbmdName = ReadNSBMDname(reader); buildingEditorBldListBox.Items.Add("[" + currentIndex.ToString("D3") + "] " + nsbmdName); } diff --git a/DS_Map/DSUtils.cs b/DS_Map/DSUtils.cs index b8e1f03..4cb1086 100644 --- a/DS_Map/DSUtils.cs +++ b/DS_Map/DSUtils.cs @@ -1,39 +1,68 @@ -using NarcAPI; +using LibNDSFormats.NSBMD; +using NarcAPI; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; +using System.Text; using System.Windows.Forms; using static DSPRE.RomInfo; namespace DSPRE { - static class DSUtils { - public static void WriteToFile(string filepath, byte[] bytesToWrite, uint writeAt = 0, int readFrom = 0) { + public static class DSUtils { + + public const int NSBMD_DOESNTHAVE_TEXTURE = 0; + public const int NSBMD_HAS_TEXTURE = 1; + + public static void WriteToFile(string filepath, byte[] bytesToWrite, uint writeAt = 0, int readFrom = 0, bool fromScratch = false) { + if (fromScratch) + File.Delete(filepath); + using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(filepath))) { writer.BaseStream.Position = writeAt; writer.Write(bytesToWrite, readFrom, bytesToWrite.Length - readFrom); } } + public static byte[] ReadFromFile(string filepath, long startOffset = 0, long numberOfBytes = 0) { - FileStream f = File.OpenRead(filepath); - BinaryReader reader = new BinaryReader(f); - reader.BaseStream.Position = startOffset; byte[] buffer = null; - try { - if (numberOfBytes == 0) { - buffer = reader.ReadBytes((int)(f.Length - reader.BaseStream.Position)); - } else { - buffer = reader.ReadBytes((int)numberOfBytes); + FileStream f = File.OpenRead(filepath); + using (BinaryReader reader = new BinaryReader(f)) { + reader.BaseStream.Position = startOffset; + + try { + if (numberOfBytes == 0) { + buffer = reader.ReadBytes((int)(f.Length - reader.BaseStream.Position)); + } else { + buffer = reader.ReadBytes((int)numberOfBytes); + } + } catch (EndOfStreamException) { + Console.WriteLine("Stream ended"); } - } catch (EndOfStreamException) { - Console.WriteLine("Stream ended"); - } finally { - reader.Dispose(); } return buffer; } + public static byte[] ReadFromByteArray(byte[] input, long readFrom = 0, long numberOfBytes = 0) { + byte[] buffer = null; + + using (BinaryReader reader = new BinaryReader(new MemoryStream(input))) { + reader.BaseStream.Position = readFrom; + + try { + if (numberOfBytes == 0) { + buffer = reader.ReadBytes((int)(input.Length - reader.BaseStream.Position)); + } else { + buffer = reader.ReadBytes((int)numberOfBytes); + } + } catch (EndOfStreamException) { + Console.WriteLine("Stream ended"); + } + } + return buffer; + } public static int DecompressOverlay(int overlayNumber, bool makeBackup) { String overlayFilePath = GetOverlayPath(overlayNumber); @@ -204,10 +233,11 @@ namespace DSPRE { opened.ExtractToFolder(paths.unpackedPath); - if (progress != null) + if (progress != null) { try { progress.Value++; } catch (ArgumentOutOfRangeException) { } + } } } } @@ -228,32 +258,104 @@ namespace DSPRE { mdl0Data = modelReader.ReadBytes((int)mdl0Size); } - using (BinaryWriter writer = new BinaryWriter(new MemoryStream())) { + MemoryStream output = new MemoryStream(); + using (BinaryWriter writer = new BinaryWriter(output)) { writer.Write(nsbmdHeaderData); // Write first header bytes, same for all NSBMD. writer.Write(mdl0Size + 0x14); writer.Write((short)0x10); // Writes BMD0 header size (always 16) writer.Write((short)0x1); // Write new number of sub-files, since embedded textures are removed - writer.Write(0x14); // Writes new start offset of MDL0 + writer.Write((uint)0x14); // Writes new start offset of MDL0 writer.Write(mdl0Data); // Writes MDL0; - - return ((MemoryStream)writer.BaseStream).ToArray(); } + return output.ToArray(); } - public static byte[] BuildNSBTXHeader(int texturesSize) { + public static byte[] BuildNSBTXHeader(uint texturesSize) { MemoryStream ms = new MemoryStream(); using (BinaryWriter bw = new BinaryWriter(ms)) { - bw.Write((UInt32)0x30585442); // Write magic code BTX0 - bw.Write((UInt16)0xFEFF); // Byte order - bw.Write((UInt16)0x0001); // ??? - bw.Write((UInt32)texturesSize); // Write size of textures block - bw.Write((UInt16)0x0010); //Header size??? - bw.Write((UInt16)0x0001); //Number of blocks??? - bw.Write((UInt32)0x00000014); // Offset to block + bw.Write(Encoding.UTF8.GetBytes("BTX0")); // Write magic code BTX0 + bw.Write((ushort)0xFEFF); // Byte order + bw.Write((ushort)0x0001); // ??? + bw.Write(texturesSize); // Write size of textures block + bw.Write((short)0x10); //Header size + bw.Write((short)0x01); //Number of sub-files??? + bw.Write((uint)0x14); // Offset to sub-file } return ms.ToArray(); } + + public static byte[] GetTexturesFromTexturedNSBMD(byte[] modelFile) { + using (BinaryReader byteArrReader = new BinaryReader(new MemoryStream(modelFile))) { + byteArrReader.BaseStream.Position = 20; + int texAbsoluteOffset = byteArrReader.ReadInt32(); + + byteArrReader.BaseStream.Position = texAbsoluteOffset + 4; + uint textureSize = byteArrReader.ReadUInt32(); + + byte[] nsbtxHeader = DSUtils.BuildNSBTXHeader(20 + textureSize); + byte[] texData = DSUtils.ReadFromByteArray(modelFile, readFrom: texAbsoluteOffset); + + byte[] output = new byte[nsbtxHeader.Length + texData.Length]; + Buffer.BlockCopy(nsbtxHeader, 0, output, 0, nsbtxHeader.Length); + Buffer.BlockCopy(texData, 0, output, nsbtxHeader.Length, texData.Length); + return output; + } + } + + public static int CheckNSBMDHeader(byte[] modelFile) { + using (BinaryReader byteArrReader = new BinaryReader(new MemoryStream(modelFile))) { + if (byteArrReader.ReadUInt32() != NSBMD.NDS_TYPE_BMD0) { + MessageBox.Show("Please select an NSBMD file.", "Invalid File", MessageBoxButtons.OK, MessageBoxIcon.Error); + return -1; + } + + byteArrReader.BaseStream.Position = 0xE; + return byteArrReader.ReadInt16() >= 2 ? NSBMD_HAS_TEXTURE : NSBMD_DOESNTHAVE_TEXTURE; + } + } + + public static byte[] BuildNSBMDwithTextures(byte[] nsbmd, byte[] nsbtx) { + byte[] wholeTEX0 = GetFirstBlock(nsbtx); + byte[] wholeMDL0 = GetFirstBlock(nsbmd); + + MemoryStream ms = new MemoryStream(); + using (BinaryReader nsbmdReader = new BinaryReader(new MemoryStream(nsbmd))) { + using (BinaryWriter msWriter = new BinaryWriter(ms)) { + msWriter.Write(nsbmdReader.ReadInt32()); //BMD0 segment + msWriter.Write(nsbmdReader.ReadInt32()); //Byte order??? segment + msWriter.Write(wholeMDL0.Length + wholeTEX0.Length + NSBMD.HEADERSIZE); + nsbmdReader.BaseStream.Position += 4; + + msWriter.Write(nsbmdReader.ReadUInt16()); //Header size, always 16 + msWriter.Write((ushort)0x2); //Number of blocks, now it's 2 because we are inserting textures + nsbmdReader.BaseStream.Position += 2; + + msWriter.Write((uint)msWriter.BaseStream.Position + (4 * 2)); //Absolute offset to model data. We are gonna have to write two offsets + nsbmdReader.BaseStream.Position += 4; + msWriter.Write((uint)nsbmdReader.ReadUInt32()); //Copy offset to TEX0 + msWriter.Write(wholeMDL0); + msWriter.Write(wholeTEX0); + } + } + return ms.ToArray(); + } + + private static byte[] GetFirstBlock(byte[] NSBFile) { + int blockSize; + uint offsetToMainBlock; + using (BinaryReader reader = new BinaryReader(new MemoryStream(NSBFile))) { + reader.BaseStream.Position = 16; + offsetToMainBlock = reader.ReadUInt32(); + + reader.BaseStream.Position = offsetToMainBlock + 4; + blockSize = reader.ReadInt32(); + } + byte[] blockData = new byte[blockSize]; + Buffer.BlockCopy(NSBFile, (int)offsetToMainBlock, blockData, 0, blockSize); + + return blockData; + } } } diff --git a/DS_Map/LibNDSFormats/NSBCA/NSBCALoader.cs b/DS_Map/LibNDSFormats/NSBCA/NSBCALoader.cs index 39a57d5..be526b3 100644 --- a/DS_Map/LibNDSFormats/NSBCA/NSBCALoader.cs +++ b/DS_Map/LibNDSFormats/NSBCA/NSBCALoader.cs @@ -5,13 +5,11 @@ using System.Text; using System.IO; using LibNDSFormats.NSBMD; -namespace LibNDSFormats.NSBCA -{ +namespace LibNDSFormats.NSBCA { /// /// Loader for NSBCA files & data. /// - public static class NSBCALoader - { + public static class NSBCALoader { #region Methods (2) // Public Methods (2) @@ -21,27 +19,24 @@ namespace LibNDSFormats.NSBCA /// /// Stream to use. /// Material definitions. - public static IEnumerable LoadNsbca(Stream stream) - { + public static IEnumerable LoadNsbca(Stream stream) { List animation = new List(); var reader = new EndianBinaryReader(stream, Endianness.LittleEndian); byte[] id = reader.ReadBytes(4); - if (id == new byte[] { 0x42, 0x43, 0x41, 0x30 }) - { - throw new Exception(); + if (id == new byte[] { 0x42, 0x43, 0x41, 0x30 }) { + throw new Exception(); } - int i = reader.ReadInt32(); - if (i == NSBMD.NSBMD.NDS_TYPE_MAGIC1) - { + + reader.BaseStream.Position += 2; + int i = reader.ReadUInt16(); + if (i == NSBMD.NSBMD.NDS_TYPE_UNK1) { i = reader.ReadInt32(); - if (i == stream.Length) - { + if (i == stream.Length) { int numblock = reader.ReadInt32(); numblock >>= 16; int r = reader.ReadInt32(); id = reader.ReadBytes(4); - if (numblock == 1 && r == 0x14) - { + if (numblock == 1 && r == 0x14) { animation.AddRange(ReadJnt0(stream, 0x14)); } } @@ -55,11 +50,9 @@ namespace LibNDSFormats.NSBCA /// /// File to use. /// Material definitions. - public static IEnumerable LoadNsbca(FileInfo fileInfo) - { + public static IEnumerable LoadNsbca(FileInfo fileInfo) { IEnumerable result = null; - using (var fileStream = new FileStream(fileInfo.FullName, FileMode.Open)) - { + using (var fileStream = new FileStream(fileInfo.FullName, FileMode.Open)) { result = LoadNsbca(fileStream); } return result; @@ -70,8 +63,7 @@ namespace LibNDSFormats.NSBCA /// /// Stream to use. /// Material definitions. - public static IEnumerable ReadJnt0(Stream stream, int blockoffset) - { + public static IEnumerable ReadJnt0(Stream stream, int blockoffset) { EndianBinaryReader reader = new EndianBinaryReader(stream, Endianness.LittleEndian); int blocksize, blockptr, blocklimit; int num, objnum, i, j, r; @@ -104,11 +96,10 @@ namespace LibNDSFormats.NSBCA //fseek( fnsbca, 16 * num, SEEK_CUR ); // skip names blockptr += 16 * num; - for (i = 0; i < num; i++) - { + for (i = 0; i < num; i++) { reader.BaseStream.Seek(dataoffset[i], SeekOrigin.Begin); //j = getdword(); - if (reader.ReadBytes(4) == new byte[] {0x4A,0x00,0x41,0x43 }) return null; + if (reader.ReadBytes(4) == new byte[] { 0x4A, 0x00, 0x41, 0x43 }) return null; blockptr += 4; animlen.Add(getword(reader.ReadBytes(2))); @@ -127,90 +118,58 @@ namespace LibNDSFormats.NSBCA sec2offset = getdword(reader.ReadBytes(4)) + dataoffset[i]; blockptr += 8; - for (j = 0; j < objnum; j++) - { + for (j = 0; j < objnum; j++) { animation[j] = new NSBMDAnimation(); animation[j].dataoffset = getword(reader.ReadBytes(2)) + dataoffset[i]; } - for (j = 0; j < objnum; j++) - { + for (j = 0; j < objnum; j++) { NSBMD.NSBMDAnimation anim = animation[j]; r = getdword(reader.ReadBytes(4)); anim.flag = r; - // if ((r >> 1 & 1) == 0) + // if ((r >> 1 & 1) == 0) //{ // any transformation? - if ((r >> 1 & 1) == 0) - { // translation - if ((r & 4) == 1) - { // use Base T + if ((r >> 1 & 1) == 0) { // translation + if ((r & 4) == 1) { // use Base T + } else { + if ((r & 8) == 1) { // consTX + anim.m_trans[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; + } else { } - else - { - if ((r & 8) == 1) - { // consTX - anim.m_trans[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; - } - else - { - } - if ((r & 0x10) == 1) - { // consTY - anim.m_trans[1] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; - } - else - { - } - if ((r & 0x20) == 1) - { // consTZ - anim.m_trans[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; - } - else - { - } + if ((r & 0x10) == 1) { // consTY + anim.m_trans[1] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; + } else { + } + if ((r & 0x20) == 1) { // consTZ + anim.m_trans[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; + } else { } } - if ((r >> 6 & 1) == 0) - { // rotation - if ((r & 0x100) == 1) - { // constR - anim.a = ((float)getword(reader.ReadBytes(2))) / 4096.0f; - anim.b = ((float)getword(reader.ReadBytes(2))) / 4096.0f; + } + if ((r >> 6 & 1) == 0) { // rotation + if ((r & 0x100) == 1) { // constR + anim.a = ((float)getword(reader.ReadBytes(2))) / 4096.0f; + anim.b = ((float)getword(reader.ReadBytes(2))) / 4096.0f; + } else { + } + } + if ((r >> 9 & 1) == 0) { // scale + if ((r & 0x400) == 1) { // use Base S + } else { + if ((r & 0x800) == 1) { // consSX + anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; + } else { } - else - { + if ((r & 0x1000) == 1) {// consSY + anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; + } else { + } + if ((r & 0x2000) == 1) {// consSZ + anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; + } else { } } - if ((r >> 9 & 1) == 0) - { // scale - if ((r & 0x400) == 1) - { // use Base S - } - else - { - if ((r & 0x800) == 1) - { // consSX - anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; - } - else - { - } - if ((r & 0x1000) == 1) - {// consSY - anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; - } - else - { - } - if ((r & 0x2000) == 1) - {// consSZ - anim.m_scale[0] = ((float)getdword(reader.ReadBytes(4))) / 4096.0f; - } - else - { - } - } - // } + // } } animation[j] = anim; } @@ -220,8 +179,7 @@ namespace LibNDSFormats.NSBCA //free(dataoffset); return animation; } - static Int32 getdword(byte[] b) - { + static Int32 getdword(byte[] b) { Int32 v; v = b[0]; v |= b[1] << 8; @@ -229,13 +187,12 @@ namespace LibNDSFormats.NSBCA v |= b[3] << 24; return v; } - static Int32 getword(byte[] b) - { + static Int32 getword(byte[] b) { Int32 v; v = b[0]; v |= b[1] << 8; return v; - } + } #endregion Methods } } diff --git a/DS_Map/LibNDSFormats/NSBMD/NSBMD.cs b/DS_Map/LibNDSFormats/NSBMD/NSBMD.cs index 76b0b86..b074a71 100644 --- a/DS_Map/LibNDSFormats/NSBMD/NSBMD.cs +++ b/DS_Map/LibNDSFormats/NSBMD/NSBMD.cs @@ -20,12 +20,14 @@ namespace LibNDSFormats.NSBMD #region Constants - public const int NDS_TYPE_MDL0 = 0x304c444d; - public const int NDS_TYPE_TEX0 = 0x30584554; - public const int NDS_TYPE_BMD0 = 0x30444d42; - public const int NDS_TYPE_MAGIC2 = 0x0002feff; - public const int NDS_TYPE_MAGIC1 = 0x0001feff; - public const int NDS_TYPE_BTX0 = 0x30585442; + public const uint NDS_TYPE_MDL0 = 0x304c444d; + public const uint NDS_TYPE_TEX0 = 0x30584554; + public const uint NDS_TYPE_BMD0 = 0x30444d42; + public const ushort NDS_TYPE_BYTEORDER = 0xfeff; + public const ushort NDS_TYPE_UNK2 = 0x0002; + public const ushort NDS_TYPE_UNK1 = 0x0001; + public const uint NDS_TYPE_BTX0 = 0x30585442; + public const uint HEADERSIZE = 16; #endregion Constants @@ -1166,12 +1168,19 @@ namespace LibNDSFormats.NSBMD tmp = reader.ReadInt32(); if (tmp != NDS_TYPE_BMD0) throw new Exception(); - tmp = reader.ReadInt32(); - if (tmp != NDS_TYPE_MAGIC2) + + tmp = reader.ReadUInt16(); + if (tmp != NDS_TYPE_BYTEORDER) throw new Exception(); + + tmp = reader.ReadUInt16(); + if (tmp != NDS_TYPE_UNK2) + throw new Exception(); + int filesize = reader.ReadInt32(); if (filesize > stream.Length) throw new Exception(); + int numblock = reader.ReadInt32(); numblock >>= 16; if (numblock == 0) @@ -1192,11 +1201,10 @@ namespace LibNDSFormats.NSBMD for (int i = 0; i < numblock; i++) { stream.Position = blockoffset[i]; - int id = reader.ReadInt32(); + uint id = reader.ReadUInt32(); int texnum = 0, palnum = 0; - switch (id) - { + switch (id) { case NDS_TYPE_MDL0: result.models = ReadMdl0(stream, blockoffset[i]); diff --git a/DS_Map/LibNDSFormats/NSBTX/NSBTXLoader.cs b/DS_Map/LibNDSFormats/NSBTX/NSBTXLoader.cs index 61c3d34..7b617d7 100644 --- a/DS_Map/LibNDSFormats/NSBTX/NSBTXLoader.cs +++ b/DS_Map/LibNDSFormats/NSBTX/NSBTXLoader.cs @@ -37,8 +37,9 @@ namespace LibNDSFormats.NSBTX return null; } - int i = reader.ReadInt32(); - if (i == NSBMD.NSBMD.NDS_TYPE_MAGIC1) { + reader.BaseStream.Position += 2; + int i = reader.ReadUInt16(); + if (i == NSBMD.NSBMD.NDS_TYPE_UNK1) { i = reader.ReadInt32(); if (i == stream.Length) { diff --git a/DS_Map/Main Window.cs b/DS_Map/Main Window.cs index 41f5733..32c588c 100644 --- a/DS_Map/Main Window.cs +++ b/DS_Map/Main Window.cs @@ -709,6 +709,108 @@ namespace DSPRE { private void scriptCommandsDatabaseToolStripButton_Click(object sender, EventArgs e) { OpenCommandsDatabase(RomInfo.ScriptCommandNamesDict, RomInfo.CommandParametersDict); } + private void nsbmdExportTexButton_Click(object sender, EventArgs e) { + OpenFileDialog of = new OpenFileDialog { + Filter = "Textured NSBMD File(*.nsbmd)|*.nsbmd" + }; + if (of.ShowDialog(this) != DialogResult.OK) + return; + + byte[] modelFile = DSUtils.ReadFromFile(of.FileName); + if (DSUtils.CheckNSBMDHeader(modelFile) == DSUtils.NSBMD_DOESNTHAVE_TEXTURE) { + MessageBox.Show("This NSBMD file is already untextured.", "No textures to remove", MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + MessageBox.Show("Choose where to save the textures.", "Choose destination path", MessageBoxButtons.OK, MessageBoxIcon.Information); + SaveFileDialog texSf = new SaveFileDialog { + Filter = "NSBTX File(*.nsbtx)|*.nsbtx", + FileName = Path.GetFileNameWithoutExtension(of.FileName) + }; + if (texSf.ShowDialog() != DialogResult.OK) + return; + + DSUtils.WriteToFile(texSf.FileName, DSUtils.GetTexturesFromTexturedNSBMD(modelFile)); + } + + private void nsbmdRemoveTexButton_Click(object sender, EventArgs e) { + OpenFileDialog of = new OpenFileDialog { + Filter = "Textured NSBMD File(*.nsbmd)|*.nsbmd" + }; + if (of.ShowDialog(this) != DialogResult.OK) + return; + + byte[] modelFile = DSUtils.ReadFromFile(of.FileName); + if (DSUtils.CheckNSBMDHeader(modelFile) == DSUtils.NSBMD_DOESNTHAVE_TEXTURE) { + MessageBox.Show("This NSBMD file is already untextured.", "No textures to remove", MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + string extramsg = ""; + DialogResult d = MessageBox.Show("Would you like to save the removed textures to a file?", "Save textures?", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (d.Equals(DialogResult.Yes)) { + + MessageBox.Show("Choose where to save the textures.", "Choose destination path", MessageBoxButtons.OK, MessageBoxIcon.Information); + SaveFileDialog texSf = new SaveFileDialog { + Filter = "NSBTX File(*.nsbtx)|*.nsbtx", + FileName = Path.GetFileNameWithoutExtension(of.FileName) + }; + + if (texSf.ShowDialog() == DialogResult.OK) { + DSUtils.WriteToFile(texSf.FileName, DSUtils.GetTexturesFromTexturedNSBMD(modelFile)); + extramsg = " exported and"; + } + } + + MessageBox.Show("Choose where to save the untextured model.", "Choose destination path", MessageBoxButtons.OK, MessageBoxIcon.Information); + SaveFileDialog sf = new SaveFileDialog { + Filter = "Untextured NSBMD File(*.nsbmd)|*.nsbmd", + FileName = Path.GetFileNameWithoutExtension(of.FileName) + "_untextured" + }; + if (sf.ShowDialog(this) != DialogResult.OK) + return; + + DSUtils.WriteToFile(sf.FileName, DSUtils.GetModelWithoutTextures(modelFile)); + MessageBox.Show("Textures correctly" + extramsg + " removed!", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + private void nsbmdAddTexButton_Click(object sender, EventArgs e) { + OpenFileDialog of = new OpenFileDialog { + Filter = "NSBMD File(*.nsbmd)|*.nsbmd" + }; + if (of.ShowDialog(this) != DialogResult.OK) + return; + + byte[] modelFile = File.ReadAllBytes(of.FileName); + if (DSUtils.CheckNSBMDHeader(modelFile) == DSUtils.NSBMD_HAS_TEXTURE) { + DialogResult d = MessageBox.Show("This NSBMD file is already textured.\nDo you want to overwrite its textures?", "Textures found", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (d.Equals(DialogResult.No)) { + return; + } + } + + MessageBox.Show("Select the new NSBTX texture file.", "Choose NSBTX", MessageBoxButtons.OK, MessageBoxIcon.Information); + + OpenFileDialog openNsbtx = new OpenFileDialog { + Filter = "NSBTX File(*.nsbtx)|*.nsbtx" + }; + if (openNsbtx.ShowDialog(this) != DialogResult.OK) + return; + byte[] textureFile = File.ReadAllBytes(openNsbtx.FileName); + + MessageBox.Show("Choose where to save the new textured model.", "Choose destination path", MessageBoxButtons.OK, MessageBoxIcon.Information); + + string texturedPath = Path.GetFileNameWithoutExtension(of.FileName); + SaveFileDialog sf = new SaveFileDialog { + Filter = "Textured NSBMD File(*.nsbmd)|*.nsbmd", + FileName = texturedPath.Substring(0, texturedPath.Length - "_untextured".Length) + "_textured" + }; + + if (sf.ShowDialog(this) != DialogResult.OK) + return; + + DSUtils.WriteToFile(sf.FileName, DSUtils.BuildNSBMDwithTextures(modelFile, textureFile), fromScratch: true); + MessageBox.Show("Textures correctly written to NSBMD file.", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information); + } private void OpenCommandsDatabase(Dictionary namesDict, Dictionary paramsDict) { statusLabel.Text = "Setting up Commands Database. Please wait..."; Update(); @@ -6318,68 +6420,5 @@ namespace DSPRE { MessageBox.Show("AreaData File imported successfully!", "", MessageBoxButtons.OK, MessageBoxIcon.Information); } #endregion - - private void nsbmdExportTexButton_Click(object sender, EventArgs e) { - - } - - private void nsbmdRemoveTexButton_Click(object sender, EventArgs e) { - OpenFileDialog of = new OpenFileDialog(); - of.Filter = "Textured NSBMD File(*.nsbmd)|*.nsbmd"; - if (of.ShowDialog(this) != DialogResult.OK) - return; - - byte[] modelFile = DSUtils.ReadFromFile(of.FileName); - - string extramsg = ""; - using (BinaryReader reader = new BinaryReader(new MemoryStream(modelFile))) { - if (reader.ReadUInt32() != NSBMD.NDS_TYPE_BMD0) { - MessageBox.Show("Please select an NSBMD file.", "Invalid File", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - reader.BaseStream.Position = 0xE; - if (reader.ReadInt16() < 2) { - MessageBox.Show("This NSBMD file doesn't contain any textures.", "No textures found", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - DialogResult d = MessageBox.Show("Would you like to save the removed textures to a file?", "Save textures?", MessageBoxButtons.YesNo, MessageBoxIcon.Question); - if (d.Equals(DialogResult.Yes)) { - MessageBox.Show("Choose where to save the textures.", "Choose destination path", MessageBoxButtons.OK, MessageBoxIcon.Information); - - SaveFileDialog texSf = new SaveFileDialog(); - texSf.Filter = "NSBTX File(*.nsbtx)|*.nsbtx"; - texSf.FileName = Path.GetFileNameWithoutExtension(of.FileName); - if (texSf.ShowDialog(this) != DialogResult.OK) - return; - - int bmdAbsoluteOffset = reader.ReadInt32(); - int texAbsoluteOffset = reader.ReadInt32(); - - reader.BaseStream.Position = texAbsoluteOffset + 4; - int textureSize = reader.ReadInt32(); - - DSUtils.WriteToFile(texSf.FileName, DSUtils.BuildNSBTXHeader(20 + textureSize)); - DSUtils.WriteToFile(texSf.FileName, DSUtils.ReadFromFile(of.FileName, texAbsoluteOffset), 20); - - extramsg = "and exported"; - } - } - - MessageBox.Show("Choose where to save the untextured model.", "Choose destination path", MessageBoxButtons.OK, MessageBoxIcon.Information); - SaveFileDialog sf = new SaveFileDialog(); - sf.Filter = "Untextured NSBMD File(*.nsbmd)|*.nsbmd"; - sf.FileName = Path.GetFileNameWithoutExtension(of.FileName) + "_untextured"; - if (sf.ShowDialog(this) != DialogResult.OK) - return; - - DSUtils.WriteToFile(sf.FileName, DSUtils.GetModelWithoutTextures(modelFile)); - MessageBox.Show("Textures correctly removed " + extramsg + '!', "", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - private void nsbmdAddTexButton_Click(object sender, EventArgs e) { - - } } } \ No newline at end of file