123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "tr_local.h"
- #ifdef __ppc__
- #include <vecLib/vecLib.h>
- #endif
- #if defined(MACOS_X) && defined(__i386__)
- #include <xmmintrin.h>
- #endif
- //====================================================================
- /*
- ======================
- idScreenRect::Clear
- ======================
- */
- void idScreenRect::Clear() {
- x1 = y1 = 32000;
- x2 = y2 = -32000;
- zmin = 0.0f; zmax = 1.0f;
- }
- /*
- ======================
- idScreenRect::AddPoint
- ======================
- */
- void idScreenRect::AddPoint( float x, float y ) {
- int ix = idMath::FtoiFast( x );
- int iy = idMath::FtoiFast( y );
- if ( ix < x1 ) {
- x1 = ix;
- }
- if ( ix > x2 ) {
- x2 = ix;
- }
- if ( iy < y1 ) {
- y1 = iy;
- }
- if ( iy > y2 ) {
- y2 = iy;
- }
- }
- /*
- ======================
- idScreenRect::Expand
- ======================
- */
- void idScreenRect::Expand() {
- x1--;
- y1--;
- x2++;
- y2++;
- }
- /*
- ======================
- idScreenRect::Intersect
- ======================
- */
- void idScreenRect::Intersect( const idScreenRect &rect ) {
- if ( rect.x1 > x1 ) {
- x1 = rect.x1;
- }
- if ( rect.x2 < x2 ) {
- x2 = rect.x2;
- }
- if ( rect.y1 > y1 ) {
- y1 = rect.y1;
- }
- if ( rect.y2 < y2 ) {
- y2 = rect.y2;
- }
- }
- /*
- ======================
- idScreenRect::Union
- ======================
- */
- void idScreenRect::Union( const idScreenRect &rect ) {
- if ( rect.x1 < x1 ) {
- x1 = rect.x1;
- }
- if ( rect.x2 > x2 ) {
- x2 = rect.x2;
- }
- if ( rect.y1 < y1 ) {
- y1 = rect.y1;
- }
- if ( rect.y2 > y2 ) {
- y2 = rect.y2;
- }
- }
- /*
- ======================
- idScreenRect::Equals
- ======================
- */
- bool idScreenRect::Equals( const idScreenRect &rect ) const {
- return ( x1 == rect.x1 && x2 == rect.x2 && y1 == rect.y1 && y2 == rect.y2 );
- }
- /*
- ======================
- idScreenRect::IsEmpty
- ======================
- */
- bool idScreenRect::IsEmpty() const {
- return ( x1 > x2 || y1 > y2 );
- }
- /*
- ======================
- R_ScreenRectFromViewFrustumBounds
- ======================
- */
- idScreenRect R_ScreenRectFromViewFrustumBounds( const idBounds &bounds ) {
- idScreenRect screenRect;
- screenRect.x1 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[1].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) );
- screenRect.x2 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[0].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) );
- screenRect.y1 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[0].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) );
- screenRect.y2 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[1].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) );
- if ( r_useDepthBoundsTest.GetInteger() ) {
- R_TransformEyeZToWin( -bounds[0].x, tr.viewDef->projectionMatrix, screenRect.zmin );
- R_TransformEyeZToWin( -bounds[1].x, tr.viewDef->projectionMatrix, screenRect.zmax );
- }
- return screenRect;
- }
- /*
- ======================
- R_ShowColoredScreenRect
- ======================
- */
- void R_ShowColoredScreenRect( const idScreenRect &rect, int colorIndex ) {
- if ( !rect.IsEmpty() ) {
- static idVec4 colors[] = { colorRed, colorGreen, colorBlue, colorYellow, colorMagenta, colorCyan, colorWhite, colorPurple };
- tr.viewDef->renderWorld->DebugScreenRect( colors[colorIndex & 7], rect, tr.viewDef );
- }
- }
- /*
- ====================
- R_ToggleSmpFrame
- ====================
- */
- void R_ToggleSmpFrame( void ) {
- if ( r_lockSurfaces.GetBool() ) {
- return;
- }
- R_FreeDeferredTriSurfs( frameData );
- // clear frame-temporary data
- frameData_t *frame;
- frameMemoryBlock_t *block;
- // update the highwater mark
- R_CountFrameData();
- frame = frameData;
- // reset the memory allocation to the first block
- frame->alloc = frame->memory;
- // clear all the blocks
- for ( block = frame->memory ; block ; block = block->next ) {
- block->used = 0;
- }
- R_ClearCommandChain();
- }
- //=====================================================
- #define MEMORY_BLOCK_SIZE 0x100000
- /*
- =====================
- R_ShutdownFrameData
- =====================
- */
- void R_ShutdownFrameData( void ) {
- frameData_t *frame;
- frameMemoryBlock_t *block;
- // free any current data
- frame = frameData;
- if ( !frame ) {
- return;
- }
- R_FreeDeferredTriSurfs( frame );
- frameMemoryBlock_t *nextBlock;
- for ( block = frame->memory ; block ; block = nextBlock ) {
- nextBlock = block->next;
- Mem_Free( block );
- }
- Mem_Free( frame );
- frameData = NULL;
- }
- /*
- =====================
- R_InitFrameData
- =====================
- */
- void R_InitFrameData( void ) {
- int size;
- frameData_t *frame;
- frameMemoryBlock_t *block;
- R_ShutdownFrameData();
- frameData = (frameData_t *)Mem_ClearedAlloc( sizeof( *frameData ));
- frame = frameData;
- size = MEMORY_BLOCK_SIZE;
- block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) );
- if ( !block ) {
- common->FatalError( "R_InitFrameData: Mem_Alloc() failed" );
- }
- block->size = size;
- block->used = 0;
- block->next = NULL;
- frame->memory = block;
- frame->memoryHighwater = 0;
- R_ToggleSmpFrame();
- }
- /*
- ================
- R_CountFrameData
- ================
- */
- int R_CountFrameData( void ) {
- frameData_t *frame;
- frameMemoryBlock_t *block;
- int count;
- count = 0;
- frame = frameData;
- for ( block = frame->memory ; block ; block=block->next ) {
- count += block->used;
- if ( block == frame->alloc ) {
- break;
- }
- }
- // note if this is a new highwater mark
- if ( count > frame->memoryHighwater ) {
- frame->memoryHighwater = count;
- }
- return count;
- }
- /*
- =================
- R_StaticAlloc
- =================
- */
- void *R_StaticAlloc( int bytes ) {
- void *buf;
- tr.pc.c_alloc++;
- tr.staticAllocCount += bytes;
- buf = Mem_Alloc( bytes );
- // don't exit on failure on zero length allocations since the old code didn't
- if ( !buf && ( bytes != 0 ) ) {
- common->FatalError( "R_StaticAlloc failed on %i bytes", bytes );
- }
- return buf;
- }
- /*
- =================
- R_ClearedStaticAlloc
- =================
- */
- void *R_ClearedStaticAlloc( int bytes ) {
- void *buf;
- buf = R_StaticAlloc( bytes );
- SIMDProcessor->Memset( buf, 0, bytes );
- return buf;
- }
- /*
- =================
- R_StaticFree
- =================
- */
- void R_StaticFree( void *data ) {
- tr.pc.c_free++;
- Mem_Free( data );
- }
- /*
- ================
- R_FrameAlloc
- This data will be automatically freed when the
- current frame's back end completes.
- This should only be called by the front end. The
- back end shouldn't need to allocate memory.
- If we passed smpFrame in, the back end could
- alloc memory, because it will always be a
- different frameData than the front end is using.
- All temporary data, like dynamic tesselations
- and local spaces are allocated here.
- The memory will not move, but it may not be
- contiguous with previous allocations even
- from this frame.
- The memory is NOT zero filled.
- Should part of this be inlined in a macro?
- ================
- */
- void *R_FrameAlloc( int bytes ) {
- frameData_t *frame;
- frameMemoryBlock_t *block;
- void *buf;
-
- bytes = (bytes+16)&~15;
- // see if it can be satisfied in the current block
- frame = frameData;
- block = frame->alloc;
- if ( block->size - block->used >= bytes ) {
- buf = block->base + block->used;
- block->used += bytes;
- return buf;
- }
- // advance to the next memory block if available
- block = block->next;
- // create a new block if we are at the end of
- // the chain
- if ( !block ) {
- int size;
- size = MEMORY_BLOCK_SIZE;
- block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) );
- if ( !block ) {
- common->FatalError( "R_FrameAlloc: Mem_Alloc() failed" );
- }
- block->size = size;
- block->used = 0;
- block->next = NULL;
- frame->alloc->next = block;
- }
- // we could fix this if we needed to...
- if ( bytes > block->size ) {
- common->FatalError( "R_FrameAlloc of %i exceeded MEMORY_BLOCK_SIZE",
- bytes );
- }
- frame->alloc = block;
- block->used = bytes;
- return block->base;
- }
- /*
- ==================
- R_ClearedFrameAlloc
- ==================
- */
- void *R_ClearedFrameAlloc( int bytes ) {
- void *r;
- r = R_FrameAlloc( bytes );
- SIMDProcessor->Memset( r, 0, bytes );
- return r;
- }
- /*
- ==================
- R_FrameFree
- This does nothing at all, as the frame data is reused every frame
- and can only be stack allocated.
- The only reason for it's existance is so functions that can
- use either static or frame memory can set function pointers
- to both alloc and free.
- ==================
- */
- void R_FrameFree( void *data ) {
- }
- //==========================================================================
- void R_AxisToModelMatrix( const idMat3 &axis, const idVec3 &origin, float modelMatrix[16] ) {
- modelMatrix[0] = axis[0][0];
- modelMatrix[4] = axis[1][0];
- modelMatrix[8] = axis[2][0];
- modelMatrix[12] = origin[0];
- modelMatrix[1] = axis[0][1];
- modelMatrix[5] = axis[1][1];
- modelMatrix[9] = axis[2][1];
- modelMatrix[13] = origin[1];
- modelMatrix[2] = axis[0][2];
- modelMatrix[6] = axis[1][2];
- modelMatrix[10] = axis[2][2];
- modelMatrix[14] = origin[2];
- modelMatrix[3] = 0;
- modelMatrix[7] = 0;
- modelMatrix[11] = 0;
- modelMatrix[15] = 1;
- }
- // FIXME: these assume no skewing or scaling transforms
- void R_LocalPointToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
- #if defined(MACOS_X) && defined(__i386__)
- __m128 m0, m1, m2, m3;
- __m128 in0, in1, in2;
- float i0,i1,i2;
- i0 = in[0];
- i1 = in[1];
- i2 = in[2];
-
- m0 = _mm_loadu_ps(&modelMatrix[0]);
- m1 = _mm_loadu_ps(&modelMatrix[4]);
- m2 = _mm_loadu_ps(&modelMatrix[8]);
- m3 = _mm_loadu_ps(&modelMatrix[12]);
-
- in0 = _mm_load1_ps(&i0);
- in1 = _mm_load1_ps(&i1);
- in2 = _mm_load1_ps(&i2);
-
- m0 = _mm_mul_ps(m0, in0);
- m1 = _mm_mul_ps(m1, in1);
- m2 = _mm_mul_ps(m2, in2);
- m0 = _mm_add_ps(m0, m1);
- m0 = _mm_add_ps(m0, m2);
- m0 = _mm_add_ps(m0, m3);
-
- _mm_store_ss(&out[0], m0);
- m1 = (__m128) _mm_shuffle_epi32((__m128i)m0, 0x55);
- _mm_store_ss(&out[1], m1);
- m2 = _mm_movehl_ps(m2, m0);
- _mm_store_ss(&out[2], m2);
- #else
- out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4]
- + in[2] * modelMatrix[8] + modelMatrix[12];
- out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5]
- + in[2] * modelMatrix[9] + modelMatrix[13];
- out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6]
- + in[2] * modelMatrix[10] + modelMatrix[14];
- #endif
- }
- void R_PointTimesMatrix( const float modelMatrix[16], const idVec4 &in, idVec4 &out ) {
- out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4]
- + in[2] * modelMatrix[8] + modelMatrix[12];
- out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5]
- + in[2] * modelMatrix[9] + modelMatrix[13];
- out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6]
- + in[2] * modelMatrix[10] + modelMatrix[14];
- out[3] = in[0] * modelMatrix[3] + in[1] * modelMatrix[7]
- + in[2] * modelMatrix[11] + modelMatrix[15];
- }
- void R_GlobalPointToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
- idVec3 temp;
- VectorSubtract( in, &modelMatrix[12], temp );
- out[0] = DotProduct( temp, &modelMatrix[0] );
- out[1] = DotProduct( temp, &modelMatrix[4] );
- out[2] = DotProduct( temp, &modelMatrix[8] );
- }
- void R_LocalVectorToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
- out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4]
- + in[2] * modelMatrix[8];
- out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5]
- + in[2] * modelMatrix[9];
- out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6]
- + in[2] * modelMatrix[10];
- }
- void R_GlobalVectorToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
- out[0] = DotProduct( in, &modelMatrix[0] );
- out[1] = DotProduct( in, &modelMatrix[4] );
- out[2] = DotProduct( in, &modelMatrix[8] );
- }
- void R_GlobalPlaneToLocal( const float modelMatrix[16], const idPlane &in, idPlane &out ) {
- out[0] = DotProduct( in, &modelMatrix[0] );
- out[1] = DotProduct( in, &modelMatrix[4] );
- out[2] = DotProduct( in, &modelMatrix[8] );
- out[3] = in[3] + modelMatrix[12] * in[0] + modelMatrix[13] * in[1] + modelMatrix[14] * in[2];
- }
- void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane &in, idPlane &out ) {
- float offset;
- R_LocalVectorToGlobal( modelMatrix, in.Normal(), out.Normal() );
- offset = modelMatrix[12] * out[0] + modelMatrix[13] * out[1] + modelMatrix[14] * out[2];
- out[3] = in[3] - offset;
- }
- // transform Z in eye coordinates to window coordinates
- void R_TransformEyeZToWin( float src_z, const float *projectionMatrix, float &dst_z ) {
- float clip_z, clip_w;
- // projection
- clip_z = src_z * projectionMatrix[ 2 + 2 * 4 ] + projectionMatrix[ 2 + 3 * 4 ];
- clip_w = src_z * projectionMatrix[ 3 + 2 * 4 ] + projectionMatrix[ 3 + 3 * 4 ];
- if ( clip_w <= 0.0f ) {
- dst_z = 0.0f; // clamp to near plane
- } else {
- dst_z = clip_z / clip_w;
- dst_z = dst_z * 0.5f + 0.5f; // convert to window coords
- }
- }
- /*
- =================
- R_RadiusCullLocalBox
- A fast, conservative center-to-corner culling test
- Returns true if the box is outside the given global frustum, (positive sides are out)
- =================
- */
- bool R_RadiusCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
- int i;
- float d;
- idVec3 worldOrigin;
- float worldRadius;
- const idPlane *frust;
- if ( r_useCulling.GetInteger() == 0 ) {
- return false;
- }
- // transform the surface bounds into world space
- idVec3 localOrigin = ( bounds[0] + bounds[1] ) * 0.5;
- R_LocalPointToGlobal( modelMatrix, localOrigin, worldOrigin );
- worldRadius = (bounds[0] - localOrigin).Length(); // FIXME: won't be correct for scaled objects
- for ( i = 0 ; i < numPlanes ; i++ ) {
- frust = planes + i;
- d = frust->Distance( worldOrigin );
- if ( d > worldRadius ) {
- return true; // culled
- }
- }
- return false; // no culled
- }
- /*
- =================
- R_CornerCullLocalBox
- Tests all corners against the frustum.
- Can still generate a few false positives when the box is outside a corner.
- Returns true if the box is outside the given global frustum, (positive sides are out)
- =================
- */
- bool R_CornerCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
- int i, j;
- idVec3 transformed[8];
- float dists[8];
- idVec3 v;
- const idPlane *frust;
- // we can disable box culling for experimental timing purposes
- if ( r_useCulling.GetInteger() < 2 ) {
- return false;
- }
- // transform into world space
- for ( i = 0 ; i < 8 ; i++ ) {
- v[0] = bounds[i&1][0];
- v[1] = bounds[(i>>1)&1][1];
- v[2] = bounds[(i>>2)&1][2];
- R_LocalPointToGlobal( modelMatrix, v, transformed[i] );
- }
- // check against frustum planes
- for ( i = 0 ; i < numPlanes ; i++ ) {
- frust = planes + i;
- for ( j = 0 ; j < 8 ; j++ ) {
- dists[j] = frust->Distance( transformed[j] );
- if ( dists[j] < 0 ) {
- break;
- }
- }
- if ( j == 8 ) {
- // all points were behind one of the planes
- tr.pc.c_box_cull_out++;
- return true;
- }
- }
- tr.pc.c_box_cull_in++;
- return false; // not culled
- }
- /*
- =================
- R_CullLocalBox
- Performs quick test before expensive test
- Returns true if the box is outside the given global frustum, (positive sides are out)
- =================
- */
- bool R_CullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
- if ( R_RadiusCullLocalBox( bounds, modelMatrix, numPlanes, planes ) ) {
- return true;
- }
- return R_CornerCullLocalBox( bounds, modelMatrix, numPlanes, planes );
- }
- /*
- ==========================
- R_TransformModelToClip
- ==========================
- */
- void R_TransformModelToClip( const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst ) {
- int i;
- for ( i = 0 ; i < 4 ; i++ ) {
- eye[i] =
- src[0] * modelMatrix[ i + 0 * 4 ] +
- src[1] * modelMatrix[ i + 1 * 4 ] +
- src[2] * modelMatrix[ i + 2 * 4 ] +
- 1 * modelMatrix[ i + 3 * 4 ];
- }
- for ( i = 0 ; i < 4 ; i++ ) {
- dst[i] =
- eye[0] * projectionMatrix[ i + 0 * 4 ] +
- eye[1] * projectionMatrix[ i + 1 * 4 ] +
- eye[2] * projectionMatrix[ i + 2 * 4 ] +
- eye[3] * projectionMatrix[ i + 3 * 4 ];
- }
- }
- /*
- ==========================
- R_GlobalToNormalizedDeviceCoordinates
- -1 to 1 range in x, y, and z
- ==========================
- */
- void R_GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ) {
- int i;
- idPlane view;
- idPlane clip;
- // _D3XP added work on primaryView when no viewDef
- if ( !tr.viewDef ) {
- for ( i = 0 ; i < 4 ; i ++ ) {
- view[i] =
- global[0] * tr.primaryView->worldSpace.modelViewMatrix[ i + 0 * 4 ] +
- global[1] * tr.primaryView->worldSpace.modelViewMatrix[ i + 1 * 4 ] +
- global[2] * tr.primaryView->worldSpace.modelViewMatrix[ i + 2 * 4 ] +
- tr.primaryView->worldSpace.modelViewMatrix[ i + 3 * 4 ];
- }
- for ( i = 0 ; i < 4 ; i ++ ) {
- clip[i] =
- view[0] * tr.primaryView->projectionMatrix[ i + 0 * 4 ] +
- view[1] * tr.primaryView->projectionMatrix[ i + 1 * 4 ] +
- view[2] * tr.primaryView->projectionMatrix[ i + 2 * 4 ] +
- view[3] * tr.primaryView->projectionMatrix[ i + 3 * 4 ];
- }
- } else {
- for ( i = 0 ; i < 4 ; i ++ ) {
- view[i] =
- global[0] * tr.viewDef->worldSpace.modelViewMatrix[ i + 0 * 4 ] +
- global[1] * tr.viewDef->worldSpace.modelViewMatrix[ i + 1 * 4 ] +
- global[2] * tr.viewDef->worldSpace.modelViewMatrix[ i + 2 * 4 ] +
- tr.viewDef->worldSpace.modelViewMatrix[ i + 3 * 4 ];
- }
- for ( i = 0 ; i < 4 ; i ++ ) {
- clip[i] =
- view[0] * tr.viewDef->projectionMatrix[ i + 0 * 4 ] +
- view[1] * tr.viewDef->projectionMatrix[ i + 1 * 4 ] +
- view[2] * tr.viewDef->projectionMatrix[ i + 2 * 4 ] +
- view[3] * tr.viewDef->projectionMatrix[ i + 3 * 4 ];
- }
- }
- ndc[0] = clip[0] / clip[3];
- ndc[1] = clip[1] / clip[3];
- ndc[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
- }
- /*
- ==========================
- R_TransformClipToDevice
- Clip to normalized device coordinates
- ==========================
- */
- void R_TransformClipToDevice( const idPlane &clip, const viewDef_t *view, idVec3 &normalized ) {
- normalized[0] = clip[0] / clip[3];
- normalized[1] = clip[1] / clip[3];
- normalized[2] = clip[2] / clip[3];
- }
- /*
- ==========================
- myGlMultMatrix
- ==========================
- */
- void myGlMultMatrix( const float a[16], const float b[16], float out[16] ) {
- #if 0
- int i, j;
- for ( i = 0 ; i < 4 ; i++ ) {
- for ( j = 0 ; j < 4 ; j++ ) {
- out[ i * 4 + j ] =
- a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
- + a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
- + a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
- + a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
- }
- }
- #else
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- 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];
- #endif
- }
- /*
- ================
- R_TransposeGLMatrix
- ================
- */
- void R_TransposeGLMatrix( const float in[16], float out[16] ) {
- int i, j;
- for ( i = 0 ; i < 4 ; i++ ) {
- for ( j = 0 ; j < 4 ; j++ ) {
- out[i*4+j] = in[j*4+i];
- }
- }
- }
- /*
- =================
- R_SetViewMatrix
- Sets up the world to view matrix for a given viewParm
- =================
- */
- void R_SetViewMatrix( viewDef_t *viewDef ) {
- idVec3 origin;
- viewEntity_t *world;
- float viewerMatrix[16];
- static float s_flipMatrix[16] = {
- // convert from our coordinate system (looking down X)
- // to OpenGL's coordinate system (looking down -Z)
- 0, 0, -1, 0,
- -1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 0, 1
- };
- world = &viewDef->worldSpace;
- memset( world, 0, sizeof(*world) );
- // the model matrix is an identity
- world->modelMatrix[0*4+0] = 1;
- world->modelMatrix[1*4+1] = 1;
- world->modelMatrix[2*4+2] = 1;
- // transform by the camera placement
- origin = viewDef->renderView.vieworg;
- viewerMatrix[0] = viewDef->renderView.viewaxis[0][0];
- viewerMatrix[4] = viewDef->renderView.viewaxis[0][1];
- viewerMatrix[8] = viewDef->renderView.viewaxis[0][2];
- viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
- viewerMatrix[1] = viewDef->renderView.viewaxis[1][0];
- viewerMatrix[5] = viewDef->renderView.viewaxis[1][1];
- viewerMatrix[9] = viewDef->renderView.viewaxis[1][2];
- viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
- viewerMatrix[2] = viewDef->renderView.viewaxis[2][0];
- viewerMatrix[6] = viewDef->renderView.viewaxis[2][1];
- viewerMatrix[10] = viewDef->renderView.viewaxis[2][2];
- viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
- viewerMatrix[3] = 0;
- viewerMatrix[7] = 0;
- viewerMatrix[11] = 0;
- viewerMatrix[15] = 1;
- // convert from our coordinate system (looking down X)
- // to OpenGL's coordinate system (looking down -Z)
- myGlMultMatrix( viewerMatrix, s_flipMatrix, world->modelViewMatrix );
- }
- /*
- ===============
- R_SetupProjection
- This uses the "infinite far z" trick
- ===============
- */
- void R_SetupProjection( void ) {
- float xmin, xmax, ymin, ymax;
- float width, height;
- float zNear;
- float jitterx, jittery;
- static idRandom random;
- // random jittering is usefull when multiple
- // frames are going to be blended together
- // for motion blurred anti-aliasing
- if ( r_jitter.GetBool() ) {
- jitterx = random.RandomFloat();
- jittery = random.RandomFloat();
- } else {
- jitterx = jittery = 0;
- }
- //
- // set up projection matrix
- //
- zNear = r_znear.GetFloat();
- if ( tr.viewDef->renderView.cramZNear ) {
- zNear *= 0.25;
- }
- ymax = zNear * tan( tr.viewDef->renderView.fov_y * idMath::PI / 360.0f );
- ymin = -ymax;
- xmax = zNear * tan( tr.viewDef->renderView.fov_x * idMath::PI / 360.0f );
- xmin = -xmax;
- width = xmax - xmin;
- height = ymax - ymin;
- jitterx = jitterx * width / ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 + 1 );
- xmin += jitterx;
- xmax += jitterx;
- jittery = jittery * height / ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 + 1 );
- ymin += jittery;
- ymax += jittery;
- tr.viewDef->projectionMatrix[0] = 2 * zNear / width;
- tr.viewDef->projectionMatrix[4] = 0;
- tr.viewDef->projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0
- tr.viewDef->projectionMatrix[12] = 0;
- tr.viewDef->projectionMatrix[1] = 0;
- tr.viewDef->projectionMatrix[5] = 2 * zNear / height;
- tr.viewDef->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
- tr.viewDef->projectionMatrix[13] = 0;
- // this is the far-plane-at-infinity formulation, and
- // crunches the Z range slightly so w=0 vertexes do not
- // rasterize right at the wraparound point
- tr.viewDef->projectionMatrix[2] = 0;
- tr.viewDef->projectionMatrix[6] = 0;
- tr.viewDef->projectionMatrix[10] = -0.999f;
- tr.viewDef->projectionMatrix[14] = -2.0f * zNear;
- tr.viewDef->projectionMatrix[3] = 0;
- tr.viewDef->projectionMatrix[7] = 0;
- tr.viewDef->projectionMatrix[11] = -1;
- tr.viewDef->projectionMatrix[15] = 0;
- }
- /*
- =================
- R_SetupViewFrustum
- Setup that culling frustum planes for the current view
- FIXME: derive from modelview matrix times projection matrix
- =================
- */
- static void R_SetupViewFrustum( void ) {
- int i;
- float xs, xc;
- float ang;
- ang = DEG2RAD( tr.viewDef->renderView.fov_x ) * 0.5f;
- idMath::SinCos( ang, xs, xc );
- tr.viewDef->frustum[0] = xs * tr.viewDef->renderView.viewaxis[0] + xc * tr.viewDef->renderView.viewaxis[1];
- tr.viewDef->frustum[1] = xs * tr.viewDef->renderView.viewaxis[0] - xc * tr.viewDef->renderView.viewaxis[1];
- ang = DEG2RAD( tr.viewDef->renderView.fov_y ) * 0.5f;
- idMath::SinCos( ang, xs, xc );
- tr.viewDef->frustum[2] = xs * tr.viewDef->renderView.viewaxis[0] + xc * tr.viewDef->renderView.viewaxis[2];
- tr.viewDef->frustum[3] = xs * tr.viewDef->renderView.viewaxis[0] - xc * tr.viewDef->renderView.viewaxis[2];
- // plane four is the front clipping plane
- tr.viewDef->frustum[4] = /* vec3_origin - */ tr.viewDef->renderView.viewaxis[0];
- for ( i = 0; i < 5; i++ ) {
- // flip direction so positive side faces out (FIXME: globally unify this)
- tr.viewDef->frustum[i] = -tr.viewDef->frustum[i].Normal();
- tr.viewDef->frustum[i][3] = -( tr.viewDef->renderView.vieworg * tr.viewDef->frustum[i].Normal() );
- }
- // eventually, plane five will be the rear clipping plane for fog
- float dNear, dFar, dLeft, dUp;
- dNear = r_znear.GetFloat();
- if ( tr.viewDef->renderView.cramZNear ) {
- dNear *= 0.25f;
- }
- dFar = MAX_WORLD_SIZE;
- dLeft = dFar * tan( DEG2RAD( tr.viewDef->renderView.fov_x * 0.5f ) );
- dUp = dFar * tan( DEG2RAD( tr.viewDef->renderView.fov_y * 0.5f ) );
- tr.viewDef->viewFrustum.SetOrigin( tr.viewDef->renderView.vieworg );
- tr.viewDef->viewFrustum.SetAxis( tr.viewDef->renderView.viewaxis );
- tr.viewDef->viewFrustum.SetSize( dNear, dFar, dLeft, dUp );
- }
- /*
- ===================
- R_ConstrainViewFrustum
- ===================
- */
- static void R_ConstrainViewFrustum( void ) {
- idBounds bounds;
- // constrain the view frustum to the total bounds of all visible lights and visible entities
- bounds.Clear();
- for ( viewLight_t *vLight = tr.viewDef->viewLights; vLight; vLight = vLight->next ) {
- bounds.AddBounds( vLight->lightDef->frustumTris->bounds );
- }
- for ( viewEntity_t *vEntity = tr.viewDef->viewEntitys; vEntity; vEntity = vEntity->next ) {
- bounds.AddBounds( vEntity->entityDef->referenceBounds );
- }
- tr.viewDef->viewFrustum.ConstrainToBounds( bounds );
- if ( r_useFrustumFarDistance.GetFloat() > 0.0f ) {
- tr.viewDef->viewFrustum.MoveFarDistance( r_useFrustumFarDistance.GetFloat() );
- }
- }
- /*
- ==========================================================================================
- DRAWSURF SORTING
- ==========================================================================================
- */
- /*
- =======================
- R_QsortSurfaces
- =======================
- */
- static int R_QsortSurfaces( const void *a, const void *b ) {
- const drawSurf_t *ea, *eb;
- ea = *(drawSurf_t **)a;
- eb = *(drawSurf_t **)b;
- if ( ea->sort < eb->sort ) {
- return -1;
- }
- if ( ea->sort > eb->sort ) {
- return 1;
- }
- return 0;
- }
- /*
- =================
- R_SortDrawSurfs
- =================
- */
- static void R_SortDrawSurfs( void ) {
- // sort the drawsurfs by sort type, then orientation, then shader
- qsort( tr.viewDef->drawSurfs, tr.viewDef->numDrawSurfs, sizeof( tr.viewDef->drawSurfs[0] ),
- R_QsortSurfaces );
- }
- //========================================================================
- //==============================================================================
- /*
- ================
- R_RenderView
- A view may be either the actual camera view,
- a mirror / remote location, or a 3D view on a gui surface.
- Parms will typically be allocated with R_FrameAlloc
- ================
- */
- void R_RenderView( viewDef_t *parms ) {
- viewDef_t *oldView;
- if ( parms->renderView.width <= 0 || parms->renderView.height <= 0 ) {
- return;
- }
- tr.viewCount++;
- // save view in case we are a subview
- oldView = tr.viewDef;
- tr.viewDef = parms;
- tr.sortOffset = 0;
- // set the matrix for world space to eye space
- R_SetViewMatrix( tr.viewDef );
- // the four sides of the view frustum are needed
- // for culling and portal visibility
- R_SetupViewFrustum();
- // we need to set the projection matrix before doing
- // portal-to-screen scissor box calculations
- R_SetupProjection();
- // identify all the visible portalAreas, and the entityDefs and
- // lightDefs that are in them and pass culling.
- static_cast<idRenderWorldLocal *>(parms->renderWorld)->FindViewLightsAndEntities();
- // constrain the view frustum to the view lights and entities
- R_ConstrainViewFrustum();
- // make sure that interactions exist for all light / entity combinations
- // that are visible
- // add any pre-generated light shadows, and calculate the light shader values
- R_AddLightSurfaces();
- // adds ambient surfaces and create any necessary interaction surfaces to add to the light
- // lists
- R_AddModelSurfaces();
- // any viewLight that didn't have visible surfaces can have it's shadows removed
- R_RemoveUnecessaryViewLights();
- // sort all the ambient surfaces for translucency ordering
- R_SortDrawSurfs();
- // generate any subviews (mirrors, cameras, etc) before adding this view
- if ( R_GenerateSubViews() ) {
- // if we are debugging subviews, allow the skipping of the
- // main view draw
- if ( r_subviewOnly.GetBool() ) {
- return;
- }
- }
- // write everything needed to the demo file
- if ( session->writeDemo ) {
- static_cast<idRenderWorldLocal *>(parms->renderWorld)->WriteVisibleDefs( tr.viewDef );
- }
- // add the rendering commands for this viewDef
- R_AddDrawViewCmd( parms );
- // restore view in case we are a subview
- tr.viewDef = oldView;
- }
|