RenderWorld_load.cpp (27901B)
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 34 35 /* 36 ================ 37 idRenderWorldLocal::FreeWorld 38 ================ 39 */ 40 void idRenderWorldLocal::FreeWorld() { 41 // this will free all the lightDefs and entityDefs 42 FreeDefs(); 43 44 // free all the portals and check light/model references 45 for ( int i = 0; i < numPortalAreas; i++ ) { 46 portalArea_t *area; 47 portal_t *portal, *nextPortal; 48 49 area = &portalAreas[i]; 50 for ( portal = area->portals; portal; portal = nextPortal ) { 51 nextPortal = portal->next; 52 delete portal->w; 53 R_StaticFree( portal ); 54 } 55 56 // there shouldn't be any remaining lightRefs or entityRefs 57 if ( area->lightRefs.areaNext != &area->lightRefs ) { 58 common->Error( "FreeWorld: unexpected remaining lightRefs" ); 59 } 60 if ( area->entityRefs.areaNext != &area->entityRefs ) { 61 common->Error( "FreeWorld: unexpected remaining entityRefs" ); 62 } 63 } 64 65 if ( portalAreas ) { 66 R_StaticFree( portalAreas ); 67 portalAreas = NULL; 68 numPortalAreas = 0; 69 R_StaticFree( areaScreenRect ); 70 areaScreenRect = NULL; 71 } 72 73 if ( doublePortals ) { 74 R_StaticFree( doublePortals ); 75 doublePortals = NULL; 76 numInterAreaPortals = 0; 77 } 78 79 if ( areaNodes ) { 80 R_StaticFree( areaNodes ); 81 areaNodes = NULL; 82 } 83 84 // free all the inline idRenderModels 85 for ( int i = 0; i < localModels.Num(); i++ ) { 86 renderModelManager->RemoveModel( localModels[i] ); 87 delete localModels[i]; 88 } 89 localModels.Clear(); 90 91 areaReferenceAllocator.Shutdown(); 92 interactionAllocator.Shutdown(); 93 94 mapName = "<FREED>"; 95 } 96 97 /* 98 ================ 99 idRenderWorldLocal::TouchWorldModels 100 ================ 101 */ 102 void idRenderWorldLocal::TouchWorldModels() { 103 for ( int i = 0; i < localModels.Num(); i++ ) { 104 renderModelManager->CheckModel( localModels[i]->Name() ); 105 } 106 } 107 108 /* 109 ================ 110 idRenderWorldLocal::ReadBinaryShadowModel 111 ================ 112 */ 113 idRenderModel *idRenderWorldLocal::ReadBinaryModel( idFile *fileIn ) { 114 idStrStatic< MAX_OSPATH > name; 115 fileIn->ReadString( name ); 116 idRenderModel * model = renderModelManager->AllocModel(); 117 model->InitEmpty( name ); 118 if ( model->LoadBinaryModel( fileIn, mapTimeStamp ) ) { 119 return model; 120 } 121 return NULL; 122 } 123 124 extern idCVar r_binaryLoadRenderModels; 125 126 /* 127 ================ 128 idRenderWorldLocal::ParseModel 129 ================ 130 */ 131 idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src, const char *mapName, ID_TIME_T mapTimeStamp, idFile *fileOut ) { 132 idToken token; 133 134 src->ExpectTokenString( "{" ); 135 136 // parse the name 137 src->ExpectAnyToken( &token ); 138 139 idRenderModel * model = renderModelManager->AllocModel(); 140 model->InitEmpty( token ); 141 142 if ( fileOut != NULL ) { 143 // write out the type so the binary reader knows what to instantiate 144 fileOut->WriteString( "shadowmodel" ); 145 fileOut->WriteString( token ); 146 } 147 148 int numSurfaces = src->ParseInt(); 149 if ( numSurfaces < 0 ) { 150 src->Error( "R_ParseModel: bad numSurfaces" ); 151 } 152 153 for ( int i = 0; i < numSurfaces; i++ ) { 154 src->ExpectTokenString( "{" ); 155 156 src->ExpectAnyToken( &token ); 157 158 modelSurface_t surf; 159 surf.shader = declManager->FindMaterial( token ); 160 161 ((idMaterial*)surf.shader)->AddReference(); 162 163 srfTriangles_t * tri = R_AllocStaticTriSurf(); 164 surf.geometry = tri; 165 166 tri->numVerts = src->ParseInt(); 167 tri->numIndexes = src->ParseInt(); 168 169 // parse the vertices 170 idTempArray<float> verts( tri->numVerts * 8 ); 171 for ( int j = 0; j < tri->numVerts; j++ ) { 172 src->Parse1DMatrix( 8, &verts[j * 8] ); 173 } 174 175 // parse the indices 176 idTempArray<triIndex_t> indexes( tri->numIndexes ); 177 for ( int j = 0; j < tri->numIndexes; j++ ) { 178 indexes[j] = src->ParseInt(); 179 } 180 181 #if 1 182 // find the island that each vertex belongs to 183 idTempArray<int> vertIslands( tri->numVerts ); 184 idTempArray<bool> trisVisited( tri->numIndexes ); 185 vertIslands.Zero(); 186 trisVisited.Zero(); 187 int numIslands = 0; 188 for ( int j = 0; j < tri->numIndexes; j += 3 ) { 189 if ( trisVisited[j] ) { 190 continue; 191 } 192 193 int islandNum = ++numIslands; 194 vertIslands[indexes[j + 0]] = islandNum; 195 vertIslands[indexes[j + 1]] = islandNum; 196 vertIslands[indexes[j + 2]] = islandNum; 197 trisVisited[j] = true; 198 199 idList<int> queue; 200 queue.Append( j ); 201 for ( int n = 0; n < queue.Num(); n++ ) { 202 int t = queue[n]; 203 for ( int k = 0; k < tri->numIndexes; k += 3 ) { 204 if ( trisVisited[k] ) { 205 continue; 206 } 207 bool connected = indexes[t + 0] == indexes[k + 0] || indexes[t + 0] == indexes[k + 1] || indexes[t + 0] == indexes[k + 2] || 208 indexes[t + 1] == indexes[k + 0] || indexes[t + 1] == indexes[k + 1] || indexes[t + 1] == indexes[k + 2] || 209 indexes[t + 2] == indexes[k + 0] || indexes[t + 2] == indexes[k + 1] || indexes[t + 2] == indexes[k + 2]; 210 if ( connected ) { 211 vertIslands[indexes[k + 0]] = islandNum; 212 vertIslands[indexes[k + 1]] = islandNum; 213 vertIslands[indexes[k + 2]] = islandNum; 214 trisVisited[k] = true; 215 queue.Append( k ); 216 } 217 } 218 } 219 } 220 221 // center the texture coordinates for each island for maximum 16-bit precision 222 for ( int j = 1; j <= numIslands; j++ ) { 223 float minS = idMath::INFINITY; 224 float minT = idMath::INFINITY; 225 float maxS = -idMath::INFINITY; 226 float maxT = -idMath::INFINITY; 227 for ( int k = 0; k < tri->numVerts; k++ ) { 228 if ( vertIslands[k] == j ) { 229 minS = Min( minS, verts[k * 8 + 3] ); 230 maxS = Max( maxS, verts[k * 8 + 3] ); 231 minT = Min( minT, verts[k * 8 + 4] ); 232 maxT = Max( maxT, verts[k * 8 + 4] ); 233 } 234 } 235 const float averageS = idMath::Ftoi( ( minS + maxS ) * 0.5f ); 236 const float averageT = idMath::Ftoi( ( minT + maxT ) * 0.5f ); 237 for ( int k = 0; k < tri->numVerts; k++ ) { 238 if ( vertIslands[k] == j ) { 239 verts[k * 8 + 3] -= averageS; 240 verts[k * 8 + 4] -= averageT; 241 } 242 } 243 } 244 #endif 245 246 R_AllocStaticTriSurfVerts( tri, tri->numVerts ); 247 for ( int j = 0; j < tri->numVerts; j++ ) { 248 tri->verts[j].xyz[0] = verts[j * 8 + 0]; 249 tri->verts[j].xyz[1] = verts[j * 8 + 1]; 250 tri->verts[j].xyz[2] = verts[j * 8 + 2]; 251 tri->verts[j].SetTexCoord( verts[j * 8 + 3], verts[j * 8 + 4] ); 252 tri->verts[j].SetNormal( verts[j * 8 + 5], verts[j * 8 + 6], verts[j * 8 + 7] ); 253 } 254 255 R_AllocStaticTriSurfIndexes( tri, tri->numIndexes ); 256 for ( int j = 0; j < tri->numIndexes; j++ ) { 257 tri->indexes[j] = indexes[j]; 258 } 259 src->ExpectTokenString( "}" ); 260 261 // add the completed surface to the model 262 model->AddSurface( surf ); 263 } 264 265 src->ExpectTokenString( "}" ); 266 267 model->FinishSurfaces(); 268 269 if ( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() ) { 270 model->WriteBinaryModel( fileOut, &mapTimeStamp ); 271 } 272 273 return model; 274 } 275 276 /* 277 ================ 278 idRenderWorldLocal::ReadBinaryShadowModel 279 ================ 280 */ 281 idRenderModel *idRenderWorldLocal::ReadBinaryShadowModel( idFile *fileIn ) { 282 idStrStatic< MAX_OSPATH > name; 283 fileIn->ReadString( name ); 284 idRenderModel * model = renderModelManager->AllocModel(); 285 model->InitEmpty( name ); 286 if ( model->LoadBinaryModel( fileIn, mapTimeStamp ) ) { 287 return model; 288 } 289 return NULL; 290 } 291 /* 292 ================ 293 idRenderWorldLocal::ParseShadowModel 294 ================ 295 */ 296 idRenderModel *idRenderWorldLocal::ParseShadowModel( idLexer *src, idFile *fileOut ) { 297 idToken token; 298 299 src->ExpectTokenString( "{" ); 300 301 // parse the name 302 src->ExpectAnyToken( &token ); 303 304 idRenderModel * model = renderModelManager->AllocModel(); 305 model->InitEmpty( token ); 306 307 if ( fileOut != NULL ) { 308 // write out the type so the binary reader knows what to instantiate 309 fileOut->WriteString( "shadowmodel" ); 310 fileOut->WriteString( token ); 311 } 312 313 srfTriangles_t * tri = R_AllocStaticTriSurf(); 314 315 tri->numVerts = src->ParseInt(); 316 tri->numShadowIndexesNoCaps = src->ParseInt(); 317 tri->numShadowIndexesNoFrontCaps = src->ParseInt(); 318 tri->numIndexes = src->ParseInt(); 319 tri->shadowCapPlaneBits = src->ParseInt(); 320 321 assert( ( tri->numVerts & 1 ) == 0 ); 322 323 R_AllocStaticTriSurfPreLightShadowVerts( tri, ALIGN( tri->numVerts, 2 ) ); 324 tri->bounds.Clear(); 325 for ( int j = 0; j < tri->numVerts; j++ ) { 326 float vec[8]; 327 328 src->Parse1DMatrix( 3, vec ); 329 tri->preLightShadowVertexes[j].xyzw[0] = vec[0]; 330 tri->preLightShadowVertexes[j].xyzw[1] = vec[1]; 331 tri->preLightShadowVertexes[j].xyzw[2] = vec[2]; 332 tri->preLightShadowVertexes[j].xyzw[3] = 1.0f; // no homogenous value 333 334 tri->bounds.AddPoint( tri->preLightShadowVertexes[j].xyzw.ToVec3() ); 335 } 336 // clear the last vertex if it wasn't stored 337 if ( ( tri->numVerts & 1 ) != 0 ) { 338 tri->preLightShadowVertexes[ALIGN( tri->numVerts, 2 ) - 1].xyzw.Zero(); 339 } 340 341 // to be consistent set the number of vertices to half the number of shadow vertices 342 tri->numVerts = ALIGN( tri->numVerts, 2 ) / 2; 343 344 R_AllocStaticTriSurfIndexes( tri, tri->numIndexes ); 345 for ( int j = 0; j < tri->numIndexes; j++ ) { 346 tri->indexes[j] = src->ParseInt(); 347 } 348 349 // add the completed surface to the model 350 modelSurface_t surf; 351 surf.id = 0; 352 surf.shader = tr.defaultMaterial; 353 surf.geometry = tri; 354 355 model->AddSurface( surf ); 356 357 src->ExpectTokenString( "}" ); 358 359 // NOTE: we do NOT do a model->FinishSurfaceces, because we don't need sil edges, planes, tangents, etc. 360 361 if ( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() ) { 362 model->WriteBinaryModel( fileOut, &mapTimeStamp ); 363 } 364 365 return model; 366 } 367 368 /* 369 ================ 370 idRenderWorldLocal::SetupAreaRefs 371 ================ 372 */ 373 void idRenderWorldLocal::SetupAreaRefs() { 374 connectedAreaNum = 0; 375 for ( int i = 0; i < numPortalAreas; i++ ) { 376 portalAreas[i].areaNum = i; 377 portalAreas[i].lightRefs.areaNext = 378 portalAreas[i].lightRefs.areaPrev = &portalAreas[i].lightRefs; 379 portalAreas[i].entityRefs.areaNext = 380 portalAreas[i].entityRefs.areaPrev = &portalAreas[i].entityRefs; 381 } 382 } 383 384 /* 385 ================ 386 idRenderWorldLocal::ParseInterAreaPortals 387 ================ 388 */ 389 void idRenderWorldLocal::ParseInterAreaPortals( idLexer *src, idFile *fileOut ) { 390 src->ExpectTokenString( "{" ); 391 392 numPortalAreas = src->ParseInt(); 393 if ( numPortalAreas < 0 ) { 394 src->Error( "R_ParseInterAreaPortals: bad numPortalAreas" ); 395 return; 396 } 397 398 if ( fileOut != NULL ) { 399 // write out the type so the binary reader knows what to instantiate 400 fileOut->WriteString( "interAreaPortals" ); 401 } 402 403 404 portalAreas = (portalArea_t *)R_ClearedStaticAlloc( numPortalAreas * sizeof( portalAreas[0] ) ); 405 areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( numPortalAreas * sizeof( idScreenRect ) ); 406 407 // set the doubly linked lists 408 SetupAreaRefs(); 409 410 numInterAreaPortals = src->ParseInt(); 411 if ( numInterAreaPortals < 0 ) { 412 src->Error( "R_ParseInterAreaPortals: bad numInterAreaPortals" ); 413 return; 414 } 415 416 if ( fileOut != NULL ) { 417 fileOut->WriteBig( numPortalAreas ); 418 fileOut->WriteBig( numInterAreaPortals ); 419 } 420 421 doublePortals = (doublePortal_t *)R_ClearedStaticAlloc( numInterAreaPortals * 422 sizeof( doublePortals [0] ) ); 423 424 for ( int i = 0; i < numInterAreaPortals; i++ ) { 425 int numPoints, a1, a2; 426 idWinding *w; 427 portal_t *p; 428 429 numPoints = src->ParseInt(); 430 a1 = src->ParseInt(); 431 a2 = src->ParseInt(); 432 433 if ( fileOut != NULL ) { 434 fileOut->WriteBig( numPoints ); 435 fileOut->WriteBig( a1 ); 436 fileOut->WriteBig( a2 ); 437 } 438 439 w = new (TAG_RENDER_WINDING) idWinding( numPoints ); 440 w->SetNumPoints( numPoints ); 441 for ( int j = 0; j < numPoints; j++ ) { 442 src->Parse1DMatrix( 3, (*w)[j].ToFloatPtr() ); 443 444 if ( fileOut != NULL ) { 445 fileOut->WriteBig( (*w)[j].x ); 446 fileOut->WriteBig( (*w)[j].y ); 447 fileOut->WriteBig( (*w)[j].z ); 448 } 449 // no texture coordinates 450 (*w)[j][3] = 0; 451 (*w)[j][4] = 0; 452 } 453 454 // add the portal to a1 455 p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) ); 456 p->intoArea = a2; 457 p->doublePortal = &doublePortals[i]; 458 p->w = w; 459 p->w->GetPlane( p->plane ); 460 461 p->next = portalAreas[a1].portals; 462 portalAreas[a1].portals = p; 463 464 doublePortals[i].portals[0] = p; 465 466 // reverse it for a2 467 p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) ); 468 p->intoArea = a1; 469 p->doublePortal = &doublePortals[i]; 470 p->w = w->Reverse(); 471 p->w->GetPlane( p->plane ); 472 473 p->next = portalAreas[a2].portals; 474 portalAreas[a2].portals = p; 475 476 doublePortals[i].portals[1] = p; 477 } 478 479 src->ExpectTokenString( "}" ); 480 } 481 482 /* 483 ================ 484 idRenderWorldLocal::ParseInterAreaPortals 485 ================ 486 */ 487 void idRenderWorldLocal::ReadBinaryAreaPortals( idFile *file ) { 488 489 file->ReadBig( numPortalAreas ); 490 file->ReadBig( numInterAreaPortals ); 491 492 portalAreas = (portalArea_t *)R_ClearedStaticAlloc( numPortalAreas * sizeof( portalAreas[0] ) ); 493 areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( numPortalAreas * sizeof( idScreenRect ) ); 494 495 // set the doubly linked lists 496 SetupAreaRefs(); 497 498 doublePortals = (doublePortal_t *)R_ClearedStaticAlloc( numInterAreaPortals * sizeof( doublePortals [0] ) ); 499 500 for ( int i = 0; i < numInterAreaPortals; i++ ) { 501 int numPoints, a1, a2; 502 idWinding *w; 503 portal_t *p; 504 505 file->ReadBig( numPoints ); 506 file->ReadBig( a1 ); 507 file->ReadBig( a2 ); 508 w = new (TAG_RENDER_WINDING) idWinding( numPoints ); 509 w->SetNumPoints( numPoints ); 510 for ( int j = 0; j < numPoints; j++ ) { 511 file->ReadBig( (*w)[ j ][ 0 ] ); 512 file->ReadBig( (*w)[ j ][ 1 ] ); 513 file->ReadBig( (*w)[ j ][ 2 ] ); 514 // no texture coordinates 515 (*w)[ j ][ 3 ] = 0; 516 (*w)[ j ][ 4 ] = 0; 517 } 518 519 // add the portal to a1 520 p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) ); 521 p->intoArea = a2; 522 p->doublePortal = &doublePortals[i]; 523 p->w = w; 524 p->w->GetPlane( p->plane ); 525 526 p->next = portalAreas[a1].portals; 527 portalAreas[a1].portals = p; 528 529 doublePortals[i].portals[0] = p; 530 531 // reverse it for a2 532 p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) ); 533 p->intoArea = a1; 534 p->doublePortal = &doublePortals[i]; 535 p->w = w->Reverse(); 536 p->w->GetPlane( p->plane ); 537 538 p->next = portalAreas[a2].portals; 539 portalAreas[a2].portals = p; 540 541 doublePortals[i].portals[1] = p; 542 } 543 } 544 545 546 /* 547 ================ 548 idRenderWorldLocal::ParseNodes 549 ================ 550 */ 551 void idRenderWorldLocal::ParseNodes( idLexer *src, idFile *fileOut ) { 552 src->ExpectTokenString( "{" ); 553 554 numAreaNodes = src->ParseInt(); 555 if ( numAreaNodes < 0 ) { 556 src->Error( "R_ParseNodes: bad numAreaNodes" ); 557 } 558 areaNodes = (areaNode_t *)R_ClearedStaticAlloc( numAreaNodes * sizeof( areaNodes[0] ) ); 559 560 if ( fileOut != NULL ) { 561 // write out the type so the binary reader knows what to instantiate 562 fileOut->WriteString( "nodes" ); 563 } 564 565 if ( fileOut != NULL ) { 566 fileOut->WriteBig( numAreaNodes ); 567 } 568 569 for ( int i = 0; i < numAreaNodes; i++ ) { 570 areaNode_t *node; 571 572 node = &areaNodes[i]; 573 574 src->Parse1DMatrix( 4, node->plane.ToFloatPtr() ); 575 576 node->children[0] = src->ParseInt(); 577 node->children[1] = src->ParseInt(); 578 579 if ( fileOut != NULL ) { 580 fileOut->WriteBig( node->plane[ 0 ] ); 581 fileOut->WriteBig( node->plane[ 1 ] ); 582 fileOut->WriteBig( node->plane[ 2 ] ); 583 fileOut->WriteBig( node->plane[ 3 ] ); 584 fileOut->WriteBig( node->children[ 0 ] ); 585 fileOut->WriteBig( node->children[ 1 ] ); 586 } 587 588 } 589 590 src->ExpectTokenString( "}" ); 591 } 592 593 /* 594 ================ 595 idRenderWorldLocal::ReadBinaryNodes 596 ================ 597 */ 598 void idRenderWorldLocal::ReadBinaryNodes( idFile * file ) { 599 file->ReadBig( numAreaNodes ); 600 areaNodes = (areaNode_t *)R_ClearedStaticAlloc( numAreaNodes * sizeof( areaNodes[0] ) ); 601 for ( int i = 0; i < numAreaNodes; i++ ) { 602 areaNode_t * node = &areaNodes[ i ]; 603 file->ReadBig( node->plane[ 0 ] ); 604 file->ReadBig( node->plane[ 1 ] ); 605 file->ReadBig( node->plane[ 2 ] ); 606 file->ReadBig( node->plane[ 3 ] ); 607 file->ReadBig( node->children[ 0 ] ); 608 file->ReadBig( node->children[ 1 ] ); 609 } 610 } 611 612 /* 613 ================ 614 idRenderWorldLocal::CommonChildrenArea_r 615 ================ 616 */ 617 int idRenderWorldLocal::CommonChildrenArea_r( areaNode_t *node ) { 618 int nums[2]; 619 620 for ( int i = 0; i < 2; i++ ) { 621 if ( node->children[i] <= 0 ) { 622 nums[i] = -1 - node->children[i]; 623 } else { 624 nums[i] = CommonChildrenArea_r( &areaNodes[ node->children[i] ] ); 625 } 626 } 627 628 // solid nodes will match any area 629 if ( nums[0] == AREANUM_SOLID ) { 630 nums[0] = nums[1]; 631 } 632 if ( nums[1] == AREANUM_SOLID ) { 633 nums[1] = nums[0]; 634 } 635 636 int common; 637 if ( nums[0] == nums[1] ) { 638 common = nums[0]; 639 } else { 640 common = CHILDREN_HAVE_MULTIPLE_AREAS; 641 } 642 643 node->commonChildrenArea = common; 644 645 return common; 646 } 647 648 /* 649 ================= 650 idRenderWorldLocal::ClearWorld 651 652 Sets up for a single area world 653 ================= 654 */ 655 void idRenderWorldLocal::ClearWorld() { 656 numPortalAreas = 1; 657 portalAreas = (portalArea_t *)R_ClearedStaticAlloc( sizeof( portalAreas[0] ) ); 658 areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( sizeof( idScreenRect ) ); 659 660 SetupAreaRefs(); 661 662 // even though we only have a single area, create a node 663 // that has both children pointing at it so we don't need to 664 // 665 areaNodes = (areaNode_t *)R_ClearedStaticAlloc( sizeof( areaNodes[0] ) ); 666 areaNodes[0].plane[3] = 1; 667 areaNodes[0].children[0] = -1; 668 areaNodes[0].children[1] = -1; 669 } 670 671 /* 672 ================= 673 idRenderWorldLocal::FreeDefs 674 675 dump all the interactions 676 ================= 677 */ 678 void idRenderWorldLocal::FreeDefs() { 679 generateAllInteractionsCalled = false; 680 681 if ( interactionTable ) { 682 R_StaticFree( interactionTable ); 683 interactionTable = NULL; 684 } 685 686 // free all lightDefs 687 for ( int i = 0; i < lightDefs.Num(); i++ ) { 688 idRenderLightLocal * light = lightDefs[i]; 689 if ( light != NULL && light->world == this ) { 690 FreeLightDef( i ); 691 lightDefs[i] = NULL; 692 } 693 } 694 695 // free all entityDefs 696 for ( int i = 0; i < entityDefs.Num(); i++ ) { 697 idRenderEntityLocal * mod = entityDefs[i]; 698 if ( mod != NULL && mod->world == this ) { 699 FreeEntityDef( i ); 700 entityDefs[i] = NULL; 701 } 702 } 703 704 // Reset decals and overlays 705 for ( int i = 0; i < decals.Num(); i++ ) { 706 decals[i].entityHandle = -1; 707 decals[i].lastStartTime = 0; 708 } 709 for ( int i = 0; i < overlays.Num(); i++ ) { 710 overlays[i].entityHandle = -1; 711 overlays[i].lastStartTime = 0; 712 } 713 } 714 715 /* 716 ================= 717 idRenderWorldLocal::InitFromMap 718 719 A NULL or empty name will make a world without a map model, which 720 is still useful for displaying a bare model 721 ================= 722 */ 723 bool idRenderWorldLocal::InitFromMap( const char *name ) { 724 idLexer * src; 725 idToken token; 726 idRenderModel * lastModel; 727 728 // if this is an empty world, initialize manually 729 if ( !name || !name[0] ) { 730 FreeWorld(); 731 mapName.Clear(); 732 ClearWorld(); 733 return true; 734 } 735 736 // load it 737 idStrStatic< MAX_OSPATH > filename = name; 738 filename.SetFileExtension( PROC_FILE_EXT ); 739 740 // check for generated file 741 idStrStatic< MAX_OSPATH > generatedFileName = filename; 742 generatedFileName.Insert( "generated/", 0 ); 743 generatedFileName.SetFileExtension( "bproc" ); 744 745 // if we are reloading the same map, check the timestamp 746 // and try to skip all the work 747 ID_TIME_T currentTimeStamp = fileSystem->GetTimestamp( filename ); 748 749 if ( name == mapName ) { 750 if ( fileSystem->InProductionMode() || ( currentTimeStamp != FILE_NOT_FOUND_TIMESTAMP && currentTimeStamp == mapTimeStamp ) ) { 751 common->Printf( "idRenderWorldLocal::InitFromMap: retaining existing map\n" ); 752 FreeDefs(); 753 TouchWorldModels(); 754 AddWorldModelEntities(); 755 ClearPortalStates(); 756 return true; 757 } 758 common->Printf( "idRenderWorldLocal::InitFromMap: timestamp has changed, reloading.\n" ); 759 } 760 761 FreeWorld(); 762 763 // see if we have a generated version of this 764 static const byte BPROC_VERSION = 1; 765 static const unsigned int BPROC_MAGIC = ( 'P' << 24 ) | ( 'R' << 16 ) | ( 'O' << 8 ) | BPROC_VERSION; 766 bool loaded = false; 767 idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) ); 768 if ( file != NULL ) { 769 int numEntries = 0; 770 int magic = 0; 771 file->ReadBig( magic ); 772 if ( magic == BPROC_MAGIC ) { 773 file->ReadBig( numEntries ); 774 file->ReadString( mapName ); 775 file->ReadBig( mapTimeStamp ); 776 loaded = true; 777 for ( int i = 0; i < numEntries; i++ ) { 778 idStrStatic< MAX_OSPATH > type; 779 file->ReadString( type ); 780 type.ToLower(); 781 if ( type == "model" ) { 782 idRenderModel * lastModel = ReadBinaryModel( file ); 783 if ( lastModel == NULL ) { 784 loaded = false; 785 break; 786 } 787 renderModelManager->AddModel( lastModel ); 788 localModels.Append( lastModel ); 789 } else if ( type == "shadowmodel" ) { 790 idRenderModel * lastModel = ReadBinaryModel( file ); 791 if ( lastModel == NULL ) { 792 loaded = false; 793 break; 794 } 795 renderModelManager->AddModel( lastModel ); 796 localModels.Append( lastModel ); 797 } else if ( type == "interareaportals" ) { 798 ReadBinaryAreaPortals( file ); 799 } else if ( type == "nodes" ) { 800 ReadBinaryNodes( file ); 801 } else { 802 idLib::Error( "Binary proc file failed, unexpected type %s\n", type.c_str() ); 803 } 804 } 805 } 806 } 807 808 if ( !loaded ) { 809 810 src = new (TAG_RENDER) idLexer( filename, LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE ); 811 if ( !src->IsLoaded() ) { 812 common->Printf( "idRenderWorldLocal::InitFromMap: %s not found\n", filename.c_str() ); 813 ClearWorld(); 814 return false; 815 } 816 817 818 mapName = name; 819 mapTimeStamp = currentTimeStamp; 820 821 // if we are writing a demo, archive the load command 822 if ( common->WriteDemo() ) { 823 WriteLoadMap(); 824 } 825 826 if ( !src->ReadToken( &token ) || token.Icmp( PROC_FILE_ID ) ) { 827 common->Printf( "idRenderWorldLocal::InitFromMap: bad id '%s' instead of '%s'\n", token.c_str(), PROC_FILE_ID ); 828 delete src; 829 return false; 830 } 831 832 int numEntries = 0; 833 idFileLocal outputFile( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) ); 834 if ( outputFile != NULL ) { 835 int magic = BPROC_MAGIC; 836 outputFile->WriteBig( magic ); 837 outputFile->WriteBig( numEntries ); 838 outputFile->WriteString( mapName ); 839 outputFile->WriteBig( mapTimeStamp ); 840 } 841 842 // parse the file 843 while ( 1 ) { 844 if ( !src->ReadToken( &token ) ) { 845 break; 846 } 847 848 common->UpdateLevelLoadPacifier(); 849 850 851 if ( token == "model" ) { 852 lastModel = ParseModel( src, name, currentTimeStamp, outputFile ); 853 854 // add it to the model manager list 855 renderModelManager->AddModel( lastModel ); 856 857 // save it in the list to free when clearing this map 858 localModels.Append( lastModel ); 859 860 numEntries++; 861 862 continue; 863 } 864 865 if ( token == "shadowModel" ) { 866 lastModel = ParseShadowModel( src, outputFile ); 867 868 // add it to the model manager list 869 renderModelManager->AddModel( lastModel ); 870 871 // save it in the list to free when clearing this map 872 localModels.Append( lastModel ); 873 874 numEntries++; 875 continue; 876 } 877 878 if ( token == "interAreaPortals" ) { 879 ParseInterAreaPortals( src, outputFile ); 880 881 numEntries++; 882 continue; 883 } 884 885 if ( token == "nodes" ) { 886 ParseNodes( src, outputFile ); 887 888 numEntries++; 889 continue; 890 } 891 892 src->Error( "idRenderWorldLocal::InitFromMap: bad token \"%s\"", token.c_str() ); 893 } 894 895 delete src; 896 897 if ( outputFile != NULL ) { 898 outputFile->Seek( 0, FS_SEEK_SET ); 899 int magic = BPROC_MAGIC; 900 outputFile->WriteBig( magic ); 901 outputFile->WriteBig( numEntries ); 902 } 903 904 } 905 906 907 908 // if it was a trivial map without any areas, create a single area 909 if ( !numPortalAreas ) { 910 ClearWorld(); 911 } 912 913 // find the points where we can early-our of reference pushing into the BSP tree 914 CommonChildrenArea_r( &areaNodes[0] ); 915 916 AddWorldModelEntities(); 917 ClearPortalStates(); 918 919 // done! 920 return true; 921 } 922 923 /* 924 ===================== 925 idRenderWorldLocal::ClearPortalStates 926 ===================== 927 */ 928 void idRenderWorldLocal::ClearPortalStates() { 929 // all portals start off open 930 for ( int i = 0; i < numInterAreaPortals; i++ ) { 931 doublePortals[i].blockingBits = PS_BLOCK_NONE; 932 } 933 934 // flood fill all area connections 935 for ( int i = 0; i < numPortalAreas; i++ ) { 936 for ( int j = 0; j < NUM_PORTAL_ATTRIBUTES; j++ ) { 937 connectedAreaNum++; 938 FloodConnectedAreas( &portalAreas[i], j ); 939 } 940 } 941 } 942 943 /* 944 ===================== 945 idRenderWorldLocal::AddWorldModelEntities 946 ===================== 947 */ 948 void idRenderWorldLocal::AddWorldModelEntities() { 949 // add the world model for each portal area 950 // we can't just call AddEntityDef, because that would place the references 951 // based on the bounding box, rather than explicitly into the correct area 952 for ( int i = 0; i < numPortalAreas; i++ ) { 953 common->UpdateLevelLoadPacifier(); 954 955 956 idRenderEntityLocal * def = new (TAG_RENDER_ENTITY) idRenderEntityLocal; 957 958 // try and reuse a free spot 959 int index = entityDefs.FindNull(); 960 if ( index == -1 ) { 961 index = entityDefs.Append(def); 962 } else { 963 entityDefs[index] = def; 964 } 965 966 def->index = index; 967 def->world = this; 968 969 def->parms.hModel = renderModelManager->FindModel( va("_area%i", i ) ); 970 if ( def->parms.hModel->IsDefaultModel() || !def->parms.hModel->IsStaticWorldModel() ) { 971 common->Error( "idRenderWorldLocal::InitFromMap: bad area model lookup" ); 972 } 973 974 idRenderModel *hModel = def->parms.hModel; 975 976 for ( int j = 0; j < hModel->NumSurfaces(); j++ ) { 977 const modelSurface_t *surf = hModel->Surface( j ); 978 979 if ( surf->shader->GetName() == idStr( "textures/smf/portal_sky" ) ) { 980 def->needsPortalSky = true; 981 } 982 } 983 984 // the local and global reference bounds are the same for area models 985 def->localReferenceBounds = def->parms.hModel->Bounds(); 986 def->globalReferenceBounds = def->parms.hModel->Bounds(); 987 988 def->parms.axis[0][0] = 1.0f; 989 def->parms.axis[1][1] = 1.0f; 990 def->parms.axis[2][2] = 1.0f; 991 992 // in case an explicit shader is used on the world, we don't 993 // want it to have a 0 alpha or color 994 def->parms.shaderParms[0] = 1.0f; 995 def->parms.shaderParms[1] = 1.0f; 996 def->parms.shaderParms[2] = 1.0f; 997 def->parms.shaderParms[3] = 1.0f; 998 999 R_DeriveEntityData( def ); 1000 1001 AddEntityRefToArea( def, &portalAreas[i] ); 1002 } 1003 } 1004 1005 /* 1006 ===================== 1007 CheckAreaForPortalSky 1008 ===================== 1009 */ 1010 bool idRenderWorldLocal::CheckAreaForPortalSky( int areaNum ) { 1011 assert( areaNum >= 0 && areaNum < numPortalAreas ); 1012 1013 for ( areaReference_t * ref = portalAreas[areaNum].entityRefs.areaNext; ref->entity; ref = ref->areaNext ) { 1014 assert( ref->area == &portalAreas[areaNum] ); 1015 1016 if ( ref->entity && ref->entity->needsPortalSky ) { 1017 return true; 1018 } 1019 } 1020 1021 return false; 1022 } 1023 1024 /* 1025 ===================== 1026 ResetLocalRenderModels 1027 ===================== 1028 */ 1029 void idRenderWorldLocal::ResetLocalRenderModels() { 1030 localModels.Clear(); // Clear out the list when switching between expansion packs, so InitFromMap doesn't try to delete the list whose content has already been deleted by the model manager being re-started 1031 }