123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "tr_local.h"
- /*
- ================
- idRenderWorldLocal::FreeWorld
- ================
- */
- void idRenderWorldLocal::FreeWorld() {
- int i;
- // this will free all the lightDefs and entityDefs
- FreeDefs();
- // free all the portals and check light/model references
- for ( i = 0 ; i < numPortalAreas ; i++ ) {
- portalArea_t *area;
- portal_t *portal, *nextPortal;
- area = &portalAreas[i];
- for ( portal = area->portals ; portal ; portal = nextPortal ) {
- nextPortal = portal->next;
- delete portal->w;
- R_StaticFree( portal );
- }
- // there shouldn't be any remaining lightRefs or entityRefs
- if ( area->lightRefs.areaNext != &area->lightRefs ) {
- common->Error( "FreeWorld: unexpected remaining lightRefs" );
- }
- if ( area->entityRefs.areaNext != &area->entityRefs ) {
- common->Error( "FreeWorld: unexpected remaining entityRefs" );
- }
- }
- if ( portalAreas ) {
- R_StaticFree( portalAreas );
- portalAreas = NULL;
- numPortalAreas = 0;
- R_StaticFree( areaScreenRect );
- areaScreenRect = NULL;
- }
- if ( doublePortals ) {
- R_StaticFree( doublePortals );
- doublePortals = NULL;
- numInterAreaPortals = 0;
- }
- if ( areaNodes ) {
- R_StaticFree( areaNodes );
- areaNodes = NULL;
- }
- // free all the inline idRenderModels
- for ( i = 0 ; i < localModels.Num() ; i++ ) {
- renderModelManager->RemoveModel( localModels[i] );
- delete localModels[i];
- }
- localModels.Clear();
- areaReferenceAllocator.Shutdown();
- interactionAllocator.Shutdown();
- areaNumRefAllocator.Shutdown();
- mapName = "<FREED>";
- }
- /*
- ================
- idRenderWorldLocal::TouchWorldModels
- ================
- */
- void idRenderWorldLocal::TouchWorldModels( void ) {
- int i;
- for ( i = 0 ; i < localModels.Num() ; i++ ) {
- renderModelManager->CheckModel( localModels[i]->Name() );
- }
- }
- /*
- ================
- idRenderWorldLocal::ParseModel
- ================
- */
- idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) {
- idRenderModel *model;
- idToken token;
- int i, j;
- srfTriangles_t *tri;
- modelSurface_t surf;
- src->ExpectTokenString( "{" );
- // parse the name
- src->ExpectAnyToken( &token );
- model = renderModelManager->AllocModel();
- model->InitEmpty( token );
- int numSurfaces = src->ParseInt();
- if ( numSurfaces < 0 ) {
- src->Error( "R_ParseModel: bad numSurfaces" );
- }
- for ( i = 0 ; i < numSurfaces ; i++ ) {
- src->ExpectTokenString( "{" );
- src->ExpectAnyToken( &token );
- surf.shader = declManager->FindMaterial( token );
- ((idMaterial*)surf.shader)->AddReference();
- tri = R_AllocStaticTriSurf();
- surf.geometry = tri;
- tri->numVerts = src->ParseInt();
- tri->numIndexes = src->ParseInt();
- R_AllocStaticTriSurfVerts( tri, tri->numVerts );
- for ( j = 0 ; j < tri->numVerts ; j++ ) {
- float vec[8];
- src->Parse1DMatrix( 8, vec );
- tri->verts[j].xyz[0] = vec[0];
- tri->verts[j].xyz[1] = vec[1];
- tri->verts[j].xyz[2] = vec[2];
- tri->verts[j].st[0] = vec[3];
- tri->verts[j].st[1] = vec[4];
- tri->verts[j].normal[0] = vec[5];
- tri->verts[j].normal[1] = vec[6];
- tri->verts[j].normal[2] = vec[7];
- }
- R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
- for ( j = 0 ; j < tri->numIndexes ; j++ ) {
- tri->indexes[j] = src->ParseInt();
- }
- src->ExpectTokenString( "}" );
- // add the completed surface to the model
- model->AddSurface( surf );
- }
- src->ExpectTokenString( "}" );
- model->FinishSurfaces();
- return model;
- }
- /*
- ================
- idRenderWorldLocal::ParseShadowModel
- ================
- */
- idRenderModel *idRenderWorldLocal::ParseShadowModel( idLexer *src ) {
- idRenderModel *model;
- idToken token;
- int j;
- srfTriangles_t *tri;
- modelSurface_t surf;
- src->ExpectTokenString( "{" );
- // parse the name
- src->ExpectAnyToken( &token );
- model = renderModelManager->AllocModel();
- model->InitEmpty( token );
- surf.shader = tr.defaultMaterial;
- tri = R_AllocStaticTriSurf();
- surf.geometry = tri;
- tri->numVerts = src->ParseInt();
- tri->numShadowIndexesNoCaps = src->ParseInt();
- tri->numShadowIndexesNoFrontCaps = src->ParseInt();
- tri->numIndexes = src->ParseInt();
- tri->shadowCapPlaneBits = src->ParseInt();
- R_AllocStaticTriSurfShadowVerts( tri, tri->numVerts );
- tri->bounds.Clear();
- for ( j = 0 ; j < tri->numVerts ; j++ ) {
- float vec[8];
- src->Parse1DMatrix( 3, vec );
- tri->shadowVertexes[j].xyz[0] = vec[0];
- tri->shadowVertexes[j].xyz[1] = vec[1];
- tri->shadowVertexes[j].xyz[2] = vec[2];
- tri->shadowVertexes[j].xyz[3] = 1; // no homogenous value
- tri->bounds.AddPoint( tri->shadowVertexes[j].xyz.ToVec3() );
- }
- R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
- for ( j = 0 ; j < tri->numIndexes ; j++ ) {
- tri->indexes[j] = src->ParseInt();
- }
- // add the completed surface to the model
- model->AddSurface( surf );
- src->ExpectTokenString( "}" );
- // we do NOT do a model->FinishSurfaceces, because we don't need sil edges, planes, tangents, etc.
- // model->FinishSurfaces();
- return model;
- }
- /*
- ================
- idRenderWorldLocal::SetupAreaRefs
- ================
- */
- void idRenderWorldLocal::SetupAreaRefs() {
- int i;
- connectedAreaNum = 0;
- for ( i = 0 ; i < numPortalAreas ; i++ ) {
- portalAreas[i].areaNum = i;
- portalAreas[i].lightRefs.areaNext =
- portalAreas[i].lightRefs.areaPrev =
- &portalAreas[i].lightRefs;
- portalAreas[i].entityRefs.areaNext =
- portalAreas[i].entityRefs.areaPrev =
- &portalAreas[i].entityRefs;
- }
- }
- /*
- ================
- idRenderWorldLocal::ParseInterAreaPortals
- ================
- */
- void idRenderWorldLocal::ParseInterAreaPortals( idLexer *src ) {
- int i, j;
- src->ExpectTokenString( "{" );
- numPortalAreas = src->ParseInt();
- if ( numPortalAreas < 0 ) {
- src->Error( "R_ParseInterAreaPortals: bad numPortalAreas" );
- return;
- }
- portalAreas = (portalArea_t *)R_ClearedStaticAlloc( numPortalAreas * sizeof( portalAreas[0] ) );
- areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( numPortalAreas * sizeof( idScreenRect ) );
- // set the doubly linked lists
- SetupAreaRefs();
- numInterAreaPortals = src->ParseInt();
- if ( numInterAreaPortals < 0 ) {
- src->Error( "R_ParseInterAreaPortals: bad numInterAreaPortals" );
- return;
- }
- doublePortals = (doublePortal_t *)R_ClearedStaticAlloc( numInterAreaPortals *
- sizeof( doublePortals [0] ) );
- for ( i = 0 ; i < numInterAreaPortals ; i++ ) {
- int numPoints, a1, a2;
- idWinding *w;
- portal_t *p;
- numPoints = src->ParseInt();
- a1 = src->ParseInt();
- a2 = src->ParseInt();
- w = new idWinding( numPoints );
- w->SetNumPoints( numPoints );
- for ( j = 0 ; j < numPoints ; j++ ) {
- src->Parse1DMatrix( 3, (*w)[j].ToFloatPtr() );
- // no texture coordinates
- (*w)[j][3] = 0;
- (*w)[j][4] = 0;
- }
- // add the portal to a1
- p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) );
- p->intoArea = a2;
- p->doublePortal = &doublePortals[i];
- p->w = w;
- p->w->GetPlane( p->plane );
- p->next = portalAreas[a1].portals;
- portalAreas[a1].portals = p;
- doublePortals[i].portals[0] = p;
- // reverse it for a2
- p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) );
- p->intoArea = a1;
- p->doublePortal = &doublePortals[i];
- p->w = w->Reverse();
- p->w->GetPlane( p->plane );
- p->next = portalAreas[a2].portals;
- portalAreas[a2].portals = p;
- doublePortals[i].portals[1] = p;
- }
- src->ExpectTokenString( "}" );
- }
- /*
- ================
- idRenderWorldLocal::ParseNodes
- ================
- */
- void idRenderWorldLocal::ParseNodes( idLexer *src ) {
- int i;
- src->ExpectTokenString( "{" );
- numAreaNodes = src->ParseInt();
- if ( numAreaNodes < 0 ) {
- src->Error( "R_ParseNodes: bad numAreaNodes" );
- }
- areaNodes = (areaNode_t *)R_ClearedStaticAlloc( numAreaNodes * sizeof( areaNodes[0] ) );
- for ( i = 0 ; i < numAreaNodes ; i++ ) {
- areaNode_t *node;
- node = &areaNodes[i];
- src->Parse1DMatrix( 4, node->plane.ToFloatPtr() );
- node->children[0] = src->ParseInt();
- node->children[1] = src->ParseInt();
- }
- src->ExpectTokenString( "}" );
- }
- /*
- ================
- idRenderWorldLocal::CommonChildrenArea_r
- ================
- */
- int idRenderWorldLocal::CommonChildrenArea_r( areaNode_t *node ) {
- int nums[2];
- for ( int i = 0 ; i < 2 ; i++ ) {
- if ( node->children[i] <= 0 ) {
- nums[i] = -1 - node->children[i];
- } else {
- nums[i] = CommonChildrenArea_r( &areaNodes[ node->children[i] ] );
- }
- }
- // solid nodes will match any area
- if ( nums[0] == AREANUM_SOLID ) {
- nums[0] = nums[1];
- }
- if ( nums[1] == AREANUM_SOLID ) {
- nums[1] = nums[0];
- }
- int common;
- if ( nums[0] == nums[1] ) {
- common = nums[0];
- } else {
- common = CHILDREN_HAVE_MULTIPLE_AREAS;
- }
- node->commonChildrenArea = common;
- return common;
- }
- /*
- =================
- idRenderWorldLocal::ClearWorld
- Sets up for a single area world
- =================
- */
- void idRenderWorldLocal::ClearWorld() {
- numPortalAreas = 1;
- portalAreas = (portalArea_t *)R_ClearedStaticAlloc( sizeof( portalAreas[0] ) );
- areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( sizeof( idScreenRect ) );
- SetupAreaRefs();
- // even though we only have a single area, create a node
- // that has both children pointing at it so we don't need to
- //
- areaNodes = (areaNode_t *)R_ClearedStaticAlloc( sizeof( areaNodes[0] ) );
- areaNodes[0].plane[3] = 1;
- areaNodes[0].children[0] = -1;
- areaNodes[0].children[1] = -1;
- }
- /*
- =================
- idRenderWorldLocal::FreeDefs
- dump all the interactions
- =================
- */
- void idRenderWorldLocal::FreeDefs() {
- int i;
- generateAllInteractionsCalled = false;
- if ( interactionTable ) {
- R_StaticFree( interactionTable );
- interactionTable = NULL;
- }
- // free all lightDefs
- for ( i = 0 ; i < lightDefs.Num() ; i++ ) {
- idRenderLightLocal *light;
- light = lightDefs[i];
- if ( light && light->world == this ) {
- FreeLightDef( i );
- lightDefs[i] = NULL;
- }
- }
- // free all entityDefs
- for ( i = 0 ; i < entityDefs.Num() ; i++ ) {
- idRenderEntityLocal *mod;
- mod = entityDefs[i];
- if ( mod && mod->world == this ) {
- FreeEntityDef( i );
- entityDefs[i] = NULL;
- }
- }
- }
- /*
- =================
- idRenderWorldLocal::InitFromMap
- A NULL or empty name will make a world without a map model, which
- is still useful for displaying a bare model
- =================
- */
- bool idRenderWorldLocal::InitFromMap( const char *name ) {
- idLexer * src;
- idToken token;
- idStr filename;
- idRenderModel * lastModel;
- // if this is an empty world, initialize manually
- if ( !name || !name[0] ) {
- FreeWorld();
- mapName.Clear();
- ClearWorld();
- return true;
- }
- // load it
- filename = name;
- filename.SetFileExtension( PROC_FILE_EXT );
- // if we are reloading the same map, check the timestamp
- // and try to skip all the work
- ID_TIME_T currentTimeStamp;
- fileSystem->ReadFile( filename, NULL, ¤tTimeStamp );
- if ( name == mapName ) {
- if ( currentTimeStamp != FILE_NOT_FOUND_TIMESTAMP && currentTimeStamp == mapTimeStamp ) {
- common->Printf( "idRenderWorldLocal::InitFromMap: retaining existing map\n" );
- FreeDefs();
- TouchWorldModels();
- AddWorldModelEntities();
- ClearPortalStates();
- return true;
- }
- common->Printf( "idRenderWorldLocal::InitFromMap: timestamp has changed, reloading.\n" );
- }
- FreeWorld();
- src = new idLexer( filename, LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
- if ( !src->IsLoaded() ) {
- common->Printf( "idRenderWorldLocal::InitFromMap: %s not found\n", filename.c_str() );
- ClearWorld();
- return false;
- }
- mapName = name;
- mapTimeStamp = currentTimeStamp;
- // if we are writing a demo, archive the load command
- if ( session->writeDemo ) {
- WriteLoadMap();
- }
- if ( !src->ReadToken( &token ) || token.Icmp( PROC_FILE_ID ) ) {
- common->Printf( "idRenderWorldLocal::InitFromMap: bad id '%s' instead of '%s'\n", token.c_str(), PROC_FILE_ID );
- delete src;
- return false;
- }
- // parse the file
- while ( 1 ) {
- if ( !src->ReadToken( &token ) ) {
- break;
- }
- if ( token == "model" ) {
- lastModel = ParseModel( src );
- // add it to the model manager list
- renderModelManager->AddModel( lastModel );
- // save it in the list to free when clearing this map
- localModels.Append( lastModel );
- continue;
- }
- if ( token == "shadowModel" ) {
- lastModel = ParseShadowModel( src );
- // add it to the model manager list
- renderModelManager->AddModel( lastModel );
- // save it in the list to free when clearing this map
- localModels.Append( lastModel );
- continue;
- }
- if ( token == "interAreaPortals" ) {
- ParseInterAreaPortals( src );
- continue;
- }
- if ( token == "nodes" ) {
- ParseNodes( src );
- continue;
- }
- src->Error( "idRenderWorldLocal::InitFromMap: bad token \"%s\"", token.c_str() );
- }
- delete src;
- // if it was a trivial map without any areas, create a single area
- if ( !numPortalAreas ) {
- ClearWorld();
- }
- // find the points where we can early-our of reference pushing into the BSP tree
- CommonChildrenArea_r( &areaNodes[0] );
- AddWorldModelEntities();
- ClearPortalStates();
- // done!
- return true;
- }
- /*
- =====================
- idRenderWorldLocal::ClearPortalStates
- =====================
- */
- void idRenderWorldLocal::ClearPortalStates() {
- int i, j;
- // all portals start off open
- for ( i = 0 ; i < numInterAreaPortals ; i++ ) {
- doublePortals[i].blockingBits = PS_BLOCK_NONE;
- }
- // flood fill all area connections
- for ( i = 0 ; i < numPortalAreas ; i++ ) {
- for ( j = 0 ; j < NUM_PORTAL_ATTRIBUTES ; j++ ) {
- connectedAreaNum++;
- FloodConnectedAreas( &portalAreas[i], j );
- }
- }
- }
- /*
- =====================
- idRenderWorldLocal::AddWorldModelEntities
- =====================
- */
- void idRenderWorldLocal::AddWorldModelEntities() {
- int i;
- // add the world model for each portal area
- // we can't just call AddEntityDef, because that would place the references
- // based on the bounding box, rather than explicitly into the correct area
- for ( i = 0 ; i < numPortalAreas ; i++ ) {
- idRenderEntityLocal *def;
- int index;
- def = new idRenderEntityLocal;
- // try and reuse a free spot
- index = entityDefs.FindNull();
- if ( index == -1 ) {
- index = entityDefs.Append(def);
- } else {
- entityDefs[index] = def;
- }
- def->index = index;
- def->world = this;
- def->parms.hModel = renderModelManager->FindModel( va("_area%i", i ) );
- if ( def->parms.hModel->IsDefaultModel() || !def->parms.hModel->IsStaticWorldModel() ) {
- common->Error( "idRenderWorldLocal::InitFromMap: bad area model lookup" );
- }
- idRenderModel *hModel = def->parms.hModel;
- for ( int j = 0; j < hModel->NumSurfaces(); j++ ) {
- const modelSurface_t *surf = hModel->Surface( j );
- if ( surf->shader->GetName() == idStr( "textures/skies/skyportal" ) ) {
- def->needsPortalSky = true;
- }
- }
- def->referenceBounds = def->parms.hModel->Bounds();
- def->parms.axis[0][0] = 1;
- def->parms.axis[1][1] = 1;
- def->parms.axis[2][2] = 1;
- R_AxisToModelMatrix( def->parms.axis, def->parms.origin, def->modelMatrix );
- // in case an explicit shader is used on the world, we don't
- // want it to have a 0 alpha or color
- def->parms.shaderParms[0] =
- def->parms.shaderParms[1] =
- def->parms.shaderParms[2] =
- def->parms.shaderParms[3] = 1;
- AddEntityRefToArea( def, &portalAreas[i] );
- }
- }
- /*
- =====================
- CheckAreaForPortalSky
- =====================
- */
- bool idRenderWorldLocal::CheckAreaForPortalSky( int areaNum ) {
- areaReference_t *ref;
- assert( areaNum >= 0 && areaNum < numPortalAreas );
- for ( ref = portalAreas[areaNum].entityRefs.areaNext; ref->entity; ref = ref->areaNext ) {
- assert( ref->area == &portalAreas[areaNum] );
- if ( ref->entity && ref->entity->needsPortalSky ) {
- return true;
- }
- }
- return false;
- }
|