예제 #1
0
        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();
            }
        }
예제 #2
0
        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();
            }
        }