/* ** RB_StageIteratorGeneric */ void RB_StageIteratorGeneric( void ) { shaderCommands_t *input; unsigned int vertexAttribs = 0; input = &tess; if (!input->numVertexes || !input->numIndexes) { return; } if (tess.useInternalVBO) { RB_DeformTessGeometry(); } vertexAttribs = RB_CalcShaderVertexAttribs( input ); if (tess.useInternalVBO) { RB_UpdateVBOs(vertexAttribs); } else { backEnd.pc.c_staticVboDraws++; } // // log this call // if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); } // // set face culling appropriately // if ((backEnd.viewParms.flags & VPF_DEPTHSHADOW)) { //GL_Cull( CT_TWO_SIDED ); if (input->shader->cullType == CT_TWO_SIDED) GL_Cull( CT_TWO_SIDED ); else if (input->shader->cullType == CT_FRONT_SIDED) GL_Cull( CT_BACK_SIDED ); else GL_Cull( CT_FRONT_SIDED ); } else GL_Cull( input->shader->cullType ); // set polygon offset if necessary if ( input->shader->polygonOffset ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } // // Set vertex attribs and pointers // GLSL_VertexAttribsState(vertexAttribs); // // render depth if in depthfill mode // if (backEnd.depthFill) { RB_IterateStagesGeneric( input ); // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } return; } // // render shadowmap if in shadowmap mode // if (backEnd.viewParms.flags & VPF_SHADOWMAP) { if ( input->shader->sort == SS_OPAQUE ) { RB_RenderShadowmap( input ); } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } return; } // // // call shader function // RB_IterateStagesGeneric( input ); // // pshadows! // if (glRefConfig.framebufferObject && tess.pshadowBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { ProjectPshadowVBOGLSL(); } // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader && (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer) { ForwardDlight(); } else { ProjectDlightTexture(); } } if ((backEnd.viewParms.flags & VPF_USESUNLIGHT) && tess.shader->sort <= SS_OPAQUE //if ((tr.sunShadows || r_forceSunlight->value > 0.0f) && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) && tess.xstages[0]->glslShaderGroup == tr.lightallShader) { ForwardSunlight(); } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(); } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } }
/* * RE_StretchRaw * * FIXME: not exactly backend * Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. * Used for cinematics. */ void RE_StretchRaw(int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qbool dirty) { int i, j; int start, end; shaderProgram_t *sp = &tr.textureColorShader; Vec4 color; if(!tr.registered){ return; } R_SyncRenderThread(); /* we definately want to sync every frame for the cinematics */ qglFinish(); start = 0; if(r_speeds->integer){ start = ri.Milliseconds(); } /* make sure rows and cols are powers of 2 */ for(i = 0; (1 << i) < cols; i++){ } for(j = 0; (1 << j) < rows; j++){ } if((1 << i) != cols || (1 << j) != rows){ ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); } GL_Bind(tr.scratchImage[client]); /* if the scratchImage isn't in the format we want, specify it as a new texture */ if(cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height){ tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); }else{ if(dirty){ /* otherwise, just subimage upload it so that drivers can tell we are going to be changing * it and don't try and do a texture compression */ qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data); } } if(r_speeds->integer){ end = ri.Milliseconds(); ri.Printf(PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start); } /* FIXME: HUGE hack */ if(glRefConfig.framebufferObject && !glState.currentFBO){ if(backEnd.framePostProcessed){ FBO_Bind(tr.screenScratchFbo); }else{ FBO_Bind(tr.renderFbo); } } RB_SetGL2D(); tess.numIndexes = 0; tess.numVertexes = 0; tess.firstIndex = 0; tess.xyz[tess.numVertexes][0] = x; tess.xyz[tess.numVertexes][1] = y; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = 0.5f / cols; tess.texCoords[tess.numVertexes][0][1] = 0.5f / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = x + w; tess.xyz[tess.numVertexes][1] = y; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = (cols - 0.5f) / cols; tess.texCoords[tess.numVertexes][0][1] = 0.5f / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = x + w; tess.xyz[tess.numVertexes][1] = y + h; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = (cols - 0.5f) / cols; tess.texCoords[tess.numVertexes][0][1] = (rows - 0.5f) / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = x; tess.xyz[tess.numVertexes][1] = y + h; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = 0.5f / cols; tess.texCoords[tess.numVertexes][0][1] = (rows - 0.5f) / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; /* FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function */ RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD); sp = &tr.textureColorShader; GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); GLSL_BindProgram(sp); GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); setv34(color, 1, 1, 1, 1); GLSL_SetUniformVec4(sp, TEXTURECOLOR_UNIFORM_COLOR, color); qglDrawElements(GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(0)); /* R_BindNullVBO(); * R_BindNullIBO(); */ tess.numIndexes = 0; tess.numVertexes = 0; tess.firstIndex = 0; }
/* ** RB_StageIteratorGeneric */ void RB_StageIteratorGeneric( void ) { shaderCommands_t *input; unsigned int vertexAttribs = 0; input = &tess; if (!input->numVertexes || !input->numIndexes) { return; } if (tess.useInternalVBO) { RB_DeformTessGeometry(); } vertexAttribs = RB_CalcShaderVertexAttribs( input ); if (tess.useInternalVBO) { RB_UpdateVBOs(vertexAttribs); } else { backEnd.pc.c_staticVboDraws++; } // // log this call // if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); } if ( qglPNTrianglesiATI && tess.ATI_tess ) { // RF< so we can send the normals as an array qglEnableClientState( GL_NORMAL_ARRAY ); qglEnable( GL_PN_TRIANGLES_ATI ); // ATI PN-Triangles extension } // // set face culling appropriately // if ((backEnd.viewParms.flags & VPF_DEPTHSHADOW)) { //GL_Cull( CT_TWO_SIDED ); if (input->shader->cullType == CT_TWO_SIDED) GL_Cull( CT_TWO_SIDED ); else if (input->shader->cullType == CT_FRONT_SIDED) GL_Cull( CT_BACK_SIDED ); else GL_Cull( CT_FRONT_SIDED ); } else GL_Cull( input->shader->cullType ); // set polygon offset if necessary if ( input->shader->polygonOffset ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } // // Set vertex attribs and pointers // GLSL_VertexAttribsState(vertexAttribs); // // render depth if in depthfill mode // if (backEnd.depthFill) { RB_IterateStagesGeneric( input ); // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } return; } // // render shadowmap if in shadowmap mode // if (backEnd.viewParms.flags & VPF_SHADOWMAP) { if ( input->shader->sort == SS_OPAQUE ) { RB_RenderShadowmap( input ); } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } return; } // // // call shader function // RB_IterateStagesGeneric( input ); // // pshadows! // if (glRefConfig.framebufferObject && r_shadows->integer == 4 && tess.pshadowBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { ProjectPshadowVBOGLSL(); } // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader && (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer) { ForwardDlight(); } else { ProjectDlightTexture(); } } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(0); } // // RTCW fog // may not match original RTCW fog, since that's done per stage // if ( r_wolffog->integer && tess.shader->fogPass && tess.shader->sort <= SS_OPAQUE ) { int stage, stageFog = 0; // make sure at least one stage has fog for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { shaderStage_t *pStage = tess.xstages[stage]; if ( !pStage ) { break; } if (pStage->isFogged) { stageFog = 1; break; } } // FIXME: this logic sucks if (tess.shader->noFog && stageFog) { RB_FogPass(1); } else if (tess.shader->noFog && !stageFog) { } else { RB_FogPass(1); } } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } // turn truform back off if ( qglPNTrianglesiATI && tess.ATI_tess ) { qglDisable( GL_PN_TRIANGLES_ATI ); // ATI PN-Triangles extension qglDisableClientState( GL_NORMAL_ARRAY ); } }