]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/Model_md5.cpp
hello world
[icculus/iodoom3.git] / neo / renderer / Model_md5.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "tr_local.h"
33 #include "Model_local.h"
34
35 static const char *MD5_SnapshotName = "_MD5_Snapshot_";
36
37
38 /***********************************************************************
39
40         idMD5Mesh
41
42 ***********************************************************************/
43
44 static int c_numVerts = 0;
45 static int c_numWeights = 0;
46 static int c_numWeightJoints = 0;
47
48 typedef struct vertexWeight_s {
49         int                                                     vert;
50         int                                                     joint;
51         idVec3                                          offset;
52         float                                           jointWeight;
53 } vertexWeight_t;
54
55 /*
56 ====================
57 idMD5Mesh::idMD5Mesh
58 ====================
59 */
60 idMD5Mesh::idMD5Mesh() {
61         scaledWeights   = NULL;
62         weightIndex             = NULL;
63         shader                  = NULL;
64         numTris                 = 0;
65         deformInfo              = NULL;
66         surfaceNum              = 0;
67 }
68
69 /*
70 ====================
71 idMD5Mesh::~idMD5Mesh
72 ====================
73 */
74 idMD5Mesh::~idMD5Mesh() {
75         Mem_Free16( scaledWeights );
76         Mem_Free16( weightIndex );
77         if ( deformInfo ) {
78                 R_FreeDeformInfo( deformInfo );
79                 deformInfo = NULL;
80         }
81 }
82
83 /*
84 ====================
85 idMD5Mesh::ParseMesh
86 ====================
87 */
88 void idMD5Mesh::ParseMesh( idLexer &parser, int numJoints, const idJointMat *joints ) {
89         idToken         token;
90         idToken         name;
91         int                     num;
92         int                     count;
93         int                     jointnum;
94         idStr           shaderName;
95         int                     i, j;
96         idList<int>     tris;
97         idList<int>     firstWeightForVertex;
98         idList<int>     numWeightsForVertex;
99         int                     maxweight;
100         idList<vertexWeight_t> tempWeights;
101
102         parser.ExpectTokenString( "{" );
103
104         //
105         // parse name
106         //
107         if ( parser.CheckTokenString( "name" ) ) {
108                 parser.ReadToken( &name );
109         }
110
111         //
112         // parse shader
113         //
114         parser.ExpectTokenString( "shader" );
115
116         parser.ReadToken( &token );
117         shaderName = token;
118
119     shader = declManager->FindMaterial( shaderName );
120
121         //
122         // parse texture coordinates
123         //
124         parser.ExpectTokenString( "numverts" );
125         count = parser.ParseInt();
126         if ( count < 0 ) {
127                 parser.Error( "Invalid size: %s", token.c_str() );
128         }
129
130         texCoords.SetNum( count );
131         firstWeightForVertex.SetNum( count );
132         numWeightsForVertex.SetNum( count );
133
134         numWeights = 0;
135         maxweight = 0;
136         for( i = 0; i < texCoords.Num(); i++ ) {
137                 parser.ExpectTokenString( "vert" );
138                 parser.ParseInt();
139
140                 parser.Parse1DMatrix( 2, texCoords[ i ].ToFloatPtr() );
141
142                 firstWeightForVertex[ i ]       = parser.ParseInt();
143                 numWeightsForVertex[ i ]        = parser.ParseInt();
144
145                 if ( !numWeightsForVertex[ i ] ) {
146                         parser.Error( "Vertex without any joint weights." );
147                 }
148
149                 numWeights += numWeightsForVertex[ i ];
150                 if ( numWeightsForVertex[ i ] + firstWeightForVertex[ i ] > maxweight ) {
151                         maxweight = numWeightsForVertex[ i ] + firstWeightForVertex[ i ];
152                 }
153         }
154
155         //
156         // parse tris
157         //
158         parser.ExpectTokenString( "numtris" );
159         count = parser.ParseInt();
160         if ( count < 0 ) {
161                 parser.Error( "Invalid size: %d", count );
162         }
163
164         tris.SetNum( count * 3 );
165         numTris = count;
166         for( i = 0; i < count; i++ ) {
167                 parser.ExpectTokenString( "tri" );
168                 parser.ParseInt();
169
170                 tris[ i * 3 + 0 ] = parser.ParseInt();
171                 tris[ i * 3 + 1 ] = parser.ParseInt();
172                 tris[ i * 3 + 2 ] = parser.ParseInt();
173         }
174
175         //
176         // parse weights
177         //
178         parser.ExpectTokenString( "numweights" );
179         count = parser.ParseInt();
180         if ( count < 0 ) {
181                 parser.Error( "Invalid size: %d", count );
182         }
183
184         if ( maxweight > count ) {
185                 parser.Warning( "Vertices reference out of range weights in model (%d of %d weights).", maxweight, count );
186         }
187
188         tempWeights.SetNum( count );
189
190         for( i = 0; i < count; i++ ) {
191                 parser.ExpectTokenString( "weight" );
192                 parser.ParseInt();
193
194                 jointnum = parser.ParseInt();
195                 if ( ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
196                         parser.Error( "Joint Index out of range(%d): %d", numJoints, jointnum );
197                 }
198
199                 tempWeights[ i ].joint                  = jointnum;
200                 tempWeights[ i ].jointWeight    = parser.ParseFloat();
201
202                 parser.Parse1DMatrix( 3, tempWeights[ i ].offset.ToFloatPtr() );
203         }
204
205         // create pre-scaled weights and an index for the vertex/joint lookup
206         scaledWeights = (idVec4 *) Mem_Alloc16( numWeights * sizeof( scaledWeights[0] ) );
207         weightIndex = (int *) Mem_Alloc16( numWeights * 2 * sizeof( weightIndex[0] ) );
208         memset( weightIndex, 0, numWeights * 2 * sizeof( weightIndex[0] ) );
209
210         count = 0;
211         for( i = 0; i < texCoords.Num(); i++ ) {
212                 num = firstWeightForVertex[i];
213                 for( j = 0; j < numWeightsForVertex[i]; j++, num++, count++ ) {
214                         scaledWeights[count].ToVec3() = tempWeights[num].offset * tempWeights[num].jointWeight;
215                         scaledWeights[count].w = tempWeights[num].jointWeight;
216                         weightIndex[count * 2 + 0] = tempWeights[num].joint * sizeof( idJointMat );
217                 }
218                 weightIndex[count * 2 - 1] = 1;
219         }
220
221         tempWeights.Clear();
222         numWeightsForVertex.Clear();
223         firstWeightForVertex.Clear();
224
225         parser.ExpectTokenString( "}" );
226
227         // update counters
228         c_numVerts += texCoords.Num();
229         c_numWeights += numWeights;
230         c_numWeightJoints++;
231         for ( i = 0; i < numWeights; i++ ) {
232                 c_numWeightJoints += weightIndex[i*2+1];
233         }
234
235         //
236         // build the information that will be common to all animations of this mesh:
237         // silhouette edge connectivity and normal / tangent generation information
238         //
239         idDrawVert *verts = (idDrawVert *) _alloca16( texCoords.Num() * sizeof( idDrawVert ) );
240         for ( i = 0; i < texCoords.Num(); i++ ) {
241                 verts[i].Clear();
242                 verts[i].st = texCoords[i];
243         }
244         TransformVerts( verts, joints );
245         deformInfo = R_BuildDeformInfo( texCoords.Num(), verts, tris.Num(), tris.Ptr(), shader->UseUnsmoothedTangents() );
246 }
247
248 /*
249 ====================
250 idMD5Mesh::TransformVerts
251 ====================
252 */
253 void idMD5Mesh::TransformVerts( idDrawVert *verts, const idJointMat *entJoints ) {
254         SIMDProcessor->TransformVerts( verts, texCoords.Num(), entJoints, scaledWeights, weightIndex, numWeights );
255 }
256
257 /*
258 ====================
259 idMD5Mesh::TransformScaledVerts
260
261 Special transform to make the mesh seem fat or skinny.  May be used for zombie deaths
262 ====================
263 */
264 void idMD5Mesh::TransformScaledVerts( idDrawVert *verts, const idJointMat *entJoints, float scale ) {
265         idVec4 *scaledWeights = (idVec4 *) _alloca16( numWeights * sizeof( scaledWeights[0] ) );
266         SIMDProcessor->Mul( scaledWeights[0].ToFloatPtr(), scale, scaledWeights[0].ToFloatPtr(), numWeights * 4 );
267         SIMDProcessor->TransformVerts( verts, texCoords.Num(), entJoints, scaledWeights, weightIndex, numWeights );
268 }
269
270 /*
271 ====================
272 idMD5Mesh::UpdateSurface
273 ====================
274 */
275 void idMD5Mesh::UpdateSurface( const struct renderEntity_s *ent, const idJointMat *entJoints, modelSurface_t *surf ) {
276         int i, base;
277         srfTriangles_t *tri;
278
279         tr.pc.c_deformedSurfaces++;
280         tr.pc.c_deformedVerts += deformInfo->numOutputVerts;
281         tr.pc.c_deformedIndexes += deformInfo->numIndexes;
282
283         surf->shader = shader;
284
285         if ( surf->geometry ) {
286                 // if the number of verts and indexes are the same we can re-use the triangle surface
287                 // the number of indexes must be the same to assure the correct amount of memory is allocated for the facePlanes
288                 if ( surf->geometry->numVerts == deformInfo->numOutputVerts && surf->geometry->numIndexes == deformInfo->numIndexes ) {
289                         R_FreeStaticTriSurfVertexCaches( surf->geometry );
290                 } else {
291                         R_FreeStaticTriSurf( surf->geometry );
292                         surf->geometry = R_AllocStaticTriSurf();
293                 }
294         } else {
295                 surf->geometry = R_AllocStaticTriSurf();
296         }
297
298         tri = surf->geometry;
299
300         // note that some of the data is references, and should not be freed
301         tri->deformedSurface = true;
302         tri->tangentsCalculated = false;
303         tri->facePlanesCalculated = false;
304
305         tri->numIndexes = deformInfo->numIndexes;
306         tri->indexes = deformInfo->indexes;
307         tri->silIndexes = deformInfo->silIndexes;
308         tri->numMirroredVerts = deformInfo->numMirroredVerts;
309         tri->mirroredVerts = deformInfo->mirroredVerts;
310         tri->numDupVerts = deformInfo->numDupVerts;
311         tri->dupVerts = deformInfo->dupVerts;
312         tri->numSilEdges = deformInfo->numSilEdges;
313         tri->silEdges = deformInfo->silEdges;
314         tri->dominantTris = deformInfo->dominantTris;
315         tri->numVerts = deformInfo->numOutputVerts;
316
317         if ( tri->verts == NULL ) {
318                 R_AllocStaticTriSurfVerts( tri, tri->numVerts );
319                 for ( i = 0; i < deformInfo->numSourceVerts; i++ ) {
320                         tri->verts[i].Clear();
321                         tri->verts[i].st = texCoords[i];
322                 }
323         }
324
325         if ( ent->shaderParms[ SHADERPARM_MD5_SKINSCALE ] != 0.0f ) {
326                 TransformScaledVerts( tri->verts, entJoints, ent->shaderParms[ SHADERPARM_MD5_SKINSCALE ] );
327         } else {
328                 TransformVerts( tri->verts, entJoints );
329         }
330
331         // replicate the mirror seam vertexes
332         base = deformInfo->numOutputVerts - deformInfo->numMirroredVerts;
333         for ( i = 0; i < deformInfo->numMirroredVerts; i++ ) {
334                 tri->verts[base + i] = tri->verts[deformInfo->mirroredVerts[i]];
335         }
336
337         R_BoundTriSurf( tri );
338
339         // If a surface is going to be have a lighting interaction generated, it will also have to call
340         // R_DeriveTangents() to get normals, tangents, and face planes.  If it only
341         // needs shadows generated, it will only have to generate face planes.  If it only
342         // has ambient drawing, or is culled, no additional work will be necessary
343         if ( !r_useDeferredTangents.GetBool() ) {
344                 // set face planes, vertex normals, tangents
345                 R_DeriveTangents( tri );
346         }
347 }
348
349 /*
350 ====================
351 idMD5Mesh::CalcBounds
352 ====================
353 */
354 idBounds idMD5Mesh::CalcBounds( const idJointMat *entJoints ) {
355         idBounds        bounds;
356         idDrawVert *verts = (idDrawVert *) _alloca16( texCoords.Num() * sizeof( idDrawVert ) );
357
358         TransformVerts( verts, entJoints );
359
360         SIMDProcessor->MinMax( bounds[0], bounds[1], verts, texCoords.Num() );
361
362         return bounds;
363 }
364
365 /*
366 ====================
367 idMD5Mesh::NearestJoint
368 ====================
369 */
370 int idMD5Mesh::NearestJoint( int a, int b, int c ) const {
371         int i, bestJoint, vertNum, weightVertNum;
372         float bestWeight;
373
374         // duplicated vertices might not have weights
375         if ( a >= 0 && a < texCoords.Num() ) {
376                 vertNum = a;
377         } else if ( b >= 0 && b < texCoords.Num() ) {
378                 vertNum = b;
379         } else if ( c >= 0 && c < texCoords.Num() ) {
380                 vertNum = c;
381         } else {
382                 // all vertices are duplicates which shouldn't happen
383                 return 0;
384         }
385
386         // find the first weight for this vertex
387         weightVertNum = 0;
388         for( i = 0; weightVertNum < vertNum; i++ ) {
389                 weightVertNum += weightIndex[i*2+1];
390         }
391
392         // get the joint for the largest weight
393         bestWeight = scaledWeights[i].w;
394         bestJoint = weightIndex[i*2+0] / sizeof( idJointMat );
395         for( ; weightIndex[i*2+1] == 0; i++ ) {
396                 if ( scaledWeights[i].w > bestWeight ) {
397                         bestWeight = scaledWeights[i].w;
398                         bestJoint = weightIndex[i*2+0] / sizeof( idJointMat );
399                 }
400         }
401         return bestJoint;
402 }
403
404 /*
405 ====================
406 idMD5Mesh::NumVerts
407 ====================
408 */
409 int idMD5Mesh::NumVerts( void ) const {
410         return texCoords.Num();
411 }
412
413 /*
414 ====================
415 idMD5Mesh::NumTris
416 ====================
417 */
418 int     idMD5Mesh::NumTris( void ) const {
419         return numTris;
420 }
421
422 /*
423 ====================
424 idMD5Mesh::NumWeights
425 ====================
426 */
427 int     idMD5Mesh::NumWeights( void ) const {
428         return numWeights;
429 }
430
431 /***********************************************************************
432
433         idRenderModelMD5
434
435 ***********************************************************************/
436
437 /*
438 ====================
439 idRenderModelMD5::ParseJoint
440 ====================
441 */
442 void idRenderModelMD5::ParseJoint( idLexer &parser, idMD5Joint *joint, idJointQuat *defaultPose ) {
443         idToken token;
444         int             num;
445
446         //
447         // parse name
448         //
449         parser.ReadToken( &token );
450         joint->name = token;
451
452         //
453         // parse parent
454         //
455         num = parser.ParseInt();
456         if ( num < 0 ) {
457                 joint->parent = NULL;
458         } else {
459                 if ( num >= joints.Num() - 1 ) {
460                         parser.Error( "Invalid parent for joint '%s'", joint->name.c_str() );
461                 }
462                 joint->parent = &joints[ num ];
463         }
464
465         //
466         // parse default pose
467         //
468         parser.Parse1DMatrix( 3, defaultPose->t.ToFloatPtr() );
469         parser.Parse1DMatrix( 3, defaultPose->q.ToFloatPtr() );
470         defaultPose->q.w = defaultPose->q.CalcW();
471 }
472
473 /*
474 ====================
475 idRenderModelMD5::InitFromFile
476 ====================
477 */
478 void idRenderModelMD5::InitFromFile( const char *fileName ) {
479         name = fileName;
480         LoadModel();
481 }
482
483 /*
484 ====================
485 idRenderModelMD5::LoadModel
486
487 used for initial loads, reloadModel, and reloading the data of purged models
488 Upon exit, the model will absolutely be valid, but possibly as a default model
489 ====================
490 */
491 void idRenderModelMD5::LoadModel() {
492         int                     version;
493         int                     i;
494         int                     num;
495         int                     parentNum;
496         idToken         token;
497         idLexer         parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS );
498         idJointQuat     *pose;
499         idMD5Joint      *joint;
500         idJointMat *poseMat3;
501
502         if ( !purged ) {
503                 PurgeModel();
504         }
505         purged = false;
506
507         if ( !parser.LoadFile( name ) ) {
508                 MakeDefaultModel();
509                 return;
510         }
511
512         parser.ExpectTokenString( MD5_VERSION_STRING );
513         version = parser.ParseInt();
514
515         if ( version != MD5_VERSION ) {
516                 parser.Error( "Invalid version %d.  Should be version %d\n", version, MD5_VERSION );
517         }
518
519         //
520         // skip commandline
521         //
522         parser.ExpectTokenString( "commandline" );
523         parser.ReadToken( &token );
524
525         // parse num joints
526         parser.ExpectTokenString( "numJoints" );
527         num  = parser.ParseInt();
528         joints.SetGranularity( 1 );
529         joints.SetNum( num );
530         defaultPose.SetGranularity( 1 );
531         defaultPose.SetNum( num );
532         poseMat3 = ( idJointMat * )_alloca16( num * sizeof( *poseMat3 ) );
533
534         // parse num meshes
535         parser.ExpectTokenString( "numMeshes" );
536         num = parser.ParseInt();
537         if ( num < 0 ) {
538                 parser.Error( "Invalid size: %d", num );
539         }
540         meshes.SetGranularity( 1 );
541         meshes.SetNum( num );
542
543         //
544         // parse joints
545         //
546         parser.ExpectTokenString( "joints" );
547         parser.ExpectTokenString( "{" );
548         pose = defaultPose.Ptr();
549         joint = joints.Ptr();
550         for( i = 0; i < joints.Num(); i++, joint++, pose++ ) {
551                 ParseJoint( parser, joint, pose );
552                 poseMat3[ i ].SetRotation( pose->q.ToMat3() );
553                 poseMat3[ i ].SetTranslation( pose->t );
554                 if ( joint->parent ) {
555                         parentNum = joint->parent - joints.Ptr();
556                         pose->q = ( poseMat3[ i ].ToMat3() * poseMat3[ parentNum ].ToMat3().Transpose() ).ToQuat();
557                         pose->t = ( poseMat3[ i ].ToVec3() - poseMat3[ parentNum ].ToVec3() ) * poseMat3[ parentNum ].ToMat3().Transpose();
558                 }
559         }
560         parser.ExpectTokenString( "}" );
561
562         for( i = 0; i < meshes.Num(); i++ ) {
563                 parser.ExpectTokenString( "mesh" );
564                 meshes[ i ].ParseMesh( parser, defaultPose.Num(), poseMat3 );
565         }
566
567         //
568         // calculate the bounds of the model
569         //
570         CalculateBounds( poseMat3 );
571
572         // set the timestamp for reloadmodels
573         fileSystem->ReadFile( name, NULL, &timeStamp );
574 }
575
576 /*
577 ==============
578 idRenderModelMD5::Print
579 ==============
580 */
581 void idRenderModelMD5::Print() const {
582         const idMD5Mesh *mesh;
583         int                     i;
584
585         common->Printf( "%s\n", name.c_str() );
586         common->Printf( "Dynamic model.\n" );
587         common->Printf( "Generated smooth normals.\n" );
588         common->Printf( "    verts  tris weights material\n" );
589         int     totalVerts = 0;
590         int     totalTris = 0;
591         int     totalWeights = 0;
592         for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
593                 totalVerts += mesh->NumVerts();
594                 totalTris += mesh->NumTris();
595                 totalWeights += mesh->NumWeights();
596                 common->Printf( "%2i: %5i %5i %7i %s\n", i, mesh->NumVerts(), mesh->NumTris(), mesh->NumWeights(), mesh->shader->GetName() );
597         }       
598         common->Printf( "-----\n" );
599         common->Printf( "%4i verts.\n", totalVerts );
600         common->Printf( "%4i tris.\n", totalTris );
601         common->Printf( "%4i weights.\n", totalWeights );
602         common->Printf( "%4i joints.\n", joints.Num() );
603 }
604
605 /*
606 ==============
607 idRenderModelMD5::List
608 ==============
609 */
610 void idRenderModelMD5::List() const {
611         int                     i;
612         const idMD5Mesh *mesh;
613         int                     totalTris = 0;
614         int                     totalVerts = 0;
615
616         for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
617                 totalTris += mesh->numTris;
618                 totalVerts += mesh->NumVerts();
619         }
620         common->Printf( " %4ik %3i %4i %4i %s(MD5)", Memory()/1024, meshes.Num(), totalVerts, totalTris, Name() );
621
622         if ( defaulted ) {
623                 common->Printf( " (DEFAULTED)" );
624         }
625
626         common->Printf( "\n" );
627 }
628
629 /*
630 ====================
631 idRenderModelMD5::CalculateBounds
632 ====================
633 */
634 void idRenderModelMD5::CalculateBounds( const idJointMat *entJoints ) {
635         int                     i;
636         idMD5Mesh       *mesh;
637
638         bounds.Clear();
639         for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
640                 bounds.AddBounds( mesh->CalcBounds( entJoints ) );
641         }
642 }
643
644 /*
645 ====================
646 idRenderModelMD5::Bounds
647
648 This calculates a rough bounds by using the joint radii without
649 transforming all the points
650 ====================
651 */
652 idBounds idRenderModelMD5::Bounds( const renderEntity_t *ent ) const {
653 #if 0
654         // we can't calculate a rational bounds without an entity,
655         // because joints could be positioned to deform it into an
656         // arbitrarily large shape
657         if ( !ent ) {
658                 common->Error( "idRenderModelMD5::Bounds: called without entity" );
659         }
660 #endif
661
662         if ( !ent ) {
663                 // this is the bounds for the reference pose
664                 return bounds;
665         }
666
667         return ent->bounds;
668 }
669
670 /*
671 ====================
672 idRenderModelMD5::DrawJoints
673 ====================
674 */
675 void idRenderModelMD5::DrawJoints( const renderEntity_t *ent, const struct viewDef_s *view ) const {
676         int                                     i;
677         int                                     num;
678         idVec3                          pos;
679         const idJointMat        *joint;
680         const idMD5Joint        *md5Joint;
681         int                                     parentNum;
682
683         num = ent->numJoints;
684         joint = ent->joints;
685         md5Joint = joints.Ptr();        
686         for( i = 0; i < num; i++, joint++, md5Joint++ ) {
687                 pos = ent->origin + joint->ToVec3() * ent->axis;
688                 if ( md5Joint->parent ) {
689                         parentNum = md5Joint->parent - joints.Ptr();
690                         session->rw->DebugLine( colorWhite, ent->origin + ent->joints[ parentNum ].ToVec3() * ent->axis, pos );
691                 }
692
693                 session->rw->DebugLine( colorRed,       pos, pos + joint->ToMat3()[ 0 ] * 2.0f * ent->axis );
694                 session->rw->DebugLine( colorGreen,     pos, pos + joint->ToMat3()[ 1 ] * 2.0f * ent->axis );
695                 session->rw->DebugLine( colorBlue,      pos, pos + joint->ToMat3()[ 2 ] * 2.0f * ent->axis );
696         }
697
698         idBounds bounds;
699
700         bounds.FromTransformedBounds( ent->bounds, vec3_zero, ent->axis );
701         session->rw->DebugBounds( colorMagenta, bounds, ent->origin );
702
703         if ( ( r_jointNameScale.GetFloat() != 0.0f ) && ( bounds.Expand( 128.0f ).ContainsPoint( view->renderView.vieworg - ent->origin ) ) ) {
704                 idVec3  offset( 0, 0, r_jointNameOffset.GetFloat() );
705                 float   scale;
706
707                 scale = r_jointNameScale.GetFloat();
708                 joint = ent->joints;
709                 num = ent->numJoints;
710                 for( i = 0; i < num; i++, joint++ ) {
711                         pos = ent->origin + joint->ToVec3() * ent->axis;
712                         session->rw->DrawText( joints[ i ].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 );
713                 }
714         }
715 }
716
717 /*
718 ====================
719 idRenderModelMD5::InstantiateDynamicModel
720 ====================
721 */
722 idRenderModel *idRenderModelMD5::InstantiateDynamicModel( const struct renderEntity_s *ent, const struct viewDef_s *view, idRenderModel *cachedModel ) {
723         int                                     i, surfaceNum;
724         idMD5Mesh                       *mesh;
725         idRenderModelStatic     *staticModel;
726
727         if ( cachedModel && !r_useCachedDynamicModels.GetBool() ) {
728                 delete cachedModel;
729                 cachedModel = NULL;
730         }
731
732         if ( purged ) {
733                 common->DWarning( "model %s instantiated while purged", Name() );
734                 LoadModel();
735         }
736
737         if ( !ent->joints ) {
738                 common->Printf( "idRenderModelMD5::InstantiateDynamicModel: NULL joints on renderEntity for '%s'\n", Name() );
739                 delete cachedModel;
740                 return NULL;
741         } else if ( ent->numJoints != joints.Num() ) {
742                 common->Printf( "idRenderModelMD5::InstantiateDynamicModel: renderEntity has different number of joints than model for '%s'\n", Name() );
743                 delete cachedModel;
744                 return NULL;
745         }
746
747         tr.pc.c_generateMd5++;
748
749         if ( cachedModel ) {
750                 assert( dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL );
751                 assert( idStr::Icmp( cachedModel->Name(), MD5_SnapshotName ) == 0 );
752                 staticModel = static_cast<idRenderModelStatic *>(cachedModel);
753         } else {
754                 staticModel = new idRenderModelStatic;
755                 staticModel->InitEmpty( MD5_SnapshotName );
756         }
757
758         staticModel->bounds.Clear();
759
760         if ( r_showSkel.GetInteger() ) {
761                 if ( ( view != NULL ) && ( !r_skipSuppress.GetBool() || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) ) {
762                         // only draw the skeleton
763                         DrawJoints( ent, view );
764                 }
765
766                 if ( r_showSkel.GetInteger() > 1 ) {
767                         // turn off the model when showing the skeleton
768                         staticModel->InitEmpty( MD5_SnapshotName );
769                         return staticModel;
770                 }
771         }
772
773         // create all the surfaces
774         for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
775                 // avoid deforming the surface if it will be a nodraw due to a skin remapping
776                 // FIXME: may have to still deform clipping hulls
777                 const idMaterial *shader = mesh->shader;
778                 
779                 shader = R_RemapShaderBySkin( shader, ent->customSkin, ent->customShader );
780                 
781                 if ( !shader || ( !shader->IsDrawn() && !shader->SurfaceCastsShadow() ) ) {
782                         staticModel->DeleteSurfaceWithId( i );
783                         mesh->surfaceNum = -1;
784                         continue;
785                 }
786
787                 modelSurface_t *surf;
788
789                 if ( staticModel->FindSurfaceWithId( i, surfaceNum ) ) {
790                         mesh->surfaceNum = surfaceNum;
791                         surf = &staticModel->surfaces[surfaceNum];
792                 } else {
793
794                         // Remove Overlays before adding new surfaces
795                         idRenderModelOverlay::RemoveOverlaySurfacesFromModel( staticModel );
796
797                         mesh->surfaceNum = staticModel->NumSurfaces();
798                         surf = &staticModel->surfaces.Alloc();
799                         surf->geometry = NULL;
800                         surf->shader = NULL;
801                         surf->id = i;
802                 }
803
804                 mesh->UpdateSurface( ent, ent->joints, surf );
805
806                 staticModel->bounds.AddPoint( surf->geometry->bounds[0] );
807                 staticModel->bounds.AddPoint( surf->geometry->bounds[1] );
808         }
809
810         return staticModel;
811 }
812
813 /*
814 ====================
815 idRenderModelMD5::IsDynamicModel
816 ====================
817 */
818 dynamicModel_t idRenderModelMD5::IsDynamicModel() const {
819         return DM_CACHED;
820 }
821
822 /*
823 ====================
824 idRenderModelMD5::NumJoints
825 ====================
826 */
827 int idRenderModelMD5::NumJoints( void ) const {
828         return joints.Num();
829 }
830
831 /*
832 ====================
833 idRenderModelMD5::GetJoints
834 ====================
835 */
836 const idMD5Joint *idRenderModelMD5::GetJoints( void ) const {
837         return joints.Ptr();
838 }
839
840 /*
841 ====================
842 idRenderModelMD5::GetDefaultPose
843 ====================
844 */
845 const idJointQuat *idRenderModelMD5::GetDefaultPose( void ) const {
846         return defaultPose.Ptr();
847 }
848
849 /*
850 ====================
851 idRenderModelMD5::GetJointHandle
852 ====================
853 */
854 jointHandle_t idRenderModelMD5::GetJointHandle( const char *name ) const {
855         const idMD5Joint *joint;
856         int     i;
857         
858         joint = joints.Ptr();
859         for( i = 0; i < joints.Num(); i++, joint++ ) {
860                 if ( idStr::Icmp( joint->name.c_str(), name ) == 0 ) {
861                         return ( jointHandle_t )i;
862                 }
863         }
864
865         return INVALID_JOINT;
866 }
867
868 /*
869 =====================
870 idRenderModelMD5::GetJointName
871 =====================
872 */
873 const char *idRenderModelMD5::GetJointName( jointHandle_t handle ) const {
874         if ( ( handle < 0 ) || ( handle >= joints.Num() ) ) {
875                 return "<invalid joint>";
876         }
877
878         return joints[ handle ].name;
879 }
880
881 /*
882 ====================
883 idRenderModelMD5::NearestJoint
884 ====================
885 */
886 int idRenderModelMD5::NearestJoint( int surfaceNum, int a, int b, int c ) const {
887         int i;
888         const idMD5Mesh *mesh;
889
890         if ( surfaceNum > meshes.Num() ) {
891                 common->Error( "idRenderModelMD5::NearestJoint: surfaceNum > meshes.Num()" );
892         }
893
894         for ( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
895                 if ( mesh->surfaceNum == surfaceNum ) {
896                         return mesh->NearestJoint( a, b, c );
897                 }
898         }
899         return 0;
900 }
901
902 /*
903 ====================
904 idRenderModelMD5::TouchData
905
906 models that are already loaded at level start time
907 will still touch their materials to make sure they
908 are kept loaded
909 ====================
910 */
911 void idRenderModelMD5::TouchData() {
912         idMD5Mesh       *mesh;
913         int                     i;
914
915         for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
916                 declManager->FindMaterial( mesh->shader->GetName() );
917         }
918 }
919
920 /*
921 ===================
922 idRenderModelMD5::PurgeModel
923
924 frees all the data, but leaves the class around for dangling references,
925 which can regenerate the data with LoadModel()
926 ===================
927 */
928 void idRenderModelMD5::PurgeModel() {
929         purged = true;
930         joints.Clear();
931         defaultPose.Clear();
932         meshes.Clear();
933 }
934
935 /*
936 ===================
937 idRenderModelMD5::Memory
938 ===================
939 */
940 int     idRenderModelMD5::Memory() const {
941         int             total, i;
942
943         total = sizeof( *this );
944         total += joints.MemoryUsed() + defaultPose.MemoryUsed() + meshes.MemoryUsed();
945
946         // count up strings
947         for ( i = 0; i < joints.Num(); i++ ) {
948                 total += joints[i].name.DynamicMemoryUsed();
949         }
950
951         // count up meshes
952         for ( i = 0 ; i < meshes.Num() ; i++ ) {
953                 const idMD5Mesh *mesh = &meshes[i];
954
955                 total += mesh->texCoords.MemoryUsed() + mesh->numWeights * ( sizeof( mesh->scaledWeights[0] ) + sizeof( mesh->weightIndex[0] ) * 2 );
956
957                 // sum up deform info
958                 total += sizeof( mesh->deformInfo );
959                 total += R_DeformInfoMemoryUsed( mesh->deformInfo );
960         }
961         return total;
962 }