Пример #1
0
        public GenericModel ToGenericModel()
        {
            var model = new GenericModel();

            model.Skeleton = skeleton;

            var mesh = new GenericMesh();

            for (int i = 0; i < PositionBuffer.Length; i++)
            {
                var vertex = new GenericVertex()
                {
                    Pos = PositionBuffer[i].Xyz
                };
                if (UV0Buffer.Length == PositionBuffer.Length)
                {
                    vertex.UV0 = UV0Buffer[i];
                }
                if (UV1Buffer.Length == PositionBuffer.Length)
                {
                    vertex.UV1 = UV1Buffer[i];
                }
                if (UV2Buffer.Length == PositionBuffer.Length)
                {
                    vertex.UV2 = UV2Buffer[i];
                }
                mesh.Vertices.Add(vertex);
            }

            List <short> tris = new List <short>();

            tris.AddRange(IndexBuffer);
            TriangleConverter.StripToList(tris, out tris);

            short max = 0;

            foreach (var t in tris)
            {
                if (t > mesh.VertexCount)
                {
                    break;
                }
                max = Math.Max(max, t);
                mesh.Triangles.Add((uint)t);
            }

            Console.WriteLine(max.ToString("X") + " " + mesh.VertexCount.ToString("X"));

            model.Meshes.Add(mesh);

            return(model);
        }
        public static HSD_DOBJ GenerateOutlineMesh(HSD_DOBJ DOBJ)
        {
            var settings = new OutlineSettings();

            using (PropertyDialog d = new PropertyDialog("Outline Settings", settings))
            {
                if (d.ShowDialog() != DialogResult.OK)
                {
                    return(null);
                }
            }

            var pobjGen = new POBJ_Generator();

            pobjGen.UseTriangleStrips = settings.UseStrips;

            var newDOBJ = new HSD_DOBJ();

            newDOBJ.Mobj = new HSD_MOBJ()
            {
                Material = new HSD_Material()
                {
                    AmbientColor  = Color.White,
                    SpecularColor = Color.Black,
                    DiffuseColor  = settings.Color,
                    DIF_A         = 255,
                    SPC_A         = 255,
                    AMB_A         = 255,
                    Shininess     = 50,
                    Alpha         = 1
                },
                RenderFlags = RENDER_MODE.CONSTANT
            };

            foreach (var pobj in DOBJ.Pobj.List)
            {
                var dl = pobj.ToDisplayList();

                var vertices = dl.Vertices;

                GXAttribName[] attrs = new GXAttribName[]
                {
                    GXAttribName.GX_VA_POS,
                    GXAttribName.GX_VA_NULL
                };

                if (pobj.HasAttribute(GXAttribName.GX_VA_PNMTXIDX))
                {
                    attrs = new GXAttribName[]
                    {
                        GXAttribName.GX_VA_PNMTXIDX,
                        GXAttribName.GX_VA_POS,
                        GXAttribName.GX_VA_NULL
                    };
                }

                List <GX_Vertex> newVerties = new List <GX_Vertex>();

                var offset = 0;
                foreach (var prim in dl.Primitives)
                {
                    var verts = vertices.GetRange(offset, prim.Count);
                    offset += prim.Count;

                    switch (prim.PrimitiveType)
                    {
                    case GXPrimitiveType.Quads:
                        verts = TriangleConverter.QuadToList(verts);
                        break;

                    case GXPrimitiveType.TriangleStrip:
                        verts = TriangleConverter.StripToList(verts);
                        break;

                    case GXPrimitiveType.Triangles:
                        break;

                    default:
                        Console.WriteLine(prim.PrimitiveType);
                        break;
                    }

                    newVerties.AddRange(verts);
                }

                // extrude
                for (int i = 0; i < newVerties.Count; i++)
                {
                    var v = newVerties[i];
                    v.POS.X += v.NRM.X * settings.Size;
                    v.POS.Y += v.NRM.Y * settings.Size;
                    v.POS.Z += v.NRM.Z * settings.Size;
                    //v.CLR0.R = settings.Color.R / 255f;
                    //v.CLR0.G = settings.Color.G / 255f;
                    //v.CLR0.B = settings.Color.B / 255f;
                    //v.CLR0.A = settings.Color.A / 255f;
                    newVerties[i] = v;
                }

                // invert faces
                for (int i = 0; i < newVerties.Count; i += 3)
                {
                    var temp = newVerties[i];
                    newVerties[i]     = newVerties[i + 2];
                    newVerties[i + 2] = temp;
                }

                var newpobj = pobjGen.CreatePOBJsFromTriangleList(newVerties, attrs, dl.Envelopes);
                foreach (var p in newpobj.List)
                {
                    p.Flags |= POBJ_FLAG.CULLBACK | POBJ_FLAG.UNKNOWN1;
                }
                if (newDOBJ.Pobj == null)
                {
                    newDOBJ.Pobj = newpobj;
                }
                else
                {
                    newDOBJ.Pobj.Add(newpobj);
                }
            }

            pobjGen.SaveChanges();

            return(newDOBJ);
        }
Пример #3
0
        public static void RebuildPOBJs(HSD_JOBJ rootJOBJ)
        {
            var compressor = new POBJ_Generator();

            foreach (var jobj in rootJOBJ.BreathFirstList)
            {
                if (jobj.Dobj != null)
                {
                    foreach (var dobj in jobj.Dobj.List)
                    {
                        if (dobj.Pobj != null)
                        {
                            List <GX_Vertex>  triList = new List <GX_Vertex>();
                            List <HSD_JOBJ[]> bones   = new List <HSD_JOBJ[]>();
                            List <float[]>    weights = new List <float[]>();

                            foreach (var pobj in dobj.Pobj.List)
                            {
                                var dl  = pobj.ToDisplayList();
                                int off = 0;
                                foreach (var pri in dl.Primitives)
                                {
                                    var strip = dl.Vertices.GetRange(off, pri.Count);
                                    if (pri.PrimitiveType == GXPrimitiveType.TriangleStrip)
                                    {
                                        TriangleConverter.StripToList(strip, out strip);
                                    }
                                    if (pri.PrimitiveType == GXPrimitiveType.Quads)
                                    {
                                        TriangleConverter.QuadToList(strip, out strip);
                                    }
                                    off += pri.Count;

                                    //if(pobj.Flags.HasFlag(POBJ_FLAG.ENVELOPE))
                                    {
                                        triList.AddRange(strip);

                                        foreach (var v in strip)
                                        {
                                            if (dl.Envelopes.Count > 0)
                                            {
                                                var        en = dl.Envelopes[v.PNMTXIDX / 3];
                                                HSD_JOBJ[] b  = en.JOBJs;
                                                float[]    w  = en.Weights;
                                                bones.Add(b);
                                                weights.Add(w);
                                            }
                                            else
                                            {
                                                bones.Add(new HSD_JOBJ[0]);
                                                weights.Add(new float[0]);
                                            }
                                        }
                                    }
                                }
                            }

                            dobj.Pobj = compressor.CreatePOBJsFromTriangleList(triList, dobj.Pobj.Attributes.Select(e => e.AttributeName).ToArray(), bones, weights);
                        }
                    }
                }
            }
            compressor.SaveChanges();
        }
Пример #4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="rootJOBJ"></param>
        private static Vector3 RegenerateIcon(HSD_JOBJ rootJOBJ)
        {
            Vector3 Min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 Max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            foreach (var jobj in rootJOBJ.BreathFirstList)
            {
                if (jobj.Dobj != null)
                {
                    foreach (var dobj in jobj.Dobj.List)
                    {
                        if (dobj.Pobj != null)
                        {
                            foreach (var pobj in dobj.Pobj.List)
                            {
                                foreach (var v in pobj.ToDisplayList().Vertices)
                                {
                                    Min.X = Math.Min(Min.X, v.POS.X);
                                    Min.Y = Math.Min(Min.Y, v.POS.Y);
                                    Min.Z = Math.Min(Min.Z, v.POS.Z);
                                    Max.X = Math.Max(Max.X, v.POS.X);
                                    Max.Y = Math.Max(Max.Y, v.POS.Y);
                                    Max.Z = Math.Max(Max.Z, v.POS.Z);
                                }
                            }
                        }
                    }
                }
            }

            var center = (Min + Max) / 2;

            var compressor = new POBJ_Generator();

            foreach (var jobj in rootJOBJ.BreathFirstList)
            {
                if (jobj.Dobj != null)
                {
                    foreach (var dobj in jobj.Dobj.List)
                    {
                        if (dobj.Pobj != null)
                        {
                            List <GX_Vertex> triList = new List <GX_Vertex>();

                            foreach (var pobj in dobj.Pobj.List)
                            {
                                var dl  = pobj.ToDisplayList();
                                int off = 0;
                                foreach (var pri in dl.Primitives)
                                {
                                    var strip = dl.Vertices.GetRange(off, pri.Count);

                                    if (pri.PrimitiveType == GXPrimitiveType.TriangleStrip)
                                    {
                                        TriangleConverter.StripToList(strip, out strip);
                                    }

                                    if (pri.PrimitiveType == GXPrimitiveType.Quads)
                                    {
                                        TriangleConverter.QuadToList(strip, out strip);
                                    }

                                    off += pri.Count;

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

                                        v.POS.X -= center.X;
                                        v.POS.Y -= center.Y;
                                        v.POS.Z -= center.Z;

                                        strip[i] = v;
                                    }

                                    triList.AddRange(strip);
                                }
                            }

                            dobj.Pobj = compressor.CreatePOBJsFromTriangleList(triList, dobj.Pobj.Attributes.Select(e => e.AttributeName).ToArray(), null, null);
                        }
                    }
                }
            }
            compressor.SaveChanges();

            center.X *= rootJOBJ.SX;
            center.Y *= rootJOBJ.SY;
            center.Z *= rootJOBJ.SZ;

            return(center);
        }
Пример #5
0
        /// <summary>
        /// Test for rebuilding pobjs from scratch
        /// </summary>
        /// <param name="path"></param>
        public static void RebuildPOBJs(string path)
        {
            HSDRawFile file = new HSDRawFile(path);

            var rootJOBJ = (HSD_JOBJ)(file.Roots[0].Data);

            var compressor = new POBJ_Generator();

            foreach (var jobj in rootJOBJ.BreathFirstSearch)
            {
                if (jobj.Dobj != null)
                {
                    foreach (var dobj in jobj.Dobj.List)
                    {
                        if (dobj.Pobj != null)
                        {
                            GXAttribName[] attributes = null;
                            if (attributes == null)
                            {
                                attributes = new GXAttribName[dobj.Pobj.Attributes.Length - 1];
                                for (int i = 0; i < attributes.Length; i++)
                                {
                                    attributes[i] = dobj.Pobj.Attributes[i].AttributeName;
                                }
                            }

                            List <GX_Vertex>  triList = new List <GX_Vertex>();
                            List <HSD_JOBJ[]> bones   = new List <HSD_JOBJ[]>();
                            List <float[]>    weights = new List <float[]>();

                            foreach (var pobj in dobj.Pobj.List)
                            {
                                var dl  = pobj.ToDisplayList();
                                int off = 0;
                                foreach (var pri in dl.Primitives)
                                {
                                    var strip = dl.Vertices.GetRange(off, pri.Count);
                                    if (pri.PrimitiveType == GXPrimitiveType.TriangleStrip)
                                    {
                                        TriangleConverter.StripToList(strip, out strip);
                                    }
                                    if (pri.PrimitiveType == GXPrimitiveType.Quads)
                                    {
                                        TriangleConverter.QuadToList(strip, out strip);
                                    }
                                    off += pri.Count;

                                    //if(pobj.Flags.HasFlag(POBJ_FLAG.ENVELOPE))
                                    {
                                        triList.AddRange(strip);

                                        foreach (var v in strip)
                                        {
                                            if (dl.Envelopes.Count > 0)
                                            {
                                                var        en = dl.Envelopes[v.PNMTXIDX / 3];
                                                HSD_JOBJ[] b  = en.JOBJs;
                                                float[]    w  = en.Weights;
                                                bones.Add(b);
                                                weights.Add(w);
                                            }
                                            else
                                            {
                                                bones.Add(new HSD_JOBJ[0]);
                                                weights.Add(new float[0]);
                                            }
                                        }
                                    }
                                }
                            }

                            dobj.Pobj = compressor.CreatePOBJsFromTriangleList(triList, attributes, bones, weights);


                            /*List<GX_Vertex> triList = new List<GX_Vertex>();
                             * foreach (var pobj in dobj.Pobj.List)
                             * {
                             *  var dl = pobj.DisplayList;
                             *  var newPrimGroup = new List<GX_PrimitiveGroup>();
                             *  int offset = 0;
                             *  foreach (var g in dl.Primitives)
                             *  {
                             *      GX_Vertex[] strip = new GX_Vertex[g.Count];
                             *      for (int i = 0; i < g.Count; i++)
                             *          strip[i] = dl.Vertices[offset + i];
                             *      newPrimGroup.Add(compressor.Compress(g.PrimitiveType, strip, pobj.Attributes));
                             *      offset += g.Count;
                             *  }
                             *  dl.Primitives = newPrimGroup;
                             *  pobj.DisplayList = dl;
                             * }*/
                        }
                    }
                }
            }
            compressor.SaveChanges();
            file.Save(path + "_rebuilt.dat");
        }
Пример #6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="pobj"></param>
        private Mesh ProcessPOBJ(HSD_POBJ pobj, HSD_JOBJ parent, HSD_JOBJ singleBind)
        {
            Mesh m = new Mesh();

            m.Name          = "pobj";
            m.PrimitiveType = PrimitiveType.Triangle;

            m.MaterialIndex = 0;

            var dl        = pobj.ToDisplayList();
            var envelopes = pobj.EnvelopeWeights;

            var parentTransform = Matrix4.Identity;

            if (parent != null)
            {
                parentTransform = WorldTransforms[jobjToIndex[parent]];
            }

            var singleBindTransform = Matrix4.Identity;

            if (singleBind != null)
            {
                singleBindTransform = WorldTransforms[jobjToIndex[singleBind]];
            }

            Dictionary <HSD_JOBJ, Bone> jobjToBone = new Dictionary <HSD_JOBJ, Bone>();

            if (envelopes != null)
            {
                foreach (var jobj in Jobjs)
                {
                    var bone = new Bone();
                    bone.Name         = JobjNodes[jobjToIndex[jobj]].Name;
                    bone.OffsetMatrix = Matrix4ToMatrix4x4(WorldTransforms[jobjToIndex[jobj]].Inverted());
                    m.Bones.Add(bone);
                    jobjToBone.Add(jobj, bone);
                }
            }

            /*foreach (var en in envelopes)
             * {
             *  foreach (var jobj in en.JOBJs)
             *  {
             *      if (!jobjToBone.ContainsKey(jobj))
             *      {
             *          var bone = new Bone();
             *          bone.Name = JobjNodes[jobjToIndex[jobj]].Name;
             *          bone.OffsetMatrix = Matrix4ToMatrix4x4(WorldTransforms[jobjToIndex[jobj]].Inverted());
             *          m.Bones.Add(bone);
             *          jobjToBone.Add(jobj, bone);
             *      }
             *  }
             * }*/


            if (singleBind != null && !jobjToBone.ContainsKey(singleBind))
            {
                var bone = new Bone();
                bone.Name         = JobjNodes[jobjToIndex[singleBind]].Name;
                bone.OffsetMatrix = Matrix4ToMatrix4x4(WorldTransforms[jobjToIndex[singleBind]].Inverted());
                m.Bones.Add(bone);
                jobjToBone.Add(singleBind, bone);
            }

            int offset = 0;
            var vIndex = -1;

            foreach (var prim in dl.Primitives)
            {
                var verts = dl.Vertices.GetRange(offset, prim.Count);
                offset += prim.Count;

                switch (prim.PrimitiveType)
                {
                case GXPrimitiveType.Quads:
                    verts = TriangleConverter.QuadToList(verts);
                    break;

                case GXPrimitiveType.TriangleStrip:
                    verts = TriangleConverter.StripToList(verts);
                    break;

                case GXPrimitiveType.Triangles:
                    break;

                default:
                    Console.WriteLine(prim.PrimitiveType);
                    break;
                }

                for (int i = m.VertexCount; i < m.VertexCount + verts.Count; i += 3)
                {
                    var f = new Face();
                    f.Indices.Add(i);
                    f.Indices.Add(i + 1);
                    f.Indices.Add(i + 2);
                    m.Faces.Add(f);
                }

                foreach (var v in verts)
                {
                    vIndex++;
                    if (singleBind != null)
                    {
                        var vertexWeight = new VertexWeight();
                        vertexWeight.VertexID = vIndex;
                        vertexWeight.Weight   = 1;
                        jobjToBone[singleBind].VertexWeights.Add(vertexWeight);
                    }
                    Matrix4 weight = Matrix4.Identity;
                    foreach (var a in pobj.Attributes)
                    {
                        switch (a.AttributeName)
                        {
                        case GXAttribName.GX_VA_PNMTXIDX:

                            var en = envelopes[v.PNMTXIDX / 3];
                            for (int w = 0; w < en.EnvelopeCount; w++)
                            {
                                var vertexWeight = new VertexWeight();
                                vertexWeight.VertexID = vIndex;
                                vertexWeight.Weight   = en.Weights[w];
                                jobjToBone[en.JOBJs[w]].VertexWeights.Add(vertexWeight);
                            }

                            if (en.EnvelopeCount == 1 && jobjToIndex[parent] == 0)
                            {
                                weight = WorldTransforms[jobjToIndex[en.JOBJs[0]]];
                            }

                            break;

                        case GXAttribName.GX_VA_POS:
                            var vert = Vector3.TransformPosition(GXTranslator.toVector3(v.POS), parentTransform);
                            vert = Vector3.TransformPosition(vert, weight);
                            vert = Vector3.TransformPosition(vert, singleBindTransform);
                            m.Vertices.Add(new Vector3D(vert.X, vert.Y, vert.Z));
                            break;

                        case GXAttribName.GX_VA_NRM:
                            var nrm = Vector3.TransformNormal(GXTranslator.toVector3(v.NRM), parentTransform);
                            nrm = Vector3.TransformNormal(nrm, weight);
                            nrm = Vector3.TransformNormal(nrm, singleBindTransform);
                            m.Normals.Add(new Vector3D(nrm.X, nrm.Y, nrm.Z));
                            break;

                        case GXAttribName.GX_VA_CLR0:
                            m.VertexColorChannels[0].Add(new Color4D(v.CLR0.R, v.CLR0.G, v.CLR0.B, v.CLR0.A));
                            break;

                        case GXAttribName.GX_VA_CLR1:
                            m.VertexColorChannels[1].Add(new Color4D(v.CLR1.R, v.CLR1.G, v.CLR1.B, v.CLR1.A));
                            break;

                        case GXAttribName.GX_VA_TEX0:
                            m.TextureCoordinateChannels[0].Add(new Vector3D(v.TEX0.X, v.TEX0.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX1:
                            m.TextureCoordinateChannels[1].Add(new Vector3D(v.TEX1.X, v.TEX1.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX2:
                            m.TextureCoordinateChannels[2].Add(new Vector3D(v.TEX2.X, v.TEX2.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX3:
                            m.TextureCoordinateChannels[3].Add(new Vector3D(v.TEX3.X, v.TEX3.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX4:
                            m.TextureCoordinateChannels[4].Add(new Vector3D(v.TEX4.X, v.TEX4.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX5:
                            m.TextureCoordinateChannels[5].Add(new Vector3D(v.TEX5.X, v.TEX5.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX6:
                            m.TextureCoordinateChannels[6].Add(new Vector3D(v.TEX6.X, v.TEX6.Y, 1));
                            break;

                        case GXAttribName.GX_VA_TEX7:
                            m.TextureCoordinateChannels[7].Add(new Vector3D(v.TEX7.X, v.TEX7.Y, 1));
                            break;
                        }
                    }
                }
            }

            return(m);
        }
Пример #7
0
        public void Open(FileItem File)
        {
            var skelPath    = File.FilePath.Replace(".mdg", ".anm");
            var skelAngPath = File.FilePath.Replace(".mdg", ".ang");
            var modelPath   = File.FilePath.Replace(".mdg", ".mdl");
            var texPath     = File.FilePath.Replace(".mdg", ".tex");

            if (!System.IO.File.Exists(skelPath))
            {
                System.Windows.Forms.MessageBox.Show("Missing Skeleton File " + Path.GetFileName(skelPath));
                return;
            }
            if (!System.IO.File.Exists(skelAngPath))
            {
                System.Windows.Forms.MessageBox.Show("Missing Skeleton File " + Path.GetFileName(skelAngPath));
                return;
            }
            if (!System.IO.File.Exists(modelPath))
            {
                System.Windows.Forms.MessageBox.Show("Missing Model File " + Path.GetFileName(modelPath));
                return;
            }

            Model          = new GenericModel();
            Model.Skeleton = new GenericSkeleton();

            if (System.IO.File.Exists(texPath))
            {
                using (DataReader r = new DataReader(new FileStream(texPath, FileMode.Open)))
                {
                    r.BigEndian = true;

                    var unk        = r.ReadInt32();
                    var width      = r.ReadInt32();
                    var height     = r.ReadInt32();
                    var dataLength = r.ReadInt32();
                    var padding    = r.ReadInt32();
                    var format     = r.ReadByte();
                    var data       = r.GetSection(0x20, (int)(r.BaseStream.Length - 0x20));

                    var bmp = HSDLib.Helpers.TPL.ConvertFromTextureMelee(data, width, height, (int)TPL_TextureFormat.CMP, null, 0, 0);

                    GenericTexture t = new GenericTexture();
                    t.FromBitmap(bmp);

                    bmp.Dispose();

                    Model.TextureBank.Add("texture", t);
                    Model.MaterialBank.Add("material", new GenericMaterial()
                    {
                        TextureDiffuse = "texture"
                    });
                }
            }

            using (DataReader r = new DataReader(new FileStream(skelPath, FileMode.Open)))
            {
                r.BigEndian = false;

                r.ReadInt32(); // magic
                r.ReadInt32(); // header
                var boneCount  = r.ReadInt32();
                var boneOffset = r.ReadUInt32();

                using (DataReader angr = new DataReader(new FileStream(skelAngPath, FileMode.Open)))
                {
                    angr.BigEndian = false;
                    for (int i = 0; i < boneCount; i++)
                    {
                        r.Seek(boneOffset + (uint)(i * 0x20));
                        var bone = new GenericBone();
                        bone.Position = new OpenTK.Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
                        r.ReadSingle();
                        //r.Skip(0x10); // inverted world position
                        bone.Name        = r.ReadString(r.ReadUInt32(), -1);
                        bone.ParentIndex = r.ReadInt32();
                        var flags     = r.ReadInt32();
                        var angOffset = r.ReadUInt32();

                        /*angr.Seek(angOffset);
                         * angr.Skip(4);
                         * var posOff = angr.ReadUInt32();
                         * var rotOff = angr.ReadUInt32();
                         * var scaOff = angr.ReadUInt32();
                         * angr.Seek(posOff);
                         * bone.Position = new OpenTK.Vector3(angr.ReadSingle(), angr.ReadSingle(), angr.ReadSingle());
                         * angr.Seek(rotOff);
                         * bone.Rotation = new OpenTK.Vector3(angr.ReadSingle(), angr.ReadSingle(), angr.ReadSingle());
                         * angr.Seek(scaOff);
                         * bone.Scale = new OpenTK.Vector3(angr.ReadSingle(), angr.ReadSingle(), angr.ReadSingle());*/

                        Model.Skeleton.Bones.Add(bone);
                    }
                }
            }

            Model.Skeleton.TransformWorldToRelative();

            using (DataReader r = new DataReader(new FileStream(modelPath, FileMode.Open)))
            {
                r.BigEndian = true;

                r.ReadInt32(); // magic
                int boneCount = r.ReadInt16();
                var meshCount = r.ReadInt16();
                boneCount = r.ReadInt32();
                var meshOffset = r.ReadUInt32();
                r.ReadUInt32();
                var boneOffset = r.ReadUInt32();

                for (int i = 0; i < meshCount; i++)
                {
                    r.Seek(meshOffset + (uint)(i * 80));
                    r.Skip(0x30); // bounding stuff
                    var mesh = new GenericMesh();
                    mesh.MaterialName = "material";
                    mesh.Name         = r.ReadString(r.ReadUInt32(), -1);
                    r.Skip(4 * 4);
                    var datInfoOffset = r.ReadUInt32();
                    Model.Meshes.Add(mesh);

                    r.Seek(datInfoOffset);
                    var flag         = r.ReadInt32();
                    var bufferOffset = r.ReadUInt32();
                    var someCount    = r.ReadInt32();
                    var primCount    = r.ReadInt32();

                    using (DataReader buffer = new DataReader(new FileStream(File.FilePath, FileMode.Open)))
                    {
                        buffer.BigEndian = true;
                        if (new string(buffer.ReadChars(4)) == "MDG5")
                        {
                            buffer.Seek(0x10);
                        }
                        else
                        {
                            buffer.Seek(0);
                        }
                        buffer.Skip(bufferOffset);
                        for (int p = 0; p < primCount; p++)
                        {
                            var primitiveType = buffer.ReadInt16();
                            var pcount        = buffer.ReadInt16();

                            if (primitiveType != 0x98)
                            {
                                throw new NotSupportedException("Unknown prim type " + primitiveType.ToString("X"));
                            }

                            var strip = new List <GenericVertex>();
                            for (int v = 0; v < pcount; v++)
                            {
                                var vert = new GenericVertex();
                                vert.Pos = new OpenTK.Vector3(buffer.ReadSingle(), buffer.ReadSingle(), buffer.ReadSingle());
                                vert.Nrm = new OpenTK.Vector3(buffer.ReadSByte(), buffer.ReadSByte(), buffer.ReadSByte());
                                vert.Nrm.Normalize();

                                // Color?
                                int col = buffer.ReadInt16();
                                var R   = (col >> 12) & 0xF;
                                var G   = (col >> 8) & 0xF;
                                var B   = (col >> 4) & 0xF;
                                var A   = (col) & 0xF;
                                vert.Clr = new OpenTK.Vector4(
                                    (R | R << 4) / (float)0xFF,
                                    (G | G << 4) / (float)0xFF,
                                    (B | B << 4) / (float)0xFF,
                                    (A | A << 4) / (float)0xFF);

                                vert.UV0 = new OpenTK.Vector2(buffer.ReadInt16() / (float)0xFFF, buffer.ReadInt16() / (float)0xFFF);

                                var   weight1 = buffer.ReadByte() / (float)0xFF;
                                float weight2 = 0;
                                if (weight1 != 1)
                                {
                                    weight2 = 1 - weight1;
                                }
                                var bone1 = buffer.ReadByte();
                                var bone2 = buffer.ReadByte();
                                vert.Bones   = new OpenTK.Vector4(bone1, bone2, 0, 0);
                                vert.Weights = new OpenTK.Vector4(weight1, weight2, 0, 0);

                                strip.Add(vert);
                            }

                            TriangleConverter.StripToList(strip, out strip);

                            mesh.Vertices.AddRange(strip);
                        }
                    }

                    mesh.Optimize();
                }
            }
        }