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