示例#1
0
            public int Rebuild(FileOutput o)
            {
                o.WriteString("DTON");
                int sizeoff = o.Size();

                o.WriteInt(0);
                int size = o.Size();

                o.WriteInt(destone.Count);

                FileOutput dat = new FileOutput();

                dat.endian = Endianness.Little;

                int start = destone.Count * 8 + 4;

                for (int i = 0; i < destone.Count; i++)
                {
                    o.WriteInt(start + dat.Size());
                    o.WriteInt(destone[i].Rebuild(dat) + 4);

                    if (i != destone.Count - 1)
                    {
                        dat.WriteInt(0);
                    }
                }

                o.WriteInt(0);
                o.WriteOutput(dat);

                size = o.Size() - size;
                o.WriteIntAt(size, sizeoff);
                return(size);
            }
示例#2
0
            public int Rebuild(FileOutput o)
            {
                o.WriteString("TONE");
                int sizeoff = o.Size();

                o.WriteInt(0);
                int size = o.Size();

                o.WriteInt(tones.Count);

                FileOutput dat = new FileOutput();

                dat.endian = Endianness.Little;

                int start = tones.Count * 8 + 4;

                for (int i = 0; i < tones.Count; i++)
                {
                    o.WriteInt(start + dat.Size());
                    o.WriteInt(tones[i].Rebuild(dat));
                }

                o.WriteInt(0);
                o.WriteOutput(dat);

                size = o.Size() - size - 4;
                o.WriteIntAt(size, sizeoff);
                return(size);
            }
示例#3
0
        } // Read()

        #region serialization
        void writeSymbols(FileOutput o)
        {
            FileOutput tag = new FileOutput();

            tag.WriteInt(Strings.Count);

            Console.WriteLine($"Strings = [ // offset=0x{o.Size():X2}");
            for (int i = 0; i < Strings.Count; i++)
            {
                var str = Strings[i];

                Console.WriteLine($"\t0x{i:X3}: \"{str}\"");

                var strBytes = Encoding.UTF8.GetBytes(str);
                tag.WriteInt(strBytes.Length);
                tag.WriteBytes(strBytes);

                int padSize = 4 - (tag.Size() % 4);
                for (int j = 0; j < padSize; j++)
                {
                    tag.WriteByte(0);
                }
            }
            Console.WriteLine("]\n");

            o.WriteInt((int)TagType.Symbols);
            o.WriteInt(tag.Size() / 4);
            o.WriteOutput(tag);
        }
示例#4
0
                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);
                }
示例#5
0
        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);
        }
示例#6
0
        void writeTransforms(FileOutput o)
        {
            Console.WriteLine($"Transforms = [ // offset=0x{o.Size():X2}");

            o.WriteInt((int)TagType.Transforms);
            o.WriteInt(Transforms.Count * 6 + 1);
            o.WriteInt(Transforms.Count);

            for (int i = 0; i < Transforms.Count; i++)
            {
                var transform = Transforms[i];

                Console.WriteLine($"\t[{transform.M11:f2}, {transform.M21:f2}] // offset=0x{o.Size():X2}");
                Console.WriteLine($"\t[{transform.M12:f2}, {transform.M22:f2}]");
                Console.WriteLine($"\t[{transform.M41:f2}, {transform.M42:f2}]\n");
                o.WriteFloat(transform.M11);
                o.WriteFloat(transform.M21);
                o.WriteFloat(transform.M12);
                o.WriteFloat(transform.M22);
                o.WriteFloat(transform.M41);
                o.WriteFloat(transform.M42);
            }

            Console.WriteLine("]\n");
        }
示例#7
0
            public void Write(FileOutput o)
            {
                Console.WriteLine($"Properties {{ // offset=0x{o.Size():X2}");
                Console.WriteLine($"\tunk0: 0x{unk0:X8}");
                Console.WriteLine($"\tunk1: 0x{unk1:X8}");
                Console.WriteLine($"\tunk2: 0x{unk2:X8}");
                Console.WriteLine($"\tmaxCharacterId: 0x{maxCharacterId:X8}");
                Console.WriteLine($"\tunk4: 0x{unk4:X8}");
                Console.WriteLine($"\tmaxCharacterId2: 0x{maxCharacterId2:X2}");
                Console.WriteLine($"\tmaxDepth: 0x{maxDepth:X4}");
                Console.WriteLine($"\tunk7: 0x{unk7:X4}");
                Console.WriteLine($"\tframerate: {framerate}");
                Console.WriteLine($"\tdimensions: {width}x{height}");
                Console.WriteLine($"\tunk8: 0x{unk8:X8}");
                Console.WriteLine($"\tunk9: 0x{unk9:X8}");
                Console.WriteLine("}\n");

                o.WriteInt((int)TagType.Properties);
                o.WriteInt(12);

                o.WriteInt((int)unk0);
                o.WriteInt((int)unk1);
                o.WriteInt((int)unk2);
                o.WriteInt((int)maxCharacterId);
                o.WriteInt(unk4);
                o.WriteInt((int)maxCharacterId2);
                o.WriteShort((short)maxDepth);
                o.WriteShort((short)unk7);
                o.WriteFloat(framerate);
                o.WriteFloat(width);
                o.WriteFloat(height);
                o.WriteInt((int)unk8);
                o.WriteInt((int)unk9);
            }
示例#8
0
            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);
            }
示例#9
0
        public static void WriteKeyData(Animation.KeyGroup group, FileOutput boneHeader, FileOutput keyData, FileOutput d_Main3, int start, ref int track)
        {
            if (group.keys.Count == 1)
            {
                boneHeader.WriteFloat(group.keys[0].Value);
            }
            else
            if (group.keys.Count == 0)
            {
                boneHeader.WriteInt(0);
            }
            else
            {
                int off = (group.keys.Count * 4);
                boneHeader.WriteOffset(start + keyData.Size(), d_Main3); // bone offset

                keyData.WriteFloat(0);
                keyData.WriteFloat(group.FrameCount);
                keyData.WriteInt(track++ << 16);                     // track
                keyData.WriteInt((group.keys.Count << 16) | 0x0701); // 7 is quantinization and 1 is linear interpolation

                float minv = 999, maxv = -999;
                float minf = 999, maxf = -999;
                foreach (Animation.KeyFrame key in group.keys)
                {
                    minv = Math.Min(key.Value, minv);
                    maxv = Math.Max(key.Value, maxv);
                    minf = Math.Min(key.Frame, minf);
                    maxf = Math.Max(key.Frame, maxf);
                }
                maxv -= minv;
                keyData.WriteFloat(maxv / 0xFFFFF);                       // value scale
                keyData.WriteFloat(minv);                                 // value offset
                keyData.WriteFloat(1f);                                   // frame scale
                keyData.WriteFloat(minf);                                 // frame offset

                keyData.WriteOffset(start + keyData.Size() + 4, d_Main3); // useless flags

                foreach (Animation.KeyFrame key in group.keys)
                {
                    keyData.WriteInt((((int)(((key.Value - minv) / (maxv)) * 0xFFFFF)) << 12) | (((int)(key.Frame - minf)) & 0xFFF));
                }
            }
            //------
        }
示例#10
0
                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);
                }
示例#11
0
            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);
            }
示例#12
0
        void writeBounds(FileOutput o)
        {
            Console.WriteLine($"Bounds = [ // offset=0x{o.Size():X2}");

            o.WriteInt((int)TagType.Bounds);
            o.WriteInt(Bounds.Count * 4 + 1);
            o.WriteInt(Bounds.Count);

            for (int i = 0; i < Bounds.Count; i++)
            {
                var bb = Bounds[i];
                Console.WriteLine($"\t0x{i:X2}: {bb} // offset=0x{o.Size():X2}");

                o.WriteFloat(bb.TopLeft.X);
                o.WriteFloat(bb.TopLeft.Y);
                o.WriteFloat(bb.BottomRight.X);
                o.WriteFloat(bb.BottomRight.Y);
            }

            Console.WriteLine("]\n");
        }
示例#13
0
        public static byte[] FromIDSP(byte[] idsp)
        {
            File.WriteAllBytes("temp.idsp", idsp);
            IntPtr vgm = VGMStreamNative.InitVGMStream("temp.idsp");

            if (vgm == IntPtr.Zero)
            {
                throw new Exception("Error loading idsp");
            }

            int channelCount = VGMStreamNative.GetVGMStreamChannelCount(vgm);
            int bitsPerFrame = VGMStreamNative.GetVGMStreamFrameSize(vgm);
            int size         = VGMStreamNative.GetVGMStreamTotalSamples(vgm);
            int samplerate   = VGMStreamNative.GetVGMStreamSampleRate(vgm);

            int total = (int)((samplerate * bitsPerFrame * channelCount * (size / 24576000f)) / 8 * 1024);

            short[] buffer = new short[total];
            VGMStreamNative.RenderVGMStream(buffer, buffer.Length / 2, vgm);

            FileOutput o = new FileOutput();

            o.endian = Endianness.Little;

            o.WriteString("RIFF");
            o.WriteInt(0);
            o.WriteString("WAVEfmt ");

            o.WriteInt(0x10);
            o.WriteShort(1);
            o.WriteShort(channelCount);
            o.WriteInt(samplerate);
            o.WriteInt(size);
            o.WriteShort(2);
            o.WriteShort(0x10);

            o.WriteString("data");
            o.WriteInt(buffer.Length);

            for (int i = 0; i < buffer.Length / 2; i++)
            {
                o.WriteShort(buffer[i]);
            }

            o.WriteIntAt(o.Size() - 8, 4);

            VGMStreamNative.CloseVGMStream(vgm);
            File.Delete("temp.idsp");
            return(o.GetBytes());
        }
示例#14
0
        void writeAtlases(FileOutput o)
        {
            Console.WriteLine($"TextureAtlases = [ // offset=0x{o.Size():X2}");

            o.WriteInt((int)TagType.TextureAtlases);
            o.WriteInt(Atlases.Count * 4 + 1);
            o.WriteInt(Atlases.Count);

            for (int i = 0; i < Atlases.Count; i++)
            {
                var atlas = Atlases[i];
                Console.WriteLine($"\tatlas 0x{atlas.id:X2} {{  // offset=0x{o.Size():X2}");
                Console.WriteLine($"\t\t\"name\": \"{Strings[atlas.nameId]}\"");
                Console.WriteLine($"\t\tdimensions: {atlas.width}x{atlas.height}");
                Console.WriteLine("\t}\n");

                o.WriteInt(atlas.id);
                o.WriteInt(atlas.nameId);
                o.WriteFloat(atlas.width);
                o.WriteFloat(atlas.height);
            }
            Console.WriteLine("]\n");
        }
示例#15
0
        public override byte[] Rebuild()
        {
            FileOutput o = new FileOutput();

            o.endian = Endianness.Little;

            FileOutput d = new FileOutput();

            d.endian = Endianness.Little;

            o.WriteString("NUS3");
            o.WriteInt(0);

            o.WriteString("BANKTOC ");
            o.WriteInt(0x3C);
            o.WriteInt(0x07);

            // write each section
            o.WriteString("PROP");
            o.WriteInt(prop.Rebuild(d));

            o.WriteString("BINF");
            o.WriteInt(binf.Rebuild(d));

            o.WriteString("GRP ");
            o.WriteInt(grp.Rebuild(d));

            o.WriteString("DTON");
            o.WriteInt(dton.Rebuild(d));

            o.WriteString("TONE");
            o.WriteInt(tone.Rebuild(d));

            o.WriteString("JUNK");
            o.WriteInt(4);
            //d.writeString("JUNK");
            d.WriteInt(4);
            d.WriteInt(0);

            o.WriteString("PACK");
            o.WriteInt(0);

            o.WriteOutput(d);

            o.WriteIntAt(o.Size(), 4);

            // something extra with bgm??

            return(o.GetBytes());
        }
示例#16
0
            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);
            }
示例#17
0
        void writePositions(FileOutput o)
        {
            Console.WriteLine($"Positions = [ // offset=0x{o.Size():X2}");

            o.WriteInt((int)TagType.Positions);
            o.WriteInt(Positions.Count * 2 + 1);
            o.WriteInt(Positions.Count);

            for (int i = 0; i < Positions.Count; i++)
            {
                var position = Positions[i];
                Console.WriteLine($"\t0x{i:X4}: [{position.X}, {position.Y}] // offset=0x{o.Size():X2}");
                o.WriteFloat(position.X);
                o.WriteFloat(position.Y);
            }
            Console.WriteLine("]\n");
        }
示例#18
0
        void writeColors(FileOutput o)
        {
            Console.WriteLine($"Colors = [ // offset=0x{o.Size():X2}");

            o.WriteInt((int)TagType.Colors);
            o.WriteInt(Colors.Count * 2 + 1);
            o.WriteInt(Colors.Count);

            for (int i = 0; i < Colors.Count; i++)
            {
                var color = Colors[i];
                Console.WriteLine($"\t0x{i:X3}: #{(byte)(color.X * 255):X2}{(byte)(color.Z * 255):X2}{(byte)(color.Y * 255):X2}, {(byte)(color.W * 255):X2} // offset=0x{o.Size():X2}");
                o.WriteShort((short)(color.X * 256));
                o.WriteShort((short)(color.Y * 256));
                o.WriteShort((short)(color.Z * 256));
                o.WriteShort((short)(color.W * 256));
            }
            Console.WriteLine("]\n");
        }
示例#19
0
            public void Write(FileOutput o)
            {
                Console.WriteLine($"Properties2 {{ // offset=0x{o.Size():X2}");
                Console.WriteLine($"\tnumShapes: 0x{numShapes:X8}");
                Console.WriteLine($"\tunk1: 0x{unk1:X8}");
                Console.WriteLine($"\tnumSprites: 0x{numSprites:X8}");
                Console.WriteLine($"\tunk3: 0x{unk3:X8}");
                Console.WriteLine($"\tnumTexts: 0x{numTexts:X8}");
                Console.WriteLine($"\tunk5: 0x{unk5:X8}");
                Console.WriteLine($"\tunk6: 0x{unk6:X8}");
                Console.WriteLine($"\tunk7: 0x{unk7:X8}");
                Console.WriteLine("}\n");
                o.WriteInt((int)TagType.Defines);
                o.WriteInt(8);

                o.WriteInt((int)numShapes);
                o.WriteInt((int)unk1);
                o.WriteInt((int)numSprites);
                o.WriteInt((int)unk3);
                o.WriteInt((int)numTexts);
                o.WriteInt((int)unk5);
                o.WriteInt((int)unk6);
                o.WriteInt((int)unk7);
            }
示例#20
0
            public void Write(FileOutput o)
            {
                Console.WriteLine($"unk_{(int)Type:X4} (size=0x{Size * 4:X4}) // offset=0x{o.Size():X2}\n");

                o.WriteInt((int)Type);
                o.WriteInt(Size);
                o.WriteBytes(Data);
            }
示例#21
0
        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());
        }
示例#22
0
        public byte[] Rebuild(bool dump = false)
        {
            FileOutput o = new FileOutput();

            TextWriter   oldOut = Console.Out;
            MemoryStream ostrm  = new MemoryStream(0xA00000);
            StreamWriter writer = new StreamWriter(ostrm);

            Console.SetOut(writer);

            // TODO: write correct filesize in header.
            // It isn't checked by the game, but what the hell, right?
            header.Write(o);

            writeSymbols(o);
            writeColors(o);
            writeTransforms(o);
            writePositions(o);
            writeBounds(o);

            Actionscript.Write(o);
            if (Actionscript2 != null)
            {
                Actionscript2.Write(o);
            }

            writeAtlases(o);

            unkF008.Write(o);
            unkF009.Write(o);
            unkF00A.Write(o);
            unk000A.Write(o);
            unkF00B.Write(o);
            properties.Write(o);

            Defines.numShapes  = (uint)Shapes.Count;
            Defines.numSprites = (uint)Sprites.Count;
            Defines.numTexts   = (uint)Texts.Count;
            Defines.Write(o);

            writeShapes(o);
            writeSprites(o);
            writeTexts(o);

            o.WriteInt((int)TagType.End);
            o.WriteInt(0);

            int padSize = (4 - (o.Size() % 4)) % 4;

            for (int i = 0; i < padSize; i++)
            {
                o.WriteByte(0);
            }

            if (dump)
            {
                writer.Flush();
                using (var filestream = new FileStream("dump.txt", FileMode.Create))
                    ostrm.WriteTo(filestream);
            }

            Console.SetOut(oldOut);
            o.Save(Filename);
            return(o.GetBytes());
        }
示例#23
0
        void writeShapes(FileOutput o)
        {
            Console.WriteLine($"Shapes = [ // offset=0x{o.Size():X2}");

            for (int i = 0; i < Shapes.Count; i++)
            {
                var shape = Shapes[i];

                Console.WriteLine($"\tCharacterId: 0x{shape.CharacterId:X4} // offset=0x{o.Size():X2}");
                Console.WriteLine($"\tUnk1: 0x{shape.Unk1:X8}");
                Console.WriteLine($"\tBounds: {Bounds[shape.BoundsId]} (0x{shape.BoundsId:X2})");
                Console.WriteLine($"\tUnk3: 0x{shape.Unk3:X8}");
                Console.WriteLine("\t[");

                o.WriteInt((int)TagType.Shape);
                o.WriteInt(5);

                o.WriteInt(shape.CharacterId);
                o.WriteInt(shape.Unk1);
                o.WriteInt(shape.BoundsId);
                o.WriteInt(shape.Unk3);
                o.WriteInt(shape.Graphics.Length);


                foreach (var graphic in shape.Graphics)
                {
                    Console.WriteLine($"\t\tGraphic {{ // offset=0x{o.Size():X2}");
                    Console.WriteLine($"\t\t\tAtlasId: {graphic.AtlasId}");
                    Console.WriteLine($"\t\t\tFillType: {graphic.FillType} (0x{(short)graphic.FillType:X2})");

                    var graphicTag = new FileOutput();
                    graphicTag.WriteInt(graphic.AtlasId);
                    graphicTag.WriteShort((short)graphic.FillType);
                    graphicTag.WriteShort((short)graphic.Verts.Length);
                    graphicTag.WriteInt(graphic.Indices.Length);

                    foreach (var vert in graphic.Verts)
                    {
                        Console.WriteLine($"\t\t\t\t{vert}");
                        graphicTag.WriteFloat(vert.X);
                        graphicTag.WriteFloat(vert.Y);
                        graphicTag.WriteFloat(vert.U);
                        graphicTag.WriteFloat(vert.V);
                    }

                    Console.Write("\t\t\t[");
                    foreach (var index in graphic.Indices)
                    {
                        Console.Write($"{index}, ");
                        graphicTag.WriteShort((short)index);
                    }
                    Console.WriteLine("]");

                    Console.WriteLine("\t\t}\n");

                    if ((graphic.Indices.Length % 2) != 0)
                    {
                        graphicTag.WriteShort(0);
                    }

                    o.WriteInt((int)TagType.Graphic);
                    o.WriteInt(graphicTag.Size() / 4);
                    o.WriteOutput(graphicTag);
                }

                Console.WriteLine("\t]\n");
            }

            Console.WriteLine("]\n");
        }
示例#24
0
        public static byte[] createOMO(SkelAnimation a, VBN vbn)
        {
            List <int> nodeid = a.GetNodes(true, vbn);

            int startNode = 0;
            int sizeNode  = nodeid.Count;

            FileOutput o = new FileOutput();

            o.endian = Endianness.Big;

            FileOutput t1 = new FileOutput();

            t1.endian = Endianness.Big;

            FileOutput t2 = new FileOutput();

            t2.endian = Endianness.Big;

            o.WriteString("OMO ");
            o.WriteShort(1);        //idk
            o.WriteShort(3);        //idk

            o.WriteInt(0x091E100C); //flags??


            o.WriteShort(0);              //padding
            o.WriteShort(sizeNode);       // numOfNodes

            o.WriteShort(a.frames.Count); // frame size
            o.WriteShort(0);              // frame start ??

            o.WriteInt(0);
            o.WriteInt(0);
            o.WriteInt(0);

            o.WriteIntAt(o.Size(), 0x14);


            // ASSESSMENT
            KeyNode[] minmax   = new KeyNode[sizeNode];
            bool[]    hasScale = new bool[sizeNode];
            bool[]    hasTrans = new bool[sizeNode];
            bool[]    hasRot   = new bool[sizeNode];

            bool[] conScale = new bool[sizeNode];
            bool[] conTrans = new bool[sizeNode];
            bool[] conRot   = new bool[sizeNode];

            a.SetFrame(0);

            List <List <Bone> > Frames = new List <List <Bone> >();
            VBN tempvbn = new VBN();

            for (int i = 0; i < a.Size(); i++)
            {
                a.NextFrame(vbn, true);
                List <Bone> bonelist = new List <Bone>();
                for (int j = 0; j < nodeid.Count; j++)
                {
                    Bone node = getNodeId(vbn, nodeid[j]);

                    Bone f1 = new Bone(tempvbn);
                    f1.pos = node.pos;
                    f1.rot = node.rot;
                    f1.sca = node.sca;
                    bonelist.Add(f1);

                    if (minmax[j] == null)
                    {
                        hasRot[j]   = false;
                        hasScale[j] = false;
                        hasTrans[j] = false;

                        KeyNode n = a.GetFirstNode(nodeid[j]);
                        if (n != null)
                        {
                            if (n.rType != -1)
                            {
                                hasRot[j] = true;
                            }
                            if (n.tType != -1)
                            {
                                hasTrans[j] = true;
                            }
                            if (n.sType != -1)
                            {
                                hasScale[j] = true;
                            }
                        }

                        minmax[j]    = new KeyNode();
                        minmax[j].t  = new Vector3(999f, 999f, 999f);
                        minmax[j].r  = new Quaternion(999f, 999f, 999f, 999f);
                        minmax[j].s  = new Vector3(999f, 999f, 999f);
                        minmax[j].t2 = new Vector3(-999f, -999f, -999f);
                        minmax[j].r2 = new Quaternion(-999f, -999f, -999f, -999f);
                        minmax[j].s2 = new Vector3(-999f, -999f, -999f);
                    }

                    if (node.pos.X < minmax[j].t.X)
                    {
                        minmax[j].t.X = node.pos.X;
                    }
                    if (node.pos.X > minmax[j].t2.X)
                    {
                        minmax[j].t2.X = node.pos.X;
                    }

                    if (node.pos.Y < minmax[j].t.Y)
                    {
                        minmax[j].t.Y = node.pos.Y;
                    }
                    if (node.pos.Y > minmax[j].t2.Y)
                    {
                        minmax[j].t2.Y = node.pos.Y;
                    }

                    if (node.pos.Z < minmax[j].t.Z)
                    {
                        minmax[j].t.Z = node.pos.Z;
                    }
                    if (node.pos.Z > minmax[j].t2.Z)
                    {
                        minmax[j].t2.Z = node.pos.Z;
                    }

                    //				float[] fix = Node.fix360(node.nrx, node.nry, node.nrz);
                    //float[] f = Bone.CalculateRotation(node.nrx, node.nry, node.nrz);
                    Quaternion r = node.rot;

                    if (r.X < minmax[j].r.X)
                    {
                        minmax[j].r.X = r.X;
                    }
                    if (r.X > minmax[j].r2.X)
                    {
                        minmax[j].r2.X = r.X;
                    }

                    if (r.Y < minmax[j].r.Y)
                    {
                        minmax[j].r.Y = r.Y;
                    }
                    if (r.Y > minmax[j].r2.Y)
                    {
                        minmax[j].r2.Y = r.Y;
                    }

                    if (r.Z < minmax[j].r.Z)
                    {
                        minmax[j].r.Z = r.Z;
                    }
                    if (r.Z > minmax[j].r2.Z)
                    {
                        minmax[j].r2.Z = r.Z;
                    }


                    if (node.sca.X < minmax[j].s.X)
                    {
                        minmax[j].s.X = node.sca.X;
                    }
                    if (node.sca.X > minmax[j].s2.X)
                    {
                        minmax[j].s2.X = node.sca.X;
                    }

                    if (node.sca.Y < minmax[j].s.Y)
                    {
                        minmax[j].s.Y = node.sca.Y;
                    }
                    if (node.sca.Y > minmax[j].s2.Y)
                    {
                        minmax[j].s2.Y = node.sca.Y;
                    }

                    if (node.sca.Z < minmax[j].s.Z)
                    {
                        minmax[j].s.Z = node.sca.Z;
                    }
                    if (node.sca.Z > minmax[j].s2.Z)
                    {
                        minmax[j].s2.Z = node.sca.Z;
                    }
                }
            }

            // NODE INFO

            int t2Size = 0;

            for (int i = 0; i < sizeNode; i++)
            {
                int flag = 0;

                conRot[i]   = false;
                conScale[i] = false;
                conTrans[i] = false;

                // check for constant
                if (minmax[i].t.Equals(minmax[i].t2))
                {
                    conTrans[i] = true;
                }
                if (minmax[i].r.Equals(minmax[i].r2))
                {
                    conRot[i] = true;
                }
                if (minmax[i].s.Equals(minmax[i].s2))
                {
                    conScale[i] = true;
                }

                if (hasTrans[i])
                {
                    flag |= 0x01000000;
                }
                if (hasRot[i])
                {
                    flag |= 0x02000000;
                }
                if (hasScale[i])
                {
                    flag |= 0x04000000;
                }

                if (conTrans[i] && hasTrans[i])
                {
                    flag |= 0x00200000;
                }
                else
                {
                    flag |= 0x00080000;
                }

                if (conRot[i] && hasRot[i])
                {
                    flag |= 0x00007000;
                }
                else
                {
                    flag |= 0x00005000;
                }

                if (conScale[i] && hasScale[i])
                {
                    flag |= 0x00000200;
                }
                else
                {
                    flag |= 0x00000080;
                }

                flag |= 0x00000001;

                int hash = -1;
                if (MainForm.hashes.names.ContainsKey(getNodeId(vbn, nodeid[i]).Text))
                {
                    hash = (int)MainForm.hashes.names[getNodeId(vbn, nodeid[i]).Text];
                }
                //else hash = (int)FileData.crc12(getNodeId(vbn, nodeid[i]).Text);
                o.WriteInt(flag);      // flags...
                o.WriteInt(hash);      //hash
                o.WriteInt(t1.Size()); // Offset in 1 table
                o.WriteInt(t2Size);    // Offset in 2 table

                // calculate size needed
                if (hasTrans[i])
                {
                    t1.WriteFloat(minmax[i].t.X);
                    t1.WriteFloat(minmax[i].t.Y);
                    t1.WriteFloat(minmax[i].t.Z);

                    if (!conTrans[i])
                    {
                        minmax[i].t2.X -= minmax[i].t.X;
                        minmax[i].t2.Y -= minmax[i].t.Y;
                        minmax[i].t2.Z -= minmax[i].t.Z;

                        t1.WriteFloat(minmax[i].t2.X);
                        t1.WriteFloat(minmax[i].t2.Y);
                        t1.WriteFloat(minmax[i].t2.Z);

                        t2Size += 6;
                    }
                }

                if (hasRot[i])
                {
                    t1.WriteFloat(minmax[i].r.X);
                    t1.WriteFloat(minmax[i].r.Y);
                    t1.WriteFloat(minmax[i].r.Z);

                    if (!conRot[i])
                    {
                        minmax[i].r2.X -= minmax[i].r.X;
                        minmax[i].r2.Y -= minmax[i].r.Y;
                        minmax[i].r2.Z -= minmax[i].r.Z;

                        t1.WriteFloat(minmax[i].r2.X);
                        t1.WriteFloat(minmax[i].r2.Y);
                        t1.WriteFloat(minmax[i].r2.Z);

                        t2Size += 6;
                    }
                }

                if (hasScale[i])
                {
                    t1.WriteFloat(minmax[i].s.X);
                    t1.WriteFloat(minmax[i].s.Y);
                    t1.WriteFloat(minmax[i].s.Z);

                    if (!conScale[i])
                    {
                        minmax[i].s2.X -= minmax[i].s.X;
                        minmax[i].s2.Y -= minmax[i].s.Y;
                        minmax[i].s2.Z -= minmax[i].s.Z;

                        t1.WriteFloat(minmax[i].s2.X);
                        t1.WriteFloat(minmax[i].s2.Y);
                        t1.WriteFloat(minmax[i].s2.Z);

                        t2Size += 6;
                    }
                }
            }

            o.WriteIntAt(o.Size(), 0x18);

            o.WriteOutput(t1);

            o.WriteIntAt(o.Size(), 0x1C);

            // INTERPOLATION

            //a.setFrame(0);

            bool go = false;

            foreach (List <Bone> bonelist in Frames)
            {
                //a.nextFrame(vbn);
                int j = 0;
                foreach (Bone node in bonelist)
                {
                    //Bone node = getNodeId(vbn, nodeid[j]);

                    if (hasTrans[j] && !conTrans[j])
                    {
                        t2.WriteShort((int)(((node.pos.X - minmax[j].t.X) / minmax[j].t2.X) * 0xFFFF));
                        t2.WriteShort((int)(((node.pos.Y - minmax[j].t.Y) / minmax[j].t2.Y) * 0xFFFF));
                        t2.WriteShort((int)(((node.pos.Z - minmax[j].t.Z) / minmax[j].t2.Z) * 0xFFFF));
                    }

                    if (hasRot[j] && !conRot[j])
                    {
                        //					float[] fix = Node.fix360(node.nrx, node.nry, node.nrz);
                        //float[] f = CalculateRotation(node.nrx, node.nry, node.nrz);
                        Quaternion r = node.rot;

                        t2.WriteShort((int)(((r.X - minmax[j].r.X) / minmax[j].r2.X) * 0xFFFF));
                        t2.WriteShort((int)(((r.Y - minmax[j].r.Y) / minmax[j].r2.Y) * 0xFFFF));
                        t2.WriteShort((int)(((r.Z - minmax[j].r.Z) / minmax[j].r2.Z) * 0xFFFF));
                    }

                    if (hasScale[j] && !conScale[j])
                    {
                        t2.WriteShort((int)(((node.sca.X - minmax[j].s.X) / minmax[j].s2.X) * 0xFFFF));
                        t2.WriteShort((int)(((node.sca.Y - minmax[j].s.Y) / minmax[j].s2.Y) * 0xFFFF));
                        t2.WriteShort((int)(((node.sca.Z - minmax[j].s.Z) / minmax[j].s2.Z) * 0xFFFF));
                    }
                    j++;
                }
                if (!go)
                {
                    o.WriteShortAt(t2.Size(), 0x12);
                    go = true;
                }
            }

            o.WriteOutput(t2);
            return(o.GetBytes());
        }
示例#25
0
        public static byte[] CreateOMOFromAnimation(Animation a, VBN vbn)
        {
            if (vbn == null || a == null)
            {
                return new byte[] { }
            }
            ;

            // Test Actual Bones
            //-------------------------

            List <Animation.KeyNode> toRem = new List <Animation.KeyNode>();

            for (int j = 0; j < a.bones.Count; j++)
            {
                Animation.KeyNode keynode = ((Animation.KeyNode)a.bones[j]);
                Bone b = vbn.getBone(keynode.Text);

                if (b == null)
                {
                    toRem.Add(keynode);
                }
            }
            foreach (Animation.KeyNode r in toRem)
            {
                Console.WriteLine("Removing " + r.Text);
                a.bones.Remove(r);
            }

            //-------------------------

            FileOutput o = new FileOutput();

            o.endian = Endianness.Big;

            FileOutput t1 = new FileOutput();

            t1.endian = Endianness.Big;

            FileOutput t2 = new FileOutput();

            t2.endian = Endianness.Big;

            o.WriteString("OMO ");
            o.WriteShort(1);        //idk
            o.WriteShort(3);        //idk

            o.WriteInt(0x091E100C); //flags??


            o.WriteShort(0);             //padding
            o.WriteShort(a.bones.Count); // numOfNodes

            o.WriteShort(a.frameCount);  // frame size
            o.WriteShort(0);             // frame start ??

            o.WriteInt(0);
            o.WriteInt(0);
            o.WriteInt(0);

            o.WriteIntAt(o.Size(), 0x14);

            // ASSESSMENT
            Vector3[] maxT     = new Vector3[a.bones.Count], minT = new Vector3[a.bones.Count];
            Vector4[] maxR     = new Vector4[a.bones.Count], minR = new Vector4[a.bones.Count];
            Vector3[] maxS     = new Vector3[a.bones.Count], minS = new Vector3[a.bones.Count];
            bool[]    hasScale = new bool[a.bones.Count];
            bool[]    hasTrans = new bool[a.bones.Count];
            bool[]    hasRot   = new bool[a.bones.Count];

            bool[] conScale = new bool[a.bones.Count];
            bool[] conTrans = new bool[a.bones.Count];
            bool[] conRot   = new bool[a.bones.Count];

            a.SetFrame(0);

            List <List <Bone> > Frames = new List <List <Bone> >();

            {
                for (int j = 0; j < a.bones.Count; j++)
                {
                    Animation.KeyNode keynode = ((Animation.KeyNode)a.bones[j]);
                    if (keynode.xpos.HasAnimation() || keynode.ypos.HasAnimation() || keynode.zpos.HasAnimation())
                    {
                        hasTrans[j] = true;
                    }
                    if (keynode.xrot.HasAnimation())
                    {
                        hasRot[j] = true;
                    }
                    if (keynode.xsca.HasAnimation() || keynode.ysca.HasAnimation() || keynode.zsca.HasAnimation())
                    {
                        hasScale[j] = true;
                    }

                    maxT[j] = new Vector3(-999f, -999f, -999f);
                    minT[j] = new Vector3(999f, 999f, 999f);
                    maxS[j] = new Vector3(-999f, -999f, -999f);
                    minS[j] = new Vector3(999f, 999f, 999f);
                    maxR[j] = new Vector4(-999f, -999f, -999f, -999f);
                    minR[j] = new Vector4(999f, 999f, 999f, 999f);

                    foreach (Animation.KeyFrame key in keynode.xpos.keys)
                    {
                        maxT[j].X = Math.Max(maxT[j].X, key.Value);
                        minT[j].X = Math.Min(minT[j].X, key.Value);
                    }
                    foreach (Animation.KeyFrame key in keynode.ypos.keys)
                    {
                        maxT[j].Y = Math.Max(maxT[j].Y, key.Value);
                        minT[j].Y = Math.Min(minT[j].Y, key.Value);
                    }
                    foreach (Animation.KeyFrame key in keynode.zpos.keys)
                    {
                        maxT[j].Z = Math.Max(maxT[j].Z, key.Value);
                        minT[j].Z = Math.Min(minT[j].Z, key.Value);
                    }
                    foreach (Animation.KeyFrame key in keynode.xsca.keys)
                    {
                        maxS[j].X = Math.Max(maxS[j].X, key.Value);
                        minS[j].X = Math.Min(minS[j].X, key.Value);
                    }
                    foreach (Animation.KeyFrame key in keynode.ysca.keys)
                    {
                        maxS[j].Y = Math.Max(maxS[j].Y, key.Value);
                        minS[j].Y = Math.Min(minS[j].Y, key.Value);
                    }
                    foreach (Animation.KeyFrame key in keynode.zsca.keys)
                    {
                        maxS[j].Z = Math.Max(maxS[j].Z, key.Value);
                        minS[j].Z = Math.Min(minS[j].Z, key.Value);
                    }

                    Bone b = vbn.getBone(keynode.Text);
                    for (int i = 0; i < a.frameCount; i++)
                    {
                        Quaternion r = new Quaternion();
                        if (keynode.rotType == Animation.RotationType.Quaternion)
                        {
                            Animation.KeyFrame[] x  = keynode.xrot.GetFrame(i);
                            Animation.KeyFrame[] y  = keynode.yrot.GetFrame(i);
                            Animation.KeyFrame[] z  = keynode.zrot.GetFrame(i);
                            Animation.KeyFrame[] w  = keynode.wrot.GetFrame(i);
                            Quaternion           q1 = new Quaternion(x[0].Value, y[0].Value, z[0].Value, w[0].Value);
                            Quaternion           q2 = new Quaternion(x[1].Value, y[1].Value, z[1].Value, w[1].Value);
                            if (x[0].Frame == i)
                            {
                                r = q1;
                            }
                            else
                            if (x[1].Frame == i)
                            {
                                r = q2;
                            }
                            else
                            {
                                r = Quaternion.Slerp(q1, q2, (i - x[0].Frame) / (x[1].Frame - x[0].Frame));
                            }
                        }
                        else
                        if (keynode.rotType == Animation.RotationType.Euler)
                        {
                            float x = keynode.xrot.HasAnimation() ? keynode.xrot.GetValue(i) : b.rotation[0];
                            float y = keynode.yrot.HasAnimation() ? keynode.yrot.GetValue(i) : b.rotation[1];
                            float z = keynode.zrot.HasAnimation() ? keynode.zrot.GetValue(i) : b.rotation[2];
                            r = Animation.EulerToQuat(z, y, x);
                        }
                        r.Normalize();

                        maxR[j].X = Math.Max(maxR[j].X, r.X);
                        minR[j].X = Math.Min(minR[j].X, r.X);
                        maxR[j].Y = Math.Max(maxR[j].Y, r.Y);
                        minR[j].Y = Math.Min(minR[j].Y, r.Y);
                        maxR[j].Z = Math.Max(maxR[j].Z, r.Z);
                        minR[j].Z = Math.Min(minR[j].Z, r.Z);
                    }

                    //if (b == null)continue;
                    if (b != null)
                    {
                        if (maxT[j].X == -999)
                        {
                            maxT[j].X = b.position[0];
                        }
                        if (maxT[j].Y == -999)
                        {
                            maxT[j].Y = b.position[1];
                        }
                        if (maxT[j].Z == -999)
                        {
                            maxT[j].Z = b.position[2];
                        }
                        if (minT[j].X == -999)
                        {
                            minT[j].X = b.position[0];
                        }
                        if (minT[j].Y == -999)
                        {
                            minT[j].Y = b.position[1];
                        }
                        if (minT[j].Z == -999)
                        {
                            minT[j].Z = b.position[2];
                        }

                        if (maxS[j].X == -999)
                        {
                            maxS[j].X = b.scale[0];
                        }
                        if (maxS[j].Y == -999)
                        {
                            maxS[j].Y = b.scale[1];
                        }
                        if (maxS[j].Z == -999)
                        {
                            maxS[j].Z = b.scale[2];
                        }
                        if (minS[j].X == -999)
                        {
                            minS[j].X = b.scale[0];
                        }
                        if (minS[j].Y == -999)
                        {
                            minS[j].Y = b.scale[1];
                        }
                        if (minS[j].Z == -999)
                        {
                            minS[j].Z = b.scale[2];
                        }
                    }
                }
            }

            //TODO: Euler Rotation Values

            /*VBN tempvbn = new VBN();
             * a.SetFrame(0);
             * for (int i = 0; i < a.FrameCount; i++)
             * {
             *  //Frames.Add(new List<Bone>());
             *  for (int j = 0; j < a.Bones.Count; j++)
             *  {
             *      Animation.KeyNode keynode = a.Bones[j];
             *      Bone b = vbn.getBone(keynode.Text);
             *      //if(b == null) continue;
             *      maxR[j].X = Math.Max(maxR[j].X, b.rot.X);
             *      minR[j].X = Math.Min(minR[j].X, b.rot.X);
             *      maxR[j].Y = Math.Max(maxR[j].Y, b.rot.Y);
             *      minR[j].Y = Math.Min(minR[j].Y, b.rot.Y);
             *      maxR[j].Z = Math.Max(maxR[j].Z, b.rot.Z);
             *      minR[j].Z = Math.Min(minR[j].Z, b.rot.Z);
             *
             *      Bone f1 = new Bone(tempvbn);
             *      f1.pos = b.pos;
             *      f1.rot = b.rot;
             *      f1.sca = b.sca;
             *      //Frames[i].Add(f1);
             *  }
             *  a.NextFrame(vbn);
             * }*/

            // NODE INFO

            int t2Size = 0;

            for (int i = 0; i < a.bones.Count; i++)
            {
                int flag = 0;

                conRot[i]   = false;
                conScale[i] = false;
                conTrans[i] = false;

                // check for constant
                if (maxT[i].Equals(minT[i]))
                {
                    conTrans[i] = true;
                }
                if (maxR[i].Equals(minR[i]))
                {
                    conRot[i] = true;
                }
                if (maxS[i].Equals(minS[i]))
                {
                    conScale[i] = true;
                }

                if (hasTrans[i])
                {
                    flag |= 0x01000000;
                }
                if (hasRot[i])
                {
                    flag |= 0x02000000;
                }
                if (hasScale[i])
                {
                    flag |= 0x04000000;
                }

                if (conTrans[i] && hasTrans[i])
                {
                    flag |= 0x00200000;
                }
                else
                {
                    flag |= 0x00080000;
                }

                if (conRot[i] && hasRot[i])
                {
                    flag |= 0x00007000;
                }
                else
                {
                    flag |= 0x00005000;
                }

                if (conScale[i] && hasScale[i])
                {
                    flag |= 0x00000200;
                }
                else
                {
                    flag |= 0x00000080;
                }

                flag |= 0x00000001;

                //uint id = 999;

                Bone b    = vbn.getBone(a.bones[i].Text);
                int  hash = -1;
                if (MainForm.hashes.names.ContainsKey(a.bones[i].Text))
                {
                    hash = (int)MainForm.hashes.names[a.bones[i].Text];
                }
                else
                {
                    if (b != null)
                    {
                        hash = (int)b.boneId;
                    }
                    else
                    {
                        continue;
                    }
                }
                //if(hash == -1)
                //hash = (int)FileData.crc32(getNodeId(nodeid.get(i)).name);
                o.WriteInt(flag);      // flags...
                o.WriteInt(hash);      //hash
                o.WriteInt(t1.Size()); // Offset in 1 table
                o.WriteInt(t2Size);    // Offset in 2 table

                // calculate size needed
                if (hasTrans[i])
                {
                    t1.WriteFloat(minT[i].X);
                    t1.WriteFloat(minT[i].Y);
                    t1.WriteFloat(minT[i].Z);

                    if (!conTrans[i])
                    {
                        maxT[i].X -= minT[i].X;
                        maxT[i].Y -= minT[i].Y;
                        maxT[i].Z -= minT[i].Z;

                        t1.WriteFloat(maxT[i].X);
                        t1.WriteFloat(maxT[i].Y);
                        t1.WriteFloat(maxT[i].Z);

                        t2Size += 6;
                    }
                }

                if (hasRot[i])
                {
                    t1.WriteFloat(minR[i].X);
                    t1.WriteFloat(minR[i].Y);
                    t1.WriteFloat(minR[i].Z);

                    if (!conRot[i])
                    {
                        maxR[i].X -= minR[i].X;
                        maxR[i].Y -= minR[i].Y;
                        maxR[i].Z -= minR[i].Z;

                        t1.WriteFloat(maxR[i].X);
                        t1.WriteFloat(maxR[i].Y);
                        t1.WriteFloat(maxR[i].Z);

                        t2Size += 6;
                    }
                }

                if (hasScale[i])
                {
                    t1.WriteFloat(minS[i].X);
                    t1.WriteFloat(minS[i].Y);
                    t1.WriteFloat(minS[i].Z);

                    if (!conScale[i])
                    {
                        maxS[i].X -= minS[i].X;
                        maxS[i].Y -= minS[i].Y;
                        maxS[i].Z -= minS[i].Z;

                        t1.WriteFloat(maxS[i].X);
                        t1.WriteFloat(maxS[i].Y);
                        t1.WriteFloat(maxS[i].Z);

                        t2Size += 6;
                    }
                }
            }

            o.WriteIntAt(o.Size(), 0x18);

            o.WriteOutput(t1);

            o.WriteIntAt(o.Size(), 0x1C);

            // INTERPOLATION

            a.SetFrame(0);

            bool go = true;

            for (int i = 0; i < a.frameCount; i++)
            {
                //a.NextFrame(vbn);
                for (int j = 0; j < a.bones.Count; j++)
                {
                    Bone node = vbn.getBone(a.bones[j].Text);

                    Animation.KeyNode anode = a.bones[j];
                    //if (node == null) continue;

                    if (hasTrans[j] && !conTrans[j])
                    {
                        t2.WriteShort((int)(((anode.xpos.GetValue(i) - minT[j].X) / maxT[j].X) * 0xFFFF));
                        t2.WriteShort((int)(((anode.ypos.GetValue(i) - minT[j].Y) / maxT[j].Y) * 0xFFFF));
                        t2.WriteShort((int)(((anode.zpos.GetValue(i) - minT[j].Z) / maxT[j].Z) * 0xFFFF));
                    }

                    if (hasRot[j] && !conRot[j])
                    {
                        Quaternion r = new Quaternion();
                        if (anode.rotType == Animation.RotationType.Quaternion)
                        {
                            Animation.KeyFrame[] x  = anode.xrot.GetFrame(i);
                            Animation.KeyFrame[] y  = anode.yrot.GetFrame(i);
                            Animation.KeyFrame[] z  = anode.zrot.GetFrame(i);
                            Animation.KeyFrame[] w  = anode.wrot.GetFrame(i);
                            Quaternion           q1 = new Quaternion(x[0].Value, y[0].Value, z[0].Value, w[0].Value);
                            Quaternion           q2 = new Quaternion(x[1].Value, y[1].Value, z[1].Value, w[1].Value);
                            if (x[0].Frame == i)
                            {
                                r = q1;
                            }
                            else
                            if (x[1].Frame == i)
                            {
                                r = q2;
                            }
                            else
                            {
                                r = Quaternion.Slerp(q1, q2, (i - x[0].Frame) / (x[1].Frame - x[0].Frame));
                            }
                        }
                        else
                        if (anode.rotType == Animation.RotationType.Euler)
                        {
                            float x = anode.xrot.HasAnimation() ? anode.xrot.GetValue(i) : node.rotation[0];
                            float y = anode.yrot.HasAnimation() ? anode.yrot.GetValue(i) : node.rotation[1];
                            float z = anode.zrot.HasAnimation() ? anode.zrot.GetValue(i) : node.rotation[2];
                            r = Animation.EulerToQuat(z, y, x);
                        }
                        r.Normalize();
                        t2.WriteShort((int)(((r.X - minR[j].X) / maxR[j].X) * 0xFFFF));
                        t2.WriteShort((int)(((r.Y - minR[j].Y) / maxR[j].Y) * 0xFFFF));
                        t2.WriteShort((int)(((r.Z - minR[j].Z) / maxR[j].Z) * 0xFFFF));
                    }

                    if (hasScale[j] && !conScale[j])
                    {
                        t2.WriteShort((int)(((anode.xsca.GetValue(i) - minS[j].X) / maxS[j].X) * 0xFFFF));
                        t2.WriteShort((int)(((anode.ysca.GetValue(i) - minS[j].Y) / maxS[j].Y) * 0xFFFF));
                        t2.WriteShort((int)(((anode.zsca.GetValue(i) - minS[j].Z) / maxS[j].Z) * 0xFFFF));
                    }
                }

                if (go)
                {
                    o.WriteShortAt(t2.Size(), 0x12);
                    go = false;
                }
            }

            o.WriteOutput(t2);
            return(o.GetBytes());
        }
    }
示例#26
0
        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);
        }
示例#27
0
        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);
        }
示例#28
0
        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());
        }