123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112 |
- /*
- ===========================================================================
- 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"
- /*
- ===================
- R_ListRenderLightDefs_f
- ===================
- */
- void R_ListRenderLightDefs_f( const idCmdArgs &args ) {
- int i;
- idRenderLightLocal *ldef;
- if ( !tr.primaryWorld ) {
- return;
- }
- int active = 0;
- int totalRef = 0;
- int totalIntr = 0;
- for ( i = 0; i < tr.primaryWorld->lightDefs.Num(); i++ ) {
- ldef = tr.primaryWorld->lightDefs[i];
- if ( !ldef ) {
- common->Printf( "%4i: FREED\n", i );
- continue;
- }
- // count up the interactions
- int iCount = 0;
- for ( idInteraction *inter = ldef->firstInteraction; inter != NULL; inter = inter->lightNext ) {
- iCount++;
- }
- totalIntr += iCount;
- // count up the references
- int rCount = 0;
- for ( areaReference_t *ref = ldef->references; ref; ref = ref->ownerNext ) {
- rCount++;
- }
- totalRef += rCount;
- common->Printf( "%4i: %3i intr %2i refs %s\n", i, iCount, rCount, ldef->lightShader->GetName());
- active++;
- }
- common->Printf( "%i lightDefs, %i interactions, %i areaRefs\n", active, totalIntr, totalRef );
- }
- /*
- ===================
- R_ListRenderEntityDefs_f
- ===================
- */
- void R_ListRenderEntityDefs_f( const idCmdArgs &args ) {
- int i;
- idRenderEntityLocal *mdef;
- if ( !tr.primaryWorld ) {
- return;
- }
- int active = 0;
- int totalRef = 0;
- int totalIntr = 0;
- for ( i = 0; i < tr.primaryWorld->entityDefs.Num(); i++ ) {
- mdef = tr.primaryWorld->entityDefs[i];
- if ( !mdef ) {
- common->Printf( "%4i: FREED\n", i );
- continue;
- }
- // count up the interactions
- int iCount = 0;
- for ( idInteraction *inter = mdef->firstInteraction; inter != NULL; inter = inter->entityNext ) {
- iCount++;
- }
- totalIntr += iCount;
- // count up the references
- int rCount = 0;
- for ( areaReference_t *ref = mdef->entityRefs; ref; ref = ref->ownerNext ) {
- rCount++;
- }
- totalRef += rCount;
- common->Printf( "%4i: %3i intr %2i refs %s\n", i, iCount, rCount, mdef->parms.hModel->Name());
- active++;
- }
- common->Printf( "total active: %i\n", active );
- }
- /*
- ===================
- idRenderWorldLocal::idRenderWorldLocal
- ===================
- */
- idRenderWorldLocal::idRenderWorldLocal() {
- mapName.Clear();
- mapTimeStamp = FILE_NOT_FOUND_TIMESTAMP;
- generateAllInteractionsCalled = false;
- areaNodes = NULL;
- numAreaNodes = 0;
- portalAreas = NULL;
- numPortalAreas = 0;
- doublePortals = NULL;
- numInterAreaPortals = 0;
- interactionTable = 0;
- interactionTableWidth = 0;
- interactionTableHeight = 0;
- for ( int i = 0; i < decals.Num(); i++ ) {
- decals[i].entityHandle = -1;
- decals[i].lastStartTime = 0;
- decals[i].decals = new (TAG_MODEL) idRenderModelDecal();
- }
- for ( int i = 0; i < overlays.Num(); i++ ) {
- overlays[i].entityHandle = -1;
- overlays[i].lastStartTime = 0;
- overlays[i].overlays = new (TAG_MODEL) idRenderModelOverlay();
- }
- }
- /*
- ===================
- idRenderWorldLocal::~idRenderWorldLocal
- ===================
- */
- idRenderWorldLocal::~idRenderWorldLocal() {
- // free all the entityDefs, lightDefs, portals, etc
- FreeWorld();
- for ( int i = 0; i < decals.Num(); i++ ) {
- delete decals[i].decals;
- }
- for ( int i = 0; i < overlays.Num(); i++ ) {
- delete overlays[i].overlays;
- }
- // free up the debug lines, polys, and text
- RB_ClearDebugPolygons( 0 );
- RB_ClearDebugLines( 0 );
- RB_ClearDebugText( 0 );
- }
- /*
- ===================
- ResizeInteractionTable
- ===================
- */
- void idRenderWorldLocal::ResizeInteractionTable() {
- // we overflowed the interaction table, so make it larger
- common->Printf( "idRenderWorldLocal::ResizeInteractionTable: overflowed interactionTable, resizing\n" );
- const int oldInteractionTableWidth = interactionTableWidth;
- const int oldIinteractionTableHeight = interactionTableHeight;
- idInteraction ** oldInteractionTable = interactionTable;
- // build the interaction table
- // this will be dynamically resized if the entity / light counts grow too much
- interactionTableWidth = entityDefs.Num() + 100;
- interactionTableHeight = lightDefs.Num() + 100;
- const int size = interactionTableWidth * interactionTableHeight * sizeof( *interactionTable );
- interactionTable = (idInteraction **)R_ClearedStaticAlloc( size );
- for ( int l = 0; l < oldIinteractionTableHeight; l++ ) {
- for ( int e = 0; e < oldInteractionTableWidth; e++ ) {
- interactionTable[ l * interactionTableWidth + e ] = oldInteractionTable[ l * oldInteractionTableWidth + e ];
- }
- }
- R_StaticFree( oldInteractionTable );
- }
- /*
- ===================
- AddEntityDef
- ===================
- */
- qhandle_t idRenderWorldLocal::AddEntityDef( const renderEntity_t *re ){
- // try and reuse a free spot
- int entityHandle = entityDefs.FindNull();
- if ( entityHandle == -1 ) {
- entityHandle = entityDefs.Append( NULL );
- if ( interactionTable && entityDefs.Num() > interactionTableWidth ) {
- ResizeInteractionTable();
- }
- }
- UpdateEntityDef( entityHandle, re );
-
- return entityHandle;
- }
- /*
- ==============
- UpdateEntityDef
- Does not write to the demo file, which will only be updated for
- visible entities
- ==============
- */
- int c_callbackUpdate;
- void idRenderWorldLocal::UpdateEntityDef( qhandle_t entityHandle, const renderEntity_t *re ) {
- if ( r_skipUpdates.GetBool() ) {
- return;
- }
- tr.pc.c_entityUpdates++;
- if ( !re->hModel && !re->callback ) {
- common->Error( "idRenderWorld::UpdateEntityDef: NULL hModel" );
- }
- // create new slots if needed
- if ( entityHandle < 0 || entityHandle > LUDICROUS_INDEX ) {
- common->Error( "idRenderWorld::UpdateEntityDef: index = %i", entityHandle );
- }
- while ( entityHandle >= entityDefs.Num() ) {
- entityDefs.Append( NULL );
- }
- idRenderEntityLocal *def = entityDefs[entityHandle];
- if ( def != NULL ) {
- if ( !re->forceUpdate ) {
- // check for exact match (OPTIMIZE: check through pointers more)
- if ( !re->joints && !re->callbackData && !def->dynamicModel && !memcmp( re, &def->parms, sizeof( *re ) ) ) {
- return;
- }
- // if the only thing that changed was shaderparms, we can just leave things as they are
- // after updating parms
- // if we have a callback function and the bounds, origin, axis and model match,
- // then we can leave the references as they are
- if ( re->callback ) {
- bool axisMatch = ( re->axis == def->parms.axis );
- bool originMatch = ( re->origin == def->parms.origin );
- bool boundsMatch = ( re->bounds == def->localReferenceBounds );
- bool modelMatch = ( re->hModel == def->parms.hModel );
- if ( boundsMatch && originMatch && axisMatch && modelMatch ) {
- // only clear the dynamic model and interaction surfaces if they exist
- c_callbackUpdate++;
- R_ClearEntityDefDynamicModel( def );
- def->parms = *re;
- return;
- }
- }
- }
- // save any decals if the model is the same, allowing marks to move with entities
- if ( def->parms.hModel == re->hModel ) {
- R_FreeEntityDefDerivedData( def, true, true );
- } else {
- R_FreeEntityDefDerivedData( def, false, false );
- }
- } else {
- // creating a new one
- def = new (TAG_RENDER_ENTITY) idRenderEntityLocal;
- entityDefs[entityHandle] = def;
- def->world = this;
- def->index = entityHandle;
- }
- def->parms = *re;
- def->lastModifiedFrameNum = tr.frameCount;
- if ( common->WriteDemo() && def->archived ) {
- WriteFreeEntity( entityHandle );
- def->archived = false;
- }
- // optionally immediately issue any callbacks
- if ( !r_useEntityCallbacks.GetBool() && def->parms.callback != NULL ) {
- R_IssueEntityDefCallback( def );
- }
- // trigger entities don't need to get linked in and processed,
- // they only exist for editor use
- if ( def->parms.hModel != NULL && !def->parms.hModel->ModelHasDrawingSurfaces() ) {
- return;
- }
- // based on the model bounds, add references in each area
- // that may contain the updated surface
- R_CreateEntityRefs( def );
- }
- /*
- ===================
- FreeEntityDef
- Frees all references and lit surfaces from the model, and
- NULL's out it's entry in the world list
- ===================
- */
- void idRenderWorldLocal::FreeEntityDef( qhandle_t entityHandle ) {
- idRenderEntityLocal *def;
- if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
- common->Printf( "idRenderWorld::FreeEntityDef: handle %i > %i\n", entityHandle, entityDefs.Num() );
- return;
- }
- def = entityDefs[entityHandle];
- if ( !def ) {
- common->Printf( "idRenderWorld::FreeEntityDef: handle %i is NULL\n", entityHandle );
- return;
- }
- R_FreeEntityDefDerivedData( def, false, false );
- if ( common->WriteDemo() && def->archived ) {
- WriteFreeEntity( entityHandle );
- }
- // if we are playing a demo, these will have been freed
- // in R_FreeEntityDefDerivedData(), otherwise the gui
- // object still exists in the game
- def->parms.gui[ 0 ] = NULL;
- def->parms.gui[ 1 ] = NULL;
- def->parms.gui[ 2 ] = NULL;
- delete def;
- entityDefs[ entityHandle ] = NULL;
- }
- /*
- ==================
- GetRenderEntity
- ==================
- */
- const renderEntity_t *idRenderWorldLocal::GetRenderEntity( qhandle_t entityHandle ) const {
- idRenderEntityLocal *def;
- if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
- common->Printf( "idRenderWorld::GetRenderEntity: invalid handle %i [0, %i]\n", entityHandle, entityDefs.Num() );
- return NULL;
- }
- def = entityDefs[entityHandle];
- if ( !def ) {
- common->Printf( "idRenderWorld::GetRenderEntity: handle %i is NULL\n", entityHandle );
- return NULL;
- }
- return &def->parms;
- }
- /*
- ==================
- AddLightDef
- ==================
- */
- qhandle_t idRenderWorldLocal::AddLightDef( const renderLight_t *rlight ) {
- // try and reuse a free spot
- int lightHandle = lightDefs.FindNull();
- if ( lightHandle == -1 ) {
- lightHandle = lightDefs.Append( NULL );
- if ( interactionTable && lightDefs.Num() > interactionTableHeight ) {
- ResizeInteractionTable();
- }
- }
- UpdateLightDef( lightHandle, rlight );
- return lightHandle;
- }
- /*
- =================
- UpdateLightDef
- The generation of all the derived interaction data will
- usually be deferred until it is visible in a scene
- Does not write to the demo file, which will only be done for visible lights
- =================
- */
- void idRenderWorldLocal::UpdateLightDef( qhandle_t lightHandle, const renderLight_t *rlight ) {
- if ( r_skipUpdates.GetBool() ) {
- return;
- }
- tr.pc.c_lightUpdates++;
- // create new slots if needed
- if ( lightHandle < 0 || lightHandle > LUDICROUS_INDEX ) {
- common->Error( "idRenderWorld::UpdateLightDef: index = %i", lightHandle );
- }
- while ( lightHandle >= lightDefs.Num() ) {
- lightDefs.Append( NULL );
- }
- bool justUpdate = false;
- idRenderLightLocal *light = lightDefs[lightHandle];
- if ( light ) {
- // if the shape of the light stays the same, we don't need to dump
- // any of our derived data, because shader parms are calculated every frame
- if ( rlight->axis == light->parms.axis && rlight->end == light->parms.end &&
- rlight->lightCenter == light->parms.lightCenter && rlight->lightRadius == light->parms.lightRadius &&
- rlight->noShadows == light->parms.noShadows && rlight->origin == light->parms.origin &&
- rlight->parallel == light->parms.parallel && rlight->pointLight == light->parms.pointLight &&
- rlight->right == light->parms.right && rlight->start == light->parms.start &&
- rlight->target == light->parms.target && rlight->up == light->parms.up &&
- rlight->shader == light->lightShader && rlight->prelightModel == light->parms.prelightModel ) {
- justUpdate = true;
- } else {
- // if we are updating shadows, the prelight model is no longer valid
- light->lightHasMoved = true;
- R_FreeLightDefDerivedData( light );
- }
- } else {
- // create a new one
- light = new (TAG_RENDER_LIGHT) idRenderLightLocal;
- lightDefs[lightHandle] = light;
- light->world = this;
- light->index = lightHandle;
- }
- light->parms = *rlight;
- light->lastModifiedFrameNum = tr.frameCount;
- if ( common->WriteDemo() && light->archived ) {
- WriteFreeLight( lightHandle );
- light->archived = false;
- }
- // new for BFG edition: force noShadows on spectrum lights so teleport spawns
- // don't cause such a slowdown. Hell writing shouldn't be shadowed anyway...
- if ( light->parms.shader && light->parms.shader->Spectrum() ) {
- light->parms.noShadows = true;
- }
- if ( light->lightHasMoved ) {
- light->parms.prelightModel = NULL;
- }
- if ( !justUpdate ) {
- R_CreateLightRefs( light );
- }
- }
- /*
- ====================
- FreeLightDef
- Frees all references and lit surfaces from the light, and
- NULL's out it's entry in the world list
- ====================
- */
- void idRenderWorldLocal::FreeLightDef( qhandle_t lightHandle ) {
- idRenderLightLocal *light;
- if ( lightHandle < 0 || lightHandle >= lightDefs.Num() ) {
- common->Printf( "idRenderWorld::FreeLightDef: invalid handle %i [0, %i]\n", lightHandle, lightDefs.Num() );
- return;
- }
- light = lightDefs[lightHandle];
- if ( !light ) {
- common->Printf( "idRenderWorld::FreeLightDef: handle %i is NULL\n", lightHandle );
- return;
- }
- R_FreeLightDefDerivedData( light );
- if ( common->WriteDemo() && light->archived ) {
- WriteFreeLight( lightHandle );
- }
- delete light;
- lightDefs[lightHandle] = NULL;
- }
- /*
- ==================
- GetRenderLight
- ==================
- */
- const renderLight_t *idRenderWorldLocal::GetRenderLight( qhandle_t lightHandle ) const {
- idRenderLightLocal *def;
- if ( lightHandle < 0 || lightHandle >= lightDefs.Num() ) {
- common->Printf( "idRenderWorld::GetRenderLight: handle %i > %i\n", lightHandle, lightDefs.Num() );
- return NULL;
- }
- def = lightDefs[lightHandle];
- if ( !def ) {
- common->Printf( "idRenderWorld::GetRenderLight: handle %i is NULL\n", lightHandle );
- return NULL;
- }
- return &def->parms;
- }
- /*
- ================
- idRenderWorldLocal::ProjectDecalOntoWorld
- ================
- */
- void idRenderWorldLocal::ProjectDecalOntoWorld( const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
- decalProjectionParms_t globalParms;
- if ( !idRenderModelDecal::CreateProjectionParms( globalParms, winding, projectionOrigin, parallel, fadeDepth, material, startTime ) ) {
- return;
- }
- // get the world areas touched by the projection volume
- int areas[10];
- int numAreas = BoundsInAreas( globalParms.projectionBounds, areas, 10 );
- // check all areas for models
- for ( int i = 0; i < numAreas; i++ ) {
- const portalArea_t * area = &portalAreas[ areas[i] ];
- // check all models in this area
- for ( const areaReference_t * ref = area->entityRefs.areaNext; ref != &area->entityRefs; ref = ref->areaNext ) {
- idRenderEntityLocal * def = ref->entity;
- if ( def->parms.noOverlays ) {
- continue;
- }
- if ( def->parms.customShader != NULL && !def->parms.customShader->AllowOverlays() ) {
- continue;
- }
- // completely ignore any dynamic or callback models
- const idRenderModel * model = def->parms.hModel;
- if ( def->parms.callback != NULL || model == NULL || model->IsDynamicModel() != DM_STATIC ) {
- continue;
- }
- idBounds bounds;
- bounds.FromTransformedBounds( model->Bounds( &def->parms ), def->parms.origin, def->parms.axis );
- // if the model bounds do not overlap with the projection bounds
- decalProjectionParms_t localParms;
- if ( !globalParms.projectionBounds.IntersectsBounds( bounds ) ) {
- continue;
- }
- // transform the bounding planes, fade planes and texture axis into local space
- idRenderModelDecal::GlobalProjectionParmsToLocal( localParms, globalParms, def->parms.origin, def->parms.axis );
- localParms.force = ( def->parms.customShader != NULL );
- if ( def->decals == NULL ) {
- def->decals = AllocDecal( def->index, startTime );
- }
- def->decals->AddDeferredDecal( localParms );
- }
- }
- }
- /*
- ====================
- idRenderWorldLocal::ProjectDecal
- ====================
- */
- void idRenderWorldLocal::ProjectDecal( qhandle_t entityHandle, const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
- if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
- common->Error( "idRenderWorld::ProjectOverlay: index = %i", entityHandle );
- return;
- }
- idRenderEntityLocal *def = entityDefs[ entityHandle ];
- if ( def == NULL ) {
- return;
- }
- const idRenderModel *model = def->parms.hModel;
- if ( model == NULL || model->IsDynamicModel() != DM_STATIC || def->parms.callback != NULL ) {
- return;
- }
- decalProjectionParms_t globalParms;
- if ( !idRenderModelDecal::CreateProjectionParms( globalParms, winding, projectionOrigin, parallel, fadeDepth, material, startTime ) ) {
- return;
- }
- idBounds bounds;
- bounds.FromTransformedBounds( model->Bounds( &def->parms ), def->parms.origin, def->parms.axis );
- // if the model bounds do not overlap with the projection bounds
- if ( !globalParms.projectionBounds.IntersectsBounds( bounds ) ) {
- return;
- }
- // transform the bounding planes, fade planes and texture axis into local space
- decalProjectionParms_t localParms;
- idRenderModelDecal::GlobalProjectionParmsToLocal( localParms, globalParms, def->parms.origin, def->parms.axis );
- localParms.force = ( def->parms.customShader != NULL );
- if ( def->decals == NULL ) {
- def->decals = AllocDecal( def->index, startTime );
- }
- def->decals->AddDeferredDecal( localParms );
- }
- /*
- ====================
- idRenderWorldLocal::ProjectOverlay
- ====================
- */
- void idRenderWorldLocal::ProjectOverlay( qhandle_t entityHandle, const idPlane localTextureAxis[2], const idMaterial *material, const int startTime ) {
- if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
- common->Error( "idRenderWorld::ProjectOverlay: index = %i", entityHandle );
- return;
- }
- idRenderEntityLocal *def = entityDefs[ entityHandle ];
- if ( def == NULL ) {
- return;
- }
- const idRenderModel * model = def->parms.hModel;
- if ( model->IsDynamicModel() != DM_CACHED ) { // FIXME: probably should be MD5 only
- return;
- }
- overlayProjectionParms_t localParms;
- localParms.localTextureAxis[0] = localTextureAxis[0];
- localParms.localTextureAxis[1] = localTextureAxis[1];
- localParms.material = material;
- localParms.startTime = startTime;
- if ( def->overlays == NULL ) {
- def->overlays = AllocOverlay( def->index, startTime );
- }
- def->overlays->AddDeferredOverlay( localParms );
- }
- /*
- ====================
- idRenderWorldLocal::AllocDecal
- ====================
- */
- idRenderModelDecal * idRenderWorldLocal::AllocDecal( qhandle_t newEntityHandle, int startTime ) {
- int oldest = 0;
- int oldestTime = MAX_TYPE( oldestTime );
- for ( int i = 0; i < decals.Num(); i++ ) {
- if ( decals[i].lastStartTime < oldestTime ) {
- oldestTime = decals[i].lastStartTime;
- oldest = i;
- }
- }
- // remove any reference another model may still have to this decal
- if ( decals[oldest].entityHandle >= 0 && decals[oldest].entityHandle < entityDefs.Num() ) {
- idRenderEntityLocal *def = entityDefs[decals[oldest].entityHandle];
- if ( def != NULL && def->decals == decals[oldest].decals ) {
- def->decals = NULL;
- }
- }
- decals[oldest].entityHandle = newEntityHandle;
- decals[oldest].lastStartTime = startTime;
- decals[oldest].decals->ReUse();
- return decals[oldest].decals;
- }
- /*
- ====================
- idRenderWorldLocal::AllocOverlay
- ====================
- */
- idRenderModelOverlay * idRenderWorldLocal::AllocOverlay( qhandle_t newEntityHandle, int startTime ) {
- int oldest = 0;
- int oldestTime = MAX_TYPE( oldestTime );
- for ( int i = 0; i < overlays.Num(); i++ ) {
- if ( overlays[i].lastStartTime < oldestTime ) {
- oldestTime = overlays[i].lastStartTime;
- oldest = i;
- }
- }
- // remove any reference another model may still have to this overlay
- if ( overlays[oldest].entityHandle >= 0 && overlays[oldest].entityHandle < entityDefs.Num() ) {
- idRenderEntityLocal *def = entityDefs[overlays[oldest].entityHandle];
- if ( def != NULL && def->overlays == overlays[oldest].overlays ) {
- def->overlays = NULL;
- }
- }
- overlays[oldest].entityHandle = newEntityHandle;
- overlays[oldest].lastStartTime = startTime;
- overlays[oldest].overlays->ReUse();
- return overlays[oldest].overlays;
- }
- /*
- ====================
- idRenderWorldLocal::RemoveDecals
- ====================
- */
- void idRenderWorldLocal::RemoveDecals( qhandle_t entityHandle ) {
- if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
- common->Error( "idRenderWorld::ProjectOverlay: index = %i", entityHandle );
- return;
- }
- idRenderEntityLocal *def = entityDefs[ entityHandle ];
- if ( !def ) {
- return;
- }
- R_FreeEntityDefDecals( def );
- R_FreeEntityDefOverlay( def );
- }
- /*
- ====================
- idRenderWorldLocal::SetRenderView
- Sets the current view so any calls to the render world will use the correct parms.
- ====================
- */
- void idRenderWorldLocal::SetRenderView( const renderView_t *renderView ) {
- tr.primaryRenderView = *renderView;
- }
- /*
- ====================
- idRenderWorldLocal::RenderScene
- Draw a 3D view into a part of the window, then return
- to 2D drawing.
- Rendering a scene may require multiple views to be rendered
- to handle mirrors,
- ====================
- */
- void idRenderWorldLocal::RenderScene( const renderView_t *renderView ) {
- if ( !R_IsInitialized() ) {
- return;
- }
- renderView_t copy = *renderView;
- // skip front end rendering work, which will result
- // in only gui drawing
- if ( r_skipFrontEnd.GetBool() ) {
- return;
- }
- SCOPED_PROFILE_EVENT( "RenderWorld::RenderScene" );
- if ( renderView->fov_x <= 0 || renderView->fov_y <= 0 ) {
- common->Error( "idRenderWorld::RenderScene: bad FOVs: %f, %f", renderView->fov_x, renderView->fov_y );
- }
- // close any gui drawing
- tr.guiModel->EmitFullScreen();
- tr.guiModel->Clear();
- int startTime = Sys_Microseconds();
- // setup view parms for the initial view
- viewDef_t * parms = (viewDef_t *)R_ClearedFrameAlloc( sizeof( *parms ), FRAME_ALLOC_VIEW_DEF );
- parms->renderView = *renderView;
- if ( tr.takingScreenshot ) {
- parms->renderView.forceUpdate = true;
- }
- int windowWidth = tr.GetWidth();
- int windowHeight = tr.GetHeight();
- tr.PerformResolutionScaling( windowWidth, windowHeight );
- // screenFraction is just for quickly testing fill rate limitations
- if ( r_screenFraction.GetInteger() != 100 ) {
- windowWidth = ( windowWidth * r_screenFraction.GetInteger() ) / 100;
- windowHeight = ( windowHeight * r_screenFraction.GetInteger() ) / 100;
- }
- tr.CropRenderSize( windowWidth, windowHeight );
- tr.GetCroppedViewport( &parms->viewport );
- // the scissor bounds may be shrunk in subviews even if
- // the viewport stays the same
- // this scissor range is local inside the viewport
- parms->scissor.x1 = 0;
- parms->scissor.y1 = 0;
- parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
- parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
- parms->isSubview = false;
- parms->initialViewAreaOrigin = renderView->vieworg;
- parms->renderWorld = this;
- // see if the view needs to reverse the culling sense in mirrors
- // or environment cube sides
- idVec3 cross;
- cross = parms->renderView.viewaxis[1].Cross( parms->renderView.viewaxis[2] );
- if ( cross * parms->renderView.viewaxis[0] > 0 ) {
- parms->isMirror = false;
- } else {
- parms->isMirror = true;
- }
- // save this world for use by some console commands
- tr.primaryWorld = this;
- tr.primaryRenderView = *renderView;
- tr.primaryView = parms;
- // rendering this view may cause other views to be rendered
- // for mirrors / portals / shadows / environment maps
- // this will also cause any necessary entities and lights to be
- // updated to the demo file
- R_RenderView( parms );
- // render any post processing after the view and all its subviews has been draw
- R_RenderPostProcess( parms );
- // now write delete commands for any modified-but-not-visible entities, and
- // add the renderView command to the demo
- if ( common->WriteDemo() ) {
- WriteRenderView( renderView );
- }
- #if 0
- for ( int i = 0; i < entityDefs.Num(); i++ ) {
- idRenderEntityLocal *def = entityDefs[i];
- if ( !def ) {
- continue;
- }
- if ( def->parms.callback ) {
- continue;
- }
- if ( def->parms.hModel->IsDynamicModel() == DM_CONTINUOUS ) {
- }
- }
- #endif
- tr.UnCrop();
- int endTime = Sys_Microseconds();
- tr.pc.frontEndMicroSec += endTime - startTime;
- // prepare for any 2D drawing after this
- tr.guiModel->Clear();
- }
- /*
- ===================
- idRenderWorldLocal::NumAreas
- ===================
- */
- int idRenderWorldLocal::NumAreas() const {
- return numPortalAreas;
- }
- /*
- ===================
- idRenderWorldLocal::NumPortalsInArea
- ===================
- */
- int idRenderWorldLocal::NumPortalsInArea( int areaNum ) {
- portalArea_t *area;
- int count;
- portal_t *portal;
- if ( areaNum >= numPortalAreas || areaNum < 0 ) {
- common->Error( "idRenderWorld::NumPortalsInArea: bad areanum %i", areaNum );
- }
- area = &portalAreas[areaNum];
- count = 0;
- for ( portal = area->portals; portal; portal = portal->next ) {
- count++;
- }
- return count;
- }
- /*
- ===================
- idRenderWorldLocal::GetPortal
- ===================
- */
- exitPortal_t idRenderWorldLocal::GetPortal( int areaNum, int portalNum ) {
- portalArea_t *area;
- int count;
- portal_t *portal;
- exitPortal_t ret;
- if ( areaNum > numPortalAreas ) {
- common->Error( "idRenderWorld::GetPortal: areaNum > numAreas" );
- }
- area = &portalAreas[areaNum];
- count = 0;
- for ( portal = area->portals; portal; portal = portal->next ) {
- if ( count == portalNum ) {
- ret.areas[0] = areaNum;
- ret.areas[1] = portal->intoArea;
- ret.w = portal->w;
- ret.blockingBits = portal->doublePortal->blockingBits;
- ret.portalHandle = portal->doublePortal - doublePortals + 1;
- return ret;
- }
- count++;
- }
- common->Error( "idRenderWorld::GetPortal: portalNum > numPortals" );
- memset( &ret, 0, sizeof( ret ) );
- return ret;
- }
- /*
- ===============
- idRenderWorldLocal::PointInAreaNum
- Will return -1 if the point is not in an area, otherwise
- it will return 0 <= value < tr.world->numPortalAreas
- ===============
- */
- int idRenderWorldLocal::PointInArea( const idVec3 &point ) const {
- areaNode_t *node;
- int nodeNum;
- float d;
-
- node = areaNodes;
- if ( !node ) {
- return -1;
- }
- while( 1 ) {
- d = point * node->plane.Normal() + node->plane[3];
- if (d > 0) {
- nodeNum = node->children[0];
- } else {
- nodeNum = node->children[1];
- }
- if ( nodeNum == 0 ) {
- return -1; // in solid
- }
- if ( nodeNum < 0 ) {
- nodeNum = -1 - nodeNum;
- if ( nodeNum >= numPortalAreas ) {
- common->Error( "idRenderWorld::PointInArea: area out of range" );
- }
- return nodeNum;
- }
- node = areaNodes + nodeNum;
- }
-
- return -1;
- }
- /*
- ===================
- idRenderWorldLocal::BoundsInAreas_r
- ===================
- */
- void idRenderWorldLocal::BoundsInAreas_r( int nodeNum, const idBounds &bounds, int *areas, int *numAreas, int maxAreas ) const {
- int side, i;
- areaNode_t *node;
- do {
- if ( nodeNum < 0 ) {
- nodeNum = -1 - nodeNum;
- for ( i = 0; i < (*numAreas); i++ ) {
- if ( areas[i] == nodeNum ) {
- break;
- }
- }
- if ( i >= (*numAreas) && (*numAreas) < maxAreas ) {
- areas[(*numAreas)++] = nodeNum;
- }
- return;
- }
- node = areaNodes + nodeNum;
- side = bounds.PlaneSide( node->plane );
- if ( side == PLANESIDE_FRONT ) {
- nodeNum = node->children[0];
- }
- else if ( side == PLANESIDE_BACK ) {
- nodeNum = node->children[1];
- }
- else {
- if ( node->children[1] != 0 ) {
- BoundsInAreas_r( node->children[1], bounds, areas, numAreas, maxAreas );
- if ( (*numAreas) >= maxAreas ) {
- return;
- }
- }
- nodeNum = node->children[0];
- }
- } while( nodeNum != 0 );
- return;
- }
- /*
- ===================
- idRenderWorldLocal::BoundsInAreas
- fills the *areas array with the number of the areas the bounds are in
- returns the total number of areas the bounds are in
- ===================
- */
- int idRenderWorldLocal::BoundsInAreas( const idBounds &bounds, int *areas, int maxAreas ) const {
- int numAreas = 0;
- assert( areas );
- assert( bounds[0][0] <= bounds[1][0] && bounds[0][1] <= bounds[1][1] && bounds[0][2] <= bounds[1][2] );
- assert( bounds[1][0] - bounds[0][0] < 1e4f && bounds[1][1] - bounds[0][1] < 1e4f && bounds[1][2] - bounds[0][2] < 1e4f );
- if ( !areaNodes ) {
- return numAreas;
- }
- BoundsInAreas_r( 0, bounds, areas, &numAreas, maxAreas );
- return numAreas;
- }
- /*
- ================
- idRenderWorldLocal::GuiTrace
- checks a ray trace against any gui surfaces in an entity, returning the
- fraction location of the trace on the gui surface, or -1,-1 if no hit.
- this doesn't do any occlusion testing, simply ignoring non-gui surfaces.
- start / end are in global world coordinates.
- ================
- */
- guiPoint_t idRenderWorldLocal::GuiTrace( qhandle_t entityHandle, const idVec3 start, const idVec3 end ) const {
- guiPoint_t pt;
- pt.x = pt.y = -1;
- pt.guiId = 0;
- if ( ( entityHandle < 0 ) || ( entityHandle >= entityDefs.Num() ) ) {
- common->Printf( "idRenderWorld::GuiTrace: invalid handle %i\n", entityHandle );
- return pt;
- }
- idRenderEntityLocal * def = entityDefs[entityHandle];
- if ( def == NULL ) {
- common->Printf( "idRenderWorld::GuiTrace: handle %i is NULL\n", entityHandle );
- return pt;
- }
- idRenderModel * model = def->parms.hModel;
- if ( model == NULL || model->IsDynamicModel() != DM_STATIC || def->parms.callback != NULL ) {
- return pt;
- }
- // transform the points into local space
- idVec3 localStart, localEnd;
- R_GlobalPointToLocal( def->modelMatrix, start, localStart );
- R_GlobalPointToLocal( def->modelMatrix, end, localEnd );
- for ( int i = 0; i < model->NumSurfaces(); i++ ) {
- const modelSurface_t *surf = model->Surface( i );
- const srfTriangles_t * tri = surf->geometry;
- if ( tri == NULL ) {
- continue;
- }
- const idMaterial * shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
- if ( shader == NULL ) {
- continue;
- }
- // only trace against gui surfaces
- if ( !shader->HasGui() ) {
- continue;
- }
- localTrace_t local = R_LocalTrace( localStart, localEnd, 0.0f, tri );
- if ( local.fraction < 1.0f ) {
- idVec3 origin, axis[3];
- R_SurfaceToTextureAxis( tri, origin, axis );
- const idVec3 cursor = local.point - origin;
- float axisLen[2];
- axisLen[0] = axis[0].Length();
- axisLen[1] = axis[1].Length();
- pt.x = ( cursor * axis[0] ) / ( axisLen[0] * axisLen[0] );
- pt.y = ( cursor * axis[1] ) / ( axisLen[1] * axisLen[1] );
- pt.guiId = shader->GetEntityGui();
- return pt;
- }
- }
- return pt;
- }
- /*
- ===================
- idRenderWorldLocal::ModelTrace
- ===================
- */
- bool idRenderWorldLocal::ModelTrace( modelTrace_t &trace, qhandle_t entityHandle, const idVec3 &start, const idVec3 &end, const float radius ) const {
- memset( &trace, 0, sizeof( trace ) );
- trace.fraction = 1.0f;
- trace.point = end;
- if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
- return false;
- }
- idRenderEntityLocal *def = entityDefs[entityHandle];
- if ( def == NULL ) {
- return false;
- }
- renderEntity_t *refEnt = &def->parms;
- idRenderModel *model = R_EntityDefDynamicModel( def );
- if ( model == NULL ) {
- return false;
- }
- // transform the points into local space
- float modelMatrix[16];
- idVec3 localStart;
- idVec3 localEnd;
- R_AxisToModelMatrix( refEnt->axis, refEnt->origin, modelMatrix );
- R_GlobalPointToLocal( modelMatrix, start, localStart );
- R_GlobalPointToLocal( modelMatrix, end, localEnd );
- // if we have explicit collision surfaces, only collide against them
- // (FIXME, should probably have a parm to control this)
- bool collisionSurface = false;
- for ( int i = 0; i < model->NumBaseSurfaces(); i++ ) {
- const modelSurface_t *surf = model->Surface( i );
- const idMaterial *shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
- if ( shader->GetSurfaceFlags() & SURF_COLLISION ) {
- collisionSurface = true;
- break;
- }
- }
- // only use baseSurfaces, not any overlays
- for ( int i = 0; i < model->NumBaseSurfaces(); i++ ) {
- const modelSurface_t *surf = model->Surface( i );
- const idMaterial *shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
- if ( surf->geometry == NULL || shader == NULL ) {
- continue;
- }
- if ( collisionSurface ) {
- // only trace vs collision surfaces
- if ( ( shader->GetSurfaceFlags() & SURF_COLLISION ) == 0 ) {
- continue;
- }
- } else {
- // skip if not drawn or translucent
- if ( !shader->IsDrawn() || ( shader->Coverage() != MC_OPAQUE && shader->Coverage() != MC_PERFORATED ) ) {
- continue;
- }
- }
- localTrace_t localTrace = R_LocalTrace( localStart, localEnd, radius, surf->geometry );
- if ( localTrace.fraction < trace.fraction ) {
- trace.fraction = localTrace.fraction;
- R_LocalPointToGlobal( modelMatrix, localTrace.point, trace.point );
- trace.normal = localTrace.normal * refEnt->axis;
- trace.material = shader;
- trace.entity = &def->parms;
- trace.jointNumber = refEnt->hModel->NearestJoint( i, localTrace.indexes[0], localTrace.indexes[1], localTrace.indexes[2] );
- }
- }
- return ( trace.fraction < 1.0f );
- }
- /*
- ===================
- idRenderWorldLocal::Trace
- ===================
- */
- // FIXME: _D3XP added those.
- const char * playerModelExcludeList[] = {
- "models/md5/characters/player/d3xp_spplayer.md5mesh",
- "models/md5/characters/player/head/d3xp_head.md5mesh",
- "models/md5/weapons/pistol_world/worldpistol.md5mesh",
- NULL
- };
- const char * playerMaterialExcludeList[] = {
- "muzzlesmokepuff",
- NULL
- };
- bool idRenderWorldLocal::Trace( modelTrace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, bool skipDynamic, bool skipPlayer /*_D3XP*/ ) const {
- trace.fraction = 1.0f;
- trace.point = end;
- // bounds for the whole trace
- idBounds traceBounds;
- traceBounds.Clear();
- traceBounds.AddPoint( start );
- traceBounds.AddPoint( end );
- // get the world areas the trace is in
- int areas[128];
- int numAreas = BoundsInAreas( traceBounds, areas, 128 );
- int numSurfaces = 0;
- // check all areas for models
- for ( int i = 0; i < numAreas; i++ ) {
- portalArea_t * area = &portalAreas[ areas[i] ];
- // check all models in this area
- for ( areaReference_t * ref = area->entityRefs.areaNext; ref != &area->entityRefs; ref = ref->areaNext ) {
- idRenderEntityLocal * def = ref->entity;
- idRenderModel * model = def->parms.hModel;
- if ( model == NULL ) {
- continue;
- }
- if ( model->IsDynamicModel() != DM_STATIC ) {
- if ( skipDynamic ) {
- continue;
- }
- #if 1 /* _D3XP addition. could use a cleaner approach */
- if ( skipPlayer ) {
- bool exclude = false;
- for ( int k = 0; playerModelExcludeList[k] != NULL; k++ ) {
- if ( idStr::Cmp( model->Name(), playerModelExcludeList[k] ) == 0 ) {
- exclude = true;
- break;
- }
- }
- if ( exclude ) {
- continue;
- }
- }
- #endif
- model = R_EntityDefDynamicModel( def );
- if ( !model ) {
- continue; // can happen with particle systems, which don't instantiate without a valid view
- }
- }
- idBounds bounds;
- bounds.FromTransformedBounds( model->Bounds( &def->parms ), def->parms.origin, def->parms.axis );
- // if the model bounds do not overlap with the trace bounds
- if ( !traceBounds.IntersectsBounds( bounds ) || !bounds.LineIntersection( start, trace.point ) ) {
- continue;
- }
- // check all model surfaces
- for ( int j = 0; j < model->NumSurfaces(); j++ ) {
- const modelSurface_t *surf = model->Surface( j );
- const idMaterial * shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
- // if no geometry or no shader
- if ( surf->geometry == NULL || shader == NULL ) {
- continue;
- }
- #if 1 /* _D3XP addition. could use a cleaner approach */
- if ( skipPlayer ) {
- bool exclude = false;
- for ( int k = 0; playerMaterialExcludeList[k] != NULL; k++ ) {
- if ( idStr::Cmp( shader->GetName(), playerMaterialExcludeList[k] ) == 0 ) {
- exclude = true;
- break;
- }
- }
- if ( exclude ) {
- continue;
- }
- }
- #endif
- const srfTriangles_t * tri = surf->geometry;
- bounds.FromTransformedBounds( tri->bounds, def->parms.origin, def->parms.axis );
- // if triangle bounds do not overlap with the trace bounds
- if ( !traceBounds.IntersectsBounds( bounds ) || !bounds.LineIntersection( start, trace.point ) ) {
- continue;
- }
- numSurfaces++;
- // transform the points into local space
- float modelMatrix[16];
- idVec3 localStart, localEnd;
- R_AxisToModelMatrix( def->parms.axis, def->parms.origin, modelMatrix );
- R_GlobalPointToLocal( modelMatrix, start, localStart );
- R_GlobalPointToLocal( modelMatrix, end, localEnd );
- localTrace_t localTrace = R_LocalTrace( localStart, localEnd, radius, surf->geometry );
- if ( localTrace.fraction < trace.fraction ) {
- trace.fraction = localTrace.fraction;
- R_LocalPointToGlobal( modelMatrix, localTrace.point, trace.point );
- trace.normal = localTrace.normal * def->parms.axis;
- trace.material = shader;
- trace.entity = &def->parms;
- trace.jointNumber = model->NearestJoint( j, localTrace.indexes[0], localTrace.indexes[1], localTrace.indexes[2] );
- traceBounds.Clear();
- traceBounds.AddPoint( start );
- traceBounds.AddPoint( start + trace.fraction * (end - start) );
- }
- }
- }
- }
- return ( trace.fraction < 1.0f );
- }
- /*
- ==================
- idRenderWorldLocal::RecurseProcBSP
- ==================
- */
- void idRenderWorldLocal::RecurseProcBSP_r( modelTrace_t *results, int parentNodeNum, int nodeNum, float p1f, float p2f, const idVec3 &p1, const idVec3 &p2 ) const {
- float t1, t2;
- float frac;
- idVec3 mid;
- int side;
- float midf;
- areaNode_t *node;
- if ( results->fraction <= p1f) {
- return; // already hit something nearer
- }
- // empty leaf
- if ( nodeNum < 0 ) {
- return;
- }
- // if solid leaf node
- if ( nodeNum == 0 ) {
- if ( parentNodeNum != -1 ) {
- results->fraction = p1f;
- results->point = p1;
- node = &areaNodes[parentNodeNum];
- results->normal = node->plane.Normal();
- return;
- }
- }
- node = &areaNodes[nodeNum];
- // distance from plane for trace start and end
- t1 = node->plane.Normal() * p1 + node->plane[3];
- t2 = node->plane.Normal() * p2 + node->plane[3];
- if ( t1 >= 0.0f && t2 >= 0.0f ) {
- RecurseProcBSP_r( results, nodeNum, node->children[0], p1f, p2f, p1, p2 );
- return;
- }
- if ( t1 < 0.0f && t2 < 0.0f ) {
- RecurseProcBSP_r( results, nodeNum, node->children[1], p1f, p2f, p1, p2 );
- return;
- }
- side = t1 < t2;
- frac = t1 / (t1 - t2);
- midf = p1f + frac*(p2f - p1f);
- mid[0] = p1[0] + frac*(p2[0] - p1[0]);
- mid[1] = p1[1] + frac*(p2[1] - p1[1]);
- mid[2] = p1[2] + frac*(p2[2] - p1[2]);
- RecurseProcBSP_r( results, nodeNum, node->children[side], p1f, midf, p1, mid );
- RecurseProcBSP_r( results, nodeNum, node->children[side^1], midf, p2f, mid, p2 );
- }
- /*
- ==================
- idRenderWorldLocal::FastWorldTrace
- ==================
- */
- bool idRenderWorldLocal::FastWorldTrace( modelTrace_t &results, const idVec3 &start, const idVec3 &end ) const {
- memset( &results, 0, sizeof( modelTrace_t ) );
- results.fraction = 1.0f;
- if ( areaNodes != NULL ) {
- RecurseProcBSP_r( &results, -1, 0, 0.0f, 1.0f, start, end );
- return ( results.fraction < 1.0f );
- }
- return false;
- }
- /*
- =================================================================================
- CREATE MODEL REFS
- =================================================================================
- */
- /*
- =================
- idRenderWorldLocal::AddEntityRefToArea
- This is called by R_PushVolumeIntoTree and also directly
- for the world model references that are precalculated.
- =================
- */
- void idRenderWorldLocal::AddEntityRefToArea( idRenderEntityLocal *def, portalArea_t *area ) {
- areaReference_t *ref;
- if ( def == NULL ) {
- common->Error( "idRenderWorldLocal::AddEntityRefToArea: NULL def" );
- return;
- }
- for ( ref = def->entityRefs; ref != NULL; ref = ref->ownerNext ) {
- if ( ref->area == area ) {
- return;
- }
- }
- ref = areaReferenceAllocator.Alloc();
- tr.pc.c_entityReferences++;
- ref->entity = def;
- // link to entityDef
- ref->ownerNext = def->entityRefs;
- def->entityRefs = ref;
- // link to end of area list
- ref->area = area;
- ref->areaNext = &area->entityRefs;
- ref->areaPrev = area->entityRefs.areaPrev;
- ref->areaNext->areaPrev = ref;
- ref->areaPrev->areaNext = ref;
- }
- /*
- ===================
- idRenderWorldLocal::AddLightRefToArea
- ===================
- */
- void idRenderWorldLocal::AddLightRefToArea( idRenderLightLocal *light, portalArea_t *area ) {
- areaReference_t *lref;
- for ( lref = light->references; lref != NULL; lref = lref->ownerNext ) {
- if ( lref->area == area ) {
- return;
- }
- }
- // add a lightref to this area
- lref = areaReferenceAllocator.Alloc();
- lref->light = light;
- lref->area = area;
- lref->ownerNext = light->references;
- light->references = lref;
- tr.pc.c_lightReferences++;
- // doubly linked list so we can free them easily later
- area->lightRefs.areaNext->areaPrev = lref;
- lref->areaNext = area->lightRefs.areaNext;
- lref->areaPrev = &area->lightRefs;
- area->lightRefs.areaNext = lref;
- }
- /*
- ===================
- idRenderWorldLocal::GenerateAllInteractions
- Force the generation of all light / surface interactions at the start of a level
- If this isn't called, they will all be dynamically generated
- ===================
- */
- void idRenderWorldLocal::GenerateAllInteractions() {
- if ( !R_IsInitialized() ) {
- return;
- }
- int start = Sys_Milliseconds();
- generateAllInteractionsCalled = false;
- // let the interaction creation code know that it shouldn't
- // try and do any view specific optimizations
- tr.viewDef = NULL;
- // build the interaction table
- // this will be dynamically resized if the entity / light counts grow too much
- interactionTableWidth = entityDefs.Num() + 100;
- interactionTableHeight = lightDefs.Num() + 100;
- int size = interactionTableWidth * interactionTableHeight * sizeof( *interactionTable );
- interactionTable = (idInteraction **)R_ClearedStaticAlloc( size );
- // itterate through all lights
- int count = 0;
- for ( int i = 0; i < this->lightDefs.Num(); i++ ) {
- idRenderLightLocal *ldef = this->lightDefs[i];
- if ( ldef == NULL ) {
- continue;
- }
- // check all areas the light touches
- for ( areaReference_t *lref = ldef->references; lref; lref = lref->ownerNext ) {
- portalArea_t *area = lref->area;
- // check all the models in this area
- for ( areaReference_t *eref = area->entityRefs.areaNext; eref != &area->entityRefs; eref = eref->areaNext ) {
- idRenderEntityLocal *edef = eref->entity;
- // scan the doubly linked lists, which may have several dozen entries
- idInteraction *inter;
- // we could check either model refs or light refs for matches, but it is
- // assumed that there will be less lights in an area than models
- // so the entity chains should be somewhat shorter (they tend to be fairly close).
- for ( inter = edef->firstInteraction; inter != NULL; inter = inter->entityNext ) {
- if ( inter->lightDef == ldef ) {
- break;
- }
- }
- // if we already have an interaction, we don't need to do anything
- if ( inter != NULL ) {
- continue;
- }
- // make an interaction for this light / entity pair
- // and add a pointer to it in the table
- inter = idInteraction::AllocAndLink( edef, ldef );
- count++;
- // the interaction may create geometry
- inter->CreateStaticInteraction();
- }
- }
- session->Pump();
- }
- int end = Sys_Milliseconds();
- int msec = end - start;
- common->Printf( "idRenderWorld::GenerateAllInteractions, msec = %i\n", msec );
- common->Printf( "interactionTable size: %i bytes\n", size );
- common->Printf( "%i interactions take %i bytes\n", count, count * sizeof( idInteraction ) );
- // entities flagged as noDynamicInteractions will no longer make any
- generateAllInteractionsCalled = true;
- }
- /*
- ===================
- idRenderWorldLocal::FreeInteractions
- ===================
- */
- void idRenderWorldLocal::FreeInteractions() {
- int i;
- idRenderEntityLocal *def;
- for ( i = 0; i < entityDefs.Num(); i++ ) {
- def = entityDefs[i];
- if ( !def ) {
- continue;
- }
- // free all the interactions
- while ( def->firstInteraction != NULL ) {
- def->firstInteraction->UnlinkAndFree();
- }
- }
- }
- /*
- ==================
- idRenderWorldLocal::PushFrustumIntoTree_r
- Used for both light volumes and model volumes.
- This does not clip the points by the planes, so some slop
- occurs.
- tr.viewCount should be bumped before calling, allowing it
- to prevent double checking areas.
- We might alternatively choose to do this with an area flow.
- ==================
- */
- void idRenderWorldLocal::PushFrustumIntoTree_r( idRenderEntityLocal *def, idRenderLightLocal *light,
- const frustumCorners_t & corners, int nodeNum ) {
- if ( nodeNum < 0 ) {
- int areaNum = -1 - nodeNum;
- portalArea_t * area = &portalAreas[ areaNum ];
- if ( area->viewCount == tr.viewCount ) {
- return; // already added a reference here
- }
- area->viewCount = tr.viewCount;
- if ( def != NULL ) {
- AddEntityRefToArea( def, area );
- }
- if ( light != NULL ) {
- AddLightRefToArea( light, area );
- }
- return;
- }
- areaNode_t * node = areaNodes + nodeNum;
- // if we know that all possible children nodes only touch an area
- // we have already marked, we can early out
- if ( node->commonChildrenArea != CHILDREN_HAVE_MULTIPLE_AREAS && r_useNodeCommonChildren.GetBool() ) {
- // note that we do NOT try to set a reference in this area
- // yet, because the test volume may yet wind up being in the
- // solid part, which would cause bounds slightly poked into
- // a wall to show up in the next room
- if ( portalAreas[ node->commonChildrenArea ].viewCount == tr.viewCount ) {
- return;
- }
- }
- // exact check all the corners against the node plane
- frustumCull_t cull = idRenderMatrix::CullFrustumCornersToPlane( corners, node->plane );
- if ( cull != FRUSTUM_CULL_BACK ) {
- nodeNum = node->children[0];
- if ( nodeNum != 0 ) { // 0 = solid
- PushFrustumIntoTree_r( def, light, corners, nodeNum );
- }
- }
- if ( cull != FRUSTUM_CULL_FRONT ) {
- nodeNum = node->children[1];
- if ( nodeNum != 0 ) { // 0 = solid
- PushFrustumIntoTree_r( def, light, corners, nodeNum );
- }
- }
- }
- /*
- ==============
- idRenderWorldLocal::PushFrustumIntoTree
- ==============
- */
- void idRenderWorldLocal::PushFrustumIntoTree( idRenderEntityLocal *def, idRenderLightLocal *light, const idRenderMatrix & frustumTransform, const idBounds & frustumBounds ) {
- if ( areaNodes == NULL ) {
- return;
- }
- // calculate the corners of the frustum in word space
- ALIGNTYPE16 frustumCorners_t corners;
- idRenderMatrix::GetFrustumCorners( corners, frustumTransform, frustumBounds );
- PushFrustumIntoTree_r( def, light, corners, 0 );
- }
- //===================================================================
- /*
- ====================
- idRenderWorldLocal::DebugClearLines
- ====================
- */
- void idRenderWorldLocal::DebugClearLines( int time ) {
- RB_ClearDebugLines( time );
- RB_ClearDebugText( time );
- }
- /*
- ====================
- idRenderWorldLocal::DebugLine
- ====================
- */
- void idRenderWorldLocal::DebugLine( const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifetime, const bool depthTest ) {
- RB_AddDebugLine( color, start, end, lifetime, depthTest );
- }
- /*
- ================
- idRenderWorldLocal::DebugArrow
- ================
- */
- void idRenderWorldLocal::DebugArrow( const idVec4 &color, const idVec3 &start, const idVec3 &end, int size, const int lifetime ) {
- idVec3 forward, right, up, v1, v2;
- float a, s;
- int i;
- static float arrowCos[40];
- static float arrowSin[40];
- static int arrowStep;
- DebugLine( color, start, end, lifetime );
- if ( r_debugArrowStep.GetInteger() <= 10 ) {
- return;
- }
- // calculate sine and cosine when step size changes
- if ( arrowStep != r_debugArrowStep.GetInteger() ) {
- arrowStep = r_debugArrowStep.GetInteger();
- for ( i = 0, a = 0; a < 360.0f; a += arrowStep, i++ ) {
- arrowCos[i] = idMath::Cos16( DEG2RAD( a ) );
- arrowSin[i] = idMath::Sin16( DEG2RAD( a ) );
- }
- arrowCos[i] = arrowCos[0];
- arrowSin[i] = arrowSin[0];
- }
- // draw a nice arrow
- forward = end - start;
- forward.Normalize();
- forward.NormalVectors( right, up);
- for ( i = 0, a = 0; a < 360.0f; a += arrowStep, i++ ) {
- s = 0.5f * size * arrowCos[i];
- v1 = end - size * forward;
- v1 = v1 + s * right;
- s = 0.5f * size * arrowSin[i];
- v1 = v1 + s * up;
- s = 0.5f * size * arrowCos[i+1];
- v2 = end - size * forward;
- v2 = v2 + s * right;
- s = 0.5f * size * arrowSin[i+1];
- v2 = v2 + s * up;
- DebugLine( color, v1, end, lifetime );
- DebugLine( color, v1, v2, lifetime );
- }
- }
- /*
- ====================
- idRenderWorldLocal::DebugWinding
- ====================
- */
- void idRenderWorldLocal::DebugWinding( const idVec4 &color, const idWinding &w, const idVec3 &origin, const idMat3 &axis, const int lifetime, const bool depthTest ) {
- int i;
- idVec3 point, lastPoint;
- if ( w.GetNumPoints() < 2 ) {
- return;
- }
- lastPoint = origin + w[w.GetNumPoints()-1].ToVec3() * axis;
- for ( i = 0; i < w.GetNumPoints(); i++ ) {
- point = origin + w[i].ToVec3() * axis;
- DebugLine( color, lastPoint, point, lifetime, depthTest );
- lastPoint = point;
- }
- }
- /*
- ====================
- idRenderWorldLocal::DebugCircle
- ====================
- */
- void idRenderWorldLocal::DebugCircle( const idVec4 &color, const idVec3 &origin, const idVec3 &dir, const float radius, const int numSteps, const int lifetime, const bool depthTest ) {
- int i;
- float a;
- idVec3 left, up, point, lastPoint;
- dir.OrthogonalBasis( left, up );
- left *= radius;
- up *= radius;
- lastPoint = origin + up;
- for ( i = 1; i <= numSteps; i++ ) {
- a = idMath::TWO_PI * i / numSteps;
- point = origin + idMath::Sin16( a ) * left + idMath::Cos16( a ) * up;
- DebugLine( color, lastPoint, point, lifetime, depthTest );
- lastPoint = point;
- }
- }
- /*
- ============
- idRenderWorldLocal::DebugSphere
- ============
- */
- void idRenderWorldLocal::DebugSphere( const idVec4 &color, const idSphere &sphere, const int lifetime, const bool depthTest /*_D3XP*/ ) {
- int i, j, n, num;
- float s, c;
- idVec3 p, lastp, *lastArray;
- num = 360 / 15;
- lastArray = (idVec3 *) _alloca16( num * sizeof( idVec3 ) );
- lastArray[0] = sphere.GetOrigin() + idVec3( 0, 0, sphere.GetRadius() );
- for ( n = 1; n < num; n++ ) {
- lastArray[n] = lastArray[0];
- }
- for ( i = 15; i <= 360; i += 15 ) {
- s = idMath::Sin16( DEG2RAD(i) );
- c = idMath::Cos16( DEG2RAD(i) );
- lastp[0] = sphere.GetOrigin()[0];
- lastp[1] = sphere.GetOrigin()[1] + sphere.GetRadius() * s;
- lastp[2] = sphere.GetOrigin()[2] + sphere.GetRadius() * c;
- for ( n = 0, j = 15; j <= 360; j += 15, n++ ) {
- p[0] = sphere.GetOrigin()[0] + idMath::Sin16( DEG2RAD(j) ) * sphere.GetRadius() * s;
- p[1] = sphere.GetOrigin()[1] + idMath::Cos16( DEG2RAD(j) ) * sphere.GetRadius() * s;
- p[2] = lastp[2];
- DebugLine( color, lastp, p, lifetime,depthTest );
- DebugLine( color, lastp, lastArray[n], lifetime, depthTest );
- lastArray[n] = lastp;
- lastp = p;
- }
- }
- }
- /*
- ====================
- idRenderWorldLocal::DebugBounds
- ====================
- */
- void idRenderWorldLocal::DebugBounds( const idVec4 &color, const idBounds &bounds, const idVec3 &org, const int lifetime ) {
- int i;
- idVec3 v[8];
- if ( bounds.IsCleared() ) {
- return;
- }
- for ( i = 0; i < 8; i++ ) {
- v[i][0] = org[0] + bounds[(i^(i>>1))&1][0];
- v[i][1] = org[1] + bounds[(i>>1)&1][1];
- v[i][2] = org[2] + bounds[(i>>2)&1][2];
- }
- for ( i = 0; i < 4; i++ ) {
- DebugLine( color, v[i], v[(i+1)&3], lifetime );
- DebugLine( color, v[4+i], v[4+((i+1)&3)], lifetime );
- DebugLine( color, v[i], v[4+i], lifetime );
- }
- }
- /*
- ====================
- idRenderWorldLocal::DebugBox
- ====================
- */
- void idRenderWorldLocal::DebugBox( const idVec4 &color, const idBox &box, const int lifetime ) {
- int i;
- idVec3 v[8];
- box.ToPoints( v );
- for ( i = 0; i < 4; i++ ) {
- DebugLine( color, v[i], v[(i+1)&3], lifetime );
- DebugLine( color, v[4+i], v[4+((i+1)&3)], lifetime );
- DebugLine( color, v[i], v[4+i], lifetime );
- }
- }
- /*
- ============
- idRenderWorldLocal::DebugCone
- dir is the cone axis
- radius1 is the radius at the apex
- radius2 is the radius at apex+dir
- ============
- */
- void idRenderWorldLocal::DebugCone( const idVec4 &color, const idVec3 &apex, const idVec3 &dir, float radius1, float radius2, const int lifetime ) {
- int i;
- idMat3 axis;
- idVec3 top, p1, p2, lastp1, lastp2, d;
- axis[2] = dir;
- axis[2].Normalize();
- axis[2].NormalVectors( axis[0], axis[1] );
- axis[1] = -axis[1];
- top = apex + dir;
- lastp2 = top + radius2 * axis[1];
- if ( radius1 == 0.0f ) {
- for ( i = 20; i <= 360; i += 20 ) {
- d = idMath::Sin16( DEG2RAD(i) ) * axis[0] + idMath::Cos16( DEG2RAD(i) ) * axis[1];
- p2 = top + d * radius2;
- DebugLine( color, lastp2, p2, lifetime );
- DebugLine( color, p2, apex, lifetime );
- lastp2 = p2;
- }
- } else {
- lastp1 = apex + radius1 * axis[1];
- for ( i = 20; i <= 360; i += 20 ) {
- d = idMath::Sin16( DEG2RAD(i) ) * axis[0] + idMath::Cos16( DEG2RAD(i) ) * axis[1];
- p1 = apex + d * radius1;
- p2 = top + d * radius2;
- DebugLine( color, lastp1, p1, lifetime );
- DebugLine( color, lastp2, p2, lifetime );
- DebugLine( color, p1, p2, lifetime );
- lastp1 = p1;
- lastp2 = p2;
- }
- }
- }
- /*
- ================
- idRenderWorldLocal::DebugAxis
- ================
- */
- void idRenderWorldLocal::DebugAxis( const idVec3 &origin, const idMat3 &axis ) {
- idVec3 start = origin;
- idVec3 end = start + axis[0] * 20.0f;
- DebugArrow( colorWhite, start, end, 2 );
- end = start + axis[0] * -20.0f;
- DebugArrow( colorWhite, start, end, 2 );
- end = start + axis[1] * +20.0f;
- DebugArrow( colorGreen, start, end, 2 );
- end = start + axis[1] * -20.0f;
- DebugArrow( colorGreen, start, end, 2 );
- end = start + axis[2] * +20.0f;
- DebugArrow( colorBlue, start, end, 2 );
- end = start + axis[2] * -20.0f;
- DebugArrow( colorBlue, start, end, 2 );
- }
- /*
- ====================
- idRenderWorldLocal::DebugClearPolygons
- ====================
- */
- void idRenderWorldLocal::DebugClearPolygons( int time ) {
- RB_ClearDebugPolygons( time );
- }
- /*
- ====================
- idRenderWorldLocal::DebugPolygon
- ====================
- */
- void idRenderWorldLocal::DebugPolygon( const idVec4 &color, const idWinding &winding, const int lifeTime, const bool depthTest ) {
- RB_AddDebugPolygon( color, winding, lifeTime, depthTest );
- }
- /*
- ================
- idRenderWorldLocal::DebugScreenRect
- ================
- */
- void idRenderWorldLocal::DebugScreenRect( const idVec4 &color, const idScreenRect &rect, const viewDef_t *viewDef, const int lifetime ) {
- int i;
- float centerx, centery, dScale, hScale, vScale;
- idBounds bounds;
- idVec3 p[4];
- centerx = ( viewDef->viewport.x2 - viewDef->viewport.x1 ) * 0.5f;
- centery = ( viewDef->viewport.y2 - viewDef->viewport.y1 ) * 0.5f;
- dScale = r_znear.GetFloat() + 1.0f;
- hScale = dScale * idMath::Tan16( DEG2RAD( viewDef->renderView.fov_x * 0.5f ) );
- vScale = dScale * idMath::Tan16( DEG2RAD( viewDef->renderView.fov_y * 0.5f ) );
- bounds[0][0] = bounds[1][0] = dScale;
- bounds[0][1] = -( rect.x1 - centerx ) / centerx * hScale;
- bounds[1][1] = -( rect.x2 - centerx ) / centerx * hScale;
- bounds[0][2] = ( rect.y1 - centery ) / centery * vScale;
- bounds[1][2] = ( rect.y2 - centery ) / centery * vScale;
- for ( i = 0; i < 4; i++ ) {
- p[i].x = bounds[0][0];
- p[i].y = bounds[(i^(i>>1))&1].y;
- p[i].z = bounds[(i>>1)&1].z;
- p[i] = viewDef->renderView.vieworg + p[i] * viewDef->renderView.viewaxis;
- }
- for ( i = 0; i < 4; i++ ) {
- DebugLine( color, p[i], p[(i+1)&3], false );
- }
- }
- /*
- ================
- idRenderWorldLocal::DrawTextLength
- returns the length of the given text
- ================
- */
- float idRenderWorldLocal::DrawTextLength( const char *text, float scale, int len ) {
- return RB_DrawTextLength( text, scale, len );
- }
- /*
- ================
- idRenderWorldLocal::DrawText
- oriented on the viewaxis
- align can be 0-left, 1-center (default), 2-right
- ================
- */
- void idRenderWorldLocal::DrawText( const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align, const int lifetime, const bool depthTest ) {
- RB_AddDebugText( text, origin, scale, color, viewAxis, align, lifetime, depthTest );
- }
- /*
- ===============
- idRenderWorldLocal::RegenerateWorld
- ===============
- */
- void idRenderWorldLocal::RegenerateWorld() {
- R_FreeDerivedData();
- R_ReCreateWorldReferences();
- }
- /*
- ===============
- R_GlobalShaderOverride
- ===============
- */
- bool R_GlobalShaderOverride( const idMaterial **shader ) {
- if ( !(*shader)->IsDrawn() ) {
- return false;
- }
- if ( tr.primaryRenderView.globalMaterial ) {
- *shader = tr.primaryRenderView.globalMaterial;
- return true;
- }
- if ( r_materialOverride.GetString()[0] != '\0' ) {
- *shader = declManager->FindMaterial( r_materialOverride.GetString() );
- return true;
- }
-
- return false;
- }
- /*
- ===============
- R_RemapShaderBySkin
- ===============
- */
- const idMaterial *R_RemapShaderBySkin( const idMaterial *shader, const idDeclSkin *skin, const idMaterial *customShader ) {
- if ( !shader ) {
- return NULL;
- }
- // never remap surfaces that were originally nodraw, like collision hulls
- if ( !shader->IsDrawn() ) {
- return shader;
- }
- if ( customShader ) {
- // this is sort of a hack, but cause deformed surfaces to map to empty surfaces,
- // so the item highlight overlay doesn't highlight the autosprite surface
- if ( shader->Deform() ) {
- return NULL;
- }
- return const_cast<idMaterial *>(customShader);
- }
- if ( !skin ) {
- return const_cast<idMaterial *>(shader);
- }
- return skin->RemapShaderBySkin( shader );
- }
|