/* ** RB_StageIteratorVertexLitTexture */ void RB_StageIteratorVertexLitTexture( void ) { shaderCommands_t *input; shader_t *shader; input = &tess; shader = input->shader; // // compute colors // RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); // // 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_StageIteratorVertexLitTexturedUnfogged( %s ) ---\n", tess.shader->name) ); } // // set face culling appropriately // GL_Cull( shader->cullType ); // // set arrays and lock // qglEnableClientState( GL_COLOR_ARRAY); qglEnableClientState( GL_TEXTURE_COORD_ARRAY); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); qglVertexPointer (3, GL_FLOAT, 16, input->xyz); if ( qglLockArraysEXT ) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment( "glLockArraysEXT\n" ); } // // call special shade routine // R_BindAnimatedImage( &tess.xstages[0]->bundle[0] ); GL_State( tess.xstages[0]->stateBits ); R_DrawElements( input->numIndexes, input->indexes ); // // 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" ); } }
/* =================== DynamicLightPass() perform dynamic lighting with multiple rendering passes =================== */ static void DynamicLightPass(void) { int i, l, a, b, c, color, *intColors; vec3_t origin; byte *colors; glIndex_t hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float radius, radiusInverseCubed; float intensity, remainder, modulate; vec3_t floatColor, dir; dlight_t *dl; // early out if (backEnd.refdef.num_dlights == 0) { return; } // walk light list for (l = 0; l < backEnd.refdef.num_dlights; l++) { // early out if (!(tess.dlightBits & (1 << l))) { continue; } // clear colors Com_Memset(tess.svars.colors, 0, sizeof(tess.svars.colors)); // setup dl = &backEnd.refdef.dlights[l]; VectorCopy(dl->transformed, origin); radius = dl->radius; radiusInverseCubed = dl->radiusInverseCubed; intensity = dl->intensity; floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; // directional lights have max intensity and washout remainder intensity if (dl->flags & REF_DIRECTED_DLIGHT) { remainder = intensity * 0.125; } else { remainder = 0.0f; } // illuminate vertexes colors = tess.svars.colors[0]; for (i = 0; i < tess.numVertexes; i++, colors += 4) { backEnd.pc.c_dlightVertexes++; // directional dlight, origin is a directional normal if (dl->flags & REF_DIRECTED_DLIGHT) { // twosided surfaces use absolute value of the calculated lighting modulate = intensity * DotProduct(dl->origin, tess.normal[i].v); if (tess.shader->cullType == CT_TWO_SIDED) { modulate = fabs(modulate); } modulate += remainder; } // ball dlight else { dir[0] = radius - fabs(origin[0] - tess.xyz[i].v[0]); if (dir[0] <= 0.0f) { continue; } dir[1] = radius - fabs(origin[1] - tess.xyz[i].v[1]); if (dir[1] <= 0.0f) { continue; } dir[2] = radius - fabs(origin[2] - tess.xyz[i].v[2]); if (dir[2] <= 0.0f) { continue; } modulate = intensity * dir[0] * dir[1] * dir[2] * radiusInverseCubed; } // optimizations if (modulate < (1.0f / 128.0f)) { continue; } else if (modulate > 1.0f) { modulate = 1.0f; } // set color color = (int)(floatColor[0] * modulate); colors[0] = color > 255 ? 255 : color; color = (int)(floatColor[1] * modulate); colors[1] = color > 255 ? 255 : color; color = (int)(floatColor[2] * modulate); colors[2] = color > 255 ? 255 : color; } // build a list of triangles that need light intColors = (int *) tess.svars.colors; numIndexes = 0; for (i = 0; i < tess.numIndexes; i += 3) { a = tess.indexes[i]; b = tess.indexes[i + 1]; c = tess.indexes[i + 2]; if (!(intColors[a] | intColors[b] | intColors[c])) { continue; } hitIndexes[numIndexes++] = a; hitIndexes[numIndexes++] = b; hitIndexes[numIndexes++] = c; } if (numIndexes == 0) { continue; } // debug code (fixme, there's a bug in this function!) //for( i = 0; i < numIndexes; i++ ) // intColors[ hitIndexes[ i ] ] = 0x000000FF; qglEnableClientState(GL_COLOR_ARRAY); qglColorPointer(4, GL_UNSIGNED_BYTE, 0, tess.svars.colors); R_FogOff(); GL_Bind(tr.whiteImage); GL_State(GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL); R_DrawElements(numIndexes, hitIndexes); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; R_FogOn(); } }
/* ** RB_StageIteratorGeneric */ void RB_StageIteratorGeneric( void ) { shaderCommands_t *input; shader_t *shader; input = &tess; shader = input->shader; RB_DeformTessGeometry(); // // log this call // if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) ); } // // set face culling appropriately // GL_Cull( shader->cullType ); // set polygon offset if necessary if ( shader->polygonOffset ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } // // if there is only a single pass then we can enable color // and texture arrays before we compile, otherwise we need // to avoid compiling those arrays since they will change // during multipass rendering // if ( tess.numPasses > 1 || shader->multitextureEnv ) { setArraysOnce = qfalse; qglDisableClientState (GL_COLOR_ARRAY); qglDisableClientState (GL_TEXTURE_COORD_ARRAY); } else { setArraysOnce = qtrue; qglEnableClientState( GL_COLOR_ARRAY); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); } // // lock XYZ // qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD if (qglLockArraysEXT) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment( "glLockArraysEXT\n" ); } // // enable color and texcoord arrays after the lock if necessary // if ( !setArraysOnce ) { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglEnableClientState( GL_COLOR_ARRAY ); } // // call shader function // RB_IterateStagesGeneric( input ); // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { ProjectDlightTexture(); } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(); } // // unlock arrays // if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } // // reset polygon offset // if ( shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } }
/* ============= RB_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); }
/* =================== 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" ); } } }
static void ProjectDlightTexture_scalar( 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]; unsigned hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; vec3_t floatColor; float modulate = 0.0f; 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; if(r_greyscale->integer) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = floatColor[1] = floatColor[2] = luminance; } else if(r_greyscale->value) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); } else { 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 ) { int clip = 0; vec3_t dist; VectorSubtract( origin, tess.xyz[i], dist ); backEnd.pc.c_dlightVertexes++; texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[1] * scale; if( !r_dlightBacks->integer && // dist . tess.normal[i] ( dist[0] * tess.normal[i][0] + dist[1] * tess.normal[i][1] + dist[2] * tess.normal[i][2] ) < 0.0f ) { clip = 63; } else { 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; } texCoords[0] = texCoords[0]; texCoords[1] = texCoords[1]; // modulate the strength based on the height and color if ( dist[2] > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist[2] < -radius ) { clip |= 32; modulate = 0.0f; } else { dist[2] = Q_fabs(dist[2]); if ( dist[2] < radius * 0.5f ) { modulate = 1.0f; } else { modulate = 2.0f * (radius - dist[2]) * scale; } } } clipBits[i] = clip; colors[0] = ri.ftol(floatColor[0] * modulate); colors[1] = ri.ftol(floatColor[1] * modulate); colors[2] = ri.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; } 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 ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } }
/* ============= 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 ); }
static void ProjectDlightTexture_scalar( void ) { int i, l; vec3_t origin; float *texCoords; byte *colors; int *intColors; 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; float radiusInverseCubed; float intensity, remainder; vec3_t floatColor; float modulate = 0.0f; qboolean vertexLight; 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 } // clear colors Com_Memset( colorArray, 0, sizeof( colorArray ) ); texCoords = texCoordsArray[0]; colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; VectorCopy( dl->transformed, origin ); radius = dl->radius; scale = 1.0f / radius; radiusInverseCubed = dl->radiusInverseCubed; intensity = dl->intensity; vertexLight = ( ( dl->flags & REF_DIRECTED_DLIGHT ) || ( dl->flags & REF_VERTEX_DLIGHT ) ); // directional lights have max intensity and washout remainder intensity if ( dl->flags & REF_DIRECTED_DLIGHT ) { remainder = intensity * 0.125; } else { remainder = 0.0f; } if(r_greyscale->integer) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = floatColor[1] = floatColor[2] = luminance; } else if(r_greyscale->value) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); } else { 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 ) { int clip = 0; vec3_t dist; VectorSubtract( origin, tess.xyz[i], dist ); backEnd.pc.c_dlightVertexes++; // directional dlight, origin is a directional normal if ( dl->flags & REF_DIRECTED_DLIGHT ) { // twosided surfaces use absolute value of the calculated lighting modulate = intensity * DotProduct( dl->origin, tess.normal[ i ] ); if ( tess.shader->cullType == CT_TWO_SIDED ) { modulate = fabs( modulate ); } modulate += remainder; } // spherical vertex lit dlight else if ( dl->flags & REF_VERTEX_DLIGHT ) { vec3_t dir; dir[ 0 ] = radius - fabs( dist[ 0 ] ); if ( dir[ 0 ] <= 0.0f ) { continue; } dir[ 1 ] = radius - fabs( dist[ 1 ] ); if ( dir[ 1 ] <= 0.0f ) { continue; } dir[ 2 ] = radius - fabs( dist[ 2 ] ); if ( dir[ 2 ] <= 0.0f ) { continue; } modulate = intensity * dir[ 0 ] * dir[ 1 ] * dir[ 2 ] * radiusInverseCubed; } // vertical cylinder dlight else { texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[1] * scale; if( !r_dlightBacks->integer && // dist . tess.normal[i] ( dist[0] * tess.normal[i][0] + dist[1] * tess.normal[i][1] + dist[2] * tess.normal[i][2] ) < 0.0f ) { clip = 63; } else { 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; } texCoords[0] = texCoords[0]; texCoords[1] = texCoords[1]; // modulate the strength based on the height and color if ( dist[2] > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist[2] < -radius ) { clip |= 32; modulate = 0.0f; } else { dist[2] = Q_fabs(dist[2]); if ( dist[2] < radius * 0.5f ) { modulate = intensity; } else { modulate = intensity * 2.0f * (radius - dist[2]) * scale; } } } } // optimizations if ( vertexLight && modulate < ( 1.0f / 128.0f ) ) { continue; } else if ( modulate > 1.0f ) { modulate = 1.0f; } clipBits[i] = clip; colors[0] = Com_Clamp( 0, 255, ri.ftol(floatColor[0] * modulate) ); colors[1] = Com_Clamp( 0, 255, ri.ftol(floatColor[1] * modulate) ); colors[2] = Com_Clamp( 0, 255, ri.ftol(floatColor[2] * modulate) ); colors[3] = 255; } // build a list of triangles that need light intColors = (int*) colorArray; 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 ( vertexLight ) { if ( !( intColors[ a ] | intColors[ b ] | intColors[ c ] ) ) { continue; } } else { 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; } if ( !vertexLight ) { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); } else { qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); } qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); if ( dl->dlshader ) { shader_t *dls = dl->dlshader; for ( i = 0; i < dls->numUnfoggedPasses; i++ ) { shaderStage_t *stage = dls->stages[i]; R_BindAnimatedImage( &dls->stages[i]->bundle[0] ); GL_State( stage->stateBits | GLS_DEPTHFUNC_EQUAL ); R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } } else { R_FogOff(); if ( !vertexLight ) { GL_Bind( tr.dlightImage ); } else { GL_Bind( tr.whiteImage ); } // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->flags & REF_ADDITIVE_DLIGHT ) { 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 ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; RB_FogOn(); } } }
/* =================== RB_FogPass Blends a fog texture on top of everything else =================== */ static void RB_FogPass( void ) { fog_t *fog; unsigned colorInt; fogType_t fogType; int i; // no world, no fogging if ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) { return; } if ( r_useGlFog->integer ) { return; } if ( tess.shader->isSky ) { fogType = tr.skyFogType; colorInt = tr.skyFogColorInt; } else { fog = tr.world->fogs + tess.fogNum; // Global fog if ( fog->originalBrushNumber < 0 ) { fogType = backEnd.refdef.fogType; colorInt = backEnd.refdef.fogColorInt; } else { fogType = fog->shader->fogParms.fogType; colorInt = fog->colorInt; } } if ( fogType == FT_NONE ) { return; } // check if any stage is fogged if ( tess.shader->noFog ) { int i; for ( i = 0 ; i < MAX_SHADER_STAGES; i++ ) { shaderStage_t *pStage = tess.xstages[i]; if ( !pStage ) { return; } if ( pStage->isFogged ) { break; } } } 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] ); for ( i = 0; i < tess.numVertexes; i++ ) { * ( int * )&tess.svars.colors[i] = colorInt; } RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] ); if ( fogType == FT_LINEAR ) { GL_Bind( tr.linearFogImage ); } else { GL_Bind( tr.fogImage ); } if ( tess.shader->fogPass == FP_EQUAL ) { GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); } else { GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); } R_DrawElements( tess.numIndexes, tess.indexes ); }
/* ** RB_IterateStagesGeneric */ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { int stage; qboolean overridealpha = qfalse; int oldAlphaGen = AGEN_IDENTITY; int oldStateBits = 0; qboolean overridecolor = qfalse; int oldRgbGen = CGEN_IDENTITY; for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { shaderStage_t *pStage = tess.xstages[stage]; if ( !pStage ) { break; } // override the shader alpha channel if requested if ( backEnd.currentEntity && backEnd.currentEntity->e.renderfx & RF_FORCE_ENT_ALPHA ) { overridealpha = qtrue; oldAlphaGen = pStage->alphaGen; oldStateBits = pStage->stateBits; pStage->alphaGen = AGEN_ENTITY; // set bits for blendfunc blend pStage->stateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA; // keep the original alphafunc, if any pStage->stateBits |= ( oldStateBits & GLS_ATEST_BITS ); } else { overridealpha = qfalse; } // override the shader color channels if requested if ( backEnd.currentEntity && backEnd.currentEntity->e.renderfx & RF_RGB_TINT ) { overridecolor = qtrue; oldRgbGen = pStage->rgbGen; pStage->rgbGen = CGEN_ENTITY; } else { overridecolor = qfalse; } ComputeColors( pStage ); ComputeTexCoords( pStage ); if ( !setArraysOnce ) { qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors ); } // per stage fogging (detail textures) if ( !tess.shader->noFog || pStage->isFogged ) { RB_FogOn(); } else { R_FogOff(); } // // do multitexture // if ( pStage->bundle[1].image[0] != 0 ) { DrawMultitextured( input, stage ); } else { if ( !setArraysOnce ) { qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); } // // set state // R_BindAnimatedImage( &pStage->bundle[0] ); // Disable depth test for 2D drawing if ( backEnd.currentEntity == &backEnd.entity2D ) { GL_State( pStage->stateBits | GLS_DEPTHTEST_DISABLE ); } else { GL_State( pStage->stateBits ); } // // draw // R_DrawElements( input->numIndexes, input->indexes ); } if ( overridealpha ) { pStage->alphaGen = oldAlphaGen; pStage->stateBits = oldStateBits; } if ( overridecolor ) { pStage->rgbGen = oldRgbGen; } // allow skipping out to show just lightmaps during development if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) { break; } } }
static void ProjectDlightTexture_altivec( void ) { int i, l; vec_t origin0, origin1, origin2; float texCoords0, texCoords1; vector float floatColorVec0, floatColorVec1; vector float modulateVec, colorVec, zero; vector short colorShort; vector signed int colorInt; vector unsigned char floatColorVecPerm, modulatePerm, colorChar; vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff); float *texCoords; byte *colors; int *intColors; 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; float radiusInverseCubed; float intensity, remainder; vec3_t floatColor; float modulate = 0.0f; qboolean vertexLight; if ( !backEnd.refdef.num_dlights ) { return; } // There has to be a better way to do this so that floatColor // and/or modulate are already 16-byte aligned. floatColorVecPerm = vec_lvsl(0,(float *)floatColor); modulatePerm = vec_lvsl(0,(float *)&modulate); modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0); zero = (vector float)vec_splat_s8(0); 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 } // clear colors Com_Memset( colorArray, 0, sizeof( colorArray ) ); texCoords = texCoordsArray[0]; colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; origin0 = dl->transformed[0]; origin1 = dl->transformed[1]; origin2 = dl->transformed[2]; radius = dl->radius; scale = 1.0f / radius; radiusInverseCubed = dl->radiusInverseCubed; intensity = dl->intensity; vertexLight = ( ( dl->flags & REF_DIRECTED_DLIGHT ) || ( dl->flags & REF_VERTEX_DLIGHT ) ); // directional lights have max intensity and washout remainder intensity if ( dl->flags & REF_DIRECTED_DLIGHT ) { remainder = intensity * 0.125; } else { remainder = 0.0f; } if(r_greyscale->integer) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = floatColor[1] = floatColor[2] = luminance; } else if(r_greyscale->value) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); } else { floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; } floatColorVec0 = vec_ld(0, floatColor); floatColorVec1 = vec_ld(11, floatColor); floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { int clip = 0; vec_t dist0, dist1, dist2; dist0 = origin0 - tess.xyz[i][0]; dist1 = origin1 - tess.xyz[i][1]; dist2 = origin2 - tess.xyz[i][2]; backEnd.pc.c_dlightVertexes++; // directional dlight, origin is a directional normal if ( dl->flags & REF_DIRECTED_DLIGHT ) { // twosided surfaces use absolute value of the calculated lighting modulate = intensity * DotProduct( dl->origin, tess.normal[ i ] ); if ( tess.shader->cullType == CT_TWO_SIDED ) { modulate = fabs( modulate ); } modulate += remainder; } // spherical vertex lit dlight else if ( dl->flags & REF_VERTEX_DLIGHT ) { vec3_t dir; dir[ 0 ] = radius - fabs( dist0 ); if ( dir[ 0 ] <= 0.0f ) { continue; } dir[ 1 ] = radius - fabs( dist1 ); if ( dir[ 1 ] <= 0.0f ) { continue; } dir[ 2 ] = radius - fabs( dist2 ); if ( dir[ 2 ] <= 0.0f ) { continue; } modulate = intensity * dir[ 0 ] * dir[ 1 ] * dir[ 2 ] * radiusInverseCubed; } // vertical cylinder dlight else { texCoords0 = 0.5f + dist0 * scale; texCoords1 = 0.5f + dist1 * scale; if( !r_dlightBacks->integer && // dist . tess.normal[i] ( dist0 * tess.normal[i][0] + dist1 * tess.normal[i][1] + dist2 * tess.normal[i][2] ) < 0.0f ) { clip = 63; } else { if ( texCoords0 < 0.0f ) { clip |= 1; } else if ( texCoords0 > 1.0f ) { clip |= 2; } if ( texCoords1 < 0.0f ) { clip |= 4; } else if ( texCoords1 > 1.0f ) { clip |= 8; } texCoords[0] = texCoords0; texCoords[1] = texCoords1; // modulate the strength based on the height and color if ( dist2 > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist2 < -radius ) { clip |= 32; modulate = 0.0f; } else { dist2 = Q_fabs(dist2); if ( dist2 < radius * 0.5f ) { modulate = intensity; } else { modulate = intensity * 2.0f * (radius - dist2) * scale; } } } } clipBits[i] = clip; // optimizations if ( vertexLight && modulate < ( 1.0f / 128.0f ) ) { continue; } else if ( modulate > 1.0f ) { modulate = 1.0f; } // ZTM: FIXME: should probably clamp to 0-255 range before converting to char, // but I don't know how to do altvec stuff or if it's even used anymore modulateVec = vec_ld(0,(float *)&modulate); modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); colorVec = vec_madd(floatColorVec0,modulateVec,zero); colorInt = vec_cts(colorVec,0); // RGBx colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color } // build a list of triangles that need light intColors = (int*) colorArray; 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 ( vertexLight ) { if ( !( intColors[ a ] | intColors[ b ] | intColors[ c ] ) ) { continue; } } else { 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; } if ( !vertexLight ) { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); } else { qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); } qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); if ( dl->dlshader ) { shader_t *dls = dl->dlshader; for ( i = 0; i < dls->numUnfoggedPasses; i++ ) { shaderStage_t *stage = dls->stages[i]; R_BindAnimatedImage( &dls->stages[i]->bundle[0] ); GL_State( stage->stateBits | GLS_DEPTHFUNC_EQUAL ); R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } } else { R_FogOff(); if ( !vertexLight ) { GL_Bind( tr.dlightImage ); } else { GL_Bind( tr.whiteImage ); } // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered if ( dl->flags & REF_ADDITIVE_DLIGHT ) { 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 ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; RB_FogOn(); } } }
/* * 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); }
/* ** RB_IterateStagesGeneric */ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { int stage; #ifdef ELITEFORCE qboolean overridealpha; int oldalphaGen = 0; #endif for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { shaderStage_t *pStage = tess.xstages[stage]; if ( !pStage ) { break; } #ifdef ELITEFORCE // Override the shader alpha channel if requested. if(backEnd.currentEntity->e.renderfx & RF_FORCE_ENT_ALPHA) { overridealpha = qtrue; oldalphaGen = pStage->alphaGen; pStage->alphaGen = AGEN_ENTITY; } else overridealpha = qfalse; #endif ComputeColors( pStage ); #ifdef ELITEFORCE if(overridealpha) pStage->alphaGen = oldalphaGen; #endif ComputeTexCoords( pStage ); if ( !setArraysOnce ) { qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors ); } // // do multitexture // if ( pStage->bundle[1].image[0] != 0 ) { DrawMultitextured( input, stage ); } else { if ( !setArraysOnce ) { qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); } // // set state // R_BindAnimatedImage( &pStage->bundle[0] ); #ifdef ELITEFORCE if(overridealpha && backEnd.currentEntity->e.shaderRGBA[3] < 0xFF && !(pStage->stateBits & GLS_ATEST_BITS)) { // set bits for blendfunc blend GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); } else #endif GL_State( pStage->stateBits ); // // draw // R_DrawElements( input->numIndexes, input->indexes ); } // allow skipping out to show just lightmaps during development if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) { break; } } }
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; } }
void RB_StageIteratorLightmappedMultitexture( void ) { shaderCommands_t *input; shader_t *shader; input = &tess; 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 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, 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_StageIteratorGeneric */ void RB_StageIteratorGeneric( void ) { shaderCommands_t *input; input = &tess; RB_DeformTessGeometry(); // // log this call // if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va( "--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name ) ); } // set GL fog SetIteratorFog(); if ( qglPNTrianglesiATI && tess.ATI_tess ) { // RF< so we can send the normals as an array qglEnableClientState( GL_NORMAL_ARRAY ); #ifdef __MACOS__ //DAJ ATI qglPNTrianglesiATI( GL_PN_TRIANGLES_ATI, 1 ); #else qglEnable( GL_PN_TRIANGLES_ATI ); // ATI PN-Triangles extension #endif } // // set face culling appropriately // GL_Cull( input->shader->cullType ); // set polygon offset if necessary if ( input->shader->polygonOffset ) { qglEnable( GL_POLYGON_OFFSET_FILL ); qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); } // // if there is only a single pass then we can enable color // and texture arrays before we compile, otherwise we need // to avoid compiling those arrays since they will change // during multipass rendering // if ( tess.numPasses > 1 || input->shader->multitextureEnv ) { setArraysOnce = qfalse; qglDisableClientState( GL_COLOR_ARRAY ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); } else { setArraysOnce = qtrue; qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] ); } // RF, send normals only if required // This must be done first, since we can't change the arrays once they have been // locked if ( qglPNTrianglesiATI && tess.ATI_tess ) { qglNormalPointer( GL_FLOAT, 16, input->normal ); } // // lock XYZ // qglVertexPointer( 3, GL_FLOAT, 16, input->xyz ); // padded for SIMD if ( qglLockArraysEXT ) { qglLockArraysEXT( 0, input->numVertexes ); GLimp_LogComment( "glLockArraysEXT\n" ); } // // enable color and texcoord arrays after the lock if necessary // if ( !setArraysOnce ) { qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglEnableClientState( GL_COLOR_ARRAY ); } // // call shader function // RB_IterateStagesGeneric( input ); // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && !( tess.shader->surfaceFlags & ( SURF_NODLIGHT | SURF_SKY ) ) ) { ProjectDlightTexture(); } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(); } // // unlock arrays // if ( qglUnlockArraysEXT ) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } // // reset polygon offset // if ( input->shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } // turn truform back off if ( qglPNTrianglesiATI && tess.ATI_tess ) { #ifdef __MACOS__ //DAJ ATI qglPNTrianglesiATI( GL_PN_TRIANGLES_ATI, 0 ); #else qglDisable( GL_PN_TRIANGLES_ATI ); // ATI PN-Triangles extension #endif qglDisableClientState( GL_NORMAL_ARRAY ); } }
static void ProjectDlightTexture_altivec( void ) { int i, l; vec_t origin0, origin1, origin2; float texCoords0, texCoords1; vector float floatColorVec0, floatColorVec1; vector float modulateVec, colorVec, zero; vector short colorShort; vector signed int colorInt; vector unsigned char floatColorVecPerm, modulatePerm, colorChar; vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff); float *texCoords; byte *colors; byte clipBits[SHADER_MAX_VERTEXES]; float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; unsigned hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; vec3_t floatColor; float modulate = 0.0f; if ( !backEnd.refdef.num_dlights ) { return; } // There has to be a better way to do this so that floatColor // and/or modulate are already 16-byte aligned. floatColorVecPerm = vec_lvsl(0,(float *)floatColor); modulatePerm = vec_lvsl(0,(float *)&modulate); modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0); zero = (vector float)vec_splat_s8(0); 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]; origin0 = dl->transformed[0]; origin1 = dl->transformed[1]; origin2 = dl->transformed[2]; radius = dl->radius; scale = 1.0f / radius; if(r_greyscale->integer) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = floatColor[1] = floatColor[2] = luminance; } else if(r_greyscale->value) { float luminance; luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); } else { floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; } floatColorVec0 = vec_ld(0, floatColor); floatColorVec1 = vec_ld(11, floatColor); floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { int clip = 0; vec_t dist0, dist1, dist2; dist0 = origin0 - tess.xyz[i][0]; dist1 = origin1 - tess.xyz[i][1]; dist2 = origin2 - tess.xyz[i][2]; backEnd.pc.c_dlightVertexes++; texCoords0 = 0.5f + dist0 * scale; texCoords1 = 0.5f + dist1 * scale; if( !r_dlightBacks->integer && // dist . tess.normal[i] ( dist0 * tess.normal[i][0] + dist1 * tess.normal[i][1] + dist2 * tess.normal[i][2] ) < 0.0f ) { clip = 63; } else { if ( texCoords0 < 0.0f ) { clip |= 1; } else if ( texCoords0 > 1.0f ) { clip |= 2; } if ( texCoords1 < 0.0f ) { clip |= 4; } else if ( texCoords1 > 1.0f ) { clip |= 8; } texCoords[0] = texCoords0; texCoords[1] = texCoords1; // modulate the strength based on the height and color if ( dist2 > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist2 < -radius ) { clip |= 32; modulate = 0.0f; } else { dist2 = Q_fabs(dist2); if ( dist2 < radius * 0.5f ) { modulate = 1.0f; } else { modulate = 2.0f * (radius - dist2) * scale; } } } clipBits[i] = clip; modulateVec = vec_ld(0,(float *)&modulate); modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); colorVec = vec_madd(floatColorVec0,modulateVec,zero); colorInt = vec_cts(colorVec,0); // RGBx colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color } // 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; } 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 ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } }
/* =================== ProjectDlightTexture Perform dynamic lighting with another rendering pass =================== */ static void ProjectDlightTexture( void ) { int i, l; vec3_t origin; float *texCoords; byte *colors; byte clipBits[SHADER_MAX_VERTEXES]; MAC_STATIC float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; unsigned hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; vec3_t floatColor; if ( !backEnd.refdef.num_dlights ) { return; } if ( backEnd.refdef.rdflags & RDF_SNOOPERVIEW ) { // no dlights for snooper 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; if ( 0 ) { clipBits[i] = 255; // definately not dlighted continue; } VectorSubtract( origin, tess.xyz[i], dist ); // if(!r_dlightBacks->integer) { // vec3_t dir; // VectorNormalize2(dist, dir); // if( DotProduct( tess.normal[i], dir) < 0) { // clipBits[i] = 255; // not lighted (backface) // continue; // } // } backEnd.pc.c_dlightVertexes++; texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[1] * 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[2] > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist[2] < -radius ) { clip |= 32; modulate = 0.0f; } else { dist[2] = Q_fabs( dist[2] ); if ( dist[2] < radius * 0.5f ) { modulate = 1.0f; } else { modulate = 2.0f * ( radius - dist[2] ) * scale; } } clipBits[i] = clip; colors[0] = myftol( floatColor[0] * modulate ); colors[1] = myftol( floatColor[1] * modulate ); colors[2] = myftol( 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 } // if(!r_dlightBacks->integer) { // vec3_t dir; // VectorSubtract( origin, tess.xyz[a], dir ); // VectorNormalize(dir); // if( DotProduct( tess.normal[i], dir) < 0) { // continue; // not lighted (backface) // } // } hitIndexes[numIndexes] = a; hitIndexes[numIndexes + 1] = b; hitIndexes[numIndexes + 2] = c; numIndexes += 3; } if ( !numIndexes ) { continue; } qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); //----(SA) creating dlight shader to allow for special blends or alternate dlight texture { shader_t *dls = dl->dlshader; if ( dls ) { // if (!qglActiveTextureARB || dls->numUnfoggedPasses < 2) { for ( i = 0; i < dls->numUnfoggedPasses; i++ ) { shaderStage_t *stage = dls->stages[i]; R_BindAnimatedImage( &dls->stages[i]->bundle[0] ); GL_State( stage->stateBits | GLS_DEPTHFUNC_EQUAL ); R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } /* } else { // optimize for multitexture for(i=0;i<dls->numUnfoggedPasses;) { shaderStage_t *stage = dls->stages[i]; GL_State(stage->stateBits | GLS_DEPTHFUNC_EQUAL); // setup each TMU for (tmu=0; tmu<glConfig.maxActiveTextures && i<dls->numUnfoggedPasses; tmu++, i++) { GL_SelectTexture( tmu ); if (tmu) { qglEnable( GL_TEXTURE_2D ); } R_BindAnimatedImage( &dls->stages[i]->bundle[0] ); } // draw the elements R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } // turn off unused TMU's for (tmu=1; tmu<glConfig.maxActiveTextures; tmu++) { // set back to default state GL_SelectTexture( tmu ); qglDisable( GL_TEXTURE_2D ); } // return to TEXTURE0 GL_SelectTexture( 0 ); } */ } else { R_FogOff(); // if (!dl->overdraw || !qglActiveTextureARB) { GL_Bind( tr.dlightImage ); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; // Ridah, overdraw lights several times, rather than sending // multiple lights through for ( i = 0; i < dl->overdraw; i++ ) { R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } /* } else { // optimize for multitexture GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); // setup each TMU (use all available TMU's) for (tmu=0; tmu<glConfig.maxActiveTextures && tmu<(dl->overdraw+1); tmu++) { GL_SelectTexture( tmu ); if (tmu) { qglEnable( GL_TEXTURE_2D ); GL_TexEnv( GL_ADD ); GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); 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 ); } // draw each bundle for(i=0; i<(dl->overdraw+1); i+=glConfig.maxActiveTextures) { // make sure we dont draw with too many TMU's if (i+glConfig.maxActiveTextures>(dl->overdraw+1)) { for (tmu=0; tmu<glConfig.maxActiveTextures; tmu++) { if (tmu+i>=(dl->overdraw+1)) { GL_SelectTexture( tmu ); qglDisable( GL_TEXTURE_2D ); } } } // draw the elements R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } // turn off unused TMU's for (tmu=1; tmu<glConfig.maxActiveTextures; tmu++) { // set back to default state GL_SelectTexture( tmu ); qglDisable( GL_TEXTURE_2D ); } // return to TEXTURE0 GL_SelectTexture( 0 ); } */ R_FogOn(); } } } }
void CQuickSpriteSystem::Flush(void) { if (mNextVert==0) { return; } /* if (mUseFog && r_drawfog->integer == 2 && mFogIndex == tr.world->globalFog) { //enable hardware fog when we draw this thing if applicable -rww fog_t *fog = tr.world->fogs + mFogIndex; #ifdef _XBOX qglFogi(GL_FOG_MODE, GL_EXP2); #else qglFogf(GL_FOG_MODE, GL_EXP2); #endif qglFogf(GL_FOG_DENSITY, logtestExp2 / fog->parms.depthForOpaque); qglFogfv(GL_FOG_COLOR, fog->parms.color); qglEnable(GL_FOG); } */ //this should not be needed, since I just wait to disable fog for the surface til after surface sprites are done // // render the main pass // R_BindAnimatedImage( mTexBundle ); GL_State(mGLStateBits); // // set arrays and lock // qglEnableClientState( GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer( 2, GL_FLOAT, 0, mTextureCoords ); qglEnableClientState( GL_COLOR_ARRAY); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColors ); qglVertexPointer (3, GL_FLOAT, 16, mVerts); if ( qglLockArraysEXT ) { qglLockArraysEXT(0, mNextVert); GLimp_LogComment( "glLockArraysEXT\n" ); } qglDrawArrays(GL_QUADS, 0, mNextVert); backEnd.pc.c_vertexes += mNextVert; backEnd.pc.c_indexes += mNextVert; backEnd.pc.c_totalIndexes += mNextVert; //only for software fog pass (global soft/volumetric) -rww if (mUseFog && (r_drawfog->integer != 2 || mFogIndex != tr.world->globalFog)) { fog_t *fog = tr.world->fogs + mFogIndex; // // render the fog pass // GL_Bind( tr.fogImage ); GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); // // set arrays and lock // qglTexCoordPointer( 2, GL_FLOAT, 0, mFogTextureCoords); // qglEnableClientState( GL_TEXTURE_COORD_ARRAY); // Done above qglDisableClientState( GL_COLOR_ARRAY ); qglColor4ubv((GLubyte *)&fog->colorInt); // qglVertexPointer (3, GL_FLOAT, 16, mVerts); // Done above qglDrawArrays(GL_QUADS, 0, mNextVert); // Second pass from fog backEnd.pc.c_totalIndexes += mNextVert; } // // unlock arrays // if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } mNextVert=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); }
/** * Draws simple colored rectangle with given parameters. */ void Gui_DrawRect(const GLfloat &x, const GLfloat &y, const GLfloat &width, const GLfloat &height, const float colorUpperLeft[], const float colorUpperRight[], const float colorLowerLeft[], const float colorLowerRight[], const int &blendMode, const GLuint texture) { switch(blendMode) { case BM_HIDE: return; case BM_MULTIPLY: qglBlendFunc(GL_SRC_ALPHA, GL_ONE); break; case BM_SIMPLE_SHADE: qglBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; case BM_SCREEN: qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; default: case BM_OPAQUE: qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; }; GLfloat x0 = x; GLfloat y0 = y + height; GLfloat x1 = x + width; GLfloat y1 = y; GLfloat *v, rectArray[32]; v = rectArray; *v++ = x0; *v++ = y0; *v++ = 0.0f; *v++ = 0.0f; vec4_copy(v, colorUpperLeft); v += 4; *v++ = x1; *v++ = y0; *v++ = 1.0f; *v++ = 0.0f; vec4_copy(v, colorUpperRight); v += 4; *v++ = x1; *v++ = y1; *v++ = 1.0f; *v++ = 1.0f; vec4_copy(v, colorLowerRight); v += 4; *v++ = x0; *v++ = y1; *v++ = 0.0f; *v++ = 1.0f; vec4_copy(v, colorLowerLeft); if(qglIsTexture(texture)) { qglBindTexture(GL_TEXTURE_2D, texture); } else { BindWhiteTexture(); } qglBindBufferARB(GL_ARRAY_BUFFER, rectBuffer); qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), rectArray, GL_DYNAMIC_DRAW); qglVertexPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)0); qglTexCoordPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[2])); qglColorPointer(4, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[4])); qglDrawArrays(GL_TRIANGLE_FAN, 0, 4); }
/* =================== 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"); } }
/* ** RB_IterateStagesGeneric */ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { int stage; for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) { shaderStage_t *pStage = tess.xstages[stage]; if ( !pStage ) { break; } ComputeColors( pStage ); ComputeTexCoords( pStage ); if ( !setArraysOnce ) { qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors ); } // // do multitexture // if ( pStage->bundle[1].image[0] != 0 ) { DrawMultitextured( input, stage ); } else { int fadeStart, fadeEnd; if ( !setArraysOnce ) { qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); } // // set state // 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] ); } // Ridah, per stage fogging (detail textures) 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. //----(SA) fading model stuff fadeStart = backEnd.currentEntity->e.fadeStartTime; if ( fadeStart ) { fadeEnd = backEnd.currentEntity->e.fadeEndTime; if ( fadeStart > tr.refdef.time ) { // has not started to fade yet GL_State( pStage->stateBits ); } else { int i; unsigned int tempState; float alphaval; if ( fadeEnd < tr.refdef.time ) { // entity faded out completely continue; } alphaval = (float)( fadeEnd - tr.refdef.time ) / (float)( fadeEnd - fadeStart ); tempState = pStage->stateBits; // remove the current blend, and don't write to Z buffer tempState &= ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_DEPTHMASK_TRUE ); // set the blend to src_alpha, dst_one_minus_src_alpha tempState |= ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_State( tempState ); GL_Cull( CT_FRONT_SIDED ); // modulate the alpha component of each vertex in the render list for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] *= alphaval; tess.svars.colors[i][1] *= alphaval; tess.svars.colors[i][2] *= alphaval; tess.svars.colors[i][3] *= alphaval; } } } else { GL_State( pStage->stateBits ); } //----(SA) end // // draw // R_DrawElements( input->numIndexes, input->indexes ); } // 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; } } }
static void RB_IterateStagesGeneric( shaderCommands_t *input ) { int stage; bool UseGLFog = false; bool FogColorChange = false; fog_t *fog = NULL; if (tess.fogNum && tess.shader->fogPass && (tess.fogNum == tr.world->globalFog || tess.fogNum == tr.world->numfogs) && r_drawfog->value == 2) { // only gl fog global fog and the "special fog" fog = tr.world->fogs + tess.fogNum; if (tr.rangedFog) { //ranged fog, used for sniper scope float fStart = fog->parms.depthForOpaque; if (tr.rangedFog < 0.0f) { //special designer override fStart = -tr.rangedFog; } else { //the greater tr.rangedFog is, the more fog we will get between the view point and cull distance if ((tr.distanceCull-fStart) < tr.rangedFog) { //assure a minimum range between fog beginning and cutoff distance fStart = tr.distanceCull-tr.rangedFog; if (fStart < 16.0f) { fStart = 16.0f; } } } qglFogi(GL_FOG_MODE, GL_LINEAR); qglFogf(GL_FOG_START, fStart); qglFogf(GL_FOG_END, tr.distanceCull); } else { qglFogi(GL_FOG_MODE, GL_EXP2); qglFogf(GL_FOG_DENSITY, logtestExp2 / fog->parms.depthForOpaque); } if ( g_bRenderGlowingObjects ) { const float fogColor[3] = { 0.0f, 0.0f, 0.0f }; qglFogfv(GL_FOG_COLOR, fogColor ); } else { qglFogfv(GL_FOG_COLOR, fog->parms.color); } qglEnable(GL_FOG); UseGLFog = true; } for ( stage = 0; stage < input->shader->numUnfoggedPasses; stage++ ) { shaderStage_t *pStage = &tess.xstages[stage]; int forceRGBGen = 0; int stateBits = 0; if ( !pStage->active ) { break; } // Reject this stage if it's not a glow stage but we are doing a glow pass. if ( g_bRenderGlowingObjects && !pStage->glow ) { continue; } if ( stage && r_lightmap->integer && !( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) ) { break; } stateBits = pStage->stateBits; if ( backEnd.currentEntity ) { assert(backEnd.currentEntity->e.renderfx >= 0); if ( backEnd.currentEntity->e.renderfx & RF_DISINTEGRATE1 ) { // we want to be able to rip a hole in the thing being disintegrated, and by doing the depth-testing it avoids some kinds of artefacts, but will probably introduce others? stateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK_TRUE | GLS_ATEST_GE_C0; } if ( backEnd.currentEntity->e.renderfx & RF_RGB_TINT ) {//want to use RGBGen from ent forceRGBGen = CGEN_ENTITY; } } if (pStage->ss && pStage->ss->surfaceSpriteType) { // We check for surfacesprites AFTER drawing everything else continue; } if (UseGLFog) { if (pStage->mGLFogColorOverride) { qglFogfv(GL_FOG_COLOR, GLFogOverrideColors[pStage->mGLFogColorOverride]); FogColorChange = true; } else if (FogColorChange && fog) { FogColorChange = false; qglFogfv(GL_FOG_COLOR, fog->parms.color); } } if (!input->fading) { //this means ignore this, while we do a fade-out ComputeColors( pStage, forceRGBGen ); } ComputeTexCoords( pStage ); if ( !setArraysOnce ) { qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors ); } // // do multitexture // if ( pStage->bundle[1].image != 0 ) { DrawMultitextured( input, stage ); } else { static bool lStencilled = false; if ( !setArraysOnce ) { qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); } // // set state // if ( (tess.shader == tr.distortionShader) || (backEnd.currentEntity && (backEnd.currentEntity->e.renderfx & RF_DISTORTION)) ) { //special distortion effect -rww //tr.screenImage should have been set for this specific entity before we got in here. GL_Bind( tr.screenImage ); GL_Cull(CT_TWO_SIDED); } else if ( pStage->bundle[0].vertexLightmap && ( r_vertexLight->integer && !r_uiFullScreen->integer ) && r_lightmap->integer ) { GL_Bind( tr.whiteImage ); } else R_BindAnimatedImage( &pStage->bundle[0] ); if (tess.shader == tr.distortionShader && glConfig.stencilBits >= 4) { //draw it to the stencil buffer! tr_stencilled = true; lStencilled = true; qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF); qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); //don't depthmask, don't blend.. don't do anything GL_State(0); } else if (backEnd.currentEntity && (backEnd.currentEntity->e.renderfx & RF_FORCE_ENT_ALPHA)) { ForceAlpha((unsigned char *) tess.svars.colors, backEnd.currentEntity->e.shaderRGBA[3]); if (backEnd.currentEntity->e.renderfx & RF_ALPHA_DEPTH) { //depth write, so faces through the model will be stomped over by nearer ones. this works because //we draw RF_FORCE_ENT_ALPHA stuff after everything else, including standard alpha surfs. GL_State(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK_TRUE); } else { GL_State(GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); } } else { GL_State( stateBits ); } // // draw // R_DrawElements( input->numIndexes, input->indexes ); if (lStencilled) { //re-enable the color buffer, disable stencil test lStencilled = false; qglDisable(GL_STENCIL_TEST); qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } } } if (FogColorChange) { qglFogfv(GL_FOG_COLOR, fog->parms.color); } }