1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”).
8 
9 RTCW SP 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 RTCW SP 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 RTCW SP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW SP 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 RTCW SP 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 
30 #include "tr_local.h"
31 
32 int r_firstSceneDrawSurf;
33 
34 int r_numdlights;
35 int r_firstSceneDlight;
36 
37 int r_numcoronas;
38 int r_firstSceneCorona;
39 
40 int r_numentities;
41 int r_firstSceneEntity;
42 
43 int r_numpolys;
44 int r_firstScenePoly;
45 
46 int r_numpolyverts;
47 
48 int skyboxportal;
49 int drawskyboxportal;
50 
51 /*
52 ====================
53 R_InitNextFrame
54 ====================
55 */
R_InitNextFrame(void)56 void R_InitNextFrame( void ) {
57 	backEndData->commands.used = 0;
58 
59 	r_firstSceneDrawSurf = 0;
60 
61 	r_numdlights = 0;
62 	r_firstSceneDlight = 0;
63 
64 	r_numcoronas = 0;
65 	r_firstSceneCorona = 0;
66 
67 	r_numentities = 0;
68 	r_firstSceneEntity = 0;
69 
70 	r_numpolys = 0;
71 	r_firstScenePoly = 0;
72 
73 	r_numpolyverts = 0;
74 }
75 
76 
77 /*
78 ====================
79 RE_ClearScene
80 
81 ====================
82 */
RE_ClearScene(void)83 void RE_ClearScene( void ) {
84 	r_firstSceneDlight = r_numdlights;
85 	r_firstSceneCorona = r_numcoronas;
86 	r_firstSceneEntity = r_numentities;
87 	r_firstScenePoly = r_numpolys;
88 }
89 
90 /*
91 ===========================================================================
92 
93 DISCRETE POLYS
94 
95 ===========================================================================
96 */
97 
98 /*
99 =====================
100 R_AddPolygonSurfaces
101 
102 Adds all the scene's polys into this view's drawsurf list
103 =====================
104 */
R_AddPolygonSurfaces(void)105 void R_AddPolygonSurfaces( void ) {
106 	int i;
107 	shader_t    *sh;
108 	srfPoly_t   *poly;
109 	int		fogMask;
110 
111 	tr.currentEntityNum = REFENTITYNUM_WORLD;
112 	tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
113 	fogMask = -((tr.refdef.rdflags & RDF_NOFOG) == 0);
114 
115 	for ( i = 0, poly = tr.refdef.polys; i < tr.refdef.numPolys ; i++, poly++ ) {
116 		sh = R_GetShaderByHandle( poly->hShader );
117 // GR - not tessellated
118 		R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex & fogMask, qfalse, qfalse, 0, /*cubeMap*/ ATI_TESS_NONE );
119 	}
120 }
121 
122 /*
123 =====================
124 RE_AddPolyToScene
125 
126 =====================
127 */
RE_AddPolyToScene(qhandle_t hShader,int numVerts,const polyVert_t * verts)128 void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts ) {
129 	srfPoly_t   *poly;
130 	int i;
131 	int fogIndex;
132 	fog_t       *fog;
133 	vec3_t bounds[2];
134 
135 	if ( !tr.registered ) {
136 		return;
137 	}
138 
139 	if ( !hShader ) {
140 		// This isn't a useful warning, and an hShader of zero isn't a null shader, it's
141 		// the default shader.
142 		//ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolyToScene: NULL poly shader\n");
143 		//return;
144 	}
145 
146 	if ( ( ( r_numpolyverts + numVerts ) >= max_polyverts ) || ( r_numpolys >= max_polys ) ) {
147 		return;
148 	}
149 
150 	poly = &backEndData->polys[r_numpolys];
151 	poly->surfaceType = SF_POLY;
152 	poly->hShader = hShader;
153 	poly->numVerts = numVerts;
154 	poly->verts = &backEndData->polyVerts[r_numpolyverts];
155 
156 	memcpy( poly->verts, verts, numVerts * sizeof( *verts ) );
157 	// Ridah
158 	if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
159 		poly->verts->modulate[0] = 255;
160 		poly->verts->modulate[1] = 255;
161 		poly->verts->modulate[2] = 255;
162 		poly->verts->modulate[3] = 255;
163 	}
164 	// done.
165 	r_numpolys++;
166 	r_numpolyverts += numVerts;
167 
168 	// see if it is in a fog volume
169 	if ( tr.world->numfogs == 1 ) {
170 		fogIndex = 0;
171 	} else {
172 		// find which fog volume the poly is in
173 		VectorCopy( poly->verts[0].xyz, bounds[0] );
174 		VectorCopy( poly->verts[0].xyz, bounds[1] );
175 		for ( i = 1 ; i < poly->numVerts ; i++ ) {
176 			AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
177 		}
178 		for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
179 			fog = &tr.world->fogs[fogIndex];
180 			if ( bounds[1][0] >= fog->bounds[0][0]
181 				 && bounds[1][1] >= fog->bounds[0][1]
182 				 && bounds[1][2] >= fog->bounds[0][2]
183 				 && bounds[0][0] <= fog->bounds[1][0]
184 				 && bounds[0][1] <= fog->bounds[1][1]
185 				 && bounds[0][2] <= fog->bounds[1][2] ) {
186 				break;
187 			}
188 		}
189 		if ( fogIndex == tr.world->numfogs ) {
190 			fogIndex = 0;
191 		}
192 	}
193 	poly->fogIndex = fogIndex;
194 }
195 
196 // Ridah
197 /*
198 =====================
199 RE_AddPolysToScene
200 
201 =====================
202 */
RE_AddPolysToScene(qhandle_t hShader,int numVerts,const polyVert_t * verts,int numPolys)203 void RE_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ) {
204 	srfPoly_t   *poly;
205 	int i;
206 	int fogIndex;
207 	fog_t       *fog;
208 	vec3_t bounds[2];
209 	int j;
210 
211 	if ( !tr.registered ) {
212 		return;
213 	}
214 
215 	if ( !hShader ) {
216 		ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolysToScene: NULL poly shader\n" );
217 		return;
218 	}
219 
220 	for ( j = 0; j < numPolys; j++ ) {
221 		if ( r_numpolyverts + numVerts >= max_polyverts || r_numpolys >= max_polys ) {
222 //			ri.Printf( PRINT_WARNING, "WARNING: RE_AddPolysToScene: MAX_POLYS or MAX_POLYVERTS reached\n");
223 			return;
224 		}
225 
226 		poly = &backEndData->polys[r_numpolys];
227 		poly->surfaceType = SF_POLY;
228 		poly->hShader = hShader;
229 		poly->numVerts = numVerts;
230 		poly->verts = &backEndData->polyVerts[r_numpolyverts];
231 
232 		memcpy( poly->verts, &verts[numVerts * j], numVerts * sizeof( *verts ) );
233 		// Ridah
234 		if ( glConfig.hardwareType == GLHW_RAGEPRO ) {
235 			poly->verts->modulate[0] = 255;
236 			poly->verts->modulate[1] = 255;
237 			poly->verts->modulate[2] = 255;
238 			poly->verts->modulate[3] = 255;
239 		}
240 		// done.
241 		r_numpolys++;
242 		r_numpolyverts += numVerts;
243 
244 		// if no world is loaded
245 		if ( tr.world == NULL ) {
246 			fogIndex = 0;
247 		}
248 		// see if it is in a fog volume
249 		else if ( tr.world->numfogs == 1 ) {
250 			fogIndex = 0;
251 		} else {
252 			// find which fog volume the poly is in
253 			VectorCopy( poly->verts[0].xyz, bounds[0] );
254 			VectorCopy( poly->verts[0].xyz, bounds[1] );
255 			for ( i = 1 ; i < poly->numVerts ; i++ ) {
256 				AddPointToBounds( poly->verts[i].xyz, bounds[0], bounds[1] );
257 			}
258 			for ( fogIndex = 1 ; fogIndex < tr.world->numfogs ; fogIndex++ ) {
259 				fog = &tr.world->fogs[fogIndex];
260 				if ( bounds[1][0] >= fog->bounds[0][0]
261 					 && bounds[1][1] >= fog->bounds[0][1]
262 					 && bounds[1][2] >= fog->bounds[0][2]
263 					 && bounds[0][0] <= fog->bounds[1][0]
264 					 && bounds[0][1] <= fog->bounds[1][1]
265 					 && bounds[0][2] <= fog->bounds[1][2] ) {
266 					break;
267 				}
268 			}
269 			if ( fogIndex == tr.world->numfogs ) {
270 				fogIndex = 0;
271 			}
272 		}
273 		poly->fogIndex = fogIndex;
274 	}
275 }
276 // done.
277 
278 
279 //=================================================================================
280 
281 
282 /*
283 =====================
284 RE_AddRefEntityToScene
285 
286 =====================
287 */
RE_AddRefEntityToScene(const refEntity_t * ent)288 void RE_AddRefEntityToScene( const refEntity_t *ent ) {
289 	vec3_t cross;
290 
291 	if ( !tr.registered ) {
292 		return;
293 	}
294 	// show_bug.cgi?id=402
295 	if ( r_numentities >= MAX_REFENTITIES ) {
296 		ri.Printf(PRINT_DEVELOPER, "RE_AddRefEntityToScene: Dropping refEntity, reached MAX_REFENTITIES\n");
297 		return;
298 	}
299 	if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
300 		static qboolean firstTime = qtrue;
301 		if (firstTime) {
302 			firstTime = qfalse;
303 			ri.Printf( PRINT_WARNING, "RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
304 		}
305 		return;
306 	}
307 	if ( (int)ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
308 		ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
309 	}
310 
311 	backEndData->entities[r_numentities].e = *ent;
312 	backEndData->entities[r_numentities].lightingCalculated = qfalse;
313 
314 	CrossProduct(ent->axis[0], ent->axis[1], cross);
315 	backEndData->entities[r_numentities].mirrored = (DotProduct(ent->axis[2], cross) < 0.f);
316 
317 	r_numentities++;
318 }
319 
320 // Ridah, added support for overdraw field
321 /*
322 =====================
323 RE_AddLightToScene
324 
325 =====================
326 */
RE_AddLightToScene(const vec3_t org,float intensity,float r,float g,float b,int overdraw)327 void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b, int overdraw ) {
328 	dlight_t    *dl;
329 
330 	if ( !tr.registered ) {
331 		return;
332 	}
333 	if ( r_numdlights >= MAX_DLIGHTS ) {
334 		return;
335 	}
336 	if ( intensity <= 0 ) {
337 		return;
338 	}
339 	// these cards don't have the correct blend mode
340 	if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
341 		return;
342 	}
343 	// RF, allow us to force some dlights under all circumstances
344 	if ( !( overdraw & REF_FORCE_DLIGHT ) ) {
345 		if ( r_dynamiclight->integer == 0 ) {
346 			return;
347 		}
348 		if ( r_dynamiclight->integer == 2 && !( backEndData->dlights[r_numdlights].forced ) ) {
349 			return;
350 		}
351 	}
352 
353 	if ( r_dlightScale->value <= 0 ) { //----(SA)	added
354 		return;
355 	}
356 
357 	overdraw &= ~REF_FORCE_DLIGHT;
358 	overdraw &= ~REF_JUNIOR_DLIGHT;
359 
360 	dl = &backEndData->dlights[r_numdlights++];
361 	VectorCopy( org, dl->origin );
362 
363 	dl->radius = intensity * r_dlightScale->value;  //----(SA)	modified
364 	dl->color[0] = r;
365 	dl->color[1] = g;
366 	dl->color[2] = b;
367 	dl->dlshader = NULL;
368 	dl->overdraw = 0;
369 
370 	if ( overdraw == 10 ) { // sorry, hijacking 10 for a quick hack (SA)
371 		dl->dlshader = R_GetShaderByHandle( RE_RegisterShader( "negdlightshader" ) );
372 	} else if ( overdraw == 11 ) { // 11 is flames
373 		dl->dlshader = R_GetShaderByHandle( RE_RegisterShader( "flamedlightshader" ) );
374 	} else {
375 		dl->overdraw = overdraw;
376 	}
377 }
378 // done.
379 
380 
381 /*
382 ==============
383 RE_AddCoronaToScene
384 ==============
385 */
RE_AddCoronaToScene(const vec3_t org,float r,float g,float b,float scale,int id,int flags)386 void RE_AddCoronaToScene( const vec3_t org, float r, float g, float b, float scale, int id, int flags ) {
387 	corona_t    *cor;
388 
389 	if ( !tr.registered ) {
390 		return;
391 	}
392 	if ( r_numcoronas >= MAX_CORONAS ) {
393 		return;
394 	}
395 
396 	cor = &backEndData->coronas[r_numcoronas++];
397 	VectorCopy( org, cor->origin );
398 	cor->color[0] = r;
399 	cor->color[1] = g;
400 	cor->color[2] = b;
401 	cor->scale = scale;
402 	cor->id = id;
403 	cor->flags = flags;
404 }
405 
RE_BeginScene(const refdef_t * fd)406 void RE_BeginScene(const refdef_t *fd)
407 {
408 	memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) );
409 
410 	tr.refdef.x = fd->x;
411 	tr.refdef.y = fd->y;
412 	tr.refdef.width = fd->width;
413 	tr.refdef.height = fd->height;
414 	tr.refdef.fov_x = fd->fov_x;
415 	tr.refdef.fov_y = fd->fov_y;
416 
417 	VectorCopy( fd->vieworg, tr.refdef.vieworg );
418 	VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] );
419 	VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] );
420 	VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] );
421 
422 	tr.refdef.time = fd->time;
423 	tr.refdef.rdflags = fd->rdflags;
424 
425 	if ( fd->rdflags & RDF_SKYBOXPORTAL ) {
426 		skyboxportal = 1;
427 	}
428 
429 	if ( fd->rdflags & RDF_DRAWSKYBOX ) {
430 		drawskyboxportal = 1;
431 	} else {
432 		drawskyboxportal = 0;
433 	}
434 
435 	// copy the areamask data over and note if it has changed, which
436 	// will force a reset of the visible leafs even if the view hasn't moved
437 	tr.refdef.areamaskModified = qfalse;
438 	if ( !( tr.refdef.rdflags & RDF_NOWORLDMODEL ) ) {
439 		int areaDiff;
440 		int i;
441 
442 		// compare the area bits
443 		areaDiff = 0;
444 		for ( i = 0 ; i < MAX_MAP_AREA_BYTES / 4 ; i++ ) {
445 			areaDiff |= ( (int *)tr.refdef.areamask )[i] ^ ( (int *)fd->areamask )[i];
446 			( (int *)tr.refdef.areamask )[i] = ( (int *)fd->areamask )[i];
447 		}
448 
449 		if ( areaDiff ) {
450 			// a door just opened or something
451 			tr.refdef.areamaskModified = qtrue;
452 		}
453 	}
454 
455 	tr.refdef.sunDir[3] = 0.0f;
456 	tr.refdef.sunCol[3] = 1.0f;
457 	tr.refdef.sunAmbCol[3] = 1.0f;
458 
459 	VectorCopy(tr.sunDirection, tr.refdef.sunDir);
460 	if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){
461 		VectorSet(tr.refdef.sunCol, 0, 0, 0);
462 		VectorSet(tr.refdef.sunAmbCol, 0, 0, 0);
463 	}
464 	else
465 	{
466 		float scale = (1 << r_mapOverBrightBits->integer) / 255.0f;
467 
468 		if (r_forceSun->integer)
469 			VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol);
470 		else
471 			VectorScale(tr.sunLight, scale, tr.refdef.sunCol);
472 
473 		if (r_sunlightMode->integer == 1)
474 		{
475 			tr.refdef.sunAmbCol[0] =
476 			tr.refdef.sunAmbCol[1] =
477 			tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale;
478 		}
479 		else
480 		{
481 			if (r_forceSun->integer)
482 				VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol);
483 			else
484 				VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol);
485 		}
486 	}
487 
488 	if (r_forceAutoExposure->integer)
489 	{
490 		tr.refdef.autoExposureMinMax[0] = r_forceAutoExposureMin->value;
491 		tr.refdef.autoExposureMinMax[1] = r_forceAutoExposureMax->value;
492 	}
493 	else
494 	{
495 		tr.refdef.autoExposureMinMax[0] = tr.autoExposureMinMax[0];
496 		tr.refdef.autoExposureMinMax[1] = tr.autoExposureMinMax[1];
497 	}
498 
499 	if (r_forceToneMap->integer)
500 	{
501 		tr.refdef.toneMinAvgMaxLinear[0] = pow(2, r_forceToneMapMin->value);
502 		tr.refdef.toneMinAvgMaxLinear[1] = pow(2, r_forceToneMapAvg->value);
503 		tr.refdef.toneMinAvgMaxLinear[2] = pow(2, r_forceToneMapMax->value);
504 	}
505 	else
506 	{
507 		tr.refdef.toneMinAvgMaxLinear[0] = pow(2, tr.toneMinAvgMaxLevel[0]);
508 		tr.refdef.toneMinAvgMaxLinear[1] = pow(2, tr.toneMinAvgMaxLevel[1]);
509 		tr.refdef.toneMinAvgMaxLinear[2] = pow(2, tr.toneMinAvgMaxLevel[2]);
510 	}
511 
512 	// Makro - copy exta info if present
513 	if (fd->rdflags & RDF_EXTRA) {
514 		const refdefex_t* extra = (const refdefex_t*) (fd+1);
515 
516 		tr.refdef.blurFactor = extra->blurFactor;
517 
518 		if (fd->rdflags & RDF_SUNLIGHT)
519 		{
520 			VectorCopy(extra->sunDir,    tr.refdef.sunDir);
521 			VectorCopy(extra->sunCol,    tr.refdef.sunCol);
522 			VectorCopy(extra->sunAmbCol, tr.refdef.sunAmbCol);
523 		}
524 	}
525 	else
526 	{
527 		tr.refdef.blurFactor = 0.0f;
528 	}
529 
530 	// derived info
531 
532 	tr.refdef.floatTime = tr.refdef.time * 0.001;
533 
534 	tr.refdef.numDrawSurfs = r_firstSceneDrawSurf;
535 	tr.refdef.drawSurfs = backEndData->drawSurfs;
536 
537 	tr.refdef.num_entities = r_numentities - r_firstSceneEntity;
538 	tr.refdef.entities = &backEndData->entities[r_firstSceneEntity];
539 
540 	tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight;
541 	tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight];
542 
543 	tr.refdef.num_coronas = r_numcoronas - r_firstSceneCorona;
544 	tr.refdef.coronas = &backEndData->coronas[r_firstSceneCorona];
545 
546 	tr.refdef.numPolys = r_numpolys - r_firstScenePoly;
547 	tr.refdef.polys = &backEndData->polys[r_firstScenePoly];
548 
549 	tr.refdef.num_pshadows = 0;
550 	tr.refdef.pshadows = &backEndData->pshadows[0];
551 
552 	// turn off dynamic lighting globally by clearing all the
553 	// dlights if it needs to be disabled or if vertex lighting is enabled
554 	if ( /*r_dynamiclight->integer == 0 ||*/    // RF, disabled so we can force things like lightning dlights
555 		r_vertexLight->integer == 1 ||
556 		glConfig.hardwareType == GLHW_PERMEDIA2 ) {
557 		tr.refdef.num_dlights = 0;
558 	}
559 
560 	// a single frame may have multiple scenes draw inside it --
561 	// a 3D game view, 3D status bar renderings, 3D menus, etc.
562 	// They need to be distinguished by the light flare code, because
563 	// the visibility state for a given surface may be different in
564 	// each scene / view.
565 	tr.frameSceneNum++;
566 	tr.sceneCount++;
567 }
568 
RE_EndScene(void)569 void RE_EndScene(void)
570 {
571 	// the next scene rendered in this frame will tack on after this one
572 	r_firstSceneDrawSurf = tr.refdef.numDrawSurfs;
573 	r_firstSceneEntity = r_numentities;
574 	r_firstSceneDlight = r_numdlights;
575 	r_firstScenePoly = r_numpolys;
576 }
577 
578 /*
579 @@@@@@@@@@@@@@@@@@@@@
580 RE_RenderScene
581 
582 Draw a 3D view into a part of the window, then return
583 to 2D drawing.
584 
585 Rendering a scene may require multiple views to be rendered
586 to handle mirrors,
587 @@@@@@@@@@@@@@@@@@@@@
588 */
RE_RenderScene(const refdef_t * fd)589 void RE_RenderScene( const refdef_t *fd ) {
590 	viewParms_t		parms;
591 	int				startTime;
592 
593 	if ( !tr.registered ) {
594 		return;
595 	}
596 	GLimp_LogComment( "====== RE_RenderScene =====\n" );
597 
598 	if ( r_norefresh->integer ) {
599 		return;
600 	}
601 
602 	startTime = ri.Milliseconds();
603 
604 	if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
605 		ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel");
606 	}
607 
608 	RE_BeginScene(fd);
609 
610 	// SmileTheory: playing with shadow mapping
611 	if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2)
612 	{
613 		R_RenderDlightCubemaps(fd);
614 	}
615 
616 	/* playing with more shadows */
617 	if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && r_shadows->integer == 4)
618 	{
619 		R_RenderPshadowMaps(fd);
620 	}
621 
622 	// playing with even more shadows
623 	if(glRefConfig.framebufferObject && r_sunlightMode->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows))
624 	{
625 		if (r_shadowCascadeZFar->integer != 0)
626 		{
627 			R_RenderSunShadowMaps(fd, 0);
628 			R_RenderSunShadowMaps(fd, 1);
629 			R_RenderSunShadowMaps(fd, 2);
630 		}
631 		else
632 		{
633 			Mat4Zero(tr.refdef.sunShadowMvp[0]);
634 			Mat4Zero(tr.refdef.sunShadowMvp[1]);
635 			Mat4Zero(tr.refdef.sunShadowMvp[2]);
636 		}
637 
638 		// only rerender last cascade if sun has changed position
639 		if (r_forceSun->integer == 2 || !VectorCompare(tr.refdef.sunDir, tr.lastCascadeSunDirection))
640 		{
641 			VectorCopy(tr.refdef.sunDir, tr.lastCascadeSunDirection);
642 			R_RenderSunShadowMaps(fd, 3);
643 			Mat4Copy(tr.refdef.sunShadowMvp[3], tr.lastCascadeSunMvp);
644 		}
645 		else
646 		{
647 			Mat4Copy(tr.lastCascadeSunMvp, tr.refdef.sunShadowMvp[3]);
648 		}
649 	}
650 
651 	// playing with cube maps
652 	// this is where dynamic cubemaps would be rendered
653 	if (0) //(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ))
654 	{
655 		int i, j;
656 
657 		for (i = 0; i < tr.numCubemaps; i++)
658 		{
659 			for (j = 0; j < 6; j++)
660 			{
661 				R_RenderCubemapSide(i, j, qtrue);
662 			}
663 		}
664 	}
665 
666 	// setup view parms for the initial view
667 	//
668 	// set up viewport
669 	// The refdef takes 0-at-the-top y coordinates, so
670 	// convert to GL's 0-at-the-bottom space
671 	//
672 	memset( &parms, 0, sizeof( parms ) );
673 	parms.viewportX = tr.refdef.x;
674 	parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height );
675 	parms.viewportWidth = tr.refdef.width;
676 	parms.viewportHeight = tr.refdef.height;
677 	parms.isPortal = qfalse;
678 
679 	parms.fovX = tr.refdef.fov_x;
680 	parms.fovY = tr.refdef.fov_y;
681 
682 	parms.stereoFrame = tr.refdef.stereoFrame;
683 
684 	VectorCopy( fd->vieworg, parms.or.origin );
685 	VectorCopy( fd->viewaxis[0], parms.or.axis[0] );
686 	VectorCopy( fd->viewaxis[1], parms.or.axis[1] );
687 	VectorCopy( fd->viewaxis[2], parms.or.axis[2] );
688 
689 	VectorCopy( fd->vieworg, parms.pvsOrigin );
690 
691 	if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows))
692 	{
693 		parms.flags = VPF_USESUNLIGHT;
694 	}
695 
696 	R_RenderView( &parms );
697 
698 	if(!( fd->rdflags & RDF_NOWORLDMODEL ))
699 		R_AddPostProcessCmd();
700 
701 	RE_EndScene();
702 
703 	tr.frontEndMsec += ri.Milliseconds() - startTime;
704 }
705