mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-23 12:53:09 +00:00
32530bf7a2
Only stubs left.
870 lines
29 KiB
C++
870 lines
29 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
|
|
|
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "sys/platform.h"
|
|
#include "renderer/VertexCache.h"
|
|
|
|
#include "renderer/tr_local.h"
|
|
|
|
typedef enum {
|
|
FPROG_BUMP_AND_LIGHT,
|
|
FPROG_DIFFUSE_COLOR,
|
|
FPROG_SPECULAR_COLOR,
|
|
FPROG_DIFFUSE_AND_SPECULAR_COLOR,
|
|
|
|
FPROG_NUM_FRAGMENT_PROGRAMS
|
|
} fragmentProgram_t;
|
|
|
|
GLuint fragmentDisplayListBase; // FPROG_NUM_FRAGMENT_PROGRAMS lists
|
|
|
|
void RB_NV20_DependentSpecularPass( const drawInteraction_t *din );
|
|
void RB_NV20_DependentAmbientPass( void );
|
|
|
|
/*
|
|
=========================================================================================
|
|
|
|
GENERAL INTERACTION RENDERING
|
|
|
|
=========================================================================================
|
|
*/
|
|
|
|
/*
|
|
====================
|
|
GL_SelectTextureNoClient
|
|
====================
|
|
*/
|
|
void GL_SelectTextureNoClient( int unit ) {
|
|
backEnd.glState.currenttmu = unit;
|
|
qglActiveTextureARB( GL_TEXTURE0_ARB + unit );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_BumpAndLightFragment
|
|
==================
|
|
*/
|
|
static void RB_NV20_BumpAndLightFragment( void ) {
|
|
if ( r_useCombinerDisplayLists.GetBool() ) {
|
|
qglCallList( fragmentDisplayListBase + FPROG_BUMP_AND_LIGHT );
|
|
return;
|
|
}
|
|
|
|
// program the nvidia register combiners
|
|
qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 3 );
|
|
|
|
// stage 0 rgb performs the dot product
|
|
// SPARE0 = TEXTURE0 dot TEXTURE1
|
|
qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
|
|
GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE );
|
|
|
|
|
|
// stage 1 rgb multiplies texture 2 and 3 together
|
|
// SPARE1 = TEXTURE2 * TEXTURE3
|
|
qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB,
|
|
GL_SPARE1_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
// stage 1 alpha does nohing
|
|
|
|
// stage 2 color multiplies spare0 * spare 1 just for debugging
|
|
// SPARE0 = SPARE0 * SPARE1
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER2_NV, GL_RGB,
|
|
GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
// stage 2 alpha multiples spare0 * spare 1
|
|
// SPARE0 = SPARE0 * SPARE1
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_ALPHA, GL_VARIABLE_A_NV,
|
|
GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_ALPHA, GL_VARIABLE_B_NV,
|
|
GL_SPARE1_NV, GL_UNSIGNED_IDENTITY_NV, GL_BLUE );
|
|
qglCombinerOutputNV( GL_COMBINER2_NV, GL_ALPHA,
|
|
GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
// final combiner
|
|
qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_SPARE0_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_SPARE0_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_DI_BumpAndLightPass
|
|
|
|
We are going to write alpha as light falloff * ( bump dot light ) * lightProjection
|
|
If the light isn't a monoLightShader, the lightProjection will be skipped, because
|
|
it will have to be done on an itterated basis
|
|
==================
|
|
*/
|
|
static void RB_NV20_DI_BumpAndLightPass( const drawInteraction_t *din, bool monoLightShader ) {
|
|
GL_State( GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc );
|
|
|
|
// texture 0 is the normalization cube map
|
|
// GL_TEXTURE0_ARB will be the normalized vector
|
|
// towards the light source
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 0 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 0 );
|
|
#endif
|
|
if ( din->ambientLight ) {
|
|
globalImages->ambientNormalMap->Bind();
|
|
} else {
|
|
globalImages->normalCubeMapImage->Bind();
|
|
}
|
|
|
|
// texture 1 will be the per-surface bump map
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 1 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 1 );
|
|
#endif
|
|
din->bumpImage->Bind();
|
|
|
|
// texture 2 will be the light falloff texture
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 2 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 2 );
|
|
#endif
|
|
din->lightFalloffImage->Bind();
|
|
|
|
// texture 3 will be the light projection texture
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 3 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 3 );
|
|
#endif
|
|
if ( monoLightShader ) {
|
|
din->lightImage->Bind();
|
|
} else {
|
|
// if the projected texture is multi-colored, we
|
|
// will need to do it in subsequent passes
|
|
globalImages->whiteImage->Bind();
|
|
}
|
|
|
|
// bind our "fragment program"
|
|
RB_NV20_BumpAndLightFragment();
|
|
|
|
// draw it
|
|
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_BUMP_AND_LIGHT );
|
|
RB_DrawElementsWithCounters( din->surf->geo );
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_DiffuseColorFragment
|
|
==================
|
|
*/
|
|
static void RB_NV20_DiffuseColorFragment( void ) {
|
|
if ( r_useCombinerDisplayLists.GetBool() ) {
|
|
qglCallList( fragmentDisplayListBase + FPROG_DIFFUSE_COLOR );
|
|
return;
|
|
}
|
|
|
|
// program the nvidia register combiners
|
|
qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 1 );
|
|
|
|
// stage 0 is free, so we always do the multiply of the vertex color
|
|
// when the vertex color is inverted, qglCombinerInputNV(GL_VARIABLE_B_NV) will be changed
|
|
qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
|
|
GL_TEXTURE0_ARB, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
qglCombinerOutputNV( GL_COMBINER0_NV, GL_ALPHA,
|
|
GL_DISCARD_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
|
|
// for GL_CONSTANT_COLOR0_NV * TEXTURE0 * TEXTURE1
|
|
qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_CONSTANT_COLOR0_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_E_TIMES_F_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_TEXTURE0_ARB,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_TEXTURE1_ARB,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
|
|
|
|
}
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_DI_DiffuseColorPass
|
|
|
|
==================
|
|
*/
|
|
static void RB_NV20_DI_DiffuseColorPass( const drawInteraction_t *din ) {
|
|
GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_ALPHAMASK
|
|
| backEnd.depthFunc );
|
|
|
|
// texture 0 will be the per-surface diffuse map
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 0 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 0 );
|
|
#endif
|
|
din->diffuseImage->Bind();
|
|
|
|
// texture 1 will be the light projected texture
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 1 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 1 );
|
|
#endif
|
|
din->lightImage->Bind();
|
|
|
|
// texture 2 is disabled
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 2 );
|
|
qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 2 );
|
|
#endif
|
|
globalImages->BindNull();
|
|
|
|
// texture 3 is disabled
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 3 );
|
|
qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 3 );
|
|
#endif
|
|
globalImages->BindNull();
|
|
|
|
// bind our "fragment program"
|
|
RB_NV20_DiffuseColorFragment();
|
|
|
|
// override one parameter for inverted vertex color
|
|
if ( din->vertexColor == SVC_INVERSE_MODULATE ) {
|
|
qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_PRIMARY_COLOR_NV, GL_UNSIGNED_INVERT_NV, GL_RGB );
|
|
}
|
|
|
|
// draw it
|
|
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_DIFFUSE_COLOR );
|
|
RB_DrawElementsWithCounters( din->surf->geo );
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_SpecularColorFragment
|
|
==================
|
|
*/
|
|
static void RB_NV20_SpecularColorFragment( void ) {
|
|
if ( r_useCombinerDisplayLists.GetBool() ) {
|
|
qglCallList( fragmentDisplayListBase + FPROG_SPECULAR_COLOR );
|
|
return;
|
|
}
|
|
|
|
// program the nvidia register combiners
|
|
qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 4 );
|
|
|
|
// we want GL_CONSTANT_COLOR1_NV * PRIMARY_COLOR * TEXTURE2 * TEXTURE3 * specular( TEXTURE0 * TEXTURE1 )
|
|
|
|
// stage 0 rgb performs the dot product
|
|
// GL_SPARE0_NV = ( TEXTURE0 dot TEXTURE1 - 0.5 ) * 2
|
|
// TEXTURE2 = TEXTURE2 * PRIMARY_COLOR
|
|
// the scale and bias steepen the specular curve
|
|
qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
|
|
GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_TRUE, GL_FALSE, GL_FALSE );
|
|
|
|
// stage 0 alpha does nothing
|
|
|
|
// stage 1 color takes bump * bump
|
|
// GL_SPARE0_NV = ( GL_SPARE0_NV * GL_SPARE0_NV - 0.5 ) * 2
|
|
// the scale and bias steepen the specular curve
|
|
qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB,
|
|
GL_SPARE0_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
// stage 1 alpha does nothing
|
|
|
|
// stage 2 color
|
|
// GL_SPARE0_NV = GL_SPARE0_NV * TEXTURE3
|
|
// SECONDARY_COLOR = CONSTANT_COLOR * TEXTURE2
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_C_NV,
|
|
GL_CONSTANT_COLOR1_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_D_NV,
|
|
GL_TEXTURE2_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER2_NV, GL_RGB,
|
|
GL_SPARE0_NV, GL_SECONDARY_COLOR_NV, GL_DISCARD_NV,
|
|
GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
// stage 2 alpha does nothing
|
|
|
|
|
|
// stage 3 scales the texture by the vertex color
|
|
qglCombinerInputNV( GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_PRIMARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER3_NV, GL_RGB,
|
|
GL_SECONDARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
// stage 3 alpha does nothing
|
|
|
|
// final combiner = GL_SPARE0_NV * SECONDARY_COLOR + PRIMARY_COLOR * SECONDARY_COLOR
|
|
qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_SPARE0_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_SECONDARY_COLOR_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_E_TIMES_F_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_SPARE0_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_SECONDARY_COLOR_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_DI_SpecularColorPass
|
|
|
|
==================
|
|
*/
|
|
static void RB_NV20_DI_SpecularColorPass( const drawInteraction_t *din ) {
|
|
GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_ALPHAMASK
|
|
| backEnd.depthFunc );
|
|
|
|
// texture 0 is the normalization cube map for the half angle
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 0 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 0 );
|
|
#endif
|
|
globalImages->normalCubeMapImage->Bind();
|
|
|
|
// texture 1 will be the per-surface bump map
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 1 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 1 );
|
|
#endif
|
|
din->bumpImage->Bind();
|
|
|
|
// texture 2 will be the per-surface specular map
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 2 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 2 );
|
|
#endif
|
|
din->specularImage->Bind();
|
|
|
|
// texture 3 will be the light projected texture
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 3 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 3 );
|
|
#endif
|
|
din->lightImage->Bind();
|
|
|
|
// bind our "fragment program"
|
|
RB_NV20_SpecularColorFragment();
|
|
|
|
// override one parameter for inverted vertex color
|
|
if ( din->vertexColor == SVC_INVERSE_MODULATE ) {
|
|
qglCombinerInputNV( GL_COMBINER3_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_PRIMARY_COLOR_NV, GL_UNSIGNED_INVERT_NV, GL_RGB );
|
|
}
|
|
|
|
// draw it
|
|
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_SPECULAR_COLOR );
|
|
RB_DrawElementsWithCounters( din->surf->geo );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_DiffuseAndSpecularColorFragment
|
|
==================
|
|
*/
|
|
static void RB_NV20_DiffuseAndSpecularColorFragment( void ) {
|
|
if ( r_useCombinerDisplayLists.GetBool() ) {
|
|
qglCallList( fragmentDisplayListBase + FPROG_DIFFUSE_AND_SPECULAR_COLOR );
|
|
return;
|
|
}
|
|
|
|
// program the nvidia register combiners
|
|
qglCombinerParameteriNV( GL_NUM_GENERAL_COMBINERS_NV, 3 );
|
|
|
|
// GL_CONSTANT_COLOR0_NV will be the diffuse color
|
|
// GL_CONSTANT_COLOR1_NV will be the specular color
|
|
|
|
// stage 0 rgb performs the dot product
|
|
// GL_SECONDARY_COLOR_NV = ( TEXTURE0 dot TEXTURE1 - 0.5 ) * 2
|
|
// the scale and bias steepen the specular curve
|
|
qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_TEXTURE0_ARB, GL_EXPAND_NORMAL_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER0_NV, GL_RGB,
|
|
GL_SECONDARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_TRUE, GL_FALSE, GL_FALSE );
|
|
|
|
// stage 0 alpha does nothing
|
|
|
|
// stage 1 color takes bump * bump
|
|
// PRIMARY_COLOR = ( GL_SECONDARY_COLOR_NV * GL_SECONDARY_COLOR_NV - 0.5 ) * 2
|
|
// the scale and bias steepen the specular curve
|
|
qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER1_NV, GL_RGB,
|
|
GL_SECONDARY_COLOR_NV, GL_DISCARD_NV, GL_DISCARD_NV,
|
|
GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
// stage 1 alpha does nothing
|
|
|
|
// stage 2 color
|
|
// PRIMARY_COLOR = ( PRIMARY_COLOR * TEXTURE3 ) * 2
|
|
// SPARE0 = 1.0 * 1.0 (needed for final combiner)
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_A_NV,
|
|
GL_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_B_NV,
|
|
GL_TEXTURE3_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_C_NV,
|
|
GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB );
|
|
qglCombinerInputNV( GL_COMBINER2_NV, GL_RGB, GL_VARIABLE_D_NV,
|
|
GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB );
|
|
qglCombinerOutputNV( GL_COMBINER2_NV, GL_RGB,
|
|
GL_SECONDARY_COLOR_NV, GL_SPARE0_NV, GL_DISCARD_NV,
|
|
GL_SCALE_BY_TWO_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
// stage 2 alpha does nothing
|
|
|
|
// final combiner = TEXTURE2_ARB * CONSTANT_COLOR0_NV + PRIMARY_COLOR_NV * CONSTANT_COLOR1_NV
|
|
// alpha = GL_ZERO
|
|
qglFinalCombinerInputNV( GL_VARIABLE_A_NV, GL_CONSTANT_COLOR1_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_B_NV, GL_SECONDARY_COLOR_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_C_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_D_NV, GL_E_TIMES_F_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_E_NV, GL_TEXTURE2_ARB,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_F_NV, GL_CONSTANT_COLOR0_NV,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_RGB );
|
|
qglFinalCombinerInputNV( GL_VARIABLE_G_NV, GL_ZERO,
|
|
GL_UNSIGNED_IDENTITY_NV, GL_ALPHA );
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_DI_DiffuseAndSpecularColorPass
|
|
|
|
==================
|
|
*/
|
|
static void RB_NV20_DI_DiffuseAndSpecularColorPass( const drawInteraction_t *din ) {
|
|
GL_State( GLS_SRCBLEND_DST_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc );
|
|
|
|
// texture 0 is the normalization cube map for the half angle
|
|
// still bound from RB_NV_BumpAndLightPass
|
|
// GL_SelectTextureNoClient( 0 );
|
|
// GL_Bind( tr.normalCubeMapImage );
|
|
|
|
// texture 1 is the per-surface bump map
|
|
// still bound from RB_NV_BumpAndLightPass
|
|
// GL_SelectTextureNoClient( 1 );
|
|
// GL_Bind( din->bumpImage );
|
|
|
|
// texture 2 is the per-surface diffuse map
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 2 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 2 );
|
|
#endif
|
|
din->diffuseImage->Bind();
|
|
|
|
// texture 3 is the per-surface specular map
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 3 );
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 3 );
|
|
#endif
|
|
din->specularImage->Bind();
|
|
|
|
// bind our "fragment program"
|
|
RB_NV20_DiffuseAndSpecularColorFragment();
|
|
|
|
// draw it
|
|
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_NV20_DIFFUSE_AND_SPECULAR_COLOR );
|
|
RB_DrawElementsWithCounters( din->surf->geo );
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_DrawInteraction
|
|
==================
|
|
*/
|
|
static void RB_NV20_DrawInteraction( const drawInteraction_t *din ) {
|
|
// load all the vertex program parameters
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_ORIGIN, din->localLightOrigin.ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_VIEW_ORIGIN, din->localViewOrigin.ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_S, din->lightProjection[0].ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_T, din->lightProjection[1].ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_PROJECT_Q, din->lightProjection[2].ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_LIGHT_FALLOFF_S, din->lightProjection[3].ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_S, din->bumpMatrix[0].ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_BUMP_MATRIX_T, din->bumpMatrix[1].ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_S, din->diffuseMatrix[0].ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_DIFFUSE_MATRIX_T, din->diffuseMatrix[1].ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_S, din->specularMatrix[0].ToFloatPtr() );
|
|
qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_SPECULAR_MATRIX_T, din->specularMatrix[1].ToFloatPtr() );
|
|
|
|
// set the constant colors
|
|
qglCombinerParameterfvNV( GL_CONSTANT_COLOR0_NV, din->diffuseColor.ToFloatPtr() );
|
|
qglCombinerParameterfvNV( GL_CONSTANT_COLOR1_NV, din->specularColor.ToFloatPtr() );
|
|
|
|
// vertex color passes should be pretty rare (cross-faded bump map surfaces), so always
|
|
// run them down as three-passes
|
|
if ( din->vertexColor != SVC_IGNORE ) {
|
|
qglEnableClientState( GL_COLOR_ARRAY );
|
|
RB_NV20_DI_BumpAndLightPass( din, false );
|
|
RB_NV20_DI_DiffuseColorPass( din );
|
|
RB_NV20_DI_SpecularColorPass( din );
|
|
qglDisableClientState( GL_COLOR_ARRAY );
|
|
return;
|
|
}
|
|
|
|
qglColor3f( 1, 1, 1 );
|
|
|
|
// on an ideal card, we would now just bind the textures and call a
|
|
// single pass vertex / fragment program, but
|
|
// on NV20, we need to decide which single / dual / tripple pass set of programs to use
|
|
|
|
// ambient light could be done as a single pass if we want to optimize for it
|
|
|
|
// monochrome light is two passes
|
|
if ( ( r_useNV20MonoLights.GetInteger() == 2 ) ||
|
|
( din->lightImage->isMonochrome && r_useNV20MonoLights.GetInteger() ) ) {
|
|
// do a two-pass rendering
|
|
RB_NV20_DI_BumpAndLightPass( din, true );
|
|
RB_NV20_DI_DiffuseAndSpecularColorPass( din );
|
|
} else {
|
|
// general case is three passes
|
|
// ( bump dot lightDir ) * lightFalloff
|
|
// diffuse * lightProject
|
|
// specular * ( bump dot halfAngle extended ) * lightProject
|
|
RB_NV20_DI_BumpAndLightPass( din, false );
|
|
RB_NV20_DI_DiffuseColorPass( din );
|
|
RB_NV20_DI_SpecularColorPass( din );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
RB_NV20_CreateDrawInteractions
|
|
|
|
=============
|
|
*/
|
|
static void RB_NV20_CreateDrawInteractions( const drawSurf_t *surf ) {
|
|
if ( !surf ) {
|
|
return;
|
|
}
|
|
|
|
qglEnable( GL_VERTEX_PROGRAM_ARB );
|
|
qglEnable( GL_REGISTER_COMBINERS_NV );
|
|
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture(0);
|
|
qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
|
|
qglEnableVertexAttribArrayARB( 8 );
|
|
qglEnableVertexAttribArrayARB( 9 );
|
|
qglEnableVertexAttribArrayARB( 10 );
|
|
qglEnableVertexAttribArrayARB( 11 );
|
|
#endif
|
|
|
|
for ( ; surf ; surf=surf->nextOnLight ) {
|
|
// set the vertex pointers
|
|
idDrawVert *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache );
|
|
qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color );
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 0 );
|
|
qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
|
|
GL_SelectTexture( 1 );
|
|
qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() );
|
|
GL_SelectTexture( 2 );
|
|
qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() );
|
|
GL_SelectTexture( 3 );
|
|
qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() );
|
|
GL_SelectTexture( 0 );
|
|
#else
|
|
qglVertexAttribPointerARB( 11, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->normal.ToFloatPtr() );
|
|
qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() );
|
|
qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() );
|
|
qglVertexAttribPointerARB( 8, 2, GL_FLOAT, false, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
|
|
#endif
|
|
qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
|
|
|
|
RB_CreateSingleDrawInteractions( surf, RB_NV20_DrawInteraction );
|
|
}
|
|
|
|
#ifndef MACOS_X
|
|
qglDisableVertexAttribArrayARB( 8 );
|
|
qglDisableVertexAttribArrayARB( 9 );
|
|
qglDisableVertexAttribArrayARB( 10 );
|
|
qglDisableVertexAttribArrayARB( 11 );
|
|
#endif
|
|
|
|
// disable features
|
|
#ifdef MACOS_X
|
|
GL_SelectTexture( 3 );
|
|
globalImages->BindNull();
|
|
qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
|
|
GL_SelectTexture( 2 );
|
|
globalImages->BindNull();
|
|
qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
|
|
GL_SelectTexture( 1 );
|
|
globalImages->BindNull();
|
|
qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
#else
|
|
GL_SelectTextureNoClient( 3 );
|
|
globalImages->BindNull();
|
|
|
|
GL_SelectTextureNoClient( 2 );
|
|
globalImages->BindNull();
|
|
|
|
GL_SelectTextureNoClient( 1 );
|
|
globalImages->BindNull();
|
|
#endif
|
|
|
|
backEnd.glState.currenttmu = -1;
|
|
GL_SelectTexture( 0 );
|
|
|
|
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
|
|
|
qglDisable( GL_VERTEX_PROGRAM_ARB );
|
|
qglDisable( GL_REGISTER_COMBINERS_NV );
|
|
}
|
|
|
|
|
|
//======================================================================================
|
|
|
|
|
|
/*
|
|
==================
|
|
RB_NV20_DrawInteractions
|
|
==================
|
|
*/
|
|
void RB_NV20_DrawInteractions( void ) {
|
|
viewLight_t *vLight;
|
|
|
|
//
|
|
// for each light, perform adding and shadowing
|
|
//
|
|
for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
|
|
// do fogging later
|
|
if ( vLight->lightShader->IsFogLight() ) {
|
|
continue;
|
|
}
|
|
if ( vLight->lightShader->IsBlendLight() ) {
|
|
continue;
|
|
}
|
|
if ( !vLight->localInteractions && !vLight->globalInteractions
|
|
&& !vLight->translucentInteractions ) {
|
|
continue;
|
|
}
|
|
|
|
backEnd.vLight = vLight;
|
|
|
|
// clear the stencil buffer if needed
|
|
if ( vLight->globalShadows || vLight->localShadows ) {
|
|
backEnd.currentScissor = vLight->scissorRect;
|
|
if ( r_useScissor.GetBool() ) {
|
|
qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
|
|
backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
|
|
backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
|
|
backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
|
|
}
|
|
qglClear( GL_STENCIL_BUFFER_BIT );
|
|
} else {
|
|
// no shadows, so no need to read or write the stencil buffer
|
|
// we might in theory want to use GL_ALWAYS instead of disabling
|
|
// completely, to satisfy the invarience rules
|
|
qglStencilFunc( GL_ALWAYS, 128, 255 );
|
|
}
|
|
|
|
backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
|
|
|
|
if ( r_useShadowVertexProgram.GetBool() ) {
|
|
qglEnable( GL_VERTEX_PROGRAM_ARB );
|
|
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
|
|
RB_StencilShadowPass( vLight->globalShadows );
|
|
RB_NV20_CreateDrawInteractions( vLight->localInteractions );
|
|
qglEnable( GL_VERTEX_PROGRAM_ARB );
|
|
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
|
|
RB_StencilShadowPass( vLight->localShadows );
|
|
RB_NV20_CreateDrawInteractions( vLight->globalInteractions );
|
|
qglDisable( GL_VERTEX_PROGRAM_ARB ); // if there weren't any globalInteractions, it would have stayed on
|
|
} else {
|
|
RB_StencilShadowPass( vLight->globalShadows );
|
|
RB_NV20_CreateDrawInteractions( vLight->localInteractions );
|
|
RB_StencilShadowPass( vLight->localShadows );
|
|
RB_NV20_CreateDrawInteractions( vLight->globalInteractions );
|
|
}
|
|
|
|
// translucent surfaces never get stencil shadowed
|
|
if ( r_skipTranslucent.GetBool() ) {
|
|
continue;
|
|
}
|
|
|
|
qglStencilFunc( GL_ALWAYS, 128, 255 );
|
|
|
|
backEnd.depthFunc = GLS_DEPTHFUNC_LESS;
|
|
RB_NV20_CreateDrawInteractions( vLight->translucentInteractions );
|
|
|
|
backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
|
|
/*
|
|
==================
|
|
R_NV20_Init
|
|
|
|
==================
|
|
*/
|
|
void R_NV20_Init( void ) {
|
|
glConfig.allowNV20Path = false;
|
|
|
|
common->Printf( "---------- R_NV20_Init ----------\n" );
|
|
|
|
if ( !glConfig.registerCombinersAvailable || !glConfig.ARBVertexProgramAvailable || glConfig.maxTextureUnits < 4 ) {
|
|
common->Printf( "Not available.\n" );
|
|
return;
|
|
}
|
|
|
|
GL_CheckErrors();
|
|
|
|
// create our "fragment program" display lists
|
|
fragmentDisplayListBase = qglGenLists( FPROG_NUM_FRAGMENT_PROGRAMS );
|
|
|
|
// force them to issue commands to build the list
|
|
bool temp = r_useCombinerDisplayLists.GetBool();
|
|
r_useCombinerDisplayLists.SetBool( false );
|
|
|
|
qglNewList( fragmentDisplayListBase + FPROG_BUMP_AND_LIGHT, GL_COMPILE );
|
|
RB_NV20_BumpAndLightFragment();
|
|
qglEndList();
|
|
|
|
qglNewList( fragmentDisplayListBase + FPROG_DIFFUSE_COLOR, GL_COMPILE );
|
|
RB_NV20_DiffuseColorFragment();
|
|
qglEndList();
|
|
|
|
qglNewList( fragmentDisplayListBase + FPROG_SPECULAR_COLOR, GL_COMPILE );
|
|
RB_NV20_SpecularColorFragment();
|
|
qglEndList();
|
|
|
|
qglNewList( fragmentDisplayListBase + FPROG_DIFFUSE_AND_SPECULAR_COLOR, GL_COMPILE );
|
|
RB_NV20_DiffuseAndSpecularColorFragment();
|
|
qglEndList();
|
|
|
|
r_useCombinerDisplayLists.SetBool( temp );
|
|
|
|
common->Printf( "---------------------------------\n" );
|
|
|
|
glConfig.allowNV20Path = true;
|
|
}
|