finish up plugin architecture
[csRadar.git] / vmdl.h
1 // This software is not affiliated with Valve Corporation
2 // We are not affiliated, associated, authorized, endorsed by, or in any way officially
3 // connected with Valve Corporation, or any of its subsidiaries or its affiliates.
4 //
5 // All trademarks are property of their respective owners
6
7 typedef struct mdl_mesh mdl_mesh_t;
8
9 // High level API
10 //=======================================================================================================================
11
12 // Load model from vfs
13 int mdl_from_find_files( const char *mdlname, mdl_mesh_t *ctx );
14 void mdl_free( mdl_mesh_t *m );
15
16 // Set ctx to blank / 0,0
17 void mdl_error( mdl_mesh_t *m );
18
19 // Implementation
20 //=======================================================================================================================
21
22 struct mdl_mesh
23 {
24 u16 *indices;
25 u32 num_indices;
26
27 float *vertices;
28 u32 num_vertices;
29
30 // Bounding box
31 boxf bounds;
32 };
33
34 #ifdef VALVE_IMPLEMENTATION
35
36 // VVD
37 //=======================================================================================================================
38 //StudioMDL constants
39
40 #define MAX_NUM_LODS 8
41 #define MAX_NUM_BONES_PER_VERT 3
42
43 #pragma pack(push, 1)
44 typedef struct
45 {
46 float weight[MAX_NUM_BONES_PER_VERT];
47 char bone[MAX_NUM_BONES_PER_VERT];
48 char numbones;
49 }
50 boneWeight_t;
51
52 typedef struct
53 {
54 boneWeight_t boneweights;
55 float pos[3];
56 float norm[3];
57 float uv[2];
58 }
59 mstudiovertex_t;
60
61 typedef struct
62 {
63 int id;
64 int version;
65 int checksum;
66 int numLods;
67 int numLodVertexes[MAX_NUM_LODS];
68 int numFixups;
69 int fixupTableStart;
70 int vertexDataStart;
71 int tangentDataStart;
72 }
73 vertexFileHeader_t;
74
75 #pragma pack(pop)
76
77 mstudiovertex_t *GetVertexData( vertexFileHeader_t *t )
78 {
79 return (mstudiovertex_t *) ( (char *)t + t->vertexDataStart );
80 }
81
82 // VTX
83 //=======================================================================================================================
84
85 #pragma pack(push, 1)
86
87 typedef struct
88 {
89 // these index into the mesh's vert[origMeshVertID]'s bones
90 unsigned char boneWeightIndex[3];
91 unsigned char numBones;
92
93 unsigned short origMeshVertID;
94
95 // for sw skinned verts, these are indices into the global list of bones
96 // for hw skinned verts, these are hardware bone indices
97 char boneID[3];
98 }
99 VTXVertex_t;
100
101 enum StripGroupFlags
102 {
103 STRIPGROUP_IS_FLEXED = 0x01,
104 STRIPGROUP_IS_HWSKINNED = 0x02,
105 STRIPGROUP_IS_DELTA_FLEXED = 0x04,
106 STRIPGROUP_SUPPRESS_HW_MORPH = 0x08, // NOTE: This is a temporary flag used at run time.
107 };
108
109 enum StripHeaderFlags_t {
110 STRIP_IS_TRILIST = 0x01,
111 STRIP_IS_TRISTRIP = 0x02
112 };
113
114 // A strip is a piece of a stripgroup which is divided by bones
115 typedef struct
116 {
117 //Indices array
118 int numIndices;
119 int indexOffset;
120
121 //Vertices array
122 int numVerts;
123 int vertOffset;
124
125 short numBones;
126
127 unsigned char flags;
128
129 int numBoneStateChanges;
130 int boneStateChangeOffset;
131 }
132 VTXStripHeader_t;
133 // Bone state change inline code ommited
134
135 // a locking group
136 // a single vertex buffer
137 // a single index buffer
138 typedef struct
139 {
140 // These are the arrays of all verts and indices for this mesh. strips index into this.
141 int numVerts;
142 int vertOffset;
143
144 int numIndices;
145 int indexOffset;
146
147 int numStrips;
148 int stripOffset;
149
150 unsigned char flags;
151 }
152 VTXStripGroupHeader_t;
153
154 VTXVertex_t *pVertexVTX( VTXStripGroupHeader_t *t, int i )
155 {
156 return (VTXVertex_t *)(((char *)t) + t->vertOffset) + i;
157 }
158 unsigned short *pIndexVTX( VTXStripGroupHeader_t *t, int i )
159 {
160 return (unsigned short *)(((char *)t) + t->indexOffset) + i;
161 }
162 VTXStripHeader_t *pStripVTX( VTXStripGroupHeader_t *t, int i )
163 {
164 return (VTXStripHeader_t *)(((char *)t) + t->stripOffset) + i;
165 }
166
167 typedef struct
168 {
169 int numStripGroups;
170 int stripGroupHeaderOffset;
171
172 unsigned char flags;
173 }
174 VTXMeshHeader_t;
175 VTXStripGroupHeader_t *pStripGroupVTX( VTXMeshHeader_t *t, int i )
176 {
177 return (VTXStripGroupHeader_t *)(((char *)t) + t->stripGroupHeaderOffset) + i;
178 }
179
180 typedef struct
181 {
182 //Mesh array
183 int numMeshes;
184 int meshOffset;
185
186 float switchPoint;
187 }
188 VTXModelLODHeader_t;
189 VTXMeshHeader_t *pMeshVTX( VTXModelLODHeader_t *t, int i )
190 {
191 return (VTXMeshHeader_t *)(((char *)t) + t->meshOffset) + i;
192 }
193
194 // This maps one to one with models in the mdl file.
195 typedef struct
196 {
197 //LOD mesh array
198 int numLODs; //This is also specified in FileHeader_t
199 int lodOffset;
200 }
201 VTXModelHeader_t;
202 VTXModelLODHeader_t *pLODVTX( VTXModelHeader_t *t, int i )
203 {
204 return (VTXModelLODHeader_t *)(((char *)t) + t->lodOffset) + i;
205 }
206
207 typedef struct
208 {
209 //Model array
210 int numModels;
211 int modelOffset;
212 }
213 VTXBodyPartHeader_t;
214 VTXModelHeader_t *pModelVTX( VTXBodyPartHeader_t *t, int i )
215 {
216 return (VTXModelHeader_t *)(((char *)t) + t->modelOffset) + i;
217 }
218
219 typedef struct
220 {
221 // file version as defined by OPTIMIZED_MODEL_FILE_VERSION (currently 7)
222 int version;
223
224 // hardware params that affect how the model is to be optimized.
225 int vertCacheSize;
226 unsigned short maxBonesPerStrip;
227 unsigned short maxBonesPerTri;
228 int maxBonesPerVert;
229
230 // must match checkSum in the .mdl
231 int checkSum;
232
233 int numLODs; // Also specified in ModelHeader_t's and should match
234
235 // Offset to materialReplacementList Array. one of these for each LOD, 8 in total
236 int materialReplacementListOffset;
237
238 //Defines the size and location of the body part array
239 int numBodyParts;
240 int bodyPartOffset;
241 }
242 VTXFileHeader_t;
243 VTXBodyPartHeader_t *pBodyPartVTX( VTXFileHeader_t *t, int i )
244 {
245 return (VTXBodyPartHeader_t *)(((char *)t) + t->bodyPartOffset) + i;
246 }
247
248 /*
249 .VTX file structure
250 =============================================
251
252 FileHeader
253 L BodyParts::
254 L Models::
255 L LODS::
256 L Meshes::
257 L StripGroups::
258 L VerticesTable[StudioMDL.Vertex]
259 L IndicesTable[UINT16]
260 |
261 L Strips::
262 L Vertices[UINT16]
263 L Indices[UINT16]
264 */
265
266 #pragma pack(pop)
267
268 u32 vtx_count_indices( VTXFileHeader_t *t )
269 {
270 u32 indices = 0;
271
272 for ( int bodyID = 0; bodyID < t->numBodyParts; ++bodyID )
273 {
274 VTXBodyPartHeader_t* pVtxBodyPart = pBodyPartVTX( t, bodyID );
275 for ( int modelID = 0; modelID < pVtxBodyPart->numModels; ++modelID )
276 {
277 VTXModelHeader_t* pVtxModel = pModelVTX( pVtxBodyPart, modelID );
278
279 int nLod = 0;
280 VTXModelLODHeader_t *pVtxLOD = pLODVTX( pVtxModel, nLod );
281
282 for ( int nMesh = 0; nMesh < pVtxLOD->numMeshes; ++nMesh )
283 {
284 VTXMeshHeader_t* pVtxMesh = pMeshVTX( pVtxLOD, nMesh );
285
286 for ( int nGroup = 0; nGroup < pVtxMesh->numStripGroups; ++nGroup )
287 {
288 VTXStripGroupHeader_t* pStripGroup = pStripGroupVTX( pVtxMesh, nGroup );
289
290 for ( int nStrip = 0; nStrip < pStripGroup->numStrips; nStrip++ )
291 {
292 VTXStripHeader_t *pStrip = pStripVTX( pStripGroup, nStrip );
293
294 if ( pStrip->flags & STRIP_IS_TRILIST )
295 {
296 indices += pStrip->numIndices;
297 }
298 }
299 }
300 }
301 }
302 }
303
304 return indices;
305 }
306
307 // MDL
308 //=======================================================================================================================
309
310 #pragma pack(push, 1)
311
312 typedef struct
313 {
314 // base of external vertex data stores
315 void *pVertexData;
316 void *pTangentData;
317 }
318 mstudio_modelvertexdata_t;
319
320 typedef struct
321 {
322 // indirection to this mesh's model's vertex data
323 int unused_modelvertexdata; // 64b - Moved to follow num_LOD_Vertexes.
324
325 // used for fixup calcs when culling top level lods
326 // expected number of mesh verts at desired lod
327 int numLODVertexes[MAX_NUM_LODS];
328
329 mstudio_modelvertexdata_t *_the_death_ptr;
330 }
331 mstudio_meshvertexdata_t;
332
333 typedef struct mstudiomodel_t mstudiomodel_t;
334
335 typedef struct
336 {
337 int material;
338 int modelindex;
339 int numvertices; // number of unique vertices/normals/texcoords
340 int vertexoffset; // vertex mstudiovertex_t
341 int numflexes; // vertex animation
342 int flexindex;
343 // special codes for material operations
344 int materialtype;
345 int materialparam;
346 // a unique ordinal for this mesh
347 int meshid;
348 float center[3];
349 mstudio_meshvertexdata_t vertexdata;
350
351 int unused[6]; // remove as appropriate
352 }
353 mstudiomesh_t;
354
355 // studio models
356 struct mstudiomodel_t
357 {
358 char name[64];
359 int type;
360 float boundingradius;
361
362 int nummeshes;
363 int meshindex;
364
365 int numvertices; // number of unique vertices/normals/texcoords
366 int vertexindex; // vertex Vector
367 int tangentsindex; // tangents Vector
368
369 int numattachments;
370 int attachmentindex;
371
372 int numeyeballs;
373 int eyeballindex;
374
375 mstudio_modelvertexdata_t vertexdata;
376
377 int unused[8]; // remove as appropriate
378 };
379 mstudiomesh_t *studiomodel_pMesh( mstudiomodel_t *t, int i )
380 {
381 return (mstudiomesh_t *)(((char *)t) + t->meshindex) + i;
382 };
383
384 typedef struct
385 {
386 int sznameindex;
387 int nummodels;
388 int base;
389 int modelindex; // index into models array
390 } mstudiobodyparts_t;
391
392 mstudiomodel_t *mstudiobodyparts_pModel( mstudiobodyparts_t *t, int i )
393 {
394 return (mstudiomodel_t *)(((char *)t) + t->modelindex) + i;
395 };
396
397 typedef struct {
398 int id;
399 int version;
400 int checksum; // this has to be the same in the phy and vtx files to load!
401 char name[64];
402 int length;
403 float eyeposition[3]; // ideal eye position
404 float illumposition[3]; // illumination center
405 float hull_min[3]; // ideal movement hull size
406 float hull_max[3];
407 float view_bbmin[3]; // clipping bounding box
408 float view_bbmax[3];
409 int flags;
410 int numbones; // bones
411 int boneindex;
412 int numbonecontrollers; // bone controllers
413 int bonecontrollerindex;
414 int numhitboxsets;
415 int hitboxsetindex;
416 int numlocalanim; // animations/poses
417 int localanimindex; // animation descriptions
418 int numlocalseq; // sequences
419 int localseqindex;
420 int activitylistversion;
421 int eventsindexed;
422 // raw textures
423 int numtextures;
424 int textureindex;
425 // raw textures search paths
426 int numcdtextures;
427 int cdtextureindex;
428 // replaceable textures tables
429 int numskinref;
430 int numskinfamilies;
431 int skinindex;
432 int numbodyparts;
433 int bodypartindex;
434 // queryable attachable points
435 int numlocalattachments;
436 int localattachmentindex;
437 // animation node to animation node transition graph
438 int numlocalnodes;
439 int localnodeindex;
440 int localnodenameindex;
441 int numflexdesc;
442 int flexdescindex;
443 int numflexcontrollers;
444 int flexcontrollerindex;
445 int numflexrules;
446 int flexruleindex;
447 int numikchains;
448 int ikchainindex;
449 int nummouths;
450 int mouthindex;
451 int numlocalposeparameters;
452 int localposeparamindex;
453 int surfacepropindex;
454 // Key values
455 int keyvalueindex;
456 int keyvaluesize;
457 int numlocalikautoplaylocks;
458 int localikautoplaylockindex;
459 // The collision model mass that jay wanted
460 float mass;
461 int contents;
462 // external animations, models, etc.
463 int numincludemodels;
464 int includemodelindex;
465 // for demand loaded animation blocks
466 int szanimblocknameindex;
467 int numanimblocks;
468 int animblockindex;
469 int bonetablebynameindex;
470 char constdirectionallightdot;
471 char rootLOD;
472 char numAllowedRootLODs;
473 char unused[1];
474 int unused4; // zero out if version < 47
475 int numflexcontrollerui;
476 int flexcontrolleruiindex;
477 float flVertAnimFixedPointScale;
478 int unused3[1];
479 int studiohdr2index;
480 int unused2[1];
481 }
482 studiohdr_t;
483
484 mstudiobodyparts_t *studiohdr_pBodypart( studiohdr_t *t, int i )
485 {
486 return (mstudiobodyparts_t *)(((char *)t) + t->bodypartindex) + i;
487 };
488
489 #pragma pack(pop)
490
491 void mdl_free( mdl_mesh_t *m )
492 {
493 free( m->indices );
494 free( m->vertices );
495 }
496
497 void mdl_error( mdl_mesh_t *m )
498 {
499 m->num_indices = 0;
500 m->num_vertices = 0;
501 m->indices = NULL;
502 m->vertices = NULL;
503 }
504
505 int mdl_from_find_files( const char *mdlname, mdl_mesh_t *ctx )
506 {
507 // Read entire files into memory (inline functions map memory)
508 // .DX90.VTX
509 char path[1024];
510 strcpy( path, mdlname );
511 csr_stripext( path );
512 strcat( path, ".dx90.vtx" );
513 VTXFileHeader_t *pVtxHdr = (VTXFileHeader_t *)valve_fs_get( path );
514
515 if( !pVtxHdr )
516 {
517 mdl_error( ctx );
518 return 0;
519 }
520
521 // .VVD
522 strcpy( path, mdlname );
523 csr_stripext( path );
524 strcat( path, ".vvd" );
525 vertexFileHeader_t *pVvdHdr = (vertexFileHeader_t *)valve_fs_get( path );
526
527 if( !pVvdHdr )
528 {
529 free( pVtxHdr );
530 mdl_error( ctx );
531 return 0;
532 }
533
534 // .MDL
535 strcpy( path, mdlname );
536 csr_stripext( path );
537 strcat( path, ".mdl" );
538 studiohdr_t *pMdl = (studiohdr_t *)valve_fs_get( path );
539
540 if( !pMdl )
541 {
542 free( pVtxHdr );
543 free( pVvdHdr );
544 mdl_error( ctx );
545 return 0;
546 }
547
548 v3_copy( pMdl->hull_min, ctx->bounds[0] );
549 v3_copy( pMdl->hull_max, ctx->bounds[1] );
550
551 ctx->num_indices = vtx_count_indices( pVtxHdr );
552
553 // Allocate and read indices
554 ctx->indices = (u16 *)csr_malloc( ctx->num_indices * sizeof( u16 ) );
555 ctx->num_indices = 0;
556
557 for ( int bodyID = 0; bodyID < pMdl->numbodyparts; ++bodyID )
558 {
559 // Body parts
560 VTXBodyPartHeader_t* pVtxBodyPart = pBodyPartVTX( pVtxHdr, bodyID );
561 mstudiobodyparts_t *pBodyPart = studiohdr_pBodypart( pMdl, bodyID );
562
563 for ( int modelID = 0; modelID < pBodyPart->nummodels; ++modelID )
564 {
565 // Models
566 VTXModelHeader_t* pVtxModel = pModelVTX( pVtxBodyPart, modelID );
567 mstudiomodel_t *pStudioModel = mstudiobodyparts_pModel( pBodyPart, modelID );
568
569 int nLod = 0;
570 VTXModelLODHeader_t *pVtxLOD = pLODVTX( pVtxModel, nLod );
571
572 for ( int nMesh = 0; nMesh < pStudioModel->nummeshes; ++nMesh )
573 {
574 // Meshes
575 VTXMeshHeader_t* pVtxMesh = pMeshVTX( pVtxLOD, nMesh );
576 mstudiomesh_t* pMesh = studiomodel_pMesh( pStudioModel, nMesh );
577
578 for ( int nGroup = 0; nGroup < pVtxMesh->numStripGroups; ++nGroup )
579 {
580 // Groups
581 VTXStripGroupHeader_t* pStripGroup = pStripGroupVTX( pVtxMesh, nGroup );
582
583 for ( int nStrip = 0; nStrip < pStripGroup->numStrips; nStrip++ )
584 {
585 // Strips
586 VTXStripHeader_t *pStrip = pStripVTX( pStripGroup, nStrip );
587
588 if ( pStrip->flags & STRIP_IS_TRILIST )
589 {
590 // Indices
591 for ( int i = 0; i < pStrip->numIndices; i ++ )
592 {
593 u16 i1 = *pIndexVTX( pStripGroup, pStrip->indexOffset + i );
594 ctx->indices[ ctx->num_indices ++ ] = pVertexVTX( pStripGroup, i1 )->origMeshVertID + pMesh->vertexoffset;
595 }
596 }
597 }
598 }
599 }
600 }
601 }
602
603 mstudiovertex_t *vertexData = GetVertexData( pVvdHdr );
604
605 // Allocate vertex blob (XYZ|NRM|UV)
606 ctx->num_vertices = pVvdHdr->numLodVertexes[0];
607 ctx->vertices = (float *)csr_malloc( ctx->num_vertices * 8 * sizeof( float ) );
608
609 for( int i = 0; i < ctx->num_vertices; i ++ )
610 {
611 mstudiovertex_t *vert = vertexData + i;
612 memcpy( ctx->vertices + i * 8, vert->pos, 8 * sizeof(float) );
613 }
614
615 free( pVtxHdr );
616 free( pVvdHdr );
617 free( pMdl );
618
619 return 1;
620 }
621
622 #endif