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