doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Model_md5.cpp
Go to the documentation of this file.
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;
52  float jointWeight;
54 
55 /*
56 ====================
57 idMD5Mesh::idMD5Mesh
58 ====================
59 */
62  weightIndex = NULL;
63  shader = NULL;
64  numTris = 0;
65  deformInfo = NULL;
66  surfaceNum = 0;
67 }
68 
69 /*
70 ====================
71 idMD5Mesh::~idMD5Mesh
72 ====================
73 */
77  if ( 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 ) {
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 );
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 
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
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 
306  tri->indexes = deformInfo->indexes;
311  tri->dupVerts = deformInfo->dupVerts;
313  tri->silEdges = deformInfo->silEdges;
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 ) {
327  } else {
328  TransformVerts( tri->verts, entJoints );
329  }
330 
331  // replicate the mirror seam vertexes
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 */
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 */
492  int version;
493  int i;
494  int num;
495  int parentNum;
496  idToken token;
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 ) ) {
509  return;
510  }
511 
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 );
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
574 }
575 
576 /*
577 ==============
578 idRenderModelMD5::Print
579 ==============
580 */
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 */
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 */
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 */
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 
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 ) ) ) {
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
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 */
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 */
837  return joints.Ptr();
838 }
839 
840 /*
841 ====================
842 idRenderModelMD5::GetDefaultPose
843 ====================
844 */
846  return defaultPose.Ptr();
847 }
848 
849 /*
850 ====================
851 idRenderModelMD5::GetJointHandle
852 ====================
853 */
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 */
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 */
929  purged = true;
930  joints.Clear();
931  defaultPose.Clear();
932  meshes.Clear();
933 }
934 
935 /*
936 ===================
937 idRenderModelMD5::Memory
938 ===================
939 */
941  int total, i;
942 
943  total = sizeof( *this );
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 }
static void RemoveOverlaySurfacesFromModel(idRenderModel *baseModel)
jointHandle_t
Definition: Model.h:156
bool SurfaceCastsShadow(void) const
Definition: Material.h:392
int CheckTokenString(const char *string)
Definition: Lexer.cpp:1007
virtual const char * Name() const
Definition: Model.cpp:367
struct deformInfo_s * deformInfo
Definition: Model_local.h:160
virtual void LoadModel()
Definition: Model_md5.cpp:491
virtual void List() const
Definition: Model_md5.cpp:610
deformInfo_t * R_BuildDeformInfo(int numVerts, const idDrawVert *verts, int numIndexes, const int *indexes, bool useUnsmoothedTangents)
bool AddBounds(const idBounds &a)
Definition: Bounds.h:255
bool FindSurfaceWithId(int id, int &surfaceNum)
Definition: Model.cpp:2318
idMat3 ToMat3(void) const
Definition: Vector.cpp:195
idList< modelSurface_t > surfaces
Definition: Model_local.h:106
void TransformScaledVerts(idDrawVert *verts, const idJointMat *joints, float scale)
Definition: Model_md5.cpp:264
idVec4 colorGreen
Definition: Lib.cpp:118
void CalculateBounds(const idJointMat *joints)
Definition: Model_md5.cpp:634
assert(prefInfo.fullscreenBtn)
virtual const idMD5Joint * GetJoints(void) const
Definition: Model_md5.cpp:836
const float * ToFloatPtr(void) const
Definition: Quat.h:289
void Clear(void)
Definition: DrawVert.h:73
glIndex_t * silIndexes
Definition: Model.h:104
idVec4 colorWhite
Definition: Lib.cpp:116
int numVerts
Definition: Model.h:98
float GetFloat(void) const
Definition: CVarSystem.h:144
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
idMat3 ToMat3(void) const
Definition: Quat.cpp:70
const float * ToFloatPtr(void) const
Definition: Vector.h:719
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
int surfaceNum
Definition: Model_local.h:161
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:4804
idMat3 Transpose(void) const
Definition: Matrix.h:677
void ParseMesh(idLexer &parser, int numJoints, const idJointMat *joints)
Definition: Model_md5.cpp:88
idList< idMD5Joint > joints
Definition: Model_local.h:187
int Parse1DMatrix(int x, float *m)
Definition: Lexer.cpp:1300
float w
Definition: Quat.h:53
int numDupVerts
Definition: Model.h:109
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
const idMaterial * shader
Definition: Model.h:146
void SetGranularity(int newgranularity)
Definition: List.h:305
#define MD5_VERSION_STRING
Definition: Model.h:41
glIndex_t * indexes
Definition: tr_local.h:1526
const char * GetName(void) const
Definition: DeclManager.h:140
Definition: Vector.h:316
bool facePlanesCalculated
Definition: Model.h:93
int numMirroredVerts
Definition: tr_local.h:1522
type * Ptr(void)
Definition: List.h:596
performanceCounters_t pc
Definition: tr_local.h:788
silEdge_t * silEdges
Definition: Model.h:113
void TransformVerts(idDrawVert *verts, const idJointMat *joints)
Definition: Model_md5.cpp:253
virtual const char * Name() const =0
idCVar r_showSkel("r_showSkel","0", CVAR_RENDERER|CVAR_INTEGER,"draw the skeleton when model animates, 1 = draw model with skeleton, 2 = draw skeleton only", 0, 2, idCmdSystem::ArgCompletion_Integer< 0, 2 >)
void Clear(void)
Definition: Bounds.h:201
Definition: Token.h:71
void R_DeriveTangents(srfTriangles_t *tri, bool allocFacePlanes=true)
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
bool tangentsCalculated
Definition: Model.h:92
float ParseFloat(bool *errorFlag=NULL)
Definition: Lexer.cpp:1264
srfTriangles_t * R_AllocStaticTriSurf(void)
Definition: tr_trisurf.cpp:523
void UpdateSurface(const struct renderEntity_s *ent, const idJointMat *joints, modelSurface_t *surf)
Definition: Model_md5.cpp:275
glIndex_t * silIndexes
Definition: tr_local.h:1528
virtual jointHandle_t GetJointHandle(const char *name) const
Definition: Model_md5.cpp:854
bool DeleteSurfaceWithId(int id)
Definition: Model.cpp:2283
int i
Definition: process.py:33
GLintptr offset
Definition: glext.h:3113
int ParseInt(void)
Definition: Lexer.cpp:1227
GLuint GLuint num
Definition: glext.h:5390
void MakeDefaultModel()
Definition: Model.cpp:229
const int SHADERPARM_MD5_SKINSCALE
Definition: RenderWorld.h:57
void SetTranslation(const idVec3 &t)
void R_FreeDeformInfo(deformInfo_t *deformInfo)
bool IsDrawn(void) const
Definition: Material.h:378
const idMaterial * customShader
Definition: RenderWorld.h:123
int Icmp(const char *text) const
Definition: Str.h:667
virtual int NearestJoint(int surfaceNum, int a, int b, int c) const
Definition: Model_md5.cpp:886
idCVar r_skipSuppress("r_skipSuppress","0", CVAR_RENDERER|CVAR_BOOL,"ignore the per-view suppressions")
void SetRotation(const idMat3 &m)
idVec4 * scaledWeights
Definition: Model_local.h:156
idVec4 colorRed
Definition: Lib.cpp:117
int * dupVerts
Definition: tr_local.h:1531
struct version_s version
int numSilEdges
Definition: Model.h:112
virtual void TouchData()
Definition: Model_md5.cpp:911
bool AddPoint(const idVec3 &v)
Definition: Bounds.h:226
idVec2 st
Definition: DrawVert.h:43
Definition: Lexer.h:137
void Error(const char *str,...) id_attribute((format(printf
Definition: Lexer.cpp:215
idCVar r_useDeferredTangents("r_useDeferredTangents","1", CVAR_RENDERER|CVAR_BOOL,"defer tangents calculations after deform")
idRenderWorld * rw
Definition: Session.h:153
virtual idBounds Bounds(const struct renderEntity_s *ent) const
Definition: Model_md5.cpp:652
virtual int Memory() const
Definition: Model_md5.cpp:940
GLuint GLuint GLsizei count
Definition: glext.h:2845
virtual void VPCALL MinMax(float &min, float &max, const float *src, const int count)=0
int numMirroredVerts
Definition: Model.h:106
virtual void InitEmpty(const char *name)
Definition: Model.cpp:332
struct vertexWeight_s vertexWeight_t
virtual void DebugLine(const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifetime=0, const bool depthTest=false)=0
const GLubyte * c
Definition: glext.h:4677
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
Definition: Vector.h:808
virtual void VPCALL TransformVerts(idDrawVert *verts, const int numVerts, const idJointMat *joints, const idVec4 *weights, const int *index, const int numWeights)=0
#define vec3_zero
Definition: Vector.h:390
idVec3 ToVec3(void) const
idBounds bounds
Definition: Model.h:87
int NumWeights(void) const
Definition: Model_md5.cpp:427
virtual void virtual void virtual void DWarning(const char *fmt,...) id_attribute((format(printf
renderView_t renderView
Definition: tr_local.h:370
idCommon * common
Definition: Common.cpp:206
bool deformedSurface
Definition: Model.h:95
idJointMat * joints
Definition: RenderWorld.h:135
#define NULL
Definition: Lib.h:88
const idMD5Joint * parent
Definition: Model.h:164
srfTriangles_t * geometry
Definition: Model.h:147
void ParseJoint(idLexer &parser, idMD5Joint *joint, idJointQuat *defaultPose)
Definition: Model_md5.cpp:442
const idDeclSkin * customSkin
Definition: RenderWorld.h:125
const idMaterial * R_RemapShaderBySkin(const idMaterial *shader, const idDeclSkin *skin, const idMaterial *customShader)
int GetInteger(void) const
Definition: CVarSystem.h:143
int * weightIndex
Definition: Model_local.h:157
void * Mem_Alloc16(const int size)
Definition: Heap.cpp:1107
void R_FreeStaticTriSurf(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:489
float w
Definition: Vector.h:813
virtual void DrawText(const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align=1, const int lifetime=0, bool depthTest=false)=0
void FromTransformedBounds(const idBounds &bounds, const idVec3 &origin, const idMat3 &axis)
Definition: Bounds.cpp:232
virtual void VPCALL Mul(float *dst, const float constant, const float *src, const int count)=0
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
virtual void Printf(const char *fmt,...) id_attribute((format(printf
void R_BoundTriSurf(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:704
int numSilEdges
Definition: tr_local.h:1533
idBounds Expand(const float d) const
Definition: Bounds.h:317
bool UseUnsmoothedTangents(void) const
Definition: Material.h:417
virtual void PurgeModel()
Definition: Model_md5.cpp:928
int numSourceVerts
Definition: tr_local.h:1515
int * mirroredVerts
Definition: Model.h:107
idDeclManager * declManager
int NearestJoint(int a, int b, int c) const
Definition: Model_md5.cpp:370
const idMaterial * shader
Definition: Model_local.h:158
GLubyte GLubyte b
Definition: glext.h:4662
idMat3 ToMat3(void) const
int ExpectTokenString(const char *string)
Definition: Lexer.cpp:919
idVec3 vieworg
Definition: RenderWorld.h:215
idCVar r_useCachedDynamicModels("r_useCachedDynamicModels","1", CVAR_RENDERER|CVAR_BOOL,"cache snapshots of dynamic models")
void void Warning(const char *str,...) id_attribute((format(printf
Definition: Lexer.cpp:241
virtual dynamicModel_t IsDynamicModel() const
Definition: Model_md5.cpp:818
bool GetBool(void) const
Definition: CVarSystem.h:142
int NumTris(void) const
Definition: Model_md5.cpp:418
int numDupVerts
Definition: tr_local.h:1530
virtual void InitFromFile(const char *fileName)
Definition: Model_md5.cpp:478
int Num(void) const
Definition: List.h:265
dynamicModel_t
Definition: Model.h:150
const GLcharARB * name
Definition: glext.h:3629
int numIndexes
Definition: tr_local.h:1525
void Mem_Free16(void *ptr)
Definition: Heap.cpp:1128
Definition: Str.h:116
idBounds bounds
Definition: RenderWorld.h:95
int NumVerts(void) const
Definition: Model_md5.cpp:409
idStr name
Definition: Model.h:163
int suppressSurfaceInViewID
Definition: RenderWorld.h:104
idBounds CalcBounds(const idJointMat *joints)
Definition: Model_md5.cpp:354
idCVar r_jointNameScale("r_jointNameScale","0.02", CVAR_RENDERER|CVAR_FLOAT,"size of joint names when r_showskel is set to 1")
virtual void Print() const
Definition: Model_md5.cpp:581
const char * c_str(void) const
Definition: Str.h:487
glIndex_t * indexes
Definition: Model.h:102
dominantTri_t * dominantTris
Definition: tr_local.h:1536
virtual int NumSurfaces() const
Definition: Model.cpp:385
idRenderSystemLocal tr
const idVec3 & ToVec3(void) const
Definition: Vector.h:1043
float CalcW(void) const
Definition: Quat.h:280
silEdge_t * silEdges
Definition: tr_local.h:1534
int * dupVerts
Definition: Model.h:110
GLint j
Definition: qgl.h:264
virtual void DebugBounds(const idVec4 &color, const idBounds &bounds, const idVec3 &org=vec3_origin, const int lifetime=0)=0
int numIndexes
Definition: Model.h:101
int * mirroredVerts
Definition: tr_local.h:1523
virtual idRenderModel * InstantiateDynamicModel(const struct renderEntity_s *ent, const struct viewDef_s *view, idRenderModel *cachedModel)
Definition: Model_md5.cpp:722
idSession * session
Definition: Session.cpp:48
int numWeights
Definition: Model_local.h:155
virtual const char * GetJointName(jointHandle_t handle) const
Definition: Model_md5.cpp:873
virtual void Error(const char *fmt,...) id_attribute((format(printf
idMat3 viewaxis
Definition: RenderWorld.h:216
virtual const idJointQuat * GetDefaultPose(void) const
Definition: Model_md5.cpp:845
idCVar r_jointNameOffset("r_jointNameOffset","0.5", CVAR_RENDERER|CVAR_FLOAT,"offset of joint names when r_showskel is set to 1")
#define MD5_VERSION
Definition: Model.h:45
idVec4 colorMagenta
Definition: Lib.cpp:121
virtual int NumJoints(void) const
Definition: Model_md5.cpp:827
void R_AllocStaticTriSurfVerts(srfTriangles_t *tri, int numVerts)
Definition: tr_trisurf.cpp:555
bool ContainsPoint(const idVec3 &p) const
Definition: Bounds.h:353
float shaderParms[MAX_ENTITY_SHADER_PARMS]
Definition: RenderWorld.h:127
int R_DeformInfoMemoryUsed(deformInfo_t *deformInfo)
int ReadToken(idToken *token)
Definition: Lexer.cpp:820
idList< idMD5Mesh > meshes
Definition: Model_local.h:189
void R_FreeStaticTriSurfVertexCaches(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:343
idList< idJointQuat > defaultPose
Definition: Model_local.h:188
float jointWeight
Definition: Model_md5.cpp:52
idDrawVert * verts
Definition: Model.h:99
idVec4 colorBlue
Definition: Lib.cpp:119
int numOutputVerts
Definition: tr_local.h:1520
void DrawJoints(const renderEntity_t *ent, const struct viewDef_s *view) const
Definition: Model_md5.cpp:675
size_t MemoryUsed(void) const
Definition: List.h:252
int LoadFile(const char *filename, bool OSPath=false)
Definition: Lexer.cpp:1591
idList< idVec2 > texCoords
Definition: Model_local.h:154
void Clear(void)
Definition: List.h:184
idSIMDProcessor * SIMDProcessor
Definition: Simd.cpp:43
dominantTri_t * dominantTris
Definition: Model.h:117