mirror of
https://github.com/dhewm/dhewm3.git
synced 2025-02-01 22:20:45 +00:00
736ec20d4d
Don't include the lazy precompiled.h everywhere, only what's required for the compilation unit. platform.h needs to be included instead to provide all essential defines and types. All includes use the relative path to the neo or the game specific root. Move all idlib related includes from idlib/Lib.h to precompiled.h. precompiled.h still exists for the MFC stuff in tools/. Add some missing header guards.
881 lines
29 KiB
C++
881 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_LogComment( "glActiveTextureARB( %i )\n", 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 ) {
|
|
RB_LogComment( "---------- RB_NV_BumpAndLightPass ----------\n" );
|
|
|
|
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 ) {
|
|
RB_LogComment( "---------- RB_NV20_DiffuseColorPass ----------\n" );
|
|
|
|
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 ) {
|
|
RB_LogComment( "---------- RB_NV20_SpecularColorPass ----------\n" );
|
|
|
|
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 ) {
|
|
RB_LogComment( "---------- RB_NV20_DI_DiffuseAndSpecularColorPass ----------\n" );
|
|
|
|
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;
|
|
|
|
RB_LogComment( "---------- RB_RenderViewLight 0x%p ----------\n", 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;
|
|
}
|