2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 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.
24 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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
34 #include <vecLib/vecLib.h>
36 #if defined(MACOS_X) && defined(__i386__)
37 #include <xmmintrin.h>
40 //====================================================================
43 ======================
45 ======================
47 void idScreenRect::Clear() {
50 zmin = 0.0f; zmax = 1.0f;
54 ======================
55 idScreenRect::AddPoint
56 ======================
58 void idScreenRect::AddPoint( float x, float y ) {
59 int ix = idMath::FtoiFast( x );
60 int iy = idMath::FtoiFast( y );
77 ======================
79 ======================
81 void idScreenRect::Expand() {
89 ======================
90 idScreenRect::Intersect
91 ======================
93 void idScreenRect::Intersect( const idScreenRect &rect ) {
100 if ( rect.y1 > y1 ) {
103 if ( rect.y2 < y2 ) {
109 ======================
111 ======================
113 void idScreenRect::Union( const idScreenRect &rect ) {
114 if ( rect.x1 < x1 ) {
117 if ( rect.x2 > x2 ) {
120 if ( rect.y1 < y1 ) {
123 if ( rect.y2 > y2 ) {
129 ======================
131 ======================
133 bool idScreenRect::Equals( const idScreenRect &rect ) const {
134 return ( x1 == rect.x1 && x2 == rect.x2 && y1 == rect.y1 && y2 == rect.y2 );
138 ======================
139 idScreenRect::IsEmpty
140 ======================
142 bool idScreenRect::IsEmpty() const {
143 return ( x1 > x2 || y1 > y2 );
147 ======================
148 R_ScreenRectFromViewFrustumBounds
149 ======================
151 idScreenRect R_ScreenRectFromViewFrustumBounds( const idBounds &bounds ) {
152 idScreenRect screenRect;
154 screenRect.x1 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[1].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) );
155 screenRect.x2 = idMath::FtoiFast( 0.5f * ( 1.0f - bounds[0].y ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) );
156 screenRect.y1 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[0].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) );
157 screenRect.y2 = idMath::FtoiFast( 0.5f * ( 1.0f + bounds[1].z ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) );
159 if ( r_useDepthBoundsTest.GetInteger() ) {
160 R_TransformEyeZToWin( -bounds[0].x, tr.viewDef->projectionMatrix, screenRect.zmin );
161 R_TransformEyeZToWin( -bounds[1].x, tr.viewDef->projectionMatrix, screenRect.zmax );
168 ======================
169 R_ShowColoredScreenRect
170 ======================
172 void R_ShowColoredScreenRect( const idScreenRect &rect, int colorIndex ) {
173 if ( !rect.IsEmpty() ) {
174 static idVec4 colors[] = { colorRed, colorGreen, colorBlue, colorYellow, colorMagenta, colorCyan, colorWhite, colorPurple };
175 tr.viewDef->renderWorld->DebugScreenRect( colors[colorIndex & 7], rect, tr.viewDef );
184 void R_ToggleSmpFrame( void ) {
185 if ( r_lockSurfaces.GetBool() ) {
188 R_FreeDeferredTriSurfs( frameData );
190 // clear frame-temporary data
192 frameMemoryBlock_t *block;
194 // update the highwater mark
199 // reset the memory allocation to the first block
200 frame->alloc = frame->memory;
202 // clear all the blocks
203 for ( block = frame->memory ; block ; block = block->next ) {
207 R_ClearCommandChain();
211 //=====================================================
213 #define MEMORY_BLOCK_SIZE 0x100000
216 =====================
218 =====================
220 void R_ShutdownFrameData( void ) {
222 frameMemoryBlock_t *block;
224 // free any current data
230 R_FreeDeferredTriSurfs( frame );
232 frameMemoryBlock_t *nextBlock;
233 for ( block = frame->memory ; block ; block = nextBlock ) {
234 nextBlock = block->next;
242 =====================
244 =====================
246 void R_InitFrameData( void ) {
249 frameMemoryBlock_t *block;
251 R_ShutdownFrameData();
253 frameData = (frameData_t *)Mem_ClearedAlloc( sizeof( *frameData ));
255 size = MEMORY_BLOCK_SIZE;
256 block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) );
258 common->FatalError( "R_InitFrameData: Mem_Alloc() failed" );
263 frame->memory = block;
264 frame->memoryHighwater = 0;
274 int R_CountFrameData( void ) {
276 frameMemoryBlock_t *block;
281 for ( block = frame->memory ; block ; block=block->next ) {
282 count += block->used;
283 if ( block == frame->alloc ) {
288 // note if this is a new highwater mark
289 if ( count > frame->memoryHighwater ) {
290 frame->memoryHighwater = count;
301 void *R_StaticAlloc( int bytes ) {
306 tr.staticAllocCount += bytes;
308 buf = Mem_Alloc( bytes );
310 // don't exit on failure on zero length allocations since the old code didn't
311 if ( !buf && ( bytes != 0 ) ) {
312 common->FatalError( "R_StaticAlloc failed on %i bytes", bytes );
322 void *R_ClearedStaticAlloc( int bytes ) {
325 buf = R_StaticAlloc( bytes );
326 SIMDProcessor->Memset( buf, 0, bytes );
335 void R_StaticFree( void *data ) {
344 This data will be automatically freed when the
345 current frame's back end completes.
347 This should only be called by the front end. The
348 back end shouldn't need to allocate memory.
350 If we passed smpFrame in, the back end could
351 alloc memory, because it will always be a
352 different frameData than the front end is using.
354 All temporary data, like dynamic tesselations
355 and local spaces are allocated here.
357 The memory will not move, but it may not be
358 contiguous with previous allocations even
361 The memory is NOT zero filled.
362 Should part of this be inlined in a macro?
365 void *R_FrameAlloc( int bytes ) {
367 frameMemoryBlock_t *block;
370 bytes = (bytes+16)&~15;
371 // see if it can be satisfied in the current block
373 block = frame->alloc;
375 if ( block->size - block->used >= bytes ) {
376 buf = block->base + block->used;
377 block->used += bytes;
381 // advance to the next memory block if available
383 // create a new block if we are at the end of
388 size = MEMORY_BLOCK_SIZE;
389 block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) );
391 common->FatalError( "R_FrameAlloc: Mem_Alloc() failed" );
396 frame->alloc->next = block;
399 // we could fix this if we needed to...
400 if ( bytes > block->size ) {
401 common->FatalError( "R_FrameAlloc of %i exceeded MEMORY_BLOCK_SIZE",
405 frame->alloc = block;
417 void *R_ClearedFrameAlloc( int bytes ) {
420 r = R_FrameAlloc( bytes );
421 SIMDProcessor->Memset( r, 0, bytes );
430 This does nothing at all, as the frame data is reused every frame
431 and can only be stack allocated.
433 The only reason for it's existance is so functions that can
434 use either static or frame memory can set function pointers
435 to both alloc and free.
438 void R_FrameFree( void *data ) {
443 //==========================================================================
445 void R_AxisToModelMatrix( const idMat3 &axis, const idVec3 &origin, float modelMatrix[16] ) {
446 modelMatrix[0] = axis[0][0];
447 modelMatrix[4] = axis[1][0];
448 modelMatrix[8] = axis[2][0];
449 modelMatrix[12] = origin[0];
451 modelMatrix[1] = axis[0][1];
452 modelMatrix[5] = axis[1][1];
453 modelMatrix[9] = axis[2][1];
454 modelMatrix[13] = origin[1];
456 modelMatrix[2] = axis[0][2];
457 modelMatrix[6] = axis[1][2];
458 modelMatrix[10] = axis[2][2];
459 modelMatrix[14] = origin[2];
468 // FIXME: these assume no skewing or scaling transforms
470 void R_LocalPointToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
471 #if defined(MACOS_X) && defined(__i386__)
472 __m128 m0, m1, m2, m3;
473 __m128 in0, in1, in2;
479 m0 = _mm_loadu_ps(&modelMatrix[0]);
480 m1 = _mm_loadu_ps(&modelMatrix[4]);
481 m2 = _mm_loadu_ps(&modelMatrix[8]);
482 m3 = _mm_loadu_ps(&modelMatrix[12]);
484 in0 = _mm_load1_ps(&i0);
485 in1 = _mm_load1_ps(&i1);
486 in2 = _mm_load1_ps(&i2);
488 m0 = _mm_mul_ps(m0, in0);
489 m1 = _mm_mul_ps(m1, in1);
490 m2 = _mm_mul_ps(m2, in2);
492 m0 = _mm_add_ps(m0, m1);
493 m0 = _mm_add_ps(m0, m2);
494 m0 = _mm_add_ps(m0, m3);
496 _mm_store_ss(&out[0], m0);
497 m1 = (__m128) _mm_shuffle_epi32((__m128i)m0, 0x55);
498 _mm_store_ss(&out[1], m1);
499 m2 = _mm_movehl_ps(m2, m0);
500 _mm_store_ss(&out[2], m2);
502 out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4]
503 + in[2] * modelMatrix[8] + modelMatrix[12];
504 out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5]
505 + in[2] * modelMatrix[9] + modelMatrix[13];
506 out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6]
507 + in[2] * modelMatrix[10] + modelMatrix[14];
511 void R_PointTimesMatrix( const float modelMatrix[16], const idVec4 &in, idVec4 &out ) {
512 out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4]
513 + in[2] * modelMatrix[8] + modelMatrix[12];
514 out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5]
515 + in[2] * modelMatrix[9] + modelMatrix[13];
516 out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6]
517 + in[2] * modelMatrix[10] + modelMatrix[14];
518 out[3] = in[0] * modelMatrix[3] + in[1] * modelMatrix[7]
519 + in[2] * modelMatrix[11] + modelMatrix[15];
522 void R_GlobalPointToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
525 VectorSubtract( in, &modelMatrix[12], temp );
527 out[0] = DotProduct( temp, &modelMatrix[0] );
528 out[1] = DotProduct( temp, &modelMatrix[4] );
529 out[2] = DotProduct( temp, &modelMatrix[8] );
532 void R_LocalVectorToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
533 out[0] = in[0] * modelMatrix[0] + in[1] * modelMatrix[4]
534 + in[2] * modelMatrix[8];
535 out[1] = in[0] * modelMatrix[1] + in[1] * modelMatrix[5]
536 + in[2] * modelMatrix[9];
537 out[2] = in[0] * modelMatrix[2] + in[1] * modelMatrix[6]
538 + in[2] * modelMatrix[10];
541 void R_GlobalVectorToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
542 out[0] = DotProduct( in, &modelMatrix[0] );
543 out[1] = DotProduct( in, &modelMatrix[4] );
544 out[2] = DotProduct( in, &modelMatrix[8] );
547 void R_GlobalPlaneToLocal( const float modelMatrix[16], const idPlane &in, idPlane &out ) {
548 out[0] = DotProduct( in, &modelMatrix[0] );
549 out[1] = DotProduct( in, &modelMatrix[4] );
550 out[2] = DotProduct( in, &modelMatrix[8] );
551 out[3] = in[3] + modelMatrix[12] * in[0] + modelMatrix[13] * in[1] + modelMatrix[14] * in[2];
554 void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane &in, idPlane &out ) {
557 R_LocalVectorToGlobal( modelMatrix, in.Normal(), out.Normal() );
559 offset = modelMatrix[12] * out[0] + modelMatrix[13] * out[1] + modelMatrix[14] * out[2];
560 out[3] = in[3] - offset;
563 // transform Z in eye coordinates to window coordinates
564 void R_TransformEyeZToWin( float src_z, const float *projectionMatrix, float &dst_z ) {
565 float clip_z, clip_w;
568 clip_z = src_z * projectionMatrix[ 2 + 2 * 4 ] + projectionMatrix[ 2 + 3 * 4 ];
569 clip_w = src_z * projectionMatrix[ 3 + 2 * 4 ] + projectionMatrix[ 3 + 3 * 4 ];
571 if ( clip_w <= 0.0f ) {
572 dst_z = 0.0f; // clamp to near plane
574 dst_z = clip_z / clip_w;
575 dst_z = dst_z * 0.5f + 0.5f; // convert to window coords
583 A fast, conservative center-to-corner culling test
584 Returns true if the box is outside the given global frustum, (positive sides are out)
587 bool R_RadiusCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
592 const idPlane *frust;
594 if ( r_useCulling.GetInteger() == 0 ) {
598 // transform the surface bounds into world space
599 idVec3 localOrigin = ( bounds[0] + bounds[1] ) * 0.5;
601 R_LocalPointToGlobal( modelMatrix, localOrigin, worldOrigin );
603 worldRadius = (bounds[0] - localOrigin).Length(); // FIXME: won't be correct for scaled objects
605 for ( i = 0 ; i < numPlanes ; i++ ) {
607 d = frust->Distance( worldOrigin );
608 if ( d > worldRadius ) {
609 return true; // culled
613 return false; // no culled
620 Tests all corners against the frustum.
621 Can still generate a few false positives when the box is outside a corner.
622 Returns true if the box is outside the given global frustum, (positive sides are out)
625 bool R_CornerCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
627 idVec3 transformed[8];
630 const idPlane *frust;
632 // we can disable box culling for experimental timing purposes
633 if ( r_useCulling.GetInteger() < 2 ) {
637 // transform into world space
638 for ( i = 0 ; i < 8 ; i++ ) {
639 v[0] = bounds[i&1][0];
640 v[1] = bounds[(i>>1)&1][1];
641 v[2] = bounds[(i>>2)&1][2];
643 R_LocalPointToGlobal( modelMatrix, v, transformed[i] );
646 // check against frustum planes
647 for ( i = 0 ; i < numPlanes ; i++ ) {
649 for ( j = 0 ; j < 8 ; j++ ) {
650 dists[j] = frust->Distance( transformed[j] );
651 if ( dists[j] < 0 ) {
656 // all points were behind one of the planes
657 tr.pc.c_box_cull_out++;
662 tr.pc.c_box_cull_in++;
664 return false; // not culled
671 Performs quick test before expensive test
672 Returns true if the box is outside the given global frustum, (positive sides are out)
675 bool R_CullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
676 if ( R_RadiusCullLocalBox( bounds, modelMatrix, numPlanes, planes ) ) {
679 return R_CornerCullLocalBox( bounds, modelMatrix, numPlanes, planes );
683 ==========================
684 R_TransformModelToClip
685 ==========================
687 void R_TransformModelToClip( const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst ) {
690 for ( i = 0 ; i < 4 ; i++ ) {
692 src[0] * modelMatrix[ i + 0 * 4 ] +
693 src[1] * modelMatrix[ i + 1 * 4 ] +
694 src[2] * modelMatrix[ i + 2 * 4 ] +
695 1 * modelMatrix[ i + 3 * 4 ];
698 for ( i = 0 ; i < 4 ; i++ ) {
700 eye[0] * projectionMatrix[ i + 0 * 4 ] +
701 eye[1] * projectionMatrix[ i + 1 * 4 ] +
702 eye[2] * projectionMatrix[ i + 2 * 4 ] +
703 eye[3] * projectionMatrix[ i + 3 * 4 ];
708 ==========================
709 R_GlobalToNormalizedDeviceCoordinates
711 -1 to 1 range in x, y, and z
712 ==========================
714 void R_GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ) {
719 // _D3XP added work on primaryView when no viewDef
722 for ( i = 0 ; i < 4 ; i ++ ) {
724 global[0] * tr.primaryView->worldSpace.modelViewMatrix[ i + 0 * 4 ] +
725 global[1] * tr.primaryView->worldSpace.modelViewMatrix[ i + 1 * 4 ] +
726 global[2] * tr.primaryView->worldSpace.modelViewMatrix[ i + 2 * 4 ] +
727 tr.primaryView->worldSpace.modelViewMatrix[ i + 3 * 4 ];
730 for ( i = 0 ; i < 4 ; i ++ ) {
732 view[0] * tr.primaryView->projectionMatrix[ i + 0 * 4 ] +
733 view[1] * tr.primaryView->projectionMatrix[ i + 1 * 4 ] +
734 view[2] * tr.primaryView->projectionMatrix[ i + 2 * 4 ] +
735 view[3] * tr.primaryView->projectionMatrix[ i + 3 * 4 ];
740 for ( i = 0 ; i < 4 ; i ++ ) {
742 global[0] * tr.viewDef->worldSpace.modelViewMatrix[ i + 0 * 4 ] +
743 global[1] * tr.viewDef->worldSpace.modelViewMatrix[ i + 1 * 4 ] +
744 global[2] * tr.viewDef->worldSpace.modelViewMatrix[ i + 2 * 4 ] +
745 tr.viewDef->worldSpace.modelViewMatrix[ i + 3 * 4 ];
749 for ( i = 0 ; i < 4 ; i ++ ) {
751 view[0] * tr.viewDef->projectionMatrix[ i + 0 * 4 ] +
752 view[1] * tr.viewDef->projectionMatrix[ i + 1 * 4 ] +
753 view[2] * tr.viewDef->projectionMatrix[ i + 2 * 4 ] +
754 view[3] * tr.viewDef->projectionMatrix[ i + 3 * 4 ];
759 ndc[0] = clip[0] / clip[3];
760 ndc[1] = clip[1] / clip[3];
761 ndc[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
765 ==========================
766 R_TransformClipToDevice
768 Clip to normalized device coordinates
769 ==========================
771 void R_TransformClipToDevice( const idPlane &clip, const viewDef_t *view, idVec3 &normalized ) {
772 normalized[0] = clip[0] / clip[3];
773 normalized[1] = clip[1] / clip[3];
774 normalized[2] = clip[2] / clip[3];
779 ==========================
781 ==========================
783 void myGlMultMatrix( const float a[16], const float b[16], float out[16] ) {
787 for ( i = 0 ; i < 4 ; i++ ) {
788 for ( j = 0 ; j < 4 ; j++ ) {
790 a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
791 + a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
792 + a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
793 + a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
797 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];
798 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];
799 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];
800 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];
801 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];
802 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];
803 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];
804 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];
805 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];
806 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];
807 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];
808 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];
809 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];
810 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];
811 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];
812 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];
821 void R_TransposeGLMatrix( const float in[16], float out[16] ) {
824 for ( i = 0 ; i < 4 ; i++ ) {
825 for ( j = 0 ; j < 4 ; j++ ) {
826 out[i*4+j] = in[j*4+i];
835 Sets up the world to view matrix for a given viewParm
838 void R_SetViewMatrix( viewDef_t *viewDef ) {
841 float viewerMatrix[16];
842 static float s_flipMatrix[16] = {
843 // convert from our coordinate system (looking down X)
844 // to OpenGL's coordinate system (looking down -Z)
851 world = &viewDef->worldSpace;
853 memset( world, 0, sizeof(*world) );
855 // the model matrix is an identity
856 world->modelMatrix[0*4+0] = 1;
857 world->modelMatrix[1*4+1] = 1;
858 world->modelMatrix[2*4+2] = 1;
860 // transform by the camera placement
861 origin = viewDef->renderView.vieworg;
863 viewerMatrix[0] = viewDef->renderView.viewaxis[0][0];
864 viewerMatrix[4] = viewDef->renderView.viewaxis[0][1];
865 viewerMatrix[8] = viewDef->renderView.viewaxis[0][2];
866 viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
868 viewerMatrix[1] = viewDef->renderView.viewaxis[1][0];
869 viewerMatrix[5] = viewDef->renderView.viewaxis[1][1];
870 viewerMatrix[9] = viewDef->renderView.viewaxis[1][2];
871 viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
873 viewerMatrix[2] = viewDef->renderView.viewaxis[2][0];
874 viewerMatrix[6] = viewDef->renderView.viewaxis[2][1];
875 viewerMatrix[10] = viewDef->renderView.viewaxis[2][2];
876 viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
880 viewerMatrix[11] = 0;
881 viewerMatrix[15] = 1;
883 // convert from our coordinate system (looking down X)
884 // to OpenGL's coordinate system (looking down -Z)
885 myGlMultMatrix( viewerMatrix, s_flipMatrix, world->modelViewMatrix );
892 This uses the "infinite far z" trick
895 void R_SetupProjection( void ) {
896 float xmin, xmax, ymin, ymax;
899 float jitterx, jittery;
900 static idRandom random;
902 // random jittering is usefull when multiple
903 // frames are going to be blended together
904 // for motion blurred anti-aliasing
905 if ( r_jitter.GetBool() ) {
906 jitterx = random.RandomFloat();
907 jittery = random.RandomFloat();
909 jitterx = jittery = 0;
913 // set up projection matrix
915 zNear = r_znear.GetFloat();
916 if ( tr.viewDef->renderView.cramZNear ) {
920 ymax = zNear * tan( tr.viewDef->renderView.fov_y * idMath::PI / 360.0f );
923 xmax = zNear * tan( tr.viewDef->renderView.fov_x * idMath::PI / 360.0f );
927 height = ymax - ymin;
929 jitterx = jitterx * width / ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 + 1 );
932 jittery = jittery * height / ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 + 1 );
936 tr.viewDef->projectionMatrix[0] = 2 * zNear / width;
937 tr.viewDef->projectionMatrix[4] = 0;
938 tr.viewDef->projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0
939 tr.viewDef->projectionMatrix[12] = 0;
941 tr.viewDef->projectionMatrix[1] = 0;
942 tr.viewDef->projectionMatrix[5] = 2 * zNear / height;
943 tr.viewDef->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
944 tr.viewDef->projectionMatrix[13] = 0;
946 // this is the far-plane-at-infinity formulation, and
947 // crunches the Z range slightly so w=0 vertexes do not
948 // rasterize right at the wraparound point
949 tr.viewDef->projectionMatrix[2] = 0;
950 tr.viewDef->projectionMatrix[6] = 0;
951 tr.viewDef->projectionMatrix[10] = -0.999f;
952 tr.viewDef->projectionMatrix[14] = -2.0f * zNear;
954 tr.viewDef->projectionMatrix[3] = 0;
955 tr.viewDef->projectionMatrix[7] = 0;
956 tr.viewDef->projectionMatrix[11] = -1;
957 tr.viewDef->projectionMatrix[15] = 0;
964 Setup that culling frustum planes for the current view
965 FIXME: derive from modelview matrix times projection matrix
968 static void R_SetupViewFrustum( void ) {
973 ang = DEG2RAD( tr.viewDef->renderView.fov_x ) * 0.5f;
974 idMath::SinCos( ang, xs, xc );
976 tr.viewDef->frustum[0] = xs * tr.viewDef->renderView.viewaxis[0] + xc * tr.viewDef->renderView.viewaxis[1];
977 tr.viewDef->frustum[1] = xs * tr.viewDef->renderView.viewaxis[0] - xc * tr.viewDef->renderView.viewaxis[1];
979 ang = DEG2RAD( tr.viewDef->renderView.fov_y ) * 0.5f;
980 idMath::SinCos( ang, xs, xc );
982 tr.viewDef->frustum[2] = xs * tr.viewDef->renderView.viewaxis[0] + xc * tr.viewDef->renderView.viewaxis[2];
983 tr.viewDef->frustum[3] = xs * tr.viewDef->renderView.viewaxis[0] - xc * tr.viewDef->renderView.viewaxis[2];
985 // plane four is the front clipping plane
986 tr.viewDef->frustum[4] = /* vec3_origin - */ tr.viewDef->renderView.viewaxis[0];
988 for ( i = 0; i < 5; i++ ) {
989 // flip direction so positive side faces out (FIXME: globally unify this)
990 tr.viewDef->frustum[i] = -tr.viewDef->frustum[i].Normal();
991 tr.viewDef->frustum[i][3] = -( tr.viewDef->renderView.vieworg * tr.viewDef->frustum[i].Normal() );
994 // eventually, plane five will be the rear clipping plane for fog
996 float dNear, dFar, dLeft, dUp;
998 dNear = r_znear.GetFloat();
999 if ( tr.viewDef->renderView.cramZNear ) {
1003 dFar = MAX_WORLD_SIZE;
1004 dLeft = dFar * tan( DEG2RAD( tr.viewDef->renderView.fov_x * 0.5f ) );
1005 dUp = dFar * tan( DEG2RAD( tr.viewDef->renderView.fov_y * 0.5f ) );
1006 tr.viewDef->viewFrustum.SetOrigin( tr.viewDef->renderView.vieworg );
1007 tr.viewDef->viewFrustum.SetAxis( tr.viewDef->renderView.viewaxis );
1008 tr.viewDef->viewFrustum.SetSize( dNear, dFar, dLeft, dUp );
1013 R_ConstrainViewFrustum
1016 static void R_ConstrainViewFrustum( void ) {
1019 // constrain the view frustum to the total bounds of all visible lights and visible entities
1021 for ( viewLight_t *vLight = tr.viewDef->viewLights; vLight; vLight = vLight->next ) {
1022 bounds.AddBounds( vLight->lightDef->frustumTris->bounds );
1024 for ( viewEntity_t *vEntity = tr.viewDef->viewEntitys; vEntity; vEntity = vEntity->next ) {
1025 bounds.AddBounds( vEntity->entityDef->referenceBounds );
1027 tr.viewDef->viewFrustum.ConstrainToBounds( bounds );
1029 if ( r_useFrustumFarDistance.GetFloat() > 0.0f ) {
1030 tr.viewDef->viewFrustum.MoveFarDistance( r_useFrustumFarDistance.GetFloat() );
1035 ==========================================================================================
1039 ==========================================================================================
1044 =======================
1047 =======================
1049 static int R_QsortSurfaces( const void *a, const void *b ) {
1050 const drawSurf_t *ea, *eb;
1052 ea = *(drawSurf_t **)a;
1053 eb = *(drawSurf_t **)b;
1055 if ( ea->sort < eb->sort ) {
1058 if ( ea->sort > eb->sort ) {
1070 static void R_SortDrawSurfs( void ) {
1071 // sort the drawsurfs by sort type, then orientation, then shader
1072 qsort( tr.viewDef->drawSurfs, tr.viewDef->numDrawSurfs, sizeof( tr.viewDef->drawSurfs[0] ),
1078 //========================================================================
1081 //==============================================================================
1089 A view may be either the actual camera view,
1090 a mirror / remote location, or a 3D view on a gui surface.
1092 Parms will typically be allocated with R_FrameAlloc
1095 void R_RenderView( viewDef_t *parms ) {
1098 if ( parms->renderView.width <= 0 || parms->renderView.height <= 0 ) {
1104 // save view in case we are a subview
1105 oldView = tr.viewDef;
1111 // set the matrix for world space to eye space
1112 R_SetViewMatrix( tr.viewDef );
1114 // the four sides of the view frustum are needed
1115 // for culling and portal visibility
1116 R_SetupViewFrustum();
1118 // we need to set the projection matrix before doing
1119 // portal-to-screen scissor box calculations
1120 R_SetupProjection();
1122 // identify all the visible portalAreas, and the entityDefs and
1123 // lightDefs that are in them and pass culling.
1124 static_cast<idRenderWorldLocal *>(parms->renderWorld)->FindViewLightsAndEntities();
1126 // constrain the view frustum to the view lights and entities
1127 R_ConstrainViewFrustum();
1129 // make sure that interactions exist for all light / entity combinations
1131 // add any pre-generated light shadows, and calculate the light shader values
1132 R_AddLightSurfaces();
1134 // adds ambient surfaces and create any necessary interaction surfaces to add to the light
1136 R_AddModelSurfaces();
1138 // any viewLight that didn't have visible surfaces can have it's shadows removed
1139 R_RemoveUnecessaryViewLights();
1141 // sort all the ambient surfaces for translucency ordering
1144 // generate any subviews (mirrors, cameras, etc) before adding this view
1145 if ( R_GenerateSubViews() ) {
1146 // if we are debugging subviews, allow the skipping of the
1148 if ( r_subviewOnly.GetBool() ) {
1153 // write everything needed to the demo file
1154 if ( session->writeDemo ) {
1155 static_cast<idRenderWorldLocal *>(parms->renderWorld)->WriteVisibleDefs( tr.viewDef );
1158 // add the rendering commands for this viewDef
1159 R_AddDrawViewCmd( parms );
1161 // restore view in case we are a subview
1162 tr.viewDef = oldView;