RenderWorld_defs.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  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. ENTITY DEFS
  26. =================================================================================
  27. */
  28. /*
  29. =================
  30. R_DeriveEntityData
  31. =================
  32. */
  33. void R_DeriveEntityData( idRenderEntityLocal * entity ) {
  34. R_AxisToModelMatrix( entity->parms.axis, entity->parms.origin, entity->modelMatrix );
  35. idRenderMatrix::CreateFromOriginAxis( entity->parms.origin, entity->parms.axis, entity->modelRenderMatrix );
  36. // calculate the matrix that transforms the unit cube to exactly cover the model in world space
  37. idRenderMatrix::OffsetScaleForBounds( entity->modelRenderMatrix, entity->localReferenceBounds, entity->inverseBaseModelProject );
  38. // calculate the global model bounds by inverse projecting the unit cube with the 'inverseBaseModelProject'
  39. idRenderMatrix::ProjectedBounds( entity->globalReferenceBounds, entity->inverseBaseModelProject, bounds_unitCube, false );
  40. }
  41. /*
  42. ===================
  43. R_FreeEntityDefDerivedData
  44. Used by both FreeEntityDef and UpdateEntityDef
  45. Does not actually free the entityDef.
  46. ===================
  47. */
  48. void R_FreeEntityDefDerivedData( idRenderEntityLocal *def, bool keepDecals, bool keepCachedDynamicModel ) {
  49. // demo playback needs to free the joints, while normal play
  50. // leaves them in the control of the game
  51. if ( common->ReadDemo() ) {
  52. if ( def->parms.joints ) {
  53. Mem_Free16( def->parms.joints );
  54. def->parms.joints = NULL;
  55. }
  56. if ( def->parms.callbackData ) {
  57. Mem_Free( def->parms.callbackData );
  58. def->parms.callbackData = NULL;
  59. }
  60. for ( int i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
  61. if ( def->parms.gui[ i ] ) {
  62. delete def->parms.gui[ i ];
  63. def->parms.gui[ i ] = NULL;
  64. }
  65. }
  66. }
  67. // free all the interactions
  68. while ( def->firstInteraction != NULL ) {
  69. def->firstInteraction->UnlinkAndFree();
  70. }
  71. def->dynamicModelFrameCount = 0;
  72. // clear the dynamic model if present
  73. if ( def->dynamicModel ) {
  74. def->dynamicModel = NULL;
  75. }
  76. if ( !keepDecals ) {
  77. R_FreeEntityDefDecals( def );
  78. R_FreeEntityDefOverlay( def );
  79. }
  80. if ( !keepCachedDynamicModel ) {
  81. delete def->cachedDynamicModel;
  82. def->cachedDynamicModel = NULL;
  83. }
  84. // free the entityRefs from the areas
  85. areaReference_t * next = NULL;
  86. for ( areaReference_t * ref = def->entityRefs; ref != NULL; ref = next ) {
  87. next = ref->ownerNext;
  88. // unlink from the area
  89. ref->areaNext->areaPrev = ref->areaPrev;
  90. ref->areaPrev->areaNext = ref->areaNext;
  91. // put it back on the free list for reuse
  92. def->world->areaReferenceAllocator.Free( ref );
  93. }
  94. def->entityRefs = NULL;
  95. }
  96. /*
  97. ===================
  98. R_FreeEntityDefDecals
  99. ===================
  100. */
  101. void R_FreeEntityDefDecals( idRenderEntityLocal *def ) {
  102. def->decals = NULL;
  103. }
  104. /*
  105. ===================
  106. R_FreeEntityDefFadedDecals
  107. ===================
  108. */
  109. void R_FreeEntityDefFadedDecals( idRenderEntityLocal *def, int time ) {
  110. if ( def->decals != NULL ) {
  111. def->decals->RemoveFadedDecals( time );
  112. }
  113. }
  114. /*
  115. ===================
  116. R_FreeEntityDefOverlay
  117. ===================
  118. */
  119. void R_FreeEntityDefOverlay( idRenderEntityLocal *def ) {
  120. def->overlays = NULL;
  121. }
  122. /*
  123. ===============
  124. R_CreateEntityRefs
  125. Creates all needed model references in portal areas,
  126. chaining them to both the area and the entityDef.
  127. Bumps tr.viewCount, which means viewCount can change many times each frame.
  128. ===============
  129. */
  130. void R_CreateEntityRefs( idRenderEntityLocal *entity ) {
  131. if ( entity->parms.hModel == NULL ) {
  132. entity->parms.hModel = renderModelManager->DefaultModel();
  133. }
  134. // if the entity hasn't been fully specified due to expensive animation calcs
  135. // for md5 and particles, use the provided conservative bounds.
  136. if ( entity->parms.callback != NULL ) {
  137. entity->localReferenceBounds = entity->parms.bounds;
  138. } else {
  139. entity->localReferenceBounds = entity->parms.hModel->Bounds( &entity->parms );
  140. }
  141. // some models, like empty particles, may not need to be added at all
  142. if ( entity->localReferenceBounds.IsCleared() ) {
  143. return;
  144. }
  145. if ( r_showUpdates.GetBool() &&
  146. ( entity->localReferenceBounds[1][0] - entity->localReferenceBounds[0][0] > 1024.0f ||
  147. entity->localReferenceBounds[1][1] - entity->localReferenceBounds[0][1] > 1024.0f ) ) {
  148. common->Printf( "big entityRef: %f,%f\n", entity->localReferenceBounds[1][0] - entity->localReferenceBounds[0][0],
  149. entity->localReferenceBounds[1][1] - entity->localReferenceBounds[0][1] );
  150. }
  151. // derive entity data
  152. R_DeriveEntityData( entity );
  153. // bump the view count so we can tell if an
  154. // area already has a reference
  155. tr.viewCount++;
  156. // push the model frustum down the BSP tree into areas
  157. entity->world->PushFrustumIntoTree( entity, NULL, entity->inverseBaseModelProject, bounds_unitCube );
  158. }
  159. /*
  160. =================================================================================
  161. LIGHT DEFS
  162. =================================================================================
  163. */
  164. /*
  165. ========================
  166. R_ComputePointLightProjectionMatrix
  167. Computes the light projection matrix for a point light.
  168. ========================
  169. */
  170. static float R_ComputePointLightProjectionMatrix( idRenderLightLocal * light, idRenderMatrix & localProject ) {
  171. assert( light->parms.pointLight );
  172. // A point light uses a box projection.
  173. // This projects into the 0.0 - 1.0 texture range instead of -1.0 to 1.0 clip space range.
  174. localProject.Zero();
  175. localProject[0][0] = 0.5f / light->parms.lightRadius[0];
  176. localProject[1][1] = 0.5f / light->parms.lightRadius[1];
  177. localProject[2][2] = 0.5f / light->parms.lightRadius[2];
  178. localProject[0][3] = 0.5f;
  179. localProject[1][3] = 0.5f;
  180. localProject[2][3] = 0.5f;
  181. localProject[3][3] = 1.0f; // identity perspective
  182. return 1.0f;
  183. }
  184. static const float SPOT_LIGHT_MIN_Z_NEAR = 8.0f;
  185. static const float SPOT_LIGHT_MIN_Z_FAR = 16.0f;
  186. /*
  187. ========================
  188. R_ComputeSpotLightProjectionMatrix
  189. Computes the light projection matrix for a spot light.
  190. ========================
  191. */
  192. static float R_ComputeSpotLightProjectionMatrix( idRenderLightLocal * light, idRenderMatrix & localProject ) {
  193. const float targetDistSqr = light->parms.target.LengthSqr();
  194. const float invTargetDist = idMath::InvSqrt( targetDistSqr );
  195. const float targetDist = invTargetDist * targetDistSqr;
  196. const idVec3 normalizedTarget = light->parms.target * invTargetDist;
  197. const idVec3 normalizedRight = light->parms.right * ( 0.5f * targetDist / light->parms.right.LengthSqr() );
  198. const idVec3 normalizedUp = light->parms.up * ( -0.5f * targetDist / light->parms.up.LengthSqr() );
  199. localProject[0][0] = normalizedRight[0];
  200. localProject[0][1] = normalizedRight[1];
  201. localProject[0][2] = normalizedRight[2];
  202. localProject[0][3] = 0.0f;
  203. localProject[1][0] = normalizedUp[0];
  204. localProject[1][1] = normalizedUp[1];
  205. localProject[1][2] = normalizedUp[2];
  206. localProject[1][3] = 0.0f;
  207. localProject[3][0] = normalizedTarget[0];
  208. localProject[3][1] = normalizedTarget[1];
  209. localProject[3][2] = normalizedTarget[2];
  210. localProject[3][3] = 0.0f;
  211. // Set the falloff vector.
  212. // This is similar to the Z calculation for depth buffering, which means that the
  213. // mapped texture is going to be perspective distorted heavily towards the zero end.
  214. const float zNear = Max( light->parms.start * normalizedTarget, SPOT_LIGHT_MIN_Z_NEAR );
  215. const float zFar = Max( light->parms.end * normalizedTarget, SPOT_LIGHT_MIN_Z_FAR );
  216. const float zScale = ( zNear + zFar ) / zFar;
  217. localProject[2][0] = normalizedTarget[0] * zScale;
  218. localProject[2][1] = normalizedTarget[1] * zScale;
  219. localProject[2][2] = normalizedTarget[2] * zScale;
  220. localProject[2][3] = - zNear * zScale;
  221. // now offset to the 0.0 - 1.0 texture range instead of -1.0 to 1.0 clip space range
  222. idVec4 projectedTarget;
  223. localProject.TransformPoint( light->parms.target, projectedTarget );
  224. const float ofs0 = 0.5f - projectedTarget[0] / projectedTarget[3];
  225. localProject[0][0] += ofs0 * localProject[3][0];
  226. localProject[0][1] += ofs0 * localProject[3][1];
  227. localProject[0][2] += ofs0 * localProject[3][2];
  228. localProject[0][3] += ofs0 * localProject[3][3];
  229. const float ofs1 = 0.5f - projectedTarget[1] / projectedTarget[3];
  230. localProject[1][0] += ofs1 * localProject[3][0];
  231. localProject[1][1] += ofs1 * localProject[3][1];
  232. localProject[1][2] += ofs1 * localProject[3][2];
  233. localProject[1][3] += ofs1 * localProject[3][3];
  234. return 1.0f / ( zNear + zFar );
  235. }
  236. /*
  237. ========================
  238. R_ComputeParallelLightProjectionMatrix
  239. Computes the light projection matrix for a parallel light.
  240. ========================
  241. */
  242. static float R_ComputeParallelLightProjectionMatrix( idRenderLightLocal * light, idRenderMatrix & localProject ) {
  243. assert( light->parms.parallel );
  244. // A parallel light uses a box projection.
  245. // This projects into the 0.0 - 1.0 texture range instead of -1.0 to 1.0 clip space range.
  246. localProject.Zero();
  247. localProject[0][0] = 0.5f / light->parms.lightRadius[0];
  248. localProject[1][1] = 0.5f / light->parms.lightRadius[1];
  249. localProject[2][2] = 0.5f / light->parms.lightRadius[2];
  250. localProject[0][3] = 0.5f;
  251. localProject[1][3] = 0.5f;
  252. localProject[2][3] = 0.5f;
  253. localProject[3][3] = 1.0f; // identity perspective
  254. return 1.0f;
  255. }
  256. /*
  257. =================
  258. R_DeriveLightData
  259. Fills everything in based on light->parms
  260. =================
  261. */
  262. static void R_DeriveLightData( idRenderLightLocal * light ) {
  263. // decide which light shader we are going to use
  264. if ( light->parms.shader != NULL ) {
  265. light->lightShader = light->parms.shader;
  266. } else if ( light->lightShader == NULL ) {
  267. if ( light->parms.pointLight ) {
  268. light->lightShader = tr.defaultPointLight;
  269. } else {
  270. light->lightShader = tr.defaultProjectedLight;
  271. }
  272. }
  273. // get the falloff image
  274. light->falloffImage = light->lightShader->LightFalloffImage();
  275. if ( light->falloffImage == NULL ) {
  276. // use the falloff from the default shader of the correct type
  277. const idMaterial * defaultShader;
  278. if ( light->parms.pointLight ) {
  279. defaultShader = tr.defaultPointLight;
  280. // Touch the default shader. to make sure it's decl has been parsed ( it might have been purged ).
  281. declManager->Touch( static_cast< const idDecl *>( defaultShader ) );
  282. light->falloffImage = defaultShader->LightFalloffImage();
  283. } else {
  284. // projected lights by default don't diminish with distance
  285. defaultShader = tr.defaultProjectedLight;
  286. // Touch the light shader. to make sure it's decl has been parsed ( it might have been purged ).
  287. declManager->Touch( static_cast< const idDecl *>( defaultShader ) );
  288. light->falloffImage = defaultShader->LightFalloffImage();
  289. }
  290. }
  291. // ------------------------------------
  292. // compute the light projection matrix
  293. // ------------------------------------
  294. idRenderMatrix localProject;
  295. float zScale = 1.0f;
  296. if ( light->parms.parallel ) {
  297. zScale = R_ComputeParallelLightProjectionMatrix( light, localProject );
  298. } else if ( light->parms.pointLight ) {
  299. zScale = R_ComputePointLightProjectionMatrix( light, localProject );
  300. } else {
  301. zScale = R_ComputeSpotLightProjectionMatrix( light, localProject );
  302. }
  303. // set the old style light projection where Z and W are flipped and
  304. // for projected lights lightProject[3] is divided by ( zNear + zFar )
  305. light->lightProject[0][0] = localProject[0][0];
  306. light->lightProject[0][1] = localProject[0][1];
  307. light->lightProject[0][2] = localProject[0][2];
  308. light->lightProject[0][3] = localProject[0][3];
  309. light->lightProject[1][0] = localProject[1][0];
  310. light->lightProject[1][1] = localProject[1][1];
  311. light->lightProject[1][2] = localProject[1][2];
  312. light->lightProject[1][3] = localProject[1][3];
  313. light->lightProject[2][0] = localProject[3][0];
  314. light->lightProject[2][1] = localProject[3][1];
  315. light->lightProject[2][2] = localProject[3][2];
  316. light->lightProject[2][3] = localProject[3][3];
  317. light->lightProject[3][0] = localProject[2][0] * zScale;
  318. light->lightProject[3][1] = localProject[2][1] * zScale;
  319. light->lightProject[3][2] = localProject[2][2] * zScale;
  320. light->lightProject[3][3] = localProject[2][3] * zScale;
  321. // transform the lightProject
  322. float lightTransform[16];
  323. R_AxisToModelMatrix( light->parms.axis, light->parms.origin, lightTransform );
  324. for ( int i = 0; i < 4; i++ ) {
  325. idPlane temp = light->lightProject[i];
  326. R_LocalPlaneToGlobal( lightTransform, temp, light->lightProject[i] );
  327. }
  328. // adjust global light origin for off center projections and parallel projections
  329. // we are just faking parallel by making it a very far off center for now
  330. if ( light->parms.parallel ) {
  331. idVec3 dir = light->parms.lightCenter;
  332. if ( dir.Normalize() == 0.0f ) {
  333. // make point straight up if not specified
  334. dir[2] = 1.0f;
  335. }
  336. light->globalLightOrigin = light->parms.origin + dir * 100000.0f;
  337. } else {
  338. light->globalLightOrigin = light->parms.origin + light->parms.axis * light->parms.lightCenter;
  339. }
  340. // Rotate and translate the light projection by the light matrix.
  341. // 99% of lights remain axis aligned in world space.
  342. idRenderMatrix lightMatrix;
  343. idRenderMatrix::CreateFromOriginAxis( light->parms.origin, light->parms.axis, lightMatrix );
  344. idRenderMatrix inverseLightMatrix;
  345. if ( !idRenderMatrix::Inverse( lightMatrix, inverseLightMatrix ) ) {
  346. idLib::Warning( "lightMatrix invert failed" );
  347. }
  348. // 'baseLightProject' goes from global space -> light local space -> light projective space
  349. idRenderMatrix::Multiply( localProject, inverseLightMatrix, light->baseLightProject );
  350. // Invert the light projection so we can deform zero-to-one cubes into
  351. // the light model and calculate global bounds.
  352. if ( !idRenderMatrix::Inverse( light->baseLightProject, light->inverseBaseLightProject ) ) {
  353. idLib::Warning( "baseLightProject invert failed" );
  354. }
  355. // calculate the global light bounds by inverse projecting the zero to one cube with the 'inverseBaseLightProject'
  356. idRenderMatrix::ProjectedBounds( light->globalLightBounds, light->inverseBaseLightProject, bounds_zeroOneCube, false );
  357. }
  358. /*
  359. ====================
  360. R_FreeLightDefDerivedData
  361. Frees all references and lit surfaces from the light
  362. ====================
  363. */
  364. void R_FreeLightDefDerivedData( idRenderLightLocal *ldef ) {
  365. // remove any portal fog references
  366. for ( doublePortal_t *dp = ldef->foggedPortals; dp != NULL; dp = dp->nextFoggedPortal ) {
  367. dp->fogLight = NULL;
  368. }
  369. // free all the interactions
  370. while ( ldef->firstInteraction != NULL ) {
  371. ldef->firstInteraction->UnlinkAndFree();
  372. }
  373. // free all the references to the light
  374. areaReference_t * nextRef = NULL;
  375. for ( areaReference_t * lref = ldef->references; lref != NULL; lref = nextRef ) {
  376. nextRef = lref->ownerNext;
  377. // unlink from the area
  378. lref->areaNext->areaPrev = lref->areaPrev;
  379. lref->areaPrev->areaNext = lref->areaNext;
  380. // put it back on the free list for reuse
  381. ldef->world->areaReferenceAllocator.Free( lref );
  382. }
  383. ldef->references = NULL;
  384. }
  385. /*
  386. ===============
  387. WindingCompletelyInsideLight
  388. ===============
  389. */
  390. static bool WindingCompletelyInsideLight( const idWinding *w, const idRenderLightLocal *ldef ) {
  391. for ( int i = 0; i < w->GetNumPoints(); i++ ) {
  392. if ( idRenderMatrix::CullPointToMVP( ldef->baseLightProject, (*w)[i].ToVec3(), true ) ) {
  393. return false;
  394. }
  395. }
  396. return true;
  397. }
  398. /*
  399. ======================
  400. R_CreateLightDefFogPortals
  401. When a fog light is created or moved, see if it completely
  402. encloses any portals, which may allow them to be fogged closed.
  403. ======================
  404. */
  405. static void R_CreateLightDefFogPortals( idRenderLightLocal *ldef ) {
  406. ldef->foggedPortals = NULL;
  407. if ( !ldef->lightShader->IsFogLight() ) {
  408. return;
  409. }
  410. // some fog lights will explicitly disallow portal fogging
  411. if ( ldef->lightShader->TestMaterialFlag( MF_NOPORTALFOG ) ) {
  412. return;
  413. }
  414. for ( areaReference_t * lref = ldef->references; lref != NULL; lref = lref->ownerNext ) {
  415. // check all the models in this area
  416. portalArea_t * area = lref->area;
  417. for ( portal_t * prt = area->portals; prt != NULL; prt = prt->next ) {
  418. doublePortal_t * dp = prt->doublePortal;
  419. // we only handle a single fog volume covering a portal
  420. // this will never cause incorrect drawing, but it may
  421. // fail to cull a portal
  422. if ( dp->fogLight ) {
  423. continue;
  424. }
  425. if ( WindingCompletelyInsideLight( prt->w, ldef ) ) {
  426. dp->fogLight = ldef;
  427. dp->nextFoggedPortal = ldef->foggedPortals;
  428. ldef->foggedPortals = dp;
  429. }
  430. }
  431. }
  432. }
  433. /*
  434. =================
  435. R_CreateLightRefs
  436. =================
  437. */
  438. void R_CreateLightRefs( idRenderLightLocal * light ) {
  439. // derive light data
  440. R_DeriveLightData( light );
  441. // determine the areaNum for the light origin, which may let us
  442. // cull the light if it is behind a closed door
  443. // it is debatable if we want to use the entity origin or the center offset origin,
  444. // but we definitely don't want to use a parallel offset origin
  445. light->areaNum = light->world->PointInArea( light->globalLightOrigin );
  446. if ( light->areaNum == -1 ) {
  447. light->areaNum = light->world->PointInArea( light->parms.origin );
  448. }
  449. // bump the view count so we can tell if an
  450. // area already has a reference
  451. tr.viewCount++;
  452. // if we have a prelight model that includes all the shadows for the major world occluders,
  453. // we can limit the area references to those visible through the portals from the light center.
  454. // We can't do this in the normal case, because shadows are cast from back facing triangles, which
  455. // may be in areas not directly visible to the light projection center.
  456. if ( light->parms.prelightModel != NULL && r_useLightPortalFlow.GetBool() && light->lightShader->LightCastsShadows() ) {
  457. light->world->FlowLightThroughPortals( light );
  458. } else {
  459. // push the light frustum down the BSP tree into areas
  460. light->world->PushFrustumIntoTree( NULL, light, light->inverseBaseLightProject, bounds_zeroOneCube );
  461. }
  462. R_CreateLightDefFogPortals( light );
  463. }
  464. /*
  465. =================================================================================
  466. WORLD MODEL & LIGHT DEFS
  467. =================================================================================
  468. */
  469. /*
  470. ===================
  471. R_FreeDerivedData
  472. ReloadModels and RegenerateWorld call this
  473. ===================
  474. */
  475. void R_FreeDerivedData() {
  476. for ( int j = 0; j < tr.worlds.Num(); j++ ) {
  477. idRenderWorldLocal * rw = tr.worlds[j];
  478. for ( int i = 0; i < rw->entityDefs.Num(); i++ ) {
  479. idRenderEntityLocal * def = rw->entityDefs[i];
  480. if ( def == NULL ) {
  481. continue;
  482. }
  483. R_FreeEntityDefDerivedData( def, false, false );
  484. }
  485. for ( int i = 0; i < rw->lightDefs.Num(); i++ ) {
  486. idRenderLightLocal * light = rw->lightDefs[i];
  487. if ( light == NULL ) {
  488. continue;
  489. }
  490. R_FreeLightDefDerivedData( light );
  491. }
  492. }
  493. }
  494. /*
  495. ===================
  496. R_CheckForEntityDefsUsingModel
  497. ===================
  498. */
  499. void R_CheckForEntityDefsUsingModel( idRenderModel *model ) {
  500. for ( int j = 0; j < tr.worlds.Num(); j++ ) {
  501. idRenderWorldLocal * rw = tr.worlds[j];
  502. for ( int i = 0; i < rw->entityDefs.Num(); i++ ) {
  503. idRenderEntityLocal * def = rw->entityDefs[i];
  504. if ( !def ) {
  505. continue;
  506. }
  507. if ( def->parms.hModel == model ) {
  508. //assert( 0 );
  509. // this should never happen but Radiant messes it up all the time so just free the derived data
  510. R_FreeEntityDefDerivedData( def, false, false );
  511. }
  512. }
  513. }
  514. }
  515. /*
  516. ===================
  517. R_ReCreateWorldReferences
  518. ReloadModels and RegenerateWorld call this
  519. ===================
  520. */
  521. void R_ReCreateWorldReferences() {
  522. // let the interaction generation code know this
  523. // shouldn't be optimized for a particular view
  524. tr.viewDef = NULL;
  525. for ( int j = 0; j < tr.worlds.Num(); j++ ) {
  526. idRenderWorldLocal * rw = tr.worlds[j];
  527. for ( int i = 0; i < rw->entityDefs.Num(); i++ ) {
  528. idRenderEntityLocal * def = rw->entityDefs[i];
  529. if ( def == NULL ) {
  530. continue;
  531. }
  532. // the world model entities are put specifically in a single
  533. // area, instead of just pushing their bounds into the tree
  534. if ( i < rw->numPortalAreas ) {
  535. rw->AddEntityRefToArea( def, &rw->portalAreas[i] );
  536. } else {
  537. R_CreateEntityRefs( def );
  538. }
  539. }
  540. for ( int i = 0; i < rw->lightDefs.Num(); i++ ) {
  541. idRenderLightLocal * light = rw->lightDefs[i];
  542. if ( light == NULL ) {
  543. continue;
  544. }
  545. renderLight_t parms = light->parms;
  546. light->world->FreeLightDef( i );
  547. rw->UpdateLightDef( i, &parms );
  548. }
  549. }
  550. }
  551. /*
  552. ====================
  553. R_ModulateLights_f
  554. Modifies the shaderParms on all the lights so the level
  555. designers can easily test different color schemes
  556. ====================
  557. */
  558. void R_ModulateLights_f( const idCmdArgs &args ) {
  559. if ( !tr.primaryWorld ) {
  560. return;
  561. }
  562. if ( args.Argc() != 4 ) {
  563. common->Printf( "usage: modulateLights <redFloat> <greenFloat> <blueFloat>\n" );
  564. return;
  565. }
  566. float modulate[3];
  567. for ( int i = 0; i < 3; i++ ) {
  568. modulate[i] = atof( args.Argv( i+1 ) );
  569. }
  570. int count = 0;
  571. for ( int i = 0; i < tr.primaryWorld->lightDefs.Num(); i++ ) {
  572. idRenderLightLocal * light = tr.primaryWorld->lightDefs[i];
  573. if ( light != NULL ) {
  574. count++;
  575. for ( int j = 0; j < 3; j++ ) {
  576. light->parms.shaderParms[j] *= modulate[j];
  577. }
  578. }
  579. }
  580. common->Printf( "modulated %i lights\n", count );
  581. }