RenderWorld.cpp 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "tr_local.h"
  23. /*
  24. ===================
  25. R_ListRenderLightDefs_f
  26. ===================
  27. */
  28. void R_ListRenderLightDefs_f( const idCmdArgs &args ) {
  29. int i;
  30. idRenderLightLocal *ldef;
  31. if ( !tr.primaryWorld ) {
  32. return;
  33. }
  34. int active = 0;
  35. int totalRef = 0;
  36. int totalIntr = 0;
  37. for ( i = 0; i < tr.primaryWorld->lightDefs.Num(); i++ ) {
  38. ldef = tr.primaryWorld->lightDefs[i];
  39. if ( !ldef ) {
  40. common->Printf( "%4i: FREED\n", i );
  41. continue;
  42. }
  43. // count up the interactions
  44. int iCount = 0;
  45. for ( idInteraction *inter = ldef->firstInteraction; inter != NULL; inter = inter->lightNext ) {
  46. iCount++;
  47. }
  48. totalIntr += iCount;
  49. // count up the references
  50. int rCount = 0;
  51. for ( areaReference_t *ref = ldef->references; ref; ref = ref->ownerNext ) {
  52. rCount++;
  53. }
  54. totalRef += rCount;
  55. common->Printf( "%4i: %3i intr %2i refs %s\n", i, iCount, rCount, ldef->lightShader->GetName());
  56. active++;
  57. }
  58. common->Printf( "%i lightDefs, %i interactions, %i areaRefs\n", active, totalIntr, totalRef );
  59. }
  60. /*
  61. ===================
  62. R_ListRenderEntityDefs_f
  63. ===================
  64. */
  65. void R_ListRenderEntityDefs_f( const idCmdArgs &args ) {
  66. int i;
  67. idRenderEntityLocal *mdef;
  68. if ( !tr.primaryWorld ) {
  69. return;
  70. }
  71. int active = 0;
  72. int totalRef = 0;
  73. int totalIntr = 0;
  74. for ( i = 0; i < tr.primaryWorld->entityDefs.Num(); i++ ) {
  75. mdef = tr.primaryWorld->entityDefs[i];
  76. if ( !mdef ) {
  77. common->Printf( "%4i: FREED\n", i );
  78. continue;
  79. }
  80. // count up the interactions
  81. int iCount = 0;
  82. for ( idInteraction *inter = mdef->firstInteraction; inter != NULL; inter = inter->entityNext ) {
  83. iCount++;
  84. }
  85. totalIntr += iCount;
  86. // count up the references
  87. int rCount = 0;
  88. for ( areaReference_t *ref = mdef->entityRefs; ref; ref = ref->ownerNext ) {
  89. rCount++;
  90. }
  91. totalRef += rCount;
  92. common->Printf( "%4i: %3i intr %2i refs %s\n", i, iCount, rCount, mdef->parms.hModel->Name());
  93. active++;
  94. }
  95. common->Printf( "total active: %i\n", active );
  96. }
  97. /*
  98. ===================
  99. idRenderWorldLocal::idRenderWorldLocal
  100. ===================
  101. */
  102. idRenderWorldLocal::idRenderWorldLocal() {
  103. mapName.Clear();
  104. mapTimeStamp = FILE_NOT_FOUND_TIMESTAMP;
  105. generateAllInteractionsCalled = false;
  106. areaNodes = NULL;
  107. numAreaNodes = 0;
  108. portalAreas = NULL;
  109. numPortalAreas = 0;
  110. doublePortals = NULL;
  111. numInterAreaPortals = 0;
  112. interactionTable = 0;
  113. interactionTableWidth = 0;
  114. interactionTableHeight = 0;
  115. for ( int i = 0; i < decals.Num(); i++ ) {
  116. decals[i].entityHandle = -1;
  117. decals[i].lastStartTime = 0;
  118. decals[i].decals = new (TAG_MODEL) idRenderModelDecal();
  119. }
  120. for ( int i = 0; i < overlays.Num(); i++ ) {
  121. overlays[i].entityHandle = -1;
  122. overlays[i].lastStartTime = 0;
  123. overlays[i].overlays = new (TAG_MODEL) idRenderModelOverlay();
  124. }
  125. }
  126. /*
  127. ===================
  128. idRenderWorldLocal::~idRenderWorldLocal
  129. ===================
  130. */
  131. idRenderWorldLocal::~idRenderWorldLocal() {
  132. // free all the entityDefs, lightDefs, portals, etc
  133. FreeWorld();
  134. for ( int i = 0; i < decals.Num(); i++ ) {
  135. delete decals[i].decals;
  136. }
  137. for ( int i = 0; i < overlays.Num(); i++ ) {
  138. delete overlays[i].overlays;
  139. }
  140. // free up the debug lines, polys, and text
  141. RB_ClearDebugPolygons( 0 );
  142. RB_ClearDebugLines( 0 );
  143. RB_ClearDebugText( 0 );
  144. }
  145. /*
  146. ===================
  147. ResizeInteractionTable
  148. ===================
  149. */
  150. void idRenderWorldLocal::ResizeInteractionTable() {
  151. // we overflowed the interaction table, so make it larger
  152. common->Printf( "idRenderWorldLocal::ResizeInteractionTable: overflowed interactionTable, resizing\n" );
  153. const int oldInteractionTableWidth = interactionTableWidth;
  154. const int oldIinteractionTableHeight = interactionTableHeight;
  155. idInteraction ** oldInteractionTable = interactionTable;
  156. // build the interaction table
  157. // this will be dynamically resized if the entity / light counts grow too much
  158. interactionTableWidth = entityDefs.Num() + 100;
  159. interactionTableHeight = lightDefs.Num() + 100;
  160. const int size = interactionTableWidth * interactionTableHeight * sizeof( *interactionTable );
  161. interactionTable = (idInteraction **)R_ClearedStaticAlloc( size );
  162. for ( int l = 0; l < oldIinteractionTableHeight; l++ ) {
  163. for ( int e = 0; e < oldInteractionTableWidth; e++ ) {
  164. interactionTable[ l * interactionTableWidth + e ] = oldInteractionTable[ l * oldInteractionTableWidth + e ];
  165. }
  166. }
  167. R_StaticFree( oldInteractionTable );
  168. }
  169. /*
  170. ===================
  171. AddEntityDef
  172. ===================
  173. */
  174. qhandle_t idRenderWorldLocal::AddEntityDef( const renderEntity_t *re ){
  175. // try and reuse a free spot
  176. int entityHandle = entityDefs.FindNull();
  177. if ( entityHandle == -1 ) {
  178. entityHandle = entityDefs.Append( NULL );
  179. if ( interactionTable && entityDefs.Num() > interactionTableWidth ) {
  180. ResizeInteractionTable();
  181. }
  182. }
  183. UpdateEntityDef( entityHandle, re );
  184. return entityHandle;
  185. }
  186. /*
  187. ==============
  188. UpdateEntityDef
  189. Does not write to the demo file, which will only be updated for
  190. visible entities
  191. ==============
  192. */
  193. int c_callbackUpdate;
  194. void idRenderWorldLocal::UpdateEntityDef( qhandle_t entityHandle, const renderEntity_t *re ) {
  195. if ( r_skipUpdates.GetBool() ) {
  196. return;
  197. }
  198. tr.pc.c_entityUpdates++;
  199. if ( !re->hModel && !re->callback ) {
  200. common->Error( "idRenderWorld::UpdateEntityDef: NULL hModel" );
  201. }
  202. // create new slots if needed
  203. if ( entityHandle < 0 || entityHandle > LUDICROUS_INDEX ) {
  204. common->Error( "idRenderWorld::UpdateEntityDef: index = %i", entityHandle );
  205. }
  206. while ( entityHandle >= entityDefs.Num() ) {
  207. entityDefs.Append( NULL );
  208. }
  209. idRenderEntityLocal *def = entityDefs[entityHandle];
  210. if ( def != NULL ) {
  211. if ( !re->forceUpdate ) {
  212. // check for exact match (OPTIMIZE: check through pointers more)
  213. if ( !re->joints && !re->callbackData && !def->dynamicModel && !memcmp( re, &def->parms, sizeof( *re ) ) ) {
  214. return;
  215. }
  216. // if the only thing that changed was shaderparms, we can just leave things as they are
  217. // after updating parms
  218. // if we have a callback function and the bounds, origin, axis and model match,
  219. // then we can leave the references as they are
  220. if ( re->callback ) {
  221. bool axisMatch = ( re->axis == def->parms.axis );
  222. bool originMatch = ( re->origin == def->parms.origin );
  223. bool boundsMatch = ( re->bounds == def->localReferenceBounds );
  224. bool modelMatch = ( re->hModel == def->parms.hModel );
  225. if ( boundsMatch && originMatch && axisMatch && modelMatch ) {
  226. // only clear the dynamic model and interaction surfaces if they exist
  227. c_callbackUpdate++;
  228. R_ClearEntityDefDynamicModel( def );
  229. def->parms = *re;
  230. return;
  231. }
  232. }
  233. }
  234. // save any decals if the model is the same, allowing marks to move with entities
  235. if ( def->parms.hModel == re->hModel ) {
  236. R_FreeEntityDefDerivedData( def, true, true );
  237. } else {
  238. R_FreeEntityDefDerivedData( def, false, false );
  239. }
  240. } else {
  241. // creating a new one
  242. def = new (TAG_RENDER_ENTITY) idRenderEntityLocal;
  243. entityDefs[entityHandle] = def;
  244. def->world = this;
  245. def->index = entityHandle;
  246. }
  247. def->parms = *re;
  248. def->lastModifiedFrameNum = tr.frameCount;
  249. if ( common->WriteDemo() && def->archived ) {
  250. WriteFreeEntity( entityHandle );
  251. def->archived = false;
  252. }
  253. // optionally immediately issue any callbacks
  254. if ( !r_useEntityCallbacks.GetBool() && def->parms.callback != NULL ) {
  255. R_IssueEntityDefCallback( def );
  256. }
  257. // trigger entities don't need to get linked in and processed,
  258. // they only exist for editor use
  259. if ( def->parms.hModel != NULL && !def->parms.hModel->ModelHasDrawingSurfaces() ) {
  260. return;
  261. }
  262. // based on the model bounds, add references in each area
  263. // that may contain the updated surface
  264. R_CreateEntityRefs( def );
  265. }
  266. /*
  267. ===================
  268. FreeEntityDef
  269. Frees all references and lit surfaces from the model, and
  270. NULL's out it's entry in the world list
  271. ===================
  272. */
  273. void idRenderWorldLocal::FreeEntityDef( qhandle_t entityHandle ) {
  274. idRenderEntityLocal *def;
  275. if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
  276. common->Printf( "idRenderWorld::FreeEntityDef: handle %i > %i\n", entityHandle, entityDefs.Num() );
  277. return;
  278. }
  279. def = entityDefs[entityHandle];
  280. if ( !def ) {
  281. common->Printf( "idRenderWorld::FreeEntityDef: handle %i is NULL\n", entityHandle );
  282. return;
  283. }
  284. R_FreeEntityDefDerivedData( def, false, false );
  285. if ( common->WriteDemo() && def->archived ) {
  286. WriteFreeEntity( entityHandle );
  287. }
  288. // if we are playing a demo, these will have been freed
  289. // in R_FreeEntityDefDerivedData(), otherwise the gui
  290. // object still exists in the game
  291. def->parms.gui[ 0 ] = NULL;
  292. def->parms.gui[ 1 ] = NULL;
  293. def->parms.gui[ 2 ] = NULL;
  294. delete def;
  295. entityDefs[ entityHandle ] = NULL;
  296. }
  297. /*
  298. ==================
  299. GetRenderEntity
  300. ==================
  301. */
  302. const renderEntity_t *idRenderWorldLocal::GetRenderEntity( qhandle_t entityHandle ) const {
  303. idRenderEntityLocal *def;
  304. if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
  305. common->Printf( "idRenderWorld::GetRenderEntity: invalid handle %i [0, %i]\n", entityHandle, entityDefs.Num() );
  306. return NULL;
  307. }
  308. def = entityDefs[entityHandle];
  309. if ( !def ) {
  310. common->Printf( "idRenderWorld::GetRenderEntity: handle %i is NULL\n", entityHandle );
  311. return NULL;
  312. }
  313. return &def->parms;
  314. }
  315. /*
  316. ==================
  317. AddLightDef
  318. ==================
  319. */
  320. qhandle_t idRenderWorldLocal::AddLightDef( const renderLight_t *rlight ) {
  321. // try and reuse a free spot
  322. int lightHandle = lightDefs.FindNull();
  323. if ( lightHandle == -1 ) {
  324. lightHandle = lightDefs.Append( NULL );
  325. if ( interactionTable && lightDefs.Num() > interactionTableHeight ) {
  326. ResizeInteractionTable();
  327. }
  328. }
  329. UpdateLightDef( lightHandle, rlight );
  330. return lightHandle;
  331. }
  332. /*
  333. =================
  334. UpdateLightDef
  335. The generation of all the derived interaction data will
  336. usually be deferred until it is visible in a scene
  337. Does not write to the demo file, which will only be done for visible lights
  338. =================
  339. */
  340. void idRenderWorldLocal::UpdateLightDef( qhandle_t lightHandle, const renderLight_t *rlight ) {
  341. if ( r_skipUpdates.GetBool() ) {
  342. return;
  343. }
  344. tr.pc.c_lightUpdates++;
  345. // create new slots if needed
  346. if ( lightHandle < 0 || lightHandle > LUDICROUS_INDEX ) {
  347. common->Error( "idRenderWorld::UpdateLightDef: index = %i", lightHandle );
  348. }
  349. while ( lightHandle >= lightDefs.Num() ) {
  350. lightDefs.Append( NULL );
  351. }
  352. bool justUpdate = false;
  353. idRenderLightLocal *light = lightDefs[lightHandle];
  354. if ( light ) {
  355. // if the shape of the light stays the same, we don't need to dump
  356. // any of our derived data, because shader parms are calculated every frame
  357. if ( rlight->axis == light->parms.axis && rlight->end == light->parms.end &&
  358. rlight->lightCenter == light->parms.lightCenter && rlight->lightRadius == light->parms.lightRadius &&
  359. rlight->noShadows == light->parms.noShadows && rlight->origin == light->parms.origin &&
  360. rlight->parallel == light->parms.parallel && rlight->pointLight == light->parms.pointLight &&
  361. rlight->right == light->parms.right && rlight->start == light->parms.start &&
  362. rlight->target == light->parms.target && rlight->up == light->parms.up &&
  363. rlight->shader == light->lightShader && rlight->prelightModel == light->parms.prelightModel ) {
  364. justUpdate = true;
  365. } else {
  366. // if we are updating shadows, the prelight model is no longer valid
  367. light->lightHasMoved = true;
  368. R_FreeLightDefDerivedData( light );
  369. }
  370. } else {
  371. // create a new one
  372. light = new (TAG_RENDER_LIGHT) idRenderLightLocal;
  373. lightDefs[lightHandle] = light;
  374. light->world = this;
  375. light->index = lightHandle;
  376. }
  377. light->parms = *rlight;
  378. light->lastModifiedFrameNum = tr.frameCount;
  379. if ( common->WriteDemo() && light->archived ) {
  380. WriteFreeLight( lightHandle );
  381. light->archived = false;
  382. }
  383. // new for BFG edition: force noShadows on spectrum lights so teleport spawns
  384. // don't cause such a slowdown. Hell writing shouldn't be shadowed anyway...
  385. if ( light->parms.shader && light->parms.shader->Spectrum() ) {
  386. light->parms.noShadows = true;
  387. }
  388. if ( light->lightHasMoved ) {
  389. light->parms.prelightModel = NULL;
  390. }
  391. if ( !justUpdate ) {
  392. R_CreateLightRefs( light );
  393. }
  394. }
  395. /*
  396. ====================
  397. FreeLightDef
  398. Frees all references and lit surfaces from the light, and
  399. NULL's out it's entry in the world list
  400. ====================
  401. */
  402. void idRenderWorldLocal::FreeLightDef( qhandle_t lightHandle ) {
  403. idRenderLightLocal *light;
  404. if ( lightHandle < 0 || lightHandle >= lightDefs.Num() ) {
  405. common->Printf( "idRenderWorld::FreeLightDef: invalid handle %i [0, %i]\n", lightHandle, lightDefs.Num() );
  406. return;
  407. }
  408. light = lightDefs[lightHandle];
  409. if ( !light ) {
  410. common->Printf( "idRenderWorld::FreeLightDef: handle %i is NULL\n", lightHandle );
  411. return;
  412. }
  413. R_FreeLightDefDerivedData( light );
  414. if ( common->WriteDemo() && light->archived ) {
  415. WriteFreeLight( lightHandle );
  416. }
  417. delete light;
  418. lightDefs[lightHandle] = NULL;
  419. }
  420. /*
  421. ==================
  422. GetRenderLight
  423. ==================
  424. */
  425. const renderLight_t *idRenderWorldLocal::GetRenderLight( qhandle_t lightHandle ) const {
  426. idRenderLightLocal *def;
  427. if ( lightHandle < 0 || lightHandle >= lightDefs.Num() ) {
  428. common->Printf( "idRenderWorld::GetRenderLight: handle %i > %i\n", lightHandle, lightDefs.Num() );
  429. return NULL;
  430. }
  431. def = lightDefs[lightHandle];
  432. if ( !def ) {
  433. common->Printf( "idRenderWorld::GetRenderLight: handle %i is NULL\n", lightHandle );
  434. return NULL;
  435. }
  436. return &def->parms;
  437. }
  438. /*
  439. ================
  440. idRenderWorldLocal::ProjectDecalOntoWorld
  441. ================
  442. */
  443. void idRenderWorldLocal::ProjectDecalOntoWorld( const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
  444. decalProjectionParms_t globalParms;
  445. if ( !idRenderModelDecal::CreateProjectionParms( globalParms, winding, projectionOrigin, parallel, fadeDepth, material, startTime ) ) {
  446. return;
  447. }
  448. // get the world areas touched by the projection volume
  449. int areas[10];
  450. int numAreas = BoundsInAreas( globalParms.projectionBounds, areas, 10 );
  451. // check all areas for models
  452. for ( int i = 0; i < numAreas; i++ ) {
  453. const portalArea_t * area = &portalAreas[ areas[i] ];
  454. // check all models in this area
  455. for ( const areaReference_t * ref = area->entityRefs.areaNext; ref != &area->entityRefs; ref = ref->areaNext ) {
  456. idRenderEntityLocal * def = ref->entity;
  457. if ( def->parms.noOverlays ) {
  458. continue;
  459. }
  460. if ( def->parms.customShader != NULL && !def->parms.customShader->AllowOverlays() ) {
  461. continue;
  462. }
  463. // completely ignore any dynamic or callback models
  464. const idRenderModel * model = def->parms.hModel;
  465. if ( def->parms.callback != NULL || model == NULL || model->IsDynamicModel() != DM_STATIC ) {
  466. continue;
  467. }
  468. idBounds bounds;
  469. bounds.FromTransformedBounds( model->Bounds( &def->parms ), def->parms.origin, def->parms.axis );
  470. // if the model bounds do not overlap with the projection bounds
  471. decalProjectionParms_t localParms;
  472. if ( !globalParms.projectionBounds.IntersectsBounds( bounds ) ) {
  473. continue;
  474. }
  475. // transform the bounding planes, fade planes and texture axis into local space
  476. idRenderModelDecal::GlobalProjectionParmsToLocal( localParms, globalParms, def->parms.origin, def->parms.axis );
  477. localParms.force = ( def->parms.customShader != NULL );
  478. if ( def->decals == NULL ) {
  479. def->decals = AllocDecal( def->index, startTime );
  480. }
  481. def->decals->AddDeferredDecal( localParms );
  482. }
  483. }
  484. }
  485. /*
  486. ====================
  487. idRenderWorldLocal::ProjectDecal
  488. ====================
  489. */
  490. void idRenderWorldLocal::ProjectDecal( qhandle_t entityHandle, const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
  491. if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
  492. common->Error( "idRenderWorld::ProjectOverlay: index = %i", entityHandle );
  493. return;
  494. }
  495. idRenderEntityLocal *def = entityDefs[ entityHandle ];
  496. if ( def == NULL ) {
  497. return;
  498. }
  499. const idRenderModel *model = def->parms.hModel;
  500. if ( model == NULL || model->IsDynamicModel() != DM_STATIC || def->parms.callback != NULL ) {
  501. return;
  502. }
  503. decalProjectionParms_t globalParms;
  504. if ( !idRenderModelDecal::CreateProjectionParms( globalParms, winding, projectionOrigin, parallel, fadeDepth, material, startTime ) ) {
  505. return;
  506. }
  507. idBounds bounds;
  508. bounds.FromTransformedBounds( model->Bounds( &def->parms ), def->parms.origin, def->parms.axis );
  509. // if the model bounds do not overlap with the projection bounds
  510. if ( !globalParms.projectionBounds.IntersectsBounds( bounds ) ) {
  511. return;
  512. }
  513. // transform the bounding planes, fade planes and texture axis into local space
  514. decalProjectionParms_t localParms;
  515. idRenderModelDecal::GlobalProjectionParmsToLocal( localParms, globalParms, def->parms.origin, def->parms.axis );
  516. localParms.force = ( def->parms.customShader != NULL );
  517. if ( def->decals == NULL ) {
  518. def->decals = AllocDecal( def->index, startTime );
  519. }
  520. def->decals->AddDeferredDecal( localParms );
  521. }
  522. /*
  523. ====================
  524. idRenderWorldLocal::ProjectOverlay
  525. ====================
  526. */
  527. void idRenderWorldLocal::ProjectOverlay( qhandle_t entityHandle, const idPlane localTextureAxis[2], const idMaterial *material, const int startTime ) {
  528. if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
  529. common->Error( "idRenderWorld::ProjectOverlay: index = %i", entityHandle );
  530. return;
  531. }
  532. idRenderEntityLocal *def = entityDefs[ entityHandle ];
  533. if ( def == NULL ) {
  534. return;
  535. }
  536. const idRenderModel * model = def->parms.hModel;
  537. if ( model->IsDynamicModel() != DM_CACHED ) { // FIXME: probably should be MD5 only
  538. return;
  539. }
  540. overlayProjectionParms_t localParms;
  541. localParms.localTextureAxis[0] = localTextureAxis[0];
  542. localParms.localTextureAxis[1] = localTextureAxis[1];
  543. localParms.material = material;
  544. localParms.startTime = startTime;
  545. if ( def->overlays == NULL ) {
  546. def->overlays = AllocOverlay( def->index, startTime );
  547. }
  548. def->overlays->AddDeferredOverlay( localParms );
  549. }
  550. /*
  551. ====================
  552. idRenderWorldLocal::AllocDecal
  553. ====================
  554. */
  555. idRenderModelDecal * idRenderWorldLocal::AllocDecal( qhandle_t newEntityHandle, int startTime ) {
  556. int oldest = 0;
  557. int oldestTime = MAX_TYPE( oldestTime );
  558. for ( int i = 0; i < decals.Num(); i++ ) {
  559. if ( decals[i].lastStartTime < oldestTime ) {
  560. oldestTime = decals[i].lastStartTime;
  561. oldest = i;
  562. }
  563. }
  564. // remove any reference another model may still have to this decal
  565. if ( decals[oldest].entityHandle >= 0 && decals[oldest].entityHandle < entityDefs.Num() ) {
  566. idRenderEntityLocal *def = entityDefs[decals[oldest].entityHandle];
  567. if ( def != NULL && def->decals == decals[oldest].decals ) {
  568. def->decals = NULL;
  569. }
  570. }
  571. decals[oldest].entityHandle = newEntityHandle;
  572. decals[oldest].lastStartTime = startTime;
  573. decals[oldest].decals->ReUse();
  574. return decals[oldest].decals;
  575. }
  576. /*
  577. ====================
  578. idRenderWorldLocal::AllocOverlay
  579. ====================
  580. */
  581. idRenderModelOverlay * idRenderWorldLocal::AllocOverlay( qhandle_t newEntityHandle, int startTime ) {
  582. int oldest = 0;
  583. int oldestTime = MAX_TYPE( oldestTime );
  584. for ( int i = 0; i < overlays.Num(); i++ ) {
  585. if ( overlays[i].lastStartTime < oldestTime ) {
  586. oldestTime = overlays[i].lastStartTime;
  587. oldest = i;
  588. }
  589. }
  590. // remove any reference another model may still have to this overlay
  591. if ( overlays[oldest].entityHandle >= 0 && overlays[oldest].entityHandle < entityDefs.Num() ) {
  592. idRenderEntityLocal *def = entityDefs[overlays[oldest].entityHandle];
  593. if ( def != NULL && def->overlays == overlays[oldest].overlays ) {
  594. def->overlays = NULL;
  595. }
  596. }
  597. overlays[oldest].entityHandle = newEntityHandle;
  598. overlays[oldest].lastStartTime = startTime;
  599. overlays[oldest].overlays->ReUse();
  600. return overlays[oldest].overlays;
  601. }
  602. /*
  603. ====================
  604. idRenderWorldLocal::RemoveDecals
  605. ====================
  606. */
  607. void idRenderWorldLocal::RemoveDecals( qhandle_t entityHandle ) {
  608. if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
  609. common->Error( "idRenderWorld::ProjectOverlay: index = %i", entityHandle );
  610. return;
  611. }
  612. idRenderEntityLocal *def = entityDefs[ entityHandle ];
  613. if ( !def ) {
  614. return;
  615. }
  616. R_FreeEntityDefDecals( def );
  617. R_FreeEntityDefOverlay( def );
  618. }
  619. /*
  620. ====================
  621. idRenderWorldLocal::SetRenderView
  622. Sets the current view so any calls to the render world will use the correct parms.
  623. ====================
  624. */
  625. void idRenderWorldLocal::SetRenderView( const renderView_t *renderView ) {
  626. tr.primaryRenderView = *renderView;
  627. }
  628. /*
  629. ====================
  630. idRenderWorldLocal::RenderScene
  631. Draw a 3D view into a part of the window, then return
  632. to 2D drawing.
  633. Rendering a scene may require multiple views to be rendered
  634. to handle mirrors,
  635. ====================
  636. */
  637. void idRenderWorldLocal::RenderScene( const renderView_t *renderView ) {
  638. if ( !R_IsInitialized() ) {
  639. return;
  640. }
  641. renderView_t copy = *renderView;
  642. // skip front end rendering work, which will result
  643. // in only gui drawing
  644. if ( r_skipFrontEnd.GetBool() ) {
  645. return;
  646. }
  647. SCOPED_PROFILE_EVENT( "RenderWorld::RenderScene" );
  648. if ( renderView->fov_x <= 0 || renderView->fov_y <= 0 ) {
  649. common->Error( "idRenderWorld::RenderScene: bad FOVs: %f, %f", renderView->fov_x, renderView->fov_y );
  650. }
  651. // close any gui drawing
  652. tr.guiModel->EmitFullScreen();
  653. tr.guiModel->Clear();
  654. int startTime = Sys_Microseconds();
  655. // setup view parms for the initial view
  656. viewDef_t * parms = (viewDef_t *)R_ClearedFrameAlloc( sizeof( *parms ), FRAME_ALLOC_VIEW_DEF );
  657. parms->renderView = *renderView;
  658. if ( tr.takingScreenshot ) {
  659. parms->renderView.forceUpdate = true;
  660. }
  661. int windowWidth = tr.GetWidth();
  662. int windowHeight = tr.GetHeight();
  663. tr.PerformResolutionScaling( windowWidth, windowHeight );
  664. // screenFraction is just for quickly testing fill rate limitations
  665. if ( r_screenFraction.GetInteger() != 100 ) {
  666. windowWidth = ( windowWidth * r_screenFraction.GetInteger() ) / 100;
  667. windowHeight = ( windowHeight * r_screenFraction.GetInteger() ) / 100;
  668. }
  669. tr.CropRenderSize( windowWidth, windowHeight );
  670. tr.GetCroppedViewport( &parms->viewport );
  671. // the scissor bounds may be shrunk in subviews even if
  672. // the viewport stays the same
  673. // this scissor range is local inside the viewport
  674. parms->scissor.x1 = 0;
  675. parms->scissor.y1 = 0;
  676. parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
  677. parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
  678. parms->isSubview = false;
  679. parms->initialViewAreaOrigin = renderView->vieworg;
  680. parms->renderWorld = this;
  681. // see if the view needs to reverse the culling sense in mirrors
  682. // or environment cube sides
  683. idVec3 cross;
  684. cross = parms->renderView.viewaxis[1].Cross( parms->renderView.viewaxis[2] );
  685. if ( cross * parms->renderView.viewaxis[0] > 0 ) {
  686. parms->isMirror = false;
  687. } else {
  688. parms->isMirror = true;
  689. }
  690. // save this world for use by some console commands
  691. tr.primaryWorld = this;
  692. tr.primaryRenderView = *renderView;
  693. tr.primaryView = parms;
  694. // rendering this view may cause other views to be rendered
  695. // for mirrors / portals / shadows / environment maps
  696. // this will also cause any necessary entities and lights to be
  697. // updated to the demo file
  698. R_RenderView( parms );
  699. // render any post processing after the view and all its subviews has been draw
  700. R_RenderPostProcess( parms );
  701. // now write delete commands for any modified-but-not-visible entities, and
  702. // add the renderView command to the demo
  703. if ( common->WriteDemo() ) {
  704. WriteRenderView( renderView );
  705. }
  706. #if 0
  707. for ( int i = 0; i < entityDefs.Num(); i++ ) {
  708. idRenderEntityLocal *def = entityDefs[i];
  709. if ( !def ) {
  710. continue;
  711. }
  712. if ( def->parms.callback ) {
  713. continue;
  714. }
  715. if ( def->parms.hModel->IsDynamicModel() == DM_CONTINUOUS ) {
  716. }
  717. }
  718. #endif
  719. tr.UnCrop();
  720. int endTime = Sys_Microseconds();
  721. tr.pc.frontEndMicroSec += endTime - startTime;
  722. // prepare for any 2D drawing after this
  723. tr.guiModel->Clear();
  724. }
  725. /*
  726. ===================
  727. idRenderWorldLocal::NumAreas
  728. ===================
  729. */
  730. int idRenderWorldLocal::NumAreas() const {
  731. return numPortalAreas;
  732. }
  733. /*
  734. ===================
  735. idRenderWorldLocal::NumPortalsInArea
  736. ===================
  737. */
  738. int idRenderWorldLocal::NumPortalsInArea( int areaNum ) {
  739. portalArea_t *area;
  740. int count;
  741. portal_t *portal;
  742. if ( areaNum >= numPortalAreas || areaNum < 0 ) {
  743. common->Error( "idRenderWorld::NumPortalsInArea: bad areanum %i", areaNum );
  744. }
  745. area = &portalAreas[areaNum];
  746. count = 0;
  747. for ( portal = area->portals; portal; portal = portal->next ) {
  748. count++;
  749. }
  750. return count;
  751. }
  752. /*
  753. ===================
  754. idRenderWorldLocal::GetPortal
  755. ===================
  756. */
  757. exitPortal_t idRenderWorldLocal::GetPortal( int areaNum, int portalNum ) {
  758. portalArea_t *area;
  759. int count;
  760. portal_t *portal;
  761. exitPortal_t ret;
  762. if ( areaNum > numPortalAreas ) {
  763. common->Error( "idRenderWorld::GetPortal: areaNum > numAreas" );
  764. }
  765. area = &portalAreas[areaNum];
  766. count = 0;
  767. for ( portal = area->portals; portal; portal = portal->next ) {
  768. if ( count == portalNum ) {
  769. ret.areas[0] = areaNum;
  770. ret.areas[1] = portal->intoArea;
  771. ret.w = portal->w;
  772. ret.blockingBits = portal->doublePortal->blockingBits;
  773. ret.portalHandle = portal->doublePortal - doublePortals + 1;
  774. return ret;
  775. }
  776. count++;
  777. }
  778. common->Error( "idRenderWorld::GetPortal: portalNum > numPortals" );
  779. memset( &ret, 0, sizeof( ret ) );
  780. return ret;
  781. }
  782. /*
  783. ===============
  784. idRenderWorldLocal::PointInAreaNum
  785. Will return -1 if the point is not in an area, otherwise
  786. it will return 0 <= value < tr.world->numPortalAreas
  787. ===============
  788. */
  789. int idRenderWorldLocal::PointInArea( const idVec3 &point ) const {
  790. areaNode_t *node;
  791. int nodeNum;
  792. float d;
  793. node = areaNodes;
  794. if ( !node ) {
  795. return -1;
  796. }
  797. while( 1 ) {
  798. d = point * node->plane.Normal() + node->plane[3];
  799. if (d > 0) {
  800. nodeNum = node->children[0];
  801. } else {
  802. nodeNum = node->children[1];
  803. }
  804. if ( nodeNum == 0 ) {
  805. return -1; // in solid
  806. }
  807. if ( nodeNum < 0 ) {
  808. nodeNum = -1 - nodeNum;
  809. if ( nodeNum >= numPortalAreas ) {
  810. common->Error( "idRenderWorld::PointInArea: area out of range" );
  811. }
  812. return nodeNum;
  813. }
  814. node = areaNodes + nodeNum;
  815. }
  816. return -1;
  817. }
  818. /*
  819. ===================
  820. idRenderWorldLocal::BoundsInAreas_r
  821. ===================
  822. */
  823. void idRenderWorldLocal::BoundsInAreas_r( int nodeNum, const idBounds &bounds, int *areas, int *numAreas, int maxAreas ) const {
  824. int side, i;
  825. areaNode_t *node;
  826. do {
  827. if ( nodeNum < 0 ) {
  828. nodeNum = -1 - nodeNum;
  829. for ( i = 0; i < (*numAreas); i++ ) {
  830. if ( areas[i] == nodeNum ) {
  831. break;
  832. }
  833. }
  834. if ( i >= (*numAreas) && (*numAreas) < maxAreas ) {
  835. areas[(*numAreas)++] = nodeNum;
  836. }
  837. return;
  838. }
  839. node = areaNodes + nodeNum;
  840. side = bounds.PlaneSide( node->plane );
  841. if ( side == PLANESIDE_FRONT ) {
  842. nodeNum = node->children[0];
  843. }
  844. else if ( side == PLANESIDE_BACK ) {
  845. nodeNum = node->children[1];
  846. }
  847. else {
  848. if ( node->children[1] != 0 ) {
  849. BoundsInAreas_r( node->children[1], bounds, areas, numAreas, maxAreas );
  850. if ( (*numAreas) >= maxAreas ) {
  851. return;
  852. }
  853. }
  854. nodeNum = node->children[0];
  855. }
  856. } while( nodeNum != 0 );
  857. return;
  858. }
  859. /*
  860. ===================
  861. idRenderWorldLocal::BoundsInAreas
  862. fills the *areas array with the number of the areas the bounds are in
  863. returns the total number of areas the bounds are in
  864. ===================
  865. */
  866. int idRenderWorldLocal::BoundsInAreas( const idBounds &bounds, int *areas, int maxAreas ) const {
  867. int numAreas = 0;
  868. assert( areas );
  869. assert( bounds[0][0] <= bounds[1][0] && bounds[0][1] <= bounds[1][1] && bounds[0][2] <= bounds[1][2] );
  870. assert( bounds[1][0] - bounds[0][0] < 1e4f && bounds[1][1] - bounds[0][1] < 1e4f && bounds[1][2] - bounds[0][2] < 1e4f );
  871. if ( !areaNodes ) {
  872. return numAreas;
  873. }
  874. BoundsInAreas_r( 0, bounds, areas, &numAreas, maxAreas );
  875. return numAreas;
  876. }
  877. /*
  878. ================
  879. idRenderWorldLocal::GuiTrace
  880. checks a ray trace against any gui surfaces in an entity, returning the
  881. fraction location of the trace on the gui surface, or -1,-1 if no hit.
  882. this doesn't do any occlusion testing, simply ignoring non-gui surfaces.
  883. start / end are in global world coordinates.
  884. ================
  885. */
  886. guiPoint_t idRenderWorldLocal::GuiTrace( qhandle_t entityHandle, const idVec3 start, const idVec3 end ) const {
  887. guiPoint_t pt;
  888. pt.x = pt.y = -1;
  889. pt.guiId = 0;
  890. if ( ( entityHandle < 0 ) || ( entityHandle >= entityDefs.Num() ) ) {
  891. common->Printf( "idRenderWorld::GuiTrace: invalid handle %i\n", entityHandle );
  892. return pt;
  893. }
  894. idRenderEntityLocal * def = entityDefs[entityHandle];
  895. if ( def == NULL ) {
  896. common->Printf( "idRenderWorld::GuiTrace: handle %i is NULL\n", entityHandle );
  897. return pt;
  898. }
  899. idRenderModel * model = def->parms.hModel;
  900. if ( model == NULL || model->IsDynamicModel() != DM_STATIC || def->parms.callback != NULL ) {
  901. return pt;
  902. }
  903. // transform the points into local space
  904. idVec3 localStart, localEnd;
  905. R_GlobalPointToLocal( def->modelMatrix, start, localStart );
  906. R_GlobalPointToLocal( def->modelMatrix, end, localEnd );
  907. for ( int i = 0; i < model->NumSurfaces(); i++ ) {
  908. const modelSurface_t *surf = model->Surface( i );
  909. const srfTriangles_t * tri = surf->geometry;
  910. if ( tri == NULL ) {
  911. continue;
  912. }
  913. const idMaterial * shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
  914. if ( shader == NULL ) {
  915. continue;
  916. }
  917. // only trace against gui surfaces
  918. if ( !shader->HasGui() ) {
  919. continue;
  920. }
  921. localTrace_t local = R_LocalTrace( localStart, localEnd, 0.0f, tri );
  922. if ( local.fraction < 1.0f ) {
  923. idVec3 origin, axis[3];
  924. R_SurfaceToTextureAxis( tri, origin, axis );
  925. const idVec3 cursor = local.point - origin;
  926. float axisLen[2];
  927. axisLen[0] = axis[0].Length();
  928. axisLen[1] = axis[1].Length();
  929. pt.x = ( cursor * axis[0] ) / ( axisLen[0] * axisLen[0] );
  930. pt.y = ( cursor * axis[1] ) / ( axisLen[1] * axisLen[1] );
  931. pt.guiId = shader->GetEntityGui();
  932. return pt;
  933. }
  934. }
  935. return pt;
  936. }
  937. /*
  938. ===================
  939. idRenderWorldLocal::ModelTrace
  940. ===================
  941. */
  942. bool idRenderWorldLocal::ModelTrace( modelTrace_t &trace, qhandle_t entityHandle, const idVec3 &start, const idVec3 &end, const float radius ) const {
  943. memset( &trace, 0, sizeof( trace ) );
  944. trace.fraction = 1.0f;
  945. trace.point = end;
  946. if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
  947. return false;
  948. }
  949. idRenderEntityLocal *def = entityDefs[entityHandle];
  950. if ( def == NULL ) {
  951. return false;
  952. }
  953. renderEntity_t *refEnt = &def->parms;
  954. idRenderModel *model = R_EntityDefDynamicModel( def );
  955. if ( model == NULL ) {
  956. return false;
  957. }
  958. // transform the points into local space
  959. float modelMatrix[16];
  960. idVec3 localStart;
  961. idVec3 localEnd;
  962. R_AxisToModelMatrix( refEnt->axis, refEnt->origin, modelMatrix );
  963. R_GlobalPointToLocal( modelMatrix, start, localStart );
  964. R_GlobalPointToLocal( modelMatrix, end, localEnd );
  965. // if we have explicit collision surfaces, only collide against them
  966. // (FIXME, should probably have a parm to control this)
  967. bool collisionSurface = false;
  968. for ( int i = 0; i < model->NumBaseSurfaces(); i++ ) {
  969. const modelSurface_t *surf = model->Surface( i );
  970. const idMaterial *shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
  971. if ( shader->GetSurfaceFlags() & SURF_COLLISION ) {
  972. collisionSurface = true;
  973. break;
  974. }
  975. }
  976. // only use baseSurfaces, not any overlays
  977. for ( int i = 0; i < model->NumBaseSurfaces(); i++ ) {
  978. const modelSurface_t *surf = model->Surface( i );
  979. const idMaterial *shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
  980. if ( surf->geometry == NULL || shader == NULL ) {
  981. continue;
  982. }
  983. if ( collisionSurface ) {
  984. // only trace vs collision surfaces
  985. if ( ( shader->GetSurfaceFlags() & SURF_COLLISION ) == 0 ) {
  986. continue;
  987. }
  988. } else {
  989. // skip if not drawn or translucent
  990. if ( !shader->IsDrawn() || ( shader->Coverage() != MC_OPAQUE && shader->Coverage() != MC_PERFORATED ) ) {
  991. continue;
  992. }
  993. }
  994. localTrace_t localTrace = R_LocalTrace( localStart, localEnd, radius, surf->geometry );
  995. if ( localTrace.fraction < trace.fraction ) {
  996. trace.fraction = localTrace.fraction;
  997. R_LocalPointToGlobal( modelMatrix, localTrace.point, trace.point );
  998. trace.normal = localTrace.normal * refEnt->axis;
  999. trace.material = shader;
  1000. trace.entity = &def->parms;
  1001. trace.jointNumber = refEnt->hModel->NearestJoint( i, localTrace.indexes[0], localTrace.indexes[1], localTrace.indexes[2] );
  1002. }
  1003. }
  1004. return ( trace.fraction < 1.0f );
  1005. }
  1006. /*
  1007. ===================
  1008. idRenderWorldLocal::Trace
  1009. ===================
  1010. */
  1011. // FIXME: _D3XP added those.
  1012. const char * playerModelExcludeList[] = {
  1013. "models/md5/characters/player/d3xp_spplayer.md5mesh",
  1014. "models/md5/characters/player/head/d3xp_head.md5mesh",
  1015. "models/md5/weapons/pistol_world/worldpistol.md5mesh",
  1016. NULL
  1017. };
  1018. const char * playerMaterialExcludeList[] = {
  1019. "muzzlesmokepuff",
  1020. NULL
  1021. };
  1022. bool idRenderWorldLocal::Trace( modelTrace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, bool skipDynamic, bool skipPlayer /*_D3XP*/ ) const {
  1023. trace.fraction = 1.0f;
  1024. trace.point = end;
  1025. // bounds for the whole trace
  1026. idBounds traceBounds;
  1027. traceBounds.Clear();
  1028. traceBounds.AddPoint( start );
  1029. traceBounds.AddPoint( end );
  1030. // get the world areas the trace is in
  1031. int areas[128];
  1032. int numAreas = BoundsInAreas( traceBounds, areas, 128 );
  1033. int numSurfaces = 0;
  1034. // check all areas for models
  1035. for ( int i = 0; i < numAreas; i++ ) {
  1036. portalArea_t * area = &portalAreas[ areas[i] ];
  1037. // check all models in this area
  1038. for ( areaReference_t * ref = area->entityRefs.areaNext; ref != &area->entityRefs; ref = ref->areaNext ) {
  1039. idRenderEntityLocal * def = ref->entity;
  1040. idRenderModel * model = def->parms.hModel;
  1041. if ( model == NULL ) {
  1042. continue;
  1043. }
  1044. if ( model->IsDynamicModel() != DM_STATIC ) {
  1045. if ( skipDynamic ) {
  1046. continue;
  1047. }
  1048. #if 1 /* _D3XP addition. could use a cleaner approach */
  1049. if ( skipPlayer ) {
  1050. bool exclude = false;
  1051. for ( int k = 0; playerModelExcludeList[k] != NULL; k++ ) {
  1052. if ( idStr::Cmp( model->Name(), playerModelExcludeList[k] ) == 0 ) {
  1053. exclude = true;
  1054. break;
  1055. }
  1056. }
  1057. if ( exclude ) {
  1058. continue;
  1059. }
  1060. }
  1061. #endif
  1062. model = R_EntityDefDynamicModel( def );
  1063. if ( !model ) {
  1064. continue; // can happen with particle systems, which don't instantiate without a valid view
  1065. }
  1066. }
  1067. idBounds bounds;
  1068. bounds.FromTransformedBounds( model->Bounds( &def->parms ), def->parms.origin, def->parms.axis );
  1069. // if the model bounds do not overlap with the trace bounds
  1070. if ( !traceBounds.IntersectsBounds( bounds ) || !bounds.LineIntersection( start, trace.point ) ) {
  1071. continue;
  1072. }
  1073. // check all model surfaces
  1074. for ( int j = 0; j < model->NumSurfaces(); j++ ) {
  1075. const modelSurface_t *surf = model->Surface( j );
  1076. const idMaterial * shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
  1077. // if no geometry or no shader
  1078. if ( surf->geometry == NULL || shader == NULL ) {
  1079. continue;
  1080. }
  1081. #if 1 /* _D3XP addition. could use a cleaner approach */
  1082. if ( skipPlayer ) {
  1083. bool exclude = false;
  1084. for ( int k = 0; playerMaterialExcludeList[k] != NULL; k++ ) {
  1085. if ( idStr::Cmp( shader->GetName(), playerMaterialExcludeList[k] ) == 0 ) {
  1086. exclude = true;
  1087. break;
  1088. }
  1089. }
  1090. if ( exclude ) {
  1091. continue;
  1092. }
  1093. }
  1094. #endif
  1095. const srfTriangles_t * tri = surf->geometry;
  1096. bounds.FromTransformedBounds( tri->bounds, def->parms.origin, def->parms.axis );
  1097. // if triangle bounds do not overlap with the trace bounds
  1098. if ( !traceBounds.IntersectsBounds( bounds ) || !bounds.LineIntersection( start, trace.point ) ) {
  1099. continue;
  1100. }
  1101. numSurfaces++;
  1102. // transform the points into local space
  1103. float modelMatrix[16];
  1104. idVec3 localStart, localEnd;
  1105. R_AxisToModelMatrix( def->parms.axis, def->parms.origin, modelMatrix );
  1106. R_GlobalPointToLocal( modelMatrix, start, localStart );
  1107. R_GlobalPointToLocal( modelMatrix, end, localEnd );
  1108. localTrace_t localTrace = R_LocalTrace( localStart, localEnd, radius, surf->geometry );
  1109. if ( localTrace.fraction < trace.fraction ) {
  1110. trace.fraction = localTrace.fraction;
  1111. R_LocalPointToGlobal( modelMatrix, localTrace.point, trace.point );
  1112. trace.normal = localTrace.normal * def->parms.axis;
  1113. trace.material = shader;
  1114. trace.entity = &def->parms;
  1115. trace.jointNumber = model->NearestJoint( j, localTrace.indexes[0], localTrace.indexes[1], localTrace.indexes[2] );
  1116. traceBounds.Clear();
  1117. traceBounds.AddPoint( start );
  1118. traceBounds.AddPoint( start + trace.fraction * (end - start) );
  1119. }
  1120. }
  1121. }
  1122. }
  1123. return ( trace.fraction < 1.0f );
  1124. }
  1125. /*
  1126. ==================
  1127. idRenderWorldLocal::RecurseProcBSP
  1128. ==================
  1129. */
  1130. void idRenderWorldLocal::RecurseProcBSP_r( modelTrace_t *results, int parentNodeNum, int nodeNum, float p1f, float p2f, const idVec3 &p1, const idVec3 &p2 ) const {
  1131. float t1, t2;
  1132. float frac;
  1133. idVec3 mid;
  1134. int side;
  1135. float midf;
  1136. areaNode_t *node;
  1137. if ( results->fraction <= p1f) {
  1138. return; // already hit something nearer
  1139. }
  1140. // empty leaf
  1141. if ( nodeNum < 0 ) {
  1142. return;
  1143. }
  1144. // if solid leaf node
  1145. if ( nodeNum == 0 ) {
  1146. if ( parentNodeNum != -1 ) {
  1147. results->fraction = p1f;
  1148. results->point = p1;
  1149. node = &areaNodes[parentNodeNum];
  1150. results->normal = node->plane.Normal();
  1151. return;
  1152. }
  1153. }
  1154. node = &areaNodes[nodeNum];
  1155. // distance from plane for trace start and end
  1156. t1 = node->plane.Normal() * p1 + node->plane[3];
  1157. t2 = node->plane.Normal() * p2 + node->plane[3];
  1158. if ( t1 >= 0.0f && t2 >= 0.0f ) {
  1159. RecurseProcBSP_r( results, nodeNum, node->children[0], p1f, p2f, p1, p2 );
  1160. return;
  1161. }
  1162. if ( t1 < 0.0f && t2 < 0.0f ) {
  1163. RecurseProcBSP_r( results, nodeNum, node->children[1], p1f, p2f, p1, p2 );
  1164. return;
  1165. }
  1166. side = t1 < t2;
  1167. frac = t1 / (t1 - t2);
  1168. midf = p1f + frac*(p2f - p1f);
  1169. mid[0] = p1[0] + frac*(p2[0] - p1[0]);
  1170. mid[1] = p1[1] + frac*(p2[1] - p1[1]);
  1171. mid[2] = p1[2] + frac*(p2[2] - p1[2]);
  1172. RecurseProcBSP_r( results, nodeNum, node->children[side], p1f, midf, p1, mid );
  1173. RecurseProcBSP_r( results, nodeNum, node->children[side^1], midf, p2f, mid, p2 );
  1174. }
  1175. /*
  1176. ==================
  1177. idRenderWorldLocal::FastWorldTrace
  1178. ==================
  1179. */
  1180. bool idRenderWorldLocal::FastWorldTrace( modelTrace_t &results, const idVec3 &start, const idVec3 &end ) const {
  1181. memset( &results, 0, sizeof( modelTrace_t ) );
  1182. results.fraction = 1.0f;
  1183. if ( areaNodes != NULL ) {
  1184. RecurseProcBSP_r( &results, -1, 0, 0.0f, 1.0f, start, end );
  1185. return ( results.fraction < 1.0f );
  1186. }
  1187. return false;
  1188. }
  1189. /*
  1190. =================================================================================
  1191. CREATE MODEL REFS
  1192. =================================================================================
  1193. */
  1194. /*
  1195. =================
  1196. idRenderWorldLocal::AddEntityRefToArea
  1197. This is called by R_PushVolumeIntoTree and also directly
  1198. for the world model references that are precalculated.
  1199. =================
  1200. */
  1201. void idRenderWorldLocal::AddEntityRefToArea( idRenderEntityLocal *def, portalArea_t *area ) {
  1202. areaReference_t *ref;
  1203. if ( def == NULL ) {
  1204. common->Error( "idRenderWorldLocal::AddEntityRefToArea: NULL def" );
  1205. return;
  1206. }
  1207. for ( ref = def->entityRefs; ref != NULL; ref = ref->ownerNext ) {
  1208. if ( ref->area == area ) {
  1209. return;
  1210. }
  1211. }
  1212. ref = areaReferenceAllocator.Alloc();
  1213. tr.pc.c_entityReferences++;
  1214. ref->entity = def;
  1215. // link to entityDef
  1216. ref->ownerNext = def->entityRefs;
  1217. def->entityRefs = ref;
  1218. // link to end of area list
  1219. ref->area = area;
  1220. ref->areaNext = &area->entityRefs;
  1221. ref->areaPrev = area->entityRefs.areaPrev;
  1222. ref->areaNext->areaPrev = ref;
  1223. ref->areaPrev->areaNext = ref;
  1224. }
  1225. /*
  1226. ===================
  1227. idRenderWorldLocal::AddLightRefToArea
  1228. ===================
  1229. */
  1230. void idRenderWorldLocal::AddLightRefToArea( idRenderLightLocal *light, portalArea_t *area ) {
  1231. areaReference_t *lref;
  1232. for ( lref = light->references; lref != NULL; lref = lref->ownerNext ) {
  1233. if ( lref->area == area ) {
  1234. return;
  1235. }
  1236. }
  1237. // add a lightref to this area
  1238. lref = areaReferenceAllocator.Alloc();
  1239. lref->light = light;
  1240. lref->area = area;
  1241. lref->ownerNext = light->references;
  1242. light->references = lref;
  1243. tr.pc.c_lightReferences++;
  1244. // doubly linked list so we can free them easily later
  1245. area->lightRefs.areaNext->areaPrev = lref;
  1246. lref->areaNext = area->lightRefs.areaNext;
  1247. lref->areaPrev = &area->lightRefs;
  1248. area->lightRefs.areaNext = lref;
  1249. }
  1250. /*
  1251. ===================
  1252. idRenderWorldLocal::GenerateAllInteractions
  1253. Force the generation of all light / surface interactions at the start of a level
  1254. If this isn't called, they will all be dynamically generated
  1255. ===================
  1256. */
  1257. void idRenderWorldLocal::GenerateAllInteractions() {
  1258. if ( !R_IsInitialized() ) {
  1259. return;
  1260. }
  1261. int start = Sys_Milliseconds();
  1262. generateAllInteractionsCalled = false;
  1263. // let the interaction creation code know that it shouldn't
  1264. // try and do any view specific optimizations
  1265. tr.viewDef = NULL;
  1266. // build the interaction table
  1267. // this will be dynamically resized if the entity / light counts grow too much
  1268. interactionTableWidth = entityDefs.Num() + 100;
  1269. interactionTableHeight = lightDefs.Num() + 100;
  1270. int size = interactionTableWidth * interactionTableHeight * sizeof( *interactionTable );
  1271. interactionTable = (idInteraction **)R_ClearedStaticAlloc( size );
  1272. // itterate through all lights
  1273. int count = 0;
  1274. for ( int i = 0; i < this->lightDefs.Num(); i++ ) {
  1275. idRenderLightLocal *ldef = this->lightDefs[i];
  1276. if ( ldef == NULL ) {
  1277. continue;
  1278. }
  1279. // check all areas the light touches
  1280. for ( areaReference_t *lref = ldef->references; lref; lref = lref->ownerNext ) {
  1281. portalArea_t *area = lref->area;
  1282. // check all the models in this area
  1283. for ( areaReference_t *eref = area->entityRefs.areaNext; eref != &area->entityRefs; eref = eref->areaNext ) {
  1284. idRenderEntityLocal *edef = eref->entity;
  1285. // scan the doubly linked lists, which may have several dozen entries
  1286. idInteraction *inter;
  1287. // we could check either model refs or light refs for matches, but it is
  1288. // assumed that there will be less lights in an area than models
  1289. // so the entity chains should be somewhat shorter (they tend to be fairly close).
  1290. for ( inter = edef->firstInteraction; inter != NULL; inter = inter->entityNext ) {
  1291. if ( inter->lightDef == ldef ) {
  1292. break;
  1293. }
  1294. }
  1295. // if we already have an interaction, we don't need to do anything
  1296. if ( inter != NULL ) {
  1297. continue;
  1298. }
  1299. // make an interaction for this light / entity pair
  1300. // and add a pointer to it in the table
  1301. inter = idInteraction::AllocAndLink( edef, ldef );
  1302. count++;
  1303. // the interaction may create geometry
  1304. inter->CreateStaticInteraction();
  1305. }
  1306. }
  1307. session->Pump();
  1308. }
  1309. int end = Sys_Milliseconds();
  1310. int msec = end - start;
  1311. common->Printf( "idRenderWorld::GenerateAllInteractions, msec = %i\n", msec );
  1312. common->Printf( "interactionTable size: %i bytes\n", size );
  1313. common->Printf( "%i interactions take %i bytes\n", count, count * sizeof( idInteraction ) );
  1314. // entities flagged as noDynamicInteractions will no longer make any
  1315. generateAllInteractionsCalled = true;
  1316. }
  1317. /*
  1318. ===================
  1319. idRenderWorldLocal::FreeInteractions
  1320. ===================
  1321. */
  1322. void idRenderWorldLocal::FreeInteractions() {
  1323. int i;
  1324. idRenderEntityLocal *def;
  1325. for ( i = 0; i < entityDefs.Num(); i++ ) {
  1326. def = entityDefs[i];
  1327. if ( !def ) {
  1328. continue;
  1329. }
  1330. // free all the interactions
  1331. while ( def->firstInteraction != NULL ) {
  1332. def->firstInteraction->UnlinkAndFree();
  1333. }
  1334. }
  1335. }
  1336. /*
  1337. ==================
  1338. idRenderWorldLocal::PushFrustumIntoTree_r
  1339. Used for both light volumes and model volumes.
  1340. This does not clip the points by the planes, so some slop
  1341. occurs.
  1342. tr.viewCount should be bumped before calling, allowing it
  1343. to prevent double checking areas.
  1344. We might alternatively choose to do this with an area flow.
  1345. ==================
  1346. */
  1347. void idRenderWorldLocal::PushFrustumIntoTree_r( idRenderEntityLocal *def, idRenderLightLocal *light,
  1348. const frustumCorners_t & corners, int nodeNum ) {
  1349. if ( nodeNum < 0 ) {
  1350. int areaNum = -1 - nodeNum;
  1351. portalArea_t * area = &portalAreas[ areaNum ];
  1352. if ( area->viewCount == tr.viewCount ) {
  1353. return; // already added a reference here
  1354. }
  1355. area->viewCount = tr.viewCount;
  1356. if ( def != NULL ) {
  1357. AddEntityRefToArea( def, area );
  1358. }
  1359. if ( light != NULL ) {
  1360. AddLightRefToArea( light, area );
  1361. }
  1362. return;
  1363. }
  1364. areaNode_t * node = areaNodes + nodeNum;
  1365. // if we know that all possible children nodes only touch an area
  1366. // we have already marked, we can early out
  1367. if ( node->commonChildrenArea != CHILDREN_HAVE_MULTIPLE_AREAS && r_useNodeCommonChildren.GetBool() ) {
  1368. // note that we do NOT try to set a reference in this area
  1369. // yet, because the test volume may yet wind up being in the
  1370. // solid part, which would cause bounds slightly poked into
  1371. // a wall to show up in the next room
  1372. if ( portalAreas[ node->commonChildrenArea ].viewCount == tr.viewCount ) {
  1373. return;
  1374. }
  1375. }
  1376. // exact check all the corners against the node plane
  1377. frustumCull_t cull = idRenderMatrix::CullFrustumCornersToPlane( corners, node->plane );
  1378. if ( cull != FRUSTUM_CULL_BACK ) {
  1379. nodeNum = node->children[0];
  1380. if ( nodeNum != 0 ) { // 0 = solid
  1381. PushFrustumIntoTree_r( def, light, corners, nodeNum );
  1382. }
  1383. }
  1384. if ( cull != FRUSTUM_CULL_FRONT ) {
  1385. nodeNum = node->children[1];
  1386. if ( nodeNum != 0 ) { // 0 = solid
  1387. PushFrustumIntoTree_r( def, light, corners, nodeNum );
  1388. }
  1389. }
  1390. }
  1391. /*
  1392. ==============
  1393. idRenderWorldLocal::PushFrustumIntoTree
  1394. ==============
  1395. */
  1396. void idRenderWorldLocal::PushFrustumIntoTree( idRenderEntityLocal *def, idRenderLightLocal *light, const idRenderMatrix & frustumTransform, const idBounds & frustumBounds ) {
  1397. if ( areaNodes == NULL ) {
  1398. return;
  1399. }
  1400. // calculate the corners of the frustum in word space
  1401. ALIGNTYPE16 frustumCorners_t corners;
  1402. idRenderMatrix::GetFrustumCorners( corners, frustumTransform, frustumBounds );
  1403. PushFrustumIntoTree_r( def, light, corners, 0 );
  1404. }
  1405. //===================================================================
  1406. /*
  1407. ====================
  1408. idRenderWorldLocal::DebugClearLines
  1409. ====================
  1410. */
  1411. void idRenderWorldLocal::DebugClearLines( int time ) {
  1412. RB_ClearDebugLines( time );
  1413. RB_ClearDebugText( time );
  1414. }
  1415. /*
  1416. ====================
  1417. idRenderWorldLocal::DebugLine
  1418. ====================
  1419. */
  1420. void idRenderWorldLocal::DebugLine( const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifetime, const bool depthTest ) {
  1421. RB_AddDebugLine( color, start, end, lifetime, depthTest );
  1422. }
  1423. /*
  1424. ================
  1425. idRenderWorldLocal::DebugArrow
  1426. ================
  1427. */
  1428. void idRenderWorldLocal::DebugArrow( const idVec4 &color, const idVec3 &start, const idVec3 &end, int size, const int lifetime ) {
  1429. idVec3 forward, right, up, v1, v2;
  1430. float a, s;
  1431. int i;
  1432. static float arrowCos[40];
  1433. static float arrowSin[40];
  1434. static int arrowStep;
  1435. DebugLine( color, start, end, lifetime );
  1436. if ( r_debugArrowStep.GetInteger() <= 10 ) {
  1437. return;
  1438. }
  1439. // calculate sine and cosine when step size changes
  1440. if ( arrowStep != r_debugArrowStep.GetInteger() ) {
  1441. arrowStep = r_debugArrowStep.GetInteger();
  1442. for ( i = 0, a = 0; a < 360.0f; a += arrowStep, i++ ) {
  1443. arrowCos[i] = idMath::Cos16( DEG2RAD( a ) );
  1444. arrowSin[i] = idMath::Sin16( DEG2RAD( a ) );
  1445. }
  1446. arrowCos[i] = arrowCos[0];
  1447. arrowSin[i] = arrowSin[0];
  1448. }
  1449. // draw a nice arrow
  1450. forward = end - start;
  1451. forward.Normalize();
  1452. forward.NormalVectors( right, up);
  1453. for ( i = 0, a = 0; a < 360.0f; a += arrowStep, i++ ) {
  1454. s = 0.5f * size * arrowCos[i];
  1455. v1 = end - size * forward;
  1456. v1 = v1 + s * right;
  1457. s = 0.5f * size * arrowSin[i];
  1458. v1 = v1 + s * up;
  1459. s = 0.5f * size * arrowCos[i+1];
  1460. v2 = end - size * forward;
  1461. v2 = v2 + s * right;
  1462. s = 0.5f * size * arrowSin[i+1];
  1463. v2 = v2 + s * up;
  1464. DebugLine( color, v1, end, lifetime );
  1465. DebugLine( color, v1, v2, lifetime );
  1466. }
  1467. }
  1468. /*
  1469. ====================
  1470. idRenderWorldLocal::DebugWinding
  1471. ====================
  1472. */
  1473. void idRenderWorldLocal::DebugWinding( const idVec4 &color, const idWinding &w, const idVec3 &origin, const idMat3 &axis, const int lifetime, const bool depthTest ) {
  1474. int i;
  1475. idVec3 point, lastPoint;
  1476. if ( w.GetNumPoints() < 2 ) {
  1477. return;
  1478. }
  1479. lastPoint = origin + w[w.GetNumPoints()-1].ToVec3() * axis;
  1480. for ( i = 0; i < w.GetNumPoints(); i++ ) {
  1481. point = origin + w[i].ToVec3() * axis;
  1482. DebugLine( color, lastPoint, point, lifetime, depthTest );
  1483. lastPoint = point;
  1484. }
  1485. }
  1486. /*
  1487. ====================
  1488. idRenderWorldLocal::DebugCircle
  1489. ====================
  1490. */
  1491. void idRenderWorldLocal::DebugCircle( const idVec4 &color, const idVec3 &origin, const idVec3 &dir, const float radius, const int numSteps, const int lifetime, const bool depthTest ) {
  1492. int i;
  1493. float a;
  1494. idVec3 left, up, point, lastPoint;
  1495. dir.OrthogonalBasis( left, up );
  1496. left *= radius;
  1497. up *= radius;
  1498. lastPoint = origin + up;
  1499. for ( i = 1; i <= numSteps; i++ ) {
  1500. a = idMath::TWO_PI * i / numSteps;
  1501. point = origin + idMath::Sin16( a ) * left + idMath::Cos16( a ) * up;
  1502. DebugLine( color, lastPoint, point, lifetime, depthTest );
  1503. lastPoint = point;
  1504. }
  1505. }
  1506. /*
  1507. ============
  1508. idRenderWorldLocal::DebugSphere
  1509. ============
  1510. */
  1511. void idRenderWorldLocal::DebugSphere( const idVec4 &color, const idSphere &sphere, const int lifetime, const bool depthTest /*_D3XP*/ ) {
  1512. int i, j, n, num;
  1513. float s, c;
  1514. idVec3 p, lastp, *lastArray;
  1515. num = 360 / 15;
  1516. lastArray = (idVec3 *) _alloca16( num * sizeof( idVec3 ) );
  1517. lastArray[0] = sphere.GetOrigin() + idVec3( 0, 0, sphere.GetRadius() );
  1518. for ( n = 1; n < num; n++ ) {
  1519. lastArray[n] = lastArray[0];
  1520. }
  1521. for ( i = 15; i <= 360; i += 15 ) {
  1522. s = idMath::Sin16( DEG2RAD(i) );
  1523. c = idMath::Cos16( DEG2RAD(i) );
  1524. lastp[0] = sphere.GetOrigin()[0];
  1525. lastp[1] = sphere.GetOrigin()[1] + sphere.GetRadius() * s;
  1526. lastp[2] = sphere.GetOrigin()[2] + sphere.GetRadius() * c;
  1527. for ( n = 0, j = 15; j <= 360; j += 15, n++ ) {
  1528. p[0] = sphere.GetOrigin()[0] + idMath::Sin16( DEG2RAD(j) ) * sphere.GetRadius() * s;
  1529. p[1] = sphere.GetOrigin()[1] + idMath::Cos16( DEG2RAD(j) ) * sphere.GetRadius() * s;
  1530. p[2] = lastp[2];
  1531. DebugLine( color, lastp, p, lifetime,depthTest );
  1532. DebugLine( color, lastp, lastArray[n], lifetime, depthTest );
  1533. lastArray[n] = lastp;
  1534. lastp = p;
  1535. }
  1536. }
  1537. }
  1538. /*
  1539. ====================
  1540. idRenderWorldLocal::DebugBounds
  1541. ====================
  1542. */
  1543. void idRenderWorldLocal::DebugBounds( const idVec4 &color, const idBounds &bounds, const idVec3 &org, const int lifetime ) {
  1544. int i;
  1545. idVec3 v[8];
  1546. if ( bounds.IsCleared() ) {
  1547. return;
  1548. }
  1549. for ( i = 0; i < 8; i++ ) {
  1550. v[i][0] = org[0] + bounds[(i^(i>>1))&1][0];
  1551. v[i][1] = org[1] + bounds[(i>>1)&1][1];
  1552. v[i][2] = org[2] + bounds[(i>>2)&1][2];
  1553. }
  1554. for ( i = 0; i < 4; i++ ) {
  1555. DebugLine( color, v[i], v[(i+1)&3], lifetime );
  1556. DebugLine( color, v[4+i], v[4+((i+1)&3)], lifetime );
  1557. DebugLine( color, v[i], v[4+i], lifetime );
  1558. }
  1559. }
  1560. /*
  1561. ====================
  1562. idRenderWorldLocal::DebugBox
  1563. ====================
  1564. */
  1565. void idRenderWorldLocal::DebugBox( const idVec4 &color, const idBox &box, const int lifetime ) {
  1566. int i;
  1567. idVec3 v[8];
  1568. box.ToPoints( v );
  1569. for ( i = 0; i < 4; i++ ) {
  1570. DebugLine( color, v[i], v[(i+1)&3], lifetime );
  1571. DebugLine( color, v[4+i], v[4+((i+1)&3)], lifetime );
  1572. DebugLine( color, v[i], v[4+i], lifetime );
  1573. }
  1574. }
  1575. /*
  1576. ============
  1577. idRenderWorldLocal::DebugCone
  1578. dir is the cone axis
  1579. radius1 is the radius at the apex
  1580. radius2 is the radius at apex+dir
  1581. ============
  1582. */
  1583. void idRenderWorldLocal::DebugCone( const idVec4 &color, const idVec3 &apex, const idVec3 &dir, float radius1, float radius2, const int lifetime ) {
  1584. int i;
  1585. idMat3 axis;
  1586. idVec3 top, p1, p2, lastp1, lastp2, d;
  1587. axis[2] = dir;
  1588. axis[2].Normalize();
  1589. axis[2].NormalVectors( axis[0], axis[1] );
  1590. axis[1] = -axis[1];
  1591. top = apex + dir;
  1592. lastp2 = top + radius2 * axis[1];
  1593. if ( radius1 == 0.0f ) {
  1594. for ( i = 20; i <= 360; i += 20 ) {
  1595. d = idMath::Sin16( DEG2RAD(i) ) * axis[0] + idMath::Cos16( DEG2RAD(i) ) * axis[1];
  1596. p2 = top + d * radius2;
  1597. DebugLine( color, lastp2, p2, lifetime );
  1598. DebugLine( color, p2, apex, lifetime );
  1599. lastp2 = p2;
  1600. }
  1601. } else {
  1602. lastp1 = apex + radius1 * axis[1];
  1603. for ( i = 20; i <= 360; i += 20 ) {
  1604. d = idMath::Sin16( DEG2RAD(i) ) * axis[0] + idMath::Cos16( DEG2RAD(i) ) * axis[1];
  1605. p1 = apex + d * radius1;
  1606. p2 = top + d * radius2;
  1607. DebugLine( color, lastp1, p1, lifetime );
  1608. DebugLine( color, lastp2, p2, lifetime );
  1609. DebugLine( color, p1, p2, lifetime );
  1610. lastp1 = p1;
  1611. lastp2 = p2;
  1612. }
  1613. }
  1614. }
  1615. /*
  1616. ================
  1617. idRenderWorldLocal::DebugAxis
  1618. ================
  1619. */
  1620. void idRenderWorldLocal::DebugAxis( const idVec3 &origin, const idMat3 &axis ) {
  1621. idVec3 start = origin;
  1622. idVec3 end = start + axis[0] * 20.0f;
  1623. DebugArrow( colorWhite, start, end, 2 );
  1624. end = start + axis[0] * -20.0f;
  1625. DebugArrow( colorWhite, start, end, 2 );
  1626. end = start + axis[1] * +20.0f;
  1627. DebugArrow( colorGreen, start, end, 2 );
  1628. end = start + axis[1] * -20.0f;
  1629. DebugArrow( colorGreen, start, end, 2 );
  1630. end = start + axis[2] * +20.0f;
  1631. DebugArrow( colorBlue, start, end, 2 );
  1632. end = start + axis[2] * -20.0f;
  1633. DebugArrow( colorBlue, start, end, 2 );
  1634. }
  1635. /*
  1636. ====================
  1637. idRenderWorldLocal::DebugClearPolygons
  1638. ====================
  1639. */
  1640. void idRenderWorldLocal::DebugClearPolygons( int time ) {
  1641. RB_ClearDebugPolygons( time );
  1642. }
  1643. /*
  1644. ====================
  1645. idRenderWorldLocal::DebugPolygon
  1646. ====================
  1647. */
  1648. void idRenderWorldLocal::DebugPolygon( const idVec4 &color, const idWinding &winding, const int lifeTime, const bool depthTest ) {
  1649. RB_AddDebugPolygon( color, winding, lifeTime, depthTest );
  1650. }
  1651. /*
  1652. ================
  1653. idRenderWorldLocal::DebugScreenRect
  1654. ================
  1655. */
  1656. void idRenderWorldLocal::DebugScreenRect( const idVec4 &color, const idScreenRect &rect, const viewDef_t *viewDef, const int lifetime ) {
  1657. int i;
  1658. float centerx, centery, dScale, hScale, vScale;
  1659. idBounds bounds;
  1660. idVec3 p[4];
  1661. centerx = ( viewDef->viewport.x2 - viewDef->viewport.x1 ) * 0.5f;
  1662. centery = ( viewDef->viewport.y2 - viewDef->viewport.y1 ) * 0.5f;
  1663. dScale = r_znear.GetFloat() + 1.0f;
  1664. hScale = dScale * idMath::Tan16( DEG2RAD( viewDef->renderView.fov_x * 0.5f ) );
  1665. vScale = dScale * idMath::Tan16( DEG2RAD( viewDef->renderView.fov_y * 0.5f ) );
  1666. bounds[0][0] = bounds[1][0] = dScale;
  1667. bounds[0][1] = -( rect.x1 - centerx ) / centerx * hScale;
  1668. bounds[1][1] = -( rect.x2 - centerx ) / centerx * hScale;
  1669. bounds[0][2] = ( rect.y1 - centery ) / centery * vScale;
  1670. bounds[1][2] = ( rect.y2 - centery ) / centery * vScale;
  1671. for ( i = 0; i < 4; i++ ) {
  1672. p[i].x = bounds[0][0];
  1673. p[i].y = bounds[(i^(i>>1))&1].y;
  1674. p[i].z = bounds[(i>>1)&1].z;
  1675. p[i] = viewDef->renderView.vieworg + p[i] * viewDef->renderView.viewaxis;
  1676. }
  1677. for ( i = 0; i < 4; i++ ) {
  1678. DebugLine( color, p[i], p[(i+1)&3], false );
  1679. }
  1680. }
  1681. /*
  1682. ================
  1683. idRenderWorldLocal::DrawTextLength
  1684. returns the length of the given text
  1685. ================
  1686. */
  1687. float idRenderWorldLocal::DrawTextLength( const char *text, float scale, int len ) {
  1688. return RB_DrawTextLength( text, scale, len );
  1689. }
  1690. /*
  1691. ================
  1692. idRenderWorldLocal::DrawText
  1693. oriented on the viewaxis
  1694. align can be 0-left, 1-center (default), 2-right
  1695. ================
  1696. */
  1697. 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 ) {
  1698. RB_AddDebugText( text, origin, scale, color, viewAxis, align, lifetime, depthTest );
  1699. }
  1700. /*
  1701. ===============
  1702. idRenderWorldLocal::RegenerateWorld
  1703. ===============
  1704. */
  1705. void idRenderWorldLocal::RegenerateWorld() {
  1706. R_FreeDerivedData();
  1707. R_ReCreateWorldReferences();
  1708. }
  1709. /*
  1710. ===============
  1711. R_GlobalShaderOverride
  1712. ===============
  1713. */
  1714. bool R_GlobalShaderOverride( const idMaterial **shader ) {
  1715. if ( !(*shader)->IsDrawn() ) {
  1716. return false;
  1717. }
  1718. if ( tr.primaryRenderView.globalMaterial ) {
  1719. *shader = tr.primaryRenderView.globalMaterial;
  1720. return true;
  1721. }
  1722. if ( r_materialOverride.GetString()[0] != '\0' ) {
  1723. *shader = declManager->FindMaterial( r_materialOverride.GetString() );
  1724. return true;
  1725. }
  1726. return false;
  1727. }
  1728. /*
  1729. ===============
  1730. R_RemapShaderBySkin
  1731. ===============
  1732. */
  1733. const idMaterial *R_RemapShaderBySkin( const idMaterial *shader, const idDeclSkin *skin, const idMaterial *customShader ) {
  1734. if ( !shader ) {
  1735. return NULL;
  1736. }
  1737. // never remap surfaces that were originally nodraw, like collision hulls
  1738. if ( !shader->IsDrawn() ) {
  1739. return shader;
  1740. }
  1741. if ( customShader ) {
  1742. // this is sort of a hack, but cause deformed surfaces to map to empty surfaces,
  1743. // so the item highlight overlay doesn't highlight the autosprite surface
  1744. if ( shader->Deform() ) {
  1745. return NULL;
  1746. }
  1747. return const_cast<idMaterial *>(customShader);
  1748. }
  1749. if ( !skin ) {
  1750. return const_cast<idMaterial *>(shader);
  1751. }
  1752. return skin->RemapShaderBySkin( shader );
  1753. }