Example #1
0
 // Model loader for MDL files. Reference Valve's studiohdr_t struct definition for the most part.
 public DataStructures.Models.Model LoadMDL(IFile file, ModelLoadItems loadItems)
 {
     using (var fs = new MemoryStream(file.ReadAll()))
     {
         using(var br = new BinaryReader(fs))
         {
             return ReadModel(br, file, loadItems);
         }
     }
 }
Example #2
0
 // Model loader for MDL files. Reference Valve's studiohdr_t struct definition for the most part.
 public DataStructures.Models.Model LoadMDL(IFile file, ModelLoadItems loadItems)
 {
     using (var fs = file.Open())
     {
         using(var br = new BinaryReader(fs))
         {
             return ReadModel(br, file, loadItems);
         }
     }
 }
Example #3
0
        private static DataStructures.Models.Model ReadModel(BinaryReader br, IFile file, ModelLoadItems loadItems)
        {
            // int id - Not really an int. This is a magic string, either "IDST" or "IDSQ".
            var magicString = br.ReadFixedLengthString(Encoding.UTF8, 4);
            if (magicString != MagicStringIDST && magicString != MagicStringIDSQ)
            {
                throw new ProviderException("Bad magic number for model. Expected [IDST,IDSQ], got: " + magicString);
            }

            // int version - Half-life 1 models are version 10.
            var version = br.ReadInt32();
            if (version != MDLVersionGoldsource
                && version != MDLVersionSource2006
                && version != MDLVersionSourceEpisode2
                && version != MDLVersionSourcePortal
                && version != MDLVersionSource2007
                && version != MDLVersionSource2012)
            {
                throw new ProviderException("Bad version number for model. Expected [10,44,45,46,48,49], got: " + version);
            }

            var modelData = new ModelData {Version = version};

            if (version >= MDLVersionSource2006)
            {
                if (loadItems.HasFlag(ModelLoadItems.Meshes))
                {
                    // Source vertex and mesh info is stored in flat file structures, preload these separately.
                    LoadSourceMeshData(modelData, file);
                }
            }

            long checksum = 0;
            if (version >= MDLVersionSource2006)
            {
                checksum = br.ReadInt32(); // This is a long in the headers but is only written to the file in 4 bytes. Why? I don't know.
            }

            // char name[64] - The name of the model (file path)
            var path = br.ReadFixedLengthString(Encoding.UTF8, 64);

            // int length - The size of the model file in bytes
            var fileSize = br.ReadInt32();

            var eyePosition = br.ReadCoordinateF();

            var illumPosition = CoordinateF.Zero;
            if (version >= MDLVersionSource2006)
            {
                illumPosition = br.ReadCoordinateF();
            }

            var hullMin = br.ReadCoordinateF();
            var hullMax = br.ReadCoordinateF();

            var bbMin = br.ReadCoordinateF();
            var bbMax = br.ReadCoordinateF();

            // int flags - Unknown.
            var flags = br.ReadInt32();

            var numBones = br.ReadInt32();
            var boneIndex = br.ReadInt32();

            var numBoneControllers = br.ReadInt32();
            var boneControllerIndex = br.ReadInt32();

            var numHitBoxes = br.ReadInt32();
            var hitboxIndex = br.ReadInt32();

            if (version >= MDLVersionSource2006)
            {
                var numAnim = br.ReadInt32();
                var animIndex = br.ReadInt32();
                if (loadItems.HasFlag(ModelLoadItems.Animations))
                {
                    // Source animation data is stored on their own instead of inside the sequence
                    LoadSourceAnimationData(br, modelData, numAnim, animIndex);
                }
            }

            var numSeq = br.ReadInt32();
            var seqIndex = br.ReadInt32();

            int numSeqGroups = 0, seqGroupIndex = 0, activitylistversion = 0, eventsindexed = 0;
            if (version >= MDLVersionSource2006)
            {
                activitylistversion = br.ReadInt32();
                eventsindexed = br.ReadInt32();
            }
            else if (version == MDLVersionGoldsource)
            {
                numSeqGroups = br.ReadInt32();
                seqGroupIndex = br.ReadInt32();
            }

            var numTextures = br.ReadInt32();
            var textureIndex = br.ReadInt32();
            var textureDataIndex = 0;

            if (version == MDLVersionGoldsource)
            {
                textureDataIndex = br.ReadInt32();
            }

            if (version >= MDLVersionSource2006)
            {
                var numcdtextures = br.ReadInt32();
                var cdtextureindex = br.ReadInt32();
            }

            var numSkinRef = br.ReadInt32();
            var numSkinFamilies = br.ReadInt32();
            var skinIndex = br.ReadInt32();

            var numBodyParts = br.ReadInt32();
            var bodyPartIndex = br.ReadInt32();

            var numAttachments = br.ReadInt32();
            var attachmentIndex = br.ReadInt32();

            if (version >= MDLVersionSource2006)
            {
                var numlocalnodes = br.ReadInt32();
                var localnodeindex = br.ReadInt32();
                var localnodenameindex = br.ReadInt32();

                var numflexdesc = br.ReadInt32();
                var flexdescindex = br.ReadInt32();

                var numflexcontrollers = br.ReadInt32();
                var flexcontrollerindex = br.ReadInt32();

                var numflexrules = br.ReadInt32();
                var flexruleindex = br.ReadInt32();

                var numikchains = br.ReadInt32();
                var ikchainindex = br.ReadInt32();

                var nummouths = br.ReadInt32();
                var mouthindex = br.ReadInt32();

                var numlocalposeparameters = br.ReadInt32();
                var localposeparamindex = br.ReadInt32();

                var surfacepropindex = br.ReadInt32();

                var keyvalueindex = br.ReadInt32();
                var keyvaluesize = br.ReadInt32();

                var numlocalikautoplaylocks = br.ReadInt32();
                var localikautoplaylockindex = br.ReadInt32();

                var mass = br.ReadSingle();
                var contents = br.ReadInt32();

                var numincludemodels = br.ReadInt32();
                var includemodelindex = br.ReadInt32();

                var virtualModelPointer = br.ReadInt32();

                var szanimblocknameindex = br.ReadInt32();
                var numanimblocks = br.ReadInt32();
                var animblockindex = br.ReadInt32();
                var animblockModelPointer = br.ReadInt32();

                var bonetablebynameindex = br.ReadInt32();

                var pVertexBasePointer = br.ReadInt32();
                var pIndexBasePointer = br.ReadInt32();

                var constdirectionallightdot = br.ReadByte();
                var rootLod = br.ReadByte();
                var numAllowedRootLods = br.ReadByte(); // Unused in Source2006
                br.ReadByte(); // Unused

                var zeroframecacheindex = br.ReadInt32(); // Unused in Source2007

                if (version == MDLVersionSource2006)
                {
                    br.ReadBytes(6); // Unused
                }
                else if (version == MDLVersionSource2007)
                {
                    var numflexcontrollerui = br.ReadInt32();
                    var flexcontrolleruiindex = br.ReadInt32();

                    br.ReadIntArray(2); // Unused

                    var studiohdr2Index = br.ReadInt32();
                    br.ReadInt32(); // Unused
                }
            }
            else if (version == MDLVersionGoldsource)
            {
                var soundTable = br.ReadInt32();
                var soundIndex = br.ReadInt32();
                var soundGroups = br.ReadInt32();
                var soundGroupIndex = br.ReadInt32();

                var numTransitions = br.ReadInt32();
                var transitionIndex = br.ReadInt32();
            }

            var model = new DataStructures.Models.Model();
            model.Name = file.NameWithoutExtension;
            model.BonesTransformMesh = modelData.Version == MDLVersionGoldsource;

            if (loadItems.HasFlag(ModelLoadItems.Bones))
            {
                // Bones
                br.BaseStream.Position = boneIndex;
                for (var i = 0; i < numBones; i++) ReadBone(br, i, modelData, model);
            }

            // Controllers
            // TODO

            // Attachments
            // TODO

            // Hitboxes
            // TODO

            if (loadItems.HasFlag(ModelLoadItems.Animations))
            {
                if (version >= MDLVersionSource2006)
                {
                    throw new ProviderException("Source animations are currently not supported.");
                }

                // Sequence Groups
                var groups = new List<SequenceGroup>();
                br.BaseStream.Position = seqGroupIndex;
                for (var i = 0; i < numSeqGroups; i++) groups.Add(ReadSequenceGroup(br, modelData));

                // Sequences
                br.BaseStream.Position = seqIndex;
                for (var i = 0; i < numSeq; i++) ReadSequence(br, i, modelData, model, groups);
            }

            // Transitions
            // TODO

            if (loadItems.HasFlag(ModelLoadItems.Meshes))
            {
                // Body parts
                br.BaseStream.Position = bodyPartIndex;
                for (var i = 0; i < numBodyParts; i++) ReadBodyPart(br, i, modelData, model);
            }

            // Texture Info
            if (loadItems.HasFlag(ModelLoadItems.TextureInfo) || loadItems.HasFlag(ModelLoadItems.TextureData))
            {
                ReadTextureInfo(file, br, modelData, model, numTextures, textureIndex);
            }

            // Textures

            return model;
        }