Model_md5.cpp 26 KB

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