private void SaveMaterialToFile(string fileName) { FileOutput m = new FileOutput(); FileOutput s = new FileOutput(); int[] c = NUD.WriteMaterial(m, currentMaterialList, s); FileOutput fin = new FileOutput(); fin.writeInt(0); fin.writeInt(20 + c[0]); for (int i = 1; i < 4; i++) { fin.writeInt(c[i] == c[i - 1] ? 0 : 20 + c[i]); } for (int i = 0; i < 4 - c.Length; i++) { fin.writeInt(0); } fin.writeOutput(m); fin.align(32, 0xFF); fin.writeIntAt(fin.size(), 0); fin.writeOutput(s); fin.save(fileName); }
public int Rebuild(FileOutput o) { int size = o.size(); o.writeInt(hash); o.writeInt(unk1); o.writeByte(name.Length + 1); o.writeString(name); o.writeByte(0); o.align(4); o.writeInt(0); o.writeInt(8); o.writeInt(offset); o.writeInt(this.size); // write data foreach (float f in param) { o.writeFloat(f); } o.writeInt(offsets.Length); foreach (int f in offsets) { o.writeInt(f); } o.writeInt(unkvalues.Length); int v = 0; foreach (float f in unkvalues) { o.writeInt(v++); o.writeFloat(f); } foreach (int f in unkending) { o.writeInt(f); } foreach (int f in end) { o.writeInt(f); } return(o.size() - size); }
public int Rebuild(FileOutput o) { o.writeString("PROP"); int sizeoff = o.size(); o.writeInt(0); int size = o.size(); o.writeInt(0); o.writeInt(unk1); o.writeShort(0); o.writeShort(unk2); o.writeByte(project.Length + 1); o.writeString(project); o.writeByte(0); o.writeByte(0); o.writeByte(0); o.writeByte(0); o.align(4); o.writeShort(unk3); o.align(4); o.writeByte(timestamp.Length + 1); o.writeString(timestamp); o.writeByte(0); o.writeByte(0); o.writeByte(0); o.writeByte(0); o.align(4); size = o.size() - size; o.writeIntAt(size, sizeoff); return(size); }
public int Rebuild(FileOutput o) { o.writeString("GRP "); int sizeoff = o.size(); o.writeInt(0); int size = o.size(); o.writeInt(names.Count); int start = names.Count * 8 + 4; FileOutput name = new FileOutput(); name.Endian = Endianness.Little; int c = 0; foreach (string na in names) { o.writeInt(start + name.size()); int ns = name.pos(); name.writeInt(1); name.writeByte(na.Length == 0 ? 0xFF : na.Length + 1); name.writeString(na); name.writeByte(0); name.align(4); if (c != names.Count - 1) { name.writeInt(0); // padding } else { ns -= 4; } c++; o.writeInt(name.pos() - ns); } o.writeInt(0); o.writeOutput(name); size = o.size() - size; o.writeIntAt(size, sizeoff); return(size); }
//Saving Mat private void savePresetButton_Click(object sender, EventArgs e) { using (var sfd = new SaveFileDialog()) { sfd.Filter = "Namco Material (NMT)|*.nmt|" + "All files(*.*)|*.*"; sfd.InitialDirectory = Path.Combine(MainForm.executableDir, "materials\\"); Console.WriteLine(sfd.InitialDirectory); if (sfd.ShowDialog() == DialogResult.OK) { sfd.FileName = sfd.FileName; sfd.RestoreDirectory = true; if (sfd.FileName.EndsWith(".nmt")) { FileOutput m = new FileOutput(); FileOutput s = new FileOutput(); int[] c = NUD.WriteMaterial(m, currentMaterialList, s); FileOutput fin = new FileOutput(); fin.writeInt(0); fin.writeInt(20 + c[0]); for (int i = 1; i < 4; i++) { fin.writeInt(c[i] == c[i - 1] ? 0 : 20 + c[i]); } for (int i = 0; i < 4 - c.Length; i++) { fin.writeInt(0); } fin.writeOutput(m); fin.align(32, 0xFF); fin.writeIntAt(fin.size(), 0); fin.writeOutput(s); fin.save(sfd.FileName); } } } }
public int Rebuild(FileOutput o) { int size = o.size(); o.writeInt(hash); o.writeInt(unk1); o.writeByte(name.Length + 1); o.writeString(name); o.writeByte(0); o.align(4); // write data foreach (float f in data) { o.writeFloat(f); } return(o.size() - size); }
public int Rebuild(FileOutput o) { o.writeString("BINF"); int sizeoff = o.size(); o.writeInt(0); int size = o.size(); o.writeInt(0); o.writeInt(unk1); o.writeByte(name.Length + 1); o.writeString(name); o.writeByte(0); o.align(4); o.writeInt(flag); size = o.size() - size; o.writeIntAt(size, sizeoff); return(size); }
public override byte[] Rebuild() { FileOutput f = new FileOutput(); f.Endian = Endianness.Little; FileOutput fv = new FileOutput(); fv.Endian = Endianness.Little; f.writeShort(format); f.writeShort(unknown); f.writeInt(flags); f.writeInt(mode); bool hasNameTable = (flags & 2) > 0; f.writeInt(mesh.Count); int vertSize = 0; // Vertex Bank for (int i = 0; i < 1; i++) { if (mode == 0 || i == 0) { Descriptor des = descript[i]; if (format != 4) { foreach (Vertex v in vertices) { for (int k = 0; k < des.type.Length; k++) { fv.align(2, 0x00); switch (des.type[k]) { case 0: //Position writeType(fv, v.pos.X, des.format[k], des.scale[k]); writeType(fv, v.pos.Y, des.format[k], des.scale[k]); writeType(fv, v.pos.Z, des.format[k], des.scale[k]); break; case 1: //Normal writeType(fv, v.nrm.X, des.format[k], des.scale[k]); writeType(fv, v.nrm.Y, des.format[k], des.scale[k]); writeType(fv, v.nrm.Z, des.format[k], des.scale[k]); break; case 2: //Color writeType(fv, v.col.X, des.format[k], des.scale[k]); writeType(fv, v.col.Y, des.format[k], des.scale[k]); writeType(fv, v.col.Z, des.format[k], des.scale[k]); writeType(fv, v.col.W, des.format[k], des.scale[k]); break; case 3: //Tex0 writeType(fv, v.tx[0].X, des.format[k], des.scale[k]); writeType(fv, v.tx[0].Y, des.format[k], des.scale[k]); break; case 4: //Tex1 writeType(fv, v.tx[1].X, des.format[k], des.scale[k]); writeType(fv, v.tx[1].Y, des.format[k], des.scale[k]); break; case 5: //Bone Index fv.writeByte(v.node[0]); fv.writeByte(v.node[1]); break; case 6: //Bone Weight writeType(fv, v.weight[0], des.format[k], des.scale[k]); writeType(fv, v.weight[1], des.format[k], des.scale[k]); break; //default: // Console.WriteLine("WTF is this"); } } } vertSize = fv.size(); fv.align(32, 0xFF); } } for (int j = 0; j < mesh.Count; j++) { foreach (List <int> l in mesh[j].faces) { foreach (int index in l) { fv.writeShort(index); } fv.align(32, 0xFF); } } } for (int i = 0; i < mesh.Count; i++) { if (i == 0 && mode == 1) { descript[0].WriteDescription(f); f.writeInt(vertSize); } f.writeInt(mesh[i].nodeList.Count); //Console.WriteLine(mesh[i].faces.Count + " " + mesh[i].nodeList.Count); for (int j = 0; j < mesh[i].nodeList.Count; j++) { f.writeInt(mesh[i].nodeList[j].Count); for (int k = 0; k < mesh[i].nodeList[j].Count; k++) { f.writeInt(mesh[i].nodeList[j][k]); } f.writeInt(mesh[i].faces[j].Count); // TODO: This stuff if (hasNameTable) { //int nameId = d.readInt(); } /*if (mode == 0) * { * if (format == 4) * { * int[] buffer = new int[primitiveCount]; * for (int k = 0; k < primitiveCount; k++) * { * buffer[k] = d.readShort(); * } * d.align(4); * List<int> buf = new List<int>(); * buf.AddRange(buffer); * m.faces.Add(buf); * } * else * { * Descriptor des = new Descriptor(); * des.ReadDescription(d); * descript.Add(des); * } * * }*/ } } // TODO: STRING TABLE /*if (hasNameTable) * { * for (int i = 0; i < mesh.Count; i++) * { * int index = d.readByte(); * nameTable.Add(d.readString()); * } * }*/ if (format != 4) { f.align(32, 0xFF); } f.writeOutput(fv); return(f.getBytes()); }
public void SaveAsMBN(string fname) { int format = 6; FileOutput o = new FileOutput(); o.Endian = Endianness.Little; o.writeShort(format); o.writeShort(0xFFFF); o.writeInt(0); //flags o.writeInt(1); //mode o.writeInt(Nodes.Count); // Write Vertex Attributes { o.writeInt(Attributes.Count); foreach (VertexAttribute va in Attributes) { o.writeInt(va.type); o.writeInt(va.format); o.writeFloat(va.scale); } } //Vertex Buffer FileOutput vertexBuffer = new FileOutput(); vertexBuffer.Endian = Endianness.Little; for (int i = 0; i < Vertices.Length; i++) { foreach (VertexAttribute va in Attributes) { //Write Data va.WriteVertex(vertexBuffer, ref Vertices[i]); } } o.writeInt(vertexBuffer.size()); // Vertex Buffer Size //Mesh Information FileOutput indexBuffer = new FileOutput(); indexBuffer.Endian = Endianness.Little; foreach (BCH_Mesh mesh in Nodes) { o.writeInt(mesh.Nodes.Count); foreach (BCH_PolyGroup pg in mesh.Nodes) { // Node List o.writeInt(pg.BoneList.Length); foreach (int b in pg.BoneList) { o.writeInt(b); } // Triangle Count o.writeInt(pg.Faces.Length); // o.writeInt(0); something if format == 4 // Index Buffer foreach (int i in pg.Faces) { indexBuffer.writeShort(i); } indexBuffer.align(0x20, 0xFF); } } if (format != 4) { o.align(0x20, 0xFF); } o.writeOutput(vertexBuffer); o.align(0x20, 0xFF); o.writeOutput(indexBuffer); o.save(fname); }
public override byte[] Rebuild() { FileOutput o = new FileOutput(); FileOutput data = new FileOutput(); o.writeInt(0x4E545033); // "NTP3" o.writeShort(0x0200); o.writeShort(textures.Count); o.writeInt(0); o.writeInt(0); //calculate total header size int headerLength = 0; foreach (var texture in textures) { int headerSize = 0x50; if (texture.mipmaps.Count > 1) { headerSize += texture.mipmaps.Count * 4; while (headerSize % 16 != 0) { headerSize += 4; } } headerLength += headerSize; } // write headers+data foreach (var texture in textures) { int size = 0; foreach (var mip in texture.mipmaps) { size += mip.Length; while (size % 16 != 0) { size += 1; } } int headerSize = 0x50; // calculate header size if (texture.mipmaps.Count > 1) { headerSize += texture.mipmaps.Count * 4; //align to 16 while (headerSize % 16 != 0) { headerSize += 1; } } o.writeInt(size + headerSize); o.writeInt(0x00); //padding o.writeInt(size); o.writeShort(headerSize); //+ (texture.mipmaps.Count - 4 > 0 ? texture.mipmaps.Count - 4 : 0) * 4 o.writeShort(0); o.writeShort(texture.mipmaps.Count); o.writeShort(texture.getNutFormat()); o.writeShort(texture.width); o.writeShort(texture.height); o.writeInt(0); o.writeInt(0); o.writeInt(headerLength + data.size()); headerLength -= headerSize; o.writeInt(0); o.writeInt(0); o.writeInt(0); if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17) { foreach (byte[] mip in texture.mipmaps) { for (int t = 0; t < mip.Length; t += 4) { byte t1 = mip[t + 3]; mip[t + 3] = mip[t + 2]; mip[t + 2] = mip[t + 1]; mip[t + 1] = mip[t]; mip[t] = t1; } } } foreach (var mip in texture.mipmaps) { int ds = data.size(); data.writeBytes(mip); data.align(0x10); if (texture.mipmaps.Count > 1) { o.writeInt(data.size() - ds); } } o.align(16); if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17) { foreach (byte[] mip in texture.mipmaps) { for (int t = 0; t < mip.Length; t += 4) { byte t1 = mip[t]; mip[t] = mip[t + 1]; mip[t + 1] = mip[t + 2]; mip[t + 2] = mip[t + 3]; mip[t + 3] = t1; } } } o.writeInt(0x65587400); // "eXt\0" o.writeInt(0x20); o.writeInt(0x10); o.writeInt(0x00); o.writeInt(0x47494458); // "GIDX" o.writeInt(0x10); o.writeInt(texture.id); o.writeInt(0); } o.writeOutput(data); return(o.getBytes()); }
public override byte[] Rebuild() { FileOutput o = new FileOutput(); FileOutput data = new FileOutput(); o.writeUInt(0x4E545033); // "NTP3" o.writeUShort(Version); o.writeUShort((ushort)Nodes.Count); o.writeInt(0); o.writeInt(0); //calculate total header size uint headerLength = 0; foreach (NutTexture texture in Nodes) { byte surfaceCount = (byte)texture.surfaces.Count; bool isCubemap = surfaceCount == 6; if (surfaceCount < 1 || surfaceCount > 6) { throw new NotImplementedException($"Unsupported surface amount {surfaceCount} for texture with hash 0x{texture.HashId:X}. 1 to 6 faces are required."); } else if (surfaceCount > 1 && surfaceCount < 6) { throw new NotImplementedException($"Unsupported cubemap face amount for texture with hash 0x{texture.HashId:X}. Six faces are required."); } byte mipmapCount = (byte)texture.surfaces[0].mipmaps.Count; ushort headerSize = 0x50; if (isCubemap) { headerSize += 0x10; } if (mipmapCount > 1) { headerSize += (ushort)(mipmapCount * 4); while (headerSize % 0x10 != 0) { headerSize += 1; } } headerLength += headerSize; } // write headers+data foreach (NutTexture texture in Nodes) { byte surfaceCount = (byte)texture.surfaces.Count; bool isCubemap = surfaceCount == 6; byte mipmapCount = (byte)texture.surfaces[0].mipmaps.Count; uint dataSize = 0; foreach (var mip in texture.GetAllMipmaps()) { dataSize += (uint)mip.Length; while (dataSize % 0x10 != 0) { dataSize += 1; } } ushort headerSize = 0x50; if (isCubemap) { headerSize += 0x10; } if (mipmapCount > 1) { headerSize += (ushort)(mipmapCount * 4); while (headerSize % 0x10 != 0) { headerSize += 1; } } o.writeUInt(dataSize + headerSize); o.writeUInt(0); o.writeUInt(dataSize); o.writeUShort(headerSize); o.writeUShort(0); o.writeByte(0); o.writeByte(mipmapCount); o.writeByte(0); o.writeByte(texture.getNutFormat()); o.writeShort(texture.Width); o.writeShort(texture.Height); o.writeInt(0); o.writeUInt(texture.DdsCaps2); o.writeUInt((uint)(headerLength + data.size())); headerLength -= headerSize; o.writeInt(0); o.writeInt(0); o.writeInt(0); if (isCubemap) { o.writeInt(texture.surfaces[0].mipmaps[0].Length); o.writeInt(texture.surfaces[0].mipmaps[0].Length); o.writeInt(0); o.writeInt(0); } if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17) { texture.SwapChannelOrderDown(); } for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { int ds = data.size(); data.writeBytes(texture.surfaces[surfaceLevel].mipmaps[mipLevel]); data.align(0x10); if (mipmapCount > 1 && surfaceLevel == 0) { o.writeInt(data.size() - ds); } } } o.align(0x10); if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17) { texture.SwapChannelOrderUp(); } o.writeUInt(0x65587400); // "eXt\0" o.writeInt(0x20); o.writeInt(0x10); o.writeInt(0x00); o.writeUInt(0x47494458); // "GIDX" o.writeInt(0x10); o.writeInt(texture.HashId); o.writeInt(0); } o.writeOutput(data); return(o.getBytes()); }
public static void Rebuild(string fname, List <Animation> animations) { // poopity doo da // headery deadery FileOutput o = new FileOutput(); o.writeString("BCH"); o.align(4); o.writeByte(0x21); // version stuffs o.writeByte(0x21); // version stuffs o.Endian = System.IO.Endianness.Little; o.writeShort(0xA755); // version FileOutput d_Main = new FileOutput(); d_Main.Endian = System.IO.Endianness.Little; FileOutput d_Main2 = new FileOutput(); d_Main2.Endian = System.IO.Endianness.Little; FileOutput d_Main3 = new FileOutput(); d_Main3.Endian = System.IO.Endianness.Little; FileOutput d_String = new FileOutput(); d_String.Endian = System.IO.Endianness.Little; FileOutput d_GPU = new FileOutput(); d_GPU.Endian = System.IO.Endianness.Little; FileOutput d_Data = new FileOutput(); d_Data.Endian = System.IO.Endianness.Little; FileOutput Reloc = new FileOutput(); Reloc.Endian = System.IO.Endianness.Little; //Offsets o.writeInt(0); //main o.writeInt(0); //string o.writeInt(0); //gpu o.writeInt(0); //data o.writeInt(0); //dataext o.writeInt(0); //relocationtable //Length o.writeInt(0); //main o.writeInt(0); //string o.writeInt(0); //gpu o.writeInt(0); //data o.writeInt(0); //dataext o.writeInt(0); //relocationtable o.writeInt(0); //datasection o.writeInt(0); // o.writeShort(1); //flag o.writeShort(0); //addcount //Contents in the main header...... d_Main.writeInt(0); // Model d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // Material d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // Shader d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // Texture d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // MaterialLUT d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // Lights d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // Camera d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // Fog d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); // SkeAnim { // Names need to be in patricia tree....... Dictionary <string, int> NameBank = new Dictionary <string, int>(); NameBank.Add("BustN", d_String.size()); d_String.writeString("BustN"); d_String.writeByte(0); List <PatriciaTree.PatriciaTreeNode> Nodes = new List <PatriciaTree.PatriciaTreeNode>(); int maxlength = 0; foreach (Animation a in animations) { maxlength = Math.Max(maxlength, a.Text.Length); } Nodes.Add(new PatriciaTree.PatriciaTreeNode() { ReferenceBit = uint.MaxValue }); foreach (Animation a in animations) { PatriciaTree.Insert(Nodes, new PatriciaTree.PatriciaTreeNode() { Name = a.Text }, maxlength); } int nameOff = 0xb4 + d_Main2.size(); foreach (PatriciaTree.PatriciaTreeNode node in Nodes) { d_Main2.writeInt((int)node.ReferenceBit); d_Main2.writeShort(node.LeftNodeIndex); d_Main2.writeShort(node.RightNodeIndex); if (node.Name.Equals("")) { d_Main2.writeInt(0); } else { NameBank.Add(node.Name, d_String.size()); d_Main2.WriteOffset(d_String.size(), d_String); d_String.writeString(node.Name); d_String.writeByte(0); } } // bones // Okay, first create the animation data then create the table pointng to it side by side int dataOff = 0xb4 + d_Main2.size(); foreach (Animation a in animations) { d_Main2.WriteOffset(d_Main3.size(), d_Main2); // now create the actual animation data I guess d_Main3.WriteOffset(NameBank[a.Text], d_String); // name offset d_Main3.writeInt(0x2); // Flags TODO: What are these d_Main3.writeFloat(a.FrameCount + 1); d_Main3.WriteOffset(d_Main3.size() + 12, d_Main3); // bone offset d_Main3.writeInt(a.Bones.Count); // bonecount d_Main3.writeInt(0); // metadata nonsense FileOutput boneHeader = new FileOutput(); boneHeader.Endian = System.IO.Endianness.Little; FileOutput keyData = new FileOutput(); keyData.Endian = System.IO.Endianness.Little; int start = d_Main3.size() + (a.Bones.Count * 4); int track = 0; foreach (Animation.KeyNode node in a.Bones) { d_Main3.WriteOffset(start + boneHeader.size(), d_Main3); // bone offset // name type and flags if (!NameBank.ContainsKey(node.Text)) { NameBank.Add(node.Text, d_String.size()); d_String.writeString(node.Text); d_String.writeByte(0); } boneHeader.WriteOffset(NameBank[node.Text], d_String); // name offset boneHeader.writeInt(0x040000); // animation type flags, default is just simply transform // Actual Flags int flags = 0; flags |= (((node.XSCA.Keys.Count > 0) ? 0 : 1) << (16 + 0)); flags |= (((node.YSCA.Keys.Count > 0) ? 0 : 1) << (16 + 1)); flags |= (((node.ZSCA.Keys.Count > 0) ? 0 : 1) << (16 + 2)); flags |= (((node.XROT.Keys.Count > 0) ? 0 : 1) << (16 + 3)); flags |= (((node.YROT.Keys.Count > 0) ? 0 : 1) << (16 + 4)); flags |= (((node.ZROT.Keys.Count > 0) ? 0 : 1) << (16 + 5)); flags |= (((node.XPOS.Keys.Count > 0) ? 0 : 1) << (16 + 6)); flags |= (((node.YPOS.Keys.Count > 0) ? 0 : 1) << (16 + 7)); flags |= (((node.ZPOS.Keys.Count > 0) ? 0 : 1) << (16 + 8)); flags |= (((node.XSCA.Keys.Count == 1) ? 1 : 0) << (6 + 0)); flags |= (((node.YSCA.Keys.Count == 1) ? 1 : 0) << (6 + 1)); flags |= (((node.ZSCA.Keys.Count == 1) ? 1 : 0) << (6 + 2)); flags |= (((node.XROT.Keys.Count == 1) ? 1 : 0) << (6 + 3)); flags |= (((node.YROT.Keys.Count == 1) ? 1 : 0) << (6 + 4)); flags |= (((node.ZROT.Keys.Count == 1) ? 1 : 0) << (6 + 5)); flags |= (((node.XPOS.Keys.Count == 1) ? 1 : 0) << (6 + 7)); flags |= (((node.YPOS.Keys.Count == 1) ? 1 : 0) << (6 + 8)); flags |= (((node.ZPOS.Keys.Count == 1) ? 1 : 0) << (6 + 9)); boneHeader.writeInt(flags); // Create KeyFrame Data int sta = start + (a.Bones.Count * 12 * 4); WriteKeyData(node.XSCA, boneHeader, keyData, d_Main3, sta, ref track); WriteKeyData(node.YSCA, boneHeader, keyData, d_Main3, sta, ref track); WriteKeyData(node.ZSCA, boneHeader, keyData, d_Main3, sta, ref track); WriteKeyData(node.XROT, boneHeader, keyData, d_Main3, sta, ref track); WriteKeyData(node.YROT, boneHeader, keyData, d_Main3, sta, ref track); WriteKeyData(node.ZROT, boneHeader, keyData, d_Main3, sta, ref track); WriteKeyData(node.XPOS, boneHeader, keyData, d_Main3, sta, ref track); WriteKeyData(node.YPOS, boneHeader, keyData, d_Main3, sta, ref track); WriteKeyData(node.ZPOS, boneHeader, keyData, d_Main3, sta, ref track); } d_Main3.writeOutput(boneHeader); d_Main3.writeOutput(keyData); } d_Main.WriteOffset(dataOff, d_Main); d_Main.writeInt(animations.Count); // d_Main.WriteOffset(nameOff, d_Main); // } d_Main.writeInt(0); // MaterialAnim d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // VisAnim d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // LightAnim d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // CameraAnim d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // FogAnim d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeInt(0); // Scene d_Main.writeInt(0); // d_Main.WriteOffset(0xB4 + d_Main2.size(), d_Main); // d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main2.writeInt(0); d_Main.writeOutput(d_Main2); d_Main.writeOutput(d_Main3); int headSize = o.size(); o.writeIntAt(headSize, 0x08); o.writeIntAt(d_Main.size(), 0x20); o.writeOutput(d_Main); o.align(4); int stringSize = o.size(); o.writeIntAt(stringSize, 0x0C); o.writeIntAt(d_String.size(), 0x24); o.writeOutput(d_String); o.align(4); int gpuSize = o.size(); o.writeIntAt(d_GPU.size() > 0 ? gpuSize : 0, 0x10); o.writeIntAt(d_GPU.size(), 0x28); o.writeOutput(d_GPU); o.align(0x100); int dataSize = o.size(); o.writeIntAt(dataSize, 0x14); o.writeIntAt(dataSize, 0x18); o.writeIntAt(d_Data.size(), 0x2C); o.writeIntAt(d_Data.size(), 0x30); o.writeOutput(d_Data); //Create Relocation Table // Flag is 7 bits // 0 - main 1 - string 2 - gpu 3 - data foreach (FileOutput.RelocOffset off in o.Offsets) { int size = 0; int code = 0; int div = 4; if (off.output == d_Main || off.output == d_Main2 || off.output == d_Main3) { size = headSize; code = 0; if (off.output == d_Main3) { off.Value += headSize; } if (off.output == d_Main2) { off.Value += d_Main2.size() + headSize; } } if (off.output == d_String) { size = stringSize; code = 1; div = 1; } if (off.output == d_GPU) { size = gpuSize; code = 2; } if (off.output == d_Data) { size = dataSize; code = 3; } o.writeIntAt(off.Value - size, off.Position); int reloc = (code << 25) | (((off.Position - headSize) / div) & 0x1FFFFFF); Reloc.writeInt(reloc); } int relocSize = o.size(); o.writeIntAt(relocSize, 0x1C); o.writeIntAt(Reloc.size(), 0x34); o.writeOutput(Reloc); o.save(fname); }
public override byte[] Rebuild() { FileOutput o = new FileOutput(); FileOutput data = new FileOutput(); //We always want BE for the first six bytes o.Endian = Endianness.Big; data.Endian = Endianness.Big; if (Endian == Endianness.Big) { o.writeUInt(0x4E545033); //NTP3 } else if (Endian == Endianness.Little) { o.writeUInt(0x4E545744); //NTWD } //Most NTWU NUTs are 0x020E, which isn't valid for NTP3/NTWD if (Version > 0x0200) { Version = 0x0200; } o.writeUShort(Version); //After that, endian is used appropriately o.Endian = Endian; data.Endian = Endian; o.writeUShort((ushort)Nodes.Count); o.writeInt(0); o.writeInt(0); //calculate total header size uint headerLength = 0; foreach (NutTexture texture in Nodes) { byte surfaceCount = (byte)texture.surfaces.Count; bool isCubemap = surfaceCount == 6; if (surfaceCount < 1 || surfaceCount > 6) { throw new NotImplementedException($"Unsupported surface amount {surfaceCount} for texture with hash 0x{texture.HashId:X}. 1 to 6 faces are required."); } else if (surfaceCount > 1 && surfaceCount < 6) { throw new NotImplementedException($"Unsupported cubemap face amount for texture with hash 0x{texture.HashId:X}. Six faces are required."); } byte mipmapCount = (byte)texture.surfaces[0].mipmaps.Count; ushort headerSize = 0x50; if (isCubemap) { headerSize += 0x10; } if (mipmapCount > 1) { headerSize += (ushort)(mipmapCount * 4); while (headerSize % 0x10 != 0) { headerSize += 1; } } headerLength += headerSize; } // write headers+data foreach (NutTexture texture in Nodes) { byte surfaceCount = (byte)texture.surfaces.Count; bool isCubemap = surfaceCount == 6; byte mipmapCount = (byte)texture.surfaces[0].mipmaps.Count; uint dataSize = 0; foreach (var mip in texture.GetAllMipmaps()) { dataSize += (uint)mip.Length; while (dataSize % 0x10 != 0) { dataSize += 1; } } ushort headerSize = 0x50; if (isCubemap) { headerSize += 0x10; } if (mipmapCount > 1) { headerSize += (ushort)(mipmapCount * 4); while (headerSize % 0x10 != 0) { headerSize += 1; } } o.writeUInt(dataSize + headerSize); o.writeUInt(0); o.writeUInt(dataSize); o.writeUShort(headerSize); o.writeUShort(0); o.writeByte(0); o.writeByte(mipmapCount); o.writeByte(0); o.writeByte(texture.getNutFormat()); o.writeShort(texture.Width); o.writeShort(texture.Height); o.writeInt(0); o.writeUInt(texture.DdsCaps2); if (Version < 0x0200) { o.writeUInt(0); } else if (Version >= 0x0200) { o.writeUInt((uint)(headerLength + data.size())); } headerLength -= headerSize; o.writeInt(0); o.writeInt(0); o.writeInt(0); if (isCubemap) { o.writeInt(texture.surfaces[0].mipmaps[0].Length); o.writeInt(texture.surfaces[0].mipmaps[0].Length); o.writeInt(0); o.writeInt(0); } if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17) { texture.SwapChannelOrderDown(); } for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { int ds = data.size(); data.writeBytes(texture.surfaces[surfaceLevel].mipmaps[mipLevel]); data.align(0x10); if (mipmapCount > 1 && surfaceLevel == 0) { o.writeInt(data.size() - ds); } } } o.align(0x10); if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17) { texture.SwapChannelOrderUp(); } o.writeBytes(new byte[] { 0x65, 0x58, 0x74, 0x00 }); // "eXt\0" o.writeInt(0x20); o.writeInt(0x10); o.writeInt(0x00); o.writeBytes(new byte[] { 0x47, 0x49, 0x44, 0x58 }); // "GIDX" o.writeInt(0x10); o.writeInt(texture.HashId); o.writeInt(0); if (Version < 0x0200) { o.writeOutput(data); data = new FileOutput(); } } if (Version >= 0x0200) { o.writeOutput(data); } return(o.getBytes()); }