/* ================= RB_ShadowTessEnd triangleFromEdge[ v1 ][ v2 ] set triangle from edge( v1, v2, tri ) if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { } ================= */ void RB_ShadowTessEnd( void ) { int i; int numTris; vec3_t lightDir; // we can only do this if we have enough space in the vertex buffers if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); } // decide which triangles face the light Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } // draw the silhouette edges GL_Bind( tr.whiteImage ); qglEnable( GL_CULL_FACE ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); // mirrors have the culling order reversed if ( backEnd.viewParms.isMirror ) { qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } else { qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } // reenable writing to the color buffer qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); qglDisable( GL_CULL_FACE ); }
/* ================= RB_ShadowFinish Darken everything that is is a shadow volume. We have to delay this until everything has been shadowed, because otherwise shadows from different body parts would overlap and double darken. ================= */ void RB_ShadowFinish( void ) { #if defined(VV_LIGHTING) && defined(_XBOX) StencilShadower.FinishShadows(); #else if ( r_shadows->integer != 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } #ifdef _DEBUG_STENCIL_SHADOWS return; #endif qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_NOTEQUAL, 0, 255 ); qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); bool planeZeroBack = false; if (qglIsEnabled(GL_CLIP_PLANE0)) { planeZeroBack = true; qglDisable (GL_CLIP_PLANE0); } GL_Cull(CT_TWO_SIDED); //qglDisable (GL_CULL_FACE); GL_Bind( tr.whiteImage ); qglPushMatrix(); qglLoadIdentity (); // qglColor3f( 0.6f, 0.6f, 0.6f ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); // qglColor3f( 1, 0, 0 ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor4f( 0.0f, 0.0f, 0.0f, 0.5f ); //GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); #ifdef HAVE_GLES GLfloat vtx[] = { -100, 100, -10, 100, 100, -10, 100, -100, -10, -100, -100, -10 }; GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglDisableClientState( GL_COLOR_ARRAY ); qglVertexPointer ( 3, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); if (text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglEnableClientState( GL_COLOR_ARRAY ); #else qglBegin( GL_QUADS ); qglVertex3f( -100, 100, -10 ); qglVertex3f( 100, 100, -10 ); qglVertex3f( 100, -100, -10 ); qglVertex3f( -100, -100, -10 ); qglEnd (); #endif qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); if (planeZeroBack) { qglEnable (GL_CLIP_PLANE0); } qglPopMatrix(); #endif // VV_LIGHTING && _XBOX }
/* ============= RB_DrawSurfs ============= */ const void *RB_DrawSurfs( const void *data ) { const drawSurfsCommand_t *cmd; // finish any 2D drawing if needed if ( tess.numIndexes ) { RB_EndSurface(); } cmd = (const drawSurfsCommand_t *)data; backEnd.refdef = cmd->refdef; backEnd.viewParms = cmd->viewParms; // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) { qglEnable(GL_DEPTH_CLAMP); } if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW))) { FBO_t *oldFbo = glState.currentFBO; backEnd.depthFill = qtrue; qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]); backEnd.depthFill = qfalse; if (tr.msaaResolveFbo) { // If we're using multisampling, resolve the depth first FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST); } else if (tr.renderFbo == NULL) { // If we're rendering directly to the screen, copy the depth to a texture GL_BindToTMU(tr.renderDepthImage, 0); qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0); } if (r_ssao->integer) { // need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0); } if (backEnd.viewParms.flags & VPF_USESUNLIGHT) { vec4_t quadVerts[4]; vec2_t texCoords[4]; vec4_t box; FBO_Bind(tr.screenShadowFbo); box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth; box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight; box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth; box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight; qglViewport(box[0], box[1], box[2], box[3]); qglScissor(box[0], box[1], box[2], box[3]); box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth; box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight; box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth; box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight; texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; box[0] = -1.0f; box[1] = -1.0f; box[2] = 1.0f; box[3] = 1.0f; VectorSet4(quadVerts[0], box[0], box[3], 0, 1); VectorSet4(quadVerts[1], box[2], box[3], 0, 1); VectorSet4(quadVerts[2], box[2], box[1], 0, 1); VectorSet4(quadVerts[3], box[0], box[1], 0, 1); GL_State( GLS_DEPTHTEST_DISABLE ); GLSL_BindProgram(&tr.shadowmaskShader); GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP); GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); GLSL_SetUniformMatrix16(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); GLSL_SetUniformMatrix16(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); GLSL_SetUniformMatrix16(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); { vec4_t viewInfo; vec3_t viewVector; float zmax = backEnd.viewParms.zFar; float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f); float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f); float zmin = r_znear->value; VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector); VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector); VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector); GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector); VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); } if (r_ssao->integer) { vec4_t quadVerts[4]; vec2_t texCoords[4]; FBO_Bind(tr.quarterFbo[0]); qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); VectorSet4(quadVerts[0], -1, 1, 0, 1); VectorSet4(quadVerts[1], 1, 1, 0, 1); VectorSet4(quadVerts[2], 1, -1, 0, 1); VectorSet4(quadVerts[3], -1, -1, 0, 1); texCoords[0][0] = 0; texCoords[0][1] = 1; texCoords[1][0] = 1; texCoords[1][1] = 1; texCoords[2][0] = 1; texCoords[2][1] = 0; texCoords[3][0] = 0; texCoords[3][1] = 0; GL_State( GLS_DEPTHTEST_DISABLE ); GLSL_BindProgram(&tr.ssaoShader); GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); FBO_Bind(tr.quarterFbo[1]); qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); GLSL_BindProgram(&tr.depthBlurShader[0]); GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); FBO_Bind(tr.screenSsaoFbo); qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); GLSL_BindProgram(&tr.depthBlurShader[1]); GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); { vec4_t viewInfo; float zmax = backEnd.viewParms.zFar; float zmin = r_znear->value; VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); } // reset viewport and scissor FBO_Bind(oldFbo); SetViewportAndScissor(); } if (glRefConfig.framebufferObject && (backEnd.viewParms.flags & VPF_DEPTHCLAMP) && glRefConfig.depthClamp) { qglDisable(GL_DEPTH_CLAMP); } if (!(backEnd.viewParms.flags & VPF_DEPTHSHADOW)) { RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); if (r_drawSun->integer) { RB_DrawSun(0.1, tr.sunShader); } if (r_drawSunRays->integer) { FBO_t *oldFbo = glState.currentFBO; FBO_Bind(tr.sunRaysFbo); qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); qglClear( GL_COLOR_BUFFER_BIT ); if (glRefConfig.occlusionQuery) { tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); } RB_DrawSun(0.3, tr.sunFlareShader); if (glRefConfig.occlusionQuery) { qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } FBO_Bind(oldFbo); } // darken down any stencil shadows RB_ShadowFinish(); // add light flares on lights that aren't obscured RB_RenderFlares(); } if (glRefConfig.framebufferObject && backEnd.viewParms.targetFbo == tr.renderCubeFbo) { FBO_Bind(NULL); GL_SelectTexture(TB_CUBEMAP); GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP); qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP); GL_SelectTexture(0); } return (const void *)(cmd + 1); }
void RB_ColorCorrect( void ) { GLint loc; GLenum target; int width, height; int shift; float mul; if ( !r_enablePostProcess->integer || !r_enableColorCorrect->integer || !glsl ) { return; } GL_SelectTexture(0); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); target = GL_TEXTURE_RECTANGLE_ARB; width = glConfig.vidWidth; height = glConfig.vidHeight; qglBindTexture(target, tr.backBufferTexture); qglCopyTexSubImage2D(target, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); RB_SetGL2D(); GL_State( GLS_DEPTHTEST_DISABLE ); qglUseProgramObjectARB(tr.colorCorrectSp); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_gammaRecip"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_gammaRecip", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)(1.0 / r_gamma->value)); //mul = r_overBrightBitsValue->value; mul = r_overBrightBits->value; if (mul < 0.0) { mul = 0.0; } shift = tr.overbrightBits; loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_overbright"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_overbright", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)((float)(1 << shift) * mul)); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_contrast"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_contrast", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_contrast->value); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "backBufferTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get backBufferTex", __FUNCTION__); } qglUniform1iARB(loc, 0); qglBegin(GL_QUADS); qglTexCoord2i(0, 0); qglVertex2i(0, height); qglTexCoord2i(width, 0); qglVertex2i(width, height); qglTexCoord2i(width, height); qglVertex2i(width, 0); qglTexCoord2i(0, height); qglVertex2i(0, 0); qglEnd(); qglUseProgramObjectARB(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); }
/* ==================== RE_BeginFrame If running in stereo, RE_BeginFrame will be called twice for each RE_EndFrame ==================== */ void RE_BeginFrame(stereoFrame_t stereoFrame) { drawBufferCommand_t *cmd = NULL; colorMaskCommand_t *colcmd = NULL; if (!tr.registered) { return; } glState.finishCalled = qfalse; tr.frameCount++; tr.frameSceneNum = 0; // // do overdraw measurement // if (r_measureOverdraw->integer) { if (glConfig.stencilBits < 4) { ri.Printf(PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits); ri.Cvar_Set("r_measureOverdraw", "0"); r_measureOverdraw->modified = qfalse; } else if (r_shadows->integer == 2) { ri.Printf(PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n"); ri.Cvar_Set("r_measureOverdraw", "0"); r_measureOverdraw->modified = qfalse; } else { R_IssuePendingRenderCommands(); qglEnable(GL_STENCIL_TEST); qglStencilMask(~0U); qglClearStencil(0U); qglStencilFunc(GL_ALWAYS, 0U, ~0U); qglStencilOp(GL_KEEP, GL_INCR, GL_INCR); } r_measureOverdraw->modified = qfalse; } else { // this is only reached if it was on and is now off if (r_measureOverdraw->modified) { R_IssuePendingRenderCommands(); qglDisable(GL_STENCIL_TEST); } r_measureOverdraw->modified = qfalse; } // // texturemode stuff // if (r_textureMode->modified) { R_IssuePendingRenderCommands(); GL_TextureMode(r_textureMode->string); r_textureMode->modified = qfalse; } // // NVidia stuff // // fog control if (glConfig.NVFogAvailable && r_nv_fogdist_mode->modified) { r_nv_fogdist_mode->modified = qfalse; if (!Q_stricmp(r_nv_fogdist_mode->string, "GL_EYE_PLANE_ABSOLUTE_NV")) { glConfig.NVFogMode = (int)GL_EYE_PLANE_ABSOLUTE_NV; } else if (!Q_stricmp(r_nv_fogdist_mode->string, "GL_EYE_PLANE")) { glConfig.NVFogMode = (int)GL_EYE_PLANE; } else if (!Q_stricmp(r_nv_fogdist_mode->string, "GL_EYE_RADIAL_NV")) { glConfig.NVFogMode = (int)GL_EYE_RADIAL_NV; } else { // in case this was really 'else', store a valid value for next time glConfig.NVFogMode = (int)GL_EYE_RADIAL_NV; ri.Cvar_Set("r_nv_fogdist_mode", "GL_EYE_RADIAL_NV"); } } // // gamma stuff // if (r_gamma->modified) { r_gamma->modified = qfalse; R_IssuePendingRenderCommands(); R_SetColorMappings(); } // check for errors if (!r_ignoreGLErrors->integer) { int err; R_IssuePendingRenderCommands(); if ((err = qglGetError()) != GL_NO_ERROR) { ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err); } } if (glConfig.stereoEnabled) { if (!(cmd = R_GetCommandBuffer(sizeof(*cmd)))) { return; } cmd->commandId = RC_DRAW_BUFFER; if (stereoFrame == STEREO_LEFT) { cmd->buffer = (int)GL_BACK_LEFT; } else if (stereoFrame == STEREO_RIGHT) { cmd->buffer = (int)GL_BACK_RIGHT; } else { ri.Error(ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame); } } else { if (r_anaglyphMode->integer) { if (r_anaglyphMode->modified) { // clear both, front and backbuffer. qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); backEnd.colorMask[0] = GL_FALSE; backEnd.colorMask[1] = GL_FALSE; backEnd.colorMask[2] = GL_FALSE; backEnd.colorMask[3] = GL_FALSE; qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); if (glRefConfig.framebufferObject) { // clear all framebuffers if (tr.msaaResolveFbo) { FBO_Bind(tr.msaaResolveFbo); qglClear(GL_COLOR_BUFFER_BIT); } if (tr.renderFbo) { FBO_Bind(tr.renderFbo); qglClear(GL_COLOR_BUFFER_BIT); } if (tr.screenScratchFbo) { FBO_Bind(tr.screenScratchFbo); qglClear(GL_COLOR_BUFFER_BIT); } FBO_Bind(NULL); } qglDrawBuffer(GL_FRONT); qglClear(GL_COLOR_BUFFER_BIT); qglDrawBuffer(GL_BACK); qglClear(GL_COLOR_BUFFER_BIT); r_anaglyphMode->modified = qfalse; } if (stereoFrame == STEREO_LEFT) { if (!(cmd = R_GetCommandBuffer(sizeof(*cmd)))) { return; } if (!(colcmd = R_GetCommandBuffer(sizeof(*colcmd)))) { return; } } else if (stereoFrame == STEREO_RIGHT) { clearDepthCommand_t *cldcmd; if (!(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd)))) { return; } cldcmd->commandId = RC_CLEARDEPTH; if (!(colcmd = R_GetCommandBuffer(sizeof(*colcmd)))) { return; } } else { ri.Error(ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame); } R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer); colcmd->commandId = RC_COLORMASK; } else { if (stereoFrame != STEREO_CENTER) { ri.Error(ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame); } if (!(cmd = R_GetCommandBuffer(sizeof(*cmd)))) { return; } } if (cmd) { cmd->commandId = RC_DRAW_BUFFER; if (r_anaglyphMode->modified) { qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); backEnd.colorMask[0] = 0; backEnd.colorMask[1] = 0; backEnd.colorMask[2] = 0; backEnd.colorMask[3] = 0; r_anaglyphMode->modified = qfalse; } if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT")) { cmd->buffer = (int)GL_FRONT; } else { cmd->buffer = (int)GL_BACK; } } } tr.refdef.stereoFrame = stereoFrame; }
void GL_DrawAliasShadow (entity_t *e, dmdl_t *paliashdr, int posenum) { dtrivertx_t *verts; int *order; vec3_t point; float height, lheight; int count; daliasframe_t *frame; lheight = currententity->origin[2] - lightspot[2]; frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = frame->verts; // height = 0; order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); height = -lheight + 0.1f; // was 1.0f, lowered shadows to ground more - MrG // Knightmare- don't draw shadow above entity if ((currententity->origin[2]+height) > currententity->origin[2]) return; // Knightmare- don't draw shadows above view origin if (r_newrefdef.vieworg[2] < (currententity->origin[2] + height)) return; qglPushMatrix (); R_RotateForEntity (e, false); qglDisable (GL_TEXTURE_2D); qglEnable (GL_BLEND); qglColor4f (0, 0, 0, gl_shadowalpha->value); // was 0.5 // Knightmare- Stencil shadows by MrG if (gl_config.have_stencil) { qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_EQUAL, 1, 2); qglStencilOp(GL_KEEP,GL_KEEP,GL_INCR); } // End Stencil shadows - MrG while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { count = -count; qglBegin (GL_TRIANGLE_FAN); } else qglBegin (GL_TRIANGLE_STRIP); do { // normals and vertexes come from the frame list /* point[0] = verts[order[2]].v[0] * frame->scale[0] + frame->translate[0]; point[1] = verts[order[2]].v[1] * frame->scale[1] + frame->translate[1]; point[2] = verts[order[2]].v[2] * frame->scale[2] + frame->translate[2]; */ memcpy( point, s_lerped[order[2]], sizeof( point ) ); point[0] -= shadevector[0]*(point[2]+lheight); point[1] -= shadevector[1]*(point[2]+lheight); point[2] = height; // height -= 0.001; qglVertex3fv (point); order += 3; // verts++; } while (--count); qglEnd (); } // Knightmare- disable Stencil shadows if (gl_config.have_stencil) qglDisable(GL_STENCIL_TEST); qglColor4f (1,1,1,1); qglEnable (GL_TEXTURE_2D); qglDisable (GL_BLEND); qglPopMatrix (); }
/* ============= GL_DrawAliasFrameLerp interpolates between two frames and origins FIXME: batch lerp all vertexes ============= */ void GL_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp) { float l; daliasframe_t *frame, *oldframe; dtrivertx_t *v, *ov, *verts; int *order; int count; float frontlerp; float alpha; vec3_t move, delta, vectors[3]; vec3_t frontv, backv; int i; int index_xyz; float *lerp; frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + currententity->frame * paliashdr->framesize); verts = v = frame->verts; oldframe = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames + currententity->oldframe * paliashdr->framesize); ov = oldframe->verts; order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds); // glTranslatef (frame->translate[0], frame->translate[1], frame->translate[2]); // glScalef (frame->scale[0], frame->scale[1], frame->scale[2]); if (currententity->flags & RF_TRANSLUCENT) alpha = currententity->alpha; else alpha = 1.0; // PMM - added double shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) qglDisable( GL_TEXTURE_2D ); frontlerp = 1.0 - backlerp; // move should be the delta back to the previous frame * backlerp VectorSubtract (currententity->oldorigin, currententity->origin, delta); AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]); move[0] = DotProduct (delta, vectors[0]); // forward move[1] = -DotProduct (delta, vectors[1]); // left move[2] = DotProduct (delta, vectors[2]); // up VectorAdd (move, oldframe->translate, move); for (i=0 ; i<3 ; i++) { move[i] = backlerp*move[i] + frontlerp*frame->translate[i]; } for (i=0 ; i<3 ; i++) { frontv[i] = frontlerp*frame->scale[i]; backv[i] = backlerp*oldframe->scale[i]; } lerp = s_lerped[0]; GL_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv ); if ( gl_vertex_arrays->value ) { float colorArray[MAX_VERTS*4]; qglEnableClientState( GL_VERTEX_ARRAY ); qglVertexPointer( 3, GL_FLOAT, 16, s_lerped ); // padded for SIMD // if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) { qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha ); } else { qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 3, GL_FLOAT, 0, colorArray ); // // pre light everything // for ( i = 0; i < paliashdr->num_xyz; i++ ) { float l = shadedots[verts[i].lightnormalindex]; colorArray[i*3+0] = l * shadelight[0]; colorArray[i*3+1] = l * shadelight[1]; colorArray[i*3+2] = l * shadelight[2]; } } if ( qglLockArraysEXT != 0 ) qglLockArraysEXT( 0, paliashdr->num_xyz ); while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { count = -count; qglBegin (GL_TRIANGLE_FAN); } else { qglBegin (GL_TRIANGLE_STRIP); } // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) { do { index_xyz = order[2]; order += 3; qglVertex3fv( s_lerped[index_xyz] ); } while (--count); } else { do { // texture coordinates come from the draw list qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); index_xyz = order[2]; order += 3; // normals and vertexes come from the frame list // l = shadedots[verts[index_xyz].lightnormalindex]; // qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); qglArrayElement( index_xyz ); } while (--count); } qglEnd (); } if ( qglUnlockArraysEXT != 0 ) qglUnlockArraysEXT(); } else { while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { count = -count; qglBegin (GL_TRIANGLE_FAN); } else { qglBegin (GL_TRIANGLE_STRIP); } if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) { do { index_xyz = order[2]; order += 3; qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha); qglVertex3fv (s_lerped[index_xyz]); } while (--count); } else { do { // texture coordinates come from the draw list qglTexCoord2f (((float *)order)[0], ((float *)order)[1]); index_xyz = order[2]; order += 3; // normals and vertexes come from the frame list l = shadedots[verts[index_xyz].lightnormalindex]; qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha); qglVertex3fv (s_lerped[index_xyz]); } while (--count); } qglEnd (); } } // if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) ) // PMM - added double damage shell if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) qglEnable( GL_TEXTURE_2D ); }
void RB_StageIteratorLightmappedMultitexture( 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("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) ); } // // set face culling appropriately // GL_Cull( input->shader->cullType ); // // set color, pointers, and lock // GL_State( GLS_DEFAULT ); qglVertexPointer( 3, GL_FLOAT, 16, input->xyz ); #ifdef REPLACE_MODE qglDisableClientState( GL_COLOR_ARRAY ); qglColor3f( 1, 1, 1 ); qglShadeModel( GL_FLAT ); #else qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 ); #endif // // select base stage // GL_SelectTexture( 0 ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); R_BindAnimatedImage( &tess.xstages[0]->bundle[0] ); qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); // // configure second stage // GL_SelectTexture( 1 ); qglEnable( GL_TEXTURE_2D ); if ( r_lightmap->integer ) { GL_TexEnv( GL_REPLACE ); } else { GL_TexEnv( GL_MODULATE ); } R_BindAnimatedImage( &tess.xstages[0]->bundle[1] ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] ); // // lock arrays // if ( qglLockArraysEXT ) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment( "glLockArraysEXT\n" ); } R_DrawElements( input->numIndexes, input->indexes ); // // disable texturing on TEXTURE1, then select TEXTURE0 // qglDisable( GL_TEXTURE_2D ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); GL_SelectTexture( 0 ); #ifdef REPLACE_MODE GL_TexEnv( GL_MODULATE ); qglShadeModel( GL_SMOOTH ); #endif // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) { ProjectDlightTexture(); } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(); } // // unlock arrays // if ( qglUnlockArraysEXT ) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } }
//R_DRAWCEL static void R_DrawCel( int numIndexes, const glIndex_t *indexes ) { int primitives; if( //. ignore the 2d projection. do i smell the HUD? (backEnd.projection2D == qtrue) || //. ignore general entitites that are sprites. SEE NOTE #3. (backEnd.currentEntity->e.reType == RT_SPRITE) || //. ignore these liquids. why? ever see liquid with tris on the surface? exactly. SEE NOTE #4. (tess.shader->contentFlags & (CONTENTS_WATER | CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_FOG)) || //. ignore things that are two sided, meaning mostly things that have transparency. SEE NOTE #1. (tess.shader->cullType == CT_TWO_SIDED) ) { return; } primitives = r_primitives->integer; // default is to use triangles if compiled vertex arrays are present if ( primitives == 0 ) { if ( qglLockArraysEXT ) { primitives = 2; } else { primitives = 1; } } //. correction for mirrors. SEE NOTE #2. if(backEnd.viewParms.isMirror == qtrue) { qglCullFace (GL_FRONT); } else { qglCullFace (GL_BACK); } qglEnable (GL_BLEND); qglBlendFunc (GL_SRC_ALPHA ,GL_ONE_MINUS_SRC_ALPHA); qglColor3f (0.0f,0.0f,0.0f); qglLineWidth( (float) r_celoutline->integer ); if(primitives == 2) { qglDrawElements( GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, indexes ); } else if(primitives == 1) { R_DrawStripElements( numIndexes, indexes, qglArrayElement ); } else if(primitives == 3) { R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete ); } //. correction for mirrors. SEE NOTE #2. if(backEnd.viewParms.isMirror == qtrue) { qglCullFace (GL_BACK); } else { qglCullFace (GL_FRONT); } qglDisable (GL_BLEND); return; /* Notes 1. this is going to be a pain in the arse. it fixes things like light `beams` from being cel'd but it also will ignore any other shader set with no culling. this usually is everything that is translucent. but this is a good hack to clean up the screen untill something more selective comes along. or who knows group desision might actually be that this is liked. if so i take back calling it a `hack`, lol. = bob. 2. mirrors display correctly because the normals of the displayed are inverted of normal space. so to continue to have them display correctly, we must invert them inversely from a normal inversion. = bob. 3. this turns off a lot of space hogging sprite cel outlines. picture if you will five people in a small room all shooting rockets. each smoke puff gets a big black square around it, each explosion gets a big black square around it, and now nobody can see eachother because everyones screen is solid black. = bob. 4. ignoring liquids means you will not get black tris lines all over the top of your liquid. i put this in after seeing the lava on q3dm7 and water on q3ctf2 that had black lines all over the top, making the liquids look solid instead of... liquid. = bob. */ }
/* ==================== GL_State This routine is responsible for setting the most commonly changed state ==================== */ void GL_State( int stateBits ) { int diff; if ( !r_useStateCaching.GetBool() || backEnd.glState.forceGlState ) { // make sure everything is set all the time, so we // can see if our delta checking is screwing up diff = -1; backEnd.glState.forceGlState = false; } else { diff = stateBits ^ backEnd.glState.glStateBits; if ( !diff ) { return; } } // // check depthFunc bits // if ( diff & ( GLS_DEPTHFUNC_EQUAL | GLS_DEPTHFUNC_LESS | GLS_DEPTHFUNC_ALWAYS ) ) { if ( stateBits & GLS_DEPTHFUNC_EQUAL ) { qglDepthFunc( GL_EQUAL ); } else if ( stateBits & GLS_DEPTHFUNC_ALWAYS ) { qglDepthFunc( GL_ALWAYS ); } else { qglDepthFunc( GL_LEQUAL ); } } // // check blend bits // if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) { GLenum srcFactor, dstFactor; switch ( stateBits & GLS_SRCBLEND_BITS ) { case GLS_SRCBLEND_ZERO: srcFactor = GL_ZERO; break; case GLS_SRCBLEND_ONE: srcFactor = GL_ONE; break; case GLS_SRCBLEND_DST_COLOR: srcFactor = GL_DST_COLOR; break; case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: srcFactor = GL_ONE_MINUS_DST_COLOR; break; case GLS_SRCBLEND_SRC_ALPHA: srcFactor = GL_SRC_ALPHA; break; case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: srcFactor = GL_ONE_MINUS_SRC_ALPHA; break; case GLS_SRCBLEND_DST_ALPHA: srcFactor = GL_DST_ALPHA; break; case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: srcFactor = GL_ONE_MINUS_DST_ALPHA; break; case GLS_SRCBLEND_ALPHA_SATURATE: srcFactor = GL_SRC_ALPHA_SATURATE; break; default: srcFactor = GL_ONE; // to get warning to shut up common->Error( "GL_State: invalid src blend state bits\n" ); break; } switch ( stateBits & GLS_DSTBLEND_BITS ) { case GLS_DSTBLEND_ZERO: dstFactor = GL_ZERO; break; case GLS_DSTBLEND_ONE: dstFactor = GL_ONE; break; case GLS_DSTBLEND_SRC_COLOR: dstFactor = GL_SRC_COLOR; break; case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: dstFactor = GL_ONE_MINUS_SRC_COLOR; break; case GLS_DSTBLEND_SRC_ALPHA: dstFactor = GL_SRC_ALPHA; break; case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: dstFactor = GL_ONE_MINUS_SRC_ALPHA; break; case GLS_DSTBLEND_DST_ALPHA: dstFactor = GL_DST_ALPHA; break; case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: dstFactor = GL_ONE_MINUS_DST_ALPHA; break; default: dstFactor = GL_ONE; // to get warning to shut up common->Error( "GL_State: invalid dst blend state bits\n" ); break; } qglBlendFunc( srcFactor, dstFactor ); } // // check depthmask // if ( diff & GLS_DEPTHMASK ) { if ( stateBits & GLS_DEPTHMASK ) { qglDepthMask( GL_FALSE ); } else { qglDepthMask( GL_TRUE ); } } // // check colormask // if ( diff & (GLS_REDMASK|GLS_GREENMASK|GLS_BLUEMASK|GLS_ALPHAMASK) ) { GLboolean r, g, b, a; r = ( stateBits & GLS_REDMASK ) ? 0 : 1; g = ( stateBits & GLS_GREENMASK ) ? 0 : 1; b = ( stateBits & GLS_BLUEMASK ) ? 0 : 1; a = ( stateBits & GLS_ALPHAMASK ) ? 0 : 1; qglColorMask( r, g, b, a ); } // // fill/line mode // if ( diff & GLS_POLYMODE_LINE ) { if ( stateBits & GLS_POLYMODE_LINE ) { qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); } else { qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); } } // // alpha test // if ( diff & GLS_ATEST_BITS ) { switch ( stateBits & GLS_ATEST_BITS ) { case 0: qglDisable( GL_ALPHA_TEST ); break; case GLS_ATEST_EQ_255: qglEnable( GL_ALPHA_TEST ); qglAlphaFunc( GL_EQUAL, 1 ); break; case GLS_ATEST_LT_128: qglEnable( GL_ALPHA_TEST ); qglAlphaFunc( GL_LESS, 0.5 ); break; case GLS_ATEST_GE_128: qglEnable( GL_ALPHA_TEST ); qglAlphaFunc( GL_GEQUAL, 0.5 ); break; default: assert( 0 ); break; } } backEnd.glState.glStateBits = stateBits; }
/* ** 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 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 ); } //. show me cel outlines. //. there has to be a better place to put this. if(r_celoutline->integer > 0) { DrawCel(&tess); } // // 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] ); } // // 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 ); } }
/* ==================== RE_BeginFrame If running in stereo, RE_BeginFrame will be called twice for each RE_EndFrame ==================== */ void RE_BeginFrame( stereoFrame_t stereoFrame ) { drawBufferCommand_t *cmd = NULL; colorMaskCommand_t *colcmd = NULL; if ( !tr.registered ) { return; } glState.finishCalled = qfalse; tr.frameCount++; tr.frameSceneNum = 0; // // do overdraw measurement // if ( r_measureOverdraw->integer ) { if ( glConfig.stencilBits < 4 ) { ri.Printf( PRINT_ALL, "Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits ); ri.Cvar_Set( "r_measureOverdraw", "0" ); r_measureOverdraw->modified = qfalse; } else if ( r_shadows->integer == 2 ) { ri.Printf( PRINT_ALL, "Warning: stencil shadows and overdraw measurement are mutually exclusive\n" ); ri.Cvar_Set( "r_measureOverdraw", "0" ); r_measureOverdraw->modified = qfalse; } else { R_SyncRenderThread(); qglEnable( GL_STENCIL_TEST ); qglStencilMask( ~0U ); qglClearStencil( 0U ); qglStencilFunc( GL_ALWAYS, 0U, ~0U ); qglStencilOp( GL_KEEP, GL_INCR, GL_INCR ); } r_measureOverdraw->modified = qfalse; } else { // this is only reached if it was on and is now off if ( r_measureOverdraw->modified ) { R_SyncRenderThread(); qglDisable( GL_STENCIL_TEST ); } r_measureOverdraw->modified = qfalse; } // // texturemode stuff // if ( r_textureMode->modified ) { R_SyncRenderThread(); GL_TextureMode( r_textureMode->string ); r_textureMode->modified = qfalse; } // // gamma stuff // if ( r_gamma->modified ) { r_gamma->modified = qfalse; R_SyncRenderThread(); R_SetColorMappings(); } // check for errors if ( !r_ignoreGLErrors->integer ) { int err; R_SyncRenderThread(); if ((err = qglGetError()) != GL_NO_ERROR) ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err); } if (glConfig.stereoEnabled) { if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) return; cmd->commandId = RC_DRAW_BUFFER; if ( stereoFrame == STEREO_LEFT ) { cmd->buffer = (int)GL_BACK_LEFT; } else if ( stereoFrame == STEREO_RIGHT ) { cmd->buffer = (int)GL_BACK_RIGHT; } else { ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); } } else { if(r_anaglyphMode->integer) { if(r_anaglyphMode->modified) { // clear both, front and backbuffer. qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); qglDrawBuffer(GL_FRONT); qglClear(GL_COLOR_BUFFER_BIT); qglDrawBuffer(GL_BACK); qglClear(GL_COLOR_BUFFER_BIT); r_anaglyphMode->modified = qfalse; } if(stereoFrame == STEREO_LEFT) { if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) return; if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) return; } else if(stereoFrame == STEREO_RIGHT) { clearDepthCommand_t *cldcmd; if( !(cldcmd = R_GetCommandBuffer(sizeof(*cldcmd))) ) return; cldcmd->commandId = RC_CLEARDEPTH; if( !(colcmd = R_GetCommandBuffer(sizeof(*colcmd))) ) return; } else ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is enabled, but stereoFrame was %i", stereoFrame ); R_SetColorMode(colcmd->rgba, stereoFrame, r_anaglyphMode->integer); colcmd->commandId = RC_COLORMASK; } else { if(stereoFrame != STEREO_CENTER) ri.Error( ERR_FATAL, "RE_BeginFrame: Stereo is disabled, but stereoFrame was %i", stereoFrame ); if( !(cmd = R_GetCommandBuffer(sizeof(*cmd))) ) return; } if(cmd) { cmd->commandId = RC_DRAW_BUFFER; if(r_anaglyphMode->modified) { qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); r_anaglyphMode->modified = qfalse; } if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT")) cmd->buffer = (int)GL_FRONT; else cmd->buffer = (int)GL_BACK; } } tr.refdef.stereoFrame = stereoFrame; }
/* ============== Z_Draw ============== */ void Z_Draw (void) { brush_t *brush; float w, h; double start, end; qtexture_t *q; float top, bottom; vec3_t org_top, org_bottom, dir_up, dir_down; int xCam = z.width/3; if (!active_brushes.next) return; // not valid yet if (z.timing) start = Sys_DoubleTime (); // // clear // qglViewport(0, 0, z.width, z.height); qglClearColor ( g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2], 0); /* GL Bug */ /* When not using hw acceleration, gl will fault if we clear the depth buffer bit on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT only after Z_Draw() has been called once. Yeah, right. */ qglClear(glbitClear); glbitClear |= GL_DEPTH_BUFFER_BIT; qglMatrixMode(GL_PROJECTION); qglLoadIdentity (); w = z.width/2 / z.scale; h = z.height/2 / z.scale; qglOrtho (-w, w, z.origin[2]-h, z.origin[2]+h, -8, 8); qglDisable(GL_TEXTURE_2D); qglDisable(GL_TEXTURE_1D); qglDisable(GL_DEPTH_TEST); qglDisable(GL_BLEND); // // now draw the grid // Z_DrawGrid (); // // draw stuff // qglDisable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglDisable(GL_TEXTURE_2D); qglDisable(GL_BLEND); qglDisable(GL_DEPTH_TEST); // draw filled interiors and edges dir_up[0] = 0 ; dir_up[1] = 0; dir_up[2] = 1; dir_down[0] = 0 ; dir_down[1] = 0; dir_down[2] = -1; VectorCopy (z.origin, org_top); org_top[2] = 4096; VectorCopy (z.origin, org_bottom); org_bottom[2] = -4096; for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) { if (brush->mins[0] >= z.origin[0] || brush->maxs[0] <= z.origin[0] || brush->mins[1] >= z.origin[1] || brush->maxs[1] <= z.origin[1]) continue; if (!Brush_Ray (org_top, dir_down, brush, &top)) continue; top = org_top[2] - top; if (!Brush_Ray (org_bottom, dir_up, brush, &bottom)) continue; bottom = org_bottom[2] + bottom; q = Texture_ForName (brush->brush_faces->texdef.name); qglColor3f (q->color[0], q->color[1], q->color[2]); qglBegin (GL_QUADS); qglVertex2f (-xCam, bottom); qglVertex2f (xCam, bottom); qglVertex2f (xCam, top); qglVertex2f (-xCam, top); qglEnd (); qglColor3f (1,1,1); qglBegin (GL_LINE_LOOP); qglVertex2f (-xCam, bottom); qglVertex2f (xCam, bottom); qglVertex2f (xCam, top); qglVertex2f (-xCam, top); qglEnd (); } // // now draw selected brushes // for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) { if ( !(brush->mins[0] >= z.origin[0] || brush->maxs[0] <= z.origin[0] || brush->mins[1] >= z.origin[1] || brush->maxs[1] <= z.origin[1]) ) { if (Brush_Ray (org_top, dir_down, brush, &top)) { top = org_top[2] - top; if (Brush_Ray (org_bottom, dir_up, brush, &bottom)) { bottom = org_bottom[2] + bottom; q = Texture_ForName (brush->brush_faces->texdef.name); qglColor3f (q->color[0], q->color[1], q->color[2]); qglBegin (GL_QUADS); qglVertex2f (-xCam, bottom); qglVertex2f (xCam, bottom); qglVertex2f (xCam, top); qglVertex2f (-xCam, top); qglEnd (); } } } qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]); qglBegin (GL_LINE_LOOP); qglVertex2f (-xCam, brush->mins[2]); qglVertex2f (xCam, brush->mins[2]); qglVertex2f (xCam, brush->maxs[2]); qglVertex2f (-xCam, brush->maxs[2]); qglEnd (); } ZDrawCameraIcon (); qglFinish(); QE_CheckOpenGLForErrors(); if (z.timing) { end = Sys_DoubleTime (); Sys_Printf ("z: %i ms\n", (int)(1000*(end-start))); } }
void QueueDraw(){ guint32 i, k; face_t *face; winding_t *w; int j, nDrawMode = g_pParentWnd->GetCamera().draw_mode; if ( notex_faces->len ) { qglDisable( GL_TEXTURE_2D ); for ( i = 0; i < notex_faces->len; i++ ) { face = (face_t*)notex_faces->pdata[i]; w = face->face_winding; qglBegin( GL_POLYGON ); /* if (b->patchBrush) //++timo FIXME: find a use case for this?? qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); else */ qglColor4f( face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans() ); if ( g_PrefsDlg.m_bGLLighting ) { qglNormal3fv( face->plane.normal ); } for ( j = 0; j < w->numpoints; j++ ) { if ( nDrawMode == cd_texture || nDrawMode == cd_light ) { qglTexCoord2fv( &w->points[j][3] ); } qglVertex3fv( w->points[j] ); } qglEnd(); } } if ( !len ) { return; } if ( nDrawMode == cd_texture || nDrawMode == cd_light ) { qglEnable( GL_TEXTURE_2D ); } for ( k = 0; k < len; k++ ) { qglBindTexture( GL_TEXTURE_2D, sort[k].texture->texture_number ); for ( i = 0; i < sort[k].faces->len; i++ ) { face = (face_t*)sort[k].faces->pdata[i]; w = face->face_winding; qglBegin( GL_POLYGON ); /* if (b->patchBrush) //++timo FIXME: find a use case for this?? qglColor4f (face->d_color[0], face->d_color[1], face->d_color[2], 0.13); else */ qglColor4f( face->d_color[0], face->d_color[1], face->d_color[2], face->pShader->getTrans() ); if ( g_PrefsDlg.m_bGLLighting ) { qglNormal3fv( face->plane.normal ); } for ( j = 0; j < w->numpoints; j++ ) { if ( nDrawMode == cd_texture || nDrawMode == cd_light ) { qglTexCoord2fv( &w->points[j][3] ); } qglVertex3fv( w->points[j] ); } qglEnd(); } } qglBindTexture( GL_TEXTURE_2D, 0 ); }
/* ============= 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); }
void FBO_BlitFromTexture(struct image_s *src, vec4i_t inSrcBox, vec2_t inSrcTexScale, FBO_t *dst, vec4i_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend) { vec4i_t dstBox, srcBox; vec2_t srcTexScale; vec4_t color; vec4_t quadVerts[4]; vec2_t texCoords[4]; vec2_t invTexRes; FBO_t *oldFbo = glState.currentFBO; matrix_t projection; int width, height; if (!src) { return; } if (inSrcBox) { VectorSet4(srcBox, inSrcBox[0], inSrcBox[1], inSrcBox[0] + inSrcBox[2], inSrcBox[1] + inSrcBox[3]); } else { VectorSet4(srcBox, 0, 0, src->width, src->height); } // framebuffers are 0 bottom, Y up. if (inDstBox) { if (dst) { dstBox[0] = inDstBox[0]; dstBox[1] = dst->height - inDstBox[1] - inDstBox[3]; dstBox[2] = inDstBox[0] + inDstBox[2]; dstBox[3] = dst->height - inDstBox[1]; } else { dstBox[0] = inDstBox[0]; dstBox[1] = glConfig.vidHeight - inDstBox[1] - inDstBox[3]; dstBox[2] = inDstBox[0] + inDstBox[2]; dstBox[3] = glConfig.vidHeight - inDstBox[1]; } } else if (dst) { VectorSet4(dstBox, 0, dst->height, dst->width, 0); } else { VectorSet4(dstBox, 0, glConfig.vidHeight, glConfig.vidWidth, 0); } if (inSrcTexScale) { VectorCopy2(inSrcTexScale, srcTexScale); } else { srcTexScale[0] = srcTexScale[1] = 1.0f; } if (inColor) { VectorCopy4(inColor, color); } else { color[0] = color[1] = color[2] = color[3] = 1.0f; } if (!shaderProgram) { shaderProgram = &tr.textureColorShader; } FBO_Bind(dst); if (glState.currentFBO) { width = glState.currentFBO->width; height = glState.currentFBO->height; } else { width = glConfig.vidWidth; height = glConfig.vidHeight; } qglViewport(0, 0, width, height); qglScissor(0, 0, width, height); Matrix16Ortho(0, width, height, 0, 0, 1, projection); qglDisable(GL_CULL_FACE); GL_BindToTMU(src, TB_COLORMAP); VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0, 1); VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0, 1); VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0, 1); VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0, 1); texCoords[0][0] = srcBox[0] / (float)src->width; texCoords[0][1] = 1.0f - srcBox[1] / (float)src->height; texCoords[1][0] = srcBox[2] / (float)src->width; texCoords[1][1] = 1.0f - srcBox[1] / (float)src->height; texCoords[2][0] = srcBox[2] / (float)src->width; texCoords[2][1] = 1.0f - srcBox[3] / (float)src->height; texCoords[3][0] = srcBox[0] / (float)src->width; texCoords[3][1] = 1.0f - srcBox[3] / (float)src->height; invTexRes[0] = 1.0f / src->width * srcTexScale[0]; invTexRes[1] = 1.0f / src->height * srcTexScale[1]; GL_State(blend); GLSL_BindProgram(shaderProgram); GLSL_SetUniformMatrix16(shaderProgram, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, projection); GLSL_SetUniformVec4(shaderProgram, TEXTURECOLOR_UNIFORM_COLOR, color); GLSL_SetUniformVec2(shaderProgram, TEXTURECOLOR_UNIFORM_INVTEXRES, invTexRes); GLSL_SetUniformVec2(shaderProgram, TEXTURECOLOR_UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax); GLSL_SetUniformVec3(shaderProgram, TEXTURECOLOR_UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear); RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); FBO_Bind(oldFbo); }
/* ================== 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 ); }
/* ================== GL_Setup2D TODO: time is messed up ================== */ void GL_Setup2D (int time){ mat4_t projectionMatrix = {2.0f / backEnd.cropWidth, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f / backEnd.cropHeight, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 0.0f, -1.0f, 1.0f, -1.0f, 1.0f}; QGL_LogPrintf("---------- RB_Setup2D ----------\n"); backEnd.projection2D = true; backEnd.time = time; backEnd.floatTime = MS2SEC(Sys_Milliseconds()); backEnd.viewport.x = 0; backEnd.viewport.y = 0; backEnd.viewport.width = backEnd.cropWidth; backEnd.viewport.height = backEnd.cropHeight; backEnd.scissor.x = 0; backEnd.scissor.y = 0; backEnd.scissor.width = backEnd.cropWidth; backEnd.scissor.height = backEnd.cropHeight; backEnd.coordScale[0] = 1.0f / backEnd.viewport.width; backEnd.coordScale[1] = 1.0f / backEnd.viewport.height; backEnd.coordBias[0] = -backEnd.viewport.x * backEnd.coordScale[0]; backEnd.coordBias[1] = -backEnd.viewport.y * backEnd.coordScale[1]; backEnd.depthFilling = false; backEnd.debugRendering = false; backEnd.currentColorCaptured = SORT_BAD; backEnd.currentDepthCaptured = false; // Set up the viewport GL_Viewport(backEnd.viewport); // Set up the scissor GL_Scissor(backEnd.viewport); // Set up the depth bounds if (glConfig.depthBoundsTestAvailable) GL_DepthBounds(0.0f, 1.0f); // Set the projection matrix GL_LoadMatrix(GL_PROJECTION, projectionMatrix); // Set the modelview matrix GL_LoadIdentity(GL_MODELVIEW); // Set the GL state GL_PolygonMode(GL_FILL); GL_Disable(GL_CULL_FACE); GL_Disable(GL_POLYGON_OFFSET_FILL); GL_Disable(GL_BLEND); GL_Disable(GL_ALPHA_TEST); GL_Disable(GL_DEPTH_TEST); GL_Disable(GL_STENCIL_TEST); GL_DepthRange(0.0f, 1.0f); GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); GL_DepthMask(GL_FALSE); GL_StencilMask(255); // Disable the clip plane qglDisable(GL_CLIP_PLANE0); // Disable multisampling if available if (glConfig.multiSamples > 1) qglDisable(GL_MULTISAMPLE); // Check for errors if (!r_ignoreGLErrors->integerValue) GL_CheckForErrors(); QGL_LogPrintf("--------------------\n"); }
/* ================= R_DrawAliasModel ================= */ void R_DrawAliasModel (entity_t *e) { int i; dmdl_t *paliashdr; float an; vec3_t bbox[8]; image_t *skin; if ( !( e->flags & RF_WEAPONMODEL ) ) { if ( R_CullAliasModel( bbox, e ) ) return; } if ( e->flags & RF_WEAPONMODEL ) { if ( r_lefthand->value == 2 ) return; } paliashdr = (dmdl_t *)currentmodel->extradata; // // get lighting information // // PMM - rewrote, reordered to handle new shells & mixing // PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy // if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear (shadelight); if (currententity->flags & RF_SHELL_HALF_DAM) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[0] = 0.9; shadelight[1] = 0.7; } if ( currententity->flags & RF_SHELL_RED ) shadelight[0] = 1.0; if ( currententity->flags & RF_SHELL_GREEN ) shadelight[1] = 1.0; if ( currententity->flags & RF_SHELL_BLUE ) shadelight[2] = 1.0; } /* // PMM -special case for godmode if ( (currententity->flags & RF_SHELL_RED) && (currententity->flags & RF_SHELL_BLUE) && (currententity->flags & RF_SHELL_GREEN) ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) ) { VectorClear (shadelight); if ( currententity->flags & RF_SHELL_RED ) { shadelight[0] = 1.0; if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) ) shadelight[2] = 1.0; } else if ( currententity->flags & RF_SHELL_BLUE ) { if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[1] = 1.0; shadelight[2] = 1.0; } else { shadelight[2] = 1.0; } } else if ( currententity->flags & RF_SHELL_DOUBLE ) { shadelight[0] = 0.9; shadelight[1] = 0.7; } } else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) ) { VectorClear (shadelight); // PMM - new colors if ( currententity->flags & RF_SHELL_HALF_DAM ) { shadelight[0] = 0.56; shadelight[1] = 0.59; shadelight[2] = 0.45; } if ( currententity->flags & RF_SHELL_GREEN ) { shadelight[1] = 1.0; } } } //PMM - ok, now flatten these down to range from 0 to 1.0. // max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2])); // if (max_shell_val > 0) // { // for (i=0; i<3; i++) // { // shadelight[i] = shadelight[i] / max_shell_val; // } // } // pmm */ else if ( currententity->flags & RF_FULLBRIGHT ) { for (i=0 ; i<3 ; i++) shadelight[i] = 1.0; } else { R_LightPoint (currententity->origin, shadelight); // player lighting hack for communication back to server // big hack! if ( currententity->flags & RF_WEAPONMODEL ) { // pick the greatest component, which should be the same // as the mono value returned by software if (shadelight[0] > shadelight[1]) { if (shadelight[0] > shadelight[2]) r_lightlevel->value = 150*shadelight[0]; else r_lightlevel->value = 150*shadelight[2]; } else { if (shadelight[1] > shadelight[2]) r_lightlevel->value = 150*shadelight[1]; else r_lightlevel->value = 150*shadelight[2]; } } if ( gl_monolightmap->string[0] != '0' ) { float s = shadelight[0]; if ( s < shadelight[1] ) s = shadelight[1]; if ( s < shadelight[2] ) s = shadelight[2]; shadelight[0] = s; shadelight[1] = s; shadelight[2] = s; } } if ( currententity->flags & RF_MINLIGHT ) { for (i=0 ; i<3 ; i++) if (shadelight[i] > 0.1) break; if (i == 3) { shadelight[0] = 0.1; shadelight[1] = 0.1; shadelight[2] = 0.1; } } if ( currententity->flags & RF_GLOW ) { // bonus items will pulse with time float scale; float min; scale = 0.1 * sin(r_newrefdef.time*7); for (i=0 ; i<3 ; i++) { min = shadelight[i] * 0.8; shadelight[i] += scale; if (shadelight[i] < min) shadelight[i] = min; } } // ================= // PGM ir goggles color override if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) { shadelight[0] = 1.0; shadelight[1] = 0.0; shadelight[2] = 0.0; } // PGM // ================= shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; an = currententity->angles[1]/180*M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // c_alias_polys += paliashdr->num_tris; // // draw all the triangles // if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar ); qglMatrixMode( GL_PROJECTION ); qglPushMatrix(); qglLoadIdentity(); qglScalef( -1, 1, 1 ); MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height, 4, 4096); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_BACK ); } qglPushMatrix (); e->angles[PITCH] = -e->angles[PITCH]; // sigh. e->angles[ROLL] = e->angles[ROLL] * R_RollMult(); // Knightmare- roll is backwards R_RotateForEntity (e, true); e->angles[PITCH] = -e->angles[PITCH]; // sigh. e->angles[ROLL] = e->angles[ROLL] * R_RollMult(); // Knightmare- roll is backwards // select skin if (currententity->skin) skin = currententity->skin; // custom player skin else { if (currententity->skinnum >= MAX_MD2SKINS) skin = currentmodel->skins[0]; else { skin = currentmodel->skins[currententity->skinnum]; if (!skin) skin = currentmodel->skins[0]; } } if (!skin) skin = r_notexture; // fallback... GL_Bind(skin->texnum); // draw it qglShadeModel (GL_SMOOTH); GL_TexEnv( GL_MODULATE ); if ( currententity->flags & RF_TRANSLUCENT ) { qglEnable (GL_BLEND); } if ( (currententity->frame >= paliashdr->num_frames) || (currententity->frame < 0) ) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", currentmodel->name, currententity->frame); currententity->frame = 0; currententity->oldframe = 0; } if ( (currententity->oldframe >= paliashdr->num_frames) || (currententity->oldframe < 0)) { ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", currentmodel->name, currententity->oldframe); currententity->frame = 0; currententity->oldframe = 0; } if ( !r_lerpmodels->value ) currententity->backlerp = 0; GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp); GL_TexEnv( GL_REPLACE ); qglShadeModel (GL_FLAT); qglPopMatrix (); //#if 1 if (gl_showbbox->value) // Knightmare- show bbox option { qglColor4f (1.0f, 1.0f, 1.0f, 1.0f); qglDisable( GL_CULL_FACE ); qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); qglDisable( GL_TEXTURE_2D ); /* qglBegin( GL_TRIANGLE_STRIP ); for ( i = 0; i < 8; i++ ) { qglVertex3fv( bbox[i] ); } qglEnd();*/ qglBegin( GL_QUADS ); qglVertex3fv( bbox[0] ); qglVertex3fv( bbox[1] ); qglVertex3fv( bbox[3] ); qglVertex3fv( bbox[2] ); qglVertex3fv( bbox[4] ); qglVertex3fv( bbox[5] ); qglVertex3fv( bbox[7] ); qglVertex3fv( bbox[6] ); qglVertex3fv( bbox[0] ); qglVertex3fv( bbox[1] ); qglVertex3fv( bbox[5] ); qglVertex3fv( bbox[4] ); qglVertex3fv( bbox[2] ); qglVertex3fv( bbox[3] ); qglVertex3fv( bbox[7] ); qglVertex3fv( bbox[6] ); qglEnd(); qglEnable( GL_TEXTURE_2D ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); qglEnable( GL_CULL_FACE ); } //#endif if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) ) { qglMatrixMode( GL_PROJECTION ); qglPopMatrix(); qglMatrixMode( GL_MODELVIEW ); qglCullFace( GL_FRONT ); } if ( currententity->flags & RF_TRANSLUCENT ) { qglDisable (GL_BLEND); } if (currententity->flags & RF_DEPTHHACK) qglDepthRange (gldepthmin, gldepthmax); if (gl_shadows->value && !(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL))) { // qglPushMatrix (); // R_RotateForEntity (e, false); // qglDisable (GL_TEXTURE_2D); // qglEnable (GL_BLEND); // qglColor4f (0, 0, 0, gl_shadowalpha->value); // was 0.5 GL_DrawAliasShadow (e, paliashdr, currententity->frame ); // qglEnable (GL_TEXTURE_2D); // qglDisable (GL_BLEND); // qglPopMatrix (); } qglColor4f (1,1,1,1); }
/* ================== 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"); }
static void RB_BloomCombine( void ) { GLenum target; int width, height; GLint loc; GL_SelectTexture(0); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); target = GL_TEXTURE_RECTANGLE_ARB; width = tr.bloomWidth; height = tr.bloomHeight; qglBindTexture(target, tr.bloomTexture); qglCopyTexSubImage2D(target, 0, 0, 0, 0, glConfig.vidHeight - height, width, height); qglUseProgramObjectARB(tr.combineSp); qglBindTexture(target, tr.backBufferTexture); loc = qglGetUniformLocationARB(tr.combineSp, "backBufferTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get backBufferTex", __FUNCTION__); } qglUniform1iARB(loc, 0); GL_SelectTexture(1); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); qglBindTexture(target, tr.bloomTexture); loc = qglGetUniformLocationARB(tr.combineSp, "bloomTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get bloomTex", __FUNCTION__); } qglUniform1iARB(loc, 1); loc = qglGetUniformLocationARB(tr.combineSp, "p_bloomsaturation"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_bloomsaturation", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomSaturation->value); loc = qglGetUniformLocationARB(tr.combineSp, "p_scenesaturation"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_scenesaturation", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomSceneSaturation->value); loc = qglGetUniformLocationARB(tr.combineSp, "p_bloomintensity"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_bloomintensity", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomIntensity->value); loc = qglGetUniformLocationARB(tr.combineSp, "p_sceneintensity"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_sceneintensity", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_BloomSceneIntensity->value); width = glConfig.vidWidth; height = glConfig.vidHeight; qglBegin(GL_QUADS); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, 0, 0); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, 0, 0); qglVertex2i(0, height); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, width, 0); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, tr.bloomWidth, 0); qglVertex2i(width, height); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, width, height); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, tr.bloomWidth, tr.bloomHeight); qglVertex2i(width, 0); qglMultiTexCoord2iARB(GL_TEXTURE0_ARB, 0, height); qglMultiTexCoord2iARB(GL_TEXTURE1_ARB, 0, tr.bloomHeight); qglVertex2i(0, 0); qglEnd(); qglUseProgramObjectARB(0); GL_SelectTexture(1); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglDisable(GL_TEXTURE_2D); GL_SelectTexture(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); }
/* ================== GL_Disable ================== */ void GL_Disable (uint cap){ switch (cap){ case GL_CULL_FACE: if (!glState.cullFace) return; glState.cullFace = false; break; case GL_POLYGON_OFFSET_FILL: if (!glState.polygonOffsetFill) return; glState.polygonOffsetFill = false; break; case GL_POLYGON_OFFSET_LINE: if (!glState.polygonOffsetLine) return; glState.polygonOffsetLine = false; break; case GL_BLEND: if (!glState.blend) return; glState.blend = false; break; case GL_ALPHA_TEST: if (!glState.alphaTest) return; glState.alphaTest = false; break; case GL_DEPTH_TEST: if (!glState.depthTest) return; glState.depthTest = false; break; case GL_STENCIL_TEST: if (!glState.stencilTest) return; glState.stencilTest = false; break; case GL_TEXTURE_GEN_S: if (!glState.textureGen[glState.texUnit][0]) return; glState.textureGen[glState.texUnit][0] = false; break; case GL_TEXTURE_GEN_T: if (!glState.textureGen[glState.texUnit][1]) return; glState.textureGen[glState.texUnit][1] = false; break; case GL_TEXTURE_GEN_R: if (!glState.textureGen[glState.texUnit][2]) return; glState.textureGen[glState.texUnit][2] = false; break; case GL_TEXTURE_GEN_Q: if (!glState.textureGen[glState.texUnit][3]) return; glState.textureGen[glState.texUnit][3] = false; break; } qglDisable(cap); }
void InitGlslShadersAndPrograms( void ) { void *shaderSource; GLenum target; float bloomTextureScale; int ret; if ( !r_enablePostProcess->integer || !glsl ) { return; } GL_SelectTexture(0); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_ARB ); bloomTextureScale = r_BloomTextureScale->value; if ( bloomTextureScale < 0.01 ) { bloomTextureScale = 0.01; } else if ( bloomTextureScale > 1 ) { bloomTextureScale = 1; } target = GL_TEXTURE_RECTANGLE_ARB; tr.bloomWidth = glConfig.vidWidth * bloomTextureScale; tr.bloomHeight = glConfig.vidHeight * bloomTextureScale; qglGenTextures(1, &tr.bloomTexture); qglBindTexture(target, tr.bloomTexture); qglTexImage2D(target, 0, GL_RGBA8, tr.bloomWidth, tr.bloomHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); qglTexParameteri(target, GL_TEXTURE_WRAP_S, r_glClampToEdge->integer ? GL_CLAMP_TO_EDGE : GL_CLAMP); qglTexParameteri(target, GL_TEXTURE_WRAP_T, r_glClampToEdge->integer ? GL_CLAMP_TO_EDGE : GL_CLAMP); qglTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); target = GL_TEXTURE_RECTANGLE_ARB; qglGenTextures(1, &tr.backBufferTexture); qglBindTexture(target, tr.backBufferTexture); qglTexImage2D(target, 0, GL_RGB8, glConfig.vidWidth, glConfig.vidHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); qglTexParameteri(target, GL_TEXTURE_WRAP_S, r_glClampToEdge->integer ? GL_CLAMP_TO_EDGE : GL_CLAMP); qglTexParameteri(target, GL_TEXTURE_WRAP_T, r_glClampToEdge->integer ? GL_CLAMP_TO_EDGE : GL_CLAMP); qglTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); GL_SelectTexture(0); Com_VPrintf("^5scripts/posteffect.vs ->\n"); ret = ri.FS_ReadFile("scripts/posteffect.vs", &shaderSource); if (ret > 0) { tr.mainVs = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); qglShaderSourceARB(tr.mainVs, 1, (const char **)&shaderSource, NULL); qglCompileShaderARB(tr.mainVs); printGlslLog(tr.mainVs); ri.FS_FreeFile(shaderSource); } else if ( strlen(fallbackShader_posteffect) ) { Com_VPrintf("^1file not found, using fallback shader\n"); //ri.FS_FreeFile(shaderSource); tr.mainVs = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); qglShaderSourceARB(tr.mainVs, 1, &fallbackShader_posteffect, NULL); qglCompileShaderARB(tr.mainVs); printGlslLog(tr.mainVs); } else { Com_VPrintf("^1file not found\n"); glsl = qfalse; R_DeleteGlslShadersAndPrograms(); } R_InitFragmentShader( "scripts/colorcorrect.fs", &tr.colorCorrectFs, &tr.colorCorrectSp, tr.mainVs, fallbackShader_colorcorrect ); R_InitFragmentShader( "scripts/blurhoriz.fs", &tr.blurHorizFs, &tr.blurHorizSp, tr.mainVs, fallbackShader_blurhoriz ); R_InitFragmentShader( "scripts/blurvertical.fs", &tr.blurVerticalFs, &tr.blurVerticalSp, tr.mainVs, fallbackShader_blurvertical ); R_InitFragmentShader( "scripts/brightpass.fs", &tr.brightPassFs, &tr.brightPassSp, tr.mainVs, fallbackShader_brightpass ); R_InitFragmentShader( "scripts/combine.fs", &tr.combineFs, &tr.combineSp, tr.mainVs, fallbackShader_combine ); R_InitFragmentShader( "scripts/downsample1.fs", &tr.downSample1Fs, &tr.downSample1Sp, tr.mainVs, fallbackShader_downsample1 ); }
/* ================== GL_Setup3D TODO: time is messed up ================== */ void GL_Setup3D (int time){ double clipPlane[4]; QGL_LogPrintf("---------- RB_Setup3D ----------\n"); backEnd.projection2D = false; backEnd.time = time; backEnd.floatTime = MS2SEC(Sys_Milliseconds()); backEnd.viewport.x = backEnd.viewParms.viewport.x; backEnd.viewport.y = backEnd.viewParms.viewport.y; backEnd.viewport.width = backEnd.viewParms.viewport.width; backEnd.viewport.height = backEnd.viewParms.viewport.height; backEnd.scissor.x = backEnd.viewParms.scissor.x; backEnd.scissor.y = backEnd.viewParms.scissor.y; backEnd.scissor.width = backEnd.viewParms.scissor.width; backEnd.scissor.height = backEnd.viewParms.scissor.height; backEnd.coordScale[0] = 1.0f / backEnd.viewport.width; backEnd.coordScale[1] = 1.0f / backEnd.viewport.height; backEnd.coordBias[0] = -backEnd.viewport.x * backEnd.coordScale[0]; backEnd.coordBias[1] = -backEnd.viewport.y * backEnd.coordScale[1]; backEnd.depthFilling = false; backEnd.debugRendering = false; backEnd.currentColorCaptured = SORT_BAD; backEnd.currentDepthCaptured = false; // Set up the viewport GL_Viewport(backEnd.viewport); // Set up the scissor GL_Scissor(backEnd.viewport); // Set up the depth bounds if (glConfig.depthBoundsTestAvailable) GL_DepthBounds(0.0f, 1.0f); // Set the projection matrix GL_LoadMatrix(GL_PROJECTION, backEnd.viewParms.projectionMatrix); // Set the modelview matrix GL_LoadIdentity(GL_MODELVIEW); // Set the GL state GL_PolygonMode(GL_FILL); GL_Disable(GL_CULL_FACE); GL_Disable(GL_POLYGON_OFFSET_FILL); GL_Disable(GL_BLEND); GL_Disable(GL_ALPHA_TEST); GL_Disable(GL_DEPTH_TEST); GL_Disable(GL_STENCIL_TEST); GL_DepthRange(0.0f, 1.0f); GL_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); GL_DepthMask(GL_TRUE); GL_StencilMask(255); // Enable the clip plane if needed if (backEnd.viewParms.viewType != VIEW_MIRROR) qglDisable(GL_CLIP_PLANE0); else { clipPlane[0] = -DotProduct(backEnd.viewParms.axis[1], backEnd.viewParms.clipPlane.normal); clipPlane[1] = DotProduct(backEnd.viewParms.axis[2], backEnd.viewParms.clipPlane.normal); clipPlane[2] = -DotProduct(backEnd.viewParms.axis[0], backEnd.viewParms.clipPlane.normal); clipPlane[3] = DotProduct(backEnd.viewParms.origin, backEnd.viewParms.clipPlane.normal) - backEnd.viewParms.clipPlane.dist; qglEnable(GL_CLIP_PLANE0); qglClipPlane(GL_CLIP_PLANE0, clipPlane); } // Enable multisampling if available if (glConfig.multiSamples > 1) qglEnable(GL_MULTISAMPLE); // Clear the buffers qglClearColor(0.0f, 0.0f, 0.0f, 1.0f); qglClearDepth(1.0f); qglClearStencil(0); if (backEnd.viewParms.primaryView) qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); else qglClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Check for errors if (!r_ignoreGLErrors->integerValue) GL_CheckForErrors(); QGL_LogPrintf("--------------------\n"); }
/* ================= RB_BeginDrawingView Any mirrored or portaled views have already been drawn, so prepare to actually render the visible surfaces for this view ================= */ void RB_BeginDrawingView (void) { int clearBits = 0; // sync with gl if needed if ( r_finish->integer == 1 && !glState.finishCalled ) { qglFinish (); glState.finishCalled = qtrue; } if ( r_finish->integer == 0 ) { glState.finishCalled = qtrue; } // we will need to change the projection matrix before drawing // 2D images again backEnd.projection2D = qfalse; // // set the modelview matrix for the viewer // SetViewportAndScissor(); // ensures that depth writes are enabled for the depth clear GL_State( GLS_DEFAULT ); // clear relevant buffers clearBits = GL_DEPTH_BUFFER_BIT; if ( r_measureOverdraw->integer || r_shadows->integer == 2 ) { clearBits |= GL_STENCIL_BUFFER_BIT; } if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { clearBits |= GL_COLOR_BUFFER_BIT; // FIXME: only if sky shaders have been used qglClearColor( 0.8f, 0.7f, 0.4f, 1 ); // FIXME: get color of sky } qglClear( clearBits ); if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) ) { RB_Hyperspace(); return; } else { backEnd.isHyperspace = qfalse; } glState.faceCulling = -1; // force face culling to set next time // we will only draw a sun if there was sky rendered in this view backEnd.skyRenderedThisView = qfalse; // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { float plane[4]; double plane2[4]; plane[0] = backEnd.viewParms.portalPlane.normal[0]; plane[1] = backEnd.viewParms.portalPlane.normal[1]; plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; qglLoadMatrixf( s_flipMatrix ); qglClipPlane (GL_CLIP_PLANE0, plane2); qglEnable (GL_CLIP_PLANE0); } else { qglDisable (GL_CLIP_PLANE0); } }
/* ================== RB_R200_ARB_CreateDrawInteractions ================== */ static void RB_R200_ARB_CreateDrawInteractions( const drawSurf_t *surf ) { if ( !surf ) { return; } // force a space calculation for light vectors backEnd.currentSpace = NULL; // set the depth test if ( surf->material->Coverage() == MC_TRANSLUCENT /* != C_PERFORATED */ ) { GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_LESS ); } else { // only draw on the alpha tested pixels that made it to the depth buffer GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | GLS_DEPTHFUNC_EQUAL ); } // start the vertex shader qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_R200_INTERACTION ); qglEnable(GL_VERTEX_PROGRAM_ARB); // start the fragment shader qglBindFragmentShaderATI( FPROG_FAST_PATH ); #if defined( MACOS_X ) qglEnable( GL_TEXT_FRAGMENT_SHADER_ATI ); #else qglEnable( GL_FRAGMENT_SHADER_ATI ); #endif qglColor4f( 1, 1, 1, 1 ); GL_SelectTexture( 1 ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); GL_SelectTexture( 2 ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); GL_SelectTexture( 3 ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); for ( ; surf ; surf=surf->nextOnLight ) { RB_CreateSingleDrawInteractions( surf, RB_R200_ARB_DrawInteraction ); } GL_SelectTexture( 5 ); globalImages->BindNull(); GL_SelectTexture( 4 ); globalImages->BindNull(); 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 ); GL_SelectTexture( 0 ); qglDisable( GL_VERTEX_PROGRAM_ARB ); #if defined( MACOS_X ) qglDisable( GL_TEXT_FRAGMENT_SHADER_ATI ); #else qglDisable( GL_FRAGMENT_SHADER_ATI ); #endif }
void RB_DistortionFill(void) { float alpha = tr_distortionAlpha; float spost = 0.0f; float spost2 = 0.0f; if ( glConfig.stencilBits < 4 ) { return; } //ok, cap the stupid thing now I guess if (!tr_distortionPrePost) { RB_CaptureScreenImage(); } qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); qglDisable (GL_CLIP_PLANE0); GL_Cull( CT_TWO_SIDED ); //reset the view matrices and go into ortho mode qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity(); qglOrtho(0, glConfig.vidWidth, glConfig.vidHeight, 32, -1, 1); qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); qglLoadIdentity(); if (tr_distortionStretch) { //override spost = tr_distortionStretch; spost2 = tr_distortionStretch; } else { //do slow stretchy effect spost = sin(tr.refdef.time*0.0005f); if (spost < 0.0f) { spost = -spost; } spost *= 0.2f; spost2 = sin(tr.refdef.time*0.0005f); if (spost2 < 0.0f) { spost2 = -spost2; } spost2 *= 0.08f; } if (alpha != 1.0f) { //blend GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_SRC_ALPHA); } else { //be sure to reset the draw state GL_State(0); } #ifdef HAVE_GLES qglColor4f(1.0f, 1.0f, 1.0f, alpha); GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (!text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglDisableClientState( GL_COLOR_ARRAY ); GLfloat tex[] = { 0+spost2, 1-spost, 0+spost2, 0+spost, 1-spost2, 0+spost, 1-spost2, 1-spost }; GLfloat vtx[] = { 0, 0, 0, glConfig.vidHeight, glConfig.vidWidth, glConfig.vidHeight, glConfig.vidWidth, 0 }; qglTexCoordPointer( 2, GL_FLOAT, 0, tex ); qglVertexPointer ( 2, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); /* if (glcol) qglEnableClientState( GL_COLOR_ARRAY ); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY );*/ #else #ifdef _XBOX qglBeginEXT(GL_QUADS, 4, 0, 0, 4, 0); #else qglBegin(GL_QUADS); #endif // _XBOX qglColor4f(1.0f, 1.0f, 1.0f, alpha); qglTexCoord2f(0+spost2, 1-spost); qglVertex2f(0, 0); qglTexCoord2f(0+spost2, 0+spost); qglVertex2f(0, glConfig.vidHeight); qglTexCoord2f(1-spost2, 0+spost); qglVertex2f(glConfig.vidWidth, glConfig.vidHeight); qglTexCoord2f(1-spost2, 1-spost); qglVertex2f(glConfig.vidWidth, 0); qglEnd(); #endif if (tr_distortionAlpha == 1.0f && tr_distortionStretch == 0.0f) { //no overrides if (tr_distortionNegate) { //probably the crazy alternate saber trail alpha = 0.8f; GL_State(GLS_SRCBLEND_ZERO|GLS_DSTBLEND_ONE_MINUS_SRC_COLOR); } else { alpha = 0.5f; GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_SRC_ALPHA); } spost = sin(tr.refdef.time*0.0008f); if (spost < 0.0f) { spost = -spost; } spost *= 0.08f; spost2 = sin(tr.refdef.time*0.0008f); if (spost2 < 0.0f) { spost2 = -spost2; } spost2 *= 0.2f; #ifdef HAVE_GLES qglColor4f(1.0f, 1.0f, 1.0f, alpha); /* GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (!text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglDisableClientState( GL_COLOR_ARRAY );*/ GLfloat tex[] = { 0+spost2, 1-spost, 0+spost2, 0+spost, 1-spost2, 0+spost, 1-spost2, 1-spost }; GLfloat vtx[] = { 0, 0, 0, glConfig.vidHeight, glConfig.vidWidth, glConfig.vidHeight, glConfig.vidWidth, 0 }; qglTexCoordPointer( 2, GL_FLOAT, 0, tex ); qglVertexPointer ( 2, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); #else #ifdef _XBOX qglBeginEXT(GL_QUADS, 4, 0, 0, 4, 0); #else qglBegin(GL_QUADS); #endif // _XBOX qglColor4f(1.0f, 1.0f, 1.0f, alpha); qglTexCoord2f(0+spost2, 1-spost); qglVertex2f(0, 0); qglTexCoord2f(0+spost2, 0+spost); qglVertex2f(0, glConfig.vidHeight); qglTexCoord2f(1-spost2, 0+spost); qglVertex2f(glConfig.vidWidth, glConfig.vidHeight); qglTexCoord2f(1-spost2, 1-spost); qglVertex2f(glConfig.vidWidth, 0); qglEnd(); #endif } #ifdef HAVE_GLES if (glcol) qglEnableClientState( GL_COLOR_ARRAY ); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); #endif //pop the view matrices back qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); qglPopMatrix(); qglDisable( GL_STENCIL_TEST ); }
/* ================== RB_R200_DrawInteractions ================== */ void RB_R200_DrawInteractions( void ) { qglEnable( GL_STENCIL_TEST ); for ( viewLight_t *vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) { // do fogging later if ( vLight->lightShader->IsFogLight() ) { continue; } if ( vLight->lightShader->IsBlendLight() ) { 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 ); } if ( r_useShadowVertexProgram.GetBool() ) { qglEnable( GL_VERTEX_PROGRAM_ARB ); qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW ); RB_StencilShadowPass( vLight->globalShadows ); RB_R200_ARB_CreateDrawInteractions( vLight->localInteractions ); qglEnable( GL_VERTEX_PROGRAM_ARB ); qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_STENCIL_SHADOW ); RB_StencilShadowPass( vLight->localShadows ); RB_R200_ARB_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_R200_ARB_CreateDrawInteractions( vLight->localInteractions ); RB_StencilShadowPass( vLight->localShadows ); RB_R200_ARB_CreateDrawInteractions( vLight->globalInteractions ); } if ( r_skipTranslucent.GetBool() ) { continue; } // disable stencil testing for translucent interactions, because // the shadow isn't calculated at their point, and the shadow // behind them may be depth fighting with a back side, so there // isn't any reasonable thing to do qglStencilFunc( GL_ALWAYS, 128, 255 ); RB_R200_ARB_CreateDrawInteractions( vLight->translucentInteractions ); } }
/* ** GL_State ** ** This routine is responsible for setting the most commonly changed state ** in Q3. */ void GL_State( unsigned long stateBits ) { unsigned long diff = stateBits ^ glState.glStateBits; if ( !diff ) { return; } // // check depthFunc bits // if ( diff & GLS_DEPTHFUNC_BITS ) { if ( stateBits & GLS_DEPTHFUNC_EQUAL ) { qglDepthFunc( GL_EQUAL ); } else if ( stateBits & GLS_DEPTHFUNC_GREATER) { qglDepthFunc( GL_GREATER ); } else { qglDepthFunc( GL_LEQUAL ); } } // // check blend bits // if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) { GLenum srcFactor = GL_ONE, dstFactor = GL_ONE; if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) { switch ( stateBits & GLS_SRCBLEND_BITS ) { case GLS_SRCBLEND_ZERO: srcFactor = GL_ZERO; break; case GLS_SRCBLEND_ONE: srcFactor = GL_ONE; break; case GLS_SRCBLEND_DST_COLOR: srcFactor = GL_DST_COLOR; break; case GLS_SRCBLEND_ONE_MINUS_DST_COLOR: srcFactor = GL_ONE_MINUS_DST_COLOR; break; case GLS_SRCBLEND_SRC_ALPHA: srcFactor = GL_SRC_ALPHA; break; case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA: srcFactor = GL_ONE_MINUS_SRC_ALPHA; break; case GLS_SRCBLEND_DST_ALPHA: srcFactor = GL_DST_ALPHA; break; case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA: srcFactor = GL_ONE_MINUS_DST_ALPHA; break; case GLS_SRCBLEND_ALPHA_SATURATE: srcFactor = GL_SRC_ALPHA_SATURATE; break; default: ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" ); break; } switch ( stateBits & GLS_DSTBLEND_BITS ) { case GLS_DSTBLEND_ZERO: dstFactor = GL_ZERO; break; case GLS_DSTBLEND_ONE: dstFactor = GL_ONE; break; case GLS_DSTBLEND_SRC_COLOR: dstFactor = GL_SRC_COLOR; break; case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR: dstFactor = GL_ONE_MINUS_SRC_COLOR; break; case GLS_DSTBLEND_SRC_ALPHA: dstFactor = GL_SRC_ALPHA; break; case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA: dstFactor = GL_ONE_MINUS_SRC_ALPHA; break; case GLS_DSTBLEND_DST_ALPHA: dstFactor = GL_DST_ALPHA; break; case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA: dstFactor = GL_ONE_MINUS_DST_ALPHA; break; default: ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" ); break; } qglEnable( GL_BLEND ); qglBlendFunc( srcFactor, dstFactor ); } else { qglDisable( GL_BLEND ); } } // // check depthmask // if ( diff & GLS_DEPTHMASK_TRUE ) { if ( stateBits & GLS_DEPTHMASK_TRUE ) { qglDepthMask( GL_TRUE ); } else { qglDepthMask( GL_FALSE ); } } // // fill/line mode // if ( diff & GLS_POLYMODE_LINE ) { if ( stateBits & GLS_POLYMODE_LINE ) { qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); } else { qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); } } // // depthtest // if ( diff & GLS_DEPTHTEST_DISABLE ) { if ( stateBits & GLS_DEPTHTEST_DISABLE ) { qglDisable( GL_DEPTH_TEST ); } else { qglEnable( GL_DEPTH_TEST ); } } // // alpha test // if ( diff & GLS_ATEST_BITS ) { switch ( stateBits & GLS_ATEST_BITS ) { case 0: qglDisable( GL_ALPHA_TEST ); break; case GLS_ATEST_GT_0: qglEnable( GL_ALPHA_TEST ); qglAlphaFunc( GL_GREATER, 0.0f ); break; case GLS_ATEST_LT_80: qglEnable( GL_ALPHA_TEST ); qglAlphaFunc( GL_LESS, 0.5f ); break; case GLS_ATEST_GE_80: qglEnable( GL_ALPHA_TEST ); qglAlphaFunc( GL_GEQUAL, 0.5f ); break; default: assert( 0 ); break; } } glState.glStateBits = stateBits; }
/* ============== RenderBumpTriangles ============== */ static void RenderBumpTriangles( srfTriangles_t *lowMesh, renderBump_t *rb ) { int i, j; RB_SetGL2D(); qglDisable( GL_CULL_FACE ); qglColor3f( 1, 1, 1 ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, 1, 1, 0, -1, 1 ); qglDisable( GL_BLEND ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); qglDisable( GL_DEPTH_TEST ); qglClearColor(1,0,0,1); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglColor3f( 1, 1, 1 ); // create smoothed normals for the surface, which might be // different than the normals at the vertexes if the // surface uses unsmoothedNormals, which only takes the // normal from a single triangle. We need properly smoothed // normals to make sure that the traces always go off normal // to the true surface. idVec3 *lowMeshNormals = (idVec3 *)Mem_ClearedAlloc( lowMesh->numVerts * sizeof( *lowMeshNormals ) ); R_DeriveFacePlanes( lowMesh ); R_CreateSilIndexes( lowMesh ); // recreate, merging the mirrored verts back together const idPlane *planes = lowMesh->facePlanes; for ( i = 0 ; i < lowMesh->numIndexes ; i += 3, planes++ ) { for ( j = 0 ; j < 3 ; j++ ) { int index; index = lowMesh->silIndexes[i+j]; lowMeshNormals[index] += (*planes).Normal(); } } // normalize and replicate from silIndexes to all indexes for ( i = 0 ; i < lowMesh->numIndexes ; i++ ) { lowMeshNormals[lowMesh->indexes[i]] = lowMeshNormals[lowMesh->silIndexes[i]]; lowMeshNormals[lowMesh->indexes[i]].Normalize(); } // rasterize each low poly face for ( j = 0 ; j < lowMesh->numIndexes ; j+=3 ) { // pump the event loop so the window can be dragged around Sys_GenerateEvents(); RasterizeTriangle( lowMesh, lowMeshNormals, j/3, rb ); qglClearColor(1,0,0,1); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglRasterPos2f( 0, 1 ); qglPixelZoom( glConfig.vidWidth / (float)rb->width, glConfig.vidHeight / (float)rb->height ); qglDrawPixels( rb->width, rb->height, GL_RGBA, GL_UNSIGNED_BYTE, rb->localPic ); qglPixelZoom( 1, 1 ); qglFlush(); GLimp_SwapBuffers(); } Mem_Free( lowMeshNormals ); }