Model_md5.cpp (43111B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition 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 #pragma hdrstop 30 #include "../idlib/precompiled.h" 31 32 #include "tr_local.h" 33 #include "Model_local.h" 34 35 #ifdef ID_WIN_X86_SSE2_INTRIN 36 37 static const __m128 vector_float_posInfinity = { idMath::INFINITY, idMath::INFINITY, idMath::INFINITY, idMath::INFINITY }; 38 static const __m128 vector_float_negInfinity = { -idMath::INFINITY, -idMath::INFINITY, -idMath::INFINITY, -idMath::INFINITY }; 39 40 #endif 41 42 static const char *MD5_SnapshotName = "_MD5_Snapshot_"; 43 44 static const byte MD5B_VERSION = 106; 45 static const unsigned int MD5B_MAGIC = ( '5' << 24 ) | ( 'D' << 16 ) | ( 'M' << 8 ) | MD5B_VERSION; 46 47 idCVar r_useGPUSkinning( "r_useGPUSkinning", "1", CVAR_INTEGER, "animate normals and tangents instead of deriving" ); 48 49 /*********************************************************************** 50 51 idMD5Mesh 52 53 ***********************************************************************/ 54 55 static int c_numVerts = 0; 56 static int c_numWeights = 0; 57 static int c_numWeightJoints = 0; 58 59 struct vertexWeight_t { 60 int joint; 61 idVec3 offset; 62 float jointWeight; 63 }; 64 65 /* 66 ==================== 67 idMD5Mesh::idMD5Mesh 68 ==================== 69 */ 70 idMD5Mesh::idMD5Mesh() { 71 shader = NULL; 72 numVerts = 0; 73 numTris = 0; 74 meshJoints = NULL; 75 numMeshJoints = 0; 76 maxJointVertDist = 0.0f; 77 deformInfo = NULL; 78 surfaceNum = 0; 79 } 80 81 /* 82 ==================== 83 idMD5Mesh::~idMD5Mesh 84 ==================== 85 */ 86 idMD5Mesh::~idMD5Mesh() { 87 if ( meshJoints != NULL ) { 88 Mem_Free( meshJoints ); 89 meshJoints = NULL; 90 } 91 if ( deformInfo != NULL ) { 92 R_FreeDeformInfo( deformInfo ); 93 deformInfo = NULL; 94 } 95 } 96 97 /* 98 ==================== 99 idMD5Mesh::ParseMesh 100 ==================== 101 */ 102 void idMD5Mesh::ParseMesh( idLexer &parser, int numJoints, const idJointMat *joints ) { 103 idToken token; 104 idToken name; 105 106 parser.ExpectTokenString( "{" ); 107 108 // 109 // parse name 110 // 111 if ( parser.CheckTokenString( "name" ) ) { 112 parser.ReadToken( &name ); 113 } 114 115 // 116 // parse shader 117 // 118 parser.ExpectTokenString( "shader" ); 119 120 parser.ReadToken( &token ); 121 idStr shaderName = token; 122 123 shader = declManager->FindMaterial( shaderName ); 124 125 // 126 // parse texture coordinates 127 // 128 parser.ExpectTokenString( "numverts" ); 129 int count = parser.ParseInt(); 130 if ( count < 0 ) { 131 parser.Error( "Invalid size: %s", token.c_str() ); 132 } 133 134 this->numVerts = count; 135 136 idList<idVec2> texCoords; 137 idList<int> firstWeightForVertex; 138 idList<int> numWeightsForVertex; 139 140 texCoords.SetNum( count ); 141 firstWeightForVertex.SetNum( count ); 142 numWeightsForVertex.SetNum( count ); 143 144 int numWeights = 0; 145 int maxweight = 0; 146 for ( int i = 0; i < texCoords.Num(); i++ ) { 147 parser.ExpectTokenString( "vert" ); 148 parser.ParseInt(); 149 150 parser.Parse1DMatrix( 2, texCoords[ i ].ToFloatPtr() ); 151 152 firstWeightForVertex[ i ] = parser.ParseInt(); 153 numWeightsForVertex[ i ] = parser.ParseInt(); 154 155 if ( !numWeightsForVertex[ i ] ) { 156 parser.Error( "Vertex without any joint weights." ); 157 } 158 159 numWeights += numWeightsForVertex[ i ]; 160 if ( numWeightsForVertex[ i ] + firstWeightForVertex[ i ] > maxweight ) { 161 maxweight = numWeightsForVertex[ i ] + firstWeightForVertex[ i ]; 162 } 163 } 164 165 // 166 // parse tris 167 // 168 parser.ExpectTokenString( "numtris" ); 169 count = parser.ParseInt(); 170 if ( count < 0 ) { 171 parser.Error( "Invalid size: %d", count ); 172 } 173 174 idList<int> tris; 175 tris.SetNum( count * 3 ); 176 numTris = count; 177 for ( int i = 0; i < count; i++ ) { 178 parser.ExpectTokenString( "tri" ); 179 parser.ParseInt(); 180 181 tris[ i * 3 + 0 ] = parser.ParseInt(); 182 tris[ i * 3 + 1 ] = parser.ParseInt(); 183 tris[ i * 3 + 2 ] = parser.ParseInt(); 184 } 185 186 // 187 // parse weights 188 // 189 parser.ExpectTokenString( "numweights" ); 190 count = parser.ParseInt(); 191 if ( count < 0 ) { 192 parser.Error( "Invalid size: %d", count ); 193 } 194 195 if ( maxweight > count ) { 196 parser.Warning( "Vertices reference out of range weights in model (%d of %d weights).", maxweight, count ); 197 } 198 199 idList<vertexWeight_t> tempWeights; 200 tempWeights.SetNum( count ); 201 assert( numJoints < 256 ); // so we can pack into bytes 202 203 for ( int i = 0; i < count; i++ ) { 204 parser.ExpectTokenString( "weight" ); 205 parser.ParseInt(); 206 207 int jointnum = parser.ParseInt(); 208 if ( ( jointnum < 0 ) || ( jointnum >= numJoints ) ) { 209 parser.Error( "Joint Index out of range(%d): %d", numJoints, jointnum ); 210 } 211 212 tempWeights[ i ].joint = jointnum; 213 tempWeights[ i ].jointWeight = parser.ParseFloat(); 214 215 parser.Parse1DMatrix( 3, tempWeights[ i ].offset.ToFloatPtr() ); 216 } 217 218 // create pre-scaled weights and an index for the vertex/joint lookup 219 idVec4 * scaledWeights = (idVec4 *) Mem_Alloc16( numWeights * sizeof( scaledWeights[0] ), TAG_MD5_WEIGHT ); 220 int * weightIndex = (int *) Mem_Alloc16( numWeights * 2 * sizeof( weightIndex[0] ), TAG_MD5_INDEX ); 221 memset( weightIndex, 0, numWeights * 2 * sizeof( weightIndex[0] ) ); 222 223 count = 0; 224 for ( int i = 0; i < texCoords.Num(); i++ ) { 225 int num = firstWeightForVertex[i]; 226 for( int j = 0; j < numWeightsForVertex[i]; j++, num++, count++ ) { 227 scaledWeights[count].ToVec3() = tempWeights[num].offset * tempWeights[num].jointWeight; 228 scaledWeights[count].w = tempWeights[num].jointWeight; 229 weightIndex[count * 2 + 0] = tempWeights[num].joint * sizeof( idJointMat ); 230 } 231 weightIndex[count * 2 - 1] = 1; 232 } 233 234 parser.ExpectTokenString( "}" ); 235 236 // update counters 237 c_numVerts += texCoords.Num(); 238 c_numWeights += numWeights; 239 c_numWeightJoints++; 240 for ( int i = 0; i < numWeights; i++ ) { 241 c_numWeightJoints += weightIndex[i*2+1]; 242 } 243 244 // 245 // build a base pose that can be used for skinning 246 // 247 idDrawVert * basePose = (idDrawVert *)Mem_ClearedAlloc( texCoords.Num() * sizeof( *basePose ), TAG_MD5_BASE ); 248 for( int j = 0, i = 0; i < texCoords.Num(); i++ ) { 249 idVec3 v = ( *(idJointMat *) ( (byte *)joints + weightIndex[j*2+0] ) ) * scaledWeights[j]; 250 while( weightIndex[j*2+1] == 0 ) { 251 j++; 252 v += ( *(idJointMat *) ( (byte *)joints + weightIndex[j*2+0] ) ) * scaledWeights[j]; 253 } 254 j++; 255 256 basePose[i].Clear(); 257 basePose[i].xyz = v; 258 basePose[i].SetTexCoord( texCoords[i] ); 259 } 260 261 // build the weights and bone indexes into the verts, so they will be duplicated 262 // as necessary at mirror seems 263 264 static int maxWeightsPerVert; 265 static float maxResidualWeight; 266 267 const int MAX_VERTEX_WEIGHTS = 4; 268 269 idList< bool > jointIsUsed; 270 jointIsUsed.SetNum( numJoints ); 271 for ( int i = 0; i < jointIsUsed.Num(); i++ ) { 272 jointIsUsed[i] = false; 273 } 274 275 numMeshJoints = 0; 276 maxJointVertDist = 0.0f; 277 278 //----------------------------------------- 279 // new-style setup for fixed four weights and normal / tangent deformation 280 // 281 // Several important models have >25% residual weight in joints after the 282 // first four, which is worrisome for using a fixed four joint deformation. 283 //----------------------------------------- 284 for ( int i = 0; i < texCoords.Num(); i++ ) { 285 idDrawVert & dv = basePose[i]; 286 287 // some models do have >4 joint weights, so it is necessary to sort and renormalize 288 289 // sort the weights and take the four largest 290 int weights[256]; 291 const int numWeights = numWeightsForVertex[ i ]; 292 for ( int j = 0; j < numWeights; j++ ) { 293 weights[j] = firstWeightForVertex[i] + j; 294 } 295 // bubble sort 296 for ( int j = 0; j < numWeights; j++ ) { 297 for ( int k = 0; k < numWeights - 1 - j; k++ ) { 298 if ( tempWeights[weights[k]].jointWeight < tempWeights[weights[k+1]].jointWeight ) { 299 SwapValues( weights[k], weights[k+1] ); 300 } 301 } 302 } 303 304 if ( numWeights > maxWeightsPerVert ) { 305 maxWeightsPerVert = numWeights; 306 } 307 308 const int usedWeights = Min( MAX_VERTEX_WEIGHTS, numWeights ); 309 310 float totalWeight = 0; 311 for ( int j = 0; j < numWeights; j++ ) { 312 totalWeight += tempWeights[weights[j]].jointWeight; 313 } 314 assert( totalWeight > 0.999f && totalWeight < 1.001f ); 315 316 float usedWeight = 0; 317 for ( int j = 0; j < usedWeights; j++ ) { 318 usedWeight += tempWeights[weights[j]].jointWeight; 319 } 320 321 const float residualWeight = totalWeight - usedWeight; 322 if ( residualWeight > maxResidualWeight ) { 323 maxResidualWeight = residualWeight; 324 } 325 326 byte finalWeights[MAX_VERTEX_WEIGHTS] = { 0 }; 327 byte finalJointIndecies[MAX_VERTEX_WEIGHTS] = { 0 }; 328 for ( int j = 0; j < usedWeights; j++ ) { 329 const vertexWeight_t & weight = tempWeights[weights[j]]; 330 const int jointIndex = weight.joint; 331 const float fw = weight.jointWeight; 332 assert( fw >= 0.0f && fw <= 1.0f ); 333 const float normalizedWeight = fw / usedWeight; 334 finalWeights[j] = idMath::Ftob( normalizedWeight * 255.0f); 335 finalJointIndecies[j] = jointIndex; 336 } 337 338 // Sort the weights and indices for hardware skinning 339 for ( int k = 0; k < 3; ++k ) { 340 for ( int l = k + 1; l < 4; ++l ) { 341 if ( finalWeights[l] > finalWeights[k] ) { 342 SwapValues( finalWeights[k], finalWeights[l] ); 343 SwapValues( finalJointIndecies[k], finalJointIndecies[l] ); 344 } 345 } 346 } 347 348 // Give any left over to the biggest weight 349 finalWeights[0] += Max( 255 - finalWeights[0] - finalWeights[1] - finalWeights[2] - finalWeights[3], 0 ); 350 351 dv.color[0] = finalJointIndecies[0]; 352 dv.color[1] = finalJointIndecies[1]; 353 dv.color[2] = finalJointIndecies[2]; 354 dv.color[3] = finalJointIndecies[3]; 355 356 dv.color2[0] = finalWeights[0]; 357 dv.color2[1] = finalWeights[1]; 358 dv.color2[2] = finalWeights[2]; 359 dv.color2[3] = finalWeights[3]; 360 361 for ( int j = usedWeights; j < 4; j++ ) { 362 assert( dv.color2[j] == 0 ); 363 } 364 365 for ( int j = 0; j < usedWeights; j++ ) { 366 if ( !jointIsUsed[finalJointIndecies[j]] ) { 367 jointIsUsed[finalJointIndecies[j]] = true; 368 numMeshJoints++; 369 } 370 const idJointMat & joint = joints[finalJointIndecies[j]]; 371 float dist = ( dv.xyz - joint.GetTranslation() ).Length(); 372 if ( dist > maxJointVertDist ) { 373 maxJointVertDist = dist; 374 } 375 } 376 } 377 378 meshJoints = (byte *) Mem_Alloc( numMeshJoints * sizeof( meshJoints[0] ), TAG_MODEL ); 379 numMeshJoints = 0; 380 for ( int i = 0; i < numJoints; i++ ) { 381 if ( jointIsUsed[i] ) { 382 meshJoints[numMeshJoints++] = i; 383 } 384 } 385 386 // build the deformInfo and collect a final base pose with the mirror 387 // seam verts properly including the bone weights 388 deformInfo = R_BuildDeformInfo( texCoords.Num(), basePose, tris.Num(), tris.Ptr(), 389 shader->UseUnsmoothedTangents() ); 390 391 for ( int i = 0; i < deformInfo->numOutputVerts; i++ ) { 392 for ( int j = 0; j < 4; j++ ) { 393 if ( deformInfo->verts[i].color[j] >= numJoints ) { 394 idLib::FatalError( "Bad joint index" ); 395 } 396 } 397 } 398 399 Mem_Free( basePose ); 400 } 401 402 /* 403 ============ 404 TransformVertsAndTangents 405 ============ 406 */ 407 void TransformVertsAndTangents( idDrawVert * targetVerts, const int numVerts, const idDrawVert *baseVerts, const idJointMat *joints ) { 408 for( int i = 0; i < numVerts; i++ ) { 409 const idDrawVert & base = baseVerts[i]; 410 411 const idJointMat & j0 = joints[base.color[0]]; 412 const idJointMat & j1 = joints[base.color[1]]; 413 const idJointMat & j2 = joints[base.color[2]]; 414 const idJointMat & j3 = joints[base.color[3]]; 415 416 const float w0 = base.color2[0] * ( 1.0f / 255.0f ); 417 const float w1 = base.color2[1] * ( 1.0f / 255.0f ); 418 const float w2 = base.color2[2] * ( 1.0f / 255.0f ); 419 const float w3 = base.color2[3] * ( 1.0f / 255.0f ); 420 421 idJointMat accum; 422 idJointMat::Mul( accum, j0, w0 ); 423 idJointMat::Mad( accum, j1, w1 ); 424 idJointMat::Mad( accum, j2, w2 ); 425 idJointMat::Mad( accum, j3, w3 ); 426 427 targetVerts[i].xyz = accum * idVec4( base.xyz.x, base.xyz.y, base.xyz.z, 1.0f ); 428 targetVerts[i].SetNormal( accum * base.GetNormal() ); 429 targetVerts[i].SetTangent( accum * base.GetTangent() ); 430 targetVerts[i].tangent[3] = base.tangent[3]; 431 } 432 } 433 434 /* 435 ==================== 436 idMD5Mesh::UpdateSurface 437 ==================== 438 */ 439 void idMD5Mesh::UpdateSurface( const struct renderEntity_s *ent, const idJointMat *entJoints, 440 const idJointMat *entJointsInverted, modelSurface_t *surf ) { 441 442 tr.pc.c_deformedSurfaces++; 443 tr.pc.c_deformedVerts += deformInfo->numOutputVerts; 444 tr.pc.c_deformedIndexes += deformInfo->numIndexes; 445 446 surf->shader = shader; 447 448 if ( surf->geometry != NULL ) { 449 // if the number of verts and indexes are the same we can re-use the triangle surface 450 if ( surf->geometry->numVerts == deformInfo->numOutputVerts && surf->geometry->numIndexes == deformInfo->numIndexes ) { 451 R_FreeStaticTriSurfVertexCaches( surf->geometry ); 452 } else { 453 R_FreeStaticTriSurf( surf->geometry ); 454 surf->geometry = R_AllocStaticTriSurf(); 455 } 456 } else { 457 surf->geometry = R_AllocStaticTriSurf(); 458 } 459 460 srfTriangles_t * tri = surf->geometry; 461 462 // note that some of the data is referenced, and should not be freed 463 tri->referencedIndexes = true; 464 tri->numIndexes = deformInfo->numIndexes; 465 tri->indexes = deformInfo->indexes; 466 tri->silIndexes = deformInfo->silIndexes; 467 tri->numMirroredVerts = deformInfo->numMirroredVerts; 468 tri->mirroredVerts = deformInfo->mirroredVerts; 469 tri->numDupVerts = deformInfo->numDupVerts; 470 tri->dupVerts = deformInfo->dupVerts; 471 tri->numSilEdges = deformInfo->numSilEdges; 472 tri->silEdges = deformInfo->silEdges; 473 474 tri->indexCache = deformInfo->staticIndexCache; 475 476 tri->numVerts = deformInfo->numOutputVerts; 477 if ( r_useGPUSkinning.GetBool() ) { 478 if ( tri->verts != NULL && tri->verts != deformInfo->verts ) { 479 R_FreeStaticTriSurfVerts( tri ); 480 } 481 tri->verts = deformInfo->verts; 482 tri->ambientCache = deformInfo->staticAmbientCache; 483 tri->shadowCache = deformInfo->staticShadowCache; 484 tri->referencedVerts = true; 485 } else { 486 if ( tri->verts == NULL || tri->verts == deformInfo->verts ) { 487 tri->verts = NULL; 488 R_AllocStaticTriSurfVerts( tri, deformInfo->numOutputVerts ); 489 assert( tri->verts != NULL ); // quiet analyze warning 490 memcpy( tri->verts, deformInfo->verts, deformInfo->numOutputVerts * sizeof( deformInfo->verts[0] ) ); // copy over the texture coordinates 491 } 492 TransformVertsAndTangents( tri->verts, deformInfo->numOutputVerts, deformInfo->verts, entJointsInverted ); 493 tri->referencedVerts = false; 494 } 495 tri->tangentsCalculated = true; 496 497 CalculateBounds( entJoints, tri->bounds ); 498 } 499 500 /* 501 ==================== 502 idMD5Mesh::CalculateBounds 503 ==================== 504 */ 505 void idMD5Mesh::CalculateBounds( const idJointMat * entJoints, idBounds & bounds ) const { 506 #ifdef ID_WIN_X86_SSE2_INTRIN 507 508 __m128 minX = vector_float_posInfinity; 509 __m128 minY = vector_float_posInfinity; 510 __m128 minZ = vector_float_posInfinity; 511 __m128 maxX = vector_float_negInfinity; 512 __m128 maxY = vector_float_negInfinity; 513 __m128 maxZ = vector_float_negInfinity; 514 for ( int i = 0; i < numMeshJoints; i++ ) { 515 const idJointMat & joint = entJoints[meshJoints[i]]; 516 __m128 x = _mm_load_ps( joint.ToFloatPtr() + 0 * 4 ); 517 __m128 y = _mm_load_ps( joint.ToFloatPtr() + 1 * 4 ); 518 __m128 z = _mm_load_ps( joint.ToFloatPtr() + 2 * 4 ); 519 minX = _mm_min_ps( minX, x ); 520 minY = _mm_min_ps( minY, y ); 521 minZ = _mm_min_ps( minZ, z ); 522 maxX = _mm_max_ps( maxX, x ); 523 maxY = _mm_max_ps( maxY, y ); 524 maxZ = _mm_max_ps( maxZ, z ); 525 } 526 __m128 expand = _mm_splat_ps( _mm_load_ss( & maxJointVertDist ), 0 ); 527 minX = _mm_sub_ps( minX, expand ); 528 minY = _mm_sub_ps( minY, expand ); 529 minZ = _mm_sub_ps( minZ, expand ); 530 maxX = _mm_add_ps( maxX, expand ); 531 maxY = _mm_add_ps( maxY, expand ); 532 maxZ = _mm_add_ps( maxZ, expand ); 533 _mm_store_ss( bounds.ToFloatPtr() + 0, _mm_splat_ps( minX, 3 ) ); 534 _mm_store_ss( bounds.ToFloatPtr() + 1, _mm_splat_ps( minY, 3 ) ); 535 _mm_store_ss( bounds.ToFloatPtr() + 2, _mm_splat_ps( minZ, 3 ) ); 536 _mm_store_ss( bounds.ToFloatPtr() + 3, _mm_splat_ps( maxX, 3 ) ); 537 _mm_store_ss( bounds.ToFloatPtr() + 4, _mm_splat_ps( maxY, 3 ) ); 538 _mm_store_ss( bounds.ToFloatPtr() + 5, _mm_splat_ps( maxZ, 3 ) ); 539 540 #else 541 542 bounds.Clear(); 543 for ( int i = 0; i < numMeshJoints; i++ ) { 544 const idJointMat & joint = entJoints[meshJoints[i]]; 545 bounds.AddPoint( joint.GetTranslation() ); 546 } 547 bounds.ExpandSelf( maxJointVertDist ); 548 549 #endif 550 } 551 552 /* 553 ==================== 554 idMD5Mesh::NearestJoint 555 ==================== 556 */ 557 int idMD5Mesh::NearestJoint( int a, int b, int c ) const { 558 // duplicated vertices might not have weights 559 int vertNum; 560 if ( a >= 0 && a < numVerts ) { 561 vertNum = a; 562 } else if ( b >= 0 && b < numVerts ) { 563 vertNum = b; 564 } else if ( c >= 0 && c < numVerts ) { 565 vertNum = c; 566 } else { 567 // all vertices are duplicates which shouldn't happen 568 return 0; 569 } 570 571 const idDrawVert & v = deformInfo->verts[vertNum]; 572 573 int bestWeight = 0; 574 int bestJoint = 0; 575 for ( int i = 0; i < 4; i++ ) { 576 if ( v.color2[i] > bestWeight ) { 577 bestWeight = v.color2[i]; 578 bestJoint = v.color[i]; 579 } 580 } 581 582 return bestJoint; 583 } 584 585 /*********************************************************************** 586 587 idRenderModelMD5 588 589 ***********************************************************************/ 590 591 /* 592 ==================== 593 idRenderModelMD5::ParseJoint 594 ==================== 595 */ 596 void idRenderModelMD5::ParseJoint( idLexer &parser, idMD5Joint *joint, idJointQuat *defaultPose ) { 597 // 598 // parse name 599 // 600 idToken token; 601 parser.ReadToken( &token ); 602 joint->name = token; 603 604 // 605 // parse parent 606 // 607 int num = parser.ParseInt(); 608 if ( num < 0 ) { 609 joint->parent = NULL; 610 } else { 611 if ( num >= joints.Num() - 1 ) { 612 parser.Error( "Invalid parent for joint '%s'", joint->name.c_str() ); 613 } 614 joint->parent = &joints[ num ]; 615 } 616 617 // 618 // parse default pose 619 // 620 parser.Parse1DMatrix( 3, defaultPose->t.ToFloatPtr() ); 621 parser.Parse1DMatrix( 3, defaultPose->q.ToFloatPtr() ); 622 defaultPose->q.w = defaultPose->q.CalcW(); 623 } 624 625 /* 626 ==================== 627 idRenderModelMD5::InitFromFile 628 ==================== 629 */ 630 void idRenderModelMD5::InitFromFile( const char *fileName ) { 631 name = fileName; 632 LoadModel(); 633 } 634 635 /* 636 ======================== 637 idRenderModelMD5::LoadBinaryModel 638 ======================== 639 */ 640 bool idRenderModelMD5::LoadBinaryModel( idFile * file, const ID_TIME_T sourceTimeStamp ) { 641 642 if ( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) ) { 643 return false; 644 } 645 646 unsigned int magic = 0; 647 file->ReadBig( magic ); 648 if ( magic != MD5B_MAGIC ) { 649 return false; 650 } 651 652 int tempNum; 653 file->ReadBig( tempNum ); 654 joints.SetNum( tempNum ); 655 for ( int i = 0; i < joints.Num(); i++ ) { 656 file->ReadString( joints[i].name ); 657 int offset; 658 file->ReadBig( offset ); 659 if ( offset >= 0 ) { 660 joints[i].parent = joints.Ptr() + offset; 661 } else { 662 joints[i].parent = NULL; 663 } 664 } 665 666 file->ReadBig( tempNum ); 667 defaultPose.SetNum( tempNum ); 668 for ( int i = 0; i < defaultPose.Num(); i++ ) { 669 file->ReadBig( defaultPose[i].q.x ); 670 file->ReadBig( defaultPose[i].q.y ); 671 file->ReadBig( defaultPose[i].q.z ); 672 file->ReadBig( defaultPose[i].q.w ); 673 file->ReadVec3( defaultPose[i].t ); 674 } 675 676 file->ReadBig( tempNum ); 677 invertedDefaultPose.SetNum( tempNum ); 678 for ( int i = 0; i < invertedDefaultPose.Num(); i++ ) { 679 file->ReadBigArray( invertedDefaultPose[ i ].ToFloatPtr(), JOINTMAT_TYPESIZE ); 680 } 681 SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), joints.Num() ); 682 683 file->ReadBig( tempNum ); 684 meshes.SetNum( tempNum ); 685 for ( int i = 0; i < meshes.Num(); i++ ) { 686 687 idStr materialName; 688 file->ReadString( materialName ); 689 if ( materialName.IsEmpty() ) { 690 meshes[i].shader = NULL; 691 } else { 692 meshes[i].shader = declManager->FindMaterial( materialName ); 693 } 694 695 file->ReadBig( meshes[i].numVerts ); 696 file->ReadBig( meshes[i].numTris ); 697 698 file->ReadBig( meshes[i].numMeshJoints ); 699 meshes[i].meshJoints = (byte *) Mem_Alloc( meshes[i].numMeshJoints * sizeof( meshes[i].meshJoints[0] ), TAG_MODEL ); 700 file->ReadBigArray( meshes[i].meshJoints, meshes[i].numMeshJoints ); 701 file->ReadBig( meshes[i].maxJointVertDist ); 702 703 meshes[i].deformInfo = (deformInfo_t *)R_ClearedStaticAlloc( sizeof( deformInfo_t ) ); 704 deformInfo_t & deform = *meshes[i].deformInfo; 705 706 file->ReadBig( deform.numSourceVerts ); 707 file->ReadBig( deform.numOutputVerts ); 708 file->ReadBig( deform.numIndexes ); 709 file->ReadBig( deform.numMirroredVerts ); 710 file->ReadBig( deform.numDupVerts ); 711 file->ReadBig( deform.numSilEdges ); 712 713 srfTriangles_t tri; 714 memset( &tri, 0, sizeof( srfTriangles_t ) ); 715 716 if ( deform.numOutputVerts > 0 ) { 717 R_AllocStaticTriSurfVerts( &tri, deform.numOutputVerts ); 718 deform.verts = tri.verts; 719 file->ReadBigArray( deform.verts, deform.numOutputVerts ); 720 } 721 722 if ( deform.numIndexes > 0 ) { 723 R_AllocStaticTriSurfIndexes( &tri, deform.numIndexes ); 724 R_AllocStaticTriSurfSilIndexes( &tri, deform.numIndexes ); 725 deform.indexes = tri.indexes; 726 deform.silIndexes = tri.silIndexes; 727 file->ReadBigArray( deform.indexes, deform.numIndexes ); 728 file->ReadBigArray( deform.silIndexes, deform.numIndexes ); 729 } 730 731 if ( deform.numMirroredVerts > 0 ) { 732 R_AllocStaticTriSurfMirroredVerts( &tri, deform.numMirroredVerts ); 733 deform.mirroredVerts = tri.mirroredVerts; 734 file->ReadBigArray( deform.mirroredVerts, deform.numMirroredVerts ); 735 } 736 737 if ( deform.numDupVerts > 0 ) { 738 R_AllocStaticTriSurfDupVerts( &tri, deform.numDupVerts ); 739 deform.dupVerts = tri.dupVerts; 740 file->ReadBigArray( deform.dupVerts, deform.numDupVerts * 2 ); 741 } 742 743 if ( deform.numSilEdges > 0 ) { 744 R_AllocStaticTriSurfSilEdges( &tri, deform.numSilEdges ); 745 deform.silEdges = tri.silEdges; 746 assert( deform.silEdges != NULL ); 747 for ( int j = 0; j < deform.numSilEdges; j++ ) { 748 file->ReadBig( deform.silEdges[j].p1 ); 749 file->ReadBig( deform.silEdges[j].p2 ); 750 file->ReadBig( deform.silEdges[j].v1 ); 751 file->ReadBig( deform.silEdges[j].v2 ); 752 } 753 } 754 755 idShadowVertSkinned * shadowVerts = (idShadowVertSkinned *) Mem_Alloc( ALIGN( deform.numOutputVerts * 2 * sizeof( idShadowVertSkinned ), 16 ), TAG_MODEL ); 756 idShadowVertSkinned::CreateShadowCache( shadowVerts, deform.verts, deform.numOutputVerts ); 757 758 deform.staticAmbientCache = vertexCache.AllocStaticVertex( deform.verts, ALIGN( deform.numOutputVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) ); 759 deform.staticIndexCache = vertexCache.AllocStaticIndex( deform.indexes, ALIGN( deform.numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) ); 760 deform.staticShadowCache = vertexCache.AllocStaticVertex( shadowVerts, ALIGN( deform.numOutputVerts * 2 * sizeof( idShadowVertSkinned ), VERTEX_CACHE_ALIGN ) ); 761 762 Mem_Free( shadowVerts ); 763 764 file->ReadBig( meshes[i].surfaceNum ); 765 } 766 767 return true; 768 } 769 770 /* 771 ======================== 772 idRenderModelMD5::WriteBinaryModel 773 ======================== 774 */ 775 void idRenderModelMD5::WriteBinaryModel( idFile * file, ID_TIME_T *_timeStamp ) const { 776 777 idRenderModelStatic::WriteBinaryModel( file ); 778 779 if ( file == NULL ) { 780 return; 781 } 782 783 file->WriteBig( MD5B_MAGIC ); 784 785 file->WriteBig( joints.Num() ); 786 for ( int i = 0; i < joints.Num(); i++ ) { 787 file->WriteString( joints[i].name ); 788 int offset = -1; 789 if ( joints[i].parent != NULL ) { 790 offset = joints[i].parent - joints.Ptr(); 791 } 792 file->WriteBig( offset ); 793 } 794 795 file->WriteBig( defaultPose.Num() ); 796 for ( int i = 0; i < defaultPose.Num(); i++ ) { 797 file->WriteBig( defaultPose[i].q.x ); 798 file->WriteBig( defaultPose[i].q.y ); 799 file->WriteBig( defaultPose[i].q.z ); 800 file->WriteBig( defaultPose[i].q.w ); 801 file->WriteVec3( defaultPose[i].t ); 802 } 803 804 file->WriteBig( invertedDefaultPose.Num() ); 805 for ( int i = 0; i < invertedDefaultPose.Num(); i++ ) { 806 file->WriteBigArray( invertedDefaultPose[ i ].ToFloatPtr(), JOINTMAT_TYPESIZE ); 807 } 808 809 file->WriteBig( meshes.Num() ); 810 for ( int i = 0; i < meshes.Num(); i++ ) { 811 812 if ( meshes[i].shader != NULL && meshes[i].shader->GetName() != NULL ) { 813 file->WriteString( meshes[i].shader->GetName() ); 814 } else { 815 file->WriteString( "" ); 816 } 817 818 file->WriteBig( meshes[i].numVerts ); 819 file->WriteBig( meshes[i].numTris ); 820 821 file->WriteBig( meshes[i].numMeshJoints ); 822 file->WriteBigArray( meshes[i].meshJoints, meshes[i].numMeshJoints ); 823 file->WriteBig( meshes[i].maxJointVertDist ); 824 825 deformInfo_t & deform = *meshes[i].deformInfo; 826 827 file->WriteBig( deform.numSourceVerts ); 828 file->WriteBig( deform.numOutputVerts ); 829 file->WriteBig( deform.numIndexes ); 830 file->WriteBig( deform.numMirroredVerts ); 831 file->WriteBig( deform.numDupVerts ); 832 file->WriteBig( deform.numSilEdges ); 833 834 if ( deform.numOutputVerts > 0 ) { 835 file->WriteBigArray( deform.verts, deform.numOutputVerts ); 836 } 837 838 if ( deform.numIndexes > 0 ) { 839 file->WriteBigArray( deform.indexes, deform.numIndexes ); 840 file->WriteBigArray( deform.silIndexes, deform.numIndexes ); 841 } 842 843 if ( deform.numMirroredVerts > 0 ) { 844 file->WriteBigArray( deform.mirroredVerts, deform.numMirroredVerts ); 845 } 846 847 if ( deform.numDupVerts > 0 ) { 848 file->WriteBigArray( deform.dupVerts, deform.numDupVerts * 2 ); 849 } 850 851 if ( deform.numSilEdges > 0 ) { 852 for ( int j = 0; j < deform.numSilEdges; j++ ) { 853 file->WriteBig( deform.silEdges[j].p1 ); 854 file->WriteBig( deform.silEdges[j].p2 ); 855 file->WriteBig( deform.silEdges[j].v1 ); 856 file->WriteBig( deform.silEdges[j].v2 ); 857 } 858 } 859 860 file->WriteBig( meshes[i].surfaceNum ); 861 } 862 } 863 864 /* 865 ==================== 866 idRenderModelMD5::LoadModel 867 868 used for initial loads, reloadModel, and reloading the data of purged models 869 Upon exit, the model will absolutely be valid, but possibly as a default model 870 ==================== 871 */ 872 void idRenderModelMD5::LoadModel() { 873 874 int version; 875 int num; 876 int parentNum; 877 idToken token; 878 idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS ); 879 880 if ( !purged ) { 881 PurgeModel(); 882 } 883 purged = false; 884 885 if ( !parser.LoadFile( name ) ) { 886 MakeDefaultModel(); 887 return; 888 } 889 890 parser.ExpectTokenString( MD5_VERSION_STRING ); 891 version = parser.ParseInt(); 892 893 if ( version != MD5_VERSION ) { 894 parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION ); 895 } 896 897 // 898 // skip commandline 899 // 900 parser.ExpectTokenString( "commandline" ); 901 parser.ReadToken( &token ); 902 903 // parse num joints 904 parser.ExpectTokenString( "numJoints" ); 905 num = parser.ParseInt(); 906 joints.SetGranularity( 1 ); 907 joints.SetNum( num ); 908 defaultPose.SetGranularity( 1 ); 909 defaultPose.SetNum( num ); 910 911 // parse num meshes 912 parser.ExpectTokenString( "numMeshes" ); 913 num = parser.ParseInt(); 914 if ( num < 0 ) { 915 parser.Error( "Invalid size: %d", num ); 916 } 917 meshes.SetGranularity( 1 ); 918 meshes.SetNum( num ); 919 920 // 921 // parse joints 922 // 923 parser.ExpectTokenString( "joints" ); 924 parser.ExpectTokenString( "{" ); 925 idJointMat *poseMat = ( idJointMat * )_alloca16( joints.Num() * sizeof( poseMat[0] ) ); 926 for( int i = 0; i < joints.Num(); i++ ) { 927 idMD5Joint * joint = &joints[i]; 928 idJointQuat * pose = &defaultPose[i]; 929 930 ParseJoint( parser, joint, pose ); 931 poseMat[ i ].SetRotation( pose->q.ToMat3() ); 932 poseMat[ i ].SetTranslation( pose->t ); 933 if ( joint->parent ) { 934 parentNum = joint->parent - joints.Ptr(); 935 pose->q = ( poseMat[ i ].ToMat3() * poseMat[ parentNum ].ToMat3().Transpose() ).ToQuat(); 936 pose->t = ( poseMat[ i ].ToVec3() - poseMat[ parentNum ].ToVec3() ) * poseMat[ parentNum ].ToMat3().Transpose(); 937 } 938 } 939 parser.ExpectTokenString( "}" ); 940 941 //----------------------------------------- 942 // create the inverse of the base pose joints to support tech6 style deformation 943 // of base pose vertexes, normals, and tangents. 944 // 945 // vertex * joints * inverseJoints == vertex when joints is the base pose 946 // When the joints are in another pose, it gives the animated vertex position 947 //----------------------------------------- 948 invertedDefaultPose.SetNum( SIMD_ROUND_JOINTS( joints.Num() ) ); 949 for ( int i = 0; i < joints.Num(); i++ ) { 950 invertedDefaultPose[i] = poseMat[i]; 951 invertedDefaultPose[i].Invert(); 952 } 953 SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), joints.Num() ); 954 955 for ( int i = 0; i < meshes.Num(); i++ ) { 956 parser.ExpectTokenString( "mesh" ); 957 meshes[i].ParseMesh( parser, defaultPose.Num(), poseMat ); 958 } 959 960 // calculate the bounds of the model 961 bounds.Clear(); 962 for ( int i = 0; i < meshes.Num(); i++ ) { 963 idBounds meshBounds; 964 meshes[i].CalculateBounds( poseMat, meshBounds ); 965 bounds.AddBounds( meshBounds ); 966 } 967 968 // set the timestamp for reloadmodels 969 fileSystem->ReadFile( name, NULL, &timeStamp ); 970 971 common->UpdateLevelLoadPacifier(); 972 } 973 974 /* 975 ============== 976 idRenderModelMD5::Print 977 ============== 978 */ 979 void idRenderModelMD5::Print() const { 980 common->Printf( "%s\n", name.c_str() ); 981 common->Printf( "Dynamic model.\n" ); 982 common->Printf( "Generated smooth normals.\n" ); 983 common->Printf( " verts tris weights material\n" ); 984 int totalVerts = 0; 985 int totalTris = 0; 986 const idMD5Mesh * mesh = meshes.Ptr(); 987 for ( int i = 0; i < meshes.Num(); i++, mesh++ ) { 988 totalVerts += mesh->NumVerts(); 989 totalTris += mesh->NumTris(); 990 common->Printf( "%2i: %5i %5i %s\n", i, mesh->NumVerts(), mesh->NumTris(), mesh->shader->GetName() ); 991 } 992 common->Printf( "-----\n" ); 993 common->Printf( "%4i verts.\n", totalVerts ); 994 common->Printf( "%4i tris.\n", totalTris ); 995 common->Printf( "%4i joints.\n", joints.Num() ); 996 } 997 998 /* 999 ============== 1000 idRenderModelMD5::List 1001 ============== 1002 */ 1003 void idRenderModelMD5::List() const { 1004 int i; 1005 const idMD5Mesh *mesh; 1006 int totalTris = 0; 1007 int totalVerts = 0; 1008 1009 for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) { 1010 totalTris += mesh->numTris; 1011 totalVerts += mesh->NumVerts(); 1012 } 1013 common->Printf( " %4ik %3i %4i %4i %s(MD5)", Memory()/1024, meshes.Num(), totalVerts, totalTris, Name() ); 1014 1015 if ( defaulted ) { 1016 common->Printf( " (DEFAULTED)" ); 1017 } 1018 1019 common->Printf( "\n" ); 1020 } 1021 1022 /* 1023 ==================== 1024 idRenderModelMD5::Bounds 1025 1026 This calculates a rough bounds by using the joint radii without 1027 transforming all the points 1028 ==================== 1029 */ 1030 idBounds idRenderModelMD5::Bounds( const renderEntity_t *ent ) const { 1031 if ( ent == NULL ) { 1032 // this is the bounds for the reference pose 1033 return bounds; 1034 } 1035 1036 return ent->bounds; 1037 } 1038 1039 /* 1040 ==================== 1041 idRenderModelMD5::DrawJoints 1042 ==================== 1043 */ 1044 void idRenderModelMD5::DrawJoints( const renderEntity_t *ent, const viewDef_t *view ) const { 1045 int i; 1046 int num; 1047 idVec3 pos; 1048 const idJointMat *joint; 1049 const idMD5Joint *md5Joint; 1050 int parentNum; 1051 1052 num = ent->numJoints; 1053 joint = ent->joints; 1054 md5Joint = joints.Ptr(); 1055 for( i = 0; i < num; i++, joint++, md5Joint++ ) { 1056 pos = ent->origin + joint->ToVec3() * ent->axis; 1057 if ( md5Joint->parent ) { 1058 parentNum = md5Joint->parent - joints.Ptr(); 1059 common->RW()->DebugLine( colorWhite, ent->origin + ent->joints[ parentNum ].ToVec3() * ent->axis, pos ); 1060 } 1061 1062 common->RW()->DebugLine( colorRed, pos, pos + joint->ToMat3()[ 0 ] * 2.0f * ent->axis ); 1063 common->RW()->DebugLine( colorGreen,pos, pos + joint->ToMat3()[ 1 ] * 2.0f * ent->axis ); 1064 common->RW()->DebugLine( colorBlue, pos, pos + joint->ToMat3()[ 2 ] * 2.0f * ent->axis ); 1065 } 1066 1067 idBounds bounds; 1068 1069 bounds.FromTransformedBounds( ent->bounds, vec3_zero, ent->axis ); 1070 common->RW()->DebugBounds( colorMagenta, bounds, ent->origin ); 1071 1072 if ( ( r_jointNameScale.GetFloat() != 0.0f ) && ( bounds.Expand( 128.0f ).ContainsPoint( view->renderView.vieworg - ent->origin ) ) ) { 1073 idVec3 offset( 0, 0, r_jointNameOffset.GetFloat() ); 1074 float scale; 1075 1076 scale = r_jointNameScale.GetFloat(); 1077 joint = ent->joints; 1078 num = ent->numJoints; 1079 for( i = 0; i < num; i++, joint++ ) { 1080 pos = ent->origin + joint->ToVec3() * ent->axis; 1081 common->RW()->DrawText( joints[ i ].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 ); 1082 } 1083 } 1084 } 1085 1086 /* 1087 ==================== 1088 TransformJoints 1089 ==================== 1090 */ 1091 static void TransformJoints( idJointMat *__restrict outJoints, const int numJoints, const idJointMat *__restrict inJoints1, const idJointMat *__restrict inJoints2 ) { 1092 1093 float * outFloats = outJoints->ToFloatPtr(); 1094 const float * inFloats1 = inJoints1->ToFloatPtr(); 1095 const float * inFloats2 = inJoints2->ToFloatPtr(); 1096 1097 assert_16_byte_aligned( outFloats ); 1098 assert_16_byte_aligned( inFloats1 ); 1099 assert_16_byte_aligned( inFloats2 ); 1100 1101 #ifdef ID_WIN_X86_SSE2_INTRIN 1102 1103 const __m128 mask_keep_last = __m128c( _mm_set_epi32( 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 ) ); 1104 1105 for ( int i = 0; i < numJoints; i += 2, inFloats1 += 2 * 12, inFloats2 += 2 * 12, outFloats += 2 * 12 ) { 1106 __m128 m1a0 = _mm_load_ps( inFloats1 + 0 * 12 + 0 ); 1107 __m128 m1b0 = _mm_load_ps( inFloats1 + 0 * 12 + 4 ); 1108 __m128 m1c0 = _mm_load_ps( inFloats1 + 0 * 12 + 8 ); 1109 __m128 m1a1 = _mm_load_ps( inFloats1 + 1 * 12 + 0 ); 1110 __m128 m1b1 = _mm_load_ps( inFloats1 + 1 * 12 + 4 ); 1111 __m128 m1c1 = _mm_load_ps( inFloats1 + 1 * 12 + 8 ); 1112 1113 __m128 m2a0 = _mm_load_ps( inFloats2 + 0 * 12 + 0 ); 1114 __m128 m2b0 = _mm_load_ps( inFloats2 + 0 * 12 + 4 ); 1115 __m128 m2c0 = _mm_load_ps( inFloats2 + 0 * 12 + 8 ); 1116 __m128 m2a1 = _mm_load_ps( inFloats2 + 1 * 12 + 0 ); 1117 __m128 m2b1 = _mm_load_ps( inFloats2 + 1 * 12 + 4 ); 1118 __m128 m2c1 = _mm_load_ps( inFloats2 + 1 * 12 + 8 ); 1119 1120 __m128 tj0 = _mm_and_ps( m1a0, mask_keep_last ); 1121 __m128 tk0 = _mm_and_ps( m1b0, mask_keep_last ); 1122 __m128 tl0 = _mm_and_ps( m1c0, mask_keep_last ); 1123 __m128 tj1 = _mm_and_ps( m1a1, mask_keep_last ); 1124 __m128 tk1 = _mm_and_ps( m1b1, mask_keep_last ); 1125 __m128 tl1 = _mm_and_ps( m1c1, mask_keep_last ); 1126 1127 __m128 ta0 = _mm_splat_ps( m1a0, 0 ); 1128 __m128 td0 = _mm_splat_ps( m1b0, 0 ); 1129 __m128 tg0 = _mm_splat_ps( m1c0, 0 ); 1130 __m128 ta1 = _mm_splat_ps( m1a1, 0 ); 1131 __m128 td1 = _mm_splat_ps( m1b1, 0 ); 1132 __m128 tg1 = _mm_splat_ps( m1c1, 0 ); 1133 1134 __m128 ra0 = _mm_add_ps( tj0, _mm_mul_ps( ta0, m2a0 ) ); 1135 __m128 rd0 = _mm_add_ps( tk0, _mm_mul_ps( td0, m2a0 ) ); 1136 __m128 rg0 = _mm_add_ps( tl0, _mm_mul_ps( tg0, m2a0 ) ); 1137 __m128 ra1 = _mm_add_ps( tj1, _mm_mul_ps( ta1, m2a1 ) ); 1138 __m128 rd1 = _mm_add_ps( tk1, _mm_mul_ps( td1, m2a1 ) ); 1139 __m128 rg1 = _mm_add_ps( tl1, _mm_mul_ps( tg1, m2a1 ) ); 1140 1141 __m128 tb0 = _mm_splat_ps( m1a0, 1 ); 1142 __m128 te0 = _mm_splat_ps( m1b0, 1 ); 1143 __m128 th0 = _mm_splat_ps( m1c0, 1 ); 1144 __m128 tb1 = _mm_splat_ps( m1a1, 1 ); 1145 __m128 te1 = _mm_splat_ps( m1b1, 1 ); 1146 __m128 th1 = _mm_splat_ps( m1c1, 1 ); 1147 1148 __m128 rb0 = _mm_add_ps( ra0, _mm_mul_ps( tb0, m2b0 ) ); 1149 __m128 re0 = _mm_add_ps( rd0, _mm_mul_ps( te0, m2b0 ) ); 1150 __m128 rh0 = _mm_add_ps( rg0, _mm_mul_ps( th0, m2b0 ) ); 1151 __m128 rb1 = _mm_add_ps( ra1, _mm_mul_ps( tb1, m2b1 ) ); 1152 __m128 re1 = _mm_add_ps( rd1, _mm_mul_ps( te1, m2b1 ) ); 1153 __m128 rh1 = _mm_add_ps( rg1, _mm_mul_ps( th1, m2b1 ) ); 1154 1155 __m128 tc0 = _mm_splat_ps( m1a0, 2 ); 1156 __m128 tf0 = _mm_splat_ps( m1b0, 2 ); 1157 __m128 ti0 = _mm_splat_ps( m1c0, 2 ); 1158 __m128 tf1 = _mm_splat_ps( m1b1, 2 ); 1159 __m128 ti1 = _mm_splat_ps( m1c1, 2 ); 1160 __m128 tc1 = _mm_splat_ps( m1a1, 2 ); 1161 1162 __m128 rc0 = _mm_add_ps( rb0, _mm_mul_ps( tc0, m2c0 ) ); 1163 __m128 rf0 = _mm_add_ps( re0, _mm_mul_ps( tf0, m2c0 ) ); 1164 __m128 ri0 = _mm_add_ps( rh0, _mm_mul_ps( ti0, m2c0 ) ); 1165 __m128 rc1 = _mm_add_ps( rb1, _mm_mul_ps( tc1, m2c1 ) ); 1166 __m128 rf1 = _mm_add_ps( re1, _mm_mul_ps( tf1, m2c1 ) ); 1167 __m128 ri1 = _mm_add_ps( rh1, _mm_mul_ps( ti1, m2c1 ) ); 1168 1169 _mm_store_ps( outFloats + 0 * 12 + 0, rc0 ); 1170 _mm_store_ps( outFloats + 0 * 12 + 4, rf0 ); 1171 _mm_store_ps( outFloats + 0 * 12 + 8, ri0 ); 1172 _mm_store_ps( outFloats + 1 * 12 + 0, rc1 ); 1173 _mm_store_ps( outFloats + 1 * 12 + 4, rf1 ); 1174 _mm_store_ps( outFloats + 1 * 12 + 8, ri1 ); 1175 } 1176 1177 #else 1178 1179 for ( int i = 0; i < numJoints; i++ ) { 1180 idJointMat::Multiply( outJoints[i], inJoints1[i], inJoints2[i] ); 1181 } 1182 1183 #endif 1184 } 1185 1186 /* 1187 ==================== 1188 idRenderModelMD5::InstantiateDynamicModel 1189 ==================== 1190 */ 1191 idRenderModel *idRenderModelMD5::InstantiateDynamicModel( const struct renderEntity_s *ent, const viewDef_t *view, idRenderModel *cachedModel ) { 1192 if ( cachedModel != NULL && !r_useCachedDynamicModels.GetBool() ) { 1193 delete cachedModel; 1194 cachedModel = NULL; 1195 } 1196 1197 if ( purged ) { 1198 common->DWarning( "model %s instantiated while purged", Name() ); 1199 LoadModel(); 1200 } 1201 1202 if ( !ent->joints ) { 1203 common->Printf( "idRenderModelMD5::InstantiateDynamicModel: NULL joints on renderEntity for '%s'\n", Name() ); 1204 delete cachedModel; 1205 return NULL; 1206 } else if ( ent->numJoints != joints.Num() ) { 1207 common->Printf( "idRenderModelMD5::InstantiateDynamicModel: renderEntity has different number of joints than model for '%s'\n", Name() ); 1208 delete cachedModel; 1209 return NULL; 1210 } 1211 1212 tr.pc.c_generateMd5++; 1213 1214 idRenderModelStatic * staticModel; 1215 if ( cachedModel != NULL ) { 1216 assert( dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL ); 1217 assert( idStr::Icmp( cachedModel->Name(), MD5_SnapshotName ) == 0 ); 1218 staticModel = static_cast<idRenderModelStatic *>(cachedModel); 1219 } else { 1220 staticModel = new (TAG_MODEL) idRenderModelStatic; 1221 staticModel->InitEmpty( MD5_SnapshotName ); 1222 } 1223 1224 staticModel->bounds.Clear(); 1225 1226 if ( r_showSkel.GetInteger() ) { 1227 if ( ( view != NULL ) && ( !r_skipSuppress.GetBool() || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) ) { 1228 // only draw the skeleton 1229 DrawJoints( ent, view ); 1230 } 1231 1232 if ( r_showSkel.GetInteger() > 1 ) { 1233 // turn off the model when showing the skeleton 1234 staticModel->InitEmpty( MD5_SnapshotName ); 1235 return staticModel; 1236 } 1237 } 1238 1239 // update the GPU joints array 1240 const int numInvertedJoints = SIMD_ROUND_JOINTS( joints.Num() ); 1241 if ( staticModel->jointsInverted == NULL ) { 1242 staticModel->numInvertedJoints = numInvertedJoints; 1243 const int alignment = glConfig.uniformBufferOffsetAlignment; 1244 staticModel->jointsInverted = (idJointMat *)Mem_ClearedAlloc( ALIGN( numInvertedJoints * sizeof( idJointMat ), alignment ), TAG_JOINTMAT ); 1245 staticModel->jointsInvertedBuffer = 0; 1246 } else { 1247 assert( staticModel->numInvertedJoints == numInvertedJoints ); 1248 } 1249 1250 TransformJoints( staticModel->jointsInverted, joints.Num(), ent->joints, invertedDefaultPose.Ptr() ); 1251 1252 // create all the surfaces 1253 idMD5Mesh * mesh = meshes.Ptr(); 1254 for ( int i = 0; i < meshes.Num(); i++, mesh++ ) { 1255 // avoid deforming the surface if it will be a nodraw due to a skin remapping 1256 const idMaterial *shader = mesh->shader; 1257 1258 shader = R_RemapShaderBySkin( shader, ent->customSkin, ent->customShader ); 1259 1260 if ( !shader || ( !shader->IsDrawn() && !shader->SurfaceCastsShadow() ) ) { 1261 staticModel->DeleteSurfaceWithId( i ); 1262 mesh->surfaceNum = -1; 1263 continue; 1264 } 1265 1266 modelSurface_t *surf; 1267 1268 int surfaceNum = 0; 1269 if ( staticModel->FindSurfaceWithId( i, surfaceNum ) ) { 1270 mesh->surfaceNum = surfaceNum; 1271 surf = &staticModel->surfaces[surfaceNum]; 1272 } else { 1273 mesh->surfaceNum = staticModel->NumSurfaces(); 1274 surf = &staticModel->surfaces.Alloc(); 1275 surf->geometry = NULL; 1276 surf->shader = NULL; 1277 surf->id = i; 1278 } 1279 1280 mesh->UpdateSurface( ent, ent->joints, staticModel->jointsInverted, surf ); 1281 assert( surf->geometry != NULL ); // to get around compiler warning 1282 1283 // the deformation of the tangents can be deferred until each surface is added to the view 1284 surf->geometry->staticModelWithJoints = staticModel; 1285 1286 staticModel->bounds.AddBounds( surf->geometry->bounds ); 1287 } 1288 1289 return staticModel; 1290 } 1291 1292 /* 1293 ==================== 1294 idRenderModelMD5::IsDynamicModel 1295 ==================== 1296 */ 1297 dynamicModel_t idRenderModelMD5::IsDynamicModel() const { 1298 return DM_CACHED; 1299 } 1300 1301 /* 1302 ==================== 1303 idRenderModelMD5::NumJoints 1304 ==================== 1305 */ 1306 int idRenderModelMD5::NumJoints() const { 1307 return joints.Num(); 1308 } 1309 1310 /* 1311 ==================== 1312 idRenderModelMD5::GetJoints 1313 ==================== 1314 */ 1315 const idMD5Joint *idRenderModelMD5::GetJoints() const { 1316 return joints.Ptr(); 1317 } 1318 1319 /* 1320 ==================== 1321 idRenderModelMD5::GetDefaultPose 1322 ==================== 1323 */ 1324 const idJointQuat *idRenderModelMD5::GetDefaultPose() const { 1325 return defaultPose.Ptr(); 1326 } 1327 1328 /* 1329 ==================== 1330 idRenderModelMD5::GetJointHandle 1331 ==================== 1332 */ 1333 jointHandle_t idRenderModelMD5::GetJointHandle( const char *name ) const { 1334 const idMD5Joint *joint = joints.Ptr(); 1335 for ( int i = 0; i < joints.Num(); i++, joint++ ) { 1336 if ( idStr::Icmp( joint->name.c_str(), name ) == 0 ) { 1337 return ( jointHandle_t )i; 1338 } 1339 } 1340 1341 return INVALID_JOINT; 1342 } 1343 1344 /* 1345 ===================== 1346 idRenderModelMD5::GetJointName 1347 ===================== 1348 */ 1349 const char *idRenderModelMD5::GetJointName( jointHandle_t handle ) const { 1350 if ( ( handle < 0 ) || ( handle >= joints.Num() ) ) { 1351 return "<invalid joint>"; 1352 } 1353 1354 return joints[ handle ].name; 1355 } 1356 1357 /* 1358 ==================== 1359 idRenderModelMD5::NearestJoint 1360 ==================== 1361 */ 1362 int idRenderModelMD5::NearestJoint( int surfaceNum, int a, int b, int c ) const { 1363 if ( surfaceNum > meshes.Num() ) { 1364 common->Error( "idRenderModelMD5::NearestJoint: surfaceNum > meshes.Num()" ); 1365 } 1366 1367 const idMD5Mesh *mesh = meshes.Ptr(); 1368 for ( int i = 0; i < meshes.Num(); i++, mesh++ ) { 1369 if ( mesh->surfaceNum == surfaceNum ) { 1370 return mesh->NearestJoint( a, b, c ); 1371 } 1372 } 1373 return 0; 1374 } 1375 1376 /* 1377 ==================== 1378 idRenderModelMD5::TouchData 1379 1380 models that are already loaded at level start time 1381 will still touch their materials to make sure they 1382 are kept loaded 1383 ==================== 1384 */ 1385 void idRenderModelMD5::TouchData() { 1386 for ( int i = 0; i < meshes.Num(); i++ ) { 1387 declManager->FindMaterial( meshes[i].shader->GetName() ); 1388 } 1389 } 1390 1391 /* 1392 =================== 1393 idRenderModelMD5::PurgeModel 1394 1395 frees all the data, but leaves the class around for dangling references, 1396 which can regenerate the data with LoadModel() 1397 =================== 1398 */ 1399 void idRenderModelMD5::PurgeModel() { 1400 purged = true; 1401 joints.Clear(); 1402 defaultPose.Clear(); 1403 meshes.Clear(); 1404 } 1405 1406 /* 1407 =================== 1408 idRenderModelMD5::Memory 1409 =================== 1410 */ 1411 int idRenderModelMD5::Memory() const { 1412 int total = sizeof( *this ); 1413 total += joints.MemoryUsed() + defaultPose.MemoryUsed() + meshes.MemoryUsed(); 1414 1415 // count up strings 1416 for ( int i = 0; i < joints.Num(); i++ ) { 1417 total += joints[i].name.DynamicMemoryUsed(); 1418 } 1419 1420 // count up meshes 1421 for ( int i = 0; i < meshes.Num(); i++ ) { 1422 const idMD5Mesh *mesh = &meshes[i]; 1423 1424 total += mesh->numMeshJoints * sizeof( mesh->meshJoints[0] ); 1425 1426 // sum up deform info 1427 total += sizeof( mesh->deformInfo ); 1428 total += R_DeformInfoMemoryUsed( mesh->deformInfo ); 1429 } 1430 return total; 1431 }