source-mdl
Version:
This package can read source engines MDL files. To parse a model, it needs the VTX, VVD and MDL file.
470 lines (434 loc) • 23.4 kB
JavaScript
const StudioStruct = require("structron");
/**
* Structures based on /src/public/studio.h
*/
const MAX_NUM_LODS = 8;
const MAX_NUM_BONES_PER_VERT = 3;
const Vector = new StudioStruct()
.addMember(StudioStruct.TYPES.FLOAT, "x")
.addMember(StudioStruct.TYPES.FLOAT, "y")
.addMember(StudioStruct.TYPES.FLOAT, "z");
const Vector2 = new StudioStruct()
.addMember(StudioStruct.TYPES.FLOAT, "x")
.addMember(StudioStruct.TYPES.FLOAT, "y");
const Quaternion = new StudioStruct()
.addMember(StudioStruct.TYPES.FLOAT, "x")
.addMember(StudioStruct.TYPES.FLOAT, "y")
.addMember(StudioStruct.TYPES.FLOAT, "z")
.addMember(StudioStruct.TYPES.FLOAT, "w");
const matrix3x4_t = new StudioStruct()
.addMember(Vector, "col0")
.addMember(Vector, "col1")
.addMember(Vector, "col2")
.addMember(Vector, "col3")
const mstudiotexture_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "name_offset")
.addMember(StudioStruct.TYPES.INT, "flags")
.addMember(StudioStruct.TYPES.INT, "used")
.addMember(StudioStruct.TYPES.INT, "unused")
.addMember(StudioStruct.TYPES.INT, "material")
.addMember(StudioStruct.TYPES.INT, "client_material")
.addMember(StudioStruct.TYPES.SKIP(40), "unused2")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "name_offset", true);
const mstudioboneweight_t = new StudioStruct()
.addMember(StudioStruct.TYPES.FLOAT, "weight0")
.addMember(StudioStruct.TYPES.FLOAT, "weight1")
.addMember(StudioStruct.TYPES.FLOAT, "weight2")
.addMember(StudioStruct.TYPES.BYTE, "BONE0")
.addMember(StudioStruct.TYPES.BYTE, "BONE1")
.addMember(StudioStruct.TYPES.BYTE, "BONE2")
.addMember(StudioStruct.TYPES.BYTE, "numbones")
const mstudiovertex_t = new StudioStruct()
.addMember(mstudioboneweight_t, "m_BoneWeights")
.addMember(Vector, "m_vecPosition")
.addMember(Vector, "m_vecNormal")
.addMember(Vector2, "m_vecTexCoord")
const mstudio_meshvertexdata_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "modelvertexdata")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes0")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes1")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes2")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes3")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes4")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes5")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes6")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes7");
const mstudiomesh_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "material")
.addMember(StudioStruct.TYPES.INT, "modelindex")
.addMember(StudioStruct.TYPES.INT, "numvertices")
.addMember(StudioStruct.TYPES.INT, "vertexoffset")
.addMember(StudioStruct.TYPES.INT, "numflexes")
.addMember(StudioStruct.TYPES.INT, "flexindex")
.addMember(StudioStruct.TYPES.INT, "materialtype")
.addMember(StudioStruct.TYPES.INT, "materialparam")
.addMember(StudioStruct.TYPES.INT, "meshid")
.addMember(Vector, "center")
.addMember(mstudio_meshvertexdata_t, "vertexdata")
.addMember(StudioStruct.TYPES.SKIP(32), "unused");
// Index of string array
const stringIndex = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "name_offset")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "name_offset");
const mstudio_modelvertexdata_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "pVertexData")
.addMember(StudioStruct.TYPES.INT, "pTangentData");
const mstudiomodel_t = new StudioStruct()
.addMember(StudioStruct.TYPES.STRING(64), "name")
.addMember(StudioStruct.TYPES.INT, "type")
.addMember(StudioStruct.TYPES.FLOAT, "boundingradius")
.addMember(StudioStruct.TYPES.INT, "nummeshes")
.addMember(StudioStruct.TYPES.INT, "meshindex")
.addMember(StudioStruct.TYPES.INT, "numvertices")
.addMember(StudioStruct.TYPES.INT, "vertexindex")
.addMember(StudioStruct.TYPES.INT, "tangentindex")
.addMember(StudioStruct.TYPES.INT, "numattachments")
.addMember(StudioStruct.TYPES.INT, "attachmentindex")
.addMember(StudioStruct.TYPES.INT, "numeyeballs")
.addMember(StudioStruct.TYPES.INT, "eyeballindex")
.addMember(mstudio_modelvertexdata_t, "vertexdata")
.addMember(StudioStruct.TYPES.SKIP(32), "unused")
.addArray(mstudiomesh_t, "meshes", "meshindex", "nummeshes", true)
const mstudiobodyparts_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "name_offset")
.addMember(StudioStruct.TYPES.INT, "model_number")
.addMember(StudioStruct.TYPES.INT, "base")
.addMember(StudioStruct.TYPES.INT, "model_index")
.addArray(mstudiomodel_t, "models", "model_index", "model_number", true)
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "name_offset", true)
const mstudiobone_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "sznameindex")
.addMember(StudioStruct.TYPES.INT, "parent")
.addMember(StudioStruct.TYPES.INT, "bonecontroller0")
.addMember(StudioStruct.TYPES.INT, "bonecontroller1")
.addMember(StudioStruct.TYPES.INT, "bonecontroller2")
.addMember(StudioStruct.TYPES.INT, "bonecontroller3")
.addMember(StudioStruct.TYPES.INT, "bonecontroller4")
.addMember(StudioStruct.TYPES.INT, "bonecontroller5")
.addMember(Vector, "pos")
.addMember(Quaternion, "quat")
.addMember(Vector, "rot")
.addMember(Vector, "posscale")
.addMember(Vector, "rotscale")
.addMember(matrix3x4_t, "poseToBone")
.addMember(Quaternion, "qAlignment")
.addMember(StudioStruct.TYPES.INT, "flags")
.addMember(StudioStruct.TYPES.INT, "proctype")
.addMember(StudioStruct.TYPES.INT, "procindex")
.addMember(StudioStruct.TYPES.INT, "physicsbone")
.addMember(StudioStruct.TYPES.INT, "surfacepropidx")
.addMember(StudioStruct.TYPES.INT, "contents")
.addMember(StudioStruct.TYPES.SKIP(32), "unused")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true)
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "surfaceprop", "surfacepropidx", true);
const mstudiobbox_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "bone")
.addMember(StudioStruct.TYPES.INT, "group")
.addMember(Vector, "bbmin")
.addMember(Vector, "bbmax")
.addMember(StudioStruct.TYPES.INT, "szhitboxnameindex")
.addMember(StudioStruct.TYPES.SKIP(32), "unused")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "szhitboxnameindex", true);
const mstudiohitboxset_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "sznameindex")
.addMember(StudioStruct.TYPES.INT, "numhitboxes")
.addMember(StudioStruct.TYPES.INT, "hitboxindex")
.addArray(mstudiobbox_t, "hitboxes", "hitboxindex", "numhitboxes", true)
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true);
const mstudiobonecontroller_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "bone")
.addMember(StudioStruct.TYPES.INT, "type")
.addMember(StudioStruct.TYPES.FLOAT, "start")
.addMember(StudioStruct.TYPES.FLOAT, "end")
.addMember(StudioStruct.TYPES.INT, "rest")
.addMember(StudioStruct.TYPES.INT, "inputfield")
.addMember(StudioStruct.TYPES.SKIP(32), "unused");
const mstudiomovement_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "endframe")
.addMember(StudioStruct.TYPES.INT, "motionflags")
.addMember(StudioStruct.TYPES.FLOAT, "v0")
.addMember(StudioStruct.TYPES.FLOAT, "v1")
.addMember(StudioStruct.TYPES.FLOAT, "angle")
.addMember(Vector, "vector")
.addMember(Vector, "position")
const mstudioikrule_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "index")
.addMember(StudioStruct.TYPES.INT, "type")
.addMember(StudioStruct.TYPES.INT, "chain")
.addMember(StudioStruct.TYPES.INT, "bone")
.addMember(StudioStruct.TYPES.INT, "slot")
.addMember(StudioStruct.TYPES.FLOAT, "height")
.addMember(StudioStruct.TYPES.FLOAT, "radius")
.addMember(StudioStruct.TYPES.FLOAT, "floor")
.addMember(Vector, "pos")
.addMember(Quaternion, "q")
.addMember(StudioStruct.TYPES.INT, "compressedikerrorindex")
.addMember(StudioStruct.TYPES.INT, "unused2")
.addMember(StudioStruct.TYPES.INT, "iStart")
.addMember(StudioStruct.TYPES.INT, "ikerrorindex")
.addMember(StudioStruct.TYPES.FLOAT, "start")
.addMember(StudioStruct.TYPES.FLOAT, "peak")
.addMember(StudioStruct.TYPES.FLOAT, "tail")
.addMember(StudioStruct.TYPES.FLOAT, "end")
.addMember(StudioStruct.TYPES.FLOAT, "unused3")
.addMember(StudioStruct.TYPES.FLOAT, "contact")
.addMember(StudioStruct.TYPES.FLOAT, "drop")
.addMember(StudioStruct.TYPES.FLOAT, "top")
.addMember(StudioStruct.TYPES.INT, "unused6")
.addMember(StudioStruct.TYPES.INT, "unused7")
.addMember(StudioStruct.TYPES.INT, "unused8")
.addMember(StudioStruct.TYPES.INT, "szattachmentindex")
.addMember(StudioStruct.TYPES.SKIP(7*4), "unused")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "worldAttachment", "szattachmentindex");
const mstudiolocalhierarchy_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "iBone")
.addMember(StudioStruct.TYPES.INT, "iNewParent")
.addMember(StudioStruct.TYPES.FLOAT, "start")
.addMember(StudioStruct.TYPES.FLOAT, "peak")
.addMember(StudioStruct.TYPES.FLOAT, "tail")
.addMember(StudioStruct.TYPES.FLOAT, "end")
.addMember(StudioStruct.TYPES.INT, "iStart")
.addMember(StudioStruct.TYPES.INT, "localanimindex")
.addMember(StudioStruct.TYPES.SKIP(32));
const mstudioanimsections_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "animblock")
.addMember(StudioStruct.TYPES.INT, "animindex");
const mstudioanimdesc_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "baseptr")
.addMember(StudioStruct.TYPES.INT, "sznameindex")
.addMember(StudioStruct.TYPES.FLOAT, "fps")
.addMember(StudioStruct.TYPES.INT, "flags")
.addMember(StudioStruct.TYPES.INT, "numframes")
.addMember(StudioStruct.TYPES.INT, "nummovements")
.addMember(StudioStruct.TYPES.INT, "movementindex")
.addMember(StudioStruct.TYPES.SKIP(24), "unused")
.addMember(StudioStruct.TYPES.INT, "animblock")
.addMember(StudioStruct.TYPES.INT, "animindex")
.addMember(StudioStruct.TYPES.INT, "numikrules")
.addMember(StudioStruct.TYPES.INT, "ikruleindex")
.addMember(StudioStruct.TYPES.INT, "animblockikruleindex")
.addMember(StudioStruct.TYPES.INT, "numlocalhierarchy")
.addMember(StudioStruct.TYPES.INT, "localhierarchyindex")
.addMember(StudioStruct.TYPES.INT, "sectionindex")
.addMember(StudioStruct.TYPES.INT, "sectionframes")
.addMember(StudioStruct.TYPES.SHORT, "zeroframespan")
.addMember(StudioStruct.TYPES.SHORT, "zeroframecount")
.addMember(StudioStruct.TYPES.INT, "zeroframeindex")
.addMember(StudioStruct.TYPES.FLOAT, "zeroframestalltime")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true)
.addArray(mstudiomovement_t, "movements", "movementindex", "nummovements", true) // Don't know if this is relative (Did not find a model to test with)
.addArray(mstudioikrule_t, "ikrules", "ikruleindex", "numikrules", true) // Same. Don't know if index is offset
.addArray(mstudiolocalhierarchy_t, "localhierarchy", "localhierarchyindex", "numlocalhierarchy", true) // Relative !?
.addArray(mstudioanimsections_t, "sections", "sectionindex", "sectionframes", true);
const mstudioevent_t = new StudioStruct()
.addMember(StudioStruct.TYPES.FLOAT, "cycle")
.addMember(StudioStruct.TYPES.INT, "event")
.addMember(StudioStruct.TYPES.INT, "type")
.addMember(StudioStruct.TYPES.SKIP(64), "options")
.addMember(StudioStruct.TYPES.INT, "szeventindex")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "event", "szeventindex", true)
.addArray(StudioStruct.TYPES.BYTE, "options", 12, 64, true);
const mstudioautolayer_t = new StudioStruct()
.addMember(StudioStruct.TYPES.SHORT, "iSequence")
.addMember(StudioStruct.TYPES.SHORT, "iPose")
.addMember(StudioStruct.TYPES.INT, "flags")
.addMember(StudioStruct.TYPES.FLOAT, "start")
.addMember(StudioStruct.TYPES.FLOAT, "peak")
.addMember(StudioStruct.TYPES.FLOAT, "tail")
.addMember(StudioStruct.TYPES.FLOAT, "end")
const mstudioiklock_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "chain")
.addMember(StudioStruct.TYPES.FLOAT, "flPosWeight")
.addMember(StudioStruct.TYPES.FLOAT, "flLocalQWeight")
.addMember(StudioStruct.TYPES.INT, "flags")
.addMember(StudioStruct.TYPES.SKIP(32), "unused")
const mstudioseqdesc_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "baseptr")
.addMember(StudioStruct.TYPES.INT, "szlabelindex")
.addMember(StudioStruct.TYPES.INT, "szactivitynameindex")
.addMember(StudioStruct.TYPES.INT, "flags")
.addMember(StudioStruct.TYPES.INT, "activity")
.addMember(StudioStruct.TYPES.INT, "actweight")
.addMember(StudioStruct.TYPES.INT, "numevents")
.addMember(StudioStruct.TYPES.INT, "eventindex")
.addMember(Vector, "bbmin")
.addMember(Vector, "bbmax")
.addMember(StudioStruct.TYPES.INT, "numblends")
.addMember(StudioStruct.TYPES.INT, "animindexindex")
.addMember(StudioStruct.TYPES.INT, "movementindex")
.addMember(StudioStruct.TYPES.INT, "groupsize0")
.addMember(StudioStruct.TYPES.INT, "groupsize1")
.addMember(StudioStruct.TYPES.INT, "paramindex0")
.addMember(StudioStruct.TYPES.INT, "paramindex1")
.addMember(StudioStruct.TYPES.FLOAT, "paramstart0")
.addMember(StudioStruct.TYPES.FLOAT, "paramstart1")
.addMember(StudioStruct.TYPES.FLOAT, "paramend0")
.addMember(StudioStruct.TYPES.FLOAT, "paramend1")
.addMember(StudioStruct.TYPES.INT, "paramparent")
.addMember(StudioStruct.TYPES.FLOAT, "fadeintime")
.addMember(StudioStruct.TYPES.FLOAT, "fadeouttime")
.addMember(StudioStruct.TYPES.INT, "localentrynode")
.addMember(StudioStruct.TYPES.INT, "localexitnode")
.addMember(StudioStruct.TYPES.INT, "nodeflags")
.addMember(StudioStruct.TYPES.FLOAT, "entryphase")
.addMember(StudioStruct.TYPES.FLOAT, "exitphase")
.addMember(StudioStruct.TYPES.FLOAT, "lastframe")
.addMember(StudioStruct.TYPES.INT, "nextseq")
.addMember(StudioStruct.TYPES.INT, "pose")
.addMember(StudioStruct.TYPES.INT, "numikrules")
.addMember(StudioStruct.TYPES.INT, "numautolayers")
.addMember(StudioStruct.TYPES.INT, "autolayerindex")
.addMember(StudioStruct.TYPES.INT, "weightlistindex")
.addMember(StudioStruct.TYPES.INT, "posekeyindex")
.addMember(StudioStruct.TYPES.INT, "numiklocks")
.addMember(StudioStruct.TYPES.INT, "iklockindex")
.addMember(StudioStruct.TYPES.INT, "keyvalueindex")
.addMember(StudioStruct.TYPES.INT, "keyvaluesize")
.addMember(StudioStruct.TYPES.INT, "cycleposeindex")
.addMember(StudioStruct.TYPES.SKIP(4*7), "unused")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "label", "szlabelindex", true)
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "activityname", "szactivitynameindex", true)
.addArray(mstudioevent_t, "events", "eventindex", "numevents", true)
.addArray(mstudioautolayer_t, "autolayer", "autolayerindex", "numautolayers", true)
.addArray(mstudioiklock_t, "iklockindex", "numiklocks");
/**
* @todo Allow functions in array parameters
*/
//.addArray(StudioStruct.TYPES.SHORT, "anims", "animindex", data => data.groupsize[0] * data.groupsize[1])
const mstudioattachment_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "sznameindex")
.addMember(StudioStruct.TYPES.UINT, "flags")
.addMember(StudioStruct.TYPES.INT, "localbone")
.addMember(matrix3x4_t, "local")
.addMember(StudioStruct.TYPES.SKIP(32), "unused")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true);
const mstudiomodelgroup_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "szlabelindex")
.addMember(StudioStruct.TYPES.INT, "sznameindex")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "label", "szlabelindex", true)
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true);
const mstudioposeparamdesc_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "sznameindex")
.addMember(StudioStruct.TYPES.UINT, "flags")
.addMember(StudioStruct.TYPES.FLOAT, "start")
.addMember(StudioStruct.TYPES.FLOAT, "end")
.addMember(StudioStruct.TYPES.FLOAT, "loop")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "name", "sznameindex", true);
const studiohdr_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "id")
.addMember(StudioStruct.TYPES.INT, "version")
.addMember(StudioStruct.TYPES.INT, "checksum")
.addMember(StudioStruct.TYPES.STRING(64), "name")
.addMember(StudioStruct.TYPES.INT, "dataLength")
.addMember(Vector, "eyeposition")
.addMember(Vector, "illumposition")
.addMember(Vector, "hull_min")
.addMember(Vector, "hull_max")
.addMember(Vector, "view_bbmin")
.addMember(Vector, "view_bbmax")
.addMember(StudioStruct.TYPES.INT, "flags")
.addMember(StudioStruct.TYPES.INT, "bone_count")
.addMember(StudioStruct.TYPES.INT, "bone_index")
.addMember(StudioStruct.TYPES.INT, "bonecontroller_count")
.addMember(StudioStruct.TYPES.INT, "bonecontroller_offset")
.addMember(StudioStruct.TYPES.INT, "hitbox_count")
.addMember(StudioStruct.TYPES.INT, "hitbox_offset")
.addMember(StudioStruct.TYPES.INT, "localanim_count")
.addMember(StudioStruct.TYPES.INT, "localanim_offset")
.addMember(StudioStruct.TYPES.INT, "localseq_count")
.addMember(StudioStruct.TYPES.INT, "localseq_offset")
.addMember(StudioStruct.TYPES.INT, "activitylistversion")
.addMember(StudioStruct.TYPES.INT, "eventsindexed")
.addMember(StudioStruct.TYPES.INT, "texture_count")
.addMember(StudioStruct.TYPES.INT, "texture_offset")
.addMember(StudioStruct.TYPES.INT, "texturedir_count")
.addMember(StudioStruct.TYPES.INT, "texturedir_offset")
.addMember(StudioStruct.TYPES.INT, "skinreference_count")
.addMember(StudioStruct.TYPES.INT, "skinfamily_count")
.addMember(StudioStruct.TYPES.INT, "skinreference_index")
.addMember(StudioStruct.TYPES.INT, "bodypart_count")
.addMember(StudioStruct.TYPES.INT, "bodypart_offset")
.addMember(StudioStruct.TYPES.INT, "attachment_count")
.addMember(StudioStruct.TYPES.INT, "attachment_offset")
.addMember(StudioStruct.TYPES.INT, "localnode_count")
.addMember(StudioStruct.TYPES.INT, "localnode_index")
.addMember(StudioStruct.TYPES.INT, "localnode_name_index")
.addMember(StudioStruct.TYPES.INT, "flexdesc_count")
.addMember(StudioStruct.TYPES.INT, "flexdesc_index")
.addMember(StudioStruct.TYPES.INT, "flexcontroller_count")
.addMember(StudioStruct.TYPES.INT, "flexcontroller_index")
.addMember(StudioStruct.TYPES.INT, "flexrules_count")
.addMember(StudioStruct.TYPES.INT, "flexrules_index")
.addMember(StudioStruct.TYPES.INT, "ikchain_count")
.addMember(StudioStruct.TYPES.INT, "ikchain_index")
.addMember(StudioStruct.TYPES.INT, "mouths_count")
.addMember(StudioStruct.TYPES.INT, "mouths_index")
.addMember(StudioStruct.TYPES.INT, "localposeparam_count")
.addMember(StudioStruct.TYPES.INT, "localposeparam_offset")
.addMember(StudioStruct.TYPES.INT, "surfaceprop_index")
.addMember(StudioStruct.TYPES.INT, "keyvalue_index")
.addMember(StudioStruct.TYPES.INT, "keyvalue_count")
.addMember(StudioStruct.TYPES.INT, "ikblock_count")
.addMember(StudioStruct.TYPES.INT, "ikblock_index")
.addMember(StudioStruct.TYPES.FLOAT, "mass")
.addMember(StudioStruct.TYPES.INT, "contents")
.addMember(StudioStruct.TYPES.INT, "includemodel_count")
.addMember(StudioStruct.TYPES.INT, "includemodel_index")
.addMember(StudioStruct.TYPES.INT, "virtualModel")
.addMember(StudioStruct.TYPES.INT, "animblocks_name_index")
.addMember(StudioStruct.TYPES.INT, "animblocks_count")
.addMember(StudioStruct.TYPES.INT, "animblocks_index")
.addMember(StudioStruct.TYPES.INT, "animblockModel")
.addMember(StudioStruct.TYPES.INT, "bonetable_index")
.addMember(StudioStruct.TYPES.INT, "vertex_base")
.addMember(StudioStruct.TYPES.INT, "offset_base")
.addMember(StudioStruct.TYPES.BYTE, "directionaldotproduct")
.addMember(StudioStruct.TYPES.BYTE, "rootLod")
.addMember(StudioStruct.TYPES.BYTE, "numAllowedRootLods")
.addMember(StudioStruct.TYPES.SKIP(5), "unused")
.addMember(StudioStruct.TYPES.INT, "flexcontrollerui_count")
.addMember(StudioStruct.TYPES.INT, "flexcontrollerui_index")
.addMember(StudioStruct.TYPES.INT, "studiohdr2index")
.addMember(StudioStruct.TYPES.INT, "unused")
.addArray(mstudiotexture_t, "textures", "texture_offset", "texture_count")
.addArray(stringIndex, "texturedirs", "texturedir_offset", "texturedir_count")
.addArray(mstudiobodyparts_t, "bodyparts", "bodypart_offset", "bodypart_count")
.addArray(mstudiobone_t, "bones", "bone_index", "bone_count")
//.addArray(mstudiohitboxset_t, "hitboxes", "hitbox_offset", "hitbox_count") // Crashed on some files
.addArray(mstudiobonecontroller_t, "bonecontroller", "bonecontroller_offset", "bonecontroller_count")
.addArray(mstudioanimdesc_t, "localanims", "localanim_offset", "localanim_count")
.addArray(mstudioseqdesc_t, "sequences", "localseq_offset", "localseq_count")
.addArray(mstudioattachment_t, "attachments", "attachment_offset", "attachment_count")
.addArray(mstudioiklock_t, "iklocks", "iklock_index", "iklock_count")
.addArray(mstudiomodelgroup_t, "includemodel_index", "animblocks_count")
.addArray(StudioStruct.TYPES.SHORT, "skinreferences", "skinreference_index", "skinreference_count")
.addArray(mstudioposeparamdesc_t, "localposeparams", "localposeparam_offset", "localposeparam_count")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "surfaceProp", "surfaceprop_index")
.addReference(StudioStruct.TYPES.NULL_TERMINATED_STRING(), "keyvalue", "keyvalue_index");
const vertexFileFixup_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "lod")
.addMember(StudioStruct.TYPES.INT, "sourceVertexId")
.addMember(StudioStruct.TYPES.INT, "numVertexes");
const vertexFileHeader_t = new StudioStruct()
.addMember(StudioStruct.TYPES.INT, "id")
.addMember(StudioStruct.TYPES.INT, "version")
.addMember(StudioStruct.TYPES.INT, "checksum")
.addMember(StudioStruct.TYPES.INT, "numLODs")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes0")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes1")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes2")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes3")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes4")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes5")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes6")
.addMember(StudioStruct.TYPES.INT, "numLODVertexes7")
.addMember(StudioStruct.TYPES.INT, "numFixups")
.addMember(StudioStruct.TYPES.INT, "fixupTableStart")
.addMember(StudioStruct.TYPES.INT, "vertexDataStart")
.addMember(StudioStruct.TYPES.INT, "tangentDataStart")
.addArray(vertexFileFixup_t, "fixups", "fixupTableStart", "numFixups");
module.exports = {
studiohdr_t,
vertexFileHeader_t,
mstudiovertex_t
}