2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
37 idRenderWorldLocal::FreeWorld
40 void idRenderWorldLocal::FreeWorld() {
43 // this will free all the lightDefs and entityDefs
46 // free all the portals and check light/model references
47 for ( i = 0 ; i < numPortalAreas ; i++ ) {
49 portal_t *portal, *nextPortal;
51 area = &portalAreas[i];
52 for ( portal = area->portals ; portal ; portal = nextPortal ) {
53 nextPortal = portal->next;
55 R_StaticFree( portal );
58 // there shouldn't be any remaining lightRefs or entityRefs
59 if ( area->lightRefs.areaNext != &area->lightRefs ) {
60 common->Error( "FreeWorld: unexpected remaining lightRefs" );
62 if ( area->entityRefs.areaNext != &area->entityRefs ) {
63 common->Error( "FreeWorld: unexpected remaining entityRefs" );
68 R_StaticFree( portalAreas );
71 R_StaticFree( areaScreenRect );
72 areaScreenRect = NULL;
75 if ( doublePortals ) {
76 R_StaticFree( doublePortals );
78 numInterAreaPortals = 0;
82 R_StaticFree( areaNodes );
86 // free all the inline idRenderModels
87 for ( i = 0 ; i < localModels.Num() ; i++ ) {
88 renderModelManager->RemoveModel( localModels[i] );
89 delete localModels[i];
93 areaReferenceAllocator.Shutdown();
94 interactionAllocator.Shutdown();
95 areaNumRefAllocator.Shutdown();
102 idRenderWorldLocal::TouchWorldModels
105 void idRenderWorldLocal::TouchWorldModels( void ) {
108 for ( i = 0 ; i < localModels.Num() ; i++ ) {
109 renderModelManager->CheckModel( localModels[i]->Name() );
115 idRenderWorldLocal::ParseModel
118 idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) {
119 idRenderModel *model;
125 src->ExpectTokenString( "{" );
128 src->ExpectAnyToken( &token );
130 model = renderModelManager->AllocModel();
131 model->InitEmpty( token );
133 int numSurfaces = src->ParseInt();
134 if ( numSurfaces < 0 ) {
135 src->Error( "R_ParseModel: bad numSurfaces" );
138 for ( i = 0 ; i < numSurfaces ; i++ ) {
139 src->ExpectTokenString( "{" );
141 src->ExpectAnyToken( &token );
143 surf.shader = declManager->FindMaterial( token );
145 ((idMaterial*)surf.shader)->AddReference();
147 tri = R_AllocStaticTriSurf();
150 tri->numVerts = src->ParseInt();
151 tri->numIndexes = src->ParseInt();
153 R_AllocStaticTriSurfVerts( tri, tri->numVerts );
154 for ( j = 0 ; j < tri->numVerts ; j++ ) {
157 src->Parse1DMatrix( 8, vec );
159 tri->verts[j].xyz[0] = vec[0];
160 tri->verts[j].xyz[1] = vec[1];
161 tri->verts[j].xyz[2] = vec[2];
162 tri->verts[j].st[0] = vec[3];
163 tri->verts[j].st[1] = vec[4];
164 tri->verts[j].normal[0] = vec[5];
165 tri->verts[j].normal[1] = vec[6];
166 tri->verts[j].normal[2] = vec[7];
169 R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
170 for ( j = 0 ; j < tri->numIndexes ; j++ ) {
171 tri->indexes[j] = src->ParseInt();
173 src->ExpectTokenString( "}" );
175 // add the completed surface to the model
176 model->AddSurface( surf );
179 src->ExpectTokenString( "}" );
181 model->FinishSurfaces();
188 idRenderWorldLocal::ParseShadowModel
191 idRenderModel *idRenderWorldLocal::ParseShadowModel( idLexer *src ) {
192 idRenderModel *model;
198 src->ExpectTokenString( "{" );
201 src->ExpectAnyToken( &token );
203 model = renderModelManager->AllocModel();
204 model->InitEmpty( token );
206 surf.shader = tr.defaultMaterial;
208 tri = R_AllocStaticTriSurf();
211 tri->numVerts = src->ParseInt();
212 tri->numShadowIndexesNoCaps = src->ParseInt();
213 tri->numShadowIndexesNoFrontCaps = src->ParseInt();
214 tri->numIndexes = src->ParseInt();
215 tri->shadowCapPlaneBits = src->ParseInt();
217 R_AllocStaticTriSurfShadowVerts( tri, tri->numVerts );
219 for ( j = 0 ; j < tri->numVerts ; j++ ) {
222 src->Parse1DMatrix( 3, vec );
223 tri->shadowVertexes[j].xyz[0] = vec[0];
224 tri->shadowVertexes[j].xyz[1] = vec[1];
225 tri->shadowVertexes[j].xyz[2] = vec[2];
226 tri->shadowVertexes[j].xyz[3] = 1; // no homogenous value
228 tri->bounds.AddPoint( tri->shadowVertexes[j].xyz.ToVec3() );
231 R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
232 for ( j = 0 ; j < tri->numIndexes ; j++ ) {
233 tri->indexes[j] = src->ParseInt();
236 // add the completed surface to the model
237 model->AddSurface( surf );
239 src->ExpectTokenString( "}" );
241 // we do NOT do a model->FinishSurfaceces, because we don't need sil edges, planes, tangents, etc.
242 // model->FinishSurfaces();
249 idRenderWorldLocal::SetupAreaRefs
252 void idRenderWorldLocal::SetupAreaRefs() {
255 connectedAreaNum = 0;
256 for ( i = 0 ; i < numPortalAreas ; i++ ) {
257 portalAreas[i].areaNum = i;
258 portalAreas[i].lightRefs.areaNext =
259 portalAreas[i].lightRefs.areaPrev =
260 &portalAreas[i].lightRefs;
261 portalAreas[i].entityRefs.areaNext =
262 portalAreas[i].entityRefs.areaPrev =
263 &portalAreas[i].entityRefs;
269 idRenderWorldLocal::ParseInterAreaPortals
272 void idRenderWorldLocal::ParseInterAreaPortals( idLexer *src ) {
275 src->ExpectTokenString( "{" );
277 numPortalAreas = src->ParseInt();
278 if ( numPortalAreas < 0 ) {
279 src->Error( "R_ParseInterAreaPortals: bad numPortalAreas" );
282 portalAreas = (portalArea_t *)R_ClearedStaticAlloc( numPortalAreas * sizeof( portalAreas[0] ) );
283 areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( numPortalAreas * sizeof( idScreenRect ) );
285 // set the doubly linked lists
288 numInterAreaPortals = src->ParseInt();
289 if ( numInterAreaPortals < 0 ) {
290 src->Error( "R_ParseInterAreaPortals: bad numInterAreaPortals" );
294 doublePortals = (doublePortal_t *)R_ClearedStaticAlloc( numInterAreaPortals *
295 sizeof( doublePortals [0] ) );
297 for ( i = 0 ; i < numInterAreaPortals ; i++ ) {
298 int numPoints, a1, a2;
302 numPoints = src->ParseInt();
303 a1 = src->ParseInt();
304 a2 = src->ParseInt();
306 w = new idWinding( numPoints );
307 w->SetNumPoints( numPoints );
308 for ( j = 0 ; j < numPoints ; j++ ) {
309 src->Parse1DMatrix( 3, (*w)[j].ToFloatPtr() );
310 // no texture coordinates
315 // add the portal to a1
316 p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) );
318 p->doublePortal = &doublePortals[i];
320 p->w->GetPlane( p->plane );
322 p->next = portalAreas[a1].portals;
323 portalAreas[a1].portals = p;
325 doublePortals[i].portals[0] = p;
328 p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) );
330 p->doublePortal = &doublePortals[i];
332 p->w->GetPlane( p->plane );
334 p->next = portalAreas[a2].portals;
335 portalAreas[a2].portals = p;
337 doublePortals[i].portals[1] = p;
340 src->ExpectTokenString( "}" );
345 idRenderWorldLocal::ParseNodes
348 void idRenderWorldLocal::ParseNodes( idLexer *src ) {
351 src->ExpectTokenString( "{" );
353 numAreaNodes = src->ParseInt();
354 if ( numAreaNodes < 0 ) {
355 src->Error( "R_ParseNodes: bad numAreaNodes" );
357 areaNodes = (areaNode_t *)R_ClearedStaticAlloc( numAreaNodes * sizeof( areaNodes[0] ) );
359 for ( i = 0 ; i < numAreaNodes ; i++ ) {
362 node = &areaNodes[i];
364 src->Parse1DMatrix( 4, node->plane.ToFloatPtr() );
365 node->children[0] = src->ParseInt();
366 node->children[1] = src->ParseInt();
369 src->ExpectTokenString( "}" );
374 idRenderWorldLocal::CommonChildrenArea_r
377 int idRenderWorldLocal::CommonChildrenArea_r( areaNode_t *node ) {
380 for ( int i = 0 ; i < 2 ; i++ ) {
381 if ( node->children[i] <= 0 ) {
382 nums[i] = -1 - node->children[i];
384 nums[i] = CommonChildrenArea_r( &areaNodes[ node->children[i] ] );
388 // solid nodes will match any area
389 if ( nums[0] == AREANUM_SOLID ) {
392 if ( nums[1] == AREANUM_SOLID ) {
397 if ( nums[0] == nums[1] ) {
400 common = CHILDREN_HAVE_MULTIPLE_AREAS;
403 node->commonChildrenArea = common;
410 idRenderWorldLocal::ClearWorld
412 Sets up for a single area world
415 void idRenderWorldLocal::ClearWorld() {
417 portalAreas = (portalArea_t *)R_ClearedStaticAlloc( sizeof( portalAreas[0] ) );
418 areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( sizeof( idScreenRect ) );
422 // even though we only have a single area, create a node
423 // that has both children pointing at it so we don't need to
425 areaNodes = (areaNode_t *)R_ClearedStaticAlloc( sizeof( areaNodes[0] ) );
426 areaNodes[0].plane[3] = 1;
427 areaNodes[0].children[0] = -1;
428 areaNodes[0].children[1] = -1;
433 idRenderWorldLocal::FreeDefs
435 dump all the interactions
438 void idRenderWorldLocal::FreeDefs() {
441 generateAllInteractionsCalled = false;
443 if ( interactionTable ) {
444 R_StaticFree( interactionTable );
445 interactionTable = NULL;
448 // free all lightDefs
449 for ( i = 0 ; i < lightDefs.Num() ; i++ ) {
450 idRenderLightLocal *light;
452 light = lightDefs[i];
453 if ( light && light->world == this ) {
459 // free all entityDefs
460 for ( i = 0 ; i < entityDefs.Num() ; i++ ) {
461 idRenderEntityLocal *mod;
464 if ( mod && mod->world == this ) {
466 entityDefs[i] = NULL;
473 idRenderWorldLocal::InitFromMap
475 A NULL or empty name will make a world without a map model, which
476 is still useful for displaying a bare model
479 bool idRenderWorldLocal::InitFromMap( const char *name ) {
483 idRenderModel * lastModel;
485 // if this is an empty world, initialize manually
486 if ( !name || !name[0] ) {
496 filename.SetFileExtension( PROC_FILE_EXT );
498 // if we are reloading the same map, check the timestamp
499 // and try to skip all the work
500 ID_TIME_T currentTimeStamp;
501 fileSystem->ReadFile( filename, NULL, ¤tTimeStamp );
503 if ( name == mapName ) {
504 if ( currentTimeStamp != FILE_NOT_FOUND_TIMESTAMP && currentTimeStamp == mapTimeStamp ) {
505 common->Printf( "idRenderWorldLocal::InitFromMap: retaining existing map\n" );
508 AddWorldModelEntities();
512 common->Printf( "idRenderWorldLocal::InitFromMap: timestamp has changed, reloading.\n" );
517 src = new idLexer( filename, LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
518 if ( !src->IsLoaded() ) {
519 common->Printf( "idRenderWorldLocal::InitFromMap: %s not found\n", filename.c_str() );
526 mapTimeStamp = currentTimeStamp;
528 // if we are writing a demo, archive the load command
529 if ( session->writeDemo ) {
533 if ( !src->ReadToken( &token ) || token.Icmp( PROC_FILE_ID ) ) {
534 common->Printf( "idRenderWorldLocal::InitFromMap: bad id '%s' instead of '%s'\n", token.c_str(), PROC_FILE_ID );
541 if ( !src->ReadToken( &token ) ) {
545 if ( token == "model" ) {
546 lastModel = ParseModel( src );
548 // add it to the model manager list
549 renderModelManager->AddModel( lastModel );
551 // save it in the list to free when clearing this map
552 localModels.Append( lastModel );
556 if ( token == "shadowModel" ) {
557 lastModel = ParseShadowModel( src );
559 // add it to the model manager list
560 renderModelManager->AddModel( lastModel );
562 // save it in the list to free when clearing this map
563 localModels.Append( lastModel );
567 if ( token == "interAreaPortals" ) {
568 ParseInterAreaPortals( src );
572 if ( token == "nodes" ) {
577 src->Error( "idRenderWorldLocal::InitFromMap: bad token \"%s\"", token.c_str() );
582 // if it was a trivial map without any areas, create a single area
583 if ( !numPortalAreas ) {
587 // find the points where we can early-our of reference pushing into the BSP tree
588 CommonChildrenArea_r( &areaNodes[0] );
590 AddWorldModelEntities();
598 =====================
599 idRenderWorldLocal::ClearPortalStates
600 =====================
602 void idRenderWorldLocal::ClearPortalStates() {
605 // all portals start off open
606 for ( i = 0 ; i < numInterAreaPortals ; i++ ) {
607 doublePortals[i].blockingBits = PS_BLOCK_NONE;
610 // flood fill all area connections
611 for ( i = 0 ; i < numPortalAreas ; i++ ) {
612 for ( j = 0 ; j < NUM_PORTAL_ATTRIBUTES ; j++ ) {
614 FloodConnectedAreas( &portalAreas[i], j );
620 =====================
621 idRenderWorldLocal::AddWorldModelEntities
622 =====================
624 void idRenderWorldLocal::AddWorldModelEntities() {
627 // add the world model for each portal area
628 // we can't just call AddEntityDef, because that would place the references
629 // based on the bounding box, rather than explicitly into the correct area
630 for ( i = 0 ; i < numPortalAreas ; i++ ) {
631 idRenderEntityLocal *def;
634 def = new idRenderEntityLocal;
636 // try and reuse a free spot
637 index = entityDefs.FindNull();
639 index = entityDefs.Append(def);
641 entityDefs[index] = def;
647 def->parms.hModel = renderModelManager->FindModel( va("_area%i", i ) );
648 if ( def->parms.hModel->IsDefaultModel() || !def->parms.hModel->IsStaticWorldModel() ) {
649 common->Error( "idRenderWorldLocal::InitFromMap: bad area model lookup" );
652 idRenderModel *hModel = def->parms.hModel;
654 for ( int j = 0; j < hModel->NumSurfaces(); j++ ) {
655 const modelSurface_t *surf = hModel->Surface( j );
657 if ( surf->shader->GetName() == idStr( "textures/smf/portal_sky" ) ) {
658 def->needsPortalSky = true;
662 def->referenceBounds = def->parms.hModel->Bounds();
664 def->parms.axis[0][0] = 1;
665 def->parms.axis[1][1] = 1;
666 def->parms.axis[2][2] = 1;
668 R_AxisToModelMatrix( def->parms.axis, def->parms.origin, def->modelMatrix );
670 // in case an explicit shader is used on the world, we don't
671 // want it to have a 0 alpha or color
672 def->parms.shaderParms[0] =
673 def->parms.shaderParms[1] =
674 def->parms.shaderParms[2] =
675 def->parms.shaderParms[3] = 1;
677 AddEntityRefToArea( def, &portalAreas[i] );
682 =====================
683 CheckAreaForPortalSky
684 =====================
686 bool idRenderWorldLocal::CheckAreaForPortalSky( int areaNum ) {
687 areaReference_t *ref;
689 assert( areaNum >= 0 && areaNum < numPortalAreas );
691 for ( ref = portalAreas[areaNum].entityRefs.areaNext; ref->entity; ref = ref->areaNext ) {
692 assert( ref->area == &portalAreas[areaNum] );
694 if ( ref->entity && ref->entity->needsPortalSky ) {