public override void Read(string filename) { bchHeader header = new bchHeader(); FileData f = new FileData(filename); f.endian = System.IO.Endianness.Little; f.Skip(4); header.backwardCompatibility = f.ReadByte(); header.forwardCompatibility = f.ReadByte(); header.version = f.ReadUShort(); header.mainHeaderOffset = f.ReadInt(); header.stringTableOffset = f.ReadInt(); header.gpuCommandsOffset = f.ReadInt(); header.dataOffset = f.ReadInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedOffset = f.ReadInt(); } header.relocationTableOffset = f.ReadInt(); header.mainHeaderLength = f.ReadInt(); header.stringTableLength = f.ReadInt(); header.gpuCommandsLength = f.ReadInt(); header.dataLength = f.ReadInt(); if (header.backwardCompatibility > 0x20) { header.dataExtendedLength = f.ReadInt(); } header.relocationTableLength = f.ReadInt(); header.uninitializedDataSectionLength = f.ReadInt(); header.uninitializedDescriptionSectionLength = f.ReadInt(); if (header.backwardCompatibility > 7) { header.flags = f.ReadUShort(); header.addressCount = f.ReadUShort(); } // Relocation table for (int i = 0; i < header.relocationTableLength; i += 4) { f.Seek(header.relocationTableOffset + i); int val = f.ReadInt(); int off = val & 0x1FFFFFF; byte flag = (byte)(val >> 25); switch (flag) { case 0: f.Seek((off * 4) + header.mainHeaderOffset); f.WriteInt((off * 4) + header.mainHeaderOffset, f.ReadInt() + header.mainHeaderOffset); break; case 1: f.Seek(off + header.mainHeaderOffset); f.WriteInt((off) + header.mainHeaderOffset, f.ReadInt() + header.stringTableOffset); break; case 2: f.Seek((off * 4) + header.mainHeaderOffset); f.WriteInt((off * 4) + header.mainHeaderOffset, f.ReadInt() + header.gpuCommandsOffset); break; case 0xc: f.Seek((off * 4) + header.mainHeaderOffset); f.WriteInt((off * 4) + header.mainHeaderOffset, f.ReadInt() + header.dataOffset); break; } f.Seek((off * 4) + header.gpuCommandsOffset); if (header.backwardCompatibility < 6) { switch (flag) { case 0x23: f.WriteInt((off * 4) + header.gpuCommandsOffset, f.ReadInt() + header.dataOffset); break; //Texture case 0x25: f.WriteInt((off * 4) + header.gpuCommandsOffset, f.ReadInt() + header.dataOffset); break; //Vertex //case 0x26: f.writeInt((off * 4) + header.gpuCommandsOffset, ((f.readInt() + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x27: f.WriteInt((off * 4) + header.gpuCommandsOffset, (f.ReadInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (header.backwardCompatibility < 8) { switch (flag) { case 0x24: f.WriteInt((off * 4) + header.gpuCommandsOffset, f.ReadInt() + header.dataOffset); break; //Texture case 0x26: f.WriteInt((off * 4) + header.gpuCommandsOffset, f.ReadInt() + header.dataOffset); break; //Vertex //case 0x27: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x28: f.WriteInt((off * 4) + header.gpuCommandsOffset, (f.ReadInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (header.backwardCompatibility < 0x21) { switch (flag) { case 0x25: f.WriteInt((off * 4) + header.gpuCommandsOffset, f.ReadInt() + header.dataOffset); break; //Texture case 0x27: f.WriteInt((off * 4) + header.gpuCommandsOffset, f.ReadInt() + header.dataOffset); break; //Vertex //case 0x28: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x29: f.WriteInt((off * 4) + header.gpuCommandsOffset, (f.ReadInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else { switch (flag) { case 0x25: f.WriteInt((off * 4) + header.gpuCommandsOffset, f.ReadInt() + header.dataOffset); break; //Texture case 0x26: f.WriteInt((off * 4) + header.gpuCommandsOffset, f.ReadInt() + header.dataOffset); break; //Vertex relative to Data Offset //case 0x27: writer.Write(((peek(input) + header.dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Offset case 0x28: f.WriteInt((off * 4) + header.gpuCommandsOffset, (f.ReadInt() + header.dataOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Offset case 0x2b: f.WriteInt((off * 4) + header.gpuCommandsOffset, f.ReadInt() + header.dataExtendedOffset); break; //Vertex relative to Data Extended Offset //case 0x2c: writer.Write(((peek(input) + header.dataExtendedOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Extended Offset case 0x2d: f.WriteInt((off * 4) + header.gpuCommandsOffset, (f.ReadInt() + header.dataExtendedOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Extended Offset } } } // Content Header f.Seek(header.mainHeaderOffset); bchContentHeader content = new bchContentHeader(); { content.modelsPointerTableOffset = f.ReadInt(); content.modelsPointerTableEntries = f.ReadInt(); content.modelsNameOffset = f.ReadInt(); content.materialsPointerTableOffset = f.ReadInt(); content.materialsPointerTableEntries = f.ReadInt(); content.materialsNameOffset = f.ReadInt(); content.shadersPointerTableOffset = f.ReadInt(); content.shadersPointerTableEntries = f.ReadInt(); content.shadersNameOffset = f.ReadInt(); content.texturesPointerTableOffset = f.ReadInt(); content.texturesPointerTableEntries = f.ReadInt(); content.texturesNameOffset = f.ReadInt(); content.materialsLUTPointerTableOffset = f.ReadInt(); content.materialsLUTPointerTableEntries = f.ReadInt(); content.materialsLUTNameOffset = f.ReadInt(); content.lightsPointerTableOffset = f.ReadInt(); content.lightsPointerTableEntries = f.ReadInt(); content.lightsNameOffset = f.ReadInt(); content.camerasPointerTableOffset = f.ReadInt(); content.camerasPointerTableEntries = f.ReadInt(); content.camerasNameOffset = f.ReadInt(); content.fogsPointerTableOffset = f.ReadInt(); content.fogsPointerTableEntries = f.ReadInt(); content.fogsNameOffset = f.ReadInt(); content.skeletalAnimationsPointerTableOffset = f.ReadInt(); content.skeletalAnimationsPointerTableEntries = f.ReadInt(); content.skeletalAnimationsNameOffset = f.ReadInt(); content.materialAnimationsPointerTableOffset = f.ReadInt(); content.materialAnimationsPointerTableEntries = f.ReadInt(); content.materialAnimationsNameOffset = f.ReadInt(); content.visibilityAnimationsPointerTableOffset = f.ReadInt(); content.visibilityAnimationsPointerTableEntries = f.ReadInt(); content.visibilityAnimationsNameOffset = f.ReadInt(); content.lightAnimationsPointerTableOffset = f.ReadInt(); content.lightAnimationsPointerTableEntries = f.ReadInt(); content.lightAnimationsNameOffset = f.ReadInt(); content.cameraAnimationsPointerTableOffset = f.ReadInt(); content.cameraAnimationsPointerTableEntries = f.ReadInt(); content.cameraAnimationsNameOffset = f.ReadInt(); content.fogAnimationsPointerTableOffset = f.ReadInt(); content.fogAnimationsPointerTableEntries = f.ReadInt(); content.fogAnimationsNameOffset = f.ReadInt(); content.scenePointerTableOffset = f.ReadInt(); content.scenePointerTableEntries = f.ReadInt(); content.sceneNameOffset = f.ReadInt(); } //Skeletal animation for (int index1 = 0; index1 < content.skeletalAnimationsPointerTableEntries; index1++) { f.Seek(content.skeletalAnimationsPointerTableOffset + (index1 * 4)); int dataOffset = f.ReadInt(); f.Seek(dataOffset); string skeletalAnimationName = f.ReadString(f.ReadInt(), -1); int animationFlags = f.ReadInt(); //int skeletalAnimationloopMode = f.readByte(); //pas �a du tout float skeletalAnimationframeSize = f.ReadFloat(); int boneTableOffset = f.ReadInt(); int boneTableEntries = f.ReadInt(); int metaDataPointerOffset = f.ReadInt(); //Debug.WriteLine("Animation Name: " + skeletalAnimationName); //Debug.WriteLine("BonetableOffset: " + boneTableOffset.ToString("X")); //Debug.WriteLine("BonetableEntry: " + boneTableEntries.ToString("X")); for (int i = 0; i < boneTableEntries; i++) { f.Seek(boneTableOffset + (i * 4)); int offset = f.ReadInt(); OSkeletalAnimationBone bone = new OSkeletalAnimationBone(); f.Seek(offset); bone.name = f.ReadString(f.ReadInt(), -1); Console.WriteLine("Bone Name: " + bone.name); int animationTypeFlags = f.ReadInt(); int flags = f.ReadInt(); OSegmentType segmentType = (OSegmentType)((animationTypeFlags >> 16) & 0xf); switch (segmentType) { case OSegmentType.transform: f.Seek(offset + 0x18); int notExistMask = 0x80000; int constantMask = 0x200; for (int j = 0; j < 2; j++) { for (int axis = 0; axis < 3; axis++) { bool notExist = (flags & notExistMask) > 0; bool constant = (flags & constantMask) > 0; OAnimationKeyFrameGroup frame = new OAnimationKeyFrameGroup(); frame.exists = !notExist; if (frame.exists) { if (constant) { frame.interpolation = OInterpolationMode.linear; frame.keyFrames.Add(new OAnimationKeyFrame(f.ReadFloat(), 0)); } else { int frameOffset = f.ReadInt(); int position = f.Pos(); f.Seek(frameOffset); //getAnimationKeyFrame(input, frame); f.Seek(position); } } else { f.Seek(f.Pos() + 0x04); } if (j == 0) { switch (axis) { case 0: bone.rotationX = frame; break; case 1: bone.rotationY = frame; break; case 2: bone.rotationZ = frame; break; } } else { switch (axis) { case 0: bone.translationX = frame; break; case 1: bone.translationY = frame; break; case 2: bone.translationZ = frame; break; } } notExistMask <<= 1; constantMask <<= 1; } constantMask <<= 1; } break; case OSegmentType.transformQuaternion: bone.isFrameFormat = true; int scaleOffset = f.ReadInt(); int rotationOffset = f.ReadInt(); int translationOffset = f.ReadInt(); if ((flags & 0x20) == 0) { bone.scale.exists = true; f.Seek(scaleOffset); if ((flags & 4) > 0) { bone.scale.vector.Add(new Vector4( f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), 0)); } else { bone.scale.startFrame = f.ReadFloat(); bone.scale.endFrame = f.ReadFloat(); int scaleFlags = f.ReadInt(); int scaleDataOffset = f.ReadInt(); int scaleEntries = f.ReadInt(); f.Seek(scaleDataOffset); for (int j = 0; j < scaleEntries; j++) { bone.scale.vector.Add(new Vector4( f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), 0)); } } } if ((flags & 0x10) == 0) { bone.rotationQuaternion.exists = true; f.Seek(rotationOffset); if ((flags & 2) > 0) { bone.rotationQuaternion.vector.Add(new Vector4( f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), f.ReadFloat())); } else { bone.rotationQuaternion.startFrame = f.ReadFloat(); bone.rotationQuaternion.endFrame = f.ReadFloat(); int rotationFlags = f.ReadInt(); int rotationDataOffset = f.ReadInt(); int rotationEntries = f.ReadInt(); f.Seek(rotationDataOffset); for (int j = 0; j < rotationEntries; j++) { bone.rotationQuaternion.vector.Add(new Vector4( f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), f.ReadFloat())); } } } if ((flags & 8) == 0) { bone.translation.exists = true; f.Seek(translationOffset); if ((flags & 1) > 0) { bone.translation.vector.Add(new Vector4( f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), 0)); } else { bone.translation.startFrame = f.ReadFloat(); bone.translation.endFrame = f.ReadFloat(); int translationFlags = f.ReadInt(); int translationDataOffset = f.ReadInt(); int translationEntries = f.ReadInt(); f.Seek(translationDataOffset); for (int j = 0; j < translationEntries; j++) { bone.translation.vector.Add(new Vector4( f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), 0)); } } } break; case OSegmentType.transformMatrix: bone.isFullBakedFormat = true; f.ReadInt(); f.ReadInt(); int matrixOffset = f.ReadInt(); int entries = f.ReadInt(); f.Seek(matrixOffset); for (int j = 0; j < entries; j++) { /*OMatrix transform = new OMatrix(); * transform.M11 = f.readFloat(); * transform.M21 = f.readFloat(); * transform.M31 = f.readFloat(); * transform.M41 = f.readFloat(); * * transform.M12 = f.readFloat(); * transform.M22 = f.readFloat(); * transform.M32 = f.readFloat(); * transform.M42 = f.readFloat(); * * transform.M13 = f.readFloat(); * transform.M23 = f.readFloat(); * transform.M33 = f.readFloat(); * transform.M43 = f.readFloat(); * * bone.transform.Add(transform);*/ } break; default: throw new Exception(string.Format("BCH: Unknow Segment Type {0} on Skeletal Animation bone {1}! STOP!", segmentType, bone.name)); } //skeletalAnimation.bone.Add(bone); } } //Shaders (unused for now, until someone wants to add them) for (int index = 0; index < content.shadersPointerTableEntries; index++) { f.Seek(content.shadersPointerTableOffset + (index * 4)); int dataOffset = f.ReadInt(); f.Seek(dataOffset); int shaderDataOffset = f.ReadInt(); int shaderDataLength = f.ReadInt(); } // Textures // WIP Section for (int index = 0; index < content.texturesPointerTableEntries; index++) { f.Seek(content.texturesPointerTableOffset + (index * 4)); int dOffset = f.ReadInt(); f.Seek(dOffset); int textureCommandsOffset = f.ReadInt(); int textureCommandsWordCount = f.ReadInt(); f.Seek(f.Pos() + 0x14); String textureName = f.ReadString(f.ReadInt(), -1); f.Seek(textureCommandsOffset); BchTexture tex = new BchTexture(); textures.Add(textureName, tex); tex.height = f.ReadUShort(); tex.width = f.ReadUShort(); f.Skip(12); int doffset = f.ReadInt(); f.Skip(4); tex.type = f.ReadInt(); tex.data = f.GetSection(doffset, f.Size() - doffset); tex.texture = _3DS.DecodeImage(tex.data, tex.width, tex.height, (_3DS.Tex_Formats)tex.type); //Texture texture = new Texture2D(tex.texture); //tex.display = texture.Id; } // Model data for (int modelIndex = 0; modelIndex < content.modelsPointerTableEntries; modelIndex++) { f.Seek(content.modelsPointerTableOffset + (modelIndex * 4)); int objectsHeaderOffset = f.ReadInt(); // Objects f.Seek(objectsHeaderOffset); BCH_Model model = new BCH_Model(); models.Add(model); model.flags = f.ReadByte(); model.skeletonScaleType = f.ReadByte(); model.silhouetteMaterialEntries = f.ReadUShort(); model.worldTransform = new Matrix4(f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), f.ReadFloat() , f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), f.ReadFloat() , f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), f.ReadFloat() , 0, 0, 0, 1); int materialsTableOffset = f.ReadInt(); int materialsTableEntries = f.ReadInt(); int materialsNameOffset = f.ReadInt(); int verticesTableOffset = f.ReadInt(); int verticesTableEntries = f.ReadInt(); f.Skip(0x28); int skeletonOffset = f.ReadInt(); int skeletonEntries = f.ReadInt(); int skeletonNameOffset = f.ReadInt(); int objectsNodeVisibilityOffset = f.ReadInt(); int objectsNodeCount = f.ReadInt(); String name = f.ReadString(f.ReadInt(), -1); int objectsNodeNameEntries = f.ReadInt(); int objectsNodeNameOffset = f.ReadInt(); f.ReadInt(); //0x0 int metaDataPointerOffset = f.ReadInt(); f.Seek(objectsNodeVisibilityOffset); int nodeVisibility = f.ReadInt(); string[] objectName = new string[objectsNodeNameEntries]; f.Seek(objectsNodeNameOffset); int rootReferenceBit = f.ReadInt(); //Radix tree int rootLeftNode = f.ReadUShort(); int rootRightNode = f.ReadUShort(); int rootNameOffset = f.ReadInt(); for (int i = 0; i < objectsNodeNameEntries; i++) { int referenceBit = f.ReadInt(); short leftNode = f.ReadShort(); short rightNode = f.ReadShort(); objectName[i] = f.ReadString(f.ReadInt(), -1); } // Materials // NOTE: MATERIALS AND OBJECT SECTIONS ARE REALLY MESSY ATM String[] materialNames = new String[materialsTableEntries]; for (int index = 0; index < materialsTableEntries; index++) { f.Seek(materialsTableOffset + (index * 0x2c)); int materialParametersOffset = f.ReadInt(); f.ReadInt(); f.ReadInt(); f.ReadInt(); int textureCommandsOffset = f.ReadInt(); int textureCommandsWordCount = f.ReadInt(); int materialMapperOffset = f.ReadInt(); materialNames[index] = f.ReadString(f.ReadInt(), -1); } // Object Descriptions... // Assumes MBN is already loaded for now f.Seek(verticesTableOffset); List <objDes> objDescriptors = new List <objDes>(); if (mbn == null) { mbn = new MBN(); for (int index = 0; index < verticesTableEntries; index++) { mbn.mesh.Add(new MBN.Mesh()); } mbn.PreRender(); } for (int index = 0; index < mbn.mesh.Count; index++) { int i = f.ReadUShort(); if (index > mbn.mesh.Count) { break; } if (i > materialNames.Length) { break; } mbn.mesh[index].texId = textures[materialNames[i]].display; Console.WriteLine("Tex index" + mbn.mesh[index].texId); f.Skip(2); // flags int nameId = f.ReadUShort(); mbn.mesh[index].Text = objectName[nameId]; // node visibility TODO: finish... mbn.mesh[index].Checked = ((nodeVisibility & (1 << nameId)) > 0); mbn.mesh[index].renderPriority = f.ReadUShort(); objDes des = new objDes(); objDescriptors.Add(des); des.vshAttBufferCommandOffset = f.ReadInt(); des.vshAttBufferCommandCount = f.ReadInt(); des.faceOffset = f.ReadInt(); des.faceCount = f.ReadInt(); des.vshAttBufferCommandOffsetEx = f.ReadInt(); des.vshAttBufferCommandCountEx = f.ReadInt(); f.Skip(12); // center vector f.Skip(4); // flagsOffset f.Skip(4); // 0? f.ReadInt(); //bbOffsets[i] } //Skeleton f.Seek(skeletonOffset); for (int index = 0; index < skeletonEntries; index++) { Bone bone = new Bone(model.skeleton); int boneFlags = f.ReadInt(); bone.parentIndex = f.ReadShort(); short boneSpace = f.ReadShort(); bone.scale = new float[3]; bone.rotation = new float[3]; bone.position = new float[3]; bone.scale[0] = f.ReadFloat(); bone.scale[1] = f.ReadFloat(); bone.scale[2] = f.ReadFloat(); bone.rotation[0] = f.ReadFloat(); bone.rotation[1] = f.ReadFloat(); bone.rotation[2] = f.ReadFloat(); bone.position[0] = f.ReadFloat(); bone.position[1] = f.ReadFloat(); bone.position[2] = f.ReadFloat(); // bone matrix... not really needed to be stored per say f.Skip(4 * 4 * 3); bone.Text = f.ReadString(f.ReadInt(), -1); f.Skip(4); // Meta data bones.bones.Add(bone); model.skeleton.bones.Add(bone); } model.skeleton.reset(); model.skeleton.update(); } }
public override void Read(string filename) { FileData f = new FileData(filename); f.endian = System.IO.Endianness.Little; f.Skip(4); int backwardCompatibility = f.ReadByte(); int forwardCompatibility = f.ReadByte(); int version = f.ReadUShort(); int mainHeaderOffset = f.ReadInt(); int stringTableOffset = f.ReadInt(); int gpuCommandsOffset = f.ReadInt(); int dataOffset = f.ReadInt(); int dataExtendedOffset = 0; int dataExtendedLength = 0; if (backwardCompatibility > 0x20) { dataExtendedOffset = f.ReadInt(); } int relocationTableOffset = f.ReadInt(); int mainHeaderLength = f.ReadInt(); int stringTableLength = f.ReadInt(); int gpuCommandsLength = f.ReadInt(); int dataLength = f.ReadInt(); if (backwardCompatibility > 0x20) { dataExtendedLength = f.ReadInt(); } int relocationTableLength = f.ReadInt(); int uninitializedDataSectionLength = f.ReadInt(); int uninitializedDescriptionSectionLength = f.ReadInt(); if (backwardCompatibility > 7) { int flags = f.ReadUShort(); int addressCount = f.ReadUShort(); } // Relocation table for (int i = 0; i < relocationTableLength; i += 4) { f.Seek(relocationTableOffset + i); int val = f.ReadInt(); int off = val & 0x1FFFFFF; byte flag = (byte)(val >> 25); switch (flag) { case 0: f.Seek((off * 4) + mainHeaderOffset); f.WriteInt((off * 4) + mainHeaderOffset, f.ReadInt() + mainHeaderOffset); break; case 1: f.Seek(off + mainHeaderOffset); f.WriteInt((off) + mainHeaderOffset, f.ReadInt() + stringTableOffset); break; case 2: f.Seek((off * 4) + mainHeaderOffset); f.WriteInt((off * 4) + mainHeaderOffset, f.ReadInt() + gpuCommandsOffset); break; case 0xc: f.Seek((off * 4) + mainHeaderOffset); f.WriteInt((off * 4) + mainHeaderOffset, f.ReadInt() + dataOffset); break; } f.Seek((off * 4) + gpuCommandsOffset); if (backwardCompatibility < 6) { switch (flag) { case 0x23: f.WriteInt((off * 4) + gpuCommandsOffset, f.ReadInt() + dataOffset); break; //Texture case 0x25: f.WriteInt((off * 4) + gpuCommandsOffset, f.ReadInt() + dataOffset); break; //Vertex //case 0x26: f.writeInt((off * 4) + int gpuCommandsOffset, ((f.readInt() + int dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x27: f.WriteInt((off * 4) + gpuCommandsOffset, (f.ReadInt() + dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (backwardCompatibility < 8) { switch (flag) { case 0x24: f.WriteInt((off * 4) + gpuCommandsOffset, f.ReadInt() + dataOffset); break; //Texture case 0x26: f.WriteInt((off * 4) + gpuCommandsOffset, f.ReadInt() + dataOffset); break; //Vertex //case 0x27: writer.Write(((peek(input) + int dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x28: f.WriteInt((off * 4) + gpuCommandsOffset, (f.ReadInt() + dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else if (backwardCompatibility < 0x21) { switch (flag) { case 0x25: f.WriteInt((off * 4) + gpuCommandsOffset, f.ReadInt() + dataOffset); break; //Texture case 0x27: f.WriteInt((off * 4) + gpuCommandsOffset, f.ReadInt() + dataOffset); break; //Vertex //case 0x28: writer.Write(((peek(input) + int dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode case 0x29: f.WriteInt((off * 4) + gpuCommandsOffset, (f.ReadInt() + dataOffset) & 0x7fffffff); break; //Index 8 bits mode } } else { switch (flag) { case 0x25: f.WriteInt((off * 4) + gpuCommandsOffset, f.ReadInt() + dataOffset); break; //Texture case 0x26: f.WriteInt((off * 4) + gpuCommandsOffset, f.ReadInt() + dataOffset); break; //Vertex relative to Data Offset //case 0x27: writer.Write(((peek(input) + int dataOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Offset case 0x28: f.WriteInt((off * 4) + gpuCommandsOffset, (f.ReadInt() + dataOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Offset case 0x2b: f.WriteInt((off * 4) + gpuCommandsOffset, f.ReadInt() + dataExtendedOffset); break; //Vertex relative to Data Extended Offset //case 0x2c: writer.Write(((peek(input) + int dataExtendedOffset) & 0x7fffffff) | 0x80000000); break; //Index 16 bits mode relative to Data Extended Offset case 0x2d: f.WriteInt((off * 4) + gpuCommandsOffset, (f.ReadInt() + dataExtendedOffset) & 0x7fffffff); break; //Index 8 bits mode relative to Data Extended Offset } } } //File.WriteAllBytes(filename + "_offset", f.getSection(0, f.size())); f.Seek(mainHeaderOffset); int modelsPointerTableOffset = f.ReadInt(); int modelsPointerTableEntries = f.ReadInt(); int modelsNameOffset = f.ReadInt(); int materialsPointerTableOffset = f.ReadInt(); int materialsPointerTableEntries = f.ReadInt(); int materialsNameOffset = f.ReadInt(); int shadersPointerTableOffset = f.ReadInt(); int shadersPointerTableEntries = f.ReadInt(); int shadersNameOffset = f.ReadInt(); int texturesPointerTableOffset = f.ReadInt(); int texturesPointerTableEntries = f.ReadInt(); int texturesNameOffset = f.ReadInt(); int materialsLUTPointerTableOffset = f.ReadInt(); int materialsLUTPointerTableEntries = f.ReadInt(); int materialsLUTNameOffset = f.ReadInt(); int lightsPointerTableOffset = f.ReadInt(); int lightsPointerTableEntries = f.ReadInt(); int lightsNameOffset = f.ReadInt(); int camerasPointerTableOffset = f.ReadInt(); int camerasPointerTableEntries = f.ReadInt(); int camerasNameOffset = f.ReadInt(); int fogsPointerTableOffset = f.ReadInt(); int fogsPointerTableEntries = f.ReadInt(); int fogsNameOffset = f.ReadInt(); int skeletalAnimationsPointerTableOffset = f.ReadInt(); int skeletalAnimationsPointerTableEntries = f.ReadInt(); int skeletalAnimationsNameOffset = f.ReadInt(); int materialAnimationsPointerTableOffset = f.ReadInt(); int materialAnimationsPointerTableEntries = f.ReadInt(); int materialAnimationsNameOffset = f.ReadInt(); int visibilityAnimationsPointerTableOffset = f.ReadInt(); int visibilityAnimationsPointerTableEntries = f.ReadInt(); int visibilityAnimationsNameOffset = f.ReadInt(); int lightAnimationsPointerTableOffset = f.ReadInt(); int lightAnimationsPointerTableEntries = f.ReadInt(); int lightAnimationsNameOffset = f.ReadInt(); int cameraAnimationsPointerTableOffset = f.ReadInt(); int cameraAnimationsPointerTableEntries = f.ReadInt(); int cameraAnimationsNameOffset = f.ReadInt(); int fogAnimationsPointerTableOffset = f.ReadInt(); int fogAnimationsPointerTableEntries = f.ReadInt(); int fogAnimationsNameOffset = f.ReadInt(); int scenePointerTableOffset = f.ReadInt(); int scenePointerTableEntries = f.ReadInt(); int sceneNameOffset = f.ReadInt(); Console.WriteLine(modelsPointerTableEntries > 0 ? "Has Models" : ""); Console.WriteLine(shadersPointerTableEntries > 0 ? "Has Shaders" : ""); Console.WriteLine(texturesPointerTableEntries > 0 ? "Has Textures" : ""); Console.WriteLine(materialsPointerTableEntries > 0 ? "Has Materials" : ""); Console.WriteLine(materialsLUTPointerTableEntries > 0 ? "Has Material LUT" : ""); Console.WriteLine(materialAnimationsPointerTableEntries > 0 ? "Has Material Animation" : ""); Console.WriteLine(lightsPointerTableEntries > 0 ? "Has Lights" : ""); Console.WriteLine(lightAnimationsPointerTableEntries > 0 ? "Has LightAnimations" : ""); Console.WriteLine(camerasPointerTableEntries > 0 ? "Has Camera" : ""); Console.WriteLine(cameraAnimationsPointerTableEntries > 0 ? "Has CameraAnimation" : ""); Console.WriteLine(fogsPointerTableEntries > 0 ? "Has Fog" : ""); Console.WriteLine(fogAnimationsPointerTableEntries > 0 ? "Has FogAnimation" : ""); Console.WriteLine(skeletalAnimationsPointerTableEntries > 0 ? "Has Skeletal Animations" : ""); Console.WriteLine(visibilityAnimationsPointerTableEntries > 0 ? "Has Visibility" : ""); Console.WriteLine(scenePointerTableEntries > 0 ? "Has Scene" : ""); // Textures for (int index = 0; index < texturesPointerTableEntries; index++) { f.Seek(texturesPointerTableOffset + (index * 4)); int dOffset = f.ReadInt(); f.Seek(dOffset); // one for each mip I assume int textureCommandsOffset = f.ReadInt(); int textureCommandsWordCount = f.ReadInt(); int textureCommandsOffset2 = f.ReadInt(); int textureCommandsWordCount2 = f.ReadInt(); int textureCommandsOffset3 = f.ReadInt(); int textureCommandsWordCount3 = f.ReadInt(); int unk = f.ReadInt(); BchTexture tex = new BchTexture(); tex.Text = f.ReadString(f.ReadInt(), -1); Textures.Nodes.Add(tex); f.Seek(textureCommandsOffset); tex.ReadParameters(f, textureCommandsWordCount); } //Models for (int index = 0; index < modelsPointerTableEntries; index++) { f.Seek(modelsPointerTableOffset + (index * 4)); f.Seek(f.ReadInt()); BCH_Model model = new BCH_Model(); Models.Nodes.Add(model); model.flags = f.ReadByte(); model.skeletonScaleType = f.ReadByte(); model.silhouetteMaterialEntries = f.ReadUShort(); model.worldTransform = new OpenTK.Matrix4(f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), f.ReadFloat() , f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), f.ReadFloat() , f.ReadFloat(), f.ReadFloat(), f.ReadFloat(), f.ReadFloat() , 0, 0, 0, 1); int materialsTableOffset = f.ReadInt(); int materialsTableEntries = f.ReadInt(); int materialNameOffset = f.ReadInt(); int verticesTableOffset = f.ReadInt(); int verticesTableEntries = f.ReadInt(); f.Skip(0x28); int skeletonOffset = f.ReadInt(); int skeletonEntries = f.ReadInt(); int skeletonNameOffset = f.ReadInt(); int objectsNodeVisibilityOffset = f.ReadInt(); int objectsNodeCount = f.ReadInt(); model.Text = f.ReadString(f.ReadInt(), -1); int objectsNodeNameEntries = f.ReadInt(); int objectsNodeNameOffset = f.ReadInt(); f.ReadInt(); //0x0 int metaDataPointerOffset = f.ReadInt(); f.Seek(objectsNodeVisibilityOffset); int nodeVisibility = f.ReadInt(); string[] objectName = new string[objectsNodeNameEntries]; f.Seek(objectsNodeNameOffset); int rootReferenceBit = f.ReadInt(); int rootLeftNode = f.ReadUShort(); int rootRightNode = f.ReadUShort(); int rootNameOffset = f.ReadInt(); //Console.WriteLine(rootReferenceBit.ToString("x") + " " + f.readString(rootNameOffset, -1) + " " + rootLeftNode + " " + rootRightNode); // Object name tree Radix Tree for (int i = 0; i < objectsNodeNameEntries; i++) { int referenceBit = f.ReadInt(); short leftNode = f.ReadShort(); short rightNode = f.ReadShort(); objectName[i] = f.ReadString(f.ReadInt(), -1); Console.WriteLine((referenceBit >> 3) + " " + (referenceBit & 0x7) + " " + objectName[i] + " " + leftNode + " " + rightNode); } //TODO: Metadata, boundingbox, normal mesh, materials f.Seek(verticesTableOffset); Dictionary <int, BCH_Mesh> MeshIndex = new Dictionary <int, BCH_Mesh>(); int nim = 0; for (int i = 0; i < verticesTableEntries; i++) { BCH_Mesh Mesh = new BCH_Mesh(); Mesh.MaterialIndex = f.ReadUShort(); int mflags = f.ReadUShort(); int meshId = f.ReadUShort(); if (!MeshIndex.ContainsKey(meshId)) { MeshIndex.Add(meshId, Mesh); Mesh.Text = nim < objectName.Length ? objectName[nim++] : i + ""; model.Nodes.Add(Mesh); } else { BCH_Mesh m = MeshIndex[meshId]; Mesh.Text = m.Text; model.Nodes.Insert(model.Nodes.IndexOf(m) - 1, Mesh); } // node visibility TODO: finish... Mesh.Checked = ((nodeVisibility & (1 << i)) > 0); Mesh.renderPriority = f.ReadUShort(); int vshAttBufferCommandOffset = f.ReadInt(); int vshAttBufferCommandCount = f.ReadInt(); int faceOffset = f.ReadInt(); int faceCount = f.ReadInt(); int vshAttBufferCommandOffsetEx = f.ReadInt(); int vshAttBufferCommandCountEx = f.ReadInt(); Vector3 Center = new Vector3(f.ReadFloat(), f.ReadFloat(), f.ReadFloat()); int flagoffset = f.ReadInt(); // flagsOffset f.Skip(4); // 0? int boundingBoxOffset = f.ReadInt(); } //Materials Console.WriteLine(materialsTableOffset.ToString("x") + " " + materialsPointerTableOffset.ToString("x")); for (int i = 0; i < materialsTableEntries; i++) { f.Seek(materialsTableOffset + (i * 0x2c)); int paramOffset = f.ReadInt(); f.Skip(12); // other offsets int texCommandOffset = f.ReadInt(); int texCommandCount = f.ReadInt(); int mapperOffset = f.ReadInt(); BCH_Material mat = new BCH_Material(); Materials.Nodes.Add(mat); mat.Text = f.ReadString(f.ReadInt(), -1); Console.WriteLine(mat.Text); //Console.WriteLine(f.readString(f.readInt(), -1)); //Console.WriteLine(f.readString(f.readInt(), -1)); //Console.WriteLine(f.readString(f.readInt(), -1)); // TODO: Parameters } //Skeleton f.Seek(skeletonOffset); for (int bindex = 0; bindex < skeletonEntries; bindex++) { Bone bone = new Bone(model.skeleton); int boneFlags = f.ReadInt(); bone.parentIndex = f.ReadShort(); short boneSpace = f.ReadShort(); bone.scale = new float[3]; bone.rotation = new float[3]; bone.position = new float[3]; bone.scale[0] = f.ReadFloat(); bone.scale[1] = f.ReadFloat(); bone.scale[2] = f.ReadFloat(); bone.rotation[0] = f.ReadFloat(); bone.rotation[1] = f.ReadFloat(); bone.rotation[2] = f.ReadFloat(); bone.position[0] = f.ReadFloat(); bone.position[1] = f.ReadFloat(); bone.position[2] = f.ReadFloat(); // bone matrix... not really needed to be stored per say f.Skip(4 * 4 * 3); bone.Text = f.ReadString(f.ReadInt(), -1); int metaDataPointerOffset2 = f.ReadInt(); if (metaDataPointerOffset2 != 0) { int position = f.Pos(); f.Seek(metaDataPointerOffset2); //bone.userData = getMetaData(input); f.Seek(position); } model.skeleton.bones.Add(bone); } model.skeleton.reset(); model.skeleton.update(); } }