]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/tr_main.cpp
hello world
[icculus/iodoom3.git] / neo / renderer / tr_main.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
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.
13
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.
18
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/>.
21
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.
23
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.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "tr_local.h"
33 #ifdef __ppc__
34 #include <vecLib/vecLib.h>
35 #endif
36 #if defined(MACOS_X) && defined(__i386__)
37 #include <xmmintrin.h>
38 #endif
39
40 //====================================================================
41
42 /*
43 ======================
44 idScreenRect::Clear
45 ======================
46 */
47 void idScreenRect::Clear() {
48         x1 = y1 = 32000;
49         x2 = y2 = -32000;
50         zmin = 0.0f; zmax = 1.0f;
51 }
52
53 /*
54 ======================
55 idScreenRect::AddPoint
56 ======================
57 */
58 void idScreenRect::AddPoint( float x, float y ) {
59         int     ix = idMath::FtoiFast( x );
60         int iy = idMath::FtoiFast( y );
61
62         if ( ix < x1 ) {
63                 x1 = ix;
64         }
65         if ( ix > x2 ) {
66                 x2 = ix;
67         }
68         if ( iy < y1 ) {
69                 y1 = iy;
70         }
71         if ( iy > y2 ) {
72                 y2 = iy;
73         }
74 }
75
76 /*
77 ======================
78 idScreenRect::Expand
79 ======================
80 */
81 void idScreenRect::Expand() {
82         x1--;
83         y1--;
84         x2++;
85         y2++;
86 }
87
88 /*
89 ======================
90 idScreenRect::Intersect
91 ======================
92 */
93 void idScreenRect::Intersect( const idScreenRect &rect ) {
94         if ( rect.x1 > x1 ) {
95                 x1 = rect.x1;
96         }
97         if ( rect.x2 < x2 ) {
98                 x2 = rect.x2;
99         }
100         if ( rect.y1 > y1 ) {
101                 y1 = rect.y1;
102         }
103         if ( rect.y2 < y2 ) {
104                 y2 = rect.y2;
105         }
106 }
107
108 /*
109 ======================
110 idScreenRect::Union
111 ======================
112 */
113 void idScreenRect::Union( const idScreenRect &rect ) {
114         if ( rect.x1 < x1 ) {
115                 x1 = rect.x1;
116         }
117         if ( rect.x2 > x2 ) {
118                 x2 = rect.x2;
119         }
120         if ( rect.y1 < y1 ) {
121                 y1 = rect.y1;
122         }
123         if ( rect.y2 > y2 ) {
124                 y2 = rect.y2;
125         }
126 }
127
128 /*
129 ======================
130 idScreenRect::Equals
131 ======================
132 */
133 bool idScreenRect::Equals( const idScreenRect &rect ) const {
134         return ( x1 == rect.x1 && x2 == rect.x2 && y1 == rect.y1 && y2 == rect.y2 );
135 }
136
137 /*
138 ======================
139 idScreenRect::IsEmpty
140 ======================
141 */
142 bool idScreenRect::IsEmpty() const {
143         return ( x1 > x2 || y1 > y2 );
144 }
145
146 /*
147 ======================
148 R_ScreenRectFromViewFrustumBounds
149 ======================
150 */
151 idScreenRect R_ScreenRectFromViewFrustumBounds( const idBounds &bounds ) {
152         idScreenRect screenRect;
153
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 ) );
158
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 );
162         }
163
164         return screenRect;
165 }
166
167 /*
168 ======================
169 R_ShowColoredScreenRect
170 ======================
171 */
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 );
176         }
177 }
178
179 /*
180 ====================
181 R_ToggleSmpFrame
182 ====================
183 */
184 void R_ToggleSmpFrame( void ) {
185         if ( r_lockSurfaces.GetBool() ) {
186                 return;
187         }
188         R_FreeDeferredTriSurfs( frameData );
189
190         // clear frame-temporary data
191         frameData_t             *frame;
192         frameMemoryBlock_t      *block;
193
194         // update the highwater mark
195         R_CountFrameData();
196
197         frame = frameData;
198
199         // reset the memory allocation to the first block
200         frame->alloc = frame->memory;
201
202         // clear all the blocks
203         for ( block = frame->memory ; block ; block = block->next ) {
204                 block->used = 0;
205         }
206
207         R_ClearCommandChain();
208 }
209
210
211 //=====================================================
212
213 #define MEMORY_BLOCK_SIZE       0x100000
214
215 /*
216 =====================
217 R_ShutdownFrameData
218 =====================
219 */
220 void R_ShutdownFrameData( void ) {
221         frameData_t *frame;
222         frameMemoryBlock_t *block;
223
224         // free any current data
225         frame = frameData;
226         if ( !frame ) {
227                 return;
228         }
229
230         R_FreeDeferredTriSurfs( frame );
231
232         frameMemoryBlock_t *nextBlock;
233         for ( block = frame->memory ; block ; block = nextBlock ) {
234                 nextBlock = block->next;
235                 Mem_Free( block );
236         }
237         Mem_Free( frame );
238         frameData = NULL;
239 }
240
241 /*
242 =====================
243 R_InitFrameData
244 =====================
245 */
246 void R_InitFrameData( void ) {
247         int size;
248         frameData_t *frame;
249         frameMemoryBlock_t *block;
250
251         R_ShutdownFrameData();
252
253         frameData = (frameData_t *)Mem_ClearedAlloc( sizeof( *frameData ));
254         frame = frameData;
255         size = MEMORY_BLOCK_SIZE;
256         block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) );
257         if ( !block ) {
258                 common->FatalError( "R_InitFrameData: Mem_Alloc() failed" );
259         }
260         block->size = size;
261         block->used = 0;
262         block->next = NULL;
263         frame->memory = block;
264         frame->memoryHighwater = 0;
265
266         R_ToggleSmpFrame();
267 }
268
269 /*
270 ================
271 R_CountFrameData
272 ================
273 */
274 int R_CountFrameData( void ) {
275         frameData_t             *frame;
276         frameMemoryBlock_t      *block;
277         int                             count;
278
279         count = 0;
280         frame = frameData;
281         for ( block = frame->memory ; block ; block=block->next ) {
282                 count += block->used;
283                 if ( block == frame->alloc ) {
284                         break;
285                 }
286         }
287
288         // note if this is a new highwater mark
289         if ( count > frame->memoryHighwater ) {
290                 frame->memoryHighwater = count;
291         }
292
293         return count;
294 }
295
296 /*
297 =================
298 R_StaticAlloc
299 =================
300 */
301 void *R_StaticAlloc( int bytes ) {
302         void    *buf;
303
304         tr.pc.c_alloc++;
305
306         tr.staticAllocCount += bytes;
307
308     buf = Mem_Alloc( bytes );
309
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 );
313         }
314         return buf;
315 }
316
317 /*
318 =================
319 R_ClearedStaticAlloc
320 =================
321 */
322 void *R_ClearedStaticAlloc( int bytes ) {
323         void    *buf;
324
325         buf = R_StaticAlloc( bytes );
326         SIMDProcessor->Memset( buf, 0, bytes );
327         return buf;
328 }
329
330 /*
331 =================
332 R_StaticFree
333 =================
334 */
335 void R_StaticFree( void *data ) {
336         tr.pc.c_free++;
337     Mem_Free( data );
338 }
339
340 /*
341 ================
342 R_FrameAlloc
343
344 This data will be automatically freed when the
345 current frame's back end completes.
346
347 This should only be called by the front end.  The
348 back end shouldn't need to allocate memory.
349
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.
353
354 All temporary data, like dynamic tesselations
355 and local spaces are allocated here.
356
357 The memory will not move, but it may not be
358 contiguous with previous allocations even
359 from this frame.
360
361 The memory is NOT zero filled.
362 Should part of this be inlined in a macro?
363 ================
364 */
365 void *R_FrameAlloc( int bytes ) {
366         frameData_t             *frame;
367         frameMemoryBlock_t      *block;
368         void                    *buf;
369     
370         bytes = (bytes+16)&~15;
371         // see if it can be satisfied in the current block
372         frame = frameData;
373         block = frame->alloc;
374
375         if ( block->size - block->used >= bytes ) {
376                 buf = block->base + block->used;
377                 block->used += bytes;
378                 return buf;
379         }
380
381         // advance to the next memory block if available
382         block = block->next;
383         // create a new block if we are at the end of
384         // the chain
385         if ( !block ) {
386                 int             size;
387
388                 size = MEMORY_BLOCK_SIZE;
389                 block = (frameMemoryBlock_t *)Mem_Alloc( size + sizeof( *block ) );
390                 if ( !block ) {
391                         common->FatalError( "R_FrameAlloc: Mem_Alloc() failed" );
392                 }
393                 block->size = size;
394                 block->used = 0;
395                 block->next = NULL;
396                 frame->alloc->next = block;
397         }
398
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",
402                         bytes );
403         }
404
405         frame->alloc = block;
406
407         block->used = bytes;
408
409         return block->base;
410 }
411
412 /*
413 ==================
414 R_ClearedFrameAlloc
415 ==================
416 */
417 void *R_ClearedFrameAlloc( int bytes ) {
418         void    *r;
419
420         r = R_FrameAlloc( bytes );
421         SIMDProcessor->Memset( r, 0, bytes );
422         return r;
423 }
424
425
426 /*
427 ==================
428 R_FrameFree
429
430 This does nothing at all, as the frame data is reused every frame
431 and can only be stack allocated.
432
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.
436 ==================
437 */
438 void R_FrameFree( void *data ) {
439 }
440
441
442
443 //==========================================================================
444
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];
450
451         modelMatrix[1] = axis[0][1];
452         modelMatrix[5] = axis[1][1];
453         modelMatrix[9] = axis[2][1];
454         modelMatrix[13] = origin[1];
455
456         modelMatrix[2] = axis[0][2];
457         modelMatrix[6] = axis[1][2];
458         modelMatrix[10] = axis[2][2];
459         modelMatrix[14] = origin[2];
460
461         modelMatrix[3] = 0;
462         modelMatrix[7] = 0;
463         modelMatrix[11] = 0;
464         modelMatrix[15] = 1;
465 }
466
467
468 // FIXME: these assume no skewing or scaling transforms
469
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;
474         float i0,i1,i2;
475         i0 = in[0];
476         i1 = in[1];
477         i2 = in[2];
478         
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]);
483         
484         in0 = _mm_load1_ps(&i0);
485         in1 = _mm_load1_ps(&i1);
486         in2 = _mm_load1_ps(&i2);
487         
488         m0 = _mm_mul_ps(m0, in0);
489         m1 = _mm_mul_ps(m1, in1);
490         m2 = _mm_mul_ps(m2, in2);
491
492         m0 = _mm_add_ps(m0, m1);
493         m0 = _mm_add_ps(m0, m2);
494         m0 = _mm_add_ps(m0, m3);
495         
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);
501 #else   
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];
508 #endif
509 }
510
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];
520 }
521
522 void R_GlobalPointToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
523         idVec3  temp;
524
525         VectorSubtract( in, &modelMatrix[12], temp );
526
527         out[0] = DotProduct( temp, &modelMatrix[0] );
528         out[1] = DotProduct( temp, &modelMatrix[4] );
529         out[2] = DotProduct( temp, &modelMatrix[8] );
530 }
531
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];
539 }
540
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] );
545 }
546
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];
552 }
553
554 void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane &in, idPlane &out ) {
555         float   offset;
556
557         R_LocalVectorToGlobal( modelMatrix, in.Normal(), out.Normal() );
558
559         offset = modelMatrix[12] * out[0] + modelMatrix[13] * out[1] + modelMatrix[14] * out[2];
560         out[3] = in[3] - offset;
561 }
562
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;
566
567         // projection
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 ];
570
571         if ( clip_w <= 0.0f ) {
572                 dst_z = 0.0f;                                   // clamp to near plane
573         } else {
574                 dst_z = clip_z / clip_w;
575                 dst_z = dst_z * 0.5f + 0.5f;    // convert to window coords
576         }
577 }
578
579 /*
580 =================
581 R_RadiusCullLocalBox
582
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)
585 =================
586 */
587 bool R_RadiusCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
588         int                     i;
589         float           d;
590         idVec3          worldOrigin;
591         float           worldRadius;
592         const idPlane   *frust;
593
594         if ( r_useCulling.GetInteger() == 0 ) {
595                 return false;
596         }
597
598         // transform the surface bounds into world space
599         idVec3  localOrigin = ( bounds[0] + bounds[1] ) * 0.5;
600
601         R_LocalPointToGlobal( modelMatrix, localOrigin, worldOrigin );
602
603         worldRadius = (bounds[0] - localOrigin).Length();       // FIXME: won't be correct for scaled objects
604
605         for ( i = 0 ; i < numPlanes ; i++ ) {
606                 frust = planes + i;
607                 d = frust->Distance( worldOrigin );
608                 if ( d > worldRadius ) {
609                         return true;    // culled
610                 }
611         }
612
613         return false;           // no culled
614 }
615
616 /*
617 =================
618 R_CornerCullLocalBox
619
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)
623 =================
624 */
625 bool R_CornerCullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
626         int                     i, j;
627         idVec3          transformed[8];
628         float           dists[8];
629         idVec3          v;
630         const idPlane *frust;
631
632         // we can disable box culling for experimental timing purposes
633         if ( r_useCulling.GetInteger() < 2 ) {
634                 return false;
635         }
636
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];
642
643                 R_LocalPointToGlobal( modelMatrix, v, transformed[i] );
644         }
645
646         // check against frustum planes
647         for ( i = 0 ; i < numPlanes ; i++ ) {
648                 frust = planes + i;
649                 for ( j = 0 ; j < 8 ; j++ ) {
650                         dists[j] = frust->Distance( transformed[j] );
651                         if ( dists[j] < 0 ) {
652                                 break;
653                         }
654                 }
655                 if ( j == 8 ) {
656                         // all points were behind one of the planes
657                         tr.pc.c_box_cull_out++;
658                         return true;
659                 }
660         }
661
662         tr.pc.c_box_cull_in++;
663
664         return false;           // not culled
665 }
666
667 /*
668 =================
669 R_CullLocalBox
670
671 Performs quick test before expensive test
672 Returns true if the box is outside the given global frustum, (positive sides are out)
673 =================
674 */
675 bool R_CullLocalBox( const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes ) {
676         if ( R_RadiusCullLocalBox( bounds, modelMatrix, numPlanes, planes ) ) {
677                 return true;
678         }
679         return R_CornerCullLocalBox( bounds, modelMatrix, numPlanes, planes );
680 }
681
682 /*
683 ==========================
684 R_TransformModelToClip
685 ==========================
686 */
687 void R_TransformModelToClip( const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst ) {
688         int i;
689
690         for ( i = 0 ; i < 4 ; i++ ) {
691                 eye[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 ];
696         }
697
698         for ( i = 0 ; i < 4 ; i++ ) {
699                 dst[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 ];
704         }
705 }
706
707 /*
708 ==========================
709 R_GlobalToNormalizedDeviceCoordinates
710
711 -1 to 1 range in x, y, and z
712 ==========================
713 */
714 void R_GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ) {
715         int             i;
716         idPlane view;
717         idPlane clip;
718
719         // _D3XP added work on primaryView when no viewDef
720         if ( !tr.viewDef ) {
721
722                 for ( i = 0 ; i < 4 ; i ++ ) {
723                         view[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 ];
728                 }
729
730                 for ( i = 0 ; i < 4 ; i ++ ) {
731                         clip[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 ];
736                 }
737
738         } else {
739
740                 for ( i = 0 ; i < 4 ; i ++ ) {
741                         view[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 ];
746                 }
747
748
749                 for ( i = 0 ; i < 4 ; i ++ ) {
750                         clip[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 ];
755                 }
756
757         }
758
759         ndc[0] = clip[0] / clip[3];
760         ndc[1] = clip[1] / clip[3];
761         ndc[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
762 }
763
764 /*
765 ==========================
766 R_TransformClipToDevice
767
768 Clip to normalized device coordinates
769 ==========================
770 */
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];
775 }
776
777
778 /*
779 ==========================
780 myGlMultMatrix
781 ==========================
782 */
783 void myGlMultMatrix( const float a[16], const float b[16], float out[16] ) {
784 #if 0
785         int             i, j;
786
787         for ( i = 0 ; i < 4 ; i++ ) {
788                 for ( j = 0 ; j < 4 ; j++ ) {
789                         out[ i * 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 ];
794                 }
795         }
796 #else
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];
813 #endif
814 }
815
816 /*
817 ================
818 R_TransposeGLMatrix
819 ================
820 */
821 void R_TransposeGLMatrix( const float in[16], float out[16] ) {
822         int             i, j;
823
824         for ( i = 0 ; i < 4 ; i++ ) {
825                 for ( j = 0 ; j < 4 ; j++ ) {
826                         out[i*4+j] = in[j*4+i];
827                 }
828         }
829 }
830
831 /*
832 =================
833 R_SetViewMatrix
834
835 Sets up the world to view matrix for a given viewParm
836 =================
837 */
838 void R_SetViewMatrix( viewDef_t *viewDef ) {
839         idVec3  origin;
840         viewEntity_t *world;
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)
845                 0, 0, -1, 0,
846                 -1, 0, 0, 0,
847                 0, 1, 0, 0,
848                 0, 0, 0, 1
849         };
850
851         world = &viewDef->worldSpace;
852
853         memset( world, 0, sizeof(*world) );
854
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;
859
860         // transform by the camera placement
861         origin = viewDef->renderView.vieworg;
862
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];
867
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];
872
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];
877
878         viewerMatrix[3] = 0;
879         viewerMatrix[7] = 0;
880         viewerMatrix[11] = 0;
881         viewerMatrix[15] = 1;
882
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 );
886 }
887
888 /*
889 ===============
890 R_SetupProjection
891
892 This uses the "infinite far z" trick
893 ===============
894 */
895 void R_SetupProjection( void ) {
896         float   xmin, xmax, ymin, ymax;
897         float   width, height;
898         float   zNear;
899         float   jitterx, jittery;
900         static  idRandom random;
901
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();
908         } else {
909                 jitterx = jittery = 0;
910         }
911
912         //
913         // set up projection matrix
914         //
915         zNear   = r_znear.GetFloat();
916         if ( tr.viewDef->renderView.cramZNear ) {
917                 zNear *= 0.25;
918         }
919
920         ymax = zNear * tan( tr.viewDef->renderView.fov_y * idMath::PI / 360.0f );
921         ymin = -ymax;
922
923         xmax = zNear * tan( tr.viewDef->renderView.fov_x * idMath::PI / 360.0f );
924         xmin = -xmax;
925
926         width = xmax - xmin;
927         height = ymax - ymin;
928
929         jitterx = jitterx * width / ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 + 1 );
930         xmin += jitterx;
931         xmax += jitterx;
932         jittery = jittery * height / ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 + 1 );
933         ymin += jittery;
934         ymax += jittery;
935
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;
940
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;
945
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;
953
954         tr.viewDef->projectionMatrix[3] = 0;
955         tr.viewDef->projectionMatrix[7] = 0;
956         tr.viewDef->projectionMatrix[11] = -1;
957         tr.viewDef->projectionMatrix[15] = 0;
958 }
959
960 /*
961 =================
962 R_SetupViewFrustum
963
964 Setup that culling frustum planes for the current view
965 FIXME: derive from modelview matrix times projection matrix
966 =================
967 */
968 static void R_SetupViewFrustum( void ) {
969         int             i;
970         float   xs, xc;
971         float   ang;
972
973         ang = DEG2RAD( tr.viewDef->renderView.fov_x ) * 0.5f;
974         idMath::SinCos( ang, xs, xc );
975
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];
978
979         ang = DEG2RAD( tr.viewDef->renderView.fov_y ) * 0.5f;
980         idMath::SinCos( ang, xs, xc );
981
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];
984
985         // plane four is the front clipping plane
986         tr.viewDef->frustum[4] = /* vec3_origin - */ tr.viewDef->renderView.viewaxis[0];
987
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() );
992         }
993
994         // eventually, plane five will be the rear clipping plane for fog
995
996         float dNear, dFar, dLeft, dUp;
997
998         dNear = r_znear.GetFloat();
999         if ( tr.viewDef->renderView.cramZNear ) {
1000                 dNear *= 0.25f;
1001         }
1002
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 );
1009 }
1010
1011 /*
1012 ===================
1013 R_ConstrainViewFrustum
1014 ===================
1015 */
1016 static void R_ConstrainViewFrustum( void ) {
1017         idBounds bounds;
1018
1019         // constrain the view frustum to the total bounds of all visible lights and visible entities
1020         bounds.Clear();
1021         for ( viewLight_t *vLight = tr.viewDef->viewLights; vLight; vLight = vLight->next ) {
1022                 bounds.AddBounds( vLight->lightDef->frustumTris->bounds );
1023         }
1024         for ( viewEntity_t *vEntity = tr.viewDef->viewEntitys; vEntity; vEntity = vEntity->next ) {
1025                 bounds.AddBounds( vEntity->entityDef->referenceBounds );
1026         }
1027         tr.viewDef->viewFrustum.ConstrainToBounds( bounds );
1028
1029         if ( r_useFrustumFarDistance.GetFloat() > 0.0f ) {
1030                 tr.viewDef->viewFrustum.MoveFarDistance( r_useFrustumFarDistance.GetFloat() );
1031         }
1032 }
1033
1034 /*
1035 ==========================================================================================
1036
1037 DRAWSURF SORTING
1038
1039 ==========================================================================================
1040 */
1041
1042
1043 /*
1044 =======================
1045 R_QsortSurfaces
1046
1047 =======================
1048 */
1049 static int R_QsortSurfaces( const void *a, const void *b ) {
1050         const drawSurf_t        *ea, *eb;
1051
1052         ea = *(drawSurf_t **)a;
1053         eb = *(drawSurf_t **)b;
1054
1055         if ( ea->sort < eb->sort ) {
1056                 return -1;
1057         }
1058         if ( ea->sort > eb->sort ) {
1059                 return 1;
1060         }
1061         return 0;
1062 }
1063
1064
1065 /*
1066 =================
1067 R_SortDrawSurfs
1068 =================
1069 */
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] ),
1073                 R_QsortSurfaces );
1074 }
1075
1076
1077
1078 //========================================================================
1079
1080
1081 //==============================================================================
1082
1083
1084
1085 /*
1086 ================
1087 R_RenderView
1088
1089 A view may be either the actual camera view,
1090 a mirror / remote location, or a 3D view on a gui surface.
1091
1092 Parms will typically be allocated with R_FrameAlloc
1093 ================
1094 */
1095 void R_RenderView( viewDef_t *parms ) {
1096         viewDef_t               *oldView;
1097
1098         if ( parms->renderView.width <= 0 || parms->renderView.height <= 0 ) {
1099                 return;
1100         }
1101
1102         tr.viewCount++;
1103
1104         // save view in case we are a subview
1105         oldView = tr.viewDef;
1106
1107         tr.viewDef = parms;
1108
1109         tr.sortOffset = 0;
1110
1111         // set the matrix for world space to eye space
1112         R_SetViewMatrix( tr.viewDef );
1113
1114         // the four sides of the view frustum are needed
1115         // for culling and portal visibility
1116         R_SetupViewFrustum();
1117
1118         // we need to set the projection matrix before doing
1119         // portal-to-screen scissor box calculations
1120         R_SetupProjection();
1121
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();
1125
1126         // constrain the view frustum to the view lights and entities
1127         R_ConstrainViewFrustum();
1128
1129         // make sure that interactions exist for all light / entity combinations
1130         // that are visible
1131         // add any pre-generated light shadows, and calculate the light shader values
1132         R_AddLightSurfaces();
1133
1134         // adds ambient surfaces and create any necessary interaction surfaces to add to the light
1135         // lists
1136         R_AddModelSurfaces();
1137
1138         // any viewLight that didn't have visible surfaces can have it's shadows removed
1139         R_RemoveUnecessaryViewLights();
1140
1141         // sort all the ambient surfaces for translucency ordering
1142         R_SortDrawSurfs();
1143
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
1147                 // main view draw
1148                 if ( r_subviewOnly.GetBool() ) {
1149                         return;
1150                 }
1151         }
1152
1153         // write everything needed to the demo file
1154         if ( session->writeDemo ) {
1155                 static_cast<idRenderWorldLocal *>(parms->renderWorld)->WriteVisibleDefs( tr.viewDef );
1156         }
1157
1158         // add the rendering commands for this viewDef
1159         R_AddDrawViewCmd( parms );
1160
1161         // restore view in case we are a subview
1162         tr.viewDef = oldView;
1163 }