/* ** GL_SetDefaultState */ void GL_SetDefaultState( void ) { qglClearDepth( 1.0f ); qglCullFace(GL_FRONT); qglColor4f (1,1,1,1); // initialize downstream texture unit if we're running // in a multitexture environment if ( qglActiveTextureARB ) { GL_SelectTexture( 1 ); GL_TextureMode( r_textureMode->string ); GL_TexEnv( GL_MODULATE ); qglDisable( GL_TEXTURE_2D ); GL_SelectTexture( 0 ); } qglEnable(GL_TEXTURE_2D); GL_TextureMode( r_textureMode->string ); GL_TexEnv( GL_MODULATE ); //qglShadeModel( GL_SMOOTH ); qglDepthFunc( GL_LEQUAL ); // // make sure our GL state vector is set correctly // glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE; glState.storedGlState = 0; glState.faceCulling = CT_TWO_SIDED; glState.faceCullFront = qtrue; glState.currentProgram = 0; qglUseProgramObjectARB(0); if (glRefConfig.vertexArrayObject) qglBindVertexArrayARB(0); qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); glState.currentVao = NULL; glState.vertexAttribsEnabled = 0; qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglDepthMask( GL_TRUE ); qglDisable( GL_DEPTH_TEST ); qglEnable( GL_SCISSOR_TEST ); qglDisable( GL_CULL_FACE ); qglDisable( GL_BLEND ); if (glRefConfig.seamlessCubeMap) qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // GL_POLYGON_OFFSET_FILL will be glEnable()d when this is used qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky }
/* * RB_PolygonOffset */ void RB_PolygonOffset( float factor, float offset ) { if( rb.gl.polygonOffset[0] == factor && rb.gl.polygonOffset[1] == offset ) return; qglPolygonOffset( factor, offset ); rb.gl.polygonOffset[0] = factor; rb.gl.polygonOffset[1] = offset; }
/* ===================== RB_StencilShadowPass Stencil test should already be enabled, and the stencil buffer should have been set to 128 on any surfaces that might receive shadows ===================== */ void RB_StencilShadowPass(const drawSurf_t *drawSurfs) { if (!r_shadows.GetBool()) { return; } if (!drawSurfs) { return; } RB_LogComment("---------- RB_StencilShadowPass ----------\n"); globalImages->BindNull(); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); // for visualizing the shadows if (r_showShadows.GetInteger()) { if (r_showShadows.GetInteger() == 2) { // draw filled in GL_State(GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS); } else { // draw as lines, filling the depth buffer GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS); } } else { // don't write to the color buffer, just the stencil buffer GL_State(GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS); } if (r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat()) { qglPolygonOffset(r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat()); qglEnable(GL_POLYGON_OFFSET_FILL); } qglStencilFunc(GL_ALWAYS, 1, 255); if (glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool()) { qglEnable(GL_DEPTH_BOUNDS_TEST_EXT); } RB_RenderDrawSurfChainWithFunction(drawSurfs, RB_T_Shadow); GL_Cull(CT_FRONT_SIDED); if (r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat()) { qglDisable(GL_POLYGON_OFFSET_FILL); } if (glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool()) { qglDisable(GL_DEPTH_BOUNDS_TEST_EXT); } qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglStencilFunc(GL_GEQUAL, 128, 255); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); }
/* ================== GL_PolygonOffset ================== */ void GL_PolygonOffset (float factor, float units){ if (glState.polygonOffsetFactor == factor && glState.polygonOffsetUnits == units) return; glState.polygonOffsetFactor = factor; glState.polygonOffsetUnits = units; qglPolygonOffset(factor, units); }
/* ** GL_SetDefaultState */ void GL_SetDefaultState( void ) { qglClearDepth( 1.0f ); qglCullFace(GL_FRONT); qglColor4f (1,1,1,1); GL_BindNullTextures(); if (glRefConfig.framebufferObject) GL_BindNullFramebuffers(); qglEnable(GL_TEXTURE_2D); GL_TextureMode( r_textureMode->string ); //qglShadeModel( GL_SMOOTH ); qglDepthFunc( GL_LEQUAL ); // // make sure our GL state vector is set correctly // glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE; glState.storedGlState = 0; glState.faceCulling = CT_TWO_SIDED; glState.faceCullFront = qtrue; GL_BindNullProgram(); if (glRefConfig.vertexArrayObject) qglBindVertexArray(0); qglBindBuffer(GL_ARRAY_BUFFER, 0); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glState.currentVao = NULL; glState.vertexAttribsEnabled = 0; qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglDepthMask( GL_TRUE ); qglDisable( GL_DEPTH_TEST ); qglEnable( GL_SCISSOR_TEST ); qglDisable( GL_CULL_FACE ); qglDisable( GL_BLEND ); if (glRefConfig.seamlessCubeMap) qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // GL_POLYGON_OFFSET_FILL will be glEnable()d when this is used qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // FIXME: get color of sky }
/* ===================== RB_STD_FillDepthBuffer If we are rendering a subview with a near clip plane, use a second texture to force the alpha test to fail when behind that clip plane ===================== */ void RB_STD_FillDepthBuffer(drawSurf_t **drawSurfs, int numDrawSurfs) { // if we are just doing 2D rendering, no need to fill the depth buffer if (!backEnd.viewDef->viewEntitys) { return; } RB_LogComment("---------- RB_STD_FillDepthBuffer ----------\n"); // enable the second texture for mirror plane clipping if needed if (backEnd.viewDef->numClipPlanes) { GL_SelectTexture(1); globalImages->alphaNotchImage->Bind(); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglEnable(GL_TEXTURE_GEN_S); qglTexCoord2f(1, 0.5); } // the first texture will be used for alpha tested surfaces GL_SelectTexture(0); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); // decal surfaces may enable polygon offset qglPolygonOffset(r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat()); GL_State(GLS_DEPTHFUNC_LESS); // Enable stencil test if we are going to be using it for shadows. // If we didn't do this, it would be legal behavior to get z fighting // from the ambient pass and the light passes. qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_ALWAYS, 1, 255); RB_RenderDrawSurfListWithFunction(drawSurfs, numDrawSurfs, RB_T_FillDepthBuffer); if (backEnd.viewDef->numClipPlanes) { GL_SelectTexture(1); globalImages->BindNull(); qglDisable(GL_TEXTURE_GEN_S); GL_SelectTexture(0); } }
/* * RB_SetGLDefaults */ static void RB_SetGLDefaults( void ) { if( glConfig.stencilBits ) { qglStencilMask( ( GLuint ) ~0 ); qglStencilFunc( GL_EQUAL, 128, 0xFF ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); } qglDisable( GL_CULL_FACE ); qglFrontFace( GL_CCW ); qglDisable( GL_BLEND ); qglDepthFunc( GL_LEQUAL ); qglDepthMask( GL_FALSE ); qglDisable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( -1.0f, 0.0f ); // units will be handled by RB_DepthOffset qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); qglEnable( GL_DEPTH_TEST ); #ifndef GL_ES_VERSION_2_0 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); #endif qglFrontFace( GL_CCW ); }
/* ================ RB_PrepareStageTexturing ================ */ void RB_PrepareStageTexturing( const shaderStage_t *pStage, const drawSurf_t *surf, idDrawVert *ac ) { // set privatePolygonOffset if necessary if ( pStage->privatePolygonOffset ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * pStage->privatePolygonOffset ); } // set the texture matrix if needed if ( pStage->texture.hasMatrix ) { RB_LoadShaderTextureMatrix( surf->shaderRegisters, &pStage->texture ); } // texgens if ( pStage->texture.texgen == TG_DIFFUSE_CUBE ) { qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); } if ( pStage->texture.texgen == TG_SKYBOX_CUBE || pStage->texture.texgen == TG_WOBBLESKY_CUBE ) { qglTexCoordPointer( 3, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) ); } if ( pStage->texture.texgen == TG_SCREEN ) { qglEnable( GL_TEXTURE_GEN_S ); qglEnable( GL_TEXTURE_GEN_T ); qglEnable( GL_TEXTURE_GEN_Q ); float mat[16], plane[4]; myGlMultMatrix( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); plane[0] = mat[0]; plane[1] = mat[4]; plane[2] = mat[8]; plane[3] = mat[12]; qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane ); plane[0] = mat[1]; plane[1] = mat[5]; plane[2] = mat[9]; plane[3] = mat[13]; qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane ); plane[0] = mat[3]; plane[1] = mat[7]; plane[2] = mat[11]; plane[3] = mat[15]; qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane ); } if ( pStage->texture.texgen == TG_SCREEN2 ) { qglEnable( GL_TEXTURE_GEN_S ); qglEnable( GL_TEXTURE_GEN_T ); qglEnable( GL_TEXTURE_GEN_Q ); float mat[16], plane[4]; myGlMultMatrix( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); plane[0] = mat[0]; plane[1] = mat[4]; plane[2] = mat[8]; plane[3] = mat[12]; qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane ); plane[0] = mat[1]; plane[1] = mat[5]; plane[2] = mat[9]; plane[3] = mat[13]; qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane ); plane[0] = mat[3]; plane[1] = mat[7]; plane[2] = mat[11]; plane[3] = mat[15]; qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane ); } if ( pStage->texture.texgen == TG_GLASSWARP ) { if ( tr.backEndRenderer == BE_ARB2 /*|| tr.backEndRenderer == BE_NV30*/ ) { qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_GLASSWARP ); qglEnable( GL_FRAGMENT_PROGRAM_ARB ); GL_SelectTexture( 2 ); globalImages->scratchImage->Bind(); GL_SelectTexture( 1 ); globalImages->scratchImage2->Bind(); qglEnable( GL_TEXTURE_GEN_S ); qglEnable( GL_TEXTURE_GEN_T ); qglEnable( GL_TEXTURE_GEN_Q ); float mat[16], plane[4]; myGlMultMatrix( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, mat ); plane[0] = mat[0]; plane[1] = mat[4]; plane[2] = mat[8]; plane[3] = mat[12]; qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane ); plane[0] = mat[1]; plane[1] = mat[5]; plane[2] = mat[9]; plane[3] = mat[13]; qglTexGenfv( GL_T, GL_OBJECT_PLANE, plane ); plane[0] = mat[3]; plane[1] = mat[7]; plane[2] = mat[11]; plane[3] = mat[15]; qglTexGenfv( GL_Q, GL_OBJECT_PLANE, plane ); GL_SelectTexture( 0 ); } } if ( pStage->texture.texgen == TG_REFLECT_CUBE ) { if ( tr.backEndRenderer == BE_ARB2 ) { // see if there is also a bump map specified const shaderStage_t *bumpStage = surf->material->GetBumpStage(); if ( bumpStage ) { // per-pixel reflection mapping with bump mapping GL_SelectTexture( 1 ); bumpStage->texture.image->Bind(); GL_SelectTexture( 0 ); qglNormalPointer( GL_FLOAT, 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() ); qglEnableVertexAttribArrayARB( 9 ); qglEnableVertexAttribArrayARB( 10 ); qglEnableClientState( GL_NORMAL_ARRAY ); // Program env 5, 6, 7, 8 have been set in RB_SetProgramEnvironmentSpace qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_BUMPY_ENVIRONMENT ); qglEnable( GL_FRAGMENT_PROGRAM_ARB ); qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_BUMPY_ENVIRONMENT ); qglEnable( GL_VERTEX_PROGRAM_ARB ); } else { // per-pixel reflection mapping without a normal map qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); qglEnableClientState( GL_NORMAL_ARRAY ); qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_ENVIRONMENT ); qglEnable( GL_FRAGMENT_PROGRAM_ARB ); qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_ENVIRONMENT ); qglEnable( GL_VERTEX_PROGRAM_ARB ); } } else { qglEnable( GL_TEXTURE_GEN_S ); qglEnable( GL_TEXTURE_GEN_T ); qglEnable( GL_TEXTURE_GEN_R ); qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT ); qglEnableClientState( GL_NORMAL_ARRAY ); qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); qglMatrixMode( GL_TEXTURE ); float mat[16]; R_TransposeGLMatrix( backEnd.viewDef->worldSpace.modelViewMatrix, mat ); qglLoadMatrixf( mat ); qglMatrixMode( GL_MODELVIEW ); } } }
/* ================== RB_STD_T_RenderShaderPasses This is also called for the generated 2D rendering ================== */ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) { int stage; const idMaterial *shader; const shaderStage_t *pStage; const float *regs; float color[4]; const srfTriangles_t *tri; tri = surf->geo; shader = surf->material; if ( !shader->HasAmbient() ) { return; } if ( shader->IsPortalSky() ) { return; } // change the matrix if needed if ( surf->space != backEnd.currentSpace ) { qglLoadMatrixf( surf->space->modelViewMatrix ); backEnd.currentSpace = surf->space; RB_SetProgramEnvironmentSpace(); } // change the scissor if needed if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) { backEnd.currentScissor = surf->scissorRect; 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 ); } // some deforms may disable themselves by setting numIndexes = 0 if ( !tri->numIndexes ) { return; } if ( !tri->ambientCache ) { common->Printf( "RB_T_RenderShaderPasses: !tri->ambientCache\n" ); return; } // get the expressions for conditionals / color / texcoords regs = surf->shaderRegisters; // set face culling appropriately GL_Cull( shader->GetCullType() ); // set polygon offset if necessary if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); } if ( surf->space->weaponDepthHack ) { RB_EnterWeaponDepthHack(); } if ( surf->space->modelDepthHack != 0.0f ) { RB_EnterModelDepthHack( surf->space->modelDepthHack ); } idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache ); qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), reinterpret_cast<void *>(&ac->st) ); for ( stage = 0; stage < shader->GetNumStages() ; stage++ ) { pStage = shader->GetStage(stage); // check the enable condition if ( regs[ pStage->conditionRegister ] == 0 ) { continue; } // skip the stages involved in lighting if ( pStage->lighting != SL_AMBIENT ) { continue; } // skip if the stage is ( GL_ZERO, GL_ONE ), which is used for some alpha masks if ( ( pStage->drawStateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS) ) == ( GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE ) ) { continue; } // see if we are a new-style stage newShaderStage_t *newStage = pStage->newStage; if ( newStage ) { //-------------------------- // // new style stages // //-------------------------- // completely skip the stage if we don't have the capability if ( tr.backEndRenderer != BE_ARB2 ) { continue; } if ( r_skipNewAmbient.GetBool() ) { continue; } qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), (void *)&ac->color ); qglVertexAttribPointerARB( 9, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[0].ToFloatPtr() ); qglVertexAttribPointerARB( 10, 3, GL_FLOAT, false, sizeof( idDrawVert ), ac->tangents[1].ToFloatPtr() ); qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ac->normal.ToFloatPtr() ); qglEnableClientState( GL_COLOR_ARRAY ); qglEnableVertexAttribArrayARB( 9 ); qglEnableVertexAttribArrayARB( 10 ); qglEnableClientState( GL_NORMAL_ARRAY ); GL_State( pStage->drawStateBits ); qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, newStage->vertexProgram ); qglEnable( GL_VERTEX_PROGRAM_ARB ); // megaTextures bind a lot of images and set a lot of parameters if ( newStage->megaTexture ) { newStage->megaTexture->SetMappingForSurface( tri ); idVec3 localViewer; R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, localViewer ); newStage->megaTexture->BindForViewOrigin( localViewer ); } for ( int i = 0 ; i < newStage->numVertexParms ; i++ ) { float parm[4]; parm[0] = regs[ newStage->vertexParms[i][0] ]; parm[1] = regs[ newStage->vertexParms[i][1] ]; parm[2] = regs[ newStage->vertexParms[i][2] ]; parm[3] = regs[ newStage->vertexParms[i][3] ]; qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, parm ); } for ( int i = 0 ; i < newStage->numFragmentProgramImages ; i++ ) { if ( newStage->fragmentProgramImages[i] ) { GL_SelectTexture( i ); newStage->fragmentProgramImages[i]->Bind(); } } qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, newStage->fragmentProgram ); qglEnable( GL_FRAGMENT_PROGRAM_ARB ); // draw it RB_DrawElementsWithCounters( tri ); for ( int i = 1 ; i < newStage->numFragmentProgramImages ; i++ ) { if ( newStage->fragmentProgramImages[i] ) { GL_SelectTexture( i ); globalImages->BindNull(); } } if ( newStage->megaTexture ) { newStage->megaTexture->Unbind(); } GL_SelectTexture( 0 ); qglDisable( GL_VERTEX_PROGRAM_ARB ); qglDisable( GL_FRAGMENT_PROGRAM_ARB ); // Fixme: Hack to get around an apparent bug in ATI drivers. Should remove as soon as it gets fixed. qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, 0 ); qglDisableClientState( GL_COLOR_ARRAY ); qglDisableVertexAttribArrayARB( 9 ); qglDisableVertexAttribArrayARB( 10 ); qglDisableClientState( GL_NORMAL_ARRAY ); continue; } //-------------------------- // // old style stages // //-------------------------- // set the color color[0] = regs[ pStage->color.registers[0] ]; color[1] = regs[ pStage->color.registers[1] ]; color[2] = regs[ pStage->color.registers[2] ]; color[3] = regs[ pStage->color.registers[3] ]; // skip the entire stage if an add would be black if ( ( pStage->drawStateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS) ) == ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ) && color[0] <= 0 && color[1] <= 0 && color[2] <= 0 ) { continue; } // skip the entire stage if a blend would be completely transparent if ( ( pStage->drawStateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS) ) == ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) && color[3] <= 0 ) { continue; } // select the vertex color source if ( pStage->vertexColor == SVC_IGNORE ) { qglColor4fv( color ); } else { qglColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( idDrawVert ), (void *)&ac->color ); qglEnableClientState( GL_COLOR_ARRAY ); if ( pStage->vertexColor == SVC_INVERSE_MODULATE ) { GL_TexEnv( GL_COMBINE_ARB ); qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE ); qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE ); qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB ); qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR ); qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR ); qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 ); } // for vertex color and modulated color, we need to enable a second // texture stage if ( color[0] != 1 || color[1] != 1 || color[2] != 1 || color[3] != 1 ) { GL_SelectTexture( 1 ); globalImages->whiteImage->Bind(); GL_TexEnv( GL_COMBINE_ARB ); qglTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color ); qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE ); qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB ); qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB ); qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR ); qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR ); qglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1 ); qglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE ); qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB ); qglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_CONSTANT_ARB ); qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA ); qglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA ); qglTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1 ); GL_SelectTexture( 0 ); } } // bind the texture RB_BindVariableStageImage( &pStage->texture, regs ); // set the state GL_State( pStage->drawStateBits ); RB_PrepareStageTexturing( pStage, surf, ac ); // draw it RB_DrawElementsWithCounters( tri ); RB_FinishStageTexturing( pStage, surf, ac ); if ( pStage->vertexColor != SVC_IGNORE ) { qglDisableClientState( GL_COLOR_ARRAY ); GL_SelectTexture( 1 ); GL_TexEnv( GL_MODULATE ); globalImages->BindNull(); GL_SelectTexture( 0 ); GL_TexEnv( GL_MODULATE ); } } // reset polygon offset if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) { RB_LeaveDepthHack(); } }
/* ================== RB_T_FillDepthBuffer ================== */ void RB_T_FillDepthBuffer( const drawSurf_t *surf ) { int stage; const idMaterial *shader; const shaderStage_t *pStage; const float *regs; float color[4]; const srfTriangles_t *tri; tri = surf->geo; shader = surf->material; // update the clip plane if needed if ( backEnd.viewDef->numClipPlanes && surf->space != backEnd.currentSpace ) { GL_SelectTexture( 1 ); idPlane plane; R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.viewDef->clipPlanes[0], plane ); plane[3] += 0.5; // the notch is in the middle qglTexGenfv( GL_S, GL_OBJECT_PLANE, plane.ToFloatPtr() ); GL_SelectTexture( 0 ); } if ( !shader->IsDrawn() ) { return; } // some deforms may disable themselves by setting numIndexes = 0 if ( !tri->numIndexes ) { return; } // translucent surfaces don't put anything in the depth buffer and don't // test against it, which makes them fail the mirror clip plane operation if ( shader->Coverage() == MC_TRANSLUCENT ) { return; } if ( !tri->ambientCache ) { common->Printf( "RB_T_FillDepthBuffer: !tri->ambientCache\n" ); return; } // get the expressions for conditionals / color / texcoords regs = surf->shaderRegisters; // if all stages of a material have been conditioned off, don't do anything for ( stage = 0; stage < shader->GetNumStages() ; stage++ ) { pStage = shader->GetStage(stage); // check the stage enable condition if ( regs[ pStage->conditionRegister ] != 0 ) { break; } } if ( stage == shader->GetNumStages() ) { return; } // set polygon offset if necessary if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor.GetFloat(), r_offsetUnits.GetFloat() * shader->GetPolygonOffset() ); } // subviews will just down-modulate the color buffer by overbright if ( shader->GetSort() == SS_SUBVIEW ) { GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO | GLS_DEPTHFUNC_LESS ); color[0] = color[1] = color[2] = ( 1.0 / backEnd.overBright ); color[3] = 1; } else { // others just draw black color[0] = 0; color[1] = 0; color[2] = 0; color[3] = 1; } idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache ); qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), reinterpret_cast<void *>(&ac->st) ); bool drawSolid = false; if ( shader->Coverage() == MC_OPAQUE ) { drawSolid = true; } // we may have multiple alpha tested stages if ( shader->Coverage() == MC_PERFORATED ) { // if the only alpha tested stages are condition register omitted, // draw a normal opaque surface bool didDraw = false; qglEnable( GL_ALPHA_TEST ); // perforated surfaces may have multiple alpha tested stages for ( stage = 0; stage < shader->GetNumStages() ; stage++ ) { pStage = shader->GetStage(stage); if ( !pStage->hasAlphaTest ) { continue; } // check the stage enable condition if ( regs[ pStage->conditionRegister ] == 0 ) { continue; } // if we at least tried to draw an alpha tested stage, // we won't draw the opaque surface didDraw = true; // set the alpha modulate color[3] = regs[ pStage->color.registers[3] ]; // skip the entire stage if alpha would be black if ( color[3] <= 0 ) { continue; } qglColor4fv( color ); qglAlphaFunc( GL_GREATER, regs[ pStage->alphaTestRegister ] ); // bind the texture pStage->texture.image->Bind(); // set texture matrix and texGens RB_PrepareStageTexturing( pStage, surf, ac ); // draw it RB_DrawElementsWithCounters( tri ); RB_FinishStageTexturing( pStage, surf, ac ); } qglDisable( GL_ALPHA_TEST ); if ( !didDraw ) { drawSolid = true; } } // draw the entire surface solid if ( drawSolid ) { qglColor4fv( color ); globalImages->whiteImage->Bind(); // draw it RB_DrawElementsWithCounters( tri ); } // reset polygon offset if ( shader->TestMaterialFlag(MF_POLYGONOFFSET) ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } // reset blending if ( shader->GetSort() == SS_SUBVIEW ) { GL_State( GLS_DEPTHFUNC_LESS ); } }
/* ** RB_StageIteratorGeneric */ void RB_StageIteratorGeneric( void ) { shaderCommands_t *input; unsigned int vertexAttribs = 0; input = &tess; if (!input->numVertexes || !input->numIndexes) { return; } if (tess.useInternalVBO) { RB_DeformTessGeometry(); } vertexAttribs = RB_CalcShaderVertexAttribs( input ); if (tess.useInternalVBO) { RB_UpdateVBOs(vertexAttribs); } else { backEnd.pc.c_staticVboDraws++; } // // log this call // if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); } // // set face culling appropriately // if ((backEnd.viewParms.flags & VPF_DEPTHSHADOW)) { //GL_Cull( CT_TWO_SIDED ); if (input->shader->cullType == CT_TWO_SIDED) GL_Cull( CT_TWO_SIDED ); else if (input->shader->cullType == CT_FRONT_SIDED) GL_Cull( CT_BACK_SIDED ); else GL_Cull( CT_FRONT_SIDED ); } else GL_Cull( input->shader->cullType ); // set polygon offset if necessary if ( input->shader->polygonOffset ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } // // Set vertex attribs and pointers // GLSL_VertexAttribsState(vertexAttribs); // // render depth if in depthfill mode // if (backEnd.depthFill) { RB_IterateStagesGeneric( input ); // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } return; } // // render shadowmap if in shadowmap mode // if (backEnd.viewParms.flags & VPF_SHADOWMAP) { if ( input->shader->sort == SS_OPAQUE ) { RB_RenderShadowmap( input ); } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } return; } // // // call shader function // RB_IterateStagesGeneric( input ); // // pshadows! // if (glRefConfig.framebufferObject && tess.pshadowBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { ProjectPshadowVBOGLSL(); } // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader && (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer) { ForwardDlight(); } else { ProjectDlightTexture(); } } if ((backEnd.viewParms.flags & VPF_USESUNLIGHT) && tess.shader->sort <= SS_OPAQUE //if ((tr.sunShadows || r_forceSunlight->value > 0.0f) && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) && tess.xstages[0]->glslShaderGroup == tr.lightallShader) { ForwardSunlight(); } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(); } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } }
/* ** RB_StageIteratorGeneric */ void RB_StageIteratorGeneric( void ) { shaderCommands_t *input; input = &tess; RB_DeformTessGeometry(); // // log this call // if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va( "--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name ) ); } // set GL fog SetIteratorFog(); if ( qglPNTrianglesiATI && tess.ATI_tess ) { // RF< so we can send the normals as an array qglEnableClientState( GL_NORMAL_ARRAY ); #ifdef __MACOS__ //DAJ ATI qglPNTrianglesiATI( GL_PN_TRIANGLES_ATI, 1 ); #else qglEnable( GL_PN_TRIANGLES_ATI ); // ATI PN-Triangles extension #endif } // // set face culling appropriately // GL_Cull( input->shader->cullType ); // set polygon offset if necessary if ( input->shader->polygonOffset ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } // // if there is only a single pass then we can enable color // and texture arrays before we compile, otherwise we need // to avoid compiling those arrays since they will change // during multipass rendering // if ( tess.numPasses > 1 || input->shader->multitextureEnv ) { setArraysOnce = qfalse; qglDisableClientState( GL_COLOR_ARRAY ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); } else { setArraysOnce = qtrue; qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); } // RF, send normals only if required // This must be done first, since we can't change the arrays once they have been // locked if ( qglPNTrianglesiATI && tess.ATI_tess ) { qglNormalPointer( GL_FLOAT, 16, input->normal ); } // // lock XYZ // qglVertexPointer( 3, GL_FLOAT, 16, input->xyz ); // padded for SIMD if ( qglLockArraysEXT ) { qglLockArraysEXT( 0, input->numVertexes ); GLimp_LogComment( "glLockArraysEXT\n" ); } // // enable color and texcoord arrays after the lock if necessary // if ( !setArraysOnce ) { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglEnableClientState( GL_COLOR_ARRAY ); } // // call shader function // RB_IterateStagesGeneric( input ); // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && !( tess.shader->surfaceFlags & ( SURF_NODLIGHT | SURF_SKY ) ) ) { ProjectDlightTexture(); } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(); } // // unlock arrays // if ( qglUnlockArraysEXT ) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } // turn truform back off if ( qglPNTrianglesiATI && tess.ATI_tess ) { #ifdef __MACOS__ //DAJ ATI qglPNTrianglesiATI( GL_PN_TRIANGLES_ATI, 0 ); #else qglDisable( GL_PN_TRIANGLES_ATI ); // ATI PN-Triangles extension #endif qglDisableClientState( GL_NORMAL_ARRAY ); } }
/* ** RB_StageIteratorGeneric */ void RB_StageIteratorGeneric( void ) { shaderCommands_t *input; unsigned int vertexAttribs = 0; input = &tess; if (!input->numVertexes || !input->numIndexes) { return; } if (tess.useInternalVBO) { RB_DeformTessGeometry(); } vertexAttribs = RB_CalcShaderVertexAttribs( input ); if (tess.useInternalVBO) { RB_UpdateVBOs(vertexAttribs); } else { backEnd.pc.c_staticVboDraws++; } // // log this call // if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); } if ( qglPNTrianglesiATI && tess.ATI_tess ) { // RF< so we can send the normals as an array qglEnableClientState( GL_NORMAL_ARRAY ); qglEnable( GL_PN_TRIANGLES_ATI ); // ATI PN-Triangles extension } // // set face culling appropriately // if ((backEnd.viewParms.flags & VPF_DEPTHSHADOW)) { //GL_Cull( CT_TWO_SIDED ); if (input->shader->cullType == CT_TWO_SIDED) GL_Cull( CT_TWO_SIDED ); else if (input->shader->cullType == CT_FRONT_SIDED) GL_Cull( CT_BACK_SIDED ); else GL_Cull( CT_FRONT_SIDED ); } else GL_Cull( input->shader->cullType ); // set polygon offset if necessary if ( input->shader->polygonOffset ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } // // Set vertex attribs and pointers // GLSL_VertexAttribsState(vertexAttribs); // // render depth if in depthfill mode // if (backEnd.depthFill) { RB_IterateStagesGeneric( input ); // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } return; } // // render shadowmap if in shadowmap mode // if (backEnd.viewParms.flags & VPF_SHADOWMAP) { if ( input->shader->sort == SS_OPAQUE ) { RB_RenderShadowmap( input ); } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } return; } // // // call shader function // RB_IterateStagesGeneric( input ); // // pshadows! // if (glRefConfig.framebufferObject && r_shadows->integer == 4 && tess.pshadowBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { ProjectPshadowVBOGLSL(); } // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader && (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer) { ForwardDlight(); } else { ProjectDlightTexture(); } } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(0); } // // RTCW fog // may not match original RTCW fog, since that's done per stage // if ( r_wolffog->integer && tess.shader->fogPass && tess.shader->sort <= SS_OPAQUE ) { int stage, stageFog = 0; // make sure at least one stage has fog for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { shaderStage_t *pStage = tess.xstages[stage]; if ( !pStage ) { break; } if (pStage->isFogged) { stageFog = 1; break; } } // FIXME: this logic sucks if (tess.shader->noFog && stageFog) { RB_FogPass(1); } else if (tess.shader->noFog && !stageFog) { } else { RB_FogPass(1); } } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } // turn truform back off if ( qglPNTrianglesiATI && tess.ATI_tess ) { qglDisable( GL_PN_TRIANGLES_ATI ); // ATI PN-Triangles extension qglDisableClientState( GL_NORMAL_ARRAY ); } }
/* ================== GL_SetDefaultState ================== */ void GL_SetDefaultState (){ int i; QGL_LogPrintf("---------- GL_SetDefaultState ----------\n"); // Reset the state manager glState.projectionMatrixIdentity = true; glState.modelviewMatrixIdentity = true; for (i = 0; i < MAX_TEXTURE_UNITS; i++) glState.textureMatrixIdentity[i] = true; for (i = 0; i < MAX_TEXTURE_UNITS; i++) glState.texture[i] = NULL; glState.program = NULL; glState.indexBuffer = NULL; glState.vertexBuffer = NULL; glState.viewportX = 0; glState.viewportY = 0; glState.viewportWidth = glConfig.videoWidth; glState.viewportHeight = glConfig.videoHeight; glState.scissorX = 0; glState.scissorY = 0; glState.scissorWidth = glConfig.videoWidth; glState.scissorHeight = glConfig.videoHeight; glState.depthBoundsMin = 0.0f; glState.depthBoundsMax = 1.0f; glState.texUnit = 0; for (i = 0; i < MAX_TEXTURE_UNITS; i++){ glState.texTarget[i] = 0; glState.texEnv[i] = GL_MODULATE; glState.texGen[i][0] = GL_OBJECT_LINEAR; glState.texGen[i][1] = GL_OBJECT_LINEAR; glState.texGen[i][2] = GL_OBJECT_LINEAR; glState.texGen[i][3] = GL_OBJECT_LINEAR; } glState.cullFace = false; glState.polygonOffsetFill = false; glState.polygonOffsetLine = false; glState.blend = false; glState.alphaTest = false; glState.depthTest = false; glState.stencilTest = false; for (i = 0; i < MAX_TEXTURE_UNITS; i++){ glState.textureGen[i][0] = false; glState.textureGen[i][1] = false; glState.textureGen[i][2] = false; glState.textureGen[i][3] = false; } glState.cullMode = GL_FRONT; glState.polygonMode = GL_FILL; glState.polygonOffsetFactor = 0.0f; glState.polygonOffsetUnits = 0.0f; glState.blendSrc = GL_ONE; glState.blendDst = GL_ZERO; glState.blendMode = GL_FUNC_ADD; glState.alphaFunc = GL_GREATER; glState.alphaFuncRef = 0.0f; glState.depthFunc = GL_LEQUAL; glState.stencilFunc[0] = GL_ALWAYS; glState.stencilFunc[1] = GL_ALWAYS; glState.stencilFuncRef[0] = 0; glState.stencilFuncRef[1] = 0; glState.stencilFuncMask[0] = 255; glState.stencilFuncMask[1] = 255; glState.stencilOpFail[0] = GL_KEEP; glState.stencilOpFail[1] = GL_KEEP; glState.stencilOpZFail[0] = GL_KEEP; glState.stencilOpZFail[1] = GL_KEEP; glState.stencilOpZPass[0] = GL_KEEP; glState.stencilOpZPass[1] = GL_KEEP; glState.depthMin = 0.0f; glState.depthMax = 1.0f; glState.colorMask[0] = GL_TRUE; glState.colorMask[1] = GL_TRUE; glState.colorMask[2] = GL_TRUE; glState.colorMask[3] = GL_TRUE; glState.depthMask = GL_TRUE; glState.stencilMask[0] = 255; glState.stencilMask[1] = 255; // Set default state qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); for (i = MAX_TEXTURE_UNITS - 1; i >= 0; i--){ if (i >= glConfig.maxTextureImageUnits) continue; if (i >= glConfig.maxTextureUnits){ qglActiveTexture(GL_TEXTURE0 + i); qglBindTexture(GL_TEXTURE_2D, 0); qglBindTexture(GL_TEXTURE_3D, 0); qglBindTexture(GL_TEXTURE_CUBE_MAP, 0); qglBindTexture(GL_TEXTURE_2D_ARRAY, 0); continue; } qglActiveTexture(GL_TEXTURE0 + i); qglMatrixMode(GL_TEXTURE); qglLoadIdentity(); qglDisable(GL_TEXTURE_2D); qglDisable(GL_TEXTURE_3D); qglDisable(GL_TEXTURE_CUBE_MAP); qglDisable(GL_TEXTURE_2D_ARRAY); qglBindTexture(GL_TEXTURE_2D, 0); qglBindTexture(GL_TEXTURE_3D, 0); qglBindTexture(GL_TEXTURE_CUBE_MAP, 0); qglBindTexture(GL_TEXTURE_2D_ARRAY, 0); qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); qglDisable(GL_TEXTURE_GEN_S); qglDisable(GL_TEXTURE_GEN_T); qglDisable(GL_TEXTURE_GEN_R); qglDisable(GL_TEXTURE_GEN_Q); qglTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); qglTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); qglTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); qglTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); } qglDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS); qglUseProgram(0); qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); qglBindBuffer(GL_ARRAY_BUFFER, 0); qglViewport(0, 0, glConfig.videoWidth, glConfig.videoHeight); qglEnable(GL_SCISSOR_TEST); qglScissor(0, 0, glConfig.videoWidth, glConfig.videoHeight); qglEnable(GL_DEPTH_BOUNDS_TEST_EXT); qglDepthBoundsEXT(0.0f, 1.0f); qglFrontFace(GL_CCW); qglShadeModel(GL_SMOOTH); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); qglDisable(GL_CULL_FACE); qglCullFace(GL_FRONT); qglDisable(GL_POLYGON_OFFSET_FILL); qglDisable(GL_POLYGON_OFFSET_LINE); qglPolygonOffset(0.0f, 0.0f); qglDisable(GL_BLEND); qglBlendFunc(GL_ONE, GL_ZERO); qglBlendEquation(GL_FUNC_ADD); qglDisable(GL_ALPHA_TEST); qglAlphaFunc(GL_GREATER, 0.0f); qglDisable(GL_DEPTH_TEST); qglDepthFunc(GL_LEQUAL); qglDisable(GL_STENCIL_TEST); qglStencilFunc(GL_ALWAYS, 128, 255); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); qglDepthRange(0.0f, 1.0f); qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); qglDepthMask(GL_TRUE); qglStencilMask(255); qglDisable(GL_DEPTH_CLAMP); qglDisable(GL_CLIP_PLANE0); if (glConfig.multiSamples > 1){ qglDisable(GL_MULTISAMPLE); qglDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); } qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); qglClearDepth(1.0f); qglClearStencil(128); qglEnableClientState(GL_VERTEX_ARRAY); qglDisableVertexAttribArray(GL_ATTRIB_NORMAL); qglDisableVertexAttribArray(GL_ATTRIB_TANGENT1); qglDisableVertexAttribArray(GL_ATTRIB_TANGENT2); qglDisableVertexAttribArray(GL_ATTRIB_TEXCOORD); qglDisableVertexAttribArray(GL_ATTRIB_COLOR); QGL_LogPrintf("--------------------\n"); }
/* ================ DrawTris Draws triangle outlines for debugging ================ */ static void DrawTris( shaderCommands_t *input ) { char *s = r_trisColor->string; vec4_t trisColor = { 1, 1, 1, 1 }; unsigned int stateBits = 0; GL_Bind( tr.whiteImage ); if ( *s == '0' && ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) { s += 2; if ( Q_IsHexColorString( s ) ) { trisColor[0] = ( (float)( gethex( *( s ) ) * 16 + gethex( *( s + 1 ) ) ) ) / 255.00; trisColor[1] = ( (float)( gethex( *( s + 2 ) ) * 16 + gethex( *( s + 3 ) ) ) ) / 255.00; trisColor[2] = ( (float)( gethex( *( s + 4 ) ) * 16 + gethex( *( s + 5 ) ) ) ) / 255.00; if ( Q_HexColorStringHasAlpha( s ) ) { trisColor[3] = ( (float)( gethex( *( s + 6 ) ) * 16 + gethex( *( s + 7 ) ) ) ) / 255.00; } } } else { int i; char *token; for ( i = 0 ; i < 4 ; i++ ) { token = COM_Parse( &s ); if ( token ) { trisColor[i] = atof( token ); } else { trisColor[i] = 1.f; } } if ( !trisColor[3] ) { trisColor[3] = 1.f; } } if ( trisColor[3] < 1.f ) { stateBits |= ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); } qglColor4fv( trisColor ); // ydnar r_showtris 2 if ( r_showtris->integer == 2 ) { stateBits |= ( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); GL_State( stateBits ); qglDepthRange( 0, 0 ); } #ifdef CELSHADING_HACK else if ( r_showtris->integer == 3 ) { stateBits |= ( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); GL_State( stateBits ); qglEnable( GL_POLYGON_OFFSET_LINE ); qglPolygonOffset( 4.0, 0.5 ); qglLineWidth( 5.0 ); } #endif else { stateBits |= ( GLS_POLYMODE_LINE ); GL_State( stateBits ); qglEnable( GL_POLYGON_OFFSET_LINE ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } qglDisableClientState( GL_COLOR_ARRAY ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); qglVertexPointer( 3, GL_FLOAT, 16, input->xyz ); // padded for SIMD if ( qglLockArraysEXT ) { qglLockArraysEXT( 0, input->numVertexes ); GLimp_LogComment( "glLockArraysEXT\n" ); } R_DrawElements( input->numIndexes, input->indexes ); if ( qglUnlockArraysEXT ) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } qglDepthRange( 0, 1 ); qglDisable( GL_POLYGON_OFFSET_LINE ); }
/* ** RB_StageIteratorGeneric */ void RB_StageIteratorGeneric( void ) { shaderCommands_t *input; shader_t *shader; input = &tess; shader = input->shader; RB_DeformTessGeometry(); // // log this call // if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); } // // set face culling appropriately // GL_Cull( shader->cullType ); // set polygon offset if necessary if ( shader->polygonOffset ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } // // if there is only a single pass then we can enable color // and texture arrays before we compile, otherwise we need // to avoid compiling those arrays since they will change // during multipass rendering // if ( tess.numPasses > 1 || shader->multitextureEnv ) { setArraysOnce = qfalse; qglDisableClientState (GL_COLOR_ARRAY); qglDisableClientState (GL_TEXTURE_COORD_ARRAY); } else { setArraysOnce = qtrue; qglEnableClientState( GL_COLOR_ARRAY); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); } // // lock XYZ // qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD if (qglLockArraysEXT) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment( "glLockArraysEXT\n" ); } // // enable color and texcoord arrays after the lock if necessary // if ( !setArraysOnce ) { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglEnableClientState( GL_COLOR_ARRAY ); } // // call shader function // RB_IterateStagesGeneric( input ); // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { ProjectDlightTexture(); } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(); } // // unlock arrays // if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } // // reset polygon offset // if ( shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } }
/* * RB_GLSL_StageIteratorGeneric * Stage iterator for GLSL programs */ void RB_GLSL_StageIteratorGeneric(void) { shaderCommands_t *input; input = &tess; /* log this call */ if (r_logFile->integer) { /* don't just call LogComment, or we will get a call to va() every frame! */ GLimp_LogComment(va("--- R_GLSL_StageIteratorGeneric( %s ) ---\n", input->shader->name)); } /* set face culling appropiately */ GL_Cull(input->shader->cullType); /* set polygon offset if necessary */ if (input->shader->polygonOffset) { qglEnable(GL_POLYGON_OFFSET_FILL); qglPolygonOffset(r_offsetFactor->value, r_offsetUnits->value); } /* set vertex color array */ qglEnableClientState(GL_COLOR_ARRAY); qglColorPointer(4, GL_UNSIGNED_BYTE, 0, input->vertexColors); /* set texture coordinate array 0 */ GL_SelectTexture(0); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, 16, input->texCoords[0][0]); /* set texture coordinate array 1 */ GL_SelectTexture(1); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, 16, input->texCoords[0][1]); /* set vertex normal array */ qglEnableClientState(GL_NORMAL_ARRAY); qglNormalPointer(GL_FLOAT, 16, input->normal); /* lock XYZ */ qglVertexPointer(3, GL_FLOAT, 16, input->xyz); /* padded SIMD */ if (qglLockArraysEXT) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment("glLockArraysEXT\n"); } RB_GLSL_IterateStagesGeneric(input); /* now do any dynamic lighting needed */ if (input->dlightBits && input->shader->sort <= SS_OPAQUE && !(input->shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY))) ProjectDlightTexture(); // <-- RiO_Outlines: now do outlines RB_OutlinesPass(); // --> /* now do fog */ if (input->fogNum && input->shader->fogPass) RB_FogPass(); // TODO: uses svars which aren't set, so move to program /* unlock arrays */ if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment("glUnlockArraysExt\n"); } /* reset polygon offset */ if (input->shader->polygonOffset) qglDisable(GL_POLYGON_OFFSET_FILL); }