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)); } } //------ }
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); }