]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/draw_nv10.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / renderer / draw_nv10.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 #include "../idlib/precompiled.h"
29 #pragma hdrstop
30
31 #include "tr_local.h"
32
33
34 /*
35 ==================
36 RB_RenderInteraction
37
38 backEnd.vLight
39 backEnd.lightScale
40
41
42 backEnd.depthFunc must be equal for alpha tested surfaces to work right,
43 it is set to lessThan for blended transparent surfaces
44
45 This expects a bumpmap stage before a diffuse stage before a specular stage
46 The material code is responsible for guaranteeing that, but conditional stages
47 can still make it invalid.
48
49 you can't blend two bumpmaps, but you can change bump maps between
50 blended diffuse / specular maps to get the same effect
51
52
53 ==================
54 */
55 static void RB_RenderInteraction( const drawSurf_t *surf ) {
56         const idMaterial        *surfaceShader = surf->material;
57         const float                     *surfaceRegs = surf->shaderRegisters;
58         const viewLight_t       *vLight = backEnd.vLight;
59         const idMaterial        *lightShader = vLight->lightShader;
60         const float                     *lightRegs = vLight->shaderRegisters;
61         static idPlane          lightProject[4];        // reused across function calls
62         const srfTriangles_t    *tri = surf->geo;
63         const shaderStage_t     *lastBumpStage = NULL;
64
65         RB_LogComment( "---------- RB_RenderInteraction %s on %s ----------\n", 
66                 lightShader->GetName(), surfaceShader->GetName() );
67
68         // change the matrix and light projection vectors if needed
69         if ( surf->space != backEnd.currentSpace ) {
70                 backEnd.currentSpace = surf->space;
71                 qglLoadMatrixf( surf->space->modelViewMatrix );
72
73                 for ( int i = 0 ; i < 4 ; i++ ) {
74                         R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] );
75                 }
76         }
77
78         // change the scissor if needed
79         if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) {
80                 backEnd.currentScissor = surf->scissorRect;
81                 qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, 
82                         backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
83                         backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
84                         backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
85         }
86
87         // hack depth range if needed
88         if ( surf->space->weaponDepthHack ) {
89                 RB_EnterWeaponDepthHack();
90         }
91
92         if ( surf->space->modelDepthHack != 0.0f ) {
93                 RB_EnterModelDepthHack( surf->space->modelDepthHack );
94         }
95
96
97         // set the vertex arrays, which may not all be enabled on a given pass
98         idDrawVert      *ac = (idDrawVert *)vertexCache.Position(tri->ambientCache);
99         qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
100         GL_SelectTexture( 0 );
101         qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
102         qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color );
103
104
105         // go through the individual stages
106         for ( int i = 0 ; i < surfaceShader->GetNumStages() ; i++ ) {
107                 const shaderStage_t     *surfaceStage = surfaceShader->GetStage( i );
108
109                 // ignore ambient stages while drawing interactions
110                 if ( surfaceStage->lighting == SL_AMBIENT ) {
111                         continue;
112                 }
113
114                 // ignore stages that fail the condition
115                 if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
116                         continue;
117                 }
118
119                 //-----------------------------------------------------
120                 //
121                 // bump / falloff
122                 //
123                 //-----------------------------------------------------
124                 if ( surfaceStage->lighting == SL_BUMP ) {
125                         // render light falloff * bumpmap lighting
126
127                         if ( surfaceStage->vertexColor != SVC_IGNORE ) {
128                                 common->Printf( "shader %s: vertexColor on a bump stage\n",
129                                         surfaceShader->GetName() );
130                         }
131
132                         // check for RGBA modulations in the stage, which are also illegal?
133
134                         // save the bump map stage for the specular calculation and diffuse
135                         // error checking
136                         lastBumpStage = surfaceStage;
137
138                         //
139                         // ambient lights combine non-directional bump and falloff
140                         // and write to the alpha channel
141                         //
142                         if ( lightShader->IsAmbientLight() ) {
143                                 GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
144
145                                 // texture 0 will be the per-surface bump map
146                                 GL_SelectTexture( 0 );
147                                 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
148
149                                 RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
150                                 // development aid
151                                 if ( r_skipBump.GetBool() ) {
152                                         globalImages->flatNormalMap->Bind();
153                                 }
154
155                                 // texture 1 will be the light falloff
156                                 GL_SelectTexture( 1 );
157
158                                 qglEnable( GL_TEXTURE_GEN_S );
159                                 qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[3].ToFloatPtr() );
160                                 qglTexCoord2f( 0, 0.5 );
161                                 vLight->falloffImage->Bind();
162
163                                 qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
164
165                                 // set the constant color to a bit of an angle
166                                 qglCombinerParameterfvNV( GL_CONSTANT_COLOR0_NV, tr.ambientLightVector.ToFloatPtr() );
167
168                                 // stage 0 sets primary_color = bump dot constant color
169                                 qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, 
170                                         GL_CONSTANT_COLOR0_NV, GL_EXPAND_NORMAL_NV, GL_RGB );
171                                 qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
172                                         GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
173                                 qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, 
174                                         GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
175                                         GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
176
177                                 // stage 1 alpha sets primary_color = primary_color * falloff
178                                 qglCombinerInputNV( GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_A_NV, 
179                                         GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
180                                 qglCombinerInputNV( GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_B_NV, 
181                                         GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
182                                 qglCombinerOutputNV( GL_COMBINER1_NV, GL_ALPHA, 
183                                         GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
184                                         GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
185
186                                 // final combiner takes the result for the alpha channel
187                                 qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_ZERO,
188                                         GL_UNSIGNED_IDENTITY_NV, GL_RGB );
189                                 qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO,
190                                         GL_UNSIGNED_IDENTITY_NV, GL_RGB );
191                                 qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
192                                         GL_UNSIGNED_IDENTITY_NV, GL_RGB );
193                                 qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO,
194                                         GL_UNSIGNED_IDENTITY_NV, GL_RGB );
195                                 qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_PRIMARY_COLOR_NV,
196                                         GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
197
198                                 // draw it
199                                 RB_DrawElementsWithCounters( tri );
200
201                                 globalImages->BindNull();
202                                 qglDisable( GL_TEXTURE_GEN_S );
203
204                                 GL_SelectTexture( 0 );
205                                 RB_FinishStageTexture( &surfaceStage->texture, surf );
206                                 continue;
207                         }
208
209                         //
210                         // draw light falloff to the alpha channel
211                         //
212                         GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
213                         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
214                         qglDisableClientState( GL_COLOR_ARRAY );
215                         qglEnable( GL_TEXTURE_GEN_S );
216                         qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[3].ToFloatPtr() );
217                         qglTexCoord2f( 0, 0.5 );
218                         vLight->falloffImage->Bind();
219
220                         // make sure a combiner output doesn't step on the texture
221                         qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
222                         qglCombinerOutputNV( GL_COMBINER0_NV, GL_ALPHA, 
223                                 GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV,
224                                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
225
226                         // final combiner
227                         qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_ZERO,
228                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
229                         qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO,
230                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
231                         qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
232                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
233                         qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO,
234                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
235                         qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_TEXTURE0_ARB,
236                                 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
237
238                         // draw it
239                         RB_DrawElementsWithCounters( tri );
240
241                         qglDisable( GL_TEXTURE_GEN_S );
242
243                         //
244                         // draw the bump map result onto the alpha channel
245                         //
246                         GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ZERO | GLS_COLORMASK | GLS_DEPTHMASK 
247                                 | backEnd.depthFunc );
248
249                         // texture 0 will be the per-surface bump map
250                         GL_SelectTexture( 0 );
251                         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
252                         RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
253
254                         // texture 1 is the normalization cube map
255                         // the texccords are the non-normalized vector towards the light origin
256                         GL_SelectTexture( 1 );
257                         globalImages->normalCubeMapImage->Bind();
258                         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
259                         qglTexCoordPointer( 3, GL_FLOAT, sizeof( lightingCache_t ), ((lightingCache_t *)vertexCache.Position(tri->lightingCache))->localLightVector.ToFloatPtr() );
260
261                         qglDisableClientState( GL_COLOR_ARRAY );
262
263                         // program the nvidia register combiners
264                         // I just want alpha = Dot( texture0, texture1 )
265                         qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
266
267                         // stage 0 rgb performs the dot product
268                         // SPARE0 = TEXTURE0 dot TEXTURE1
269                         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, 
270                                 GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
271                         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
272                                 GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
273                         qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, 
274                                 GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
275                                 GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
276
277                         // final combiner just takes the dot result and puts it in alpha
278                         qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_SPARE0_NV,
279                                 GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
280
281                         // draw it
282                         RB_DrawElementsWithCounters( tri );
283
284                         globalImages->BindNull();
285                         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
286
287                         GL_SelectTexture( 0 );
288                         RB_FinishStageTexture( &surfaceStage->texture, surf );
289                         continue;
290                 }
291
292                 if ( surfaceStage->lighting == SL_DIFFUSE ) {
293                         if ( !lastBumpStage ) {
294                                 common->Printf( "shader %s: diffuse stage without a preceeding bumpmap stage\n",
295                                         surfaceShader->GetName() );
296                                 continue;
297                         }
298                 }
299
300                 //-----------------------------------------------------
301                 //
302                 // specular exponent modification of the bump / falloff
303                 //
304                 //-----------------------------------------------------
305                 if ( surfaceStage->lighting == SL_SPECULAR ) {
306                         // put specular bump map into alpha channel, then treat as a diffuse
307
308                         // allow the specular to be skipped as a user speed optimization
309                         if ( r_skipSpecular.GetBool() ) {
310                                 continue;
311                         }
312
313                         // ambient lights don't have specular
314                         if ( lightShader->IsAmbientLight() ) {
315                                 continue;
316                         }
317
318                         if ( !lastBumpStage ) {
319                                 common->Printf( "shader %s: specular stage without a preceeding bumpmap stage\n",
320                                         surfaceShader->GetName() );
321                                 continue;
322                         }
323
324                         GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_SRC_ALPHA | GLS_COLORMASK | GLS_DEPTHMASK 
325                                 | backEnd.depthFunc );
326
327                         // texture 0 will be the per-surface bump map
328                         GL_SelectTexture( 0 );
329                         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
330                         RB_BindStageTexture( surfaceRegs, &lastBumpStage->texture, surf );
331
332                         // development aid
333                         if ( r_skipBump.GetBool() ) {
334                                 globalImages->flatNormalMap->Bind();
335                         }
336
337                         // texture 1 is the normalization cube map
338                         // indexed by the dynamic halfangle texcoords
339                         GL_SelectTexture( 1 );
340                         globalImages->normalCubeMapImage->Bind();
341                         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
342                         qglTexCoordPointer( 4, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) );
343
344                         // program the nvidia register combiners
345                         qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
346
347                         // stage 0 rgb performs the dot product
348                         // GL_PRIMARY_COLOR_NV = ( TEXTURE0 dot TEXTURE1 - 0.5 ) * 2
349                         // the scale and bias steepen the specular curve
350                         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, 
351                                 GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
352                         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
353                                 GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
354                         qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, 
355                                 GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
356                                 GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_TRUE, GL_FALSE, GL_FALSE );
357
358                         // stage 0 alpha does nothing
359                         qglCombinerOutputNV( GL_COMBINER0_NV, GL_ALPHA, 
360                                 GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV,
361                                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
362
363                         // stage 1 rgb does nothing
364                         qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB, 
365                                 GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
366                                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
367
368                         // stage 1 alpha takes bump * bump
369                         // PRIMARY_COLOR = ( GL_PRIMARY_COLOR_NV * GL_PRIMARY_COLOR_NV - 0.5 ) * 2
370                         // the scale and bias steepen the specular curve
371                         qglCombinerInputNV( GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_A_NV, 
372                                 GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
373                         qglCombinerInputNV( GL_COMBINER1_NV, GL_ALPHA, GL_VARIABLE_B_NV, 
374                                 GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
375                         qglCombinerOutputNV( GL_COMBINER1_NV, GL_ALPHA, 
376                                 GL_PRIMARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
377                                 GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE );
378
379                         // final combiner
380                         qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_PRIMARY_COLOR_NV,
381                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
382                         qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_ZERO,
383                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
384                         qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO,
385                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
386                         qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
387                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
388                         qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_PRIMARY_COLOR_NV,
389                                 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
390
391                         // draw it
392                         RB_DrawElementsWithCounters( tri );
393
394                         globalImages->BindNull();
395                         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
396
397                         GL_SelectTexture( 0 );
398
399                         RB_FinishStageTexture( &lastBumpStage->texture, surf );
400
401                         // the bump map in the alpha channel is now corrupted, so a normal diffuse
402                         // map can't be drawn unless a new bumpmap is put down
403                         lastBumpStage = NULL;
404
405                         // fall through to the common handling of diffuse and specular projected lighting
406                 }
407
408                 //-----------------------------------------------------
409                 //
410                 // projected light / surface color for diffuse and specular maps
411                 //
412                 //-----------------------------------------------------
413                 if ( surfaceStage->lighting == SL_DIFFUSE || surfaceStage->lighting == SL_SPECULAR ) {
414                         // don't trash alpha
415                         GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_ALPHAMASK | GLS_DEPTHMASK 
416                         | backEnd.depthFunc );
417
418                         // texture 0 will get the surface color texture
419                         GL_SelectTexture( 0 );
420                         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
421                         RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
422
423                         // development aid
424                         if ( ( surfaceStage->lighting == SL_DIFFUSE && r_skipDiffuse.GetBool() )
425                                 || ( surfaceStage->lighting == SL_SPECULAR && r_skipSpecular.GetBool() ) ) {
426                                 globalImages->blackImage->Bind();
427                         }
428
429                         // texture 1 will get the light projected texture
430                         GL_SelectTexture( 1 );
431                         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
432                         qglEnable( GL_TEXTURE_GEN_S );
433                         qglEnable( GL_TEXTURE_GEN_T );
434                         qglEnable( GL_TEXTURE_GEN_Q );
435                         qglTexGenfv( GL_S, GL_OBJECT_PLANE, lightProject[0].ToFloatPtr() );
436                         qglTexGenfv( GL_T, GL_OBJECT_PLANE, lightProject[1].ToFloatPtr() );
437                         qglTexGenfv( GL_Q, GL_OBJECT_PLANE, lightProject[2].ToFloatPtr() );
438
439                         // texture0 * texture1 * primaryColor * constantColor
440                         qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
441
442                         // SPARE0 = TEXTURE0 * PRIMARY_COLOR
443                         // SPARE1 = TEXTURE1 * CONSTANT_COLOR
444                         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, 
445                                 GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
446                         // variable B will be overriden based on the stage vertexColor option
447                         if ( surfaceStage->vertexColor == SVC_MODULATE ) {
448                                 qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
449                                         GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
450                                 qglEnableClientState( GL_COLOR_ARRAY );
451                         } else if ( surfaceStage->vertexColor == SVC_INVERSE_MODULATE ) {
452                                 qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
453                                         GL_PRIMARY_COLOR_NV, GL_UNSIGNED_INVERT_NV, GL_RGB );
454                                 qglEnableClientState( GL_COLOR_ARRAY );
455                         } else {        // SVC_IGNORE
456                                 qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
457                                         GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB );
458                                 qglDisableClientState( GL_COLOR_ARRAY );
459                         }
460                         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, 
461                                 GL_TEXTURE1_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
462                         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, 
463                                 GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
464                         qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, 
465                                 GL_SPARE0_NV, GL_SPARE1_NV, GL_DISCARD_NV,
466                                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
467
468                         // final combiner
469                         qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_SPARE1_NV,
470                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
471                         qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_SPARE0_NV,
472                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
473                         qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
474                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
475                         qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO,
476                                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
477                         qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
478                                 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
479
480                         // for all light stages, multiply the projected color by the surface
481                         // color, and blend with the framebuffer
482                         for ( int j = 0 ; j < lightShader->GetNumStages() ; j++ ) {
483                                 const shaderStage_t     *lightStage = lightShader->GetStage( j );
484                                 float   color[4];
485
486                                 // ignore stages that fail the condition
487                                 if ( !lightRegs[ lightStage->conditionRegister ] ) {
488                                         continue;
489                                 }
490
491                                 // set the color to the light color times the surface color
492                                 color[0] = backEnd.lightScale
493                                         * lightRegs[ lightStage->color.registers[0] ]
494                                         * surfaceRegs[ surfaceStage->color.registers[0] ];
495                                 color[1] = backEnd.lightScale
496                                         * lightRegs[ lightStage->color.registers[1] ]
497                                         * surfaceRegs[ surfaceStage->color.registers[1] ];
498                                 color[2] = backEnd.lightScale
499                                         * lightRegs[ lightStage->color.registers[2] ]
500                                         * surfaceRegs[ surfaceStage->color.registers[2] ];
501                                 color[3] = 1;
502
503                                 // don't draw if it would be all black
504                                 if ( color[0] == 0 && color[1] == 0 && color[2] == 0 ) {
505                                         continue;
506                                 }
507
508                                 qglCombinerParameterfvNV( GL_CONSTANT_COLOR1_NV, color );
509
510                                 RB_BindStageTexture( lightRegs, &lightStage->texture, surf );
511
512                                 RB_DrawElementsWithCounters( tri );
513
514                                 RB_FinishStageTexture( &lightStage->texture, surf );
515                         }
516
517                         if ( surfaceStage->vertexColor != SVC_IGNORE ) {
518                                 qglDisableClientState( GL_COLOR_ARRAY );
519                         }
520
521                         qglDisable( GL_TEXTURE_GEN_S );
522                         qglDisable( GL_TEXTURE_GEN_T );
523                         qglDisable( GL_TEXTURE_GEN_Q );
524
525                         globalImages->BindNull();
526                         GL_SelectTexture( 0 );
527                         RB_FinishStageTexture( &surfaceStage->texture, surf );
528
529                         continue;
530                 }
531
532         }
533         // unhack depth range if needed
534         if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) {
535                 RB_LeaveDepthHack();
536         }
537 }
538
539 /*
540 ==================
541 RB_RenderInteractionList
542 ==================
543 */
544 static void RB_RenderInteractionList( const drawSurf_t *surf ) {
545         if ( !surf ) {
546                 return;
547         }
548
549         qglEnable( GL_REGISTER_COMBINERS_NV );
550
551         // force a space calculation for light vectors
552         backEnd.currentSpace = NULL;
553
554         for ( const drawSurf_t *s = surf ; s ; s = s->nextOnLight ) {
555                 RB_RenderInteraction( s );
556         }
557
558         qglDisable( GL_REGISTER_COMBINERS_NV );
559 }
560
561
562
563 /*
564 ==================
565 RB_RenderViewLight
566
567 ==================
568 */
569 static void RB_RenderViewLight( viewLight_t *vLight ) {
570         backEnd.vLight = vLight;
571
572         // do fogging later
573         if ( vLight->lightShader->IsFogLight() ) {
574                 return;
575         }
576         if ( vLight->lightShader->IsBlendLight() ) {
577                 return;
578         }
579
580         RB_LogComment( "---------- RB_RenderViewLight 0x%p ----------\n", vLight );
581
582         // clear the stencil buffer if needed
583         if ( vLight->globalShadows || vLight->localShadows ) {
584                 backEnd.currentScissor = vLight->scissorRect;
585                 if ( r_useScissor.GetBool() ) {
586                         qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, 
587                                 backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
588                                 backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
589                                 backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
590                 }
591                 qglClear( GL_STENCIL_BUFFER_BIT );
592         } else {
593                 // no shadows, so no need to read or write the stencil buffer
594                 // we might in theory want to use GL_ALWAYS instead of disabling
595                 // completely, to satisfy the invarience rules
596                 qglStencilFunc( GL_ALWAYS, 128, 255 );
597         }
598
599         backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
600         RB_StencilShadowPass( vLight->globalShadows );
601         RB_RenderInteractionList( vLight->localInteractions );
602         RB_StencilShadowPass( vLight->localShadows );
603         RB_RenderInteractionList( vLight->globalInteractions );
604
605         if ( r_skipTranslucent.GetBool() ) {
606                 return;
607         }
608
609         // disable stencil testing for translucent interactions, because
610         // the shadow isn't calculated at their point, and the shadow
611         // behind them may be depth fighting with a back side, so there
612         // isn't any reasonable thing to do
613         qglStencilFunc( GL_ALWAYS, 128, 255 );
614         backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
615         RB_RenderInteractionList( vLight->translucentInteractions );
616 }
617
618
619 /*
620 ==================
621 RB_NV10_DrawInteractions
622 ==================
623 */
624 void RB_NV10_DrawInteractions( void ) {
625         qglEnable( GL_STENCIL_TEST );
626
627         for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
628                 RB_RenderViewLight( vLight );
629         }
630 }
631
632
633 /*
634 ==================
635 R_NV10_Init
636
637 ==================
638 */
639 void R_NV10_Init( void ) {
640         glConfig.allowNV10Path = false;
641
642         if ( !glConfig.registerCombinersAvailable ) {
643                 return;
644         }
645
646         glConfig.allowNV10Path = true;
647 }