123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- /*
- ===========================================================================
- 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 "../idlib/precompiled.h"
- #pragma hdrstop
- #include "tr_local.h"
- #include "cg_explicit.h"
- CGcontext cg_context;
- static void cg_error_callback( void ) {
- CGerror i = cgGetError();
- common->Printf( "Cg error (%d): %s\n", i, cgGetErrorString(i) );
- }
- /*
- =========================================================================================
- GENERAL INTERACTION RENDERING
- =========================================================================================
- */
- /*
- ====================
- GL_SelectTextureNoClient
- ====================
- */
- static void GL_SelectTextureNoClient( int unit ) {
- backEnd.glState.currenttmu = unit;
- qglActiveTextureARB( GL_TEXTURE0_ARB + unit );
- RB_LogComment( "glActiveTextureARB( %i )\n", unit );
- }
- /*
- ==================
- RB_ARB2_DrawInteraction
- ==================
- */
- void RB_ARB2_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() );
- // testing fragment based normal mapping
- if ( r_testARBProgram.GetBool() ) {
- qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 2, din->localLightOrigin.ToFloatPtr() );
- qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 3, din->localViewOrigin.ToFloatPtr() );
- }
- static const float zero[4] = { 0, 0, 0, 0 };
- static const float one[4] = { 1, 1, 1, 1 };
- static const float negOne[4] = { -1, -1, -1, -1 };
- switch ( din->vertexColor ) {
- case SVC_IGNORE:
- qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, zero );
- qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one );
- break;
- case SVC_MODULATE:
- qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, one );
- qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, zero );
- break;
- case SVC_INVERSE_MODULATE:
- qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_MODULATE, negOne );
- qglProgramEnvParameter4fvARB( GL_VERTEX_PROGRAM_ARB, PP_COLOR_ADD, one );
- break;
- }
- // set the constant colors
- qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, din->diffuseColor.ToFloatPtr() );
- qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 1, din->specularColor.ToFloatPtr() );
- // set the textures
- // texture 1 will be the per-surface bump map
- GL_SelectTextureNoClient( 1 );
- din->bumpImage->Bind();
- // texture 2 will be the light falloff texture
- GL_SelectTextureNoClient( 2 );
- din->lightFalloffImage->Bind();
- // texture 3 will be the light projection texture
- GL_SelectTextureNoClient( 3 );
- din->lightImage->Bind();
- // texture 4 is the per-surface diffuse map
- GL_SelectTextureNoClient( 4 );
- din->diffuseImage->Bind();
- // texture 5 is the per-surface specular map
- GL_SelectTextureNoClient( 5 );
- din->specularImage->Bind();
- // draw it
- RB_DrawElementsWithCounters( din->surf->geo );
- }
- /*
- =============
- RB_ARB2_CreateDrawInteractions
- =============
- */
- void RB_ARB2_CreateDrawInteractions( const drawSurf_t *surf ) {
- if ( !surf ) {
- return;
- }
- // perform setup here that will be constant for all interactions
- GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc );
- // bind the vertex program
- if ( r_testARBProgram.GetBool() ) {
- qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_TEST );
- qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST );
- } else {
- qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION );
- qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION );
- }
- qglEnable(GL_VERTEX_PROGRAM_ARB);
- qglEnable(GL_FRAGMENT_PROGRAM_ARB);
- // enable the vertex arrays
- qglEnableVertexAttribArrayARB( 8 );
- qglEnableVertexAttribArrayARB( 9 );
- qglEnableVertexAttribArrayARB( 10 );
- qglEnableVertexAttribArrayARB( 11 );
- qglEnableClientState( GL_COLOR_ARRAY );
- // texture 0 is the normalization cube map for the vector towards the light
- GL_SelectTextureNoClient( 0 );
- if ( backEnd.vLight->lightShader->IsAmbientLight() ) {
- globalImages->ambientNormalMap->Bind();
- } else {
- globalImages->normalCubeMapImage->Bind();
- }
- // texture 6 is the specular lookup table
- GL_SelectTextureNoClient( 6 );
- if ( r_testARBProgram.GetBool() ) {
- globalImages->specular2DTableImage->Bind(); // variable specularity in alpha channel
- } else {
- globalImages->specularTableImage->Bind();
- }
- for ( ; surf ; surf=surf->nextOnLight ) {
- // perform setup here that will not change over multiple interaction passes
- // set the vertex pointers
- idDrawVert *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), ac->color );
- 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() );
- qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
- // this may cause RB_ARB2_DrawInteraction to be exacuted multiple
- // times with different colors and images if the surface or light have multiple layers
- RB_CreateSingleDrawInteractions( surf, RB_ARB2_DrawInteraction );
- }
- qglDisableVertexAttribArrayARB( 8 );
- qglDisableVertexAttribArrayARB( 9 );
- qglDisableVertexAttribArrayARB( 10 );
- qglDisableVertexAttribArrayARB( 11 );
- qglDisableClientState( GL_COLOR_ARRAY );
- // disable features
- GL_SelectTextureNoClient( 6 );
- globalImages->BindNull();
- GL_SelectTextureNoClient( 5 );
- globalImages->BindNull();
- GL_SelectTextureNoClient( 4 );
- globalImages->BindNull();
- GL_SelectTextureNoClient( 3 );
- globalImages->BindNull();
- GL_SelectTextureNoClient( 2 );
- globalImages->BindNull();
- GL_SelectTextureNoClient( 1 );
- globalImages->BindNull();
- backEnd.glState.currenttmu = -1;
- GL_SelectTexture( 0 );
- qglDisable(GL_VERTEX_PROGRAM_ARB);
- qglDisable(GL_FRAGMENT_PROGRAM_ARB);
- }
- /*
- ==================
- RB_ARB2_DrawInteractions
- ==================
- */
- void RB_ARB2_DrawInteractions( void ) {
- viewLight_t *vLight;
- const idMaterial *lightShader;
- GL_SelectTexture( 0 );
- qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
- //
- // for each light, perform adding and shadowing
- //
- for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
- backEnd.vLight = vLight;
- // do fogging later
- if ( vLight->lightShader->IsFogLight() ) {
- continue;
- }
- if ( vLight->lightShader->IsBlendLight() ) {
- continue;
- }
- if ( !vLight->localInteractions && !vLight->globalInteractions
- && !vLight->translucentInteractions ) {
- continue;
- }
- lightShader = vLight->lightShader;
- // 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 );
- }
- if ( r_useShadowVertexProgram.GetBool() ) {
- qglEnable( GL_VERTEX_PROGRAM_ARB );
- qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
- RB_StencilShadowPass( vLight->globalShadows );
- RB_ARB2_CreateDrawInteractions( vLight->localInteractions );
- qglEnable( GL_VERTEX_PROGRAM_ARB );
- qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW );
- RB_StencilShadowPass( vLight->localShadows );
- RB_ARB2_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_ARB2_CreateDrawInteractions( vLight->localInteractions );
- RB_StencilShadowPass( vLight->localShadows );
- RB_ARB2_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_ARB2_CreateDrawInteractions( vLight->translucentInteractions );
- backEnd.depthFunc = GLS_DEPTHFUNC_EQUAL;
- }
- // disable stencil shadow test
- qglStencilFunc( GL_ALWAYS, 128, 255 );
- GL_SelectTexture( 0 );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- }
- //===================================================================================
- typedef struct {
- GLenum target;
- GLuint ident;
- char name[64];
- } progDef_t;
- static const int MAX_GLPROGS = 200;
- // a single file can have both a vertex program and a fragment program
- static progDef_t progs[MAX_GLPROGS] = {
- { GL_VERTEX_PROGRAM_ARB, VPROG_TEST, "test.vfp" },
- { GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST, "test.vfp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION, "interaction.vfp" },
- { GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION, "interaction.vfp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_BUMPY_ENVIRONMENT, "bumpyEnvironment.vfp" },
- { GL_FRAGMENT_PROGRAM_ARB, FPROG_BUMPY_ENVIRONMENT, "bumpyEnvironment.vfp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_AMBIENT, "ambientLight.vfp" },
- { GL_FRAGMENT_PROGRAM_ARB, FPROG_AMBIENT, "ambientLight.vfp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW, "shadow.vp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_R200_INTERACTION, "R200_interaction.vp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_NV20_BUMP_AND_LIGHT, "nv20_bumpAndLight.vp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_NV20_DIFFUSE_COLOR, "nv20_diffuseColor.vp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_NV20_SPECULAR_COLOR, "nv20_specularColor.vp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_NV20_DIFFUSE_AND_SPECULAR_COLOR, "nv20_diffuseAndSpecularColor.vp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_ENVIRONMENT, "environment.vfp" },
- { GL_FRAGMENT_PROGRAM_ARB, FPROG_ENVIRONMENT, "environment.vfp" },
- { GL_VERTEX_PROGRAM_ARB, VPROG_GLASSWARP, "arbVP_glasswarp.txt" },
- { GL_FRAGMENT_PROGRAM_ARB, FPROG_GLASSWARP, "arbFP_glasswarp.txt" },
- // additional programs can be dynamically specified in materials
- };
- /*
- =================
- R_LoadARBProgram
- =================
- */
- void R_LoadARBProgram( int progIndex ) {
- int ofs;
- int err;
- idStr fullPath = "glprogs/";
- fullPath += progs[progIndex].name;
- char *fileBuffer;
- char *buffer;
- char *start, *end;
- common->Printf( "%s", fullPath.c_str() );
- // load the program even if we don't support it, so
- // fs_copyfiles can generate cross-platform data dumps
- fileSystem->ReadFile( fullPath.c_str(), (void **)&fileBuffer, NULL );
- if ( !fileBuffer ) {
- common->Printf( ": File not found\n" );
- return;
- }
- // copy to stack memory and free
- buffer = (char *)_alloca( strlen( fileBuffer ) + 1 );
- strcpy( buffer, fileBuffer );
- fileSystem->FreeFile( fileBuffer );
- if ( !glConfig.isInitialized ) {
- return;
- }
- //
- // submit the program string at start to GL
- //
- if ( progs[progIndex].ident == 0 ) {
- // allocate a new identifier for this program
- progs[progIndex].ident = PROG_USER + progIndex;
- }
- // vertex and fragment programs can both be present in a single file, so
- // scan for the proper header to be the start point, and stamp a 0 in after the end
- if ( progs[progIndex].target == GL_VERTEX_PROGRAM_ARB ) {
- if ( !glConfig.ARBVertexProgramAvailable ) {
- common->Printf( ": GL_VERTEX_PROGRAM_ARB not available\n" );
- return;
- }
- start = strstr( (char *)buffer, "!!ARBvp" );
- }
- if ( progs[progIndex].target == GL_FRAGMENT_PROGRAM_ARB ) {
- if ( !glConfig.ARBFragmentProgramAvailable ) {
- common->Printf( ": GL_FRAGMENT_PROGRAM_ARB not available\n" );
- return;
- }
- start = strstr( (char *)buffer, "!!ARBfp" );
- }
- if ( !start ) {
- common->Printf( ": !!ARB not found\n" );
- return;
- }
- end = strstr( start, "END" );
- if ( !end ) {
- common->Printf( ": END not found\n" );
- return;
- }
- end[3] = 0;
- qglBindProgramARB( progs[progIndex].target, progs[progIndex].ident );
- qglGetError();
- qglProgramStringARB( progs[progIndex].target, GL_PROGRAM_FORMAT_ASCII_ARB,
- strlen( start ), (unsigned char *)start );
- err = qglGetError();
- qglGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, (GLint *)&ofs );
- if ( err == GL_INVALID_OPERATION ) {
- const GLubyte *str = qglGetString( GL_PROGRAM_ERROR_STRING_ARB );
- common->Printf( "\nGL_PROGRAM_ERROR_STRING_ARB: %s\n", str );
- if ( ofs < 0 ) {
- common->Printf( "GL_PROGRAM_ERROR_POSITION_ARB < 0 with error\n" );
- } else if ( ofs >= (int)strlen( (char *)start ) ) {
- common->Printf( "error at end of program\n" );
- } else {
- common->Printf( "error at %i:\n%s", ofs, start + ofs );
- }
- return;
- }
- if ( ofs != -1 ) {
- common->Printf( "\nGL_PROGRAM_ERROR_POSITION_ARB != -1 without error\n" );
- return;
- }
- common->Printf( "\n" );
- }
- /*
- ==================
- R_FindARBProgram
- Returns a GL identifier that can be bound to the given target, parsing
- a text file if it hasn't already been loaded.
- ==================
- */
- int R_FindARBProgram( GLenum target, const char *program ) {
- int i;
- idStr stripped = program;
- stripped.StripFileExtension();
- // see if it is already loaded
- for ( i = 0 ; progs[i].name[0] ; i++ ) {
- if ( progs[i].target != target ) {
- continue;
- }
- idStr compare = progs[i].name;
- compare.StripFileExtension();
- if ( !idStr::Icmp( stripped.c_str(), compare.c_str() ) ) {
- return progs[i].ident;
- }
- }
- if ( i == MAX_GLPROGS ) {
- common->Error( "R_FindARBProgram: MAX_GLPROGS" );
- }
- // add it to the list and load it
- progs[i].ident = (program_t)0; // will be gen'd by R_LoadARBProgram
- progs[i].target = target;
- strncpy( progs[i].name, program, sizeof( progs[i].name ) - 1 );
- R_LoadARBProgram( i );
- return progs[i].ident;
- }
- /*
- ==================
- R_ReloadARBPrograms_f
- ==================
- */
- void R_ReloadARBPrograms_f( const idCmdArgs &args ) {
- int i;
- common->Printf( "----- R_ReloadARBPrograms -----\n" );
- for ( i = 0 ; progs[i].name[0] ; i++ ) {
- R_LoadARBProgram( i );
- }
- common->Printf( "-------------------------------\n" );
- }
- /*
- ==================
- R_ARB2_Init
- ==================
- */
- void R_ARB2_Init( void ) {
- glConfig.allowARB2Path = false;
- common->Printf( "---------- R_ARB2_Init ----------\n" );
- if ( !glConfig.ARBVertexProgramAvailable || !glConfig.ARBFragmentProgramAvailable ) {
- common->Printf( "Not available.\n" );
- return;
- }
- common->Printf( "Available.\n" );
- common->Printf( "---------------------------------\n" );
- glConfig.allowARB2Path = true;
- }
|