2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
28 #include "../idlib/precompiled.h"
42 backEnd.depthFunc must be equal for alpha tested surfaces to work right,
43 it is set to lessThan for blended transparent surfaces
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.
49 you can't blend two bumpmaps, but you can change bump maps between
50 blended diffuse / specular maps to get the same effect
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;
65 RB_LogComment( "---------- RB_RenderInteraction %s on %s ----------\n",
66 lightShader->GetName(), surfaceShader->GetName() );
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 );
73 for ( int i = 0 ; i < 4 ; i++ ) {
74 R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] );
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 );
87 // hack depth range if needed
88 if ( surf->space->weaponDepthHack ) {
89 RB_EnterWeaponDepthHack();
92 if ( surf->space->modelDepthHack != 0.0f ) {
93 RB_EnterModelDepthHack( surf->space->modelDepthHack );
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 );
105 // go through the individual stages
106 for ( int i = 0 ; i < surfaceShader->GetNumStages() ; i++ ) {
107 const shaderStage_t *surfaceStage = surfaceShader->GetStage( i );
109 // ignore ambient stages while drawing interactions
110 if ( surfaceStage->lighting == SL_AMBIENT ) {
114 // ignore stages that fail the condition
115 if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
119 //-----------------------------------------------------
123 //-----------------------------------------------------
124 if ( surfaceStage->lighting == SL_BUMP ) {
125 // render light falloff * bumpmap lighting
127 if ( surfaceStage->vertexColor != SVC_IGNORE ) {
128 common->Printf( "shader %s: vertexColor on a bump stage\n",
129 surfaceShader->GetName() );
132 // check for RGBA modulations in the stage, which are also illegal?
134 // save the bump map stage for the specular calculation and diffuse
136 lastBumpStage = surfaceStage;
139 // ambient lights combine non-directional bump and falloff
140 // and write to the alpha channel
142 if ( lightShader->IsAmbientLight() ) {
143 GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
145 // texture 0 will be the per-surface bump map
146 GL_SelectTexture( 0 );
147 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
149 RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
151 if ( r_skipBump.GetBool() ) {
152 globalImages->flatNormalMap->Bind();
155 // texture 1 will be the light falloff
156 GL_SelectTexture( 1 );
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();
163 qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
165 // set the constant color to a bit of an angle
166 qglCombinerParameterfvNV( GL_CONSTANT_COLOR0_NV, tr.ambientLightVector.ToFloatPtr() );
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 );
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 );
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 );
199 RB_DrawElementsWithCounters( tri );
201 globalImages->BindNull();
202 qglDisable( GL_TEXTURE_GEN_S );
204 GL_SelectTexture( 0 );
205 RB_FinishStageTexture( &surfaceStage->texture, surf );
210 // draw light falloff to the alpha channel
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();
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 );
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 );
239 RB_DrawElementsWithCounters( tri );
241 qglDisable( GL_TEXTURE_GEN_S );
244 // draw the bump map result onto the alpha channel
246 GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ZERO | GLS_COLORMASK | GLS_DEPTHMASK
247 | backEnd.depthFunc );
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 );
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() );
261 qglDisableClientState( GL_COLOR_ARRAY );
263 // program the nvidia register combiners
264 // I just want alpha = Dot( texture0, texture1 )
265 qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
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 );
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 );
282 RB_DrawElementsWithCounters( tri );
284 globalImages->BindNull();
285 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
287 GL_SelectTexture( 0 );
288 RB_FinishStageTexture( &surfaceStage->texture, surf );
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() );
300 //-----------------------------------------------------
302 // specular exponent modification of the bump / falloff
304 //-----------------------------------------------------
305 if ( surfaceStage->lighting == SL_SPECULAR ) {
306 // put specular bump map into alpha channel, then treat as a diffuse
308 // allow the specular to be skipped as a user speed optimization
309 if ( r_skipSpecular.GetBool() ) {
313 // ambient lights don't have specular
314 if ( lightShader->IsAmbientLight() ) {
318 if ( !lastBumpStage ) {
319 common->Printf( "shader %s: specular stage without a preceeding bumpmap stage\n",
320 surfaceShader->GetName() );
324 GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_SRC_ALPHA | GLS_COLORMASK | GLS_DEPTHMASK
325 | backEnd.depthFunc );
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 );
333 if ( r_skipBump.GetBool() ) {
334 globalImages->flatNormalMap->Bind();
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 ) );
344 // program the nvidia register combiners
345 qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 2 );
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 );
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 );
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 );
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 );
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 );
392 RB_DrawElementsWithCounters( tri );
394 globalImages->BindNull();
395 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
397 GL_SelectTexture( 0 );
399 RB_FinishStageTexture( &lastBumpStage->texture, surf );
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;
405 // fall through to the common handling of diffuse and specular projected lighting
408 //-----------------------------------------------------
410 // projected light / surface color for diffuse and specular maps
412 //-----------------------------------------------------
413 if ( surfaceStage->lighting == SL_DIFFUSE || surfaceStage->lighting == SL_SPECULAR ) {
415 GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_ALPHAMASK | GLS_DEPTHMASK
416 | backEnd.depthFunc );
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 );
424 if ( ( surfaceStage->lighting == SL_DIFFUSE && r_skipDiffuse.GetBool() )
425 || ( surfaceStage->lighting == SL_SPECULAR && r_skipSpecular.GetBool() ) ) {
426 globalImages->blackImage->Bind();
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() );
439 // texture0 * texture1 * primaryColor * constantColor
440 qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
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 );
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 );
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 );
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 );
486 // ignore stages that fail the condition
487 if ( !lightRegs[ lightStage->conditionRegister ] ) {
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] ];
503 // don't draw if it would be all black
504 if ( color[0] == 0 && color[1] == 0 && color[2] == 0 ) {
508 qglCombinerParameterfvNV( GL_CONSTANT_COLOR1_NV, color );
510 RB_BindStageTexture( lightRegs, &lightStage->texture, surf );
512 RB_DrawElementsWithCounters( tri );
514 RB_FinishStageTexture( &lightStage->texture, surf );
517 if ( surfaceStage->vertexColor != SVC_IGNORE ) {
518 qglDisableClientState( GL_COLOR_ARRAY );
521 qglDisable( GL_TEXTURE_GEN_S );
522 qglDisable( GL_TEXTURE_GEN_T );
523 qglDisable( GL_TEXTURE_GEN_Q );
525 globalImages->BindNull();
526 GL_SelectTexture( 0 );
527 RB_FinishStageTexture( &surfaceStage->texture, surf );
533 // unhack depth range if needed
534 if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) {
541 RB_RenderInteractionList
544 static void RB_RenderInteractionList( const drawSurf_t *surf ) {
549 qglEnable( GL_REGISTER_COMBINERS_NV );
551 // force a space calculation for light vectors
552 backEnd.currentSpace = NULL;
554 for ( const drawSurf_t *s = surf ; s ; s = s->nextOnLight ) {
555 RB_RenderInteraction( s );
558 qglDisable( GL_REGISTER_COMBINERS_NV );
569 static void RB_RenderViewLight( viewLight_t *vLight ) {
570 backEnd.vLight = vLight;
573 if ( vLight->lightShader->IsFogLight() ) {
576 if ( vLight->lightShader->IsBlendLight() ) {
580 RB_LogComment( "---------- RB_RenderViewLight 0x%p ----------\n", vLight );
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 );
591 qglClear( GL_STENCIL_BUFFER_BIT );
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 );
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 );
605 if ( r_skipTranslucent.GetBool() ) {
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 );
621 RB_NV10_DrawInteractions
624 void RB_NV10_DrawInteractions( void ) {
625 qglEnable( GL_STENCIL_TEST );
627 for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
628 RB_RenderViewLight( vLight );
639 void R_NV10_Init( void ) {
640 glConfig.allowNV10Path = false;
642 if ( !glConfig.registerCombinersAvailable ) {
646 glConfig.allowNV10Path = true;