tr_main.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164
  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. #ifdef __ppc__
  24. #include <vecLib/vecLib.h>
  25. #endif
  26. #if defined(MACOS_X) && defined(__i386__)
  27. #include <xmmintrin.h>
  28. #endif
  29. //====================================================================
  30. /*
  31. ======================
  32. idScreenRect::Clear
  33. ======================
  34. */
  35. void idScreenRect::Clear() {
  36. x1 = y1 = 32000;
  37. x2 = y2 = -32000;
  38. zmin = 0.0f; zmax = 1.0f;
  39. }
  40. /*
  41. ======================
  42. idScreenRect::AddPoint
  43. ======================
  44. */
  45. void idScreenRect::AddPoint( float x, float y ) {
  46. int ix = idMath::FtoiFast( x );
  47. int iy = idMath::FtoiFast( y );
  48. if ( ix < x1 ) {
  49. x1 = ix;
  50. }
  51. if ( ix > x2 ) {
  52. x2 = ix;
  53. }
  54. if ( iy < y1 ) {
  55. y1 = iy;
  56. }
  57. if ( iy > y2 ) {
  58. y2 = iy;
  59. }
  60. }
  61. /*
  62. ======================
  63. idScreenRect::Expand
  64. ======================
  65. */
  66. void idScreenRect::Expand() {
  67. x1--;
  68. y1--;
  69. x2++;
  70. y2++;
  71. }
  72. /*
  73. ======================
  74. idScreenRect::Intersect
  75. ======================
  76. */
  77. void idScreenRect::Intersect( const idScreenRect &rect ) {
  78. if ( rect.x1 > x1 ) {
  79. x1 = rect.x1;
  80. }
  81. if ( rect.x2 < x2 ) {
  82. x2 = rect.x2;
  83. }
  84. if ( rect.y1 > y1 ) {
  85. y1 = rect.y1;
  86. }
  87. if ( rect.y2 < y2 ) {
  88. y2 = rect.y2;
  89. }
  90. }
  91. /*
  92. ======================
  93. idScreenRect::Union
  94. ======================
  95. */
  96. void idScreenRect::Union( const idScreenRect &rect ) {
  97. if ( rect.x1 < x1 ) {
  98. x1 = rect.x1;
  99. }
  100. if ( rect.x2 > x2 ) {
  101. x2 = rect.x2;
  102. }
  103. if ( rect.y1 < y1 ) {
  104. y1 = rect.y1;
  105. }
  106. if ( rect.y2 > y2 ) {
  107. y2 = rect.y2;
  108. }
  109. }
  110. /*
  111. ======================
  112. idScreenRect::Equals
  113. ======================
  114. */
  115. bool idScreenRect::Equals( const idScreenRect &rect ) const {
  116. return ( x1 == rect.x1 && x2 == rect.x2 && y1 == rect.y1 && y2 == rect.y2 );
  117. }
  118. /*
  119. ======================
  120. idScreenRect::IsEmpty
  121. ======================
  122. */
  123. bool idScreenRect::IsEmpty() const {
  124. return ( x1 > x2 || y1 > y2 );
  125. }
  126. /*
  127. ======================
  128. R_ScreenRectFromViewFrustumBounds
  129. ======================
  130. */
  131. idScreenRect R_ScreenRectFromViewFrustumBounds( const idBounds &bounds ) {
  132. idScreenRect screenRect;
  133. screenRect.x1 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[1].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) );
  134. screenRect.x2 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[0].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) );
  135. screenRect.y1 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[0].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) );
  136. screenRect.y2 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[1].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) );
  137. if ( r_useDepthBoundsTest.GetInteger() ) {
  138. R_TransformEyeZToWin( -bounds[0].x, tr.viewDef->projectionMatrix, screenRect.zmin );
  139. R_TransformEyeZToWin( -bounds[1].x, tr.viewDef->projectionMatrix, screenRect.zmax );
  140. }
  141. return screenRect;
  142. }
  143. /*
  144. ======================
  145. R_ShowColoredScreenRect
  146. ======================
  147. */
  148. void R_ShowColoredScreenRect( const idScreenRect &rect, int colorIndex ) {
  149. if ( !rect.IsEmpty() ) {
  150. static idVec4 colors[] = { colorRed, colorGreen, colorBlue, colorYellow, colorMagenta, colorCyan, colorWhite, colorPurple };
  151. tr.viewDef->renderWorld->DebugScreenRect( colors[colorIndex & 7], rect, tr.viewDef );
  152. }
  153. }
  154. /*
  155. ====================
  156. R_ToggleSmpFrame
  157. ====================
  158. */
  159. void R_ToggleSmpFrame( void ) {
  160. if ( r_lockSurfaces.GetBool() ) {
  161. return;
  162. }
  163. R_FreeDeferredTriSurfs( frameData );
  164. // clear frame-temporary data
  165. frameData_t *frame;
  166. frameMemoryBlock_t *block;
  167. // update the highwater mark
  168. R_CountFrameData();
  169. frame = frameData;
  170. // reset the memory allocation to the first block
  171. frame->alloc = frame->memory;
  172. // clear all the blocks
  173. for ( block = frame->memory ; block ; block = block->next ) {
  174. block->used = 0;
  175. }
  176. R_ClearCommandChain();
  177. }
  178. //=====================================================
  179. #define MEMORY_BLOCK_SIZE 0x100000
  180. /*
  181. =====================
  182. R_ShutdownFrameData
  183. =====================
  184. */
  185. void R_ShutdownFrameData( void ) {
  186. frameData_t *frame;
  187. frameMemoryBlock_t *block;
  188. // free any current data
  189. frame = frameData;
  190. if ( !frame ) {
  191. return;
  192. }
  193. R_FreeDeferredTriSurfs( frame );
  194. frameMemoryBlock_t *nextBlock;
  195. for ( block = frame->memory ; block ; block = nextBlock ) {
  196. nextBlock = block->next;
  197. Mem_Free( block );
  198. }
  199. Mem_Free( frame );
  200. frameData = NULL;
  201. }
  202. /*
  203. =====================
  204. R_InitFrameData
  205. =====================
  206. */
  207. void R_InitFrameData( void ) {
  208. int size;
  209. frameData_t *frame;
  210. frameMemoryBlock_t *block;
  211. R_ShutdownFrameData();
  212. frameData = (frameData_t *)Mem_ClearedAlloc( sizeof( *frameData ));
  213. frame = frameData;
  214. size = MEMORY_BLOCK_SIZE;
  215. block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) );
  216. if ( !block ) {
  217. common->FatalError( "R_InitFrameData: Mem_Alloc() failed" );
  218. }
  219. block->size = size;
  220. block->used = 0;
  221. block->next = NULL;
  222. frame->memory = block;
  223. frame->memoryHighwater = 0;
  224. R_ToggleSmpFrame();
  225. }
  226. /*
  227. ================
  228. R_CountFrameData
  229. ================
  230. */
  231. int R_CountFrameData( void ) {
  232. frameData_t *frame;
  233. frameMemoryBlock_t *block;
  234. int count;
  235. count = 0;
  236. frame = frameData;
  237. for ( block = frame->memory ; block ; block=block->next ) {
  238. count += block->used;
  239. if ( block == frame->alloc ) {
  240. break;
  241. }
  242. }
  243. // note if this is a new highwater mark
  244. if ( count > frame->memoryHighwater ) {
  245. frame->memoryHighwater = count;
  246. }
  247. return count;
  248. }
  249. /*
  250. =================
  251. R_StaticAlloc
  252. =================
  253. */
  254. void *R_StaticAlloc( int bytes ) {
  255. void *buf;
  256. tr.pc.c_alloc++;
  257. tr.staticAllocCount += bytes;
  258. buf = Mem_Alloc( bytes );
  259. // don't exit on failure on zero length allocations since the old code didn't
  260. if ( !buf && ( bytes != 0 ) ) {
  261. common->FatalError( "R_StaticAlloc failed on %i bytes", bytes );
  262. }
  263. return buf;
  264. }
  265. /*
  266. =================
  267. R_ClearedStaticAlloc
  268. =================
  269. */
  270. void *R_ClearedStaticAlloc( int bytes ) {
  271. void *buf;
  272. buf = R_StaticAlloc( bytes );
  273. SIMDProcessor->Memset( buf, 0, bytes );
  274. return buf;
  275. }
  276. /*
  277. =================
  278. R_StaticFree
  279. =================
  280. */
  281. void R_StaticFree( void *data ) {
  282. tr.pc.c_free++;
  283. Mem_Free( data );
  284. }
  285. /*
  286. ================
  287. R_FrameAlloc
  288. This data will be automatically freed when the
  289. current frame's back end completes.
  290. This should only be called by the front end. The
  291. back end shouldn't need to allocate memory.
  292. If we passed smpFrame in, the back end could
  293. alloc memory, because it will always be a
  294. different frameData than the front end is using.
  295. All temporary data, like dynamic tesselations
  296. and local spaces are allocated here.
  297. The memory will not move, but it may not be
  298. contiguous with previous allocations even
  299. from this frame.
  300. The memory is NOT zero filled.
  301. Should part of this be inlined in a macro?
  302. ================
  303. */
  304. void *R_FrameAlloc( int bytes ) {
  305. frameData_t *frame;
  306. frameMemoryBlock_t *block;
  307. void *buf;
  308. bytes = (bytes+16)&~15;
  309. // see if it can be satisfied in the current block
  310. frame = frameData;
  311. block = frame->alloc;
  312. if ( block->size - block->used >= bytes ) {
  313. buf = block->base + block->used;
  314. block->used += bytes;
  315. return buf;
  316. }
  317. // advance to the next memory block if available
  318. block = block->next;
  319. // create a new block if we are at the end of
  320. // the chain
  321. if ( !block ) {
  322. int size;
  323. size = MEMORY_BLOCK_SIZE;
  324. block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) );
  325. if ( !block ) {
  326. common->FatalError( "R_FrameAlloc: Mem_Alloc() failed" );
  327. }
  328. block->size = size;
  329. block->used = 0;
  330. block->next = NULL;
  331. frame->alloc->next = block;
  332. }
  333. // we could fix this if we needed to...
  334. if ( bytes > block->size ) {
  335. common->FatalError( "R_FrameAlloc of %i exceeded MEMORY_BLOCK_SIZE",
  336. bytes );
  337. }
  338. frame->alloc = block;
  339. block->used = bytes;
  340. return block->base;
  341. }
  342. /*
  343. ==================
  344. R_ClearedFrameAlloc
  345. ==================
  346. */
  347. void *R_ClearedFrameAlloc( int bytes ) {
  348. void *r;
  349. r = R_FrameAlloc( bytes );
  350. SIMDProcessor->Memset( r, 0, bytes );
  351. return r;
  352. }
  353. /*
  354. ==================
  355. R_FrameFree
  356. This does nothing at all, as the frame data is reused every frame
  357. and can only be stack allocated.
  358. The only reason for it's existance is so functions that can
  359. use either static or frame memory can set function pointers
  360. to both alloc and free.
  361. ==================
  362. */
  363. void R_FrameFree( void *data ) {
  364. }
  365. //==========================================================================
  366. void R_AxisToModelMatrix( const idMat3 &axis, const idVec3 &origin, float modelMatrix[16] ) {
  367. modelMatrix[0] = axis[0][0];
  368. modelMatrix[4] = axis[1][0];
  369. modelMatrix[8] = axis[2][0];
  370. modelMatrix[12] = origin[0];
  371. modelMatrix[1] = axis[0][1];
  372. modelMatrix[5] = axis[1][1];
  373. modelMatrix[9] = axis[2][1];
  374. modelMatrix[13] = origin[1];
  375. modelMatrix[2] = axis[0][2];
  376. modelMatrix[6] = axis[1][2];
  377. modelMatrix[10] = axis[2][2];
  378. modelMatrix[14] = origin[2];
  379. modelMatrix[3] = 0;
  380. modelMatrix[7] = 0;
  381. modelMatrix[11] = 0;
  382. modelMatrix[15] = 1;
  383. }
  384. // FIXME: these assume no skewing or scaling transforms
  385. void R_LocalPointToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
  386. #if defined(MACOS_X) && defined(__i386__)
  387. __m128 m0, m1, m2, m3;
  388. __m128 in0, in1, in2;
  389. float i0,i1,i2;
  390. i0 = in[0];
  391. i1 = in[1];
  392. i2 = in[2];
  393. m0 = _mm_loadu_ps(&modelMatrix[0]);
  394. m1 = _mm_loadu_ps(&modelMatrix[4]);
  395. m2 = _mm_loadu_ps(&modelMatrix[8]);
  396. m3 = _mm_loadu_ps(&modelMatrix[12]);
  397. in0 = _mm_load1_ps(&i0);
  398. in1 = _mm_load1_ps(&i1);
  399. in2 = _mm_load1_ps(&i2);
  400. m0 = _mm_mul_ps(m0, in0);
  401. m1 = _mm_mul_ps(m1, in1);
  402. m2 = _mm_mul_ps(m2, in2);
  403. m0 = _mm_add_ps(m0, m1);
  404. m0 = _mm_add_ps(m0, m2);
  405. m0 = _mm_add_ps(m0, m3);
  406. _mm_store_ss(&out[0], m0);
  407. m1 = (__m128) _mm_shuffle_epi32((__m128i)m0, 0x55);
  408. _mm_store_ss(&out[1], m1);
  409. m2 = _mm_movehl_ps(m2, m0);
  410. _mm_store_ss(&out[2], m2);
  411. #else
  412. out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4]
  413. + in[2] * modelMatrix[8] + modelMatrix[12];
  414. out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5]
  415. + in[2] * modelMatrix[9] + modelMatrix[13];
  416. out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6]
  417. + in[2] * modelMatrix[10] + modelMatrix[14];
  418. #endif
  419. }
  420. void R_PointTimesMatrix( const float modelMatrix[16], const idVec4 &in, idVec4 &out ) {
  421. out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4]
  422. + in[2] * modelMatrix[8] + modelMatrix[12];
  423. out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5]
  424. + in[2] * modelMatrix[9] + modelMatrix[13];
  425. out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6]
  426. + in[2] * modelMatrix[10] + modelMatrix[14];
  427. out[3] = in[0] * modelMatrix[3] + in[1] * modelMatrix[7]
  428. + in[2] * modelMatrix[11] + modelMatrix[15];
  429. }
  430. void R_GlobalPointToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
  431. idVec3 temp;
  432. VectorSubtract( in, &modelMatrix[12], temp );
  433. out[0] = DotProduct( temp, &modelMatrix[0] );
  434. out[1] = DotProduct( temp, &modelMatrix[4] );
  435. out[2] = DotProduct( temp, &modelMatrix[8] );
  436. }
  437. void R_LocalVectorToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
  438. out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4]
  439. + in[2] * modelMatrix[8];
  440. out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5]
  441. + in[2] * modelMatrix[9];
  442. out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6]
  443. + in[2] * modelMatrix[10];
  444. }
  445. void R_GlobalVectorToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
  446. out[0] = DotProduct( in, &modelMatrix[0] );
  447. out[1] = DotProduct( in, &modelMatrix[4] );
  448. out[2] = DotProduct( in, &modelMatrix[8] );
  449. }
  450. void R_GlobalPlaneToLocal( const float modelMatrix[16], const idPlane &in, idPlane &out ) {
  451. out[0] = DotProduct( in, &modelMatrix[0] );
  452. out[1] = DotProduct( in, &modelMatrix[4] );
  453. out[2] = DotProduct( in, &modelMatrix[8] );
  454. out[3] = in[3] + modelMatrix[12] * in[0] + modelMatrix[13] * in[1] + modelMatrix[14] * in[2];
  455. }
  456. void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane &in, idPlane &out ) {
  457. float offset;
  458. R_LocalVectorToGlobal( modelMatrix, in.Normal(), out.Normal() );
  459. offset = modelMatrix[12] * out[0] + modelMatrix[13] * out[1] + modelMatrix[14] * out[2];
  460. out[3] = in[3] - offset;
  461. }
  462. // transform Z in eye coordinates to window coordinates
  463. void R_TransformEyeZToWin( float src_z, const float *projectionMatrix, float &dst_z ) {
  464. float clip_z, clip_w;
  465. // projection
  466. clip_z = src_z * projectionMatrix[ 2 + 2 * 4 ] + projectionMatrix[ 2 + 3 * 4 ];
  467. clip_w = src_z * projectionMatrix[ 3 + 2 * 4 ] + projectionMatrix[ 3 + 3 * 4 ];
  468. if ( clip_w <= 0.0f ) {
  469. dst_z = 0.0f; // clamp to near plane
  470. } else {
  471. dst_z = clip_z / clip_w;
  472. dst_z = dst_z * 0.5f + 0.5f; // convert to window coords
  473. }
  474. }
  475. /*
  476. =================
  477. R_RadiusCullLocalBox
  478. A fast, conservative center-to-corner culling test
  479. Returns true if the box is outside the given global frustum, (positive sides are out)
  480. =================
  481. */
  482. bool R_RadiusCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
  483. int i;
  484. float d;
  485. idVec3 worldOrigin;
  486. float worldRadius;
  487. const idPlane *frust;
  488. if ( r_useCulling.GetInteger() == 0 ) {
  489. return false;
  490. }
  491. // transform the surface bounds into world space
  492. idVec3 localOrigin = ( bounds[0] + bounds[1] ) * 0.5;
  493. R_LocalPointToGlobal( modelMatrix, localOrigin, worldOrigin );
  494. worldRadius = (bounds[0] - localOrigin).Length(); // FIXME: won't be correct for scaled objects
  495. for ( i = 0 ; i < numPlanes ; i++ ) {
  496. frust = planes + i;
  497. d = frust->Distance( worldOrigin );
  498. if ( d > worldRadius ) {
  499. return true; // culled
  500. }
  501. }
  502. return false; // no culled
  503. }
  504. /*
  505. =================
  506. R_CornerCullLocalBox
  507. Tests all corners against the frustum.
  508. Can still generate a few false positives when the box is outside a corner.
  509. Returns true if the box is outside the given global frustum, (positive sides are out)
  510. =================
  511. */
  512. bool R_CornerCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
  513. int i, j;
  514. idVec3 transformed[8];
  515. float dists[8];
  516. idVec3 v;
  517. const idPlane *frust;
  518. // we can disable box culling for experimental timing purposes
  519. if ( r_useCulling.GetInteger() < 2 ) {
  520. return false;
  521. }
  522. // transform into world space
  523. for ( i = 0 ; i < 8 ; i++ ) {
  524. v[0] = bounds[i&1][0];
  525. v[1] = bounds[(i>>1)&1][1];
  526. v[2] = bounds[(i>>2)&1][2];
  527. R_LocalPointToGlobal( modelMatrix, v, transformed[i] );
  528. }
  529. // check against frustum planes
  530. for ( i = 0 ; i < numPlanes ; i++ ) {
  531. frust = planes + i;
  532. for ( j = 0 ; j < 8 ; j++ ) {
  533. dists[j] = frust->Distance( transformed[j] );
  534. if ( dists[j] < 0 ) {
  535. break;
  536. }
  537. }
  538. if ( j == 8 ) {
  539. // all points were behind one of the planes
  540. tr.pc.c_box_cull_out++;
  541. return true;
  542. }
  543. }
  544. tr.pc.c_box_cull_in++;
  545. return false; // not culled
  546. }
  547. /*
  548. =================
  549. R_CullLocalBox
  550. Performs quick test before expensive test
  551. Returns true if the box is outside the given global frustum, (positive sides are out)
  552. =================
  553. */
  554. bool R_CullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
  555. if ( R_RadiusCullLocalBox( bounds, modelMatrix, numPlanes, planes ) ) {
  556. return true;
  557. }
  558. return R_CornerCullLocalBox( bounds, modelMatrix, numPlanes, planes );
  559. }
  560. /*
  561. ==========================
  562. R_TransformModelToClip
  563. ==========================
  564. */
  565. void R_TransformModelToClip( const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst ) {
  566. int i;
  567. for ( i = 0 ; i < 4 ; i++ ) {
  568. eye[i] =
  569. src[0] * modelMatrix[ i + 0 * 4 ] +
  570. src[1] * modelMatrix[ i + 1 * 4 ] +
  571. src[2] * modelMatrix[ i + 2 * 4 ] +
  572. 1 * modelMatrix[ i + 3 * 4 ];
  573. }
  574. for ( i = 0 ; i < 4 ; i++ ) {
  575. dst[i] =
  576. eye[0] * projectionMatrix[ i + 0 * 4 ] +
  577. eye[1] * projectionMatrix[ i + 1 * 4 ] +
  578. eye[2] * projectionMatrix[ i + 2 * 4 ] +
  579. eye[3] * projectionMatrix[ i + 3 * 4 ];
  580. }
  581. }
  582. /*
  583. ==========================
  584. R_GlobalToNormalizedDeviceCoordinates
  585. -1 to 1 range in x, y, and z
  586. ==========================
  587. */
  588. void R_GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ) {
  589. int i;
  590. idPlane view;
  591. idPlane clip;
  592. // _D3XP added work on primaryView when no viewDef
  593. if ( !tr.viewDef ) {
  594. for ( i = 0 ; i < 4 ; i ++ ) {
  595. view[i] =
  596. global[0] * tr.primaryView->worldSpace.modelViewMatrix[ i + 0 * 4 ] +
  597. global[1] * tr.primaryView->worldSpace.modelViewMatrix[ i + 1 * 4 ] +
  598. global[2] * tr.primaryView->worldSpace.modelViewMatrix[ i + 2 * 4 ] +
  599. tr.primaryView->worldSpace.modelViewMatrix[ i + 3 * 4 ];
  600. }
  601. for ( i = 0 ; i < 4 ; i ++ ) {
  602. clip[i] =
  603. view[0] * tr.primaryView->projectionMatrix[ i + 0 * 4 ] +
  604. view[1] * tr.primaryView->projectionMatrix[ i + 1 * 4 ] +
  605. view[2] * tr.primaryView->projectionMatrix[ i + 2 * 4 ] +
  606. view[3] * tr.primaryView->projectionMatrix[ i + 3 * 4 ];
  607. }
  608. } else {
  609. for ( i = 0 ; i < 4 ; i ++ ) {
  610. view[i] =
  611. global[0] * tr.viewDef->worldSpace.modelViewMatrix[ i + 0 * 4 ] +
  612. global[1] * tr.viewDef->worldSpace.modelViewMatrix[ i + 1 * 4 ] +
  613. global[2] * tr.viewDef->worldSpace.modelViewMatrix[ i + 2 * 4 ] +
  614. tr.viewDef->worldSpace.modelViewMatrix[ i + 3 * 4 ];
  615. }
  616. for ( i = 0 ; i < 4 ; i ++ ) {
  617. clip[i] =
  618. view[0] * tr.viewDef->projectionMatrix[ i + 0 * 4 ] +
  619. view[1] * tr.viewDef->projectionMatrix[ i + 1 * 4 ] +
  620. view[2] * tr.viewDef->projectionMatrix[ i + 2 * 4 ] +
  621. view[3] * tr.viewDef->projectionMatrix[ i + 3 * 4 ];
  622. }
  623. }
  624. ndc[0] = clip[0] / clip[3];
  625. ndc[1] = clip[1] / clip[3];
  626. ndc[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
  627. }
  628. /*
  629. ==========================
  630. R_TransformClipToDevice
  631. Clip to normalized device coordinates
  632. ==========================
  633. */
  634. void R_TransformClipToDevice( const idPlane &clip, const viewDef_t *view, idVec3 &normalized ) {
  635. normalized[0] = clip[0] / clip[3];
  636. normalized[1] = clip[1] / clip[3];
  637. normalized[2] = clip[2] / clip[3];
  638. }
  639. /*
  640. ==========================
  641. myGlMultMatrix
  642. ==========================
  643. */
  644. void myGlMultMatrix( const float a[16], const float b[16], float out[16] ) {
  645. #if 0
  646. int i, j;
  647. for ( i = 0 ; i < 4 ; i++ ) {
  648. for ( j = 0 ; j < 4 ; j++ ) {
  649. out[ i * 4 + j ] =
  650. a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
  651. + a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
  652. + a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
  653. + a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
  654. }
  655. }
  656. #else
  657. out[0*4+0] = a[0*4+0]*b[0*4+0] + a[0*4+1]*b[1*4+0] + a[0*4+2]*b[2*4+0] + a[0*4+3]*b[3*4+0];
  658. out[0*4+1] = a[0*4+0]*b[0*4+1] + a[0*4+1]*b[1*4+1] + a[0*4+2]*b[2*4+1] + a[0*4+3]*b[3*4+1];
  659. out[0*4+2] = a[0*4+0]*b[0*4+2] + a[0*4+1]*b[1*4+2] + a[0*4+2]*b[2*4+2] + a[0*4+3]*b[3*4+2];
  660. out[0*4+3] = a[0*4+0]*b[0*4+3] + a[0*4+1]*b[1*4+3] + a[0*4+2]*b[2*4+3] + a[0*4+3]*b[3*4+3];
  661. out[1*4+0] = a[1*4+0]*b[0*4+0] + a[1*4+1]*b[1*4+0] + a[1*4+2]*b[2*4+0] + a[1*4+3]*b[3*4+0];
  662. out[1*4+1] = a[1*4+0]*b[0*4+1] + a[1*4+1]*b[1*4+1] + a[1*4+2]*b[2*4+1] + a[1*4+3]*b[3*4+1];
  663. out[1*4+2] = a[1*4+0]*b[0*4+2] + a[1*4+1]*b[1*4+2] + a[1*4+2]*b[2*4+2] + a[1*4+3]*b[3*4+2];
  664. out[1*4+3] = a[1*4+0]*b[0*4+3] + a[1*4+1]*b[1*4+3] + a[1*4+2]*b[2*4+3] + a[1*4+3]*b[3*4+3];
  665. out[2*4+0] = a[2*4+0]*b[0*4+0] + a[2*4+1]*b[1*4+0] + a[2*4+2]*b[2*4+0] + a[2*4+3]*b[3*4+0];
  666. out[2*4+1] = a[2*4+0]*b[0*4+1] + a[2*4+1]*b[1*4+1] + a[2*4+2]*b[2*4+1] + a[2*4+3]*b[3*4+1];
  667. out[2*4+2] = a[2*4+0]*b[0*4+2] + a[2*4+1]*b[1*4+2] + a[2*4+2]*b[2*4+2] + a[2*4+3]*b[3*4+2];
  668. out[2*4+3] = a[2*4+0]*b[0*4+3] + a[2*4+1]*b[1*4+3] + a[2*4+2]*b[2*4+3] + a[2*4+3]*b[3*4+3];
  669. out[3*4+0] = a[3*4+0]*b[0*4+0] + a[3*4+1]*b[1*4+0] + a[3*4+2]*b[2*4+0] + a[3*4+3]*b[3*4+0];
  670. out[3*4+1] = a[3*4+0]*b[0*4+1] + a[3*4+1]*b[1*4+1] + a[3*4+2]*b[2*4+1] + a[3*4+3]*b[3*4+1];
  671. out[3*4+2] = a[3*4+0]*b[0*4+2] + a[3*4+1]*b[1*4+2] + a[3*4+2]*b[2*4+2] + a[3*4+3]*b[3*4+2];
  672. out[3*4+3] = a[3*4+0]*b[0*4+3] + a[3*4+1]*b[1*4+3] + a[3*4+2]*b[2*4+3] + a[3*4+3]*b[3*4+3];
  673. #endif
  674. }
  675. /*
  676. ================
  677. R_TransposeGLMatrix
  678. ================
  679. */
  680. void R_TransposeGLMatrix( const float in[16], float out[16] ) {
  681. int i, j;
  682. for ( i = 0 ; i < 4 ; i++ ) {
  683. for ( j = 0 ; j < 4 ; j++ ) {
  684. out[i*4+j] = in[j*4+i];
  685. }
  686. }
  687. }
  688. /*
  689. =================
  690. R_SetViewMatrix
  691. Sets up the world to view matrix for a given viewParm
  692. =================
  693. */
  694. void R_SetViewMatrix( viewDef_t *viewDef ) {
  695. idVec3 origin;
  696. viewEntity_t *world;
  697. float viewerMatrix[16];
  698. static float s_flipMatrix[16] = {
  699. // convert from our coordinate system (looking down X)
  700. // to OpenGL's coordinate system (looking down -Z)
  701. 0, 0, -1, 0,
  702. -1, 0, 0, 0,
  703. 0, 1, 0, 0,
  704. 0, 0, 0, 1
  705. };
  706. world = &viewDef->worldSpace;
  707. memset( world, 0, sizeof(*world) );
  708. // the model matrix is an identity
  709. world->modelMatrix[0*4+0] = 1;
  710. world->modelMatrix[1*4+1] = 1;
  711. world->modelMatrix[2*4+2] = 1;
  712. // transform by the camera placement
  713. origin = viewDef->renderView.vieworg;
  714. viewerMatrix[0] = viewDef->renderView.viewaxis[0][0];
  715. viewerMatrix[4] = viewDef->renderView.viewaxis[0][1];
  716. viewerMatrix[8] = viewDef->renderView.viewaxis[0][2];
  717. viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
  718. viewerMatrix[1] = viewDef->renderView.viewaxis[1][0];
  719. viewerMatrix[5] = viewDef->renderView.viewaxis[1][1];
  720. viewerMatrix[9] = viewDef->renderView.viewaxis[1][2];
  721. viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
  722. viewerMatrix[2] = viewDef->renderView.viewaxis[2][0];
  723. viewerMatrix[6] = viewDef->renderView.viewaxis[2][1];
  724. viewerMatrix[10] = viewDef->renderView.viewaxis[2][2];
  725. viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
  726. viewerMatrix[3] = 0;
  727. viewerMatrix[7] = 0;
  728. viewerMatrix[11] = 0;
  729. viewerMatrix[15] = 1;
  730. // convert from our coordinate system (looking down X)
  731. // to OpenGL's coordinate system (looking down -Z)
  732. myGlMultMatrix( viewerMatrix, s_flipMatrix, world->modelViewMatrix );
  733. }
  734. /*
  735. ===============
  736. R_SetupProjection
  737. This uses the "infinite far z" trick
  738. ===============
  739. */
  740. void R_SetupProjection( void ) {
  741. float xmin, xmax, ymin, ymax;
  742. float width, height;
  743. float zNear;
  744. float jitterx, jittery;
  745. static idRandom random;
  746. // random jittering is usefull when multiple
  747. // frames are going to be blended together
  748. // for motion blurred anti-aliasing
  749. if ( r_jitter.GetBool() ) {
  750. jitterx = random.RandomFloat();
  751. jittery = random.RandomFloat();
  752. } else {
  753. jitterx = jittery = 0;
  754. }
  755. //
  756. // set up projection matrix
  757. //
  758. zNear = r_znear.GetFloat();
  759. if ( tr.viewDef->renderView.cramZNear ) {
  760. zNear *= 0.25;
  761. }
  762. ymax = zNear * tan( tr.viewDef->renderView.fov_y * idMath::PI / 360.0f );
  763. ymin = -ymax;
  764. xmax = zNear * tan( tr.viewDef->renderView.fov_x * idMath::PI / 360.0f );
  765. xmin = -xmax;
  766. width = xmax - xmin;
  767. height = ymax - ymin;
  768. jitterx = jitterx * width / ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 + 1 );
  769. xmin += jitterx;
  770. xmax += jitterx;
  771. jittery = jittery * height / ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 + 1 );
  772. ymin += jittery;
  773. ymax += jittery;
  774. tr.viewDef->projectionMatrix[0] = 2 * zNear / width;
  775. tr.viewDef->projectionMatrix[4] = 0;
  776. tr.viewDef->projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0
  777. tr.viewDef->projectionMatrix[12] = 0;
  778. tr.viewDef->projectionMatrix[1] = 0;
  779. tr.viewDef->projectionMatrix[5] = 2 * zNear / height;
  780. tr.viewDef->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
  781. tr.viewDef->projectionMatrix[13] = 0;
  782. // this is the far-plane-at-infinity formulation, and
  783. // crunches the Z range slightly so w=0 vertexes do not
  784. // rasterize right at the wraparound point
  785. tr.viewDef->projectionMatrix[2] = 0;
  786. tr.viewDef->projectionMatrix[6] = 0;
  787. tr.viewDef->projectionMatrix[10] = -0.999f;
  788. tr.viewDef->projectionMatrix[14] = -2.0f * zNear;
  789. tr.viewDef->projectionMatrix[3] = 0;
  790. tr.viewDef->projectionMatrix[7] = 0;
  791. tr.viewDef->projectionMatrix[11] = -1;
  792. tr.viewDef->projectionMatrix[15] = 0;
  793. }
  794. /*
  795. =================
  796. R_SetupViewFrustum
  797. Setup that culling frustum planes for the current view
  798. FIXME: derive from modelview matrix times projection matrix
  799. =================
  800. */
  801. static void R_SetupViewFrustum( void ) {
  802. int i;
  803. float xs, xc;
  804. float ang;
  805. ang = DEG2RAD( tr.viewDef->renderView.fov_x ) * 0.5f;
  806. idMath::SinCos( ang, xs, xc );
  807. tr.viewDef->frustum[0] = xs * tr.viewDef->renderView.viewaxis[0] + xc * tr.viewDef->renderView.viewaxis[1];
  808. tr.viewDef->frustum[1] = xs * tr.viewDef->renderView.viewaxis[0] - xc * tr.viewDef->renderView.viewaxis[1];
  809. ang = DEG2RAD( tr.viewDef->renderView.fov_y ) * 0.5f;
  810. idMath::SinCos( ang, xs, xc );
  811. tr.viewDef->frustum[2] = xs * tr.viewDef->renderView.viewaxis[0] + xc * tr.viewDef->renderView.viewaxis[2];
  812. tr.viewDef->frustum[3] = xs * tr.viewDef->renderView.viewaxis[0] - xc * tr.viewDef->renderView.viewaxis[2];
  813. // plane four is the front clipping plane
  814. tr.viewDef->frustum[4] = /* vec3_origin - */ tr.viewDef->renderView.viewaxis[0];
  815. for ( i = 0; i < 5; i++ ) {
  816. // flip direction so positive side faces out (FIXME: globally unify this)
  817. tr.viewDef->frustum[i] = -tr.viewDef->frustum[i].Normal();
  818. tr.viewDef->frustum[i][3] = -( tr.viewDef->renderView.vieworg * tr.viewDef->frustum[i].Normal() );
  819. }
  820. // eventually, plane five will be the rear clipping plane for fog
  821. float dNear, dFar, dLeft, dUp;
  822. dNear = r_znear.GetFloat();
  823. if ( tr.viewDef->renderView.cramZNear ) {
  824. dNear *= 0.25f;
  825. }
  826. dFar = MAX_WORLD_SIZE;
  827. dLeft = dFar * tan( DEG2RAD( tr.viewDef->renderView.fov_x * 0.5f ) );
  828. dUp = dFar * tan( DEG2RAD( tr.viewDef->renderView.fov_y * 0.5f ) );
  829. tr.viewDef->viewFrustum.SetOrigin( tr.viewDef->renderView.vieworg );
  830. tr.viewDef->viewFrustum.SetAxis( tr.viewDef->renderView.viewaxis );
  831. tr.viewDef->viewFrustum.SetSize( dNear, dFar, dLeft, dUp );
  832. }
  833. /*
  834. ===================
  835. R_ConstrainViewFrustum
  836. ===================
  837. */
  838. static void R_ConstrainViewFrustum( void ) {
  839. idBounds bounds;
  840. // constrain the view frustum to the total bounds of all visible lights and visible entities
  841. bounds.Clear();
  842. for ( viewLight_t *vLight = tr.viewDef->viewLights; vLight; vLight = vLight->next ) {
  843. bounds.AddBounds( vLight->lightDef->frustumTris->bounds );
  844. }
  845. for ( viewEntity_t *vEntity = tr.viewDef->viewEntitys; vEntity; vEntity = vEntity->next ) {
  846. bounds.AddBounds( vEntity->entityDef->referenceBounds );
  847. }
  848. tr.viewDef->viewFrustum.ConstrainToBounds( bounds );
  849. if ( r_useFrustumFarDistance.GetFloat() > 0.0f ) {
  850. tr.viewDef->viewFrustum.MoveFarDistance( r_useFrustumFarDistance.GetFloat() );
  851. }
  852. }
  853. /*
  854. ==========================================================================================
  855. DRAWSURF SORTING
  856. ==========================================================================================
  857. */
  858. /*
  859. =======================
  860. R_QsortSurfaces
  861. =======================
  862. */
  863. static int R_QsortSurfaces( const void *a, const void *b ) {
  864. const drawSurf_t *ea, *eb;
  865. ea = *(drawSurf_t **)a;
  866. eb = *(drawSurf_t **)b;
  867. if ( ea->sort < eb->sort ) {
  868. return -1;
  869. }
  870. if ( ea->sort > eb->sort ) {
  871. return 1;
  872. }
  873. return 0;
  874. }
  875. /*
  876. =================
  877. R_SortDrawSurfs
  878. =================
  879. */
  880. static void R_SortDrawSurfs( void ) {
  881. // sort the drawsurfs by sort type, then orientation, then shader
  882. qsort( tr.viewDef->drawSurfs, tr.viewDef->numDrawSurfs, sizeof( tr.viewDef->drawSurfs[0] ),
  883. R_QsortSurfaces );
  884. }
  885. //========================================================================
  886. //==============================================================================
  887. /*
  888. ================
  889. R_RenderView
  890. A view may be either the actual camera view,
  891. a mirror / remote location, or a 3D view on a gui surface.
  892. Parms will typically be allocated with R_FrameAlloc
  893. ================
  894. */
  895. void R_RenderView( viewDef_t *parms ) {
  896. viewDef_t *oldView;
  897. if ( parms->renderView.width <= 0 || parms->renderView.height <= 0 ) {
  898. return;
  899. }
  900. tr.viewCount++;
  901. // save view in case we are a subview
  902. oldView = tr.viewDef;
  903. tr.viewDef = parms;
  904. tr.sortOffset = 0;
  905. // set the matrix for world space to eye space
  906. R_SetViewMatrix( tr.viewDef );
  907. // the four sides of the view frustum are needed
  908. // for culling and portal visibility
  909. R_SetupViewFrustum();
  910. // we need to set the projection matrix before doing
  911. // portal-to-screen scissor box calculations
  912. R_SetupProjection();
  913. // identify all the visible portalAreas, and the entityDefs and
  914. // lightDefs that are in them and pass culling.
  915. static_cast<idRenderWorldLocal *>(parms->renderWorld)->FindViewLightsAndEntities();
  916. // constrain the view frustum to the view lights and entities
  917. R_ConstrainViewFrustum();
  918. // make sure that interactions exist for all light / entity combinations
  919. // that are visible
  920. // add any pre-generated light shadows, and calculate the light shader values
  921. R_AddLightSurfaces();
  922. // adds ambient surfaces and create any necessary interaction surfaces to add to the light
  923. // lists
  924. R_AddModelSurfaces();
  925. // any viewLight that didn't have visible surfaces can have it's shadows removed
  926. R_RemoveUnecessaryViewLights();
  927. // sort all the ambient surfaces for translucency ordering
  928. R_SortDrawSurfs();
  929. // generate any subviews (mirrors, cameras, etc) before adding this view
  930. if ( R_GenerateSubViews() ) {
  931. // if we are debugging subviews, allow the skipping of the
  932. // main view draw
  933. if ( r_subviewOnly.GetBool() ) {
  934. return;
  935. }
  936. }
  937. // write everything needed to the demo file
  938. if ( session->writeDemo ) {
  939. static_cast<idRenderWorldLocal *>(parms->renderWorld)->WriteVisibleDefs( tr.viewDef );
  940. }
  941. // add the rendering commands for this viewDef
  942. R_AddDrawViewCmd( parms );
  943. // restore view in case we are a subview
  944. tr.viewDef = oldView;
  945. }