12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "tr_local.h"
- /*
- ================
- idRenderWorldLocal::FreeWorld
- ================
- */
- void idRenderWorldLocal::FreeWorld() {
- // this will free all the lightDefs and entityDefs
- FreeDefs();
- // free all the portals and check light/model references
- for ( int 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 ( int i = 0; i < localModels.Num(); i++ ) {
- renderModelManager->RemoveModel( localModels[i] );
- delete localModels[i];
- }
- localModels.Clear();
- areaReferenceAllocator.Shutdown();
- interactionAllocator.Shutdown();
- mapName = "<FREED>";
- }
- /*
- ================
- idRenderWorldLocal::TouchWorldModels
- ================
- */
- void idRenderWorldLocal::TouchWorldModels() {
- for ( int i = 0; i < localModels.Num(); i++ ) {
- renderModelManager->CheckModel( localModels[i]->Name() );
- }
- }
- /*
- ================
- idRenderWorldLocal::ReadBinaryShadowModel
- ================
- */
- idRenderModel *idRenderWorldLocal::ReadBinaryModel( idFile *fileIn ) {
- idStrStatic< MAX_OSPATH > name;
- fileIn->ReadString( name );
- idRenderModel * model = renderModelManager->AllocModel();
- model->InitEmpty( name );
- if ( model->LoadBinaryModel( fileIn, mapTimeStamp ) ) {
- return model;
- }
- return NULL;
- }
- extern idCVar r_binaryLoadRenderModels;
- /*
- ================
- idRenderWorldLocal::ParseModel
- ================
- */
- idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src, const char *mapName, ID_TIME_T mapTimeStamp, idFile *fileOut ) {
- idToken token;
- src->ExpectTokenString( "{" );
- // parse the name
- src->ExpectAnyToken( &token );
- idRenderModel * model = renderModelManager->AllocModel();
- model->InitEmpty( token );
- if ( fileOut != NULL ) {
- // write out the type so the binary reader knows what to instantiate
- fileOut->WriteString( "shadowmodel" );
- fileOut->WriteString( token );
- }
- int numSurfaces = src->ParseInt();
- if ( numSurfaces < 0 ) {
- src->Error( "R_ParseModel: bad numSurfaces" );
- }
- for ( int i = 0; i < numSurfaces; i++ ) {
- src->ExpectTokenString( "{" );
- src->ExpectAnyToken( &token );
- modelSurface_t surf;
- surf.shader = declManager->FindMaterial( token );
- ((idMaterial*)surf.shader)->AddReference();
- srfTriangles_t * tri = R_AllocStaticTriSurf();
- surf.geometry = tri;
- tri->numVerts = src->ParseInt();
- tri->numIndexes = src->ParseInt();
- // parse the vertices
- idTempArray<float> verts( tri->numVerts * 8 );
- for ( int j = 0; j < tri->numVerts; j++ ) {
- src->Parse1DMatrix( 8, &verts[j * 8] );
- }
- // parse the indices
- idTempArray<triIndex_t> indexes( tri->numIndexes );
- for ( int j = 0; j < tri->numIndexes; j++ ) {
- indexes[j] = src->ParseInt();
- }
- #if 1
- // find the island that each vertex belongs to
- idTempArray<int> vertIslands( tri->numVerts );
- idTempArray<bool> trisVisited( tri->numIndexes );
- vertIslands.Zero();
- trisVisited.Zero();
- int numIslands = 0;
- for ( int j = 0; j < tri->numIndexes; j += 3 ) {
- if ( trisVisited[j] ) {
- continue;
- }
- int islandNum = ++numIslands;
- vertIslands[indexes[j + 0]] = islandNum;
- vertIslands[indexes[j + 1]] = islandNum;
- vertIslands[indexes[j + 2]] = islandNum;
- trisVisited[j] = true;
- idList<int> queue;
- queue.Append( j );
- for ( int n = 0; n < queue.Num(); n++ ) {
- int t = queue[n];
- for ( int k = 0; k < tri->numIndexes; k += 3 ) {
- if ( trisVisited[k] ) {
- continue;
- }
- bool connected = indexes[t + 0] == indexes[k + 0] || indexes[t + 0] == indexes[k + 1] || indexes[t + 0] == indexes[k + 2] ||
- indexes[t + 1] == indexes[k + 0] || indexes[t + 1] == indexes[k + 1] || indexes[t + 1] == indexes[k + 2] ||
- indexes[t + 2] == indexes[k + 0] || indexes[t + 2] == indexes[k + 1] || indexes[t + 2] == indexes[k + 2];
- if ( connected ) {
- vertIslands[indexes[k + 0]] = islandNum;
- vertIslands[indexes[k + 1]] = islandNum;
- vertIslands[indexes[k + 2]] = islandNum;
- trisVisited[k] = true;
- queue.Append( k );
- }
- }
- }
- }
- // center the texture coordinates for each island for maximum 16-bit precision
- for ( int j = 1; j <= numIslands; j++ ) {
- float minS = idMath::INFINITY;
- float minT = idMath::INFINITY;
- float maxS = -idMath::INFINITY;
- float maxT = -idMath::INFINITY;
- for ( int k = 0; k < tri->numVerts; k++ ) {
- if ( vertIslands[k] == j ) {
- minS = Min( minS, verts[k * 8 + 3] );
- maxS = Max( maxS, verts[k * 8 + 3] );
- minT = Min( minT, verts[k * 8 + 4] );
- maxT = Max( maxT, verts[k * 8 + 4] );
- }
- }
- const float averageS = idMath::Ftoi( ( minS + maxS ) * 0.5f );
- const float averageT = idMath::Ftoi( ( minT + maxT ) * 0.5f );
- for ( int k = 0; k < tri->numVerts; k++ ) {
- if ( vertIslands[k] == j ) {
- verts[k * 8 + 3] -= averageS;
- verts[k * 8 + 4] -= averageT;
- }
- }
- }
- #endif
- R_AllocStaticTriSurfVerts( tri, tri->numVerts );
- for ( int j = 0; j < tri->numVerts; j++ ) {
- tri->verts[j].xyz[0] = verts[j * 8 + 0];
- tri->verts[j].xyz[1] = verts[j * 8 + 1];
- tri->verts[j].xyz[2] = verts[j * 8 + 2];
- tri->verts[j].SetTexCoord( verts[j * 8 + 3], verts[j * 8 + 4] );
- tri->verts[j].SetNormal( verts[j * 8 + 5], verts[j * 8 + 6], verts[j * 8 + 7] );
- }
- R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
- for ( int j = 0; j < tri->numIndexes; j++ ) {
- tri->indexes[j] = indexes[j];
- }
- src->ExpectTokenString( "}" );
- // add the completed surface to the model
- model->AddSurface( surf );
- }
- src->ExpectTokenString( "}" );
- model->FinishSurfaces();
- if ( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() ) {
- model->WriteBinaryModel( fileOut, &mapTimeStamp );
- }
- return model;
- }
- /*
- ================
- idRenderWorldLocal::ReadBinaryShadowModel
- ================
- */
- idRenderModel *idRenderWorldLocal::ReadBinaryShadowModel( idFile *fileIn ) {
- idStrStatic< MAX_OSPATH > name;
- fileIn->ReadString( name );
- idRenderModel * model = renderModelManager->AllocModel();
- model->InitEmpty( name );
- if ( model->LoadBinaryModel( fileIn, mapTimeStamp ) ) {
- return model;
- }
- return NULL;
- }
- /*
- ================
- idRenderWorldLocal::ParseShadowModel
- ================
- */
- idRenderModel *idRenderWorldLocal::ParseShadowModel( idLexer *src, idFile *fileOut ) {
- idToken token;
- src->ExpectTokenString( "{" );
- // parse the name
- src->ExpectAnyToken( &token );
- idRenderModel * model = renderModelManager->AllocModel();
- model->InitEmpty( token );
- if ( fileOut != NULL ) {
- // write out the type so the binary reader knows what to instantiate
- fileOut->WriteString( "shadowmodel" );
- fileOut->WriteString( token );
- }
- srfTriangles_t * tri = R_AllocStaticTriSurf();
- tri->numVerts = src->ParseInt();
- tri->numShadowIndexesNoCaps = src->ParseInt();
- tri->numShadowIndexesNoFrontCaps = src->ParseInt();
- tri->numIndexes = src->ParseInt();
- tri->shadowCapPlaneBits = src->ParseInt();
- assert( ( tri->numVerts & 1 ) == 0 );
- R_AllocStaticTriSurfPreLightShadowVerts( tri, ALIGN( tri->numVerts, 2 ) );
- tri->bounds.Clear();
- for ( int j = 0; j < tri->numVerts; j++ ) {
- float vec[8];
- src->Parse1DMatrix( 3, vec );
- tri->preLightShadowVertexes[j].xyzw[0] = vec[0];
- tri->preLightShadowVertexes[j].xyzw[1] = vec[1];
- tri->preLightShadowVertexes[j].xyzw[2] = vec[2];
- tri->preLightShadowVertexes[j].xyzw[3] = 1.0f; // no homogenous value
- tri->bounds.AddPoint( tri->preLightShadowVertexes[j].xyzw.ToVec3() );
- }
- // clear the last vertex if it wasn't stored
- if ( ( tri->numVerts & 1 ) != 0 ) {
- tri->preLightShadowVertexes[ALIGN( tri->numVerts, 2 ) - 1].xyzw.Zero();
- }
- // to be consistent set the number of vertices to half the number of shadow vertices
- tri->numVerts = ALIGN( tri->numVerts, 2 ) / 2;
- R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
- for ( int j = 0; j < tri->numIndexes; j++ ) {
- tri->indexes[j] = src->ParseInt();
- }
- // add the completed surface to the model
- modelSurface_t surf;
- surf.id = 0;
- surf.shader = tr.defaultMaterial;
- surf.geometry = tri;
- model->AddSurface( surf );
- src->ExpectTokenString( "}" );
- // NOTE: we do NOT do a model->FinishSurfaceces, because we don't need sil edges, planes, tangents, etc.
- if ( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() ) {
- model->WriteBinaryModel( fileOut, &mapTimeStamp );
- }
- return model;
- }
- /*
- ================
- idRenderWorldLocal::SetupAreaRefs
- ================
- */
- void idRenderWorldLocal::SetupAreaRefs() {
- connectedAreaNum = 0;
- for ( int 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, idFile *fileOut ) {
- src->ExpectTokenString( "{" );
- numPortalAreas = src->ParseInt();
- if ( numPortalAreas < 0 ) {
- src->Error( "R_ParseInterAreaPortals: bad numPortalAreas" );
- return;
- }
- if ( fileOut != NULL ) {
- // write out the type so the binary reader knows what to instantiate
- fileOut->WriteString( "interAreaPortals" );
- }
- 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;
- }
- if ( fileOut != NULL ) {
- fileOut->WriteBig( numPortalAreas );
- fileOut->WriteBig( numInterAreaPortals );
- }
- doublePortals = (doublePortal_t *)R_ClearedStaticAlloc( numInterAreaPortals *
- sizeof( doublePortals [0] ) );
- for ( int i = 0; i < numInterAreaPortals; i++ ) {
- int numPoints, a1, a2;
- idWinding *w;
- portal_t *p;
- numPoints = src->ParseInt();
- a1 = src->ParseInt();
- a2 = src->ParseInt();
- if ( fileOut != NULL ) {
- fileOut->WriteBig( numPoints );
- fileOut->WriteBig( a1 );
- fileOut->WriteBig( a2 );
- }
- w = new (TAG_RENDER_WINDING) idWinding( numPoints );
- w->SetNumPoints( numPoints );
- for ( int j = 0; j < numPoints; j++ ) {
- src->Parse1DMatrix( 3, (*w)[j].ToFloatPtr() );
- if ( fileOut != NULL ) {
- fileOut->WriteBig( (*w)[j].x );
- fileOut->WriteBig( (*w)[j].y );
- fileOut->WriteBig( (*w)[j].z );
- }
- // 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::ParseInterAreaPortals
- ================
- */
- void idRenderWorldLocal::ReadBinaryAreaPortals( idFile *file ) {
- file->ReadBig( numPortalAreas );
- file->ReadBig( numInterAreaPortals );
- portalAreas = (portalArea_t *)R_ClearedStaticAlloc( numPortalAreas * sizeof( portalAreas[0] ) );
- areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( numPortalAreas * sizeof( idScreenRect ) );
- // set the doubly linked lists
- SetupAreaRefs();
- doublePortals = (doublePortal_t *)R_ClearedStaticAlloc( numInterAreaPortals * sizeof( doublePortals [0] ) );
- for ( int i = 0; i < numInterAreaPortals; i++ ) {
- int numPoints, a1, a2;
- idWinding *w;
- portal_t *p;
- file->ReadBig( numPoints );
- file->ReadBig( a1 );
- file->ReadBig( a2 );
- w = new (TAG_RENDER_WINDING) idWinding( numPoints );
- w->SetNumPoints( numPoints );
- for ( int j = 0; j < numPoints; j++ ) {
- file->ReadBig( (*w)[ j ][ 0 ] );
- file->ReadBig( (*w)[ j ][ 1 ] );
- file->ReadBig( (*w)[ j ][ 2 ] );
- // 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;
- }
- }
- /*
- ================
- idRenderWorldLocal::ParseNodes
- ================
- */
- void idRenderWorldLocal::ParseNodes( idLexer *src, idFile *fileOut ) {
- src->ExpectTokenString( "{" );
- numAreaNodes = src->ParseInt();
- if ( numAreaNodes < 0 ) {
- src->Error( "R_ParseNodes: bad numAreaNodes" );
- }
- areaNodes = (areaNode_t *)R_ClearedStaticAlloc( numAreaNodes * sizeof( areaNodes[0] ) );
- if ( fileOut != NULL ) {
- // write out the type so the binary reader knows what to instantiate
- fileOut->WriteString( "nodes" );
- }
- if ( fileOut != NULL ) {
- fileOut->WriteBig( numAreaNodes );
- }
- for ( int 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();
- if ( fileOut != NULL ) {
- fileOut->WriteBig( node->plane[ 0 ] );
- fileOut->WriteBig( node->plane[ 1 ] );
- fileOut->WriteBig( node->plane[ 2 ] );
- fileOut->WriteBig( node->plane[ 3 ] );
- fileOut->WriteBig( node->children[ 0 ] );
- fileOut->WriteBig( node->children[ 1 ] );
- }
- }
- src->ExpectTokenString( "}" );
- }
- /*
- ================
- idRenderWorldLocal::ReadBinaryNodes
- ================
- */
- void idRenderWorldLocal::ReadBinaryNodes( idFile * file ) {
- file->ReadBig( numAreaNodes );
- areaNodes = (areaNode_t *)R_ClearedStaticAlloc( numAreaNodes * sizeof( areaNodes[0] ) );
- for ( int i = 0; i < numAreaNodes; i++ ) {
- areaNode_t * node = &areaNodes[ i ];
- file->ReadBig( node->plane[ 0 ] );
- file->ReadBig( node->plane[ 1 ] );
- file->ReadBig( node->plane[ 2 ] );
- file->ReadBig( node->plane[ 3 ] );
- file->ReadBig( node->children[ 0 ] );
- file->ReadBig( node->children[ 1 ] );
- }
- }
- /*
- ================
- 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() {
- generateAllInteractionsCalled = false;
- if ( interactionTable ) {
- R_StaticFree( interactionTable );
- interactionTable = NULL;
- }
- // free all lightDefs
- for ( int i = 0; i < lightDefs.Num(); i++ ) {
- idRenderLightLocal * light = lightDefs[i];
- if ( light != NULL && light->world == this ) {
- FreeLightDef( i );
- lightDefs[i] = NULL;
- }
- }
- // free all entityDefs
- for ( int i = 0; i < entityDefs.Num(); i++ ) {
- idRenderEntityLocal * mod = entityDefs[i];
- if ( mod != NULL && mod->world == this ) {
- FreeEntityDef( i );
- entityDefs[i] = NULL;
- }
- }
- // Reset decals and overlays
- for ( int i = 0; i < decals.Num(); i++ ) {
- decals[i].entityHandle = -1;
- decals[i].lastStartTime = 0;
- }
- for ( int i = 0; i < overlays.Num(); i++ ) {
- overlays[i].entityHandle = -1;
- overlays[i].lastStartTime = 0;
- }
- }
- /*
- =================
- 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;
- idRenderModel * lastModel;
- // if this is an empty world, initialize manually
- if ( !name || !name[0] ) {
- FreeWorld();
- mapName.Clear();
- ClearWorld();
- return true;
- }
- // load it
- idStrStatic< MAX_OSPATH > filename = name;
- filename.SetFileExtension( PROC_FILE_EXT );
- // check for generated file
- idStrStatic< MAX_OSPATH > generatedFileName = filename;
- generatedFileName.Insert( "generated/", 0 );
- generatedFileName.SetFileExtension( "bproc" );
- // if we are reloading the same map, check the timestamp
- // and try to skip all the work
- ID_TIME_T currentTimeStamp = fileSystem->GetTimestamp( filename );
- if ( name == mapName ) {
- if ( fileSystem->InProductionMode() || ( 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();
- // see if we have a generated version of this
- static const byte BPROC_VERSION = 1;
- static const unsigned int BPROC_MAGIC = ( 'P' << 24 ) | ( 'R' << 16 ) | ( 'O' << 8 ) | BPROC_VERSION;
- bool loaded = false;
- idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
- if ( file != NULL ) {
- int numEntries = 0;
- int magic = 0;
- file->ReadBig( magic );
- if ( magic == BPROC_MAGIC ) {
- file->ReadBig( numEntries );
- file->ReadString( mapName );
- file->ReadBig( mapTimeStamp );
- loaded = true;
- for ( int i = 0; i < numEntries; i++ ) {
- idStrStatic< MAX_OSPATH > type;
- file->ReadString( type );
- type.ToLower();
- if ( type == "model" ) {
- idRenderModel * lastModel = ReadBinaryModel( file );
- if ( lastModel == NULL ) {
- loaded = false;
- break;
- }
- renderModelManager->AddModel( lastModel );
- localModels.Append( lastModel );
- } else if ( type == "shadowmodel" ) {
- idRenderModel * lastModel = ReadBinaryModel( file );
- if ( lastModel == NULL ) {
- loaded = false;
- break;
- }
- renderModelManager->AddModel( lastModel );
- localModels.Append( lastModel );
- } else if ( type == "interareaportals" ) {
- ReadBinaryAreaPortals( file );
- } else if ( type == "nodes" ) {
- ReadBinaryNodes( file );
- } else {
- idLib::Error( "Binary proc file failed, unexpected type %s\n", type.c_str() );
- }
- }
- }
- }
- if ( !loaded ) {
- src = new (TAG_RENDER) 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 ( common->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;
- }
-
- int numEntries = 0;
- idFileLocal outputFile( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) );
- if ( outputFile != NULL ) {
- int magic = BPROC_MAGIC;
- outputFile->WriteBig( magic );
- outputFile->WriteBig( numEntries );
- outputFile->WriteString( mapName );
- outputFile->WriteBig( mapTimeStamp );
- }
- // parse the file
- while ( 1 ) {
- if ( !src->ReadToken( &token ) ) {
- break;
- }
- common->UpdateLevelLoadPacifier();
- if ( token == "model" ) {
- lastModel = ParseModel( src, name, currentTimeStamp, outputFile );
- // add it to the model manager list
- renderModelManager->AddModel( lastModel );
- // save it in the list to free when clearing this map
- localModels.Append( lastModel );
- numEntries++;
- continue;
- }
- if ( token == "shadowModel" ) {
- lastModel = ParseShadowModel( src, outputFile );
- // add it to the model manager list
- renderModelManager->AddModel( lastModel );
- // save it in the list to free when clearing this map
- localModels.Append( lastModel );
- numEntries++;
- continue;
- }
- if ( token == "interAreaPortals" ) {
- ParseInterAreaPortals( src, outputFile );
- numEntries++;
- continue;
- }
- if ( token == "nodes" ) {
- ParseNodes( src, outputFile );
- numEntries++;
- continue;
- }
- src->Error( "idRenderWorldLocal::InitFromMap: bad token \"%s\"", token.c_str() );
- }
- delete src;
- if ( outputFile != NULL ) {
- outputFile->Seek( 0, FS_SEEK_SET );
- int magic = BPROC_MAGIC;
- outputFile->WriteBig( magic );
- outputFile->WriteBig( numEntries );
- }
- }
- // 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() {
- // all portals start off open
- for ( int i = 0; i < numInterAreaPortals; i++ ) {
- doublePortals[i].blockingBits = PS_BLOCK_NONE;
- }
- // flood fill all area connections
- for ( int i = 0; i < numPortalAreas; i++ ) {
- for ( int j = 0; j < NUM_PORTAL_ATTRIBUTES; j++ ) {
- connectedAreaNum++;
- FloodConnectedAreas( &portalAreas[i], j );
- }
- }
- }
- /*
- =====================
- idRenderWorldLocal::AddWorldModelEntities
- =====================
- */
- void idRenderWorldLocal::AddWorldModelEntities() {
- // 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 ( int i = 0; i < numPortalAreas; i++ ) {
- common->UpdateLevelLoadPacifier();
- idRenderEntityLocal * def = new (TAG_RENDER_ENTITY) idRenderEntityLocal;
- // try and reuse a free spot
- int 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/smf/portal_sky" ) ) {
- def->needsPortalSky = true;
- }
- }
- // the local and global reference bounds are the same for area models
- def->localReferenceBounds = def->parms.hModel->Bounds();
- def->globalReferenceBounds = def->parms.hModel->Bounds();
- def->parms.axis[0][0] = 1.0f;
- def->parms.axis[1][1] = 1.0f;
- def->parms.axis[2][2] = 1.0f;
- // 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] = 1.0f;
- def->parms.shaderParms[1] = 1.0f;
- def->parms.shaderParms[2] = 1.0f;
- def->parms.shaderParms[3] = 1.0f;
- R_DeriveEntityData( def );
- AddEntityRefToArea( def, &portalAreas[i] );
- }
- }
- /*
- =====================
- CheckAreaForPortalSky
- =====================
- */
- bool idRenderWorldLocal::CheckAreaForPortalSky( int areaNum ) {
- assert( areaNum >= 0 && areaNum < numPortalAreas );
- for ( areaReference_t * 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;
- }
- /*
- =====================
- ResetLocalRenderModels
- =====================
- */
- void idRenderWorldLocal::ResetLocalRenderModels() {
- 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
- }
|