public Block_3301(EndianReader reader, bool loadSkin, Vertex[] Vertices)
            : base(reader, 0x3301)
        {
            FirstNodeID = reader.ReadInt16();
            NodeCount = reader.ReadInt16();

            if (!loadSkin) reader.Skip(Vertices.Length * 4);
            else foreach (var v in Vertices)
                {
                    var val = Vector.FromUByte4(reader.ReadUInt32());
                    nodes.Add(val);
                    v.Values.Add(new VertexValue(val, VertexValue.ValueType.UInt8_4, "blendindices", 0));
                }
        }
        public UVDataBlock_3001(EndianReader reader, bool loadMesh, Vertex[] Vertices)
            : base(reader, 0x3001)
        {
            DataCount = reader.ReadInt32(); //vCount

            x2E00 = reader.ReadInt16(); //2E00
            reader.EndianType = EndianFormat.BigEndian;

            unkUV0 = reader.ReadInt16(); //flags? 0x1C00 when world
            unkUV1 = reader.ReadByte();
            unkUV2 = reader.ReadByte();
            unkUV3 = reader.ReadByte();
            unkUV4 = reader.ReadByte(); //0x00 when world, else 0x20
            DataSize = reader.ReadByte();

            if (!loadMesh) reader.SeekTo(EOBOffset);
            else for (int i = 0; i < DataCount; i++)
            {
                Vector tex0 = new Vector();

                #region switch
                switch (DataSize)
                {
                    case 8:
                        tex0 = Vector.FromUByteN4(reader.ReadUInt32());
                        reader.Skip(0);
                        break;
                    case 12:
                        reader.Skip(4);
                        break;
                    case 16:
                        reader.Skip(12);
                        break;
                    case 20:
                        reader.Skip(16);
                        break;
                    case 24:
                        reader.Skip(16);
                        break;
                    case 28:
                        reader.Skip(20);
                        break;
                    case 32:
                        reader.Skip(16);
                        break;
                    case 36:
                        reader.Skip(24);
                        break;
                    case 44:
                        reader.Skip(28);
                        break;
                }
                #endregion

                int u = reader.ReadInt16();
                int v = reader.ReadInt16();

                //var tex0 = new RealQuat(((float)a + (float)0) / (float)0xFFFF, ((float)b + (float)0) / (float)0xFFFF);
                var tex1 = new Vector((float)u / (float)(0x7FFF), (float)v / (float)(0x7FFF));

                #region switch
                switch (DataSize)
                {
                    case 8:
                        reader.Skip(0);
                        break;
                    case 12:
                        reader.Skip(4);
                        break;
                    case 16:
                        reader.Skip(0);
                        break;
                    case 20:
                        reader.Skip(0);
                        break;
                    case 24:
                        reader.Skip(4);
                        break;
                    case 28:
                        reader.Skip(4);
                        break;
                    case 32:
                        reader.Skip(12);
                        break;
                    case 36:
                        reader.Skip(8);
                        break;
                    case 44:
                        reader.Skip(12);
                        break;
                }
                #endregion

                //Vertices[i].Values.Add(new VertexValue(tex0, 0, "normal", 0));
                Vertices[i].Values.Add(new VertexValue(tex1, VertexValue.ValueType.Int16_N2, "texcoords", 0));
            }

            reader.EndianType = EndianFormat.LittleEndian;
        }
        public VertexBlock_F100(EndianReader reader, bool loadMesh, int geomUnk01)
            : base(reader, 0xF100)
        {
            DataCount = reader.ReadInt32();
            Data = new Vertex[DataCount];
            if (DataCount == 0) return;

            if (geomUnk01 != 134 && geomUnk01 != 142)
            {
                CentreX = reader.ReadInt16();
                CentreY = reader.ReadInt16();
                CentreZ = reader.ReadInt16();
                RadiusX = reader.ReadInt16();
                RadiusY = reader.ReadInt16();
                RadiusZ = reader.ReadInt16();
            }

            if (!loadMesh) reader.SeekTo(EOBOffset);
            else for (int i = 0; i < DataCount; i++)
            {
                Vertex v;

                if (geomUnk01 == 134 || geomUnk01 == 142)
                {
                    v = new Vertex() { FormatName = "S3D_World" };
                    var data = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                    v.Values.Add(new VertexValue(data, VertexValue.ValueType.Float32_3, "position", 0));
                }
                else
                {
                    v = new Vertex() { FormatName = "S3D_Compressed" };
                    var data = new Vector(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
                    v.Values.Add(new VertexValue(data, VertexValue.ValueType.Int16_N4, "position", 0));
                }
                Data[i] = v;
            }
        }
 public Block_1A01(EndianReader reader, bool loadSkin, Vertex[] Vertices)
     : base(reader, 0x1A01)
 {
     if (!loadSkin) reader.Skip(Vertices.Length * 4);
     else foreach (var v in Vertices)
         {
             var val = Vector.FromUByteN4(reader.ReadUInt32());
             v.Values.Add(new VertexValue(val, VertexValue.ValueType.UInt8_4, "blendweight", 0));
         }
 }
        public override void LoadRaw()
        {
            if (RawLoaded) return;

            var bb = BoundingBoxes[0];
            var IH = (Halo1PC.CacheFile.CacheIndexHeader)cache.IndexHeader;
            var reader = cache.Reader;

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

                List<int> tIndices = new List<int>();
                List<Vertex> tVertices = new List<Vertex>();

                for (int j = 0; j < section.Submeshes.Count; j++)
                {
                    var submesh = (Halo1PC.gbxmodel.ModelSection.Submesh)section.Submeshes[j];

                    #region Read Indices
                    submesh.FaceIndex = tIndices.Count;
                    var strip = new List<int>();

                    reader.SeekTo(submesh.FaceOffset + IH.vertDataOffset + IH.indexDataOffset);
                    for (int k = 0; k < submesh.FaceCount; k++)
                        strip.Add(reader.ReadUInt16() + tVertices.Count);

                    strip = ModelFunctions.GetTriangleList(strip.ToArray(), 0, strip.Count, 5);
                    strip.Reverse();
                    submesh.FaceCount = strip.Count;
                    tIndices.AddRange(strip);
                    #endregion

                    #region Read Vertices
                    reader.SeekTo(submesh.VertOffset + IH.vertDataOffset);
                    for (int k = 0; k < submesh.VertexCount; k++)
                    {
                        var v = new Vertex() { FormatName = "Halo1PC_Skinned" };
                        var position = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                        var normal = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                        var binormal = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                        var tangent = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                        var texcoord = new Vector(reader.ReadSingle() * uScale, 1f - reader.ReadSingle() * vScale);
                        var nodes = (Flags.Values[1]) ?
                            new Vector(submesh.LocalNodes[reader.ReadInt16()], submesh.LocalNodes[reader.ReadInt16()], 0, 0) :
                            new Vector(reader.ReadInt16(), reader.ReadInt16(), 0, 0);
                        var weights = new Vector(reader.ReadSingle(), reader.ReadSingle(), 0, 0);

                        v.Values.Add(new VertexValue(position, VertexValue.ValueType.Float32_3, "position", 0));
                        v.Values.Add(new VertexValue(normal, VertexValue.ValueType.Float32_3, "normal", 0));
                        v.Values.Add(new VertexValue(binormal, VertexValue.ValueType.Float32_3, "binormal", 0));
                        v.Values.Add(new VertexValue(tangent, VertexValue.ValueType.Float32_3, "tangent", 0));
                        v.Values.Add(new VertexValue(texcoord, VertexValue.ValueType.Float32_2, "texcoords", 0));
                        v.Values.Add(new VertexValue(nodes, VertexValue.ValueType.Int16_N2, "blendindices", 0));
                        v.Values.Add(new VertexValue(weights, VertexValue.ValueType.Float32_2, "blendweight", 0));

                        tVertices.Add(v);

                        bb.XBounds = new Range<float>(
                            Math.Min(bb.XBounds.Min, position.X),
                            Math.Max(bb.XBounds.Max, position.X));

                        bb.YBounds = new Range<float>(
                            Math.Min(bb.YBounds.Min, position.Y),
                            Math.Max(bb.YBounds.Max, position.Y));

                        bb.ZBounds = new Range<float>(
                            Math.Min(bb.ZBounds.Min, position.Z),
                            Math.Max(bb.ZBounds.Max, position.Z));
                    }
                    #endregion
                }

                section.Indices = tIndices.ToArray();
                section.Vertices = tVertices.ToArray();

                IndexInfoList.Add(new IndexBufferInfo() { FaceFormat = 3 });
                VertInfoList.Add(new VertexBufferInfo() { VertexCount = section.TotalVertexCount });
            }

            RawLoaded = true;
        }
        public override void LoadRaw()
        {
            if (RawLoaded) return;

            var reader = cache.Reader;

            #region Read Indices
            int[] indices = new int[indexCount];
            reader.SeekTo(indexOffset);
            for (int i = 0; i < indexCount; i++)
                indices[i] = reader.ReadUInt16();
            #endregion

            for (int i = 0; i < ModelSections.Count; i++)
            {
                var section = ModelSections[i];
                var tempVerts = new List<Vertex>();

                if (section.Submeshes.Count == 0) continue;

                #region Read Vertices
                for (int j = 0; j < section.Submeshes.Count; j++)
                {
                    var mesh = (Lightmap.Material)section.Submeshes[j];

                    reader.SeekTo(mesh.vertsOffset);
                    for (int k = 0; k < mesh.VertexCount; k++)
                    {
                        var v = new Vertex() { FormatName = "Halo1PC_World" };
                        var position = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                        var normal = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                        var binormal = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                        var tangent = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                        var texcoord = new Vector(reader.ReadSingle(), 1f - reader.ReadSingle());

                        v.Values.Add(new VertexValue(position, VertexValue.ValueType.Float32_3, "position", 0));
                        v.Values.Add(new VertexValue(normal, VertexValue.ValueType.Float32_3, "normal", 0));
                        v.Values.Add(new VertexValue(binormal, VertexValue.ValueType.Float32_3, "binormal", 0));
                        v.Values.Add(new VertexValue(tangent, VertexValue.ValueType.Float32_3, "tangent", 0));
                        v.Values.Add(new VertexValue(texcoord, VertexValue.ValueType.Float32_2, "texcoords", 0));

                        tempVerts.Add(v);
                    }
                }
                #endregion

                #region Copy & Translate Indices
                int offset = section.Submeshes[0].FaceIndex;
                section.Indices = new int[section.TotalFaceCount];
                Array.Copy(indices, offset, section.Indices, 0, section.TotalFaceCount);
                section.Vertices = tempVerts.ToArray();

                int pos = 0;
                for (int j = 0; j < section.Submeshes.Count; j++)
                {
                    var mesh = section.Submeshes[j];
                    mesh.FaceIndex -= offset;

                    for (int k = 0; k < mesh.FaceCount; k++)
                        section.Indices[k + mesh.FaceIndex] += pos;

                    Array.Reverse(section.Indices, mesh.FaceIndex, mesh.FaceCount);
                    pos += mesh.VertexCount;
                }
                #endregion

                IndexInfoList.Add(new mode.IndexBufferInfo() { FaceFormat = 3 });
                VertInfoList.Add(new mode.VertexBufferInfo() { VertexCount = section.TotalVertexCount });
            }

            RawLoaded = true;
        }
        protected void LoadModelExtras()
        {
            var mode = this;
            #region Mesh Merging
            foreach (var reg in mode.Regions)
            {
                foreach (var perm in reg.Permutations)
                {
                    if (perm.PieceCount < 2) continue;

                    var firstPart = mode.ModelSections[perm.PieceIndex];

                    if (firstPart.Submeshes.Count == 0) continue;

                    var verts = firstPart.Vertices.ToList();
                    var indices = firstPart.Indices.ToList();

                    for (int i = 1; i < perm.PieceCount; i++)
                    {
                        var nextPart = mode.ModelSections[perm.PieceIndex + i];

                        foreach (var mesh in nextPart.Submeshes)
                        {
                            firstPart.Submeshes.Add(mesh);
                            mesh.FaceIndex += indices.Count;
                        }

                        for (int j = 0; j < nextPart.Indices.Length; j++) nextPart.Indices[j] += verts.Count;

                        verts.AddRange(nextPart.Vertices);
                        indices.AddRange(nextPart.Indices);
                        nextPart.UnloadRaw(); //save memory seeing as it wont be used now
                    }

                    firstPart.Vertices = verts.ToArray();
                    firstPart.Indices = indices.ToArray();
                }
            }
            #endregion

            #region Mesh Splitting
            if (mode.InstancedGeometryIndex == -1) return;

            var part = mode.ModelSections[mode.InstancedGeometryIndex];
            var list = new List<mode.ModelSection>();

            for (int i = 0; i < part.Submeshes.Count; i++)
            {
                var submesh = part.Submeshes[i];

                for (int j = submesh.SubsetIndex; j < (submesh.SubsetIndex + submesh.SubsetCount); j++)
                {
                    var set = part.Subsets[j];
                    var vList = ModelFunctions.GetTriangleList(part.Indices, set.FaceIndex, set.FaceCount, mode.IndexInfoList[part.FacesIndex].FaceFormat);

                    var newStrip = vList.ToArray();

                    var min = vList.Min();
                    var max = vList.Max();

                    //adjust faces to start at 0, seeing as
                    //we're going to use a new set of vertices
                    for (int k = 0; k < newStrip.Length; k++)
                        newStrip[k] -= min;

                    var verts = new Vertex[(max - min) + 1];
                    for (int k = 0; k < verts.Length; k++)                    //need to deep clone in case the vertices need to be
                        verts[k] = (Vertex)ModelFunctions.DeepClone(part.Vertices[k + min]); //transformed, so it doesnt transform all instances

                    #region Make new instances
                    var newPart = new mode.ModelSection()
                    {
                        Vertices = verts,
                        Indices = newStrip,
                        Submeshes = new List<mode.ModelSection.Submesh>(),
                        Subsets = new List<mode.ModelSection.Subset>(),
                        VertexFormat = 1,
                        OpaqueNodesPerVertex = part.OpaqueNodesPerVertex,
                        NodeIndex = mode.GeomInstances[j].NodeIndex,
                        VertsIndex = mode.VertInfoList.Count,
                        FacesIndex = mode.IndexInfoList.Count
                    };

                    mode.VertInfoList.Add(new mode.VertexBufferInfo()
                    {
                        VertexCount = verts.Length //dont need the rest
                    });

                    mode.IndexInfoList.Add(new mode.IndexBufferInfo()
                    {
                        FaceFormat = 3 //dont need the rest
                    });

                    var newMesh = new mode.ModelSection.Submesh()
                    {
                        SubsetCount = 1,
                        SubsetIndex = 0,
                        FaceIndex = 0,
                        FaceCount = newStrip.Length,
                        ShaderIndex = submesh.ShaderIndex,
                        VertexCount = verts.Length
                    };

                    var newSet = new mode.ModelSection.Subset()
                    {
                        SubmeshIndex = 0,
                        FaceIndex = 0,
                        FaceCount = newStrip.Length,
                        VertexCount = verts.Length
                    };
                    #endregion

                    newPart.Submeshes.Add(newMesh);
                    newPart.Subsets.Add(newSet);

                    list.Add(newPart);
                }
            }

            //clear raw to save memory seeing as it wont be used anymore
            mode.ModelSections[mode.InstancedGeometryIndex].UnloadRaw();

            mode.ModelSections.AddRange(list.ToArray());

            var newRegion = new mode.Region()
            {
                Name = "Instances",
                Permutations = new List<mode.Region.Permutation>()
            };

            for (int i = 0; i < list.Count; i++)
            {
                var newPerm = new mode.Region.Permutation()
                {
                    Name = mode.GeomInstances[i].Name,
                    PieceIndex = mode.InstancedGeometryIndex + i + 1,
                    PieceCount = 1
                };

                newRegion.Permutations.Add(newPerm);
            }

            for (int i = 0; i < newRegion.Permutations.Count; i++)
            {
                var modelPart = mode.ModelSections[newRegion.Permutations[i].PieceIndex];
                var instance = mode.GeomInstances[i];

                //negative scale flips the faces after transform, fix it
                if (instance.TransformScale < 0) Array.Reverse(modelPart.Indices);

                for (int j = 0; j < modelPart.Vertices.Length; j++)
                {
                    var vert = modelPart.Vertices[j];
                    VertexValue p, n, v, w;

                    vert.TryGetValue("position", 0, out p);
                    vert.TryGetValue("normal", 0, out n);

                    p.Data *= instance.TransformScale;
                    p.Data.Point3DTransform(instance.TransformMatrix);

                    n.Data *= instance.TransformScale;
                    n.Data.Vector3DTransform(instance.TransformMatrix);

                    if (vert.TryGetValue("blendindices", 0, out v))
                        v.Data = new Vector(instance.NodeIndex, 0, 0, 0);
                    else
                        vert.Values.Add(new VertexValue(new Vector(instance.NodeIndex, 0, 0, 0), VertexValue.ValueType.Int8_N4, "blendindices", 0));

                    if (vert.TryGetValue("blendweight", 0, out w))
                        w.Data = new Vector(instance.NodeIndex, 0, 0, 0);
                    else
                        vert.Values.Add(new VertexValue(new Vector(1, 0, 0, 0), VertexValue.ValueType.Int8_N4, "blendweight", 0));
                }
            }

            mode.Regions.Add(newRegion);
            #endregion
        }
        public override void LoadRaw()
        {
            if (RawLoaded) return;

            for (int i = 0; i < ModelSections.Count; i++)
            {
                var section = (Halo2Xbox.render_model.ModelSection)ModelSections[i];
                var data = cache.GetRawFromID(section.rawOffset, section.rawSize);
                var ms = new MemoryStream(data);
                var reader = new EndianReader(ms, Endian.EndianFormat.LittleEndian);

                #region Read Submeshes
                for (int j = 0; j < section.rSize[0] / 72; j++)
                {
                    var mesh = new ModelSection.Submesh();
                    reader.SeekTo(section.hSize + section.rOffset[0] + j * 72 + 4);
                    mesh.ShaderIndex = reader.ReadUInt16();
                    mesh.FaceIndex = reader.ReadUInt16();
                    mesh.FaceCount = reader.ReadUInt16();
                    section.Submeshes.Add(mesh);
                }
                #endregion

                reader.SeekTo(40);
                section.Indices = new int[reader.ReadUInt16()];
                section.Vertices = new Vertex[section.vertcount];

                var facetype = 5;
                if (section.facecount * 3 == section.Indices.Length) facetype = 3;
                IndexInfoList.Add(new IndexBufferInfo() { FaceFormat = facetype });
                VertInfoList.Add(new VertexBufferInfo() { VertexCount = section.vertcount });

                #region Get Resource Indices
                int iIndex = 0, vIndex = 0, uIndex = 0, nIndex = 0, bIndex = 0;

                for (int j = 0; j < section.rType.Length; j++)
                {
                    switch (section.rType[j] & 0x0000FFFF)
                    {
                        case 32: iIndex = j;
                            break;

                        case 56:
                            switch ((section.rType[j] & 0xFFFF0000) >> 16)
                            {
                                case 0: vIndex = j;
                                    break;
                                case 1: uIndex = j;
                                    break;
                                case 2: nIndex = j;
                                    break;
                            }
                            break;

                        case 100: bIndex = j;
                            break;
                    }
                }
                #endregion

                reader.SeekTo(108);
                int bCount = reader.ReadUInt16();
                int[] bArr = new int[bCount];
                if (bCount > 0)
                {
                    reader.SeekTo(section.hSize + section.rOffset[bIndex]);
                    for (int j = 0; j < bCount; j++)
                        bArr[j] = reader.ReadByte();
                }

                #region Read Vertices
                for (int j = 0; j < section.vertcount; j++)
                {
                    reader.SeekTo(section.hSize + section.rOffset[vIndex] + ((section.rSize[vIndex] / section.vertcount) * j));
                    var v = new Vertex() { FormatName = "" };
                    var p = new Vector(
                        ((float)reader.ReadInt16() + (float)0x7FFF) / (float)0xFFFF,
                        ((float)reader.ReadInt16() + (float)0x7FFF) / (float)0xFFFF,
                        ((float)reader.ReadInt16() + (float)0x7FFF) / (float)0xFFFF, 0);

                    v.Values.Add(new VertexValue(p, 0, "position", 0));

                    var b = new Vector();
                    var w = new Vector();

                    switch (section.type)
                    {
                        case 1:
                            switch (section.bones)
                            {
                                case 0:
                                    section.NodeIndex = 0;
                                    break;
                                case 1:
                                    section.NodeIndex = (bCount > 0) ? bArr[0] : 0;
                                    break;
                            }
                            section.Vertices[j] = v;
                            continue;
                        case 2:
                            switch (section.bones)
                            {
                                case 1:
                                    b = new Vector(reader.ReadByte(), reader.ReadByte(), 0, 0);
                                    w = new Vector(1, 0, 0, 0);
                                    break;
                            }
                            break;
                        case 3:
                            switch (section.bones)
                            {
                                case 2:
                                    reader.ReadInt16();
                                    b = new Vector(reader.ReadByte(), reader.ReadByte(), 0, 0);
                                    w = new Vector((float)reader.ReadByte() / 255f, (float)reader.ReadByte() / 255f, 0, 0);
                                    break;
                                case 3:
                                    b = new Vector(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), 0);
                                    w = new Vector((float)reader.ReadByte() / 255f, (float)reader.ReadByte() / 255f, (float)reader.ReadByte() / 255f, 0);
                                    break;
                                case 4:
                                    reader.ReadInt16();
                                    b = new Vector(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    w = new Vector((float)reader.ReadByte() / 255f, (float)reader.ReadByte() / 255f, (float)reader.ReadByte() / 255f, (float)reader.ReadByte() / 255f);
                                    break;
                            }
                            break;
                    }

                    if (bCount > 0)
                    {
                        b.A = (w.A == 0) ? 0 : bArr[(int)b.A];
                        b.B = (w.B == 0) ? 0 : bArr[(int)b.B];
                        b.C = (w.C == 0) ? 0 : bArr[(int)b.C];
                        b.D = (w.D == 0) ? 0 : bArr[(int)b.D];
                    }

                    v.Values.Add(new VertexValue(b, 0, "blendindices", 0));
                    v.Values.Add(new VertexValue(w, 0, "blendweight", 0));

                    section.Vertices[j] = v;
                }
                #endregion

                #region Read UVs and Normals
                for (int j = 0; j < section.vertcount; j++)
                {
                    reader.SeekTo(section.hSize + section.rOffset[uIndex] + (4 * j));
                    var v = section.Vertices[j];
                    var uv = new Vector(((float)reader.ReadInt16() + (float)0x7FFF) / (float)0xFFFF, ((float)reader.ReadInt16() + (float)0x7FFF) / (float)0xFFFF);
                    v.Values.Add(new VertexValue(uv, 0, "texcoords", 0));
                }

                for (int j = 0; j < section.vertcount; j++)
                {
                    reader.SeekTo(section.hSize + section.rOffset[nIndex] + (12 * j));
                    var v = section.Vertices[j];
                    var n = Vector.FromHenDN3(reader.ReadUInt32());
                    v.Values.Add(new VertexValue(n, 0, "normal", 0));
                }
                #endregion

                ModelFunctions.DecompressVertex(ref section.Vertices, BoundingBoxes[0]);

                reader.SeekTo(section.hSize + section.rOffset[iIndex]);
                for (int j = 0; j < section.Indices.Length; j++)
                    section.Indices[j] = reader.ReadUInt16();
            }

            RawLoaded = true;
        }
        public override void LoadRaw()
        {
            if (RawLoaded) return;

            #region Clusters
            for (int i = 0; i < Clusters.Count; i++)
            {
                var section = (Halo2Xbox.scenario_structure_bsp.ModelSection)ModelSections[i];

                if (section.rSize.Length == 0 || section.vertcount == 0)
                {
                    IndexInfoList.Add(new mode.IndexBufferInfo());
                    continue;
                }

                var data = cache.GetRawFromID(section.rawOffset, section.rawSize);
                var ms = new MemoryStream(data);
                var reader = new EndianReader(ms, Endian.EndianFormat.LittleEndian);

                #region Read Submeshes
                for (int j = 0; j < section.rSize[0] / 72; j++)
                {
                    var mesh = new mode.ModelSection.Submesh();
                    reader.SeekTo(section.hSize + section.rOffset[0] + j * 72 + 4);
                    mesh.ShaderIndex = reader.ReadUInt16();
                    mesh.FaceIndex = reader.ReadUInt16();
                    mesh.FaceCount = reader.ReadUInt16();
                    section.Submeshes.Add(mesh);
                }
                #endregion

                #region Get Resource Indices
                int iIndex = 0, vIndex = 0, uIndex = 0, nIndex = 0, bIndex = 0;

                for (int j = 0; j < section.rType.Length; j++)
                {
                    switch (section.rType[j] & 0x0000FFFF)
                    {
                        case 32: iIndex = j;
                            break;

                        case 56:
                            switch ((section.rType[j] & 0xFFFF0000) >> 16)
                            {
                                case 0: vIndex = j;
                                    break;
                                case 1: uIndex = j;
                                    break;
                                case 2: nIndex = j;
                                    break;
                            }
                            break;

                        case 100: bIndex = j;
                            break;
                    }
                }
                #endregion

                section.Vertices = new Vertex[section.vertcount];
                for (int j = 0; j < section.vertcount; j++)
                {
                    reader.SeekTo(section.hSize + section.rOffset[vIndex] + ((section.rSize[vIndex] / section.vertcount) * j));
                    var v = new Vertex();
                    var p = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());

                    v.Values.Add(new VertexValue(p, 0, "position", 0));
                    section.Vertices[j] = v;
                }

                #region Read UVs and Normals
                for (int j = 0; j < section.vertcount; j++)
                {
                    reader.SeekTo(section.hSize + section.rOffset[uIndex] + (8 * j));
                    var v = section.Vertices[j];
                    var uv = new Vector(reader.ReadSingle(), 1 - reader.ReadSingle());
                    v.Values.Add(new VertexValue(uv, 0, "texcoords", 0));
                }

                for (int j = 0; j < section.vertcount; j++)
                {
                    reader.SeekTo(section.hSize + section.rOffset[uIndex + 1] + (12 * j));
                    var v = section.Vertices[j];
                    var n = Vector.FromHenDN3(reader.ReadUInt32());
                    v.Values.Add(new VertexValue(n, 0, "normal", 0));
                }
                #endregion

                reader.SeekTo(40);
                section.Indices = new int[reader.ReadUInt16()];
                reader.SeekTo(section.hSize + section.rOffset[iIndex]);
                for (int j = 0; j < section.Indices.Length; j++)
                    section.Indices[j] = reader.ReadUInt16();

                var facetype = 5;
                if (section.facecount * 3 == section.Indices.Length) facetype = 3;
                IndexInfoList.Add(new mode.IndexBufferInfo() { FaceFormat = facetype });
            }
            #endregion

            #region Instances
            if (GeomInstances.Count == 0) { RawLoaded = true; return; }
            for (int i = GeomInstances[0].SectionIndex; i < ModelSections.Count; i++)
            {
                var section = (Halo2Xbox.scenario_structure_bsp.ModelSection)ModelSections[i];
                var geomIndex = i - Clusters.Count;

                if (section.rSize.Length == 0 || section.vertcount == 0)
                {
                    IndexInfoList.Add(new mode.IndexBufferInfo());
                    continue;
                }

                var data = cache.GetRawFromID(section.rawOffset, section.rawSize);
                var ms = new MemoryStream(data);
                var reader = new EndianReader(ms, Endian.EndianFormat.LittleEndian);

                #region Read Submeshes
                for (int j = 0; j < section.rSize[0] / 72; j++)
                {
                    var mesh = new mode.ModelSection.Submesh();
                    reader.SeekTo(section.hSize + section.rOffset[0] + j * 72 + 4);
                    mesh.ShaderIndex = reader.ReadUInt16();
                    mesh.FaceIndex = reader.ReadUInt16();
                    mesh.FaceCount = reader.ReadUInt16();
                    section.Submeshes.Add(mesh);
                }
                #endregion

                #region Get Resource Indices
                int iIndex = 0, vIndex = 0, uIndex = 0, nIndex = 0, bIndex = 0;

                for (int j = 0; j < section.rType.Length; j++)
                {
                    switch (section.rType[j] & 0x0000FFFF)
                    {
                        case 32: iIndex = j;
                            break;

                        case 56:
                            switch ((section.rType[j] & 0xFFFF0000) >> 16)
                            {
                                case 0: vIndex = j;
                                    break;
                                case 1: uIndex = j;
                                    break;
                                case 2: nIndex = j;
                                    break;
                            }
                            break;

                        case 100: bIndex = j;
                            break;
                    }
                }
                #endregion

                section.Vertices = new Vertex[section.vertcount];
                for (int j = 0; j < section.vertcount; j++)
                {
                    reader.SeekTo(section.hSize + section.rOffset[vIndex] + ((section.rSize[vIndex] / section.vertcount) * j));
                    var v = new Vertex();
                    var p = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());

                    v.Values.Add(new VertexValue(p, 0, "position", 0));
                    section.Vertices[j] = v;
                }

                #region Read UVs and Normals
                for (int j = 0; j < section.vertcount; j++)
                {
                    reader.SeekTo(section.hSize + section.rOffset[uIndex] + (8 * j));
                    var v = section.Vertices[j];
                    var uv = new Vector(reader.ReadSingle(), 1 - reader.ReadSingle());
                    v.Values.Add(new VertexValue(uv, 0, "texcoords", 0));
                    //DecompressVertex(ref v, BoundingBoxes[geomIndex]);
                }

                for (int j = 0; j < section.vertcount; j++)
                {
                    reader.SeekTo(section.hSize + section.rOffset[nIndex] + (12 * j));
                    var v = section.Vertices[j];
                    var n = Vector.FromHenDN3(reader.ReadUInt32());
                    v.Values.Add(new VertexValue(n, 0, "normal", 0));
                }
                #endregion

                reader.SeekTo(40);
                section.Indices = new int[reader.ReadUInt16()];
                reader.SeekTo(section.hSize + section.rOffset[iIndex]);
                for (int j = 0; j < section.Indices.Length; j++)
                    section.Indices[j] = reader.ReadUInt16();

                var facetype = 5;
                if (section.facecount * 3 == section.Indices.Length) facetype = 3;
                IndexInfoList.Add(new mode.IndexBufferInfo() { FaceFormat = facetype });
            }
            #endregion

            RawLoaded = true;
        }