Model.cpp (69806B)
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 33 #include "tr_local.h" 34 #include "Model_local.h" 35 #include "Model_ase.h" 36 #include "Model_lwo.h" 37 #include "Model_ma.h" 38 39 idCVar idRenderModelStatic::r_mergeModelSurfaces( "r_mergeModelSurfaces", "1", CVAR_BOOL|CVAR_RENDERER, "combine model surfaces with the same material" ); 40 idCVar idRenderModelStatic::r_slopVertex( "r_slopVertex", "0.01", CVAR_RENDERER, "merge xyz coordinates this far apart" ); 41 idCVar idRenderModelStatic::r_slopTexCoord( "r_slopTexCoord", "0.001", CVAR_RENDERER, "merge texture coordinates this far apart" ); 42 idCVar idRenderModelStatic::r_slopNormal( "r_slopNormal", "0.02", CVAR_RENDERER, "merge normals that dot less than this" ); 43 44 static const byte BRM_VERSION = 108; 45 static const unsigned int BRM_MAGIC = ( 'B' << 24 ) | ( 'R' << 16 ) | ( 'M' << 8 ) | BRM_VERSION; 46 47 /* 48 ================ 49 idRenderModelStatic::idRenderModelStatic 50 ================ 51 */ 52 idRenderModelStatic::idRenderModelStatic() { 53 name = "<undefined>"; 54 bounds.Clear(); 55 lastModifiedFrame = 0; 56 lastArchivedFrame = 0; 57 overlaysAdded = 0; 58 isStaticWorldModel = false; 59 defaulted = false; 60 purged = false; 61 fastLoad = false; 62 reloadable = true; 63 levelLoadReferenced = false; 64 hasDrawingSurfaces = true; 65 hasInteractingSurfaces = true; 66 hasShadowCastingSurfaces = true; 67 timeStamp = 0; 68 numInvertedJoints = 0; 69 jointsInverted = NULL; 70 jointsInvertedBuffer = 0; 71 } 72 73 /* 74 ================ 75 idRenderModelStatic::~idRenderModelStatic 76 ================ 77 */ 78 idRenderModelStatic::~idRenderModelStatic() { 79 PurgeModel(); 80 } 81 82 /* 83 ============== 84 idRenderModelStatic::Print 85 ============== 86 */ 87 void idRenderModelStatic::Print() const { 88 common->Printf( "%s\n", name.c_str() ); 89 common->Printf( "Static model.\n" ); 90 common->Printf( "bounds: (%f %f %f) to (%f %f %f)\n", 91 bounds[0][0], bounds[0][1], bounds[0][2], 92 bounds[1][0], bounds[1][1], bounds[1][2] ); 93 94 common->Printf( " verts tris material\n" ); 95 for ( int i = 0; i < NumSurfaces(); i++ ) { 96 const modelSurface_t *surf = Surface( i ); 97 98 srfTriangles_t *tri = surf->geometry; 99 const idMaterial *material = surf->shader; 100 101 if ( !tri ) { 102 common->Printf( "%2i: %s, NULL surface geometry\n", i, material->GetName() ); 103 continue; 104 } 105 106 common->Printf( "%2i: %5i %5i %s", i, tri->numVerts, tri->numIndexes / 3, material->GetName() ); 107 if ( tri->generateNormals ) { 108 common->Printf( " (smoothed)\n" ); 109 } else { 110 common->Printf( "\n" ); 111 } 112 } 113 } 114 115 /* 116 ============== 117 idRenderModelStatic::Memory 118 ============== 119 */ 120 int idRenderModelStatic::Memory() const { 121 int totalBytes = 0; 122 123 totalBytes += sizeof( *this ); 124 totalBytes += name.DynamicMemoryUsed(); 125 totalBytes += surfaces.MemoryUsed(); 126 127 for ( int j = 0; j < NumSurfaces(); j++ ) { 128 const modelSurface_t *surf = Surface( j ); 129 if ( !surf->geometry ) { 130 continue; 131 } 132 totalBytes += R_TriSurfMemory( surf->geometry ); 133 } 134 135 return totalBytes; 136 } 137 138 /* 139 ============== 140 idRenderModelStatic::List 141 ============== 142 */ 143 void idRenderModelStatic::List() const { 144 int totalTris = 0; 145 int totalVerts = 0; 146 int totalBytes = 0; 147 148 totalBytes = Memory(); 149 150 char closed = 'C'; 151 for ( int j = 0; j < NumSurfaces(); j++ ) { 152 const modelSurface_t *surf = Surface( j ); 153 if ( !surf->geometry ) { 154 continue; 155 } 156 if ( !surf->geometry->perfectHull ) { 157 closed = ' '; 158 } 159 totalTris += surf->geometry->numIndexes / 3; 160 totalVerts += surf->geometry->numVerts; 161 } 162 common->Printf( "%c%4ik %3i %4i %4i %s", closed, totalBytes/1024, NumSurfaces(), totalVerts, totalTris, Name() ); 163 164 if ( IsDynamicModel() == DM_CACHED ) { 165 common->Printf( " (DM_CACHED)" ); 166 } 167 if ( IsDynamicModel() == DM_CONTINUOUS ) { 168 common->Printf( " (DM_CONTINUOUS)" ); 169 } 170 if ( defaulted ) { 171 common->Printf( " (DEFAULTED)" ); 172 } 173 if ( bounds[0][0] >= bounds[1][0] ) { 174 common->Printf( " (EMPTY BOUNDS)" ); 175 } 176 if ( bounds[1][0] - bounds[0][0] > 100000 ) { 177 common->Printf( " (HUGE BOUNDS)" ); 178 } 179 180 common->Printf( "\n" ); 181 } 182 183 /* 184 ================ 185 idRenderModelStatic::IsDefaultModel 186 ================ 187 */ 188 bool idRenderModelStatic::IsDefaultModel() const { 189 return defaulted; 190 } 191 192 /* 193 ================ 194 AddCubeFace 195 ================ 196 */ 197 static void AddCubeFace( srfTriangles_t *tri, idVec3 v1, idVec3 v2, idVec3 v3, idVec3 v4 ) { 198 tri->verts[tri->numVerts+0].Clear(); 199 tri->verts[tri->numVerts+0].xyz = v1 * 8; 200 tri->verts[tri->numVerts+0].SetTexCoord( 0, 0 ); 201 202 tri->verts[tri->numVerts+1].Clear(); 203 tri->verts[tri->numVerts+1].xyz = v2 * 8; 204 tri->verts[tri->numVerts+1].SetTexCoord( 1, 0 ); 205 206 tri->verts[tri->numVerts+2].Clear(); 207 tri->verts[tri->numVerts+2].xyz = v3 * 8; 208 tri->verts[tri->numVerts+2].SetTexCoord( 1, 1 ); 209 210 tri->verts[tri->numVerts+3].Clear(); 211 tri->verts[tri->numVerts+3].xyz = v4 * 8; 212 tri->verts[tri->numVerts+3].SetTexCoord( 0, 1 ); 213 214 tri->indexes[tri->numIndexes+0] = tri->numVerts + 0; 215 tri->indexes[tri->numIndexes+1] = tri->numVerts + 1; 216 tri->indexes[tri->numIndexes+2] = tri->numVerts + 2; 217 tri->indexes[tri->numIndexes+3] = tri->numVerts + 0; 218 tri->indexes[tri->numIndexes+4] = tri->numVerts + 2; 219 tri->indexes[tri->numIndexes+5] = tri->numVerts + 3; 220 221 tri->numVerts += 4; 222 tri->numIndexes += 6; 223 } 224 225 /* 226 ================ 227 idRenderModelStatic::MakeDefaultModel 228 ================ 229 */ 230 void idRenderModelStatic::MakeDefaultModel() { 231 232 defaulted = true; 233 234 // throw out any surfaces we already have 235 PurgeModel(); 236 237 // create one new surface 238 modelSurface_t surf; 239 240 srfTriangles_t *tri = R_AllocStaticTriSurf(); 241 242 surf.shader = tr.defaultMaterial; 243 surf.geometry = tri; 244 245 R_AllocStaticTriSurfVerts( tri, 24 ); 246 R_AllocStaticTriSurfIndexes( tri, 36 ); 247 248 AddCubeFace( tri, idVec3(-1, 1, 1), idVec3(1, 1, 1), idVec3(1, -1, 1), idVec3(-1, -1, 1) ); 249 AddCubeFace( tri, idVec3(-1, 1, -1), idVec3(-1, -1, -1), idVec3(1, -1, -1), idVec3(1, 1, -1) ); 250 251 AddCubeFace( tri, idVec3(1, -1, 1), idVec3(1, 1, 1), idVec3(1, 1, -1), idVec3(1, -1, -1) ); 252 AddCubeFace( tri, idVec3(-1, -1, 1), idVec3(-1, -1, -1), idVec3(-1, 1, -1), idVec3(-1, 1, 1) ); 253 254 AddCubeFace( tri, idVec3(-1, -1, 1), idVec3(1, -1, 1), idVec3(1, -1, -1), idVec3(-1, -1, -1) ); 255 AddCubeFace( tri, idVec3(-1, 1, 1), idVec3(-1, 1, -1), idVec3(1, 1, -1), idVec3(1, 1, 1) ); 256 257 tri->generateNormals = true; 258 259 AddSurface( surf ); 260 FinishSurfaces(); 261 } 262 263 /* 264 ================ 265 idRenderModelStatic::PartialInitFromFile 266 ================ 267 */ 268 void idRenderModelStatic::PartialInitFromFile( const char *fileName ) { 269 fastLoad = true; 270 InitFromFile( fileName ); 271 } 272 273 /* 274 ================ 275 idRenderModelStatic::InitFromFile 276 ================ 277 */ 278 void idRenderModelStatic::InitFromFile( const char *fileName ) { 279 bool loaded; 280 idStr extension; 281 282 InitEmpty( fileName ); 283 284 // FIXME: load new .proc map format 285 286 name.ExtractFileExtension( extension ); 287 288 if ( extension.Icmp( "ase" ) == 0 ) { 289 loaded = LoadASE( name ); 290 reloadable = true; 291 } else if ( extension.Icmp( "lwo" ) == 0 ) { 292 loaded = LoadLWO( name ); 293 reloadable = true; 294 } else if ( extension.Icmp( "ma" ) == 0 ) { 295 loaded = LoadMA( name ); 296 reloadable = true; 297 } else { 298 common->Warning( "idRenderModelStatic::InitFromFile: unknown type for model: \'%s\'", name.c_str() ); 299 loaded = false; 300 } 301 302 if ( !loaded ) { 303 common->Warning( "Couldn't load model: '%s'", name.c_str() ); 304 MakeDefaultModel(); 305 return; 306 } 307 308 // it is now available for use 309 purged = false; 310 311 // create the bounds for culling and dynamic surface creation 312 FinishSurfaces(); 313 } 314 315 /* 316 ======================== 317 idRenderModelStatic::LoadBinaryModel 318 ======================== 319 */ 320 bool idRenderModelStatic::LoadBinaryModel( idFile * file, const ID_TIME_T sourceTimeStamp ) { 321 if ( file == NULL ) { 322 return false; 323 } 324 325 unsigned int magic = 0; 326 file->ReadBig( magic ); 327 if ( magic != BRM_MAGIC ) { 328 return false; 329 } 330 331 file->ReadBig( timeStamp ); 332 333 if ( !fileSystem->InProductionMode() && sourceTimeStamp != timeStamp ) { 334 return false; 335 } 336 337 common->UpdateLevelLoadPacifier(); 338 339 int numSurfaces; 340 file->ReadBig( numSurfaces ); 341 surfaces.SetNum( numSurfaces ); 342 for ( int i = 0; i < surfaces.Num(); i++ ) { 343 file->ReadBig( surfaces[i].id ); 344 idStr materialName; 345 file->ReadString( materialName ); 346 if ( materialName.IsEmpty() ) { 347 surfaces[i].shader = NULL; 348 } else { 349 surfaces[i].shader = declManager->FindMaterial( materialName ); 350 } 351 352 bool isGeometry; 353 file->ReadBig( isGeometry ); 354 surfaces[i].geometry = NULL; 355 if ( isGeometry ) { 356 bool temp; 357 358 surfaces[i].geometry = R_AllocStaticTriSurf(); 359 360 // Read the contents of srfTriangles_t 361 srfTriangles_t & tri = *surfaces[i].geometry; 362 363 file->ReadVec3( tri.bounds[0] ); 364 file->ReadVec3( tri.bounds[1] ); 365 366 int ambientViewCount = 0; // FIXME: remove 367 file->ReadBig( ambientViewCount ); 368 file->ReadBig( tri.generateNormals ); 369 file->ReadBig( tri.tangentsCalculated ); 370 file->ReadBig( tri.perfectHull ); 371 file->ReadBig( tri.referencedIndexes ); 372 373 file->ReadBig( tri.numVerts ); 374 tri.verts = NULL; 375 int numInFile = 0; 376 file->ReadBig( numInFile ); 377 if ( numInFile > 0 ) { 378 R_AllocStaticTriSurfVerts( &tri, tri.numVerts ); 379 assert( tri.verts != NULL ); 380 for ( int j = 0; j < tri.numVerts; j++ ) { 381 file->ReadVec3( tri.verts[j].xyz ); 382 file->ReadBigArray( tri.verts[j].st, 2 ); 383 file->ReadBigArray( tri.verts[j].normal, 4 ); 384 file->ReadBigArray( tri.verts[j].tangent, 4 ); 385 file->ReadBigArray( tri.verts[j].color, sizeof( tri.verts[j].color ) / sizeof( tri.verts[j].color[0] ) ); 386 file->ReadBigArray( tri.verts[j].color2, sizeof( tri.verts[j].color2 ) / sizeof( tri.verts[j].color2[0] ) ); 387 } 388 } 389 390 file->ReadBig( numInFile ); 391 if ( numInFile == 0 ) { 392 tri.preLightShadowVertexes = NULL; 393 } else { 394 R_AllocStaticTriSurfPreLightShadowVerts( &tri, numInFile ); 395 for ( int j = 0; j < numInFile; j++ ) { 396 file->ReadVec4( tri.preLightShadowVertexes[ j ].xyzw ); 397 } 398 } 399 400 file->ReadBig( tri.numIndexes ); 401 tri.indexes = NULL; 402 tri.silIndexes = NULL; 403 if ( tri.numIndexes > 0 ) { 404 R_AllocStaticTriSurfIndexes( &tri, tri.numIndexes ); 405 file->ReadBigArray( tri.indexes, tri.numIndexes ); 406 } 407 file->ReadBig( numInFile ); 408 if ( numInFile > 0 ) { 409 R_AllocStaticTriSurfSilIndexes( &tri, tri.numIndexes ); 410 file->ReadBigArray( tri.silIndexes, tri.numIndexes ); 411 } 412 413 file->ReadBig( tri.numMirroredVerts ); 414 tri.mirroredVerts = NULL; 415 if ( tri.numMirroredVerts > 0 ) { 416 R_AllocStaticTriSurfMirroredVerts( &tri, tri.numMirroredVerts ); 417 file->ReadBigArray( tri.mirroredVerts, tri.numMirroredVerts ); 418 } 419 420 file->ReadBig( tri.numDupVerts ); 421 tri.dupVerts = NULL; 422 if ( tri.numDupVerts > 0 ) { 423 R_AllocStaticTriSurfDupVerts( &tri, tri.numDupVerts ); 424 file->ReadBigArray( tri.dupVerts, tri.numDupVerts * 2 ); 425 } 426 427 file->ReadBig( tri.numSilEdges ); 428 tri.silEdges = NULL; 429 if ( tri.numSilEdges > 0 ) { 430 R_AllocStaticTriSurfSilEdges( &tri, tri.numSilEdges ); 431 assert( tri.silEdges != NULL ); 432 for ( int j = 0; j < tri.numSilEdges; j++ ) { 433 file->ReadBig( tri.silEdges[j].p1 ); 434 file->ReadBig( tri.silEdges[j].p2 ); 435 file->ReadBig( tri.silEdges[j].v1 ); 436 file->ReadBig( tri.silEdges[j].v2 ); 437 } 438 } 439 440 file->ReadBig( temp ); 441 tri.dominantTris = NULL; 442 if ( temp ) { 443 R_AllocStaticTriSurfDominantTris( &tri, tri.numVerts ); 444 assert( tri.dominantTris != NULL ); 445 for ( int j = 0; j < tri.numVerts; j++ ) { 446 file->ReadBig( tri.dominantTris[j].v2 ); 447 file->ReadBig( tri.dominantTris[j].v3 ); 448 file->ReadFloat( tri.dominantTris[j].normalizationScale[0] ); 449 file->ReadFloat( tri.dominantTris[j].normalizationScale[1] ); 450 file->ReadFloat( tri.dominantTris[j].normalizationScale[2] ); 451 } 452 } 453 454 file->ReadBig( tri.numShadowIndexesNoFrontCaps ); 455 file->ReadBig( tri.numShadowIndexesNoCaps ); 456 file->ReadBig( tri.shadowCapPlaneBits ); 457 458 tri.ambientSurface = NULL; 459 tri.nextDeferredFree = NULL; 460 tri.indexCache = 0; 461 tri.ambientCache = 0; 462 tri.shadowCache = 0; 463 } 464 } 465 466 file->ReadVec3( bounds[0] ); 467 file->ReadVec3( bounds[1] ); 468 469 file->ReadBig( overlaysAdded ); 470 file->ReadBig( lastModifiedFrame ); 471 file->ReadBig( lastArchivedFrame ); 472 file->ReadString( name ); 473 file->ReadBig( isStaticWorldModel ); 474 file->ReadBig( defaulted ); 475 file->ReadBig( purged ); 476 file->ReadBig( fastLoad ); 477 file->ReadBig( reloadable ); 478 file->ReadBig( levelLoadReferenced ); // should this actually be saved/loaded? 479 file->ReadBig( hasDrawingSurfaces ); 480 file->ReadBig( hasInteractingSurfaces ); 481 file->ReadBig( hasShadowCastingSurfaces ); 482 483 return true; 484 } 485 486 /* 487 ======================== 488 idRenderModelStatic::WriteBinaryModel 489 ======================== 490 */ 491 void idRenderModelStatic::WriteBinaryModel( idFile * file, ID_TIME_T *_timeStamp ) const { 492 if ( file == NULL ) { 493 common->Printf( "Failed to WriteBinaryModel\n" ); 494 return; 495 } 496 497 file->WriteBig( BRM_MAGIC ); 498 499 if ( _timeStamp != NULL ) { 500 file->WriteBig( *_timeStamp ); 501 } else { 502 file->WriteBig( timeStamp ); 503 } 504 505 file->WriteBig( surfaces.Num() ); 506 for ( int i = 0; i < surfaces.Num(); i++ ) { 507 file->WriteBig( surfaces[i].id ); 508 if ( surfaces[i].shader != NULL && surfaces[i].shader->GetName() != NULL ) { 509 file->WriteString( surfaces[i].shader->GetName() ); 510 } else { 511 file->WriteString( "" ); 512 } 513 514 file->WriteBig( surfaces[i].geometry != NULL ); 515 if ( surfaces[i].geometry != NULL ) { 516 srfTriangles_t & tri = *surfaces[i].geometry; 517 518 file->WriteVec3( tri.bounds[0] ); 519 file->WriteVec3( tri.bounds[1] ); 520 521 int ambientViewCount = 0; // FIXME: remove 522 file->WriteBig( ambientViewCount ); 523 file->WriteBig( tri.generateNormals ); 524 file->WriteBig( tri.tangentsCalculated ); 525 file->WriteBig( tri.perfectHull ); 526 file->WriteBig( tri.referencedIndexes ); 527 528 // shadow models use numVerts but have no verts 529 file->WriteBig( tri.numVerts ); 530 if ( tri.verts != NULL ) { 531 file->WriteBig( tri.numVerts ); 532 } else { 533 file->WriteBig( ( int ) 0 ); 534 } 535 536 if ( tri.numVerts > 0 && tri.verts != NULL ) { 537 for ( int j = 0; j < tri.numVerts; j++ ) { 538 file->WriteVec3( tri.verts[j].xyz ); 539 file->WriteBigArray( tri.verts[j].st, 2 ); 540 file->WriteBigArray( tri.verts[j].normal, 4 ); 541 file->WriteBigArray( tri.verts[j].tangent, 4 ); 542 file->WriteBigArray( tri.verts[j].color, sizeof( tri.verts[j].color ) / sizeof( tri.verts[j].color[0] ) ); 543 file->WriteBigArray( tri.verts[j].color2, sizeof( tri.verts[j].color2 ) / sizeof( tri.verts[j].color2[0] ) ); 544 } 545 } 546 547 if ( tri.preLightShadowVertexes != NULL ) { 548 file->WriteBig( tri.numVerts * 2 ); 549 for ( int j = 0; j < tri.numVerts * 2; j++ ) { 550 file->WriteVec4( tri.preLightShadowVertexes[ j ].xyzw ); 551 } 552 } else { 553 file->WriteBig( ( int ) 0 ); 554 } 555 556 file->WriteBig( tri.numIndexes ); 557 558 if ( tri.numIndexes > 0 ) { 559 file->WriteBigArray( tri.indexes, tri.numIndexes ); 560 } 561 562 if ( tri.silIndexes != NULL ) { 563 file->WriteBig( tri.numIndexes ); 564 } else { 565 file->WriteBig( ( int ) 0 ); 566 } 567 568 if ( tri.numIndexes > 0 && tri.silIndexes != NULL ) { 569 file->WriteBigArray( tri.silIndexes, tri.numIndexes ); 570 } 571 572 file->WriteBig( tri.numMirroredVerts ); 573 if ( tri.numMirroredVerts > 0 ) { 574 file->WriteBigArray( tri.mirroredVerts, tri.numMirroredVerts ); 575 } 576 577 file->WriteBig( tri.numDupVerts ); 578 if ( tri.numDupVerts > 0 ) { 579 file->WriteBigArray( tri.dupVerts, tri.numDupVerts * 2 ); 580 } 581 582 file->WriteBig( tri.numSilEdges ); 583 if ( tri.numSilEdges > 0 ) { 584 for ( int j = 0; j < tri.numSilEdges; j++ ) { 585 file->WriteBig( tri.silEdges[j].p1 ); 586 file->WriteBig( tri.silEdges[j].p2 ); 587 file->WriteBig( tri.silEdges[j].v1 ); 588 file->WriteBig( tri.silEdges[j].v2 ); 589 } 590 } 591 592 file->WriteBig( tri.dominantTris != NULL ); 593 if ( tri.dominantTris != NULL ) { 594 for ( int j = 0; j < tri.numVerts; j++ ) { 595 file->WriteBig( tri.dominantTris[j].v2 ); 596 file->WriteBig( tri.dominantTris[j].v3 ); 597 file->WriteFloat( tri.dominantTris[j].normalizationScale[0] ); 598 file->WriteFloat( tri.dominantTris[j].normalizationScale[1] ); 599 file->WriteFloat( tri.dominantTris[j].normalizationScale[2] ); 600 } 601 } 602 603 file->WriteBig( tri.numShadowIndexesNoFrontCaps ); 604 file->WriteBig( tri.numShadowIndexesNoCaps ); 605 file->WriteBig( tri.shadowCapPlaneBits ); 606 } 607 } 608 609 file->WriteVec3( bounds[0] ); 610 file->WriteVec3( bounds[1] ); 611 file->WriteBig( overlaysAdded ); 612 file->WriteBig( lastModifiedFrame ); 613 file->WriteBig( lastArchivedFrame ); 614 file->WriteString( name ); 615 616 // shadowHull 617 618 file->WriteBig( isStaticWorldModel ); 619 file->WriteBig( defaulted ); 620 file->WriteBig( purged ); 621 file->WriteBig( fastLoad ); 622 file->WriteBig( reloadable ); 623 file->WriteBig( levelLoadReferenced ); 624 file->WriteBig( hasDrawingSurfaces ); 625 file->WriteBig( hasInteractingSurfaces ); 626 file->WriteBig( hasShadowCastingSurfaces ); 627 } 628 629 /* 630 ================ 631 idRenderModelStatic::LoadModel 632 ================ 633 */ 634 void idRenderModelStatic::LoadModel() { 635 PurgeModel(); 636 InitFromFile( name ); 637 } 638 639 /* 640 ================ 641 idRenderModelStatic::InitEmpty 642 ================ 643 */ 644 void idRenderModelStatic::InitEmpty( const char *fileName ) { 645 // model names of the form _area* are static parts of the 646 // world, and have already been considered for optimized shadows 647 // other model names are inline entity models, and need to be 648 // shadowed normally 649 if ( !idStr::Cmpn( fileName, "_area", 5 ) ) { 650 isStaticWorldModel = true; 651 } else { 652 isStaticWorldModel = false; 653 } 654 655 name = fileName; 656 reloadable = false; // if it didn't come from a file, we can't reload it 657 PurgeModel(); 658 purged = false; 659 bounds.Zero(); 660 } 661 662 /* 663 ================ 664 idRenderModelStatic::AddSurface 665 ================ 666 */ 667 void idRenderModelStatic::AddSurface( modelSurface_t surface ) { 668 surfaces.Append( surface ); 669 if ( surface.geometry ) { 670 bounds += surface.geometry->bounds; 671 } 672 } 673 674 /* 675 ================ 676 idRenderModelStatic::Name 677 ================ 678 */ 679 const char *idRenderModelStatic::Name() const { 680 return name; 681 } 682 683 /* 684 ================ 685 idRenderModelStatic::Timestamp 686 ================ 687 */ 688 ID_TIME_T idRenderModelStatic::Timestamp() const { 689 return timeStamp; 690 } 691 692 /* 693 ================ 694 idRenderModelStatic::NumSurfaces 695 ================ 696 */ 697 int idRenderModelStatic::NumSurfaces() const { 698 return surfaces.Num(); 699 } 700 701 /* 702 ================ 703 idRenderModelStatic::NumBaseSurfaces 704 ================ 705 */ 706 int idRenderModelStatic::NumBaseSurfaces() const { 707 return surfaces.Num() - overlaysAdded; 708 } 709 710 /* 711 ================ 712 idRenderModelStatic::Surface 713 ================ 714 */ 715 const modelSurface_t *idRenderModelStatic::Surface( int surfaceNum ) const { 716 return &surfaces[surfaceNum]; 717 } 718 719 /* 720 ================ 721 idRenderModelStatic::AllocSurfaceTriangles 722 ================ 723 */ 724 srfTriangles_t *idRenderModelStatic::AllocSurfaceTriangles( int numVerts, int numIndexes ) const { 725 srfTriangles_t *tri = R_AllocStaticTriSurf(); 726 R_AllocStaticTriSurfVerts( tri, numVerts ); 727 R_AllocStaticTriSurfIndexes( tri, numIndexes ); 728 return tri; 729 } 730 731 /* 732 ================ 733 idRenderModelStatic::FreeSurfaceTriangles 734 ================ 735 */ 736 void idRenderModelStatic::FreeSurfaceTriangles( srfTriangles_t *tris ) const { 737 R_FreeStaticTriSurf( tris ); 738 } 739 740 /* 741 ================ 742 idRenderModelStatic::IsStaticWorldModel 743 ================ 744 */ 745 bool idRenderModelStatic::IsStaticWorldModel() const { 746 return isStaticWorldModel; 747 } 748 749 /* 750 ================ 751 idRenderModelStatic::IsDynamicModel 752 ================ 753 */ 754 dynamicModel_t idRenderModelStatic::IsDynamicModel() const { 755 // dynamic subclasses will override this 756 return DM_STATIC; 757 } 758 759 /* 760 ================ 761 idRenderModelStatic::IsReloadable 762 ================ 763 */ 764 bool idRenderModelStatic::IsReloadable() const { 765 return reloadable; 766 } 767 768 /* 769 ================ 770 idRenderModelStatic::Bounds 771 ================ 772 */ 773 idBounds idRenderModelStatic::Bounds( const struct renderEntity_s *mdef ) const { 774 return bounds; 775 } 776 777 /* 778 ================ 779 idRenderModelStatic::DepthHack 780 ================ 781 */ 782 float idRenderModelStatic::DepthHack() const { 783 return 0.0f; 784 } 785 786 /* 787 ================ 788 idRenderModelStatic::InstantiateDynamicModel 789 ================ 790 */ 791 idRenderModel *idRenderModelStatic::InstantiateDynamicModel( const struct renderEntity_s *ent, const viewDef_t *view, idRenderModel *cachedModel ) { 792 if ( cachedModel ) { 793 delete cachedModel; 794 cachedModel = NULL; 795 } 796 common->Error( "InstantiateDynamicModel called on static model '%s'", name.c_str() ); 797 return NULL; 798 } 799 800 /* 801 ================ 802 idRenderModelStatic::NumJoints 803 ================ 804 */ 805 int idRenderModelStatic::NumJoints() const { 806 return 0; 807 } 808 809 /* 810 ================ 811 idRenderModelStatic::GetJoints 812 ================ 813 */ 814 const idMD5Joint *idRenderModelStatic::GetJoints() const { 815 return NULL; 816 } 817 818 /* 819 ================ 820 idRenderModelStatic::GetJointHandle 821 ================ 822 */ 823 jointHandle_t idRenderModelStatic::GetJointHandle( const char *name ) const { 824 return INVALID_JOINT; 825 } 826 827 /* 828 ================ 829 idRenderModelStatic::GetJointName 830 ================ 831 */ 832 const char * idRenderModelStatic::GetJointName( jointHandle_t handle ) const { 833 return ""; 834 } 835 836 /* 837 ================ 838 idRenderModelStatic::GetDefaultPose 839 ================ 840 */ 841 const idJointQuat *idRenderModelStatic::GetDefaultPose() const { 842 return NULL; 843 } 844 845 /* 846 ================ 847 idRenderModelStatic::NearestJoint 848 ================ 849 */ 850 int idRenderModelStatic::NearestJoint( int surfaceNum, int a, int b, int c ) const { 851 return INVALID_JOINT; 852 } 853 854 855 //===================================================================== 856 857 858 /* 859 ================ 860 idRenderModelStatic::FinishSurfaces 861 862 The mergeShadows option allows surfaces with different textures to share 863 silhouette edges for shadow calculation, instead of leaving shared edges 864 hanging. 865 866 If any of the original shaders have the noSelfShadow flag set, the surfaces 867 can't be merged, because they will need to be drawn in different order. 868 869 If there is only one surface, a separate merged surface won't be generated. 870 871 A model with multiple surfaces can't later have a skinned shader change the 872 state of the noSelfShadow flag. 873 874 ----------------- 875 876 Creates mirrored copies of two sided surfaces with normal maps, which would 877 otherwise light funny. 878 879 Extends the bounds of deformed surfaces so they don't cull incorrectly at screen edges. 880 881 ================ 882 */ 883 void idRenderModelStatic::FinishSurfaces() { 884 int i; 885 int totalVerts, totalIndexes; 886 887 hasDrawingSurfaces = false; 888 hasInteractingSurfaces = false; 889 hasShadowCastingSurfaces = false; 890 purged = false; 891 892 // make sure we don't have a huge bounds even if we don't finish everything 893 bounds.Zero(); 894 895 896 if ( surfaces.Num() == 0 ) { 897 return; 898 } 899 900 // renderBump doesn't care about most of this 901 if ( fastLoad ) { 902 bounds.Zero(); 903 for ( i = 0; i < surfaces.Num(); i++ ) { 904 const modelSurface_t *surf = &surfaces[i]; 905 906 R_BoundTriSurf( surf->geometry ); 907 bounds.AddBounds( surf->geometry->bounds ); 908 } 909 910 return; 911 } 912 913 // cleanup all the final surfaces, but don't create sil edges 914 totalVerts = 0; 915 totalIndexes = 0; 916 917 // decide if we are going to merge all the surfaces into one shadower 918 int numOriginalSurfaces = surfaces.Num(); 919 920 // make sure there aren't any NULL shaders or geometry 921 for ( i = 0; i < numOriginalSurfaces; i++ ) { 922 const modelSurface_t *surf = &surfaces[i]; 923 924 if ( surf->geometry == NULL || surf->shader == NULL ) { 925 MakeDefaultModel(); 926 common->Error( "Model %s, surface %i had NULL geometry", name.c_str(), i ); 927 } 928 if ( surf->shader == NULL ) { 929 MakeDefaultModel(); 930 common->Error( "Model %s, surface %i had NULL shader", name.c_str(), i ); 931 } 932 } 933 934 // duplicate and reverse triangles for two sided bump mapped surfaces 935 // note that this won't catch surfaces that have their shaders dynamically 936 // changed, and won't work with animated models. 937 // It is better to create completely separate surfaces, rather than 938 // add vertexes and indexes to the existing surface, because the 939 // tangent generation wouldn't like the acute shared edges 940 for ( i = 0; i < numOriginalSurfaces; i++ ) { 941 const modelSurface_t *surf = &surfaces[i]; 942 943 if ( surf->shader->ShouldCreateBackSides() ) { 944 srfTriangles_t *newTri; 945 946 newTri = R_CopyStaticTriSurf( surf->geometry ); 947 R_ReverseTriangles( newTri ); 948 949 modelSurface_t newSurf; 950 951 newSurf.shader = surf->shader; 952 newSurf.geometry = newTri; 953 954 AddSurface( newSurf ); 955 } 956 } 957 958 // clean the surfaces 959 for ( i = 0; i < surfaces.Num(); i++ ) { 960 const modelSurface_t *surf = &surfaces[i]; 961 962 R_CleanupTriangles( surf->geometry, surf->geometry->generateNormals, true, surf->shader->UseUnsmoothedTangents() ); 963 if ( surf->shader->SurfaceCastsShadow() ) { 964 totalVerts += surf->geometry->numVerts; 965 totalIndexes += surf->geometry->numIndexes; 966 } 967 } 968 969 // add up the total surface area for development information 970 for ( i = 0; i < surfaces.Num(); i++ ) { 971 const modelSurface_t *surf = &surfaces[i]; 972 srfTriangles_t *tri = surf->geometry; 973 974 for ( int j = 0; j < tri->numIndexes; j += 3 ) { 975 float area = idWinding::TriangleArea( tri->verts[tri->indexes[j]].xyz, 976 tri->verts[tri->indexes[j+1]].xyz, tri->verts[tri->indexes[j+2]].xyz ); 977 const_cast<idMaterial *>(surf->shader)->AddToSurfaceArea( area ); 978 } 979 } 980 981 // set flags for whole-model rejection 982 for ( i = 0; i < surfaces.Num(); i++ ) { 983 const modelSurface_t *surf = &surfaces[i]; 984 if ( surf->shader->IsDrawn() ) { 985 hasDrawingSurfaces = true; 986 } 987 if ( surf->shader->SurfaceCastsShadow() ) { 988 hasShadowCastingSurfaces = true; 989 } 990 if ( surf->shader->ReceivesLighting() ) { 991 hasInteractingSurfaces = true; 992 } 993 if ( strstr( surf->shader->GetName(), "trigger" ) ) { 994 static int breakHere; 995 breakHere++; 996 } 997 } 998 999 // calculate the bounds 1000 if ( surfaces.Num() == 0 ) { 1001 bounds.Zero(); 1002 } else { 1003 bounds.Clear(); 1004 for ( i = 0; i < surfaces.Num(); i++ ) { 1005 modelSurface_t *surf = &surfaces[i]; 1006 1007 // if the surface has a deformation, increase the bounds 1008 // the amount here is somewhat arbitrary, designed to handle 1009 // autosprites and flares, but could be done better with exact 1010 // deformation information. 1011 // Note that this doesn't handle deformations that are skinned in 1012 // at run time... 1013 if ( surf->shader->Deform() != DFRM_NONE ) { 1014 srfTriangles_t *tri = surf->geometry; 1015 idVec3 mid = ( tri->bounds[1] + tri->bounds[0] ) * 0.5f; 1016 float radius = ( tri->bounds[0] - mid ).Length(); 1017 radius += 20.0f; 1018 1019 tri->bounds[0][0] = mid[0] - radius; 1020 tri->bounds[0][1] = mid[1] - radius; 1021 tri->bounds[0][2] = mid[2] - radius; 1022 1023 tri->bounds[1][0] = mid[0] + radius; 1024 tri->bounds[1][1] = mid[1] + radius; 1025 tri->bounds[1][2] = mid[2] + radius; 1026 } 1027 1028 // add to the model bounds 1029 bounds.AddBounds( surf->geometry->bounds ); 1030 1031 } 1032 } 1033 } 1034 1035 /* 1036 ================= 1037 idRenderModelStatic::ConvertASEToModelSurfaces 1038 ================= 1039 */ 1040 typedef struct matchVert_s { 1041 struct matchVert_s *next; 1042 int v, tv; 1043 byte color[4]; 1044 idVec3 normal; 1045 } matchVert_t; 1046 1047 bool idRenderModelStatic::ConvertASEToModelSurfaces( const struct aseModel_s *ase ) { 1048 aseObject_t * object; 1049 aseMesh_t * mesh; 1050 aseMaterial_t * material; 1051 const idMaterial *im1, *im2; 1052 srfTriangles_t *tri; 1053 int objectNum; 1054 int i, j, k; 1055 int v, tv; 1056 int * vRemap; 1057 int * tvRemap; 1058 matchVert_t * mvTable; // all of the match verts 1059 matchVert_t ** mvHash; // points inside mvTable for each xyz index 1060 matchVert_t * lastmv; 1061 matchVert_t * mv; 1062 idVec3 normal; 1063 float uOffset, vOffset, textureSin, textureCos; 1064 float uTiling, vTiling; 1065 int * mergeTo; 1066 byte * color; 1067 static byte identityColor[4] = { 255, 255, 255, 255 }; 1068 modelSurface_t surf, *modelSurf; 1069 1070 if ( !ase ) { 1071 return false; 1072 } 1073 if ( ase->objects.Num() < 1 ) { 1074 return false; 1075 } 1076 1077 timeStamp = ase->timeStamp; 1078 1079 // the modeling programs can save out multiple surfaces with a common 1080 // material, but we would like to mege them together where possible 1081 // meaning that this->NumSurfaces() <= ase->objects.currentElements 1082 mergeTo = (int *)_alloca( ase->objects.Num() * sizeof( *mergeTo ) ); 1083 surf.geometry = NULL; 1084 if ( ase->materials.Num() == 0 ) { 1085 // if we don't have any materials, dump everything into a single surface 1086 surf.shader = tr.defaultMaterial; 1087 surf.id = 0; 1088 this->AddSurface( surf ); 1089 for ( i = 0; i < ase->objects.Num(); i++ ) { 1090 mergeTo[i] = 0; 1091 } 1092 } else if ( !r_mergeModelSurfaces.GetBool() ) { 1093 // don't merge any 1094 for ( i = 0; i < ase->objects.Num(); i++ ) { 1095 mergeTo[i] = i; 1096 object = ase->objects[i]; 1097 material = ase->materials[object->materialRef]; 1098 surf.shader = declManager->FindMaterial( material->name ); 1099 surf.id = this->NumSurfaces(); 1100 this->AddSurface( surf ); 1101 } 1102 } else { 1103 // search for material matches 1104 for ( i = 0; i < ase->objects.Num(); i++ ) { 1105 object = ase->objects[i]; 1106 material = ase->materials[object->materialRef]; 1107 im1 = declManager->FindMaterial( material->name ); 1108 if ( im1->IsDiscrete() ) { 1109 // flares, autosprites, etc 1110 j = this->NumSurfaces(); 1111 } else { 1112 for ( j = 0; j < this->NumSurfaces(); j++ ) { 1113 modelSurf = &this->surfaces[j]; 1114 im2 = modelSurf->shader; 1115 if ( im1 == im2 ) { 1116 // merge this 1117 mergeTo[i] = j; 1118 break; 1119 } 1120 } 1121 } 1122 if ( j == this->NumSurfaces() ) { 1123 // didn't merge 1124 mergeTo[i] = j; 1125 surf.shader = im1; 1126 surf.id = this->NumSurfaces(); 1127 this->AddSurface( surf ); 1128 } 1129 } 1130 } 1131 1132 idVectorSubset<idVec3, 3> vertexSubset; 1133 idVectorSubset<idVec2, 2> texCoordSubset; 1134 1135 // build the surfaces 1136 for ( objectNum = 0; objectNum < ase->objects.Num(); objectNum++ ) { 1137 object = ase->objects[objectNum]; 1138 mesh = &object->mesh; 1139 material = ase->materials[object->materialRef]; 1140 im1 = declManager->FindMaterial( material->name ); 1141 1142 bool normalsParsed = mesh->normalsParsed; 1143 1144 // completely ignore any explict normals on surfaces with a renderbump command 1145 // which will guarantee the best contours and least vertexes. 1146 const char *rb = im1->GetRenderBump(); 1147 if ( rb != NULL && rb[0] != NULL ) { 1148 normalsParsed = false; 1149 } 1150 1151 // It seems like the tools our artists are using often generate 1152 // verts and texcoords slightly separated that should be merged 1153 // note that we really should combine the surfaces with common materials 1154 // before doing this operation, because we can miss a slop combination 1155 // if they are in different surfaces 1156 1157 vRemap = (int *)R_StaticAlloc( mesh->numVertexes * sizeof( vRemap[0] ), TAG_MODEL ); 1158 1159 if ( fastLoad ) { 1160 // renderbump doesn't care about vertex count 1161 for ( j = 0; j < mesh->numVertexes; j++ ) { 1162 vRemap[j] = j; 1163 } 1164 } else { 1165 float vertexEpsilon = r_slopVertex.GetFloat(); 1166 float expand = 2 * 32 * vertexEpsilon; 1167 idVec3 mins, maxs; 1168 1169 SIMDProcessor->MinMax( mins, maxs, mesh->vertexes, mesh->numVertexes ); 1170 mins -= idVec3( expand, expand, expand ); 1171 maxs += idVec3( expand, expand, expand ); 1172 vertexSubset.Init( mins, maxs, 32, 1024 ); 1173 for ( j = 0; j < mesh->numVertexes; j++ ) { 1174 vRemap[j] = vertexSubset.FindVector( mesh->vertexes, j, vertexEpsilon ); 1175 } 1176 } 1177 1178 tvRemap = (int *)R_StaticAlloc( mesh->numTVertexes * sizeof( tvRemap[0] ), TAG_MODEL ); 1179 1180 if ( fastLoad ) { 1181 // renderbump doesn't care about vertex count 1182 for ( j = 0; j < mesh->numTVertexes; j++ ) { 1183 tvRemap[j] = j; 1184 } 1185 } else { 1186 float texCoordEpsilon = r_slopTexCoord.GetFloat(); 1187 float expand = 2 * 32 * texCoordEpsilon; 1188 idVec2 mins, maxs; 1189 1190 SIMDProcessor->MinMax( mins, maxs, mesh->tvertexes, mesh->numTVertexes ); 1191 mins -= idVec2( expand, expand ); 1192 maxs += idVec2( expand, expand ); 1193 texCoordSubset.Init( mins, maxs, 32, 1024 ); 1194 for ( j = 0; j < mesh->numTVertexes; j++ ) { 1195 tvRemap[j] = texCoordSubset.FindVector( mesh->tvertexes, j, texCoordEpsilon ); 1196 } 1197 } 1198 1199 // we need to find out how many unique vertex / texcoord combinations 1200 // there are, because ASE tracks them separately but we need them unified 1201 1202 // the maximum possible number of combined vertexes is the number of indexes 1203 mvTable = (matchVert_t *)R_ClearedStaticAlloc( mesh->numFaces * 3 * sizeof( mvTable[0] ) ); 1204 1205 // we will have a hash chain based on the xyz values 1206 mvHash = (matchVert_t **)R_ClearedStaticAlloc( mesh->numVertexes * sizeof( mvHash[0] ) ); 1207 1208 // allocate triangle surface 1209 tri = R_AllocStaticTriSurf(); 1210 tri->numVerts = 0; 1211 tri->numIndexes = 0; 1212 R_AllocStaticTriSurfIndexes( tri, mesh->numFaces * 3 ); 1213 tri->generateNormals = !normalsParsed; 1214 1215 // init default normal, color and tex coord index 1216 normal.Zero(); 1217 color = identityColor; 1218 tv = 0; 1219 1220 // find all the unique combinations 1221 float normalEpsilon = 1.0f - r_slopNormal.GetFloat(); 1222 for ( j = 0; j < mesh->numFaces; j++ ) { 1223 for ( k = 0; k < 3; k++ ) { 1224 v = mesh->faces[j].vertexNum[k]; 1225 1226 if ( v < 0 || v >= mesh->numVertexes ) { 1227 common->Error( "ConvertASEToModelSurfaces: bad vertex index in ASE file %s", name.c_str() ); 1228 } 1229 1230 // collapse the position if it was slightly offset 1231 v = vRemap[v]; 1232 1233 // we may or may not have texcoords to compare 1234 if ( mesh->numTVFaces == mesh->numFaces && mesh->numTVertexes != 0 ) { 1235 tv = mesh->faces[j].tVertexNum[k]; 1236 if ( tv < 0 || tv >= mesh->numTVertexes ) { 1237 common->Error( "ConvertASEToModelSurfaces: bad tex coord index in ASE file %s", name.c_str() ); 1238 } 1239 // collapse the tex coord if it was slightly offset 1240 tv = tvRemap[tv]; 1241 } 1242 1243 // we may or may not have normals to compare 1244 if ( normalsParsed ) { 1245 normal = mesh->faces[j].vertexNormals[k]; 1246 } 1247 1248 // we may or may not have colors to compare 1249 if ( mesh->colorsParsed ) { 1250 color = mesh->faces[j].vertexColors[k]; 1251 } 1252 1253 // find a matching vert 1254 for ( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next ) { 1255 if ( mv->tv != tv ) { 1256 continue; 1257 } 1258 if ( *(unsigned *)mv->color != *(unsigned *)color ) { 1259 continue; 1260 } 1261 if ( !normalsParsed ) { 1262 // if we are going to create the normals, just 1263 // matching texcoords is enough 1264 break; 1265 } 1266 if ( mv->normal * normal > normalEpsilon ) { 1267 break; // we already have this one 1268 } 1269 } 1270 if ( !mv ) { 1271 // allocate a new match vert and link to hash chain 1272 mv = &mvTable[ tri->numVerts ]; 1273 mv->v = v; 1274 mv->tv = tv; 1275 mv->normal = normal; 1276 *(unsigned *)mv->color = *(unsigned *)color; 1277 mv->next = NULL; 1278 if ( lastmv ) { 1279 lastmv->next = mv; 1280 } else { 1281 mvHash[v] = mv; 1282 } 1283 tri->numVerts++; 1284 } 1285 1286 tri->indexes[tri->numIndexes] = mv - mvTable; 1287 tri->numIndexes++; 1288 } 1289 } 1290 1291 // allocate space for the indexes and copy them 1292 if ( tri->numIndexes > mesh->numFaces * 3 ) { 1293 common->FatalError( "ConvertASEToModelSurfaces: index miscount in ASE file %s", name.c_str() ); 1294 } 1295 if ( tri->numVerts > mesh->numFaces * 3 ) { 1296 common->FatalError( "ConvertASEToModelSurfaces: vertex miscount in ASE file %s", name.c_str() ); 1297 } 1298 1299 // an ASE allows the texture coordinates to be scaled, translated, and rotated 1300 if ( ase->materials.Num() == 0 ) { 1301 uOffset = vOffset = 0.0f; 1302 uTiling = vTiling = 1.0f; 1303 textureSin = 0.0f; 1304 textureCos = 1.0f; 1305 } else { 1306 material = ase->materials[object->materialRef]; 1307 uOffset = -material->uOffset; 1308 vOffset = material->vOffset; 1309 uTiling = material->uTiling; 1310 vTiling = material->vTiling; 1311 textureSin = idMath::Sin( material->angle ); 1312 textureCos = idMath::Cos( material->angle ); 1313 } 1314 1315 // now allocate and generate the combined vertexes 1316 R_AllocStaticTriSurfVerts( tri, tri->numVerts ); 1317 1318 for ( j = 0; j < tri->numVerts; j++ ) { 1319 mv = &mvTable[j]; 1320 tri->verts[ j ].Clear(); 1321 tri->verts[ j ].xyz = mesh->vertexes[ mv->v ]; 1322 tri->verts[ j ].SetNormal( mv->normal ); 1323 *(unsigned *)tri->verts[j].color = *(unsigned *)mv->color; 1324 if ( mesh->numTVFaces == mesh->numFaces && mesh->numTVertexes != 0 ) { 1325 const idVec2 &tv = mesh->tvertexes[ mv->tv ]; 1326 float u = tv.x * uTiling + uOffset; 1327 float v = tv.y * vTiling + vOffset; 1328 tri->verts[j].SetTexCoord( u * textureCos + v * textureSin, u * -textureSin + v * textureCos ); 1329 } 1330 } 1331 1332 R_StaticFree( mvTable ); 1333 R_StaticFree( mvHash ); 1334 R_StaticFree( tvRemap ); 1335 R_StaticFree( vRemap ); 1336 1337 // see if we need to merge with a previous surface of the same material 1338 modelSurf = &this->surfaces[mergeTo[ objectNum ]]; 1339 srfTriangles_t *mergeTri = modelSurf->geometry; 1340 if ( !mergeTri ) { 1341 modelSurf->geometry = tri; 1342 } else { 1343 modelSurf->geometry = R_MergeTriangles( mergeTri, tri ); 1344 R_FreeStaticTriSurf( tri ); 1345 R_FreeStaticTriSurf( mergeTri ); 1346 } 1347 } 1348 1349 return true; 1350 } 1351 1352 /* 1353 ================= 1354 idRenderModelStatic::ConvertLWOToModelSurfaces 1355 ================= 1356 */ 1357 bool idRenderModelStatic::ConvertLWOToModelSurfaces( const struct st_lwObject *lwo ) { 1358 const idMaterial *im1, *im2; 1359 srfTriangles_t *tri; 1360 lwSurface * lwoSurf; 1361 int numTVertexes; 1362 int i, j, k; 1363 int v, tv; 1364 idVec3 * vList; 1365 int * vRemap; 1366 idVec2 * tvList; 1367 int * tvRemap; 1368 matchVert_t * mvTable; // all of the match verts 1369 matchVert_t ** mvHash; // points inside mvTable for each xyz index 1370 matchVert_t * lastmv; 1371 matchVert_t * mv; 1372 idVec3 normal; 1373 int * mergeTo; 1374 byte color[4]; 1375 modelSurface_t surf, *modelSurf; 1376 1377 if ( !lwo ) { 1378 return false; 1379 } 1380 if ( lwo->surf == NULL ) { 1381 return false; 1382 } 1383 1384 timeStamp = lwo->timeStamp; 1385 1386 // count the number of surfaces 1387 i = 0; 1388 for ( lwoSurf = lwo->surf; lwoSurf; lwoSurf = lwoSurf->next ) { 1389 i++; 1390 } 1391 1392 // the modeling programs can save out multiple surfaces with a common 1393 // material, but we would like to merge them together where possible 1394 mergeTo = (int *)_alloca( i * sizeof( mergeTo[0] ) ); 1395 memset( &surf, 0, sizeof( surf ) ); 1396 1397 if ( !r_mergeModelSurfaces.GetBool() ) { 1398 // don't merge any 1399 for ( lwoSurf = lwo->surf, i = 0; lwoSurf; lwoSurf = lwoSurf->next, i++ ) { 1400 mergeTo[i] = i; 1401 surf.shader = declManager->FindMaterial( lwoSurf->name ); 1402 surf.id = this->NumSurfaces(); 1403 this->AddSurface( surf ); 1404 } 1405 } else { 1406 // search for material matches 1407 for ( lwoSurf = lwo->surf, i = 0; lwoSurf; lwoSurf = lwoSurf->next, i++ ) { 1408 im1 = declManager->FindMaterial( lwoSurf->name ); 1409 if ( im1->IsDiscrete() ) { 1410 // flares, autosprites, etc 1411 j = this->NumSurfaces(); 1412 } else { 1413 for ( j = 0; j < this->NumSurfaces(); j++ ) { 1414 modelSurf = &this->surfaces[j]; 1415 im2 = modelSurf->shader; 1416 if ( im1 == im2 ) { 1417 // merge this 1418 mergeTo[i] = j; 1419 break; 1420 } 1421 } 1422 } 1423 if ( j == this->NumSurfaces() ) { 1424 // didn't merge 1425 mergeTo[i] = j; 1426 surf.shader = im1; 1427 surf.id = this->NumSurfaces(); 1428 this->AddSurface( surf ); 1429 } 1430 } 1431 } 1432 1433 idVectorSubset<idVec3, 3> vertexSubset; 1434 idVectorSubset<idVec2, 2> texCoordSubset; 1435 1436 // we only ever use the first layer 1437 lwLayer *layer = lwo->layer; 1438 1439 // vertex positions 1440 if ( layer->point.count <= 0 ) { 1441 common->Warning( "ConvertLWOToModelSurfaces: model \'%s\' has bad or missing vertex data", name.c_str() ); 1442 return false; 1443 } 1444 1445 vList = (idVec3 *)R_StaticAlloc( layer->point.count * sizeof( vList[0] ), TAG_MODEL ); 1446 for ( j = 0; j < layer->point.count; j++ ) { 1447 vList[j].x = layer->point.pt[j].pos[0]; 1448 vList[j].y = layer->point.pt[j].pos[2]; 1449 vList[j].z = layer->point.pt[j].pos[1]; 1450 } 1451 1452 // vertex texture coords 1453 numTVertexes = 0; 1454 1455 if ( layer->nvmaps ) { 1456 for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) { 1457 if ( vm->type == LWID_('T','X','U','V') ) { 1458 numTVertexes += vm->nverts; 1459 } 1460 } 1461 } 1462 1463 if ( numTVertexes ) { 1464 tvList = (idVec2 *)Mem_Alloc( numTVertexes * sizeof( tvList[0] ), TAG_MODEL ); 1465 int offset = 0; 1466 for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) { 1467 if ( vm->type == LWID_('T','X','U','V') ) { 1468 vm->offset = offset; 1469 for ( k = 0; k < vm->nverts; k++ ) { 1470 tvList[k + offset].x = vm->val[k][0]; 1471 tvList[k + offset].y = 1.0f - vm->val[k][1]; // invert the t 1472 } 1473 offset += vm->nverts; 1474 } 1475 } 1476 } else { 1477 common->Warning( "ConvertLWOToModelSurfaces: model \'%s\' has bad or missing uv data", name.c_str() ); 1478 numTVertexes = 1; 1479 tvList = (idVec2 *)Mem_ClearedAlloc( numTVertexes * sizeof( tvList[0] ), TAG_MODEL ); 1480 } 1481 1482 // It seems like the tools our artists are using often generate 1483 // verts and texcoords slightly separated that should be merged 1484 // note that we really should combine the surfaces with common materials 1485 // before doing this operation, because we can miss a slop combination 1486 // if they are in different surfaces 1487 1488 vRemap = (int *)R_StaticAlloc( layer->point.count * sizeof( vRemap[0] ), TAG_MODEL ); 1489 1490 if ( fastLoad ) { 1491 // renderbump doesn't care about vertex count 1492 for ( j = 0; j < layer->point.count; j++ ) { 1493 vRemap[j] = j; 1494 } 1495 } else { 1496 float vertexEpsilon = r_slopVertex.GetFloat(); 1497 float expand = 2 * 32 * vertexEpsilon; 1498 idVec3 mins, maxs; 1499 1500 SIMDProcessor->MinMax( mins, maxs, vList, layer->point.count ); 1501 mins -= idVec3( expand, expand, expand ); 1502 maxs += idVec3( expand, expand, expand ); 1503 vertexSubset.Init( mins, maxs, 32, 1024 ); 1504 for ( j = 0; j < layer->point.count; j++ ) { 1505 vRemap[j] = vertexSubset.FindVector( vList, j, vertexEpsilon ); 1506 } 1507 } 1508 1509 tvRemap = (int *)R_StaticAlloc( numTVertexes * sizeof( tvRemap[0] ), TAG_MODEL ); 1510 1511 if ( fastLoad ) { 1512 // renderbump doesn't care about vertex count 1513 for ( j = 0; j < numTVertexes; j++ ) { 1514 tvRemap[j] = j; 1515 } 1516 } else { 1517 float texCoordEpsilon = r_slopTexCoord.GetFloat(); 1518 float expand = 2 * 32 * texCoordEpsilon; 1519 idVec2 mins, maxs; 1520 1521 SIMDProcessor->MinMax( mins, maxs, tvList, numTVertexes ); 1522 mins -= idVec2( expand, expand ); 1523 maxs += idVec2( expand, expand ); 1524 texCoordSubset.Init( mins, maxs, 32, 1024 ); 1525 for ( j = 0; j < numTVertexes; j++ ) { 1526 tvRemap[j] = texCoordSubset.FindVector( tvList, j, texCoordEpsilon ); 1527 } 1528 } 1529 1530 // build the surfaces 1531 for ( lwoSurf = lwo->surf, i = 0; lwoSurf; lwoSurf = lwoSurf->next, i++ ) { 1532 im1 = declManager->FindMaterial( lwoSurf->name ); 1533 1534 bool normalsParsed = true; 1535 1536 // completely ignore any explict normals on surfaces with a renderbump command 1537 // which will guarantee the best contours and least vertexes. 1538 const char *rb = im1->GetRenderBump(); 1539 if ( rb && rb[0] ) { 1540 normalsParsed = false; 1541 } 1542 1543 // we need to find out how many unique vertex / texcoord combinations there are 1544 1545 // the maximum possible number of combined vertexes is the number of indexes 1546 mvTable = (matchVert_t *)R_ClearedStaticAlloc( layer->polygon.count * 3 * sizeof( mvTable[0] ) ); 1547 1548 // we will have a hash chain based on the xyz values 1549 mvHash = (matchVert_t **)R_ClearedStaticAlloc( layer->point.count * sizeof( mvHash[0] ) ); 1550 1551 // allocate triangle surface 1552 tri = R_AllocStaticTriSurf(); 1553 tri->numVerts = 0; 1554 tri->numIndexes = 0; 1555 R_AllocStaticTriSurfIndexes( tri, layer->polygon.count * 3 ); 1556 tri->generateNormals = !normalsParsed; 1557 1558 // find all the unique combinations 1559 float normalEpsilon; 1560 if ( fastLoad ) { 1561 normalEpsilon = 1.0f; // don't merge unless completely exact 1562 } else { 1563 normalEpsilon = 1.0f - r_slopNormal.GetFloat(); 1564 } 1565 for ( j = 0; j < layer->polygon.count; j++ ) { 1566 lwPolygon *poly = &layer->polygon.pol[j]; 1567 1568 if ( poly->surf != lwoSurf ) { 1569 continue; 1570 } 1571 1572 if ( poly->nverts != 3 ) { 1573 common->Warning( "ConvertLWOToModelSurfaces: model %s has too many verts for a poly! Make sure you triplet it down", name.c_str() ); 1574 continue; 1575 } 1576 1577 for ( k = 0; k < 3; k++ ) { 1578 1579 v = vRemap[poly->v[k].index]; 1580 1581 normal.x = poly->v[k].norm[0]; 1582 normal.y = poly->v[k].norm[2]; 1583 normal.z = poly->v[k].norm[1]; 1584 1585 // LWO models aren't all that pretty when it comes down to the floating point values they store 1586 normal.FixDegenerateNormal(); 1587 1588 tv = 0; 1589 1590 color[0] = lwoSurf->color.rgb[0] * 255; 1591 color[1] = lwoSurf->color.rgb[1] * 255; 1592 color[2] = lwoSurf->color.rgb[2] * 255; 1593 color[3] = 255; 1594 1595 // first set attributes from the vertex 1596 lwPoint *pt = &layer->point.pt[poly->v[k].index]; 1597 int nvm; 1598 for ( nvm = 0; nvm < pt->nvmaps; nvm++ ) { 1599 lwVMapPt *vm = &pt->vm[nvm]; 1600 1601 if ( vm->vmap->type == LWID_('T','X','U','V') ) { 1602 tv = tvRemap[vm->index + vm->vmap->offset]; 1603 } 1604 if ( vm->vmap->type == LWID_('R','G','B','A') ) { 1605 for ( int chan = 0; chan < 4; chan++ ) { 1606 color[chan] = 255 * vm->vmap->val[vm->index][chan]; 1607 } 1608 } 1609 } 1610 1611 // then override with polygon attributes 1612 for ( nvm = 0; nvm < poly->v[k].nvmaps; nvm++ ) { 1613 lwVMapPt *vm = &poly->v[k].vm[nvm]; 1614 1615 if ( vm->vmap->type == LWID_('T','X','U','V') ) { 1616 tv = tvRemap[vm->index + vm->vmap->offset]; 1617 } 1618 if ( vm->vmap->type == LWID_('R','G','B','A') ) { 1619 for ( int chan = 0; chan < 4; chan++ ) { 1620 color[chan] = 255 * vm->vmap->val[vm->index][chan]; 1621 } 1622 } 1623 } 1624 1625 // find a matching vert 1626 for ( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next ) { 1627 if ( mv->tv != tv ) { 1628 continue; 1629 } 1630 if ( *(unsigned *)mv->color != *(unsigned *)color ) { 1631 continue; 1632 } 1633 if ( !normalsParsed ) { 1634 // if we are going to create the normals, just 1635 // matching texcoords is enough 1636 break; 1637 } 1638 if ( mv->normal * normal > normalEpsilon ) { 1639 break; // we already have this one 1640 } 1641 } 1642 if ( !mv ) { 1643 // allocate a new match vert and link to hash chain 1644 mv = &mvTable[ tri->numVerts ]; 1645 mv->v = v; 1646 mv->tv = tv; 1647 mv->normal = normal; 1648 *(unsigned *)mv->color = *(unsigned *)color; 1649 mv->next = NULL; 1650 if ( lastmv ) { 1651 lastmv->next = mv; 1652 } else { 1653 mvHash[v] = mv; 1654 } 1655 tri->numVerts++; 1656 } 1657 1658 tri->indexes[tri->numIndexes] = mv - mvTable; 1659 tri->numIndexes++; 1660 } 1661 } 1662 1663 // allocate space for the indexes and copy them 1664 if ( tri->numIndexes > layer->polygon.count * 3 ) { 1665 common->FatalError( "ConvertLWOToModelSurfaces: index miscount in LWO file %s", name.c_str() ); 1666 } 1667 if ( tri->numVerts > layer->polygon.count * 3 ) { 1668 common->FatalError( "ConvertLWOToModelSurfaces: vertex miscount in LWO file %s", name.c_str() ); 1669 } 1670 1671 // now allocate and generate the combined vertexes 1672 R_AllocStaticTriSurfVerts( tri, tri->numVerts ); 1673 1674 for ( j = 0; j < tri->numVerts; j++ ) { 1675 mv = &mvTable[j]; 1676 tri->verts[ j ].Clear(); 1677 tri->verts[ j ].xyz = vList[ mv->v ]; 1678 tri->verts[ j ].SetTexCoord( tvList[ mv->tv ] ); 1679 tri->verts[ j ].SetNormal( mv->normal ); 1680 *(unsigned *)tri->verts[j].color = *(unsigned *)mv->color; 1681 } 1682 1683 R_StaticFree( mvTable ); 1684 R_StaticFree( mvHash ); 1685 1686 // see if we need to merge with a previous surface of the same material 1687 modelSurf = &this->surfaces[mergeTo[ i ]]; 1688 srfTriangles_t *mergeTri = modelSurf->geometry; 1689 if ( !mergeTri ) { 1690 modelSurf->geometry = tri; 1691 } else { 1692 modelSurf->geometry = R_MergeTriangles( mergeTri, tri ); 1693 R_FreeStaticTriSurf( tri ); 1694 R_FreeStaticTriSurf( mergeTri ); 1695 } 1696 } 1697 1698 R_StaticFree( tvRemap ); 1699 R_StaticFree( vRemap ); 1700 R_StaticFree( tvList ); 1701 R_StaticFree( vList ); 1702 1703 return true; 1704 } 1705 1706 /* 1707 ================= 1708 idRenderModelStatic::ConvertLWOToASE 1709 ================= 1710 */ 1711 struct aseModel_s *idRenderModelStatic::ConvertLWOToASE( const struct st_lwObject *obj, const char *fileName ) { 1712 int j, k; 1713 aseModel_t *ase; 1714 1715 if ( !obj ) { 1716 return NULL; 1717 } 1718 1719 // NOTE: using new operator because aseModel_t contains idList class objects 1720 ase = new (TAG_MODEL) aseModel_t; 1721 ase->timeStamp = obj->timeStamp; 1722 ase->objects.Resize( obj->nlayers, obj->nlayers ); 1723 1724 int materialRef = 0; 1725 1726 for ( lwSurface *surf = obj->surf; surf; surf = surf->next ) { 1727 1728 aseMaterial_t *mat = (aseMaterial_t *)Mem_ClearedAlloc( sizeof( *mat ), TAG_MODEL ); 1729 strcpy( mat->name, surf->name ); 1730 mat->uTiling = mat->vTiling = 1; 1731 mat->angle = mat->uOffset = mat->vOffset = 0; 1732 ase->materials.Append( mat ); 1733 1734 lwLayer *layer = obj->layer; 1735 1736 aseObject_t *object = (aseObject_t *)Mem_ClearedAlloc( sizeof( *object ), TAG_MODEL ); 1737 object->materialRef = materialRef++; 1738 1739 aseMesh_t *mesh = &object->mesh; 1740 ase->objects.Append( object ); 1741 1742 mesh->numFaces = layer->polygon.count; 1743 mesh->numTVFaces = mesh->numFaces; 1744 mesh->faces = (aseFace_t *)Mem_Alloc( mesh->numFaces * sizeof( mesh->faces[0] ), TAG_MODEL ); 1745 1746 mesh->numVertexes = layer->point.count; 1747 mesh->vertexes = (idVec3 *)Mem_Alloc( mesh->numVertexes * sizeof( mesh->vertexes[0] ), TAG_MODEL ); 1748 1749 // vertex positions 1750 if ( layer->point.count <= 0 ) { 1751 common->Warning( "ConvertLWOToASE: model \'%s\' has bad or missing vertex data", name.c_str() ); 1752 } 1753 1754 for ( j = 0; j < layer->point.count; j++ ) { 1755 mesh->vertexes[j].x = layer->point.pt[j].pos[0]; 1756 mesh->vertexes[j].y = layer->point.pt[j].pos[2]; 1757 mesh->vertexes[j].z = layer->point.pt[j].pos[1]; 1758 } 1759 1760 // vertex texture coords 1761 mesh->numTVertexes = 0; 1762 1763 if ( layer->nvmaps ) { 1764 for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) { 1765 if ( vm->type == LWID_('T','X','U','V') ) { 1766 mesh->numTVertexes += vm->nverts; 1767 } 1768 } 1769 } 1770 1771 if ( mesh->numTVertexes ) { 1772 mesh->tvertexes = (idVec2 *)Mem_Alloc( mesh->numTVertexes * sizeof( mesh->tvertexes[0] ), TAG_MODEL ); 1773 int offset = 0; 1774 for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) { 1775 if ( vm->type == LWID_('T','X','U','V') ) { 1776 vm->offset = offset; 1777 for ( k = 0; k < vm->nverts; k++ ) { 1778 mesh->tvertexes[k + offset].x = vm->val[k][0]; 1779 mesh->tvertexes[k + offset].y = 1.0f - vm->val[k][1]; // invert the t 1780 } 1781 offset += vm->nverts; 1782 } 1783 } 1784 } else { 1785 common->Warning( "ConvertLWOToASE: model \'%s\' has bad or missing uv data", fileName ); 1786 mesh->numTVertexes = 1; 1787 mesh->tvertexes = (idVec2 *)Mem_ClearedAlloc( mesh->numTVertexes * sizeof( mesh->tvertexes[0] ), TAG_MODEL ); 1788 } 1789 1790 mesh->normalsParsed = true; 1791 mesh->colorsParsed = true; // because we are falling back to the surface color 1792 1793 // triangles 1794 int faceIndex = 0; 1795 for ( j = 0; j < layer->polygon.count; j++ ) { 1796 lwPolygon *poly = &layer->polygon.pol[j]; 1797 1798 if ( poly->surf != surf ) { 1799 continue; 1800 } 1801 1802 if ( poly->nverts != 3 ) { 1803 common->Warning( "ConvertLWOToASE: model %s has too many verts for a poly! Make sure you triplet it down", fileName ); 1804 continue; 1805 } 1806 1807 mesh->faces[faceIndex].faceNormal.x = poly->norm[0]; 1808 mesh->faces[faceIndex].faceNormal.y = poly->norm[2]; 1809 mesh->faces[faceIndex].faceNormal.z = poly->norm[1]; 1810 1811 for ( k = 0; k < 3; k++ ) { 1812 1813 mesh->faces[faceIndex].vertexNum[k] = poly->v[k].index; 1814 1815 mesh->faces[faceIndex].vertexNormals[k].x = poly->v[k].norm[0]; 1816 mesh->faces[faceIndex].vertexNormals[k].y = poly->v[k].norm[2]; 1817 mesh->faces[faceIndex].vertexNormals[k].z = poly->v[k].norm[1]; 1818 1819 // complete fallbacks 1820 mesh->faces[faceIndex].tVertexNum[k] = 0; 1821 1822 mesh->faces[faceIndex].vertexColors[k][0] = surf->color.rgb[0] * 255; 1823 mesh->faces[faceIndex].vertexColors[k][1] = surf->color.rgb[1] * 255; 1824 mesh->faces[faceIndex].vertexColors[k][2] = surf->color.rgb[2] * 255; 1825 mesh->faces[faceIndex].vertexColors[k][3] = 255; 1826 1827 // first set attributes from the vertex 1828 lwPoint *pt = &layer->point.pt[poly->v[k].index]; 1829 int nvm; 1830 for ( nvm = 0; nvm < pt->nvmaps; nvm++ ) { 1831 lwVMapPt *vm = &pt->vm[nvm]; 1832 1833 if ( vm->vmap->type == LWID_('T','X','U','V') ) { 1834 mesh->faces[faceIndex].tVertexNum[k] = vm->index + vm->vmap->offset; 1835 } 1836 if ( vm->vmap->type == LWID_('R','G','B','A') ) { 1837 for ( int chan = 0; chan < 4; chan++ ) { 1838 mesh->faces[faceIndex].vertexColors[k][chan] = 255 * vm->vmap->val[vm->index][chan]; 1839 } 1840 } 1841 } 1842 1843 // then override with polygon attributes 1844 for ( nvm = 0; nvm < poly->v[k].nvmaps; nvm++ ) { 1845 lwVMapPt *vm = &poly->v[k].vm[nvm]; 1846 1847 if ( vm->vmap->type == LWID_('T','X','U','V') ) { 1848 mesh->faces[faceIndex].tVertexNum[k] = vm->index + vm->vmap->offset; 1849 } 1850 if ( vm->vmap->type == LWID_('R','G','B','A') ) { 1851 for ( int chan = 0; chan < 4; chan++ ) { 1852 mesh->faces[faceIndex].vertexColors[k][chan] = 255 * vm->vmap->val[vm->index][chan]; 1853 } 1854 } 1855 } 1856 } 1857 1858 faceIndex++; 1859 } 1860 1861 mesh->numFaces = faceIndex; 1862 mesh->numTVFaces = faceIndex; 1863 1864 aseFace_t *newFaces = ( aseFace_t* )Mem_Alloc( mesh->numFaces * sizeof ( mesh->faces[0] ), TAG_MODEL ); 1865 memcpy( newFaces, mesh->faces, sizeof( mesh->faces[0] ) * mesh->numFaces ); 1866 Mem_Free( mesh->faces ); 1867 mesh->faces = newFaces; 1868 } 1869 1870 return ase; 1871 } 1872 1873 /* 1874 ================= 1875 idRenderModelStatic::ConvertMAToModelSurfaces 1876 ================= 1877 */ 1878 bool idRenderModelStatic::ConvertMAToModelSurfaces (const struct maModel_s *ma ) { 1879 1880 maObject_t * object; 1881 maMesh_t * mesh; 1882 maMaterial_t * material; 1883 1884 const idMaterial *im1, *im2; 1885 srfTriangles_t *tri; 1886 int objectNum; 1887 int i, j, k; 1888 int v, tv; 1889 int * vRemap; 1890 int * tvRemap; 1891 matchVert_t * mvTable; // all of the match verts 1892 matchVert_t ** mvHash; // points inside mvTable for each xyz index 1893 matchVert_t * lastmv; 1894 matchVert_t * mv; 1895 idVec3 normal; 1896 float uOffset, vOffset, textureSin, textureCos; 1897 float uTiling, vTiling; 1898 int * mergeTo; 1899 byte * color; 1900 static byte identityColor[4] = { 255, 255, 255, 255 }; 1901 modelSurface_t surf, *modelSurf; 1902 1903 if ( !ma ) { 1904 return false; 1905 } 1906 if ( ma->objects.Num() < 1 ) { 1907 return false; 1908 } 1909 1910 timeStamp = ma->timeStamp; 1911 1912 // the modeling programs can save out multiple surfaces with a common 1913 // material, but we would like to mege them together where possible 1914 // meaning that this->NumSurfaces() <= ma->objects.currentElements 1915 mergeTo = (int *)_alloca( ma->objects.Num() * sizeof( *mergeTo ) ); 1916 1917 surf.geometry = NULL; 1918 if ( ma->materials.Num() == 0 ) { 1919 // if we don't have any materials, dump everything into a single surface 1920 surf.shader = tr.defaultMaterial; 1921 surf.id = 0; 1922 this->AddSurface( surf ); 1923 for ( i = 0; i < ma->objects.Num(); i++ ) { 1924 mergeTo[i] = 0; 1925 } 1926 } else if ( !r_mergeModelSurfaces.GetBool() ) { 1927 // don't merge any 1928 for ( i = 0; i < ma->objects.Num(); i++ ) { 1929 mergeTo[i] = i; 1930 object = ma->objects[i]; 1931 if(object->materialRef >= 0) { 1932 material = ma->materials[object->materialRef]; 1933 surf.shader = declManager->FindMaterial( material->name ); 1934 } else { 1935 surf.shader = tr.defaultMaterial; 1936 } 1937 surf.id = this->NumSurfaces(); 1938 this->AddSurface( surf ); 1939 } 1940 } else { 1941 // search for material matches 1942 for ( i = 0; i < ma->objects.Num(); i++ ) { 1943 object = ma->objects[i]; 1944 if(object->materialRef >= 0) { 1945 material = ma->materials[object->materialRef]; 1946 im1 = declManager->FindMaterial( material->name ); 1947 } else { 1948 im1 = tr.defaultMaterial; 1949 } 1950 if ( im1->IsDiscrete() ) { 1951 // flares, autosprites, etc 1952 j = this->NumSurfaces(); 1953 } else { 1954 for ( j = 0; j < this->NumSurfaces(); j++ ) { 1955 modelSurf = &this->surfaces[j]; 1956 im2 = modelSurf->shader; 1957 if ( im1 == im2 ) { 1958 // merge this 1959 mergeTo[i] = j; 1960 break; 1961 } 1962 } 1963 } 1964 if ( j == this->NumSurfaces() ) { 1965 // didn't merge 1966 mergeTo[i] = j; 1967 surf.shader = im1; 1968 surf.id = this->NumSurfaces(); 1969 this->AddSurface( surf ); 1970 } 1971 } 1972 } 1973 1974 idVectorSubset<idVec3, 3> vertexSubset; 1975 idVectorSubset<idVec2, 2> texCoordSubset; 1976 1977 // build the surfaces 1978 for ( objectNum = 0; objectNum < ma->objects.Num(); objectNum++ ) { 1979 object = ma->objects[objectNum]; 1980 mesh = &object->mesh; 1981 if(object->materialRef >= 0) { 1982 material = ma->materials[object->materialRef]; 1983 im1 = declManager->FindMaterial( material->name ); 1984 } else { 1985 im1 = tr.defaultMaterial; 1986 } 1987 1988 bool normalsParsed = mesh->normalsParsed; 1989 1990 // completely ignore any explict normals on surfaces with a renderbump command 1991 // which will guarantee the best contours and least vertexes. 1992 const char *rb = im1->GetRenderBump(); 1993 if ( rb != NULL && rb[0] != NULL ) { 1994 normalsParsed = false; 1995 } 1996 1997 // It seems like the tools our artists are using often generate 1998 // verts and texcoords slightly separated that should be merged 1999 // note that we really should combine the surfaces with common materials 2000 // before doing this operation, because we can miss a slop combination 2001 // if they are in different surfaces 2002 2003 vRemap = (int *)R_StaticAlloc( mesh->numVertexes * sizeof( vRemap[0] ), TAG_MODEL ); 2004 2005 if ( fastLoad ) { 2006 // renderbump doesn't care about vertex count 2007 for ( j = 0; j < mesh->numVertexes; j++ ) { 2008 vRemap[j] = j; 2009 } 2010 } else { 2011 float vertexEpsilon = r_slopVertex.GetFloat(); 2012 float expand = 2 * 32 * vertexEpsilon; 2013 idVec3 mins, maxs; 2014 2015 SIMDProcessor->MinMax( mins, maxs, mesh->vertexes, mesh->numVertexes ); 2016 mins -= idVec3( expand, expand, expand ); 2017 maxs += idVec3( expand, expand, expand ); 2018 vertexSubset.Init( mins, maxs, 32, 1024 ); 2019 for ( j = 0; j < mesh->numVertexes; j++ ) { 2020 vRemap[j] = vertexSubset.FindVector( mesh->vertexes, j, vertexEpsilon ); 2021 } 2022 } 2023 2024 tvRemap = (int *)R_StaticAlloc( mesh->numTVertexes * sizeof( tvRemap[0] ), TAG_MODEL ); 2025 2026 if ( fastLoad ) { 2027 // renderbump doesn't care about vertex count 2028 for ( j = 0; j < mesh->numTVertexes; j++ ) { 2029 tvRemap[j] = j; 2030 } 2031 } else { 2032 float texCoordEpsilon = r_slopTexCoord.GetFloat(); 2033 float expand = 2 * 32 * texCoordEpsilon; 2034 idVec2 mins, maxs; 2035 2036 SIMDProcessor->MinMax( mins, maxs, mesh->tvertexes, mesh->numTVertexes ); 2037 mins -= idVec2( expand, expand ); 2038 maxs += idVec2( expand, expand ); 2039 texCoordSubset.Init( mins, maxs, 32, 1024 ); 2040 for ( j = 0; j < mesh->numTVertexes; j++ ) { 2041 tvRemap[j] = texCoordSubset.FindVector( mesh->tvertexes, j, texCoordEpsilon ); 2042 } 2043 } 2044 2045 // we need to find out how many unique vertex / texcoord / color combinations 2046 // there are, because MA tracks them separately but we need them unified 2047 2048 // the maximum possible number of combined vertexes is the number of indexes 2049 mvTable = (matchVert_t *)R_ClearedStaticAlloc( mesh->numFaces * 3 * sizeof( mvTable[0] ) ); 2050 2051 // we will have a hash chain based on the xyz values 2052 mvHash = (matchVert_t **)R_ClearedStaticAlloc( mesh->numVertexes * sizeof( mvHash[0] ) ); 2053 2054 // allocate triangle surface 2055 tri = R_AllocStaticTriSurf(); 2056 tri->numVerts = 0; 2057 tri->numIndexes = 0; 2058 R_AllocStaticTriSurfIndexes( tri, mesh->numFaces * 3 ); 2059 tri->generateNormals = !normalsParsed; 2060 2061 // init default normal, color and tex coord index 2062 normal.Zero(); 2063 color = identityColor; 2064 tv = 0; 2065 2066 // find all the unique combinations 2067 float normalEpsilon = 1.0f - r_slopNormal.GetFloat(); 2068 for ( j = 0; j < mesh->numFaces; j++ ) { 2069 for ( k = 0; k < 3; k++ ) { 2070 v = mesh->faces[j].vertexNum[k]; 2071 2072 if ( v < 0 || v >= mesh->numVertexes ) { 2073 common->Error( "ConvertMAToModelSurfaces: bad vertex index in MA file %s", name.c_str() ); 2074 } 2075 2076 // collapse the position if it was slightly offset 2077 v = vRemap[v]; 2078 2079 // we may or may not have texcoords to compare 2080 if ( mesh->numTVertexes != 0 ) { 2081 tv = mesh->faces[j].tVertexNum[k]; 2082 if ( tv < 0 || tv >= mesh->numTVertexes ) { 2083 common->Error( "ConvertMAToModelSurfaces: bad tex coord index in MA file %s", name.c_str() ); 2084 } 2085 // collapse the tex coord if it was slightly offset 2086 tv = tvRemap[tv]; 2087 } 2088 2089 // we may or may not have normals to compare 2090 if ( normalsParsed ) { 2091 normal = mesh->faces[j].vertexNormals[k]; 2092 } 2093 2094 //BSM: Todo: Fix the vertex colors 2095 // we may or may not have colors to compare 2096 if ( mesh->faces[j].vertexColors[k] != -1 && mesh->faces[j].vertexColors[k] != -999 ) { 2097 2098 color = &mesh->colors[mesh->faces[j].vertexColors[k]*4]; 2099 } 2100 2101 // find a matching vert 2102 for ( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next ) { 2103 if ( mv->tv != tv ) { 2104 continue; 2105 } 2106 if ( *(unsigned *)mv->color != *(unsigned *)color ) { 2107 continue; 2108 } 2109 if ( !normalsParsed ) { 2110 // if we are going to create the normals, just 2111 // matching texcoords is enough 2112 break; 2113 } 2114 if ( mv->normal * normal > normalEpsilon ) { 2115 break; // we already have this one 2116 } 2117 } 2118 if ( !mv ) { 2119 // allocate a new match vert and link to hash chain 2120 mv = &mvTable[ tri->numVerts ]; 2121 mv->v = v; 2122 mv->tv = tv; 2123 mv->normal = normal; 2124 *(unsigned *)mv->color = *(unsigned *)color; 2125 mv->next = NULL; 2126 if ( lastmv ) { 2127 lastmv->next = mv; 2128 } else { 2129 mvHash[v] = mv; 2130 } 2131 tri->numVerts++; 2132 } 2133 2134 tri->indexes[tri->numIndexes] = mv - mvTable; 2135 tri->numIndexes++; 2136 } 2137 } 2138 2139 // allocate space for the indexes and copy them 2140 if ( tri->numIndexes > mesh->numFaces * 3 ) { 2141 common->FatalError( "ConvertMAToModelSurfaces: index miscount in MA file %s", name.c_str() ); 2142 } 2143 if ( tri->numVerts > mesh->numFaces * 3 ) { 2144 common->FatalError( "ConvertMAToModelSurfaces: vertex miscount in MA file %s", name.c_str() ); 2145 } 2146 2147 // an MA allows the texture coordinates to be scaled, translated, and rotated 2148 //BSM: Todo: Does Maya support this and if so how 2149 //if ( ase->materials.Num() == 0 ) { 2150 uOffset = vOffset = 0.0f; 2151 uTiling = vTiling = 1.0f; 2152 textureSin = 0.0f; 2153 textureCos = 1.0f; 2154 //} else { 2155 // material = ase->materials[object->materialRef]; 2156 // uOffset = -material->uOffset; 2157 // vOffset = material->vOffset; 2158 // uTiling = material->uTiling; 2159 // vTiling = material->vTiling; 2160 // textureSin = idMath::Sin( material->angle ); 2161 // textureCos = idMath::Cos( material->angle ); 2162 //} 2163 2164 // now allocate and generate the combined vertexes 2165 R_AllocStaticTriSurfVerts( tri, tri->numVerts ); 2166 2167 for ( j = 0; j < tri->numVerts; j++ ) { 2168 mv = &mvTable[j]; 2169 tri->verts[ j ].Clear(); 2170 tri->verts[ j ].xyz = mesh->vertexes[ mv->v ]; 2171 tri->verts[ j ].SetNormal( mv->normal ); 2172 *(unsigned *)tri->verts[j].color = *(unsigned *)mv->color; 2173 if ( mesh->numTVertexes != 0 ) { 2174 const idVec2 &tv = mesh->tvertexes[ mv->tv ]; 2175 float u = tv.x * uTiling + uOffset; 2176 float v = tv.y * vTiling + vOffset; 2177 tri->verts[j].SetTexCoord( u * textureCos + v * textureSin, u * -textureSin + v * textureCos ); 2178 } 2179 } 2180 2181 R_StaticFree( mvTable ); 2182 R_StaticFree( mvHash ); 2183 R_StaticFree( tvRemap ); 2184 R_StaticFree( vRemap ); 2185 2186 // see if we need to merge with a previous surface of the same material 2187 modelSurf = &this->surfaces[mergeTo[ objectNum ]]; 2188 srfTriangles_t *mergeTri = modelSurf->geometry; 2189 if ( !mergeTri ) { 2190 modelSurf->geometry = tri; 2191 } else { 2192 modelSurf->geometry = R_MergeTriangles( mergeTri, tri ); 2193 R_FreeStaticTriSurf( tri ); 2194 R_FreeStaticTriSurf( mergeTri ); 2195 } 2196 } 2197 2198 return true; 2199 } 2200 2201 /* 2202 ================= 2203 idRenderModelStatic::LoadASE 2204 ================= 2205 */ 2206 bool idRenderModelStatic::LoadASE( const char *fileName ) { 2207 aseModel_t *ase; 2208 2209 ase = ASE_Load( fileName ); 2210 if ( ase == NULL ) { 2211 return false; 2212 } 2213 2214 ConvertASEToModelSurfaces( ase ); 2215 2216 ASE_Free( ase ); 2217 2218 return true; 2219 } 2220 2221 /* 2222 ================= 2223 idRenderModelStatic::LoadLWO 2224 ================= 2225 */ 2226 bool idRenderModelStatic::LoadLWO( const char *fileName ) { 2227 unsigned int failID; 2228 int failPos; 2229 lwObject *lwo; 2230 2231 lwo = lwGetObject( fileName, &failID, &failPos ); 2232 if ( lwo == NULL ) { 2233 return false; 2234 } 2235 2236 ConvertLWOToModelSurfaces( lwo ); 2237 2238 lwFreeObject( lwo ); 2239 2240 return true; 2241 } 2242 2243 /* 2244 ================= 2245 idRenderModelStatic::LoadMA 2246 ================= 2247 */ 2248 bool idRenderModelStatic::LoadMA( const char *fileName ) { 2249 maModel_t *ma; 2250 2251 ma = MA_Load( fileName ); 2252 if ( ma == NULL ) { 2253 return false; 2254 } 2255 2256 ConvertMAToModelSurfaces( ma ); 2257 2258 MA_Free( ma ); 2259 2260 return true; 2261 } 2262 2263 2264 //============================================================================= 2265 2266 /* 2267 ================ 2268 idRenderModelStatic::PurgeModel 2269 ================ 2270 */ 2271 void idRenderModelStatic::PurgeModel() { 2272 for ( int i = 0; i < surfaces.Num(); i++ ) { 2273 modelSurface_t * surf = &surfaces[i]; 2274 2275 if ( surf->geometry ) { 2276 R_FreeStaticTriSurf( surf->geometry ); 2277 } 2278 } 2279 surfaces.Clear(); 2280 2281 if ( jointsInverted != NULL ) { 2282 Mem_Free( jointsInverted ); 2283 jointsInverted = NULL; 2284 } 2285 2286 purged = true; 2287 } 2288 2289 /* 2290 ============== 2291 idRenderModelStatic::FreeVertexCache 2292 2293 We are about to restart the vertex cache, so dump everything 2294 ============== 2295 */ 2296 void idRenderModelStatic::FreeVertexCache() { 2297 for ( int j = 0; j < surfaces.Num(); j++ ) { 2298 srfTriangles_t *tri = surfaces[j].geometry; 2299 if ( tri == NULL ) { 2300 continue; 2301 } 2302 R_FreeStaticTriSurfVertexCaches( tri ); 2303 } 2304 } 2305 2306 /* 2307 ================ 2308 idRenderModelStatic::ReadFromDemoFile 2309 ================ 2310 */ 2311 void idRenderModelStatic::ReadFromDemoFile( class idDemoFile *f ) { 2312 PurgeModel(); 2313 2314 InitEmpty( f->ReadHashString() ); 2315 2316 int i, j, numSurfaces; 2317 f->ReadInt( numSurfaces ); 2318 2319 for ( i = 0; i < numSurfaces; i++ ) { 2320 modelSurface_t surf; 2321 2322 surf.shader = declManager->FindMaterial( f->ReadHashString() ); 2323 2324 srfTriangles_t *tri = R_AllocStaticTriSurf(); 2325 2326 f->ReadInt( tri->numIndexes ); 2327 R_AllocStaticTriSurfIndexes( tri, tri->numIndexes ); 2328 for ( j = 0; j < tri->numIndexes; ++j ) 2329 f->ReadInt( (int&)tri->indexes[j] ); 2330 2331 f->ReadInt( tri->numVerts ); 2332 R_AllocStaticTriSurfVerts( tri, tri->numVerts ); 2333 2334 idVec3 tNormal, tTangent, tBiTangent; 2335 for ( j = 0; j < tri->numVerts; ++j ) { 2336 f->ReadVec3( tri->verts[j].xyz ); 2337 f->ReadBigArray( tri->verts[j].st, 2 ); 2338 f->ReadBigArray( tri->verts[j].normal, 4 ); 2339 f->ReadBigArray( tri->verts[j].tangent, 4 ); 2340 f->ReadUnsignedChar( tri->verts[j].color[0] ); 2341 f->ReadUnsignedChar( tri->verts[j].color[1] ); 2342 f->ReadUnsignedChar( tri->verts[j].color[2] ); 2343 f->ReadUnsignedChar( tri->verts[j].color[3] ); 2344 } 2345 2346 surf.geometry = tri; 2347 2348 this->AddSurface( surf ); 2349 } 2350 this->FinishSurfaces(); 2351 } 2352 2353 /* 2354 ================ 2355 idRenderModelStatic::WriteToDemoFile 2356 ================ 2357 */ 2358 void idRenderModelStatic::WriteToDemoFile( class idDemoFile *f ) { 2359 int data[1]; 2360 2361 // note that it has been updated 2362 lastArchivedFrame = tr.frameCount; 2363 2364 data[0] = DC_DEFINE_MODEL; 2365 f->WriteInt( data[0] ); 2366 f->WriteHashString( this->Name() ); 2367 2368 int i, j, iData = surfaces.Num(); 2369 f->WriteInt( iData ); 2370 2371 for ( i = 0; i < surfaces.Num(); i++ ) { 2372 const modelSurface_t *surf = &surfaces[i]; 2373 2374 f->WriteHashString( surf->shader->GetName() ); 2375 2376 srfTriangles_t *tri = surf->geometry; 2377 f->WriteInt( tri->numIndexes ); 2378 for ( j = 0; j < tri->numIndexes; ++j ) 2379 f->WriteInt( (int&)tri->indexes[j] ); 2380 f->WriteInt( tri->numVerts ); 2381 for ( j = 0; j < tri->numVerts; ++j ) { 2382 f->WriteVec3( tri->verts[j].xyz ); 2383 f->WriteBigArray( tri->verts[j].st, 2 ); 2384 f->WriteBigArray( tri->verts[j].normal, 4 ); 2385 f->WriteBigArray( tri->verts[j].tangent, 4 ); 2386 f->WriteUnsignedChar( tri->verts[j].color[0] ); 2387 f->WriteUnsignedChar( tri->verts[j].color[1] ); 2388 f->WriteUnsignedChar( tri->verts[j].color[2] ); 2389 f->WriteUnsignedChar( tri->verts[j].color[3] ); 2390 } 2391 } 2392 } 2393 2394 /* 2395 ================ 2396 idRenderModelStatic::IsLoaded 2397 ================ 2398 */ 2399 bool idRenderModelStatic::IsLoaded() { 2400 return !purged; 2401 } 2402 2403 /* 2404 ================ 2405 idRenderModelStatic::SetLevelLoadReferenced 2406 ================ 2407 */ 2408 void idRenderModelStatic::SetLevelLoadReferenced( bool referenced ) { 2409 levelLoadReferenced = referenced; 2410 } 2411 2412 /* 2413 ================ 2414 idRenderModelStatic::IsLevelLoadReferenced 2415 ================ 2416 */ 2417 bool idRenderModelStatic::IsLevelLoadReferenced() { 2418 return levelLoadReferenced; 2419 } 2420 2421 /* 2422 ================= 2423 idRenderModelStatic::TouchData 2424 ================= 2425 */ 2426 void idRenderModelStatic::TouchData() { 2427 for ( int i = 0; i < surfaces.Num(); i++ ) { 2428 const modelSurface_t *surf = &surfaces[i]; 2429 2430 // re-find the material to make sure it gets added to the 2431 // level keep list 2432 declManager->FindMaterial( surf->shader->GetName() ); 2433 } 2434 } 2435 2436 /* 2437 ================= 2438 idRenderModelStatic::DeleteSurfaceWithId 2439 ================= 2440 */ 2441 bool idRenderModelStatic::DeleteSurfaceWithId( int id ) { 2442 int i; 2443 2444 for ( i = 0; i < surfaces.Num(); i++ ) { 2445 if ( surfaces[i].id == id ) { 2446 R_FreeStaticTriSurf( surfaces[i].geometry ); 2447 surfaces.RemoveIndex( i ); 2448 return true; 2449 } 2450 } 2451 return false; 2452 } 2453 2454 /* 2455 ================= 2456 idRenderModelStatic::DeleteSurfacesWithNegativeId 2457 ================= 2458 */ 2459 void idRenderModelStatic::DeleteSurfacesWithNegativeId() { 2460 for ( int i = 0; i < surfaces.Num(); i++ ) { 2461 if ( surfaces[i].id < 0 ) { 2462 R_FreeStaticTriSurf( surfaces[i].geometry ); 2463 surfaces.RemoveIndex( i ); 2464 i--; 2465 } 2466 } 2467 } 2468 2469 /* 2470 ================= 2471 idRenderModelStatic::FindSurfaceWithId 2472 ================= 2473 */ 2474 bool idRenderModelStatic::FindSurfaceWithId( int id, int &surfaceNum ) const { 2475 for ( int i = 0; i < surfaces.Num(); i++ ) { 2476 if ( surfaces[i].id == id ) { 2477 surfaceNum = i; 2478 return true; 2479 } 2480 } 2481 return false; 2482 }