/* ================= R_Fog (void) ================= */ void RB_Fog( glfog_t *curfog ) { // static glfog_t setfog; GLimp_LogComment( "--- RB_Fog() ---\n" ); #if 0 if ( !r_wolfFog->integer ) { RB_FogOff(); return; } if ( !curfog->registered ) { //----(SA) RB_FogOff(); return; } //----(SA) assume values of '0' for these parameters means 'use default' if ( !curfog->density ) { curfog->density = 1; } if ( !curfog->hint ) { curfog->hint = GL_DONT_CARE; } if ( !curfog->mode ) { curfog->mode = GL_LINEAR; } //----(SA) end RB_FogOn(); // only send changes if necessary // if(curfog->mode != setfog.mode || !setfog.registered) { glFogi( GL_FOG_MODE, curfog->mode ); // setfog.mode = curfog->mode; // } // if(curfog->color[0] != setfog.color[0] || curfog->color[1] != setfog.color[1] || curfog->color[2] != setfog.color[2] || !setfog.registered) { glFogfv( GL_FOG_COLOR, curfog->color ); // VectorCopy(setfog.color, curfog->color); // } // if(curfog->density != setfog.density || !setfog.registered) { glFogf( GL_FOG_DENSITY, curfog->density ); // setfog.density = curfog->density; // } // if(curfog->hint != setfog.hint || !setfog.registered) { glHint( GL_FOG_HINT, curfog->hint ); // setfog.hint = curfog->hint; // } // if(curfog->start != setfog.start || !setfog.registered) { glFogf( GL_FOG_START, curfog->start ); // setfog.start = curfog->start; // } if ( r_zfar->value ) { // (SA) allow override for helping level designers test fog distances // if(setfog.end != r_zfar->value || !setfog.registered) { glFogf( GL_FOG_END, r_zfar->value ); // setfog.end = r_zfar->value; // } } else { // if(curfog->end != setfog.end || !setfog.registered) { glFogf( GL_FOG_END, curfog->end ); // setfog.end = curfog->end; // } } // TTimo - from SP NV fog code // NV fog mode if ( glConfig.NVFogAvailable ) { glFogi( GL_FOG_DISTANCE_MODE_NV, glConfig.NVFogMode ); } // end setfog.registered = qtrue; GL_ClearColor( curfog->color[ 0 ], curfog->color[ 1 ], curfog->color[ 2 ], curfog->color[ 3 ] ); #endif }
/* ================= RB_Fog ================= */ void RB_Fog( int fogNum ) { //static int lastFogMode = 0; //static vec3_t lastColor = { -1, -1, -1 }; //static float lastDensity = -1; //static int lastHint = -1; //static float lastStart = -1, lastEnd = -1; int fogMode; vec3_t color; float density; int hint; float start, end; if ( !r_useGlFog->integer ) { R_FogOff(); lastGlfogType = FT_NONE; return; } if ( R_IsGlobalFog( fogNum ) ) { lastGlfogType = backEnd.refdef.fogType; switch ( backEnd.refdef.fogType ) { case FT_LINEAR: fogMode = GL_LINEAR; break; case FT_EXP: fogMode = GL_EXP; break; default: R_FogOff(); lastGlfogType = FT_NONE; return; } VectorCopy( backEnd.refdef.fogColor, color ); end = backEnd.refdef.fogDepthForOpaque; density = backEnd.refdef.fogDensity; } else { fog_t *fog; fog = tr.world->fogs + fogNum; if ( !fog->shader ) { R_FogOff(); lastGlfogType = FT_NONE; return; } lastGlfogType = fog->shader->fogParms.fogType; switch ( fog->shader->fogParms.fogType ) { case FT_LINEAR: fogMode = GL_LINEAR; break; case FT_EXP: fogMode = GL_EXP; break; default: R_FogOff(); return; } VectorCopy( fog->shader->fogParms.color, color ); end = fog->shader->fogParms.depthForOpaque; density = fog->shader->fogParms.density; } hint = GL_DONT_CARE; start = 0; RB_FogOn(); // only send changes if necessary //if ( fogMode != lastFogMode ) { qglFogi( GL_FOG_MODE, fogMode ); // lastFogMode = fogMode; //} //if ( color[0] != lastColor[0] || color[1] != lastColor[1] || color[2] != lastColor[2] || !lastFogMode ) { qglFogfv( GL_FOG_COLOR, color ); // VectorCopy( lastColor, color ); //} //if ( density != lastDensity || !lastFogMode ) { qglFogf( GL_FOG_DENSITY, density ); // lastDensity = density; //} //if ( hint != lastHint || !lastFogMode ) { qglHint( GL_FOG_HINT, hint ); // lastHint = hint; //} //if ( start != lastStart || !lastFogMode ) { qglFogf( GL_FOG_START, start ); // lastStart = start; //} //if ( end != lastEnd || !lastFogMode ) { qglFogf( GL_FOG_END, end ); // lastEnd = end; //} #if 0 // ZTM: TODO: Add NVidia fog code? // TTimo - from SP NV fog code // NV fog mode if ( glConfig.NVFogAvailable ) { qglFogi( GL_FOG_DISTANCE_MODE_NV, glConfig.NVFogMode ); } // end #endif //qglClearColor( color[0], color[1], color[2], 1.0f ); }
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(); } } }
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_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; } } }