]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/draw_arb.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / renderer / draw_arb.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   with standard calls, we can't do bump mapping or vertex colors with
36   shader colors
37
38   2 texture units:
39
40 falloff
41 --
42 light cube
43 bump
44 --
45 light projection
46 diffuse
47
48
49         3 texture units:
50
51 light cube
52 bump
53 --
54 falloff
55 light projection
56 diffuse
57
58
59         5 texture units:
60
61 light cube
62 bump
63 falloff
64 light projection
65 diffuse
66
67 */
68
69 /*
70 ==================
71 RB_ARB_DrawInteraction
72
73 backEnd.vLight
74
75 backEnd.depthFunc must be equal for alpha tested surfaces to work right,
76 it is set to lessThan for blended transparent surfaces
77
78 ==================
79 */
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;
83
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 );
89
90         //-----------------------------------------------------
91         //
92         // bump / falloff
93         //
94         //-----------------------------------------------------
95         // render light falloff * bumpmap lighting
96
97         //
98         // draw light falloff to the alpha channel
99         //
100         GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
101
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 );
107
108 // ATI R100 can't do partial texgens
109 #define NO_MIXED_TEXGEN
110
111 #ifdef NO_MIXED_TEXGEN
112 idVec4  plane;
113 plane[0] = 0;
114 plane[1] = 0;
115 plane[2] = 0;
116 plane[3] = 0.5;
117 qglEnable( GL_TEXTURE_GEN_T );
118 qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane.ToFloatPtr() );
119
120 plane[0] = 0;
121 plane[1] = 0;
122 plane[2] = 0;
123 plane[3] = 1;
124 qglEnable( GL_TEXTURE_GEN_Q );
125 qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane.ToFloatPtr() );
126
127 #endif
128
129         din->lightFalloffImage->Bind();
130
131         // draw it
132         RB_DrawElementsWithCounters( tri );
133
134         qglDisable( GL_TEXTURE_GEN_S );
135 #ifdef NO_MIXED_TEXGEN
136 qglDisable( GL_TEXTURE_GEN_T );
137 qglDisable( GL_TEXTURE_GEN_Q );
138 #endif
139
140 #if 0
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() );
148 // draw it
149 RB_DrawElementsWithCounters( tri );
150 return;
151 #endif
152
153         // we can't do bump mapping with standard calls, so skip it
154         if ( glConfig.envDot3Available && glConfig.cubeMapAvailable ) {
155                 //
156                 // draw the bump map result onto the alpha channel
157                 //
158                 GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ZERO | GLS_COLORMASK | GLS_DEPTHMASK 
159                         | backEnd.depthFunc );
160
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();
166
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
172                 } else {
173                         globalImages->normalCubeMapImage->Bind();
174                 }
175                 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
176                 qglTexCoordPointer( 3, GL_FLOAT, sizeof( lightingCache_t ), ((lightingCache_t *)vertexCache.Position(tri->lightingCache))->localLightVector.ToFloatPtr() );
177
178                 // I just want alpha = Dot( texture0, texture1 )
179                 GL_TexEnv( GL_COMBINE_ARB );
180
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 );
188
189                 // draw it
190                 RB_DrawElementsWithCounters( tri );
191
192                 GL_TexEnv( GL_MODULATE );
193
194                 globalImages->BindNull();
195                 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
196
197                 GL_SelectTexture( 0 );
198 //              RB_FinishStageTexture( &surfaceStage->texture, surf );
199         }
200
201         //-----------------------------------------------------
202         //
203         // projected light / surface color for diffuse maps
204         //
205         //-----------------------------------------------------
206         // don't trash alpha
207         GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_ALPHAMASK | GLS_DEPTHMASK 
208         | backEnd.depthFunc );
209
210         // texture 0 will get the surface color texture
211         GL_SelectTexture( 0 );
212
213         // select the vertex color source
214         if ( din->vertexColor == SVC_IGNORE ) {
215                 qglColor4fv( din->diffuseColor.ToFloatPtr() );
216         } else {
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 );
220
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 );
229                 }
230         }
231
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();
236
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() );
246
247         din->lightImage->Bind();
248
249         // draw it
250         RB_DrawElementsWithCounters( tri );
251
252         qglDisable( GL_TEXTURE_GEN_S );
253         qglDisable( GL_TEXTURE_GEN_T );
254         qglDisable( GL_TEXTURE_GEN_Q );
255
256         globalImages->BindNull();
257         GL_SelectTexture( 0 );
258
259         if ( din->vertexColor != SVC_IGNORE ) {
260                 qglDisableClientState( GL_COLOR_ARRAY );
261                 GL_TexEnv( GL_MODULATE );
262         }
263
264 //      RB_FinishStageTexture( &surfaceStage->texture, surf );
265 }
266
267 /*
268 ==================
269 RB_ARB_DrawThreeTextureInteraction
270
271 Used by radeon R100 and Intel graphics parts
272
273 backEnd.vLight
274
275 backEnd.depthFunc must be equal for alpha tested surfaces to work right,
276 it is set to lessThan for blended transparent surfaces
277
278 ==================
279 */
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;
283
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 );
290
291         //
292         // bump map dot cubeMap into the alpha channel
293         //
294         GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_COLORMASK | GLS_DEPTHMASK 
295                 | backEnd.depthFunc );
296
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();
302
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
308         } else {
309                 globalImages->normalCubeMapImage->Bind();
310         }
311         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
312         qglTexCoordPointer( 3, GL_FLOAT, sizeof( lightingCache_t ), ((lightingCache_t *)vertexCache.Position(tri->lightingCache))->localLightVector.ToFloatPtr() );
313
314         // I just want alpha = Dot( texture0, texture1 )
315         GL_TexEnv( GL_COMBINE_ARB );
316
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 );
324
325         // draw it
326         RB_DrawElementsWithCounters( tri );
327
328         GL_TexEnv( GL_MODULATE );
329
330         globalImages->BindNull();
331         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
332
333         GL_SelectTexture( 0 );
334 //              RB_FinishStageTexture( &surfaceStage->texture, surf );
335
336
337         //-----------------------------------------------------
338         //
339         // light falloff / projected light / surface color for diffuse maps
340         //
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 );
345
346         // texture 0 will get the surface color texture
347         GL_SelectTexture( 0 );
348
349         // select the vertex color source
350         if ( din->vertexColor == SVC_IGNORE ) {
351                 qglColor4fv( din->diffuseColor.ToFloatPtr() );
352         } else {
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 );
356
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 );
365                 }
366         }
367
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();
372
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();
383
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 );
390
391         qglTexGenfv( GL_S, GL_OBJECT_PLANE, din->lightProjection[3].ToFloatPtr() );
392
393         idVec4  plane;
394         plane[0] = 0;
395         plane[1] = 0;
396         plane[2] = 0;
397         plane[3] = 0.5;
398         qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane.ToFloatPtr() );
399
400         plane[0] = 0;
401         plane[1] = 0;
402         plane[2] = 0;
403         plane[3] = 1;
404         qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane.ToFloatPtr() );
405
406         din->lightFalloffImage->Bind();
407
408         // draw it
409         RB_DrawElementsWithCounters( tri );
410
411         qglDisable( GL_TEXTURE_GEN_S );
412         qglDisable( GL_TEXTURE_GEN_T );
413         qglDisable( GL_TEXTURE_GEN_Q );
414         globalImages->BindNull();
415
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();
421
422         GL_SelectTexture( 0 );
423
424         if ( din->vertexColor != SVC_IGNORE ) {
425                 qglDisableClientState( GL_COLOR_ARRAY );
426                 GL_TexEnv( GL_MODULATE );
427         }
428
429 //      RB_FinishStageTexture( &surfaceStage->texture, surf );
430 }
431
432
433 /*
434 ==================
435 RB_CreateDrawInteractions
436 ==================
437 */
438 static void RB_CreateDrawInteractions( const drawSurf_t *surf ) {
439         if ( !surf ) {
440                 return;
441         }
442
443         // force a space calculation
444         backEnd.currentSpace = NULL;
445
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 );
450                 }
451         } else {
452                 for ( ; surf ; surf = surf->nextOnLight ) {
453                         // break it up into multiple primitive draw interactions if necessary
454                         RB_CreateSingleDrawInteractions( surf, RB_ARB_DrawInteraction );
455                 }
456         }
457 }
458
459
460
461 /*
462 ==================
463 RB_RenderViewLight
464
465 ==================
466 */
467 static void RB_RenderViewLight( viewLight_t *vLight ) {
468         backEnd.vLight = vLight;
469
470         // do fogging later
471         if ( vLight->lightShader->IsFogLight() ) {
472                 return;
473         }
474         if ( vLight->lightShader->IsBlendLight() ) {
475                 return;
476         }
477
478         RB_LogComment( "---------- RB_RenderViewLight 0x%p ----------\n", vLight );
479
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 );
488                 }
489                 qglClear( GL_STENCIL_BUFFER_BIT );
490         } else {
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 );
495         }
496
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 );
502
503         if ( r_skipTranslucent.GetBool() ) {
504                 return;
505         }
506
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 );
514 }
515
516
517 /*
518 ==================
519 RB_ARB_DrawInteractions
520 ==================
521 */
522 void RB_ARB_DrawInteractions( void ) {
523         qglEnable( GL_STENCIL_TEST );
524
525         for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
526                 RB_RenderViewLight( vLight );
527         }
528 }
529