]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/draw_nv20.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / renderer / draw_nv20.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "tr_local.h"
33
34 typedef enum {
35         FPROG_BUMP_AND_LIGHT,
36         FPROG_DIFFUSE_COLOR,
37         FPROG_SPECULAR_COLOR,
38         FPROG_DIFFUSE_AND_SPECULAR_COLOR,
39
40         FPROG_NUM_FRAGMENT_PROGRAMS
41 } fragmentProgram_t;
42
43 GLuint  fragmentDisplayListBase;        // FPROG_NUM_FRAGMENT_PROGRAMS lists
44
45 void RB_NV20_DependentSpecularPass( const drawInteraction_t *din );
46 void RB_NV20_DependentAmbientPass( void );
47
48 /*
49 =========================================================================================
50
51 GENERAL INTERACTION RENDERING
52
53 =========================================================================================
54 */
55
56 /*
57 ====================
58 GL_SelectTextureNoClient
59 ====================
60 */
61 void GL_SelectTextureNoClient( int unit ) {
62         backEnd.glState.currenttmu = unit;
63         qglActiveTextureARB( GL_TEXTURE0_ARB + unit );
64         RB_LogComment( "glActiveTextureARB( %i )\n", unit );
65 }
66
67 /*
68 ==================
69 RB_NV20_BumpAndLightFragment
70 ==================
71 */
72 static void RB_NV20_BumpAndLightFragment( void ) {
73         if ( r_useCombinerDisplayLists.GetBool() ) {
74                 qglCallList( fragmentDisplayListBase + FPROG_BUMP_AND_LIGHT );
75                 return;
76         }
77
78         // program the nvidia register combiners
79         qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 3 );
80
81         // stage 0 rgb performs the dot product
82         // SPARE0 = TEXTURE0 dot TEXTURE1
83         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, 
84                 GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
85         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
86                 GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
87         qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, 
88                 GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
89                 GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
90
91
92         // stage 1 rgb multiplies texture 2 and 3 together
93         // SPARE1 = TEXTURE2 * TEXTURE3
94         qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, 
95                 GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
96         qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, 
97                 GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
98         qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB, 
99                 GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV,
100                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
101
102         // stage 1 alpha does nohing
103
104         // stage 2 color multiplies spare0 * spare 1 just for debugging
105         // SPARE0 = SPARE0 * SPARE1
106         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV, 
107                 GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
108         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV, 
109                 GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
110         qglCombinerOutputNV( GL_COMBINER2_NV, GL_RGB, 
111                 GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
112                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
113
114         // stage 2 alpha multiples spare0 * spare 1
115         // SPARE0 = SPARE0 * SPARE1
116         qglCombinerInputNV( GL_COMBINER2_NV, GL_ALPHA, GL_VARIABLE_A_NV, 
117                 GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
118         qglCombinerInputNV( GL_COMBINER2_NV, GL_ALPHA, GL_VARIABLE_B_NV, 
119                 GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
120         qglCombinerOutputNV( GL_COMBINER2_NV, GL_ALPHA, 
121                 GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
122                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
123
124         // final combiner
125         qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_SPARE0_NV,
126                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
127         qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_ZERO,
128                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
129         qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO,
130                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
131         qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
132                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
133         qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_SPARE0_NV,
134                 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
135 }
136
137 /*
138 ==================
139 RB_NV20_DI_BumpAndLightPass
140
141 We are going to write alpha as light falloff * ( bump dot light ) * lightProjection
142 If the light isn't a monoLightShader, the lightProjection will be skipped, because
143 it will have to be done on an itterated basis
144 ==================
145 */
146 static void RB_NV20_DI_BumpAndLightPass( const drawInteraction_t *din, bool monoLightShader ) {
147         RB_LogComment( "---------- RB_NV_BumpAndLightPass ----------\n" );
148
149         GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
150
151         // texture 0 is the normalization cube map
152         // GL_TEXTURE0_ARB will be the normalized vector
153         // towards the light source
154 #ifdef MACOS_X
155         GL_SelectTexture( 0 );
156         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
157 #else
158         GL_SelectTextureNoClient( 0 );
159 #endif
160         if ( din->ambientLight ) {
161                 globalImages->ambientNormalMap->Bind();
162         } else {
163                 globalImages->normalCubeMapImage->Bind();
164         }
165
166         // texture 1 will be the per-surface bump map
167 #ifdef MACOS_X
168         GL_SelectTexture( 1 );
169         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
170 #else
171         GL_SelectTextureNoClient( 1 );
172 #endif
173         din->bumpImage->Bind();
174
175         // texture 2 will be the light falloff texture
176 #ifdef MACOS_X
177         GL_SelectTexture( 2 );
178         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
179 #else
180         GL_SelectTextureNoClient( 2 );
181 #endif
182         din->lightFalloffImage->Bind();
183
184         // texture 3 will be the light projection texture
185 #ifdef MACOS_X
186         GL_SelectTexture( 3 );
187         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
188 #else
189         GL_SelectTextureNoClient( 3 );
190 #endif
191         if ( monoLightShader ) {
192                 din->lightImage->Bind();
193         } else {
194                 // if the projected texture is multi-colored, we
195                 // will need to do it in subsequent passes
196                 globalImages->whiteImage->Bind();
197         }
198
199         // bind our "fragment program"
200         RB_NV20_BumpAndLightFragment();
201
202         // draw it
203         qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_BUMP_AND_LIGHT );
204         RB_DrawElementsWithCounters( din->surf->geo );
205 }
206
207
208 /*
209 ==================
210 RB_NV20_DiffuseColorFragment
211 ==================
212 */
213 static void RB_NV20_DiffuseColorFragment( void ) {
214         if ( r_useCombinerDisplayLists.GetBool() ) {
215                 qglCallList( fragmentDisplayListBase + FPROG_DIFFUSE_COLOR );
216                 return;
217         }
218
219         // program the nvidia register combiners
220         qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
221
222         // stage 0 is free, so we always do the multiply of the vertex color
223         // when the vertex color is inverted, qglCombinerInputNV(GL_VARIABLE_B_NV) will be changed
224         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, 
225                 GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
226         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
227                 GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
228         qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, 
229                 GL_TEXTURE0_ARB, GL_DISCARD_NV, GL_DISCARD_NV,
230                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
231
232         qglCombinerOutputNV( GL_COMBINER0_NV, GL_ALPHA, 
233                 GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV,
234                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
235
236
237         // for GL_CONSTANT_COLOR0_NV * TEXTURE0 * TEXTURE1
238         qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_CONSTANT_COLOR0_NV,
239                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
240         qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_E_TIMES_F_NV,
241                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
242         qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
243                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
244         qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO,
245                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
246         qglFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_TEXTURE0_ARB,
247                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
248         qglFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_TEXTURE1_ARB,
249                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
250         qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
251                 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
252
253 }
254
255 /*
256 ==================
257 RB_NV20_DI_DiffuseColorPass
258
259 ==================
260 */
261 static void RB_NV20_DI_DiffuseColorPass( const drawInteraction_t *din ) {
262         RB_LogComment( "---------- RB_NV20_DiffuseColorPass ----------\n" );
263
264         GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_ALPHAMASK 
265                 | backEnd.depthFunc );
266
267         // texture 0 will be the per-surface diffuse map
268 #ifdef MACOS_X
269         GL_SelectTexture( 0 );
270         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
271 #else
272         GL_SelectTextureNoClient( 0 );
273 #endif
274         din->diffuseImage->Bind();
275
276         // texture 1 will be the light projected texture
277 #ifdef MACOS_X
278         GL_SelectTexture( 1 );
279         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
280 #else
281         GL_SelectTextureNoClient( 1 );
282 #endif
283         din->lightImage->Bind();
284
285         // texture 2 is disabled
286 #ifdef MACOS_X
287         GL_SelectTexture( 2 );
288         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
289 #else
290         GL_SelectTextureNoClient( 2 );
291 #endif
292         globalImages->BindNull();
293
294         // texture 3 is disabled
295 #ifdef MACOS_X
296         GL_SelectTexture( 3 );
297         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
298 #else
299         GL_SelectTextureNoClient( 3 );
300 #endif
301         globalImages->BindNull();
302
303         // bind our "fragment program"
304         RB_NV20_DiffuseColorFragment();
305
306         // override one parameter for inverted vertex color
307         if ( din->vertexColor == SVC_INVERSE_MODULATE ) {
308                 qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
309                         GL_PRIMARY_COLOR_NV, GL_UNSIGNED_INVERT_NV, GL_RGB );
310         }
311
312         // draw it
313         qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_DIFFUSE_COLOR );
314         RB_DrawElementsWithCounters( din->surf->geo );
315 }
316
317
318 /*
319 ==================
320 RB_NV20_SpecularColorFragment
321 ==================
322 */
323 static void RB_NV20_SpecularColorFragment( void ) {
324         if ( r_useCombinerDisplayLists.GetBool() ) {
325                 qglCallList( fragmentDisplayListBase + FPROG_SPECULAR_COLOR );
326                 return;
327         }
328
329         // program the nvidia register combiners
330         qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 4 );
331
332         // we want GL_CONSTANT_COLOR1_NV * PRIMARY_COLOR * TEXTURE2 * TEXTURE3 * specular( TEXTURE0 * TEXTURE1 )
333
334         // stage 0 rgb performs the dot product
335         // GL_SPARE0_NV = ( TEXTURE0 dot TEXTURE1 - 0.5 ) * 2
336         // TEXTURE2 = TEXTURE2 * PRIMARY_COLOR
337         // the scale and bias steepen the specular curve
338         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, 
339                 GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
340         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
341                 GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
342         qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, 
343                 GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
344                 GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_TRUE, GL_FALSE, GL_FALSE );
345
346         // stage 0 alpha does nothing
347
348         // stage 1 color takes bump * bump
349         // GL_SPARE0_NV = ( GL_SPARE0_NV * GL_SPARE0_NV - 0.5 ) * 2
350         // the scale and bias steepen the specular curve
351         qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, 
352                 GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
353         qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, 
354                 GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
355         qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB, 
356                 GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
357                 GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE );
358
359         // stage 1 alpha does nothing
360
361         // stage 2 color
362         // GL_SPARE0_NV = GL_SPARE0_NV * TEXTURE3
363         // SECONDARY_COLOR = CONSTANT_COLOR * TEXTURE2
364         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV, 
365                 GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
366         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV, 
367                 GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
368         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_C_NV, 
369                 GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
370         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_D_NV, 
371                 GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
372         qglCombinerOutputNV( GL_COMBINER2_NV, GL_RGB, 
373                 GL_SPARE0_NV, GL_SECONDARY_COLOR_NV, GL_DISCARD_NV,
374                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
375
376         // stage 2 alpha does nothing
377
378
379         // stage 3 scales the texture by the vertex color
380         qglCombinerInputNV( GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_A_NV, 
381                 GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
382         qglCombinerInputNV( GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_B_NV, 
383                 GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
384         qglCombinerOutputNV( GL_COMBINER3_NV, GL_RGB, 
385                 GL_SECONDARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
386                 GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
387
388         // stage 3 alpha does nothing
389
390         // final combiner = GL_SPARE0_NV * SECONDARY_COLOR + PRIMARY_COLOR * SECONDARY_COLOR
391         qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_SPARE0_NV,
392                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
393         qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_SECONDARY_COLOR_NV,
394                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
395         qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
396                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
397         qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_E_TIMES_F_NV,
398                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
399         qglFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_SPARE0_NV,
400                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
401         qglFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_SECONDARY_COLOR_NV,
402                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
403         qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
404                 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
405 }
406
407
408 /*
409 ==================
410 RB_NV20_DI_SpecularColorPass
411
412 ==================
413 */
414 static void RB_NV20_DI_SpecularColorPass( const drawInteraction_t *din ) {
415         RB_LogComment( "---------- RB_NV20_SpecularColorPass ----------\n" );
416
417         GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_ALPHAMASK
418                 | backEnd.depthFunc );
419
420         // texture 0 is the normalization cube map for the half angle
421 #ifdef MACOS_X
422         GL_SelectTexture( 0 );
423         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
424 #else
425         GL_SelectTextureNoClient( 0 );
426 #endif
427         globalImages->normalCubeMapImage->Bind();
428
429         // texture 1 will be the per-surface bump map
430 #ifdef MACOS_X
431         GL_SelectTexture( 1 );
432         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
433 #else
434         GL_SelectTextureNoClient( 1 );
435 #endif
436         din->bumpImage->Bind();
437
438         // texture 2 will be the per-surface specular map
439 #ifdef MACOS_X
440         GL_SelectTexture( 2 );
441         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
442 #else
443         GL_SelectTextureNoClient( 2 );
444 #endif
445         din->specularImage->Bind();
446
447         // texture 3 will be the light projected texture
448 #ifdef MACOS_X
449         GL_SelectTexture( 3 );
450         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
451 #else
452         GL_SelectTextureNoClient( 3 );
453 #endif
454         din->lightImage->Bind();
455
456         // bind our "fragment program"
457         RB_NV20_SpecularColorFragment();
458
459         // override one parameter for inverted vertex color
460         if ( din->vertexColor == SVC_INVERSE_MODULATE ) {
461                 qglCombinerInputNV( GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_B_NV, 
462                         GL_PRIMARY_COLOR_NV, GL_UNSIGNED_INVERT_NV, GL_RGB );
463         }
464
465         // draw it
466         qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_SPECULAR_COLOR );
467         RB_DrawElementsWithCounters( din->surf->geo );
468 }
469
470
471
472 /*
473 ==================
474 RB_NV20_DiffuseAndSpecularColorFragment
475 ==================
476 */
477 static void RB_NV20_DiffuseAndSpecularColorFragment( void ) {
478         if ( r_useCombinerDisplayLists.GetBool() ) {
479                 qglCallList( fragmentDisplayListBase + FPROG_DIFFUSE_AND_SPECULAR_COLOR );
480                 return;
481         }
482
483         // program the nvidia register combiners
484         qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 3 );
485
486         // GL_CONSTANT_COLOR0_NV will be the diffuse color
487         // GL_CONSTANT_COLOR1_NV will be the specular color
488
489         // stage 0 rgb performs the dot product
490         // GL_SECONDARY_COLOR_NV = ( TEXTURE0 dot TEXTURE1 - 0.5 ) * 2
491         // the scale and bias steepen the specular curve
492         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, 
493                 GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
494         qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, 
495                 GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
496         qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB, 
497                 GL_SECONDARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
498                 GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_TRUE, GL_FALSE, GL_FALSE );
499
500         // stage 0 alpha does nothing
501
502         // stage 1 color takes bump * bump
503         // PRIMARY_COLOR = ( GL_SECONDARY_COLOR_NV * GL_SECONDARY_COLOR_NV - 0.5 ) * 2
504         // the scale and bias steepen the specular curve
505         qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, 
506                 GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
507         qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, 
508                 GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
509         qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB, 
510                 GL_SECONDARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
511                 GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE );
512
513         // stage 1 alpha does nothing
514
515         // stage 2 color
516         // PRIMARY_COLOR = ( PRIMARY_COLOR * TEXTURE3 ) * 2
517         // SPARE0 = 1.0 * 1.0 (needed for final combiner)
518         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV, 
519                 GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
520         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV, 
521                 GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
522         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_C_NV, 
523                 GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB );
524         qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_D_NV, 
525                 GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB );
526         qglCombinerOutputNV( GL_COMBINER2_NV, GL_RGB, 
527                 GL_SECONDARY_COLOR_NV, GL_SPARE0_NV, GL_DISCARD_NV,
528                 GL_SCALE_BY_TWO_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
529
530         // stage 2 alpha does nothing
531
532         // final combiner = TEXTURE2_ARB * CONSTANT_COLOR0_NV + PRIMARY_COLOR_NV * CONSTANT_COLOR1_NV
533         // alpha = GL_ZERO
534         qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_CONSTANT_COLOR1_NV,
535                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
536         qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_SECONDARY_COLOR_NV,
537                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
538         qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
539                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
540         qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_E_TIMES_F_NV,
541                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
542         qglFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_TEXTURE2_ARB,
543                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
544         qglFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_CONSTANT_COLOR0_NV,
545                 GL_UNSIGNED_IDENTITY_NV, GL_RGB );
546         qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
547                 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
548 }
549
550
551 /*
552 ==================
553 RB_NV20_DI_DiffuseAndSpecularColorPass
554
555 ==================
556 */
557 static void RB_NV20_DI_DiffuseAndSpecularColorPass( const drawInteraction_t *din ) {
558         RB_LogComment( "---------- RB_NV20_DI_DiffuseAndSpecularColorPass ----------\n" );
559
560         GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc );
561
562         // texture 0 is the normalization cube map for the half angle
563 // still bound from RB_NV_BumpAndLightPass
564 //      GL_SelectTextureNoClient( 0 );
565 //      GL_Bind( tr.normalCubeMapImage );
566
567         // texture 1 is the per-surface bump map
568 // still bound from RB_NV_BumpAndLightPass
569 //      GL_SelectTextureNoClient( 1 );
570 //      GL_Bind( din->bumpImage );
571
572         // texture 2 is the per-surface diffuse map
573 #ifdef MACOS_X
574         GL_SelectTexture( 2 );
575         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
576 #else
577         GL_SelectTextureNoClient( 2 );
578 #endif
579         din->diffuseImage->Bind();
580
581         // texture 3 is the per-surface specular map
582 #ifdef MACOS_X
583         GL_SelectTexture( 3 );
584         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
585 #else
586         GL_SelectTextureNoClient( 3 );
587 #endif
588         din->specularImage->Bind();
589
590         // bind our "fragment program"
591         RB_NV20_DiffuseAndSpecularColorFragment();
592
593         // draw it
594         qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_DIFFUSE_AND_SPECULAR_COLOR );
595         RB_DrawElementsWithCounters( din->surf->geo );
596 }
597
598
599 /*
600 ==================
601 RB_NV20_DrawInteraction
602 ==================
603 */
604 static void     RB_NV20_DrawInteraction( const drawInteraction_t *din ) {
605         const drawSurf_t *surf = din->surf;
606
607         // load all the vertex program parameters
608         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, din->localLightOrigin.ToFloatPtr() );
609         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_VIEW_ORIGIN, din->localViewOrigin.ToFloatPtr() );
610         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_S, din->lightProjection[0].ToFloatPtr() );
611         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_T, din->lightProjection[1].ToFloatPtr() );
612         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_Q, din->lightProjection[2].ToFloatPtr() );
613         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_FALLOFF_S, din->lightProjection[3].ToFloatPtr() );
614         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_S, din->bumpMatrix[0].ToFloatPtr() );
615         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_T, din->bumpMatrix[1].ToFloatPtr() );
616         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, din->diffuseMatrix[0].ToFloatPtr() );
617         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, din->diffuseMatrix[1].ToFloatPtr() );
618         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_S, din->specularMatrix[0].ToFloatPtr() );
619         qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_T, din->specularMatrix[1].ToFloatPtr() );
620
621         // set the constant colors
622         qglCombinerParameterfvNV( GL_CONSTANT_COLOR0_NV, din->diffuseColor.ToFloatPtr() );
623         qglCombinerParameterfvNV( GL_CONSTANT_COLOR1_NV, din->specularColor.ToFloatPtr() );
624
625         // vertex color passes should be pretty rare (cross-faded bump map surfaces), so always
626         // run them down as three-passes
627         if ( din->vertexColor != SVC_IGNORE ) {
628                 qglEnableClientState( GL_COLOR_ARRAY );
629                 RB_NV20_DI_BumpAndLightPass( din, false );
630                 RB_NV20_DI_DiffuseColorPass( din );
631                 RB_NV20_DI_SpecularColorPass( din );
632                 qglDisableClientState( GL_COLOR_ARRAY );
633                 return;
634         }
635
636         qglColor3f( 1, 1, 1 );
637
638         // on an ideal card, we would now just bind the textures and call a
639         // single pass vertex / fragment program, but
640         // on NV20, we need to decide which single / dual / tripple pass set of programs to use
641
642         // ambient light could be done as a single pass if we want to optimize for it
643
644         // monochrome light is two passes
645         int             internalFormat = din->lightImage->internalFormat;
646         if ( ( r_useNV20MonoLights.GetInteger() == 2 ) || 
647                 ( din->lightImage->isMonochrome && r_useNV20MonoLights.GetInteger() ) ) {
648                 // do a two-pass rendering
649                 RB_NV20_DI_BumpAndLightPass( din, true );
650                 RB_NV20_DI_DiffuseAndSpecularColorPass( din );
651         } else {
652                 // general case is three passes
653                 // ( bump dot lightDir ) * lightFalloff
654                 // diffuse * lightProject
655                 // specular * ( bump dot halfAngle extended ) * lightProject
656                 RB_NV20_DI_BumpAndLightPass( din, false );
657                 RB_NV20_DI_DiffuseColorPass( din );
658                 RB_NV20_DI_SpecularColorPass( din );
659         }
660 }
661
662
663 /*
664 =============
665 RB_NV20_CreateDrawInteractions
666
667 =============
668 */
669 static void RB_NV20_CreateDrawInteractions( const drawSurf_t *surf ) {
670         if ( !surf ) {
671                 return;
672         }
673
674         qglEnable( GL_VERTEX_PROGRAM_ARB );
675         qglEnable( GL_REGISTER_COMBINERS_NV );
676
677 #ifdef MACOS_X
678         GL_SelectTexture(0);
679         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
680 #else
681         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
682
683         qglEnableVertexAttribArrayARB( 8 );
684         qglEnableVertexAttribArrayARB( 9 );
685         qglEnableVertexAttribArrayARB( 10 );
686         qglEnableVertexAttribArrayARB( 11 );
687 #endif
688
689         for ( ; surf ; surf=surf->nextOnLight ) {
690                 // set the vertex pointers
691                 idDrawVert      *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache );
692                 qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color );
693 #ifdef MACOS_X
694                 GL_SelectTexture( 0 );
695                 qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
696                 GL_SelectTexture( 1 );
697                 qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() );
698                 GL_SelectTexture( 2 );
699                 qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() );
700                 GL_SelectTexture( 3 );
701                 qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() );
702                 GL_SelectTexture( 0 );
703 #else
704                 qglVertexAttribPointerARB( 11, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->normal.ToFloatPtr() );
705                 qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() );
706                 qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() );
707                 qglVertexAttribPointerARB( 8, 2, GL_FLOAT, false, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
708 #endif
709                 qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
710
711                 RB_CreateSingleDrawInteractions( surf, RB_NV20_DrawInteraction );
712         }
713
714 #ifndef MACOS_X
715         qglDisableVertexAttribArrayARB( 8 );
716         qglDisableVertexAttribArrayARB( 9 );
717         qglDisableVertexAttribArrayARB( 10 );
718         qglDisableVertexAttribArrayARB( 11 );
719 #endif
720
721         // disable features
722 #ifdef MACOS_X
723         GL_SelectTexture( 3 );
724         globalImages->BindNull();
725         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
726         
727         GL_SelectTexture( 2 );
728         globalImages->BindNull();
729         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
730         
731         GL_SelectTexture( 1 );
732         globalImages->BindNull();
733         qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
734 #else   
735         GL_SelectTextureNoClient( 3 );
736         globalImages->BindNull();
737
738         GL_SelectTextureNoClient( 2 );
739         globalImages->BindNull();
740
741         GL_SelectTextureNoClient( 1 );
742         globalImages->BindNull();
743 #endif
744
745         backEnd.glState.currenttmu = -1;
746         GL_SelectTexture( 0 );
747
748         qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
749
750         qglDisable( GL_VERTEX_PROGRAM_ARB );
751         qglDisable( GL_REGISTER_COMBINERS_NV );
752 }
753
754
755 //======================================================================================
756
757
758 /*
759 ==================
760 RB_NV20_DrawInteractions
761 ==================
762 */
763 void RB_NV20_DrawInteractions( void ) {
764         viewLight_t             *vLight;
765
766         //
767         // for each light, perform adding and shadowing
768         //
769         for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
770                 // do fogging later
771                 if ( vLight->lightShader->IsFogLight() ) {
772                         continue;
773                 }
774                 if ( vLight->lightShader->IsBlendLight() ) {
775                         continue;
776                 }
777                 if ( !vLight->localInteractions && !vLight->globalInteractions
778                         && !vLight->translucentInteractions ) {
779                         continue;
780                 }
781
782                 backEnd.vLight = vLight;
783
784                 RB_LogComment( "---------- RB_RenderViewLight 0x%p ----------\n", vLight );
785
786                 // clear the stencil buffer if needed
787                 if ( vLight->globalShadows || vLight->localShadows ) {
788                         backEnd.currentScissor = vLight->scissorRect;
789                         if ( r_useScissor.GetBool() ) {
790                                 qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1, 
791                                         backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
792                                         backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
793                                         backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
794                         }
795                         qglClear( GL_STENCIL_BUFFER_BIT );
796                 } else {
797                         // no shadows, so no need to read or write the stencil buffer
798                         // we might in theory want to use GL_ALWAYS instead of disabling
799                         // completely, to satisfy the invarience rules
800                         qglStencilFunc( GL_ALWAYS, 128, 255 );
801                 }
802
803                 backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
804
805                 if ( r_useShadowVertexProgram.GetBool() ) {
806                         qglEnable( GL_VERTEX_PROGRAM_ARB );
807                         qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
808                         RB_StencilShadowPass( vLight->globalShadows );
809                         RB_NV20_CreateDrawInteractions( vLight->localInteractions );
810                         qglEnable( GL_VERTEX_PROGRAM_ARB );
811                         qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
812                         RB_StencilShadowPass( vLight->localShadows );
813                         RB_NV20_CreateDrawInteractions( vLight->globalInteractions );
814                         qglDisable( GL_VERTEX_PROGRAM_ARB );    // if there weren't any globalInteractions, it would have stayed on
815                 } else {
816                         RB_StencilShadowPass( vLight->globalShadows );
817                         RB_NV20_CreateDrawInteractions( vLight->localInteractions );
818                         RB_StencilShadowPass( vLight->localShadows );
819                         RB_NV20_CreateDrawInteractions( vLight->globalInteractions );
820                 }
821
822                 // translucent surfaces never get stencil shadowed
823                 if ( r_skipTranslucent.GetBool() ) {
824                         continue;
825                 }
826
827                 qglStencilFunc( GL_ALWAYS, 128, 255 );
828
829                 backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
830                 RB_NV20_CreateDrawInteractions( vLight->translucentInteractions );
831
832                 backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
833         }
834 }
835
836 //=======================================================================
837
838 /*
839 ==================
840 R_NV20_Init
841
842 ==================
843 */
844 void R_NV20_Init( void ) {
845         glConfig.allowNV20Path = false;
846
847         common->Printf( "---------- R_NV20_Init ----------\n" );
848
849         if ( !glConfig.registerCombinersAvailable || !glConfig.ARBVertexProgramAvailable || glConfig.maxTextureUnits < 4 ) {
850                 common->Printf( "Not available.\n" );
851                 return;
852         }
853
854         GL_CheckErrors();
855
856         // create our "fragment program" display lists
857         fragmentDisplayListBase = qglGenLists( FPROG_NUM_FRAGMENT_PROGRAMS );
858
859         // force them to issue commands to build the list
860         bool temp = r_useCombinerDisplayLists.GetBool();
861         r_useCombinerDisplayLists.SetBool( false );
862
863         qglNewList( fragmentDisplayListBase + FPROG_BUMP_AND_LIGHT, GL_COMPILE );
864         RB_NV20_BumpAndLightFragment();
865         qglEndList();
866
867         qglNewList( fragmentDisplayListBase + FPROG_DIFFUSE_COLOR, GL_COMPILE );
868         RB_NV20_DiffuseColorFragment();
869         qglEndList();
870
871         qglNewList( fragmentDisplayListBase + FPROG_SPECULAR_COLOR, GL_COMPILE );
872         RB_NV20_SpecularColorFragment();
873         qglEndList();
874
875         qglNewList( fragmentDisplayListBase + FPROG_DIFFUSE_AND_SPECULAR_COLOR, GL_COMPILE );
876         RB_NV20_DiffuseAndSpecularColorFragment();
877         qglEndList();
878
879         r_useCombinerDisplayLists.SetBool( temp );
880
881         common->Printf( "---------------------------------\n" );
882
883         glConfig.allowNV20Path = true;
884 }
885