Ejemplo n.º 1
0
        private static void LoadSourceMeshData(ModelData modelData, IFile file)
        {
            modelData.Meshes = new List<VTXModel>();
            // In Source the vertices are saved to the VVD file
            // The vertex windings are saved in the VTX file
            var vvd = file.GetRelatedFile("vvd");
            var vtx = file.GetRelatedFile("vtx");
            if (vvd == null) throw new ProviderException("Unable to locate " + file.NameWithoutExtension + ".vvd");
            if (vtx == null) throw new ProviderException("Unable to locate " + file.NameWithoutExtension + ".vtx");

            var vertices = new List<VVDPoint>();

            using (var fs = vvd.Open())
            {
                using (var vbr = new BinaryReader(fs))
                {
                    var magicString = vbr.ReadFixedLengthString(Encoding.UTF8, 4);
                    if (magicString != MagicStringIDSV)
                    {
                        throw new ProviderException("Bad magic number for vertex file. Expected IDSV, got: " + magicString);
                    }

                    var version = vbr.ReadInt32();
                    if (version != VVDVersionSource)
                    {
                        throw new ProviderException("Bad version number for vertex file. Expected 4, got: " + version);
                    }

                    long checksum = vbr.ReadInt32();
                    var numLods = vbr.ReadInt32();
                    var numLodVertices = vbr.ReadIntArray(8);

                    var numFixups = vbr.ReadInt32();
                    var fixupTableStart = vbr.ReadInt32();
                    var vertexDataStart = vbr.ReadInt32();
                    var tangentDataStart = vbr.ReadInt32();

                    vbr.BaseStream.Position = vertexDataStart;

                    // Read all the vertices from LOD 0 (this should contain the vertices for all LODs)
                    for (var i = 0; i < numLodVertices[0]; i++)
                    {
                        var boneWeights = vbr.ReadSingleArray(3);
                        var bones = vbr.ReadBytes(3);
                        var numBones = vbr.ReadByte();
                        var position = vbr.ReadCoordinateF();
                        var normal = vbr.ReadCoordinateF();
                        var textureS = vbr.ReadSingle();
                        var textureT = vbr.ReadSingle();
                        vertices.Add(new VVDPoint(boneWeights, bones, numBones, position, normal, textureS, textureT));
                    }

                    // Apply the fixup table, this re-orders the indices in reverse LOD order for performance reasons
                    if (numFixups > 0)
                    {
                        vbr.BaseStream.Position = fixupTableStart;
                        var newVerts = new List<VVDPoint>();
                        for (var i = 0; i < numFixups; i++)
                        {
                            var fuLod = vbr.ReadInt32();
                            var fuvertid = vbr.ReadInt32();
                            var funumverts = vbr.ReadInt32();
                            newVerts.AddRange(vertices.GetRange(fuvertid, funumverts));
                        }
                        vertices.Clear();
                        vertices.AddRange(newVerts);
                    }

                    modelData.Vertices = vertices;
                }
            }
            using (var fs = vtx.Open())
            {
                using (var vbr = new BinaryReader(fs))
                {
                    var version = vbr.ReadInt32(); // 7
                    if (version != VTXVersionSource)
                    {
                        throw new ProviderException("Bad version number for vertex file. Expected 7, got: " + version);
                    }
                    var vertCacheSize = vbr.ReadInt32();
                    var maxBonesPerStrip = vbr.ReadUInt16();
                    var maxBonesPerTri = vbr.ReadUInt16();
                    var maxBonesPerVert = vbr.ReadInt32();
                    long checksum = vbr.ReadInt32();
                    var numLods = vbr.ReadInt32();
                    var materialReplacementListOffset = vbr.ReadInt32();
                    var numBodyParts = vbr.ReadInt32();
                    var bodyPartOffset = vbr.ReadInt32();

                    // BODY PARTS
                    long posbp = bodyPartOffset;
                    for (var bp = 0; bp < numBodyParts; bp++)
                    {
                        vbr.BaseStream.Position = posbp;

                        var numModels = vbr.ReadInt32();
                        var modelOffset = vbr.ReadInt32();

                        var posmdl = posbp + modelOffset;
                        posbp = vbr.BaseStream.Position;

                        // MODELS
                        for (var mdl = 0; mdl < numModels; mdl++)
                        {
                            vbr.BaseStream.Position = posmdl;

                            var numLod = vbr.ReadInt32();
                            var lodOffset = vbr.ReadInt32();

                            var poslod = posmdl + lodOffset;
                            posmdl = vbr.BaseStream.Position;

                            // LODS
                            for (var lod = 0; lod < numLod; lod++)
                            {
                                vbr.BaseStream.Position = poslod;

                                var meshNum = vbr.ReadInt32();
                                var meshOffset = vbr.ReadInt32();
                                var switchPoint = vbr.ReadSingle();

                                var posmesh = poslod + meshOffset;
                                poslod = vbr.BaseStream.Position;

                                // MESHES
                                for (var msh = 0; msh < meshNum; msh++)
                                {
                                    vbr.BaseStream.Position = posmesh;

                                    var sgNum = vbr.ReadInt32();
                                    var sgOffset = vbr.ReadInt32();
                                    var meshFlags = vbr.ReadByte();

                                    var possg = posmesh + sgOffset;
                                    posmesh = vbr.BaseStream.Position;

                                    var mesh = new VTXModel(bp, mdl, lod, msh);

                                    // STRIP GROUPS
                                    for (var sg = 0; sg < sgNum; sg++)
                                    {
                                        vbr.BaseStream.Position = possg;

                                        var vertNum = vbr.ReadInt32();
                                        var vertOffset = vbr.ReadInt32();
                                        var indexNum = vbr.ReadInt32();
                                        var indexOffset = vbr.ReadInt32();
                                        var stripNum = vbr.ReadInt32();
                                        var stripOffset = vbr.ReadInt32();
                                        var sgFlags = vbr.ReadByte();
                                        // vbr.ReadIntArray(2); //TODO FIXME Newer model format 49's (DOTA2, CSGO) have two extra integers here, (num + offset, purpose unknown)

                                        var posvert = possg + vertOffset;
                                        var posidx = possg + indexOffset;
                                        var posstrip = possg + stripOffset;
                                        possg = vbr.BaseStream.Position;

                                        var vertinfo = new List<VTXPoint>();
                                        vbr.BaseStream.Position = posvert;
                                        for (var vert = 0; vert < vertNum; vert++)
                                        {
                                            var boneWeightIndices = vbr.ReadBytes(3);
                                            var numBones = vbr.ReadByte();
                                            var meshVertex = vbr.ReadInt16();
                                            var boneIDs = vbr.ReadBytes(3);

                                            vertinfo.Add(new VTXPoint(boneWeightIndices, numBones, meshVertex, boneIDs));
                                        }

                                        vbr.BaseStream.Position = posidx;
                                        var indices = vbr.ReadShortArray(indexNum);

                                        // The strips hold info about whether this is a triangle strip or just a list
                                        vbr.BaseStream.Position = posstrip;
                                        for (var st = 0; st < stripNum; st++)
                                        {
                                            var numStIndices = vbr.ReadInt32();
                                            var stIndexOffset = vbr.ReadInt32();
                                            var numStVerts = vbr.ReadInt32();
                                            var stVertOffset = vbr.ReadInt32();
                                            var numStBones = vbr.ReadInt16();
                                            var stFlags = vbr.ReadByte();
                                            var numStBoneStateChanges = vbr.ReadInt32();
                                            var stBoneStateChangeOffset = vbr.ReadInt32();
                                            // vbr.ReadIntArray(2); //TODO FIXME Newer model format 49's (DOTA2, CSGO) have two extra integers here, (num + offset, purpose unknown)

                                            if ((stFlags & VTXStripGroupTriListFlag) > 0)
                                            {
                                                for (var j = stIndexOffset; j < stIndexOffset + numStIndices; j++)
                                                {
                                                    mesh.Mesh.Points.Add(vertinfo[indices[j]]);
                                                    //mesh.Vertices.Add(vertices[vertinfo[indices[j]]]);
                                                }
                                            }
                                            else if ((stFlags & VTXStripGroupTriStripFlag) > 0)
                                            {
                                                for (var j = stIndexOffset; j < stIndexOffset + numStIndices - 2; j++)
                                                {
                                                    var add = j % 2 == 1 ? new[] { j + 1, j, j + 2 } : new[] { j, j + 1, j + 2 };
                                                    foreach (var idx in add)
                                                    {
                                                        mesh.Mesh.Points.Add(vertinfo[indices[idx]]);
                                                        //mesh.Vertices.Add(vertices[vertinfo[indices[idx]]]);
                                                    }
                                                }
                                            }
                                        } // Strips
                                    } // Strip Groups
                                    modelData.Meshes.Add(mesh);
                                } // Meshes
                            } // LODs
                        } // Models
                    } // Body Parts
                } // using (var br)
            } // using (var fs)
        }