RenderWorld.cpp 58 KB

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