/* ================== RB_NV20_DI_BumpAndLightPass We are going to write alpha as light falloff * ( bump dot light ) * lightProjection If the light isn't a monoLightShader, the lightProjection will be skipped, because it will have to be done on an itterated basis ================== */ static void RB_NV20_DI_BumpAndLightPass(const drawInteraction_t *din, bool monoLightShader) { RB_LogComment("---------- RB_NV_BumpAndLightPass ----------\n"); GL_State(GLS_COLORMASK | GLS_DEPTHMASK | backEnd.depthFunc); // texture 0 is the normalization cube map // GL_TEXTURE0_ARB will be the normalized vector // towards the light source #ifdef MACOS_X GL_SelectTexture(0); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); #else GL_SelectTextureNoClient(0); #endif if (din->ambientLight) { globalImages->ambientNormalMap->Bind(); } else { globalImages->normalCubeMapImage->Bind(); } // texture 1 will be the per-surface bump map #ifdef MACOS_X GL_SelectTexture(1); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); #else GL_SelectTextureNoClient(1); #endif din->bumpImage->Bind(); // texture 2 will be the light falloff texture #ifdef MACOS_X GL_SelectTexture(2); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); #else GL_SelectTextureNoClient(2); #endif din->lightFalloffImage->Bind(); // texture 3 will be the light projection texture #ifdef MACOS_X GL_SelectTexture(3); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); #else GL_SelectTextureNoClient(3); #endif if (monoLightShader) { din->lightImage->Bind(); } else { // if the projected texture is multi-colored, we // will need to do it in subsequent passes globalImages->whiteImage->Bind(); } // bind our "fragment program" RB_NV20_BumpAndLightFragment(); // draw it qglBindProgramARB(GL_VERTEX_PROGRAM_ARB, VPROG_NV20_BUMP_AND_LIGHT); RB_DrawElementsWithCounters(din->surf->geo); }
/* ============= RB_ARB2_CreateDrawInteractions ============= */ void RB_ARB2_CreateDrawInteractions(const drawSurf_t *surf) { if (!surf) { return; } // perform setup here that will be constant for all interactions GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHMASK | backEnd.depthFunc); // bind the vertex program if (r_testARBProgram.GetBool()) { qglBindProgramARB(GL_VERTEX_PROGRAM_ARB, VPROG_TEST); qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FPROG_TEST); } else { qglBindProgramARB(GL_VERTEX_PROGRAM_ARB, VPROG_INTERACTION); qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, FPROG_INTERACTION); } qglEnable(GL_VERTEX_PROGRAM_ARB); qglEnable(GL_FRAGMENT_PROGRAM_ARB); // enable the vertex arrays qglEnableVertexAttribArrayARB(8); qglEnableVertexAttribArrayARB(9); qglEnableVertexAttribArrayARB(10); qglEnableVertexAttribArrayARB(11); qglEnableClientState(GL_COLOR_ARRAY); // texture 0 is the normalization cube map for the vector towards the light GL_SelectTextureNoClient(0); if (backEnd.vLight->lightShader->IsAmbientLight()) { globalImages->ambientNormalMap->Bind(); } else { globalImages->normalCubeMapImage->Bind(); } // texture 6 is the specular lookup table GL_SelectTextureNoClient(6); if (r_testARBProgram.GetBool()) { globalImages->specular2DTableImage->Bind(); // variable specularity in alpha channel } else { globalImages->specularTableImage->Bind(); } for (; surf ; surf=surf->nextOnLight) { // perform setup here that will not change over multiple interaction passes // set the vertex pointers idDrawVert *ac = (idDrawVert *)vertexCache.Position(surf->geo->ambientCache); qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(idDrawVert), ac->color); qglVertexAttribPointerARB(11, 3, GL_FLOAT, false, sizeof(idDrawVert), ac->normal.ToFloatPtr()); qglVertexAttribPointerARB(10, 3, GL_FLOAT, false, sizeof(idDrawVert), ac->tangents[1].ToFloatPtr()); qglVertexAttribPointerARB(9, 3, GL_FLOAT, false, sizeof(idDrawVert), ac->tangents[0].ToFloatPtr()); qglVertexAttribPointerARB(8, 2, GL_FLOAT, false, sizeof(idDrawVert), ac->st.ToFloatPtr()); qglVertexPointer(3, GL_FLOAT, sizeof(idDrawVert), ac->xyz.ToFloatPtr()); // this may cause RB_ARB2_DrawInteraction to be exacuted multiple // times with different colors and images if the surface or light have multiple layers RB_CreateSingleDrawInteractions(surf, RB_ARB2_DrawInteraction); } qglDisableVertexAttribArrayARB(8); qglDisableVertexAttribArrayARB(9); qglDisableVertexAttribArrayARB(10); qglDisableVertexAttribArrayARB(11); qglDisableClientState(GL_COLOR_ARRAY); // disable features GL_SelectTextureNoClient(6); globalImages->BindNull(); GL_SelectTextureNoClient(5); globalImages->BindNull(); GL_SelectTextureNoClient(4); globalImages->BindNull(); GL_SelectTextureNoClient(3); globalImages->BindNull(); GL_SelectTextureNoClient(2); globalImages->BindNull(); GL_SelectTextureNoClient(1); globalImages->BindNull(); backEnd.glState.currenttmu = -1; GL_SelectTexture(0); qglDisable(GL_VERTEX_PROGRAM_ARB); qglDisable(GL_FRAGMENT_PROGRAM_ARB); }
/* =================== RB_StageIteratorLightmappedMultitexture =================== */ void RB_StageIteratorLightmappedMultitexture(void) { shaderCommands_t *input = &tess; shader_t *shader = input->shader; // 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 GL fog SetIteratorFog(); // set face culling appropriately GL_Cull(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, 8, tess.texCoords0); // configure second stage GL_SelectTexture(1); qglEnable(GL_TEXTURE_2D); if (r_lightmap->integer) { GL_TexEnv(GL_REPLACE); } else { GL_TexEnv(GL_MODULATE); } // modified for snooper if (tess.xstages[0]->bundle[1].isLightmap && (backEnd.refdef.rdflags & RDF_SNOOPERVIEW)) { GL_Bind(tr.whiteImage); } else { R_BindAnimatedImage(&tess.xstages[0]->bundle[1]); } qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, 8, tess.texCoords1); // 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 ) if (tess.dlightBits && tess.shader->fogPass && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY))) { if (r_dynamiclight->integer == 2) { DynamicLightPass(); } else { DynamicLightSinglePass(); } } // now do fog if (tess.fogNum && tess.shader->fogPass) { RB_FogPass(); } // unlock arrays if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment("glUnlockArraysEXT\n"); } }
static void ProjectDlightTexture( void ) { int i, l; vec3_t origin; float *texCoords; byte *colors; byte clipBits[SHADER_MAX_VERTEXES]; float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; glIndex_t hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; int fogging; vec3_t floatColor; shaderStage_t *dStage; if ( !backEnd.refdef.num_dlights ) { return; } for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } texCoords = texCoordsArray[0]; colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; VectorCopy( dl->transformed, origin ); radius = dl->radius; scale = 1.0f / radius; floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { vec3_t dist; int clip; float modulate; backEnd.pc.c_dlightVertexes++; VectorSubtract( origin, tess.xyz[i], dist ); int l = 1; int bestIndex = 0; float greatest = tess.normal[i][0]; if (greatest < 0.0f) { greatest = -greatest; } if (VectorCompare(tess.normal[i], vec3_origin)) { //damn you terrain! bestIndex = 2; } else { while (l < 3) { if ((tess.normal[i][l] > greatest && tess.normal[i][l] > 0.0f) || (tess.normal[i][l] < -greatest && tess.normal[i][l] < 0.0f)) { greatest = tess.normal[i][l]; if (greatest < 0.0f) { greatest = -greatest; } bestIndex = l; } l++; } } float dUse = 0.0f; const float maxScale = 1.5f; const float maxGroundScale = 1.4f; const float lightScaleTolerance = 0.1f; if (bestIndex == 2) { dUse = origin[2]-tess.xyz[i][2]; if (dUse < 0.0f) { dUse = -dUse; } dUse = (radius*0.5f)/dUse; if (dUse > maxGroundScale) { dUse = maxGroundScale; } else if (dUse < 0.1f) { dUse = 0.1f; } if (VectorCompare(tess.normal[i], vec3_origin) || tess.normal[i][0] > lightScaleTolerance || tess.normal[i][0] < -lightScaleTolerance || tess.normal[i][1] > lightScaleTolerance || tess.normal[i][1] < -lightScaleTolerance) { //if not perfectly flat, we must use a constant dist scale = 1.0f / radius; } else { scale = 1.0f / (radius*dUse); } texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[1] * scale; } else if (bestIndex == 1) { dUse = origin[1]-tess.xyz[i][1]; if (dUse < 0.0f) { dUse = -dUse; } dUse = (radius*0.5f)/dUse; if (dUse > maxScale) { dUse = maxScale; } else if (dUse < 0.1f) { dUse = 0.1f; } if (tess.normal[i][0] > lightScaleTolerance || tess.normal[i][0] < -lightScaleTolerance || tess.normal[i][2] > lightScaleTolerance || tess.normal[i][2] < -lightScaleTolerance) { //if not perfectly flat, we must use a constant dist scale = 1.0f / radius; } else { scale = 1.0f / (radius*dUse); } texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[2] * scale; } else { dUse = origin[0]-tess.xyz[i][0]; if (dUse < 0.0f) { dUse = -dUse; } dUse = (radius*0.5f)/dUse; if (dUse > maxScale) { dUse = maxScale; } else if (dUse < 0.1f) { dUse = 0.1f; } if (tess.normal[i][2] > lightScaleTolerance || tess.normal[i][2] < -lightScaleTolerance || tess.normal[i][1] > lightScaleTolerance || tess.normal[i][1] < -lightScaleTolerance) { //if not perfectly flat, we must use a constant dist scale = 1.0f / radius; } else { scale = 1.0f / (radius*dUse); } texCoords[0] = 0.5f + dist[1] * scale; texCoords[1] = 0.5f + dist[2] * scale; } clip = 0; if ( texCoords[0] < 0.0f ) { clip |= 1; } else if ( texCoords[0] > 1.0f ) { clip |= 2; } if ( texCoords[1] < 0.0f ) { clip |= 4; } else if ( texCoords[1] > 1.0f ) { clip |= 8; } // modulate the strength based on the height and color if ( dist[bestIndex] > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist[bestIndex] < -radius ) { clip |= 32; modulate = 0.0f; } else { dist[bestIndex] = Q_fabs(dist[bestIndex]); if ( dist[bestIndex] < radius * 0.5f ) { modulate = 1.0f; } else { modulate = 2.0f * (radius - dist[bestIndex]) * scale; } } clipBits[i] = clip; colors[0] = Q_ftol(floatColor[0] * modulate); colors[1] = Q_ftol(floatColor[1] * modulate); colors[2] = Q_ftol(floatColor[2] * modulate); colors[3] = 255; } // build a list of triangles that need light numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { int a, b, c; a = tess.indexes[i]; b = tess.indexes[i+1]; c = tess.indexes[i+2]; if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } hitIndexes[numIndexes] = a; hitIndexes[numIndexes+1] = b; hitIndexes[numIndexes+2] = c; numIndexes += 3; } if ( !numIndexes ) { continue; } //don't have fog enabled when we redraw with alpha test, or it will double over //and screw the tri up -rww if (r_drawfog->value == 2 && tr.world && (tess.fogNum == tr.world->globalFog || tess.fogNum == tr.world->numfogs)) { fogging = qglIsEnabled(GL_FOG); if (fogging) { qglDisable(GL_FOG); } } else { fogging = 0; } dStage = NULL; if (tess.shader && qglActiveTextureARB) { int i = 0; while (i < tess.shader->numUnfoggedPasses) { const int blendBits = (GLS_SRCBLEND_BITS+GLS_DSTBLEND_BITS); if (((tess.shader->stages[i].bundle[0].image && !tess.shader->stages[i].bundle[0].isLightmap && !tess.shader->stages[i].bundle[0].numTexMods) || (tess.shader->stages[i].bundle[1].image && !tess.shader->stages[i].bundle[1].isLightmap && !tess.shader->stages[i].bundle[1].numTexMods)) && (tess.shader->stages[i].stateBits & blendBits) == 0 ) { //only use non-lightmap opaque stages dStage = &tess.shader->stages[i]; break; } i++; } } if (dStage) { GL_SelectTexture( 0 ); GL_State(0); qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); if (dStage->bundle[0].image && !dStage->bundle[0].isLightmap && !dStage->bundle[0].numTexMods) { R_BindAnimatedImage( &dStage->bundle[0] ); } else { R_BindAnimatedImage( &dStage->bundle[1] ); } GL_SelectTexture( 1 ); qglEnable( GL_TEXTURE_2D ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); GL_TexEnv( GL_MODULATE ); GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL);// | GLS_ATEST_GT_0); R_DrawElements( numIndexes, hitIndexes ); qglDisable( GL_TEXTURE_2D ); GL_SelectTexture(0); } else { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->additive ) { GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } R_DrawElements( numIndexes, hitIndexes ); } if (fogging) { qglEnable(GL_FOG); } backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } }
/* ============= 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 (r_sunlightMode->integer && 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); if (r_shadowCascadeZFar->integer != 0) { GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP4); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP4, backEnd.refdef.sunShadowMvp[3]); } else { GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP); GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[3]); } 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 && tr.renderCubeFbo && 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_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" ); } }
/* ============= RB_GLSL_CreateDrawInteractions ============= */ static void RB_GLSL_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 and fragment program if ( backEnd.vLight->lightShader->IsAmbientLight() ) { if (ambientInteractionShader.program == -1) qglUseProgramObjectARB( 0 ); else qglUseProgramObjectARB( ambientInteractionShader.program ); } else { if (interactionShader.program == -1) qglUseProgramObjectARB( 0 ); else qglUseProgramObjectARB( interactionShader.program ); } // enable the vertex arrays qglEnableVertexAttribArrayARB( 8 ); qglEnableVertexAttribArrayARB( 9 ); qglEnableVertexAttribArrayARB( 10 ); qglEnableVertexAttribArrayARB( 11 ); qglEnableClientState( GL_COLOR_ARRAY ); 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() ); // set model matrix if ( backEnd.vLight->lightShader->IsAmbientLight() ) { qglUniformMatrix4fvARB( ambientInteractionShader.modelMatrix, 1, false, surf->space->modelMatrix ); } else { qglUniformMatrix4fvARB( interactionShader.modelMatrix, 1, false, surf->space->modelMatrix ); } // this may cause RB_GLSL_DrawInteraction to be executed multiple // times with different colors and images if the surface or light have multiple layers RB_CreateSingleDrawInteractions( surf, RB_GLSL_DrawInteraction ); } qglDisableVertexAttribArrayARB( 8 ); qglDisableVertexAttribArrayARB( 9 ); qglDisableVertexAttribArrayARB( 10 ); qglDisableVertexAttribArrayARB( 11 ); qglDisableClientState( GL_COLOR_ARRAY ); // disable features 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 ); qglUseProgramObjectARB( 0 ); }
static void ForwardDlight( void ) { int l; //vec3_t origin; //float scale; float radius; int deformGen; vec5_t deformParams; vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; float eyeT = 0; shaderCommands_t *input = &tess; shaderStage_t *pStage = tess.xstages[0]; if ( !backEnd.refdef.num_dlights ) { return; } ComputeDeformValues(&deformGen, deformParams); ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; shaderProgram_t *sp; vec4_t vector; vec4_t texMatrix; vec4_t texOffTurb; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } dl = &backEnd.refdef.dlights[l]; //VectorCopy( dl->transformed, origin ); radius = dl->radius; //scale = 1.0f / radius; //if (pStage->glslShaderGroup == tr.lightallShader) { int index = pStage->glslShaderIndex; index &= ~LIGHTDEF_LIGHTTYPE_MASK; index |= LIGHTDEF_USE_LIGHT_VECTOR; sp = &tr.lightallShader[index]; } backEnd.pc.c_lightallDraws++; GLSL_BindProgram(sp); GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); } if ( input->fogNum ) { vec4_t fogColorMask; GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); ComputeFogColorMask(pStage, fogColorMask); GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); } { vec4_t baseColor; vec4_t vertColor; ComputeShaderColors(pStage, baseColor, vertColor, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); } if (pStage->alphaGen == AGEN_PORTAL) { GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange); } GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen); GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen); GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color); VectorSet(vector, 0, 0, 0); GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector); VectorCopy(dl->origin, vector); vector[3] = 1.0f; GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius); GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale); GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, pStage->specularScale); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); if (pStage->bundle[TB_DIFFUSEMAP].image[0]) R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); // bind textures that are sampled and used in the glsl shader, and // bind whiteImage to textures that are sampled but zeroed in the glsl shader // // alternatives: // - use the last bound texture // -> costs more to sample a higher res texture then throw out the result // - disable texture sampling in glsl shader with #ifdefs, as before // -> increases the number of shaders that must be compiled // if (pStage->bundle[TB_NORMALMAP].image[0]) { R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); } else if (r_normalMapping->integer) GL_BindToTMU( tr.whiteImage, TB_NORMALMAP ); if (pStage->bundle[TB_SPECULARMAP].image[0]) { R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); } else if (r_specularMapping->integer) GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP ); { vec4_t enableTextures; VectorSet4(enableTextures, 0.0f, 0.0f, 0.0f, 0.0f); GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures); } if (r_dlightMode->integer >= 2) { GL_SelectTexture(TB_SHADOWMAP); GL_Bind(tr.shadowCubemaps[l]); GL_SelectTexture(0); } ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); // // draw // if (input->multiDrawPrimitives) { R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); } backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes; backEnd.pc.c_dlightVertexes += tess.numVertexes; } }
/* * RB_GLSL_IterateStagesGeneric * Iterate over each stage of a shader */ static void RB_GLSL_IterateStagesGeneric(shaderCommands_t *input) { int stage; for(stage = 0; stage < MAX_SHADER_STAGES; stage++) { shaderStage_t *pStage = tess.xstages[stage]; glslProgram_t *program; if (!pStage || pStage->program == tr.skipProgram) break; /* set state */ GL_State(pStage->stateBits); /* * this is an ugly hack to work around a GeForce driver * bug with multitexture and clip planes */ if (backEnd.viewParms.isPortal) qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (pStage->program) /* use specified program */ R_GLSL_UseProgram(pStage->program); else /* use default program */ R_GLSL_UseProgram(tr.defaultProgram); program = tr.programs[glState.currentProgram]; /* alphaGen */ if (program->u_AlphaGen > -1) R_GLSL_SetUniform_AlphaGen(program, pStage->alphaGen); /* ambient light */ if (program->u_AmbientLight > -1) R_GLSL_SetUniform_AmbientLight(program, backEnd.currentEntity->ambientLight); /* dynamic light */ if (program->u_DynamicLight > -1) R_GLSL_SetUniform_DynamicLight(program, backEnd.currentEntity->dynamicLight); /* light distance */ if (program->u_LightDistance > -1) R_GLSL_SetUniform_LightDistance(program, backEnd.currentEntity->lightDistance); /* rgbGen */ if (program->u_ColorGen > -1) R_GLSL_SetUniform_ColorGen(program, pStage->rgbGen); /* constant color */ if (program->u_ConstantColor > -1) R_GLSL_SetUniform_ConstantColor(program, pStage->constantColor); /* directed light */ if (program->u_DirectedLight > -1) R_GLSL_SetUniform_DirectedLight(program, backEnd.currentEntity->directedLight); /* entity color */ if (program->u_EntityColor > -1) R_GLSL_SetUniform_EntityColor(program, backEnd.currentEntity->e.shaderRGBA); /* fog color */ if (program->u_FogColor > -1 && tess.fogNum) R_GLSL_SetUniform_FogColor(program, (tr.world->fogs + tess.fogNum)->colorInt); /* greyscale */ if (program->u_Greyscale > -1) R_GLSL_SetUniform_Greyscale(program, r_greyscale->integer); /* identity light */ if (program->u_IdentityLight > -1) R_GLSL_SetUniform_IdentityLight(program, tr.identityLight); /* light direction */ if (program->u_LightDirection > -1) R_GLSL_SetUniform_LightDirection(program, backEnd.currentEntity->lightDir); /* model view matrix */ if (program->u_ModelViewMatrix > -1) R_GLSL_SetUniform_ModelViewMatrix(program, glState.currentModelViewMatrix); /* model view projection matrix */ if (program->u_ModelViewProjectionMatrix > -1) R_GLSL_SetUniform_ModelViewProjectionMatrix(program, glState.currentModelViewProjectionMatrix); /* projection matrix */ if (program->u_ProjectionMatrix > -1) R_GLSL_SetUniform_ProjectionMatrix(program, glState.currentProjectionMatrix); /* texture coordinates 0 */ if (program->u_TCGen0 > -1) R_GLSL_SetUniform_TCGen0(program, pStage->bundle[0].tcGen); /* texture coordinates 1 */ if (program->u_TCGen1 > -1) R_GLSL_SetUniform_TCGen1(program, pStage->bundle[1].tcGen); /* tex env */ if (program->u_TexEnv > -1) { if (r_lightmap->integer) R_GLSL_SetUniform_TexEnv(program, GL_REPLACE); else R_GLSL_SetUniform_TexEnv(program, input->shader->multitextureEnv); } /* texture unit 0 */ if (program->u_Texture0 > -1 && pStage->bundle[0].image[0]) { GL_SelectTexture(0); if (pStage->bundle[0].vertexLightmap && ((r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2) && r_lightmap->integer) GL_Bind(tr.whiteImage); else R_BindAnimatedImage(&pStage->bundle[0]); } /* texture unit 1 */ if (program->u_Texture1 > -1 && pStage->bundle[1].image[0]) { GL_SelectTexture(1); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[1]); } /* texture unit 2 */ if (program->u_Texture2 > -1 && pStage->bundle[2].image[0]) { GL_SelectTexture(2); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[2]); } /* texture unit 3 */ if (program->u_Texture3 > -1 && pStage->bundle[3].image[0]) { GL_SelectTexture(3); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[3]); } /* texture unit 4 */ if (program->u_Texture4 > -1 && pStage->bundle[4].image[0]) { GL_SelectTexture(4); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[4]); } /* texture unit 5 */ if (program->u_Texture5 > -1 && pStage->bundle[5].image[0]) { GL_SelectTexture(5); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[5]); } /* texture unit 6 */ if (program->u_Texture6 > -1 && pStage->bundle[6].image[0]) { GL_SelectTexture(6); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[6]); } /* texture unit 7 */ if (program->u_Texture7 > -1 && pStage->bundle[7].image[0]) { GL_SelectTexture(7); qglEnable(GL_TEXTURE_2D); R_BindAnimatedImage(&pStage->bundle[7]); } /* time */ if (program->u_Time > -1) R_GLSL_SetUniform_Time(program, input->shaderTime); /* view origin */ if (program->u_ViewOrigin > -1) R_GLSL_SetUniform_ViewOrigin(program, backEnd.or.viewOrigin); /* draw */ R_DrawElements(input->numIndexes, input->indexes); /* disable texture unit 7 */ if (program->u_Texture7 > -1) qglDisable(GL_TEXTURE_2D); /* disable texture unit 6 */ if (program->u_Texture6 > -1) { GL_SelectTexture(6); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 5 */ if (program->u_Texture5 > -1) { GL_SelectTexture(5); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 4 */ if (program->u_Texture4 > -1) { GL_SelectTexture(4); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 3 */ if (program->u_Texture3 > -1) { GL_SelectTexture(3); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 2 */ if (program->u_Texture2 > -1) { GL_SelectTexture(2); qglDisable(GL_TEXTURE_2D); } /* disable texture unit 1 */ if (program->u_Texture1 > -1) { GL_SelectTexture(1); qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); } /* switch to texture unit 0 */ GL_SelectTexture(0); /* allow skipping out to show just lightmaps during development */ if (r_lightmap->integer && (pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap)) break; } /* switch to standard rendering pipeline */ R_GLSL_UseProgram(0); }
/* ================== RB_ARB2_DrawInteractions ================== */ void RB_ARB2_DrawInteractions( void ) { viewLight_t *vLight; const idMaterial *lightShader; //FCS int passCount=0; GL_SelectTexture( 0 ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); //printf("r_maxLightPasses = %d\n",r_maxLightPasses.GetInteger()); // // for each light, perform adding and shadowing // for ( vLight = backEnd.viewDef->viewLights ; vLight && passCount < r_maxLightPasses.GetInteger(); vLight = vLight->next,passCount++ ) { 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 ); }
/* ============================ idAutoRender::RenderLoadingIcon ============================ */ void idAutoRender::RenderLoadingIcon( float fracX, float fracY, float size, float speed ) { float s = 0.0f; float c = 1.0f; if( autoRenderIcon != AUTORENDER_HELLICON ) { if( Sys_Milliseconds() >= nextRotateTime ) { nextRotateTime = Sys_Milliseconds() + 100; currentRotation -= 90.0f; } float angle = DEG2RAD( currentRotation ); idMath::SinCos( angle, s, c ); } const float pixelAspect = renderSystem->GetPixelAspect(); const float screenWidth = renderSystem->GetWidth(); const float screenHeight = renderSystem->GetHeight(); const float minSize = Min( screenWidth, screenHeight ); if( minSize <= 0.0f ) { return; } float scaleX = size * minSize / screenWidth; float scaleY = size * minSize / screenHeight; float scale[16] = { 0 }; scale[0] = c * scaleX / pixelAspect; scale[1] = -s * scaleY; scale[4] = s * scaleX / pixelAspect; scale[5] = c * scaleY; scale[10] = 1.0f; scale[15] = 1.0f; scale[12] = fracX; scale[13] = fracY; float ortho[16] = { 0 }; ortho[0] = 2.0f; ortho[5] = -2.0f; ortho[10] = -2.0f; ortho[12] = -1.0f; ortho[13] = 1.0f; ortho[14] = -1.0f; ortho[15] = 1.0f; float finalOrtho[16]; R_MatrixMultiply( scale, ortho, finalOrtho ); float projMatrixTranspose[16]; R_MatrixTranspose( finalOrtho, projMatrixTranspose ); renderProgManager.SetRenderParms( RENDERPARM_MVPMATRIX_X, projMatrixTranspose, 4 ); float a = 1.0f; if( autoRenderIcon == AUTORENDER_HELLICON ) { float alpha = DEG2RAD( Sys_Milliseconds() * speed ); a = idMath::Sin( alpha ); a = 0.35f + ( 0.65f * idMath::Fabs( a ) ); } GL_SelectTexture( 0 ); if( autoRenderIcon == AUTORENDER_HELLICON ) { globalImages->hellLoadingIconImage->Bind(); } else { globalImages->loadingIconImage->Bind(); } GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); // Set Parms float texS[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; float texT[4] = { 0.0f, 1.0f, 0.0f, 0.0f }; renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_S, texS ); renderProgManager.SetRenderParm( RENDERPARM_TEXTUREMATRIX_T, texT ); if( autoRenderIcon == AUTORENDER_HELLICON ) { GL_Color( 1.0f, 1.0f, 1.0f, a ); } // disable texgen float texGenEnabled[4] = { 0, 0, 0, 0 }; renderProgManager.SetRenderParm( RENDERPARM_TEXGEN_0_ENABLED, texGenEnabled ); renderProgManager.BindShader_TextureVertexColor(); RB_DrawElementsWithCounters( &backEnd.unitSquareSurface ); }
/* ============= RB_ARB2_CreateDrawInteractions ============= */ void RB_GLSL_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 ); //GL_Cull(CT_TWO_SIDED); qglEnableClientState(GL_VERTEX_ARRAY); //qglDisableClientState(GL_VERTEX_ARRAY); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); glUseProgram(program); float modelMatrix[16]; myGlMultMatrix( surf->space->modelViewMatrix, backEnd.viewDef->projectionMatrix, modelMatrix); glUniformMatrix4fv(wvp, 1, GL_FALSE, &modelMatrix[0] ); //glUniformMatrix4fv(wvp1, 1, GL_FALSE, &surf->space->modelViewMatrix[0] ); //const float* mat = backEnd.viewDef->projectionMatrix; //glUniformMatrix4fv(wvp, 1, GL_FALSE, &mat[0] ); // enable the vertex arrays glEnableVertexAttribArray( 1 ); glEnableVertexAttribArray( 2 ); glEnableVertexAttribArray( 3 ); glEnableVertexAttribArray( 4 ); glEnableVertexAttribArray( 5 ); glEnableVertexAttribArray( 6 ); // texture 0 is the normalization cube map for the vector towards the light glActiveTexture(GL_TEXTURE0); backEnd.glState.currenttmu = 0; if ( backEnd.vLight->lightShader->IsAmbientLight() ) { globalImages->ambientNormalMap->Bind(); } else { globalImages->normalCubeMapImage->Bind(); } // texture 6 is the specular lookup table glActiveTexture(GL_TEXTURE6); backEnd.glState.currenttmu = 6; if ( r_testARBProgram.GetBool() ) { globalImages->specular2DTableImage->Bind(); // variable specularity in alpha channel } else { globalImages->specularTableImage->Bind(); } for ( ; surf ; surf=surf->nextOnLight ) { // set the vertex pointers idDrawVert *ac = (idDrawVert *)vertexCache.Position( surf->geo->ambientCache ); qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() ); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(idDrawVert), ac->xyz.ToFloatPtr()); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(idDrawVert), ac->st.ToFloatPtr()); glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(idDrawVert), ac->color); glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(idDrawVert), ac->normal.ToFloatPtr()); glVertexAttribPointer(5, 3, GL_FLOAT, GL_FALSE, sizeof(idDrawVert), ac->tangents[0].ToFloatPtr()); glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, sizeof(idDrawVert), ac->tangents[1].ToFloatPtr()); idVec4 localLight; R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.vLight->globalLightOrigin, localLight.ToVec3() ); localLight.w = 0.0f; glUniform3fv(lightOrgin, 1, localLight.ToFloatPtr()); //glDrawElements(GL_TRIANGLES, surf->geo->numIndexes, GL_UNSIGNED_SHORT, surf->geo->indexes); // 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_GLSL_DrawInteraction ); } glDisableVertexAttribArray( 1 ); glDisableVertexAttribArray( 2 ); glDisableVertexAttribArray( 3 ); glDisableVertexAttribArray( 4 ); glDisableVertexAttribArray( 5 ); glDisableVertexAttribArray( 6 ); // disable features glActiveTexture( GL_TEXTURE6 ); backEnd.glState.currenttmu = 6; globalImages->BindNull(); glActiveTexture( GL_TEXTURE5 ); backEnd.glState.currenttmu = 5; globalImages->BindNull(); glActiveTexture( GL_TEXTURE4 ); backEnd.glState.currenttmu = 4; globalImages->BindNull(); glActiveTexture( GL_TEXTURE3 ); backEnd.glState.currenttmu = 3; globalImages->BindNull(); glActiveTexture( GL_TEXTURE2 ); backEnd.glState.currenttmu = 2; globalImages->BindNull(); glActiveTexture( GL_TEXTURE1 ); backEnd.glState.currenttmu = 1; globalImages->BindNull(); glUseProgram(0); backEnd.glState.currenttmu = -1; GL_SelectTexture(0 ); }
/* =================== DrawMultitextured output = t0 * t1 or t0 + t1 t0 = most upstream according to spec t1 = most downstream according to spec =================== */ static void DrawMultitextured(shaderCommands_t * input, int stage) { shaderStage_t *pStage; pStage = tess.xstages[stage]; // Ridah if(tess.shader->noFog && pStage->isFogged) { R_FogOn(); } else if(tess.shader->noFog && !pStage->isFogged) { R_FogOff(); // turn it back off } else { // make sure it's on R_FogOn(); } // done. GL_State(pStage->stateBits); // this is an ugly hack to work around a GeForce driver // bug with multitexture and clip planes if(backEnd.viewParms.isPortal) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } // // base // GL_SelectTexture(0); glTexCoordPointer(2, GL_FLOAT, 0, input->svars.texcoords[0]); R_BindAnimatedImage(&pStage->bundle[0]); // // lightmap/secondary pass // GL_SelectTexture(1); glEnable(GL_TEXTURE_2D); glEnableClientState(GL_TEXTURE_COORD_ARRAY); if(r_lightmap->integer) { GL_TexEnv(GL_REPLACE); } else { GL_TexEnv(tess.shader->multitextureEnv); } glTexCoordPointer(2, GL_FLOAT, 0, input->svars.texcoords[1]); R_BindAnimatedImage(&pStage->bundle[1]); R_DrawElements(input->numIndexes, input->indexes); // // disable texturing on TEXTURE1, then select TEXTURE0 // //glDisableClientState( GL_TEXTURE_COORD_ARRAY ); glDisable(GL_TEXTURE_2D); GL_SelectTexture(0); }
/* ==================== Unbind This can go away once everything uses fragment programs so the enable states don't need tracking ==================== */ void idMegaTexture::Unbind( void ) { for ( int i = 0 ; i < numLevels ; i++ ) { GL_SelectTexture( 1+i ); globalImages->BindNull(); } }
/* ============= RB_NV20_CreateDrawInteractions ============= */ static void RB_NV20_CreateDrawInteractions(const drawSurf_t *surf) { if (!surf) { return; } qglEnable(GL_VERTEX_PROGRAM_ARB); qglEnable(GL_REGISTER_COMBINERS_NV); #ifdef MACOS_X GL_SelectTexture(0); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); #else qglDisableClientState(GL_TEXTURE_COORD_ARRAY); qglEnableVertexAttribArrayARB(8); qglEnableVertexAttribArrayARB(9); qglEnableVertexAttribArrayARB(10); qglEnableVertexAttribArrayARB(11); #endif for (; surf ; surf=surf->nextOnLight) { // set the vertex pointers idDrawVert *ac = (idDrawVert *)vertexCache.Position(surf->geo->ambientCache); qglColorPointer(4, GL_UNSIGNED_BYTE, sizeof(idDrawVert), ac->color); #ifdef MACOS_X GL_SelectTexture(0); qglTexCoordPointer(2, GL_FLOAT, sizeof(idDrawVert), ac->st.ToFloatPtr()); GL_SelectTexture(1); qglTexCoordPointer(3, GL_FLOAT, sizeof(idDrawVert), ac->tangents[0].ToFloatPtr()); GL_SelectTexture(2); qglTexCoordPointer(3, GL_FLOAT, sizeof(idDrawVert), ac->tangents[1].ToFloatPtr()); GL_SelectTexture(3); qglTexCoordPointer(3, GL_FLOAT, sizeof(idDrawVert), ac->normal.ToFloatPtr()); GL_SelectTexture(0); #else qglVertexAttribPointerARB(11, 3, GL_FLOAT, false, sizeof(idDrawVert), ac->normal.ToFloatPtr()); qglVertexAttribPointerARB(10, 3, GL_FLOAT, false, sizeof(idDrawVert), ac->tangents[1].ToFloatPtr()); qglVertexAttribPointerARB(9, 3, GL_FLOAT, false, sizeof(idDrawVert), ac->tangents[0].ToFloatPtr()); qglVertexAttribPointerARB(8, 2, GL_FLOAT, false, sizeof(idDrawVert), ac->st.ToFloatPtr()); #endif qglVertexPointer(3, GL_FLOAT, sizeof(idDrawVert), ac->xyz.ToFloatPtr()); RB_CreateSingleDrawInteractions(surf, RB_NV20_DrawInteraction); } #ifndef MACOS_X qglDisableVertexAttribArrayARB(8); qglDisableVertexAttribArrayARB(9); qglDisableVertexAttribArrayARB(10); qglDisableVertexAttribArrayARB(11); #endif // disable features #ifdef MACOS_X GL_SelectTexture(3); globalImages->BindNull(); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(2); globalImages->BindNull(); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(1); globalImages->BindNull(); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); #else GL_SelectTextureNoClient(3); globalImages->BindNull(); GL_SelectTextureNoClient(2); globalImages->BindNull(); GL_SelectTextureNoClient(1); globalImages->BindNull(); #endif backEnd.glState.currenttmu = -1; GL_SelectTexture(0); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglDisable(GL_VERTEX_PROGRAM_ARB); qglDisable(GL_REGISTER_COMBINERS_NV); }
/* * RB_GLSL_StageIteratorGeneric * Stage iterator for GLSL programs */ void RB_GLSL_StageIteratorGeneric(void) { shaderCommands_t *input; input = &tess; /* log this call */ if (r_logFile->integer) { /* don't just call LogComment, or we will get a call to va() every frame! */ GLimp_LogComment(va("--- R_GLSL_StageIteratorGeneric( %s ) ---\n", input->shader->name)); } /* set face culling appropiately */ GL_Cull(input->shader->cullType); /* set polygon offset if necessary */ if (input->shader->polygonOffset) { qglEnable(GL_POLYGON_OFFSET_FILL); qglPolygonOffset(r_offsetFactor->value, r_offsetUnits->value); } /* set vertex color array */ qglEnableClientState(GL_COLOR_ARRAY); qglColorPointer(4, GL_UNSIGNED_BYTE, 0, input->vertexColors); /* set texture coordinate array 0 */ GL_SelectTexture(0); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, 16, input->texCoords[0][0]); /* set texture coordinate array 1 */ GL_SelectTexture(1); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, 16, input->texCoords[0][1]); /* set vertex normal array */ qglEnableClientState(GL_NORMAL_ARRAY); qglNormalPointer(GL_FLOAT, 16, input->normal); /* lock XYZ */ qglVertexPointer(3, GL_FLOAT, 16, input->xyz); /* padded SIMD */ if (qglLockArraysEXT) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment("glLockArraysEXT\n"); } RB_GLSL_IterateStagesGeneric(input); /* now do any dynamic lighting needed */ if (input->dlightBits && input->shader->sort <= SS_OPAQUE && !(input->shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY))) ProjectDlightTexture(); // <-- RiO_Outlines: now do outlines RB_OutlinesPass(); // --> /* now do fog */ if (input->fogNum && input->shader->fogPass) RB_FogPass(); // TODO: uses svars which aren't set, so move to program /* unlock arrays */ if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment("glUnlockArraysExt\n"); } /* reset polygon offset */ if (input->shader->polygonOffset) qglDisable(GL_POLYGON_OFFSET_FILL); }
/* ================ Tess_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void Tess_StageIteratorSky( void ) { #if !defined( USE_D3D10 ) // 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 ( "--- Tess_StageIteratorSky( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name, tess.numVertexes, tess.numIndexes / 3 ) ); } if ( r_fastsky->integer ) { return; } // trebor: HACK why does this happen with cg_draw2D 0 ? if ( tess.stageIteratorFunc2 == NULL ) { //tess.stageIteratorFunc2 = Tess_StageIteratorGeneric; ri.Error( ERR_FATAL, "tess.stageIteratorFunc == NULL" ); } if ( tess.stageIteratorFunc2 == &Tess_StageIteratorDepthFill ) { // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn Tess_ClipSkyPolygons(); // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine BuildCloudData(); if ( tess.numVertexes || tess.multiDrawPrimitives ) { tess.stageIteratorFunc2(); } } else { if ( tess.stageIteratorFunc2 == &Tess_StageIteratorGBuffer ) { R_BindFBO( tr.geometricRenderFBO ); } // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn Tess_ClipSkyPolygons(); // r_showSky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if ( r_showSky->integer ) { glDepthRange( 0.0, 0.0 ); } else { glDepthRange( 1.0, 1.0 ); } // draw the outer skybox if ( tess.surfaceShader->sky.outerbox && tess.surfaceShader->sky.outerbox != tr.blackCubeImage ) { #if 1 R_BindVBO( tess.vbo ); R_BindIBO( tess.ibo ); gl_skyboxShader->SetPortalClipping( backEnd.viewParms.isPortal ); gl_skyboxShader->BindProgram(); gl_skyboxShader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); // in world space gl_skyboxShader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_skyboxShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // u_PortalPlane if ( backEnd.viewParms.isPortal ) { float plane[ 4 ]; // clipping plane in world space 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; gl_skyboxShader->SetUniform_PortalPlane( plane ); } gl_skyboxShader->SetRequiredVertexPointers(); // bind u_ColorMap GL_SelectTexture( 0 ); GL_Bind( tess.surfaceShader->sky.outerbox ); DrawSkyBox( tess.surfaceShader ); #endif } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine BuildCloudData(); if ( tess.numVertexes || tess.multiDrawPrimitives ) { tess.stageIteratorFunc2(); } // Tr3B: TODO draw the inner skybox? if ( tess.stageIteratorFunc2 == Tess_StageIteratorGBuffer ) { R_BindNullFBO(); } if ( tess.stageIteratorFunc2 != Tess_StageIteratorDepthFill ) { // back to normal depth range glDepthRange( 0.0, 1.0 ); // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; } } #endif }
/* ** GL_SetDefaultState */ void GL_SetDefaultState( void ) { qglClearDepth( 1.0f ); qglCullFace( GL_FRONT ); qglColor4f( 1,1,1,1 ); // initialize downstream texture unit if we're running // in a multitexture environment if ( qglActiveTextureARB ) { GL_SelectTexture( 1 ); GL_TextureMode( r_textureMode->string ); GL_TexEnv( GL_MODULATE ); qglDisable( GL_TEXTURE_2D ); GL_SelectTexture( 0 ); } qglEnable( GL_TEXTURE_2D ); GL_TextureMode( r_textureMode->string ); GL_TexEnv( GL_MODULATE ); qglShadeModel( GL_SMOOTH ); qglDepthFunc( GL_LEQUAL ); // the vertex array is always enabled, but the color and texture // arrays are enabled and disabled around the compiled vertex array call qglEnableClientState( GL_VERTEX_ARRAY ); // // make sure our GL state vector is set correctly // glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE; #ifndef VCMODS_OPENGLES qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); #endif qglDepthMask( GL_TRUE ); qglDisable( GL_DEPTH_TEST ); qglEnable( GL_SCISSOR_TEST ); qglDisable( GL_CULL_FACE ); qglDisable( GL_BLEND ); #ifndef VCMODS_OPENGLES //----(SA) added. // ATI pn_triangles if ( qglPNTrianglesiATI ) { int maxtess; // get max supported tesselation qglGetIntegerv( GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI, (GLint*)&maxtess ); glConfig.ATIMaxTruformTess = maxtess; // cap if necessary if ( r_ati_truform_tess->value > maxtess ) { ri.Cvar_Set( "r_ati_truform_tess", va( "%d", maxtess ) ); } // set Wolf defaults qglPNTrianglesiATI( GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, r_ati_truform_tess->value ); } if ( glConfig.anisotropicAvailable ) { float maxAnisotropy; qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy ); glConfig.maxAnisotropy = maxAnisotropy; // set when rendering // qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, glConfig.maxAnisotropy); } //----(SA) end #endif }
/* ** R_DrawTriangleOutlines */ void R_DrawTriangleOutlines(msurface_t *surf) // jit/GuyP, redone { int i; glpoly_t *p; if (!gl_showtris->value) return; // Guy: *\/\/\/ gl_showtris fix begin \/\/\/* qgl.Disable(GL_DEPTH_TEST); qgl.Color4f(1.0f, 1.0f, 1.0f, 1.0f); if (!surf) // Guy: Called from non-multitexture mode; need to loop through surfaces defined by non-mtex functions { int j; qgl.Disable(GL_TEXTURE_2D); for (i = 0; i < MAX_LIGHTMAPS; i++) { for (surf = gl_lms.lightmap_surfaces[i]; surf != 0; surf = surf->lightmapchain) { for (p = surf->polys; p; p = p->chain) { for (j = 2; j < p->numverts; j++) { qgl.Begin(GL_LINE_STRIP); qgl.Vertex3fv(p->verts[0]); qgl.Vertex3fv(p->verts[j - 1]); qgl.Vertex3fv(p->verts[j]); qgl.Vertex3fv(p->verts[0]); qgl.End(); } } } } qgl.Enable(GL_TEXTURE_2D); } else // Guy: Called from multitexture mode; surface to be rendered in wireframe already passed in { float tex_state0, tex_state1; GL_SelectTexture(QGL_TEXTURE0); qgl.GetTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &tex_state0); GL_SelectTexture(QGL_TEXTURE1); qgl.GetTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &tex_state1); GL_EnableMultitexture(false); qgl.Disable(GL_TEXTURE_2D); for (p = surf->polys; p; p = p->chain) { for (i = 2; i < p->numverts; i++) { //distcolor = p->verts[ qgl.Begin(GL_LINE_STRIP); //qgl.Color4f(1, 1, 1, 1); //qgl.Color4f(0,1,0,1); qgl.Vertex3fv(p->verts[0]); qgl.Vertex3fv(p->verts[i - 1]); qgl.Vertex3fv(p->verts[i]); qgl.Vertex3fv(p->verts[0]); qgl.End(); } } qgl.Enable(GL_TEXTURE_2D); GL_EnableMultitexture(true); GL_SelectTexture(QGL_TEXTURE0); GL_TexEnv(tex_state0); GL_SelectTexture(QGL_TEXTURE1); GL_TexEnv(tex_state1); } qgl.Enable(GL_DEPTH_TEST); // Guy: */\/\/\ gl_showtris fix end /\/\/\* }
static void ForwardDlight( void ) { int l; //vec3_t origin; //float scale; float radius; int deformGen; vec5_t deformParams; vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; float eyeT = 0; shaderCommands_t *input = &tess; shaderStage_t *pStage = tess.xstages[0]; if ( !backEnd.refdef.num_dlights ) { return; } ComputeDeformValues(&deformGen, deformParams); ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; shaderProgram_t *sp; vec4_t vector; matrix_t matrix; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } dl = &backEnd.refdef.dlights[l]; //VectorCopy( dl->transformed, origin ); radius = dl->radius; //scale = 1.0f / radius; //if (pStage->glslShaderGroup == tr.lightallShader) { int index = pStage->glslShaderIndex; index &= ~(LIGHTDEF_LIGHTTYPE_MASK | LIGHTDEF_USE_DELUXEMAP); index |= LIGHTDEF_USE_LIGHT_VECTOR; sp = &tr.lightallShader[index]; } backEnd.pc.c_lightallDraws++; GLSL_BindProgram(sp); GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams); GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); } if ( input->fogNum ) { vec4_t fogColorMask; GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDISTANCE, fogDistanceVector); GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDEPTH, fogDepthVector); GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_FOGEYET, eyeT); ComputeFogColorMask(pStage, fogColorMask); GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGCOLORMASK, fogColorMask); } { vec4_t baseColor; vec4_t vertColor; ComputeShaderColors(pStage, baseColor, vertColor); GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_BASECOLOR, baseColor); GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_VERTCOLOR, vertColor); } if (pStage->alphaGen == AGEN_PORTAL) { GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_PORTALRANGE, tess.shader->portalRange); } GLSL_SetUniformInt(sp, GENERIC_UNIFORM_COLORGEN, pStage->rgbGen); GLSL_SetUniformInt(sp, GENERIC_UNIFORM_ALPHAGEN, pStage->alphaGen); GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DIRECTEDLIGHT, dl->color); VectorSet(vector, 0, 0, 0); GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_AMBIENTLIGHT, vector); VectorCopy(dl->origin, vector); vector[3] = 1.0f; GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vector); GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, radius); GLSL_SetUniformVec2(sp, GENERIC_UNIFORM_MATERIALINFO, pStage->materialInfo); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); if (pStage->bundle[TB_DIFFUSEMAP].image[0]) R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); if (pStage->bundle[TB_NORMALMAP].image[0]) R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); if (pStage->bundle[TB_SPECULARMAP].image[0]) R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); if (r_dlightMode->integer >= 2) { GL_SelectTexture(TB_SHADOWMAP); GL_BindCubemap(tr.shadowCubemaps[l]); GL_SelectTexture(0); } ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]); GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, vector); VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]); GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXOFFTURB, vector); GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TCGEN0, pStage->bundle[0].tcGen); // // draw // if (input->multiDrawPrimitives) { R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); } backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes; } }
/* ================== RB_GLSL_DrawInteractions ================== */ void RB_GLSL_DrawInteractions( void ) { viewLight_t *vLight; 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 there are no interactions, get out! if ( !vLight->localInteractions && !vLight->globalInteractions && !vLight->translucentInteractions ) { continue; } // 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() ) { qglUseProgramObjectARB( stencilShadowShader.program ); RB_StencilShadowPass( vLight->globalShadows ); RB_GLSL_CreateDrawInteractions( vLight->localInteractions ); qglUseProgramObjectARB( stencilShadowShader.program ); RB_StencilShadowPass( vLight->localShadows ); RB_GLSL_CreateDrawInteractions( vLight->globalInteractions ); qglUseProgramObjectARB( 0 ); // if there weren't any globalInteractions, it would have stayed on } else { RB_StencilShadowPass( vLight->globalShadows ); RB_GLSL_CreateDrawInteractions( vLight->localInteractions ); RB_StencilShadowPass( vLight->localShadows ); RB_GLSL_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_GLSL_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 ); }
/* =================== ProjectDlightTexture Perform dynamic lighting with another rendering pass =================== */ static void ProjectDlightTexture2( void ) { int i, l; vec3_t origin; byte clipBits[SHADER_MAX_VERTEXES]; float texCoordsArray[SHADER_MAX_VERTEXES][2]; float oldTexCoordsArray[SHADER_MAX_VERTEXES][2]; float vertCoordsArray[SHADER_MAX_VERTEXES][4]; unsigned int colorArray[SHADER_MAX_VERTEXES]; glIndex_t hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float radius; int fogging; shaderStage_t *dStage; vec3_t posa; vec3_t posb; vec3_t posc; vec3_t dist; vec3_t e1; vec3_t e2; vec3_t normal; float fac,modulate; vec3_t floatColor; byte colorTemp[4]; int needResetVerts=0; if ( !backEnd.refdef.num_dlights ) { return; } for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } dl = &backEnd.refdef.dlights[l]; VectorCopy( dl->transformed, origin ); radius = dl->radius; int clipall = 63; for ( i = 0 ; i < tess.numVertexes ; i++) { int clip; VectorSubtract( origin, tess.xyz[i], dist ); clip = 0; if ( dist[0] < -radius ) { clip |= 1; } else if ( dist[0] > radius ) { clip |= 2; } if ( dist[1] < -radius ) { clip |= 4; } else if ( dist[1] > radius ) { clip |= 8; } if ( dist[2] < -radius ) { clip |= 16; } else if ( dist[2] > radius ) { clip |= 32; } clipBits[i] = clip; clipall &= clip; } if ( clipall ) { continue; // this surface doesn't have any of this light } floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; // build a list of triangles that need light numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { int a, b, c; a = tess.indexes[i]; b = tess.indexes[i+1]; c = tess.indexes[i+2]; if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } // copy the vertex positions VectorCopy(tess.xyz[a],posa); VectorCopy(tess.xyz[b],posb); VectorCopy(tess.xyz[c],posc); VectorSubtract( posa, posb,e1); VectorSubtract( posc, posb,e2); CrossProduct(e1,e2,normal); // rjr - removed for hacking if ( (!r_dlightBacks->integer && DotProduct(normal,origin)-DotProduct(normal,posa) <= 0.0f) || // backface if ( DotProduct(normal,origin)-DotProduct(normal,posa) <= 0.0f || // backface DotProduct(normal,normal) < 1E-8f) // junk triangle { continue; } VectorNormalize(normal); fac=DotProduct(normal,origin)-DotProduct(normal,posa); if (fac >= radius) // out of range { continue; } modulate = 1.0f-((fac*fac) / (radius*radius)); fac = 0.5f/sqrtf(radius*radius - fac*fac); // save the verts VectorCopy(posa,vertCoordsArray[numIndexes]); VectorCopy(posb,vertCoordsArray[numIndexes+1]); VectorCopy(posc,vertCoordsArray[numIndexes+2]); // now we need e1 and e2 to be an orthonormal basis if (DotProduct(e1,e1) > DotProduct(e2,e2)) { VectorNormalize(e1); CrossProduct(e1,normal,e2); } else { VectorNormalize(e2); CrossProduct(normal,e2,e1); } VectorScale(e1,fac,e1); VectorScale(e2,fac,e2); VectorSubtract( posa, origin,dist); texCoordsArray[numIndexes][0]=DotProduct(dist,e1)+0.5f; texCoordsArray[numIndexes][1]=DotProduct(dist,e2)+0.5f; VectorSubtract( posb, origin,dist); texCoordsArray[numIndexes+1][0]=DotProduct(dist,e1)+0.5f; texCoordsArray[numIndexes+1][1]=DotProduct(dist,e2)+0.5f; VectorSubtract( posc, origin,dist); texCoordsArray[numIndexes+2][0]=DotProduct(dist,e1)+0.5f; texCoordsArray[numIndexes+2][1]=DotProduct(dist,e2)+0.5f; if ((texCoordsArray[numIndexes][0] < 0.0f && texCoordsArray[numIndexes+1][0] < 0.0f && texCoordsArray[numIndexes+2][0] < 0.0f) || (texCoordsArray[numIndexes][0] > 1.0f && texCoordsArray[numIndexes+1][0] > 1.0f && texCoordsArray[numIndexes+2][0] > 1.0f) || (texCoordsArray[numIndexes][1] < 0.0f && texCoordsArray[numIndexes+1][1] < 0.0f && texCoordsArray[numIndexes+2][1] < 0.0f) || (texCoordsArray[numIndexes][1] > 1.0f && texCoordsArray[numIndexes+1][1] > 1.0f && texCoordsArray[numIndexes+2][1] > 1.0f) ) { continue; // didn't end up hitting this tri } /* old code, get from the svars = wrong oldTexCoordsArray[numIndexes][0]=tess.svars.texcoords[0][a][0]; oldTexCoordsArray[numIndexes][1]=tess.svars.texcoords[0][a][1]; oldTexCoordsArray[numIndexes+1][0]=tess.svars.texcoords[0][b][0]; oldTexCoordsArray[numIndexes+1][1]=tess.svars.texcoords[0][b][1]; oldTexCoordsArray[numIndexes+2][0]=tess.svars.texcoords[0][c][0]; oldTexCoordsArray[numIndexes+2][1]=tess.svars.texcoords[0][c][1]; */ oldTexCoordsArray[numIndexes][0]=tess.texCoords[a][0][0]; oldTexCoordsArray[numIndexes][1]=tess.texCoords[a][0][1]; oldTexCoordsArray[numIndexes+1][0]=tess.texCoords[b][0][0]; oldTexCoordsArray[numIndexes+1][1]=tess.texCoords[b][0][1]; oldTexCoordsArray[numIndexes+2][0]=tess.texCoords[c][0][0]; oldTexCoordsArray[numIndexes+2][1]=tess.texCoords[c][0][1]; colorTemp[0] = Q_ftol(floatColor[0] * modulate); colorTemp[1] = Q_ftol(floatColor[1] * modulate); colorTemp[2] = Q_ftol(floatColor[2] * modulate); colorTemp[3] = 255; byteAlias_t *ba = (byteAlias_t *)&colorTemp; colorArray[numIndexes + 0] = ba->ui; colorArray[numIndexes + 1] = ba->ui; colorArray[numIndexes + 2] = ba->ui; hitIndexes[numIndexes] = numIndexes; hitIndexes[numIndexes+1] = numIndexes+1; hitIndexes[numIndexes+2] = numIndexes+2; numIndexes += 3; if (numIndexes>=SHADER_MAX_VERTEXES-3) { break; // we are out of space, so we are done :) } } if ( !numIndexes ) { continue; } //don't have fog enabled when we redraw with alpha test, or it will double over //and screw the tri up -rww if (r_drawfog->value == 2 && tr.world && (tess.fogNum == tr.world->globalFog || tess.fogNum == tr.world->numfogs)) { fogging = qglIsEnabled(GL_FOG); if (fogging) { qglDisable(GL_FOG); } } else { fogging = 0; } dStage = NULL; if (tess.shader && qglActiveTextureARB) { int i = 0; while (i < tess.shader->numUnfoggedPasses) { const int blendBits = (GLS_SRCBLEND_BITS+GLS_DSTBLEND_BITS); if (((tess.shader->stages[i].bundle[0].image && !tess.shader->stages[i].bundle[0].isLightmap && !tess.shader->stages[i].bundle[0].numTexMods && tess.shader->stages[i].bundle[0].tcGen != TCGEN_ENVIRONMENT_MAPPED && tess.shader->stages[i].bundle[0].tcGen != TCGEN_FOG) || (tess.shader->stages[i].bundle[1].image && !tess.shader->stages[i].bundle[1].isLightmap && !tess.shader->stages[i].bundle[1].numTexMods && tess.shader->stages[i].bundle[1].tcGen != TCGEN_ENVIRONMENT_MAPPED && tess.shader->stages[i].bundle[1].tcGen != TCGEN_FOG)) && (tess.shader->stages[i].stateBits & blendBits) == 0 ) { //only use non-lightmap opaque stages dStage = &tess.shader->stages[i]; break; } i++; } } if (!needResetVerts) { needResetVerts=1; if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } } qglVertexPointer (3, GL_FLOAT, 16, vertCoordsArray); // padded for SIMD if (dStage) { GL_SelectTexture( 0 ); GL_State(0); qglTexCoordPointer( 2, GL_FLOAT, 0, oldTexCoordsArray[0] ); if (dStage->bundle[0].image && !dStage->bundle[0].isLightmap && !dStage->bundle[0].numTexMods && dStage->bundle[0].tcGen != TCGEN_ENVIRONMENT_MAPPED && dStage->bundle[0].tcGen != TCGEN_FOG) { R_BindAnimatedImage( &dStage->bundle[0] ); } else { R_BindAnimatedImage( &dStage->bundle[1] ); } GL_SelectTexture( 1 ); qglEnable( GL_TEXTURE_2D ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); GL_TexEnv( GL_MODULATE ); GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL);// | GLS_ATEST_GT_0); R_DrawElements( numIndexes, hitIndexes ); qglDisable( GL_TEXTURE_2D ); GL_SelectTexture(0); } else { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); GL_Bind( tr.dlightImage ); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->additive ) { GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } R_DrawElements( numIndexes, hitIndexes ); } if (fogging) { qglEnable(GL_FOG); } backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } if (needResetVerts) { qglVertexPointer (3, GL_FLOAT, 16, tess.xyz); // padded for SIMD if (qglLockArraysEXT) { qglLockArraysEXT(0, tess.numVertexes); GLimp_LogComment( "glLockArraysEXT\n" ); } } }