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 "sys/platform.h"
30 #include "renderer/VertexCache.h"
31 #include "renderer/Cinematic.h"
32 
33 #include "renderer/tr_local.h"
34 
35 /*
36 
37   back end scene + lights rendering functions
38 
39 */
40 
41 
42 /*
43 =================
44 RB_DrawElementsImmediate
45 
46 Draws with immediate mode commands, which is going to be very slow.
47 This should never happen if the vertex cache is operating properly.
48 =================
49 */
RB_DrawElementsImmediate(const srfTriangles_t * tri)50 void RB_DrawElementsImmediate( const srfTriangles_t *tri ) {
51 
52 	backEnd.pc.c_drawElements++;
53 	backEnd.pc.c_drawIndexes += tri->numIndexes;
54 	backEnd.pc.c_drawVertexes += tri->numVerts;
55 
56 	if ( tri->ambientSurface != NULL  ) {
57 		if ( tri->indexes == tri->ambientSurface->indexes ) {
58 			backEnd.pc.c_drawRefIndexes += tri->numIndexes;
59 		}
60 		if ( tri->verts == tri->ambientSurface->verts ) {
61 			backEnd.pc.c_drawRefVertexes += tri->numVerts;
62 		}
63 	}
64 
65 	qglBegin( GL_TRIANGLES );
66 	for ( int i = 0 ; i < tri->numIndexes ; i++ ) {
67 		qglTexCoord2fv( tri->verts[ tri->indexes[i] ].st.ToFloatPtr() );
68 		qglVertex3fv( tri->verts[ tri->indexes[i] ].xyz.ToFloatPtr() );
69 	}
70 	qglEnd();
71 }
72 
73 
74 /*
75 ================
76 RB_DrawElementsWithCounters
77 ================
78 */
RB_DrawElementsWithCounters(const srfTriangles_t * tri)79 void RB_DrawElementsWithCounters( const srfTriangles_t *tri ) {
80 
81 	backEnd.pc.c_drawElements++;
82 	backEnd.pc.c_drawIndexes += tri->numIndexes;
83 	backEnd.pc.c_drawVertexes += tri->numVerts;
84 
85 	if ( tri->ambientSurface != NULL  ) {
86 		if ( tri->indexes == tri->ambientSurface->indexes ) {
87 			backEnd.pc.c_drawRefIndexes += tri->numIndexes;
88 		}
89 		if ( tri->verts == tri->ambientSurface->verts ) {
90 			backEnd.pc.c_drawRefVertexes += tri->numVerts;
91 		}
92 	}
93 
94 	if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
95 		qglDrawElements( GL_TRIANGLES,
96 						r_singleTriangle.GetBool() ? 3 : tri->numIndexes,
97 						GL_INDEX_TYPE,
98 						(int *)vertexCache.Position( tri->indexCache ) );
99 		backEnd.pc.c_vboIndexes += tri->numIndexes;
100 	} else {
101 		if ( r_useIndexBuffers.GetBool() ) {
102 			vertexCache.UnbindIndex();
103 		}
104 		qglDrawElements( GL_TRIANGLES,
105 						r_singleTriangle.GetBool() ? 3 : tri->numIndexes,
106 						GL_INDEX_TYPE,
107 						tri->indexes );
108 	}
109 }
110 
111 /*
112 ================
113 RB_DrawShadowElementsWithCounters
114 
115 May not use all the indexes in the surface if caps are skipped
116 ================
117 */
RB_DrawShadowElementsWithCounters(const srfTriangles_t * tri,int numIndexes)118 void RB_DrawShadowElementsWithCounters( const srfTriangles_t *tri, int numIndexes ) {
119 	backEnd.pc.c_shadowElements++;
120 	backEnd.pc.c_shadowIndexes += numIndexes;
121 	backEnd.pc.c_shadowVertexes += tri->numVerts;
122 
123 	if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
124 		qglDrawElements( GL_TRIANGLES,
125 						r_singleTriangle.GetBool() ? 3 : numIndexes,
126 						GL_INDEX_TYPE,
127 						(int *)vertexCache.Position( tri->indexCache ) );
128 		backEnd.pc.c_vboIndexes += numIndexes;
129 	} else {
130 		if ( r_useIndexBuffers.GetBool() ) {
131 			vertexCache.UnbindIndex();
132 		}
133 		qglDrawElements( GL_TRIANGLES,
134 						r_singleTriangle.GetBool() ? 3 : numIndexes,
135 						GL_INDEX_TYPE,
136 						tri->indexes );
137 	}
138 }
139 
140 
141 /*
142 ===============
143 RB_RenderTriangleSurface
144 
145 Sets texcoord and vertex pointers
146 ===============
147 */
RB_RenderTriangleSurface(const srfTriangles_t * tri)148 void RB_RenderTriangleSurface( const srfTriangles_t *tri ) {
149 	if ( !tri->ambientCache ) {
150 		RB_DrawElementsImmediate( tri );
151 		return;
152 	}
153 
154 
155 	idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
156 	qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
157 	qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
158 
159 	RB_DrawElementsWithCounters( tri );
160 }
161 
162 /*
163 ===============
164 RB_T_RenderTriangleSurface
165 
166 ===============
167 */
RB_T_RenderTriangleSurface(const drawSurf_t * surf)168 void RB_T_RenderTriangleSurface( const drawSurf_t *surf ) {
169 	RB_RenderTriangleSurface( surf->geo );
170 }
171 
172 /*
173 ===============
174 RB_EnterWeaponDepthHack
175 ===============
176 */
RB_EnterWeaponDepthHack()177 void RB_EnterWeaponDepthHack() {
178 	qglDepthRange( 0, 0.5 );
179 
180 	float	matrix[16];
181 
182 	memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) );
183 
184 	matrix[14] *= 0.25;
185 
186 	qglMatrixMode(GL_PROJECTION);
187 	qglLoadMatrixf( matrix );
188 	qglMatrixMode(GL_MODELVIEW);
189 }
190 
191 /*
192 ===============
193 RB_EnterModelDepthHack
194 ===============
195 */
RB_EnterModelDepthHack(float depth)196 void RB_EnterModelDepthHack( float depth ) {
197 	qglDepthRange( 0.0f, 1.0f );
198 
199 	float	matrix[16];
200 
201 	memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) );
202 
203 	matrix[14] -= depth;
204 
205 	qglMatrixMode(GL_PROJECTION);
206 	qglLoadMatrixf( matrix );
207 	qglMatrixMode(GL_MODELVIEW);
208 }
209 
210 /*
211 ===============
212 RB_LeaveDepthHack
213 ===============
214 */
RB_LeaveDepthHack()215 void RB_LeaveDepthHack() {
216 	qglDepthRange( 0, 1 );
217 
218 	qglMatrixMode(GL_PROJECTION);
219 	qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
220 	qglMatrixMode(GL_MODELVIEW);
221 }
222 
223 /*
224 ====================
225 RB_RenderDrawSurfListWithFunction
226 
227 The triangle functions can check backEnd.currentSpace != surf->space
228 to see if they need to perform any new matrix setup.  The modelview
229 matrix will already have been loaded, and backEnd.currentSpace will
230 be updated after the triangle function completes.
231 ====================
232 */
RB_RenderDrawSurfListWithFunction(drawSurf_t ** drawSurfs,int numDrawSurfs,void (* triFunc_)(const drawSurf_t *))233 void RB_RenderDrawSurfListWithFunction( drawSurf_t **drawSurfs, int numDrawSurfs,
234 											  void (*triFunc_)( const drawSurf_t *) ) {
235 	int				i;
236 	const drawSurf_t		*drawSurf;
237 
238 	backEnd.currentSpace = NULL;
239 
240 	for (i = 0  ; i < numDrawSurfs ; i++ ) {
241 		drawSurf = drawSurfs[i];
242 
243 		// change the matrix if needed
244 		if ( drawSurf->space != backEnd.currentSpace ) {
245 			qglLoadMatrixf( drawSurf->space->modelViewMatrix );
246 		}
247 
248 		if ( drawSurf->space->weaponDepthHack ) {
249 			RB_EnterWeaponDepthHack();
250 		}
251 
252 		if ( drawSurf->space->modelDepthHack != 0.0f ) {
253 			RB_EnterModelDepthHack( drawSurf->space->modelDepthHack );
254 		}
255 
256 		// change the scissor if needed
257 		if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) {
258 			backEnd.currentScissor = drawSurf->scissorRect;
259 			qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
260 				backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
261 				backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
262 				backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
263 		}
264 
265 		// render it
266 		triFunc_( drawSurf );
267 
268 		if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) {
269 			RB_LeaveDepthHack();
270 		}
271 
272 		backEnd.currentSpace = drawSurf->space;
273 	}
274 }
275 
276 /*
277 ======================
278 RB_RenderDrawSurfChainWithFunction
279 ======================
280 */
RB_RenderDrawSurfChainWithFunction(const drawSurf_t * drawSurfs,void (* triFunc_)(const drawSurf_t *))281 void RB_RenderDrawSurfChainWithFunction( const drawSurf_t *drawSurfs,
282 										void (*triFunc_)( const drawSurf_t *) ) {
283 	const drawSurf_t		*drawSurf;
284 
285 	backEnd.currentSpace = NULL;
286 
287 	for ( drawSurf = drawSurfs ; drawSurf ; drawSurf = drawSurf->nextOnLight ) {
288 		// change the matrix if needed
289 		if ( drawSurf->space != backEnd.currentSpace ) {
290 			qglLoadMatrixf( drawSurf->space->modelViewMatrix );
291 		}
292 
293 		if ( drawSurf->space->weaponDepthHack ) {
294 			RB_EnterWeaponDepthHack();
295 		}
296 
297 		if ( drawSurf->space->modelDepthHack ) {
298 			RB_EnterModelDepthHack( drawSurf->space->modelDepthHack );
299 		}
300 
301 		// change the scissor if needed
302 		if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) {
303 			backEnd.currentScissor = drawSurf->scissorRect;
304 			qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
305 				backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
306 				backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
307 				backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
308 		}
309 
310 		// render it
311 		triFunc_( drawSurf );
312 
313 		if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) {
314 			RB_LeaveDepthHack();
315 		}
316 
317 		backEnd.currentSpace = drawSurf->space;
318 	}
319 }
320 
321 /*
322 ======================
323 RB_GetShaderTextureMatrix
324 ======================
325 */
RB_GetShaderTextureMatrix(const float * shaderRegisters,const textureStage_t * texture,float matrix[16])326 void RB_GetShaderTextureMatrix( const float *shaderRegisters,
327 							   const textureStage_t *texture, float matrix[16] ) {
328 	matrix[0] = shaderRegisters[ texture->matrix[0][0] ];
329 	matrix[4] = shaderRegisters[ texture->matrix[0][1] ];
330 	matrix[8] = 0;
331 	matrix[12] = shaderRegisters[ texture->matrix[0][2] ];
332 
333 	// we attempt to keep scrolls from generating incredibly large texture values, but
334 	// center rotations and center scales can still generate offsets that need to be > 1
335 	if ( matrix[12] < -40 || matrix[12] > 40 ) {
336 		matrix[12] -= (int)matrix[12];
337 	}
338 
339 	matrix[1] = shaderRegisters[ texture->matrix[1][0] ];
340 	matrix[5] = shaderRegisters[ texture->matrix[1][1] ];
341 	matrix[9] = 0;
342 	matrix[13] = shaderRegisters[ texture->matrix[1][2] ];
343 	if ( matrix[13] < -40 || matrix[13] > 40 ) {
344 		matrix[13] -= (int)matrix[13];
345 	}
346 
347 	matrix[2] = 0;
348 	matrix[6] = 0;
349 	matrix[10] = 1;
350 	matrix[14] = 0;
351 
352 	matrix[3] = 0;
353 	matrix[7] = 0;
354 	matrix[11] = 0;
355 	matrix[15] = 1;
356 }
357 
358 /*
359 ======================
360 RB_LoadShaderTextureMatrix
361 ======================
362 */
RB_LoadShaderTextureMatrix(const float * shaderRegisters,const textureStage_t * texture)363 void RB_LoadShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture ) {
364 	float	matrix[16];
365 
366 	RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix );
367 	qglMatrixMode( GL_TEXTURE );
368 	qglLoadMatrixf( matrix );
369 	qglMatrixMode( GL_MODELVIEW );
370 }
371 
372 /*
373 ======================
374 RB_BindVariableStageImage
375 
376 Handles generating a cinematic frame if needed
377 ======================
378 */
RB_BindVariableStageImage(const textureStage_t * texture,const float * shaderRegisters)379 void RB_BindVariableStageImage( const textureStage_t *texture, const float *shaderRegisters ) {
380 	if ( texture->cinematic ) {
381 		cinData_t	cin;
382 
383 		if ( r_skipDynamicTextures.GetBool() ) {
384 			globalImages->defaultImage->Bind();
385 			return;
386 		}
387 
388 		// offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?)
389 		// We make no attempt to optimize for multiple identical cinematics being in view, or
390 		// for cinematics going at a lower framerate than the renderer.
391 		cin = texture->cinematic->ImageForTime( (int)(1000 * ( backEnd.viewDef->floatTime + backEnd.viewDef->renderView.shaderParms[11] ) ) );
392 
393 		if ( cin.image ) {
394 			globalImages->cinematicImage->UploadScratch( cin.image, cin.imageWidth, cin.imageHeight );
395 		} else {
396 			globalImages->blackImage->Bind();
397 		}
398 	} else {
399 		//FIXME: see why image is invalid
400 		if (texture->image) {
401 			texture->image->Bind();
402 		}
403 	}
404 }
405 
406 /*
407 ======================
408 RB_BindStageTexture
409 ======================
410 */
RB_BindStageTexture(const float * shaderRegisters,const textureStage_t * texture,const drawSurf_t * surf)411 void RB_BindStageTexture( const float *shaderRegisters, const textureStage_t *texture, const drawSurf_t *surf ) {
412 	// image
413 	RB_BindVariableStageImage( texture, shaderRegisters );
414 
415 	// texgens
416 	if ( texture->texgen == TG_DIFFUSE_CUBE ) {
417 		qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() );
418 	}
419 	if ( texture->texgen == TG_SKYBOX_CUBE || texture->texgen == TG_WOBBLESKY_CUBE ) {
420 		qglTexCoordPointer( 3, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) );
421 	}
422 	if ( texture->texgen == TG_REFLECT_CUBE ) {
423 		qglEnable( GL_TEXTURE_GEN_S );
424 		qglEnable( GL_TEXTURE_GEN_T );
425 		qglEnable( GL_TEXTURE_GEN_R );
426 		qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
427 		qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
428 		qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
429 		qglEnableClientState( GL_NORMAL_ARRAY );
430 		qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() );
431 
432 		qglMatrixMode( GL_TEXTURE );
433 		float	mat[16];
434 
435 		R_TransposeGLMatrix( backEnd.viewDef->worldSpace.modelViewMatrix, mat );
436 
437 		qglLoadMatrixf( mat );
438 		qglMatrixMode( GL_MODELVIEW );
439 	}
440 
441 	// matrix
442 	if ( texture->hasMatrix ) {
443 		RB_LoadShaderTextureMatrix( shaderRegisters, texture );
444 	}
445 }
446 
447 /*
448 ======================
449 RB_FinishStageTexture
450 ======================
451 */
RB_FinishStageTexture(const textureStage_t * texture,const drawSurf_t * surf)452 void RB_FinishStageTexture( const textureStage_t *texture, const drawSurf_t *surf ) {
453 	if ( texture->texgen == TG_DIFFUSE_CUBE || texture->texgen == TG_SKYBOX_CUBE
454 		|| texture->texgen == TG_WOBBLESKY_CUBE ) {
455 		qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ),
456 			(void *)&(((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->st) );
457 	}
458 
459 	if ( texture->texgen == TG_REFLECT_CUBE ) {
460 		qglDisable( GL_TEXTURE_GEN_S );
461 		qglDisable( GL_TEXTURE_GEN_T );
462 		qglDisable( GL_TEXTURE_GEN_R );
463 		qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
464 		qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
465 		qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
466 		qglDisableClientState( GL_NORMAL_ARRAY );
467 
468 		qglMatrixMode( GL_TEXTURE );
469 		qglLoadIdentity();
470 		qglMatrixMode( GL_MODELVIEW );
471 	}
472 
473 	if ( texture->hasMatrix ) {
474 		qglMatrixMode( GL_TEXTURE );
475 		qglLoadIdentity();
476 		qglMatrixMode( GL_MODELVIEW );
477 	}
478 }
479 
480 
481 
482 //=============================================================================================
483 
484 
485 /*
486 =================
487 RB_DetermineLightScale
488 
489 Sets:
490 backEnd.lightScale
491 backEnd.overBright
492 
493 Find out how much we are going to need to overscale the lighting, so we
494 can down modulate the pre-lighting passes.
495 
496 We only look at light calculations, but an argument could be made that
497 we should also look at surface evaluations, which would let surfaces
498 overbright past 1.0
499 =================
500 */
RB_DetermineLightScale(void)501 void RB_DetermineLightScale( void ) {
502 	viewLight_t			*vLight;
503 	const idMaterial	*shader;
504 	float				max;
505 	int					i, j, numStages;
506 	const shaderStage_t	*stage;
507 
508 	// the light scale will be based on the largest color component of any surface
509 	// that will be drawn.
510 	// should we consider separating rgb scales?
511 
512 	// if there are no lights, this will remain at 1.0, so GUI-only
513 	// rendering will not lose any bits of precision
514 	max = 1.0;
515 
516 	for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
517 		// lights with no surfaces or shaderparms may still be present
518 		// for debug display
519 		if ( !vLight->localInteractions && !vLight->globalInteractions
520 			&& !vLight->translucentInteractions ) {
521 			continue;
522 		}
523 
524 		shader = vLight->lightShader;
525 		numStages = shader->GetNumStages();
526 		for ( i = 0 ; i < numStages ; i++ ) {
527 			stage = shader->GetStage( i );
528 			for ( j = 0 ; j < 3 ; j++ ) {
529 				float	v = r_lightScale.GetFloat() * vLight->shaderRegisters[ stage->color.registers[j] ];
530 				if ( v > max ) {
531 					max = v;
532 				}
533 			}
534 		}
535 	}
536 
537 	backEnd.pc.maxLightValue = max;
538 	if ( max <= tr.backEndRendererMaxLight ) {
539 		backEnd.lightScale = r_lightScale.GetFloat();
540 		backEnd.overBright = 1.0;
541 	} else {
542 		backEnd.lightScale = r_lightScale.GetFloat() * tr.backEndRendererMaxLight / max;
543 		backEnd.overBright = max / tr.backEndRendererMaxLight;
544 	}
545 }
546 
547 
548 /*
549 =================
550 RB_BeginDrawingView
551 
552 Any mirrored or portaled views have already been drawn, so prepare
553 to actually render the visible surfaces for this view
554 =================
555 */
RB_BeginDrawingView(void)556 void RB_BeginDrawingView (void) {
557 	// set the modelview matrix for the viewer
558 	qglMatrixMode(GL_PROJECTION);
559 	qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
560 	qglMatrixMode(GL_MODELVIEW);
561 
562 	// set the window clipping
563 	qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
564 		tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
565 		backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
566 		backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 );
567 
568 	// the scissor may be smaller than the viewport for subviews
569 	qglScissor( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1,
570 		tr.viewportOffset[1] + backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1,
571 		backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1,
572 		backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 );
573 	backEnd.currentScissor = backEnd.viewDef->scissor;
574 
575 	// ensures that depth writes are enabled for the depth clear
576 	GL_State( GLS_DEFAULT );
577 
578 	// we don't have to clear the depth / stencil buffer for 2D rendering
579 	if ( backEnd.viewDef->viewEntitys ) {
580 		qglStencilMask( 0xff );
581 		// some cards may have 7 bit stencil buffers, so don't assume this
582 		// should be 128
583 		qglClearStencil( 1<<(glConfig.stencilBits-1) );
584 		qglClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
585 		qglEnable( GL_DEPTH_TEST );
586 	} else {
587 		qglDisable( GL_DEPTH_TEST );
588 		qglDisable( GL_STENCIL_TEST );
589 	}
590 
591 	backEnd.glState.faceCulling = -1;		// force face culling to set next time
592 	GL_Cull( CT_FRONT_SIDED );
593 
594 }
595 
596 /*
597 ==================
598 R_SetDrawInteractions
599 ==================
600 */
R_SetDrawInteraction(const shaderStage_t * surfaceStage,const float * surfaceRegs,idImage ** image,idVec4 matrix[2],float color[4])601 void R_SetDrawInteraction( const shaderStage_t *surfaceStage, const float *surfaceRegs,
602 						  idImage **image, idVec4 matrix[2], float color[4] ) {
603 	*image = surfaceStage->texture.image;
604 	if ( surfaceStage->texture.hasMatrix ) {
605 		matrix[0][0] = surfaceRegs[surfaceStage->texture.matrix[0][0]];
606 		matrix[0][1] = surfaceRegs[surfaceStage->texture.matrix[0][1]];
607 		matrix[0][2] = 0;
608 		matrix[0][3] = surfaceRegs[surfaceStage->texture.matrix[0][2]];
609 
610 		matrix[1][0] = surfaceRegs[surfaceStage->texture.matrix[1][0]];
611 		matrix[1][1] = surfaceRegs[surfaceStage->texture.matrix[1][1]];
612 		matrix[1][2] = 0;
613 		matrix[1][3] = surfaceRegs[surfaceStage->texture.matrix[1][2]];
614 
615 		// we attempt to keep scrolls from generating incredibly large texture values, but
616 		// center rotations and center scales can still generate offsets that need to be > 1
617 		if ( matrix[0][3] < -40 || matrix[0][3] > 40 ) {
618 			matrix[0][3] -= (int)matrix[0][3];
619 		}
620 		if ( matrix[1][3] < -40 || matrix[1][3] > 40 ) {
621 			matrix[1][3] -= (int)matrix[1][3];
622 		}
623 	} else {
624 		matrix[0][0] = 1;
625 		matrix[0][1] = 0;
626 		matrix[0][2] = 0;
627 		matrix[0][3] = 0;
628 
629 		matrix[1][0] = 0;
630 		matrix[1][1] = 1;
631 		matrix[1][2] = 0;
632 		matrix[1][3] = 0;
633 	}
634 
635 	if ( color ) {
636 		for ( int i = 0 ; i < 4 ; i++ ) {
637 			color[i] = surfaceRegs[surfaceStage->color.registers[i]];
638 			// clamp here, so card with greater range don't look different.
639 			// we could perform overbrighting like we do for lights, but
640 			// it doesn't currently look worth it.
641 			if ( color[i] < 0 ) {
642 				color[i] = 0;
643 			} else if ( color[i] > 1.0 ) {
644 				color[i] = 1.0;
645 			}
646 		}
647 	}
648 }
649 
650 /*
651 =================
652 RB_SubmittInteraction
653 =================
654 */
RB_SubmittInteraction(drawInteraction_t * din,void (* DrawInteraction)(const drawInteraction_t *))655 static void RB_SubmittInteraction( drawInteraction_t *din, void (*DrawInteraction)(const drawInteraction_t *) ) {
656 	if ( !din->bumpImage ) {
657 		return;
658 	}
659 
660 	if ( !din->diffuseImage || r_skipDiffuse.GetBool() ) {
661 		din->diffuseImage = globalImages->blackImage;
662 	}
663 	if ( !din->specularImage || r_skipSpecular.GetBool() || din->ambientLight ) {
664 		din->specularImage = globalImages->blackImage;
665 	}
666 	if ( !din->bumpImage || r_skipBump.GetBool() ) {
667 		din->bumpImage = globalImages->flatNormalMap;
668 	}
669 
670 	// if we wouldn't draw anything, don't call the Draw function
671 	if (
672 		( ( din->diffuseColor[0] > 0 ||
673 		din->diffuseColor[1] > 0 ||
674 		din->diffuseColor[2] > 0 ) && din->diffuseImage != globalImages->blackImage )
675 		|| ( ( din->specularColor[0] > 0 ||
676 		din->specularColor[1] > 0 ||
677 		din->specularColor[2] > 0 ) && din->specularImage != globalImages->blackImage ) ) {
678 		DrawInteraction( din );
679 	}
680 }
681 
682 /*
683 =============
684 RB_CreateSingleDrawInteractions
685 
686 This can be used by different draw_* backends to decompose a complex light / surface
687 interaction into primitive interactions
688 =============
689 */
RB_CreateSingleDrawInteractions(const drawSurf_t * surf,void (* DrawInteraction)(const drawInteraction_t *))690 void RB_CreateSingleDrawInteractions( const drawSurf_t *surf, void (*DrawInteraction)(const drawInteraction_t *) ) {
691 	const idMaterial	*surfaceShader = surf->material;
692 	const float			*surfaceRegs = surf->shaderRegisters;
693 	const viewLight_t	*vLight = backEnd.vLight;
694 	const idMaterial	*lightShader = vLight->lightShader;
695 	const float			*lightRegs = vLight->shaderRegisters;
696 	drawInteraction_t	inter;
697 
698 	if ( r_skipInteractions.GetBool() || !surf->geo || !surf->geo->ambientCache ) {
699 		return;
700 	}
701 
702 	// change the matrix and light projection vectors if needed
703 	if ( surf->space != backEnd.currentSpace ) {
704 		backEnd.currentSpace = surf->space;
705 		qglLoadMatrixf( surf->space->modelViewMatrix );
706 	}
707 
708 	// change the scissor if needed
709 	if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) {
710 		backEnd.currentScissor = surf->scissorRect;
711 		qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
712 			backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
713 			backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
714 			backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
715 	}
716 
717 	// hack depth range if needed
718 	if ( surf->space->weaponDepthHack ) {
719 		RB_EnterWeaponDepthHack();
720 	}
721 
722 	if ( surf->space->modelDepthHack ) {
723 		RB_EnterModelDepthHack( surf->space->modelDepthHack );
724 	}
725 
726 	inter.surf = surf;
727 	inter.lightFalloffImage = vLight->falloffImage;
728 
729 	R_GlobalPointToLocal( surf->space->modelMatrix, vLight->globalLightOrigin, inter.localLightOrigin.ToVec3() );
730 	R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, inter.localViewOrigin.ToVec3() );
731 	inter.localLightOrigin[3] = 0;
732 	inter.localViewOrigin[3] = 1;
733 	inter.ambientLight = lightShader->IsAmbientLight();
734 
735 	// the base projections may be modified by texture matrix on light stages
736 	idPlane lightProject[4];
737 	for ( int i = 0 ; i < 4 ; i++ ) {
738 		R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] );
739 	}
740 
741 	for ( int lightStageNum = 0 ; lightStageNum < lightShader->GetNumStages() ; lightStageNum++ ) {
742 		const shaderStage_t	*lightStage = lightShader->GetStage( lightStageNum );
743 
744 		// ignore stages that fail the condition
745 		if ( !lightRegs[ lightStage->conditionRegister ] ) {
746 			continue;
747 		}
748 
749 		inter.lightImage = lightStage->texture.image;
750 
751 		memcpy( inter.lightProjection, lightProject, sizeof( inter.lightProjection ) );
752 		// now multiply the texgen by the light texture matrix
753 		if ( lightStage->texture.hasMatrix ) {
754 			RB_GetShaderTextureMatrix( lightRegs, &lightStage->texture, backEnd.lightTextureMatrix );
755 			RB_BakeTextureMatrixIntoTexgen( reinterpret_cast<class idPlane *>(inter.lightProjection), backEnd.lightTextureMatrix );
756 		}
757 
758 		inter.bumpImage = NULL;
759 		inter.specularImage = NULL;
760 		inter.diffuseImage = NULL;
761 		inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 0;
762 		inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0;
763 
764 		float lightColor[4];
765 
766 		// backEnd.lightScale is calculated so that lightColor[] will never exceed
767 		// tr.backEndRendererMaxLight
768 		lightColor[0] = backEnd.lightScale * lightRegs[ lightStage->color.registers[0] ];
769 		lightColor[1] = backEnd.lightScale * lightRegs[ lightStage->color.registers[1] ];
770 		lightColor[2] = backEnd.lightScale * lightRegs[ lightStage->color.registers[2] ];
771 		lightColor[3] = lightRegs[ lightStage->color.registers[3] ];
772 
773 		// go through the individual stages
774 		for ( int surfaceStageNum = 0 ; surfaceStageNum < surfaceShader->GetNumStages() ; surfaceStageNum++ ) {
775 			const shaderStage_t	*surfaceStage = surfaceShader->GetStage( surfaceStageNum );
776 
777 			switch( surfaceStage->lighting ) {
778 				case SL_AMBIENT: {
779 					// ignore ambient stages while drawing interactions
780 					break;
781 				}
782 				case SL_BUMP: {
783 					// ignore stage that fails the condition
784 					if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
785 						break;
786 					}
787 					// draw any previous interaction
788 					RB_SubmittInteraction( &inter, DrawInteraction );
789 					inter.diffuseImage = NULL;
790 					inter.specularImage = NULL;
791 					R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.bumpImage, inter.bumpMatrix, NULL );
792 					break;
793 				}
794 				case SL_DIFFUSE: {
795 					// ignore stage that fails the condition
796 					if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
797 						break;
798 					}
799 					if ( inter.diffuseImage ) {
800 						RB_SubmittInteraction( &inter, DrawInteraction );
801 					}
802 					R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.diffuseImage,
803 											inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() );
804 					inter.diffuseColor[0] *= lightColor[0];
805 					inter.diffuseColor[1] *= lightColor[1];
806 					inter.diffuseColor[2] *= lightColor[2];
807 					inter.diffuseColor[3] *= lightColor[3];
808 					inter.vertexColor = surfaceStage->vertexColor;
809 					break;
810 				}
811 				case SL_SPECULAR: {
812 					// ignore stage that fails the condition
813 					if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
814 						break;
815 					}
816 					if ( inter.specularImage ) {
817 						RB_SubmittInteraction( &inter, DrawInteraction );
818 					}
819 					R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.specularImage,
820 											inter.specularMatrix, inter.specularColor.ToFloatPtr() );
821 					inter.specularColor[0] *= lightColor[0];
822 					inter.specularColor[1] *= lightColor[1];
823 					inter.specularColor[2] *= lightColor[2];
824 					inter.specularColor[3] *= lightColor[3];
825 					inter.vertexColor = surfaceStage->vertexColor;
826 					break;
827 				}
828 			}
829 		}
830 
831 		// draw the final interaction
832 		RB_SubmittInteraction( &inter, DrawInteraction );
833 	}
834 
835 	// unhack depth range if needed
836 	if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) {
837 		RB_LeaveDepthHack();
838 	}
839 }
840 
841 /*
842 =============
843 RB_DrawView
844 =============
845 */
RB_DrawView(const void * data)846 void RB_DrawView( const void *data ) {
847 	const drawSurfsCommand_t	*cmd;
848 
849 	cmd = (const drawSurfsCommand_t *)data;
850 
851 	backEnd.viewDef = cmd->viewDef;
852 
853 	// we will need to do a new copyTexSubImage of the screen
854 	// when a SS_POST_PROCESS material is used
855 	backEnd.currentRenderCopied = false;
856 
857 	// if there aren't any drawsurfs, do nothing
858 	if ( !backEnd.viewDef->numDrawSurfs ) {
859 		return;
860 	}
861 
862 	// skip render bypasses everything that has models, assuming
863 	// them to be 3D views, but leaves 2D rendering visible
864 	if ( r_skipRender.GetBool() && backEnd.viewDef->viewEntitys ) {
865 		return;
866 	}
867 
868 	// skip render context sets the gl context to NULL,
869 	// which should factor out the API cost, under the assumption
870 	// that all gl calls just return if the context isn't valid
871 	if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) {
872 		GLimp_DeactivateContext();
873 	}
874 
875 	backEnd.pc.c_surfaces += backEnd.viewDef->numDrawSurfs;
876 
877 	RB_ShowOverdraw();
878 
879 	// render the scene, jumping to the hardware specific interaction renderers
880 	RB_STD_DrawView();
881 
882 	// restore the context for 2D drawing if we were stubbing it out
883 	if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) {
884 		GLimp_ActivateContext();
885 		RB_SetDefaultGLState();
886 	}
887 }
888