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"
35 with standard calls, we can't do bump mapping or vertex colors with
71 RB_ARB_DrawInteraction
75 backEnd.depthFunc must be equal for alpha tested surfaces to work right,
76 it is set to lessThan for blended transparent surfaces
80 static void RB_ARB_DrawInteraction( const drawInteraction_t *din ) {
81 const drawSurf_t *surf = din->surf;
82 const srfTriangles_t *tri = din->surf->geo;
84 // set the vertex arrays, which may not all be enabled on a given pass
85 idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
86 qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
87 GL_SelectTexture( 0 );
88 qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), (void *)&ac->st );
90 //-----------------------------------------------------
94 //-----------------------------------------------------
95 // render light falloff * bumpmap lighting
98 // draw light falloff to the alpha channel
100 GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
102 qglColor3f( 1, 1, 1 );
103 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
104 qglEnable( GL_TEXTURE_GEN_S );
105 qglTexGenfv( GL_S, GL_OBJECT_PLANE, din->lightProjection[3].ToFloatPtr() );
106 qglTexCoord2f( 0, 0.5 );
108 // ATI R100 can't do partial texgens
109 #define NO_MIXED_TEXGEN
111 #ifdef NO_MIXED_TEXGEN
117 qglEnable( GL_TEXTURE_GEN_T );
118 qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane.ToFloatPtr() );
124 qglEnable( GL_TEXTURE_GEN_Q );
125 qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane.ToFloatPtr() );
129 din->lightFalloffImage->Bind();
132 RB_DrawElementsWithCounters( tri );
134 qglDisable( GL_TEXTURE_GEN_S );
135 #ifdef NO_MIXED_TEXGEN
136 qglDisable( GL_TEXTURE_GEN_T );
137 qglDisable( GL_TEXTURE_GEN_Q );
141 GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK
142 | backEnd.depthFunc );
143 // the texccords are the non-normalized vector towards the light origin
144 GL_SelectTexture( 0 );
145 globalImages->normalCubeMapImage->Bind();
146 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
147 qglTexCoordPointer( 3, GL_FLOAT, sizeof( lightingCache_t ), ((lightingCache_t *)vertexCache.Position(tri->lightingCache))->localLightVector.ToFloatPtr() );
149 RB_DrawElementsWithCounters( tri );
153 // we can't do bump mapping with standard calls, so skip it
154 if ( glConfig.envDot3Available && glConfig.cubeMapAvailable ) {
156 // draw the bump map result onto the alpha channel
158 GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ZERO | GLS_COLORMASK | GLS_DEPTHMASK
159 | backEnd.depthFunc );
161 // texture 0 will be the per-surface bump map
162 GL_SelectTexture( 0 );
163 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
164 // FIXME: matrix work! RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
165 din->bumpImage->Bind();
167 // texture 1 is the normalization cube map
168 // the texccords are the non-normalized vector towards the light origin
169 GL_SelectTexture( 1 );
170 if ( din->ambientLight ) {
171 globalImages->ambientNormalMap->Bind(); // fixed value
173 globalImages->normalCubeMapImage->Bind();
175 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
176 qglTexCoordPointer( 3, GL_FLOAT, sizeof( lightingCache_t ), ((lightingCache_t *)vertexCache.Position(tri->lightingCache))->localLightVector.ToFloatPtr() );
178 // I just want alpha = Dot( texture0, texture1 )
179 GL_TexEnv( GL_COMBINE_ARB );
181 qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGBA_ARB );
182 qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
183 qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
184 qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
185 qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
186 qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 );
187 qglTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1 );
190 RB_DrawElementsWithCounters( tri );
192 GL_TexEnv( GL_MODULATE );
194 globalImages->BindNull();
195 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
197 GL_SelectTexture( 0 );
198 // RB_FinishStageTexture( &surfaceStage->texture, surf );
201 //-----------------------------------------------------
203 // projected light / surface color for diffuse maps
205 //-----------------------------------------------------
207 GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_ALPHAMASK | GLS_DEPTHMASK
208 | backEnd.depthFunc );
210 // texture 0 will get the surface color texture
211 GL_SelectTexture( 0 );
213 // select the vertex color source
214 if ( din->vertexColor == SVC_IGNORE ) {
215 qglColor4fv( din->diffuseColor.ToFloatPtr() );
217 // FIXME: does this not get diffuseColor blended in?
218 qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), (void *)&ac->color );
219 qglEnableClientState( GL_COLOR_ARRAY );
221 if ( din->vertexColor == SVC_INVERSE_MODULATE ) {
222 GL_TexEnv( GL_COMBINE_ARB );
223 qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
224 qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
225 qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB );
226 qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
227 qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR );
228 qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 );
232 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
233 // FIXME: does this not get the texture matrix?
234 // RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
235 din->diffuseImage->Bind();
237 // texture 1 will get the light projected texture
238 GL_SelectTexture( 1 );
239 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
240 qglEnable( GL_TEXTURE_GEN_S );
241 qglEnable( GL_TEXTURE_GEN_T );
242 qglEnable( GL_TEXTURE_GEN_Q );
243 qglTexGenfv( GL_S, GL_OBJECT_PLANE, din->lightProjection[0].ToFloatPtr() );
244 qglTexGenfv( GL_T, GL_OBJECT_PLANE, din->lightProjection[1].ToFloatPtr() );
245 qglTexGenfv( GL_Q, GL_OBJECT_PLANE, din->lightProjection[2].ToFloatPtr() );
247 din->lightImage->Bind();
250 RB_DrawElementsWithCounters( tri );
252 qglDisable( GL_TEXTURE_GEN_S );
253 qglDisable( GL_TEXTURE_GEN_T );
254 qglDisable( GL_TEXTURE_GEN_Q );
256 globalImages->BindNull();
257 GL_SelectTexture( 0 );
259 if ( din->vertexColor != SVC_IGNORE ) {
260 qglDisableClientState( GL_COLOR_ARRAY );
261 GL_TexEnv( GL_MODULATE );
264 // RB_FinishStageTexture( &surfaceStage->texture, surf );
269 RB_ARB_DrawThreeTextureInteraction
271 Used by radeon R100 and Intel graphics parts
275 backEnd.depthFunc must be equal for alpha tested surfaces to work right,
276 it is set to lessThan for blended transparent surfaces
280 static void RB_ARB_DrawThreeTextureInteraction( const drawInteraction_t *din ) {
281 const drawSurf_t *surf = din->surf;
282 const srfTriangles_t *tri = din->surf->geo;
284 // set the vertex arrays, which may not all be enabled on a given pass
285 idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
286 qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
287 GL_SelectTexture( 0 );
288 qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), (void *)&ac->st );
289 qglColor3f( 1, 1, 1 );
292 // bump map dot cubeMap into the alpha channel
294 GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_COLORMASK | GLS_DEPTHMASK
295 | backEnd.depthFunc );
297 // texture 0 will be the per-surface bump map
298 GL_SelectTexture( 0 );
299 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
300 // FIXME: matrix work! RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
301 din->bumpImage->Bind();
303 // texture 1 is the normalization cube map
304 // the texccords are the non-normalized vector towards the light origin
305 GL_SelectTexture( 1 );
306 if ( din->ambientLight ) {
307 globalImages->ambientNormalMap->Bind(); // fixed value
309 globalImages->normalCubeMapImage->Bind();
311 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
312 qglTexCoordPointer( 3, GL_FLOAT, sizeof( lightingCache_t ), ((lightingCache_t *)vertexCache.Position(tri->lightingCache))->localLightVector.ToFloatPtr() );
314 // I just want alpha = Dot( texture0, texture1 )
315 GL_TexEnv( GL_COMBINE_ARB );
317 qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGBA_ARB );
318 qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
319 qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
320 qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
321 qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
322 qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 );
323 qglTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1 );
326 RB_DrawElementsWithCounters( tri );
328 GL_TexEnv( GL_MODULATE );
330 globalImages->BindNull();
331 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
333 GL_SelectTexture( 0 );
334 // RB_FinishStageTexture( &surfaceStage->texture, surf );
337 //-----------------------------------------------------
339 // light falloff / projected light / surface color for diffuse maps
341 //-----------------------------------------------------
342 // multiply result by alpha, but don't trash alpha
343 GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_ALPHAMASK | GLS_DEPTHMASK
344 | backEnd.depthFunc );
346 // texture 0 will get the surface color texture
347 GL_SelectTexture( 0 );
349 // select the vertex color source
350 if ( din->vertexColor == SVC_IGNORE ) {
351 qglColor4fv( din->diffuseColor.ToFloatPtr() );
353 // FIXME: does this not get diffuseColor blended in?
354 qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), (void *)&ac->color );
355 qglEnableClientState( GL_COLOR_ARRAY );
357 if ( din->vertexColor == SVC_INVERSE_MODULATE ) {
358 GL_TexEnv( GL_COMBINE_ARB );
359 qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
360 qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
361 qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB );
362 qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
363 qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR );
364 qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 );
368 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
369 // FIXME: does this not get the texture matrix?
370 // RB_BindStageTexture( surfaceRegs, &surfaceStage->texture, surf );
371 din->diffuseImage->Bind();
373 // texture 1 will get the light projected texture
374 GL_SelectTexture( 1 );
375 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
376 qglEnable( GL_TEXTURE_GEN_S );
377 qglEnable( GL_TEXTURE_GEN_T );
378 qglEnable( GL_TEXTURE_GEN_Q );
379 qglTexGenfv( GL_S, GL_OBJECT_PLANE, din->lightProjection[0].ToFloatPtr() );
380 qglTexGenfv( GL_T, GL_OBJECT_PLANE, din->lightProjection[1].ToFloatPtr() );
381 qglTexGenfv( GL_Q, GL_OBJECT_PLANE, din->lightProjection[2].ToFloatPtr() );
382 din->lightImage->Bind();
384 // texture 2 will get the light falloff texture
385 GL_SelectTexture( 2 );
386 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
387 qglEnable( GL_TEXTURE_GEN_S );
388 qglEnable( GL_TEXTURE_GEN_T );
389 qglEnable( GL_TEXTURE_GEN_Q );
391 qglTexGenfv( GL_S, GL_OBJECT_PLANE, din->lightProjection[3].ToFloatPtr() );
398 qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane.ToFloatPtr() );
404 qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane.ToFloatPtr() );
406 din->lightFalloffImage->Bind();
409 RB_DrawElementsWithCounters( tri );
411 qglDisable( GL_TEXTURE_GEN_S );
412 qglDisable( GL_TEXTURE_GEN_T );
413 qglDisable( GL_TEXTURE_GEN_Q );
414 globalImages->BindNull();
416 GL_SelectTexture( 1 );
417 qglDisable( GL_TEXTURE_GEN_S );
418 qglDisable( GL_TEXTURE_GEN_T );
419 qglDisable( GL_TEXTURE_GEN_Q );
420 globalImages->BindNull();
422 GL_SelectTexture( 0 );
424 if ( din->vertexColor != SVC_IGNORE ) {
425 qglDisableClientState( GL_COLOR_ARRAY );
426 GL_TexEnv( GL_MODULATE );
429 // RB_FinishStageTexture( &surfaceStage->texture, surf );
435 RB_CreateDrawInteractions
438 static void RB_CreateDrawInteractions( const drawSurf_t *surf ) {
443 // force a space calculation
444 backEnd.currentSpace = NULL;
446 if ( r_useTripleTextureARB.GetBool() && glConfig.maxTextureUnits >= 3 ) {
447 for ( ; surf ; surf = surf->nextOnLight ) {
448 // break it up into multiple primitive draw interactions if necessary
449 RB_CreateSingleDrawInteractions( surf, RB_ARB_DrawThreeTextureInteraction );
452 for ( ; surf ; surf = surf->nextOnLight ) {
453 // break it up into multiple primitive draw interactions if necessary
454 RB_CreateSingleDrawInteractions( surf, RB_ARB_DrawInteraction );
467 static void RB_RenderViewLight( viewLight_t *vLight ) {
468 backEnd.vLight = vLight;
471 if ( vLight->lightShader->IsFogLight() ) {
474 if ( vLight->lightShader->IsBlendLight() ) {
478 RB_LogComment( "---------- RB_RenderViewLight 0x%p ----------\n", vLight );
480 // clear the stencil buffer if needed
481 if ( vLight->globalShadows || vLight->localShadows ) {
482 backEnd.currentScissor = vLight->scissorRect;
483 if ( r_useScissor.GetBool() ) {
484 qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
485 backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
486 backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
487 backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
489 qglClear( GL_STENCIL_BUFFER_BIT );
491 // no shadows, so no need to read or write the stencil buffer
492 // we might in theory want to use GL_ALWAYS instead of disabling
493 // completely, to satisfy the invarience rules
494 qglStencilFunc( GL_ALWAYS, 128, 255 );
497 backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
498 RB_StencilShadowPass( vLight->globalShadows );
499 RB_CreateDrawInteractions( vLight->localInteractions );
500 RB_StencilShadowPass( vLight->localShadows );
501 RB_CreateDrawInteractions( vLight->globalInteractions );
503 if ( r_skipTranslucent.GetBool() ) {
507 // disable stencil testing for translucent interactions, because
508 // the shadow isn't calculated at their point, and the shadow
509 // behind them may be depth fighting with a back side, so there
510 // isn't any reasonable thing to do
511 qglStencilFunc( GL_ALWAYS, 128, 255 );
512 backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
513 RB_CreateDrawInteractions( vLight->translucentInteractions );
519 RB_ARB_DrawInteractions
522 void RB_ARB_DrawInteractions( void ) {
523 qglEnable( GL_STENCIL_TEST );
525 for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
526 RB_RenderViewLight( vLight );