// 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); } } }
// 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); } } }
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; }