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