/* ================== RB_RenderFlare ================== */ void RB_RenderFlare( flare_t *f ) { float size; vec3_t color; int iColor[3]; float distance, intensity, factor; byte fogFactors[3] = {255, 255, 255}; backEnd.pc.c_flareRenders++; // We don't want too big values anyways when dividing by distance. if(f->eyeZ > -1.0f) distance = 1.0f; else distance = -f->eyeZ; // calculate the flare size.. size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance ); /* * This is an alternative to intensity scaling. It changes the size of the flare on screen instead * with growing distance. See in the description at the top why this is not the way to go. // size will change ~ 1/r. size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f)); */ /* * As flare sizes stay nearly constant with increasing distance we must decrease the intensity * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be * got by considering the ratio of * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) * An important requirement is: * intensity <= 1 for all distances. * * The formula used here to compute the intensity is as follows: * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2 * As you can see, the intensity will have a max. of 1 when the distance is 0. * The coefficient flareCoeff will determine the falloff speed with increasing distance. */ factor = distance + size * sqrt(flareCoeff); intensity = flareCoeff * size * size / (factor * factor); VectorScale(f->color, f->drawIntensity * intensity, color); // Calculations for fogging if(tr.world && f->fogNum < tr.world->numfogs) { tess.numVertexes = 1; VectorCopy(f->origin, tess.xyz[0]); tess.fogNum = f->fogNum; RB_CalcModulateColorsByFog(fogFactors); // We don't need to render the flare if colors are 0 anyways. if(!(fogFactors[0] || fogFactors[1] || fogFactors[2])) return; } iColor[0] = color[0] * fogFactors[0]; iColor[1] = color[1] * fogFactors[1]; iColor[2] = color[2] * fogFactors[2]; RB_BeginSurface( tr.flareShader, f->fogNum ); // FIXME: use quadstamp? tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 1; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); }
/* ================== RB_RenderFlare ================== */ void RB_RenderFlare( flare_t *f ) { float size; vec3_t color; int iColor[3]; int iAlpha, srcBlend; float distance, intensity, factor; byte fogFactors[3] = {255, 255, 255}; backEnd.pc.c_flareRenders++; // We don't want too big values anyways when dividing by distance. if(f->eyeZ > -1.0f) distance = 1.0f; else distance = -f->eyeZ; // calculate the flare size.. size = backEnd.viewParms.viewportWidth * ( ( r_flareSize->value * f->scale )/640.0f + 8 / distance ); /* * This is an alternative to intensity scaling. It changes the size of the flare on screen instead * with growing distance. See in the description at the top why this is not the way to go. // size will change ~ 1/r. size = backEnd.viewParms.viewportWidth * ( ( r_flareSize->value * f->scale ) / (distance * -2.0f)); */ /* * As flare sizes stay nearly constant with increasing distance we must decrease the intensity * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be * got by considering the ratio of * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) * An important requirement is: * intensity <= 1 for all distances. * * The formula used here to compute the intensity is as follows: * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2 * As you can see, the intensity will have a max. of 1 when the distance is 0. * The coefficient flareCoeff will determine the falloff speed with increasing distance. */ factor = distance + size * sqrt(flareCoeff); intensity = flareCoeff * size * size / (factor * factor); // Calculations for RGBA srcBlend = f->shader->stages[0] ? ( f->shader->stages[0]->stateBits & GLS_SRCBLEND_BITS ) : 0; if ( srcBlend == GLS_SRCBLEND_ONE ) { // Q3 flare, fade color. blendfunc GL_ONE GL_ONE VectorScale(f->color, f->drawIntensity * intensity, color); iAlpha = 65535; } else { // RTCW/ET flare, fade alpha. blendfunc GL_SRC_ALPHA GL_ONE // Note: RTCW source says it uses alpha blend/fade because overwise it doesn't blend in global fog and to switch back when it's fixed. VectorScale(f->color, intensity, color); iAlpha = f->drawIntensity * 255 * 257; } // Calculations for fogging if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs && !f->shader->noFog) { tess.numVertexes = 1; VectorCopy(f->origin, tess.xyz[0]); tess.fogNum = f->fogNum; RB_CalcModulateColorsByFog(fogFactors); // We don't need to render the flare if colors are 0 anyways. if(!(fogFactors[0] || fogFactors[1] || fogFactors[2])) return; } iColor[0] = color[0] * fogFactors[0] * 257; iColor[1] = color[1] * fogFactors[1] * 257; iColor[2] = color[2] * fogFactors[2] * 257; // fog calculation already done, use fogNum 0 RB_BeginSurface( f->shader, 0, 0 ); // FIXME: use quadstamp? tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.color[tess.numVertexes][0] = iColor[0]; tess.color[tess.numVertexes][1] = iColor[1]; tess.color[tess.numVertexes][2] = iColor[2]; tess.color[tess.numVertexes][3] = iAlpha; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1; tess.color[tess.numVertexes][0] = iColor[0]; tess.color[tess.numVertexes][1] = iColor[1]; tess.color[tess.numVertexes][2] = iColor[2]; tess.color[tess.numVertexes][3] = iAlpha; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 1; tess.color[tess.numVertexes][0] = iColor[0]; tess.color[tess.numVertexes][1] = iColor[1]; tess.color[tess.numVertexes][2] = iColor[2]; tess.color[tess.numVertexes][3] = iAlpha; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 1; tess.texCoords[tess.numVertexes][0][1] = 0; tess.color[tess.numVertexes][0] = iColor[0]; tess.color[tess.numVertexes][1] = iColor[1]; tess.color[tess.numVertexes][2] = iColor[2]; tess.color[tess.numVertexes][3] = iAlpha; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; RB_EndSurface(); }
/* =============== ComputeColors =============== */ static void ComputeColors( shaderStage_t *pStage ) { int i; // // rgbGen // switch ( pStage->rgbGen ) { case CGEN_IDENTITY: Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 ); break; default: case CGEN_IDENTITY_LIGHTING: Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 ); break; case CGEN_LIGHTING_DIFFUSE: RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); break; case CGEN_EXACT_VERTEX: Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); break; case CGEN_CONST: for ( i = 0; i < tess.numVertexes; i++ ) { *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor; } break; case CGEN_VERTEX: if ( tr.identityLight == 1 ) { Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); } else { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight; tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight; tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight; tess.svars.colors[i][3] = tess.vertexColors[i][3]; } } break; case CGEN_ONE_MINUS_VERTEX: if ( tr.identityLight == 1 ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0]; tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1]; tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2]; } } else { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight; tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight; tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight; } } break; case CGEN_FOG: { fog_t *fog; fog = tr.world->fogs + tess.fogNum; for ( i = 0; i < tess.numVertexes; i++ ) { * ( int * )&tess.svars.colors[i] = fog->colorInt; } } break; case CGEN_WAVEFORM: RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors ); break; case CGEN_ENTITY: RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors ); break; case CGEN_ONE_MINUS_ENTITY: RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; } // // alphaGen // switch ( pStage->alphaGen ) { case AGEN_SKIP: break; case AGEN_IDENTITY: if ( pStage->rgbGen != CGEN_IDENTITY ) { if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) || pStage->rgbGen != CGEN_VERTEX ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = 0xff; } } } break; case AGEN_CONST: if ( pStage->rgbGen != CGEN_CONST ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = pStage->constantColor[3]; } } break; case AGEN_WAVEFORM: RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors ); break; case AGEN_LIGHTING_SPECULAR: RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors ); break; case AGEN_ENTITY: RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors ); break; case AGEN_ONE_MINUS_ENTITY: RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; case AGEN_VERTEX: if ( pStage->rgbGen != CGEN_VERTEX ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = tess.vertexColors[i][3]; } } break; case AGEN_ONE_MINUS_VERTEX: for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3]; } break; case AGEN_PORTAL: { unsigned char alpha; for ( i = 0; i < tess.numVertexes; i++ ) { float len; vec3_t v; VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v ); len = VectorLength( v ); len /= tess.shader->portalRange; if ( len < 0 ) { alpha = 0; } else if ( len > 1 ) { alpha = 0xff; } else { alpha = len * 0xff; } tess.svars.colors[i][3] = alpha; } } break; } // // fog adjustment for colors to fade out as fog increases // if ( tess.fogNum ) { switch ( pStage->adjustColorsForFog ) { case ACFF_MODULATE_RGB: RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_MODULATE_ALPHA: RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_MODULATE_RGBA: RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_NONE: break; } } // if in greyscale rendering mode turn all color values into greyscale. if(r_greyscale->integer) { int scale; for(i = 0; i < tess.numVertexes; i++) { scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale; } } else if(r_greyscale->value) { float scale; for(i = 0; i < tess.numVertexes; i++) { scale = LUMA(tess.svars.colors[i][0], tess.svars.colors[i][1], tess.svars.colors[i][2]); tess.svars.colors[i][0] = LERP(tess.svars.colors[i][0], scale, r_greyscale->value); tess.svars.colors[i][1] = LERP(tess.svars.colors[i][1], scale, r_greyscale->value); tess.svars.colors[i][2] = LERP(tess.svars.colors[i][2], scale, r_greyscale->value); } } }
/* =============== ComputeColors =============== */ static void ComputeColors( shaderStage_t *pStage ) { int i; // // rgbGen // switch ( pStage->rgbGen ) { case CGEN_IDENTITY: memset( tess.svars.colors, 0xff, tess.numVertexes * 4 ); break; default: case CGEN_IDENTITY_LIGHTING: memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 ); break; case CGEN_LIGHTING_DIFFUSE: RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); break; case CGEN_EXACT_VERTEX: memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0].v ) ); break; case CGEN_CONST: for ( i = 0; i < tess.numVertexes; i++ ) { *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor; } break; case CGEN_VERTEX: if ( tr.identityLight == 1 ) { memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0].v ) ); } else { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = tess.vertexColors[i].v[0] * tr.identityLight; tess.svars.colors[i][1] = tess.vertexColors[i].v[1] * tr.identityLight; tess.svars.colors[i][2] = tess.vertexColors[i].v[2] * tr.identityLight; tess.svars.colors[i][3] = tess.vertexColors[i].v[3]; } } break; case CGEN_ONE_MINUS_VERTEX: if ( tr.identityLight == 1 ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = 255 - tess.vertexColors[i].v[0]; tess.svars.colors[i][1] = 255 - tess.vertexColors[i].v[1]; tess.svars.colors[i][2] = 255 - tess.vertexColors[i].v[2]; } } else { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i].v[0] ) * tr.identityLight; tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i].v[1] ) * tr.identityLight; tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i].v[2] ) * tr.identityLight; } } break; case CGEN_FOG: { fog_t *fog; fog = tr.world->fogs + tess.fogNum; for ( i = 0; i < tess.numVertexes; i++ ) { *( int * )&tess.svars.colors[i] = fog->shader->fogParms.colorInt; } } break; case CGEN_WAVEFORM: RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors ); break; case CGEN_ENTITY: RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors ); break; case CGEN_ONE_MINUS_ENTITY: RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; } // // alphaGen // switch ( pStage->alphaGen ) { case AGEN_SKIP: break; case AGEN_IDENTITY: if ( pStage->rgbGen != CGEN_IDENTITY ) { if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) || pStage->rgbGen != CGEN_VERTEX ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = 0xff; } } } break; case AGEN_CONST: if ( pStage->rgbGen != CGEN_CONST ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = pStage->constantColor[3]; } } break; case AGEN_WAVEFORM: RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors ); break; case AGEN_LIGHTING_SPECULAR: RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors ); break; case AGEN_ENTITY: RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors ); break; case AGEN_ONE_MINUS_ENTITY: RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; // Ridah case AGEN_NORMALZFADE: { float alpha, range, lowest, highest, dot; vec3_t worldUp; qboolean zombieEffect = qfalse; if ( VectorCompare( backEnd.currentEntity->e.fireRiseDir, vec3_origin ) ) { VectorSet( backEnd.currentEntity->e.fireRiseDir, 0, 0, 1 ); } if ( backEnd.currentEntity->e.hModel ) { // world surfaces dont have an axis VectorRotate( backEnd.currentEntity->e.fireRiseDir, backEnd.currentEntity->e.axis, worldUp ); } else { VectorCopy( backEnd.currentEntity->e.fireRiseDir, worldUp ); } lowest = pStage->zFadeBounds[0]; if ( lowest == -1000 ) { // use entity alpha lowest = backEnd.currentEntity->e.shaderTime; zombieEffect = qtrue; } highest = pStage->zFadeBounds[1]; if ( highest == -1000 ) { // use entity alpha highest = backEnd.currentEntity->e.shaderTime; zombieEffect = qtrue; } range = highest - lowest; for ( i = 0; i < tess.numVertexes; i++ ) { dot = DotProduct( tess.normal[i].v, worldUp ); // special handling for Zombie fade effect if ( zombieEffect ) { alpha = (float)backEnd.currentEntity->e.shaderRGBA[3] * ( dot + 1.0 ) / 2.0; alpha += ( 2.0 * (float)backEnd.currentEntity->e.shaderRGBA[3] ) * ( 1.0 - ( dot + 1.0 ) / 2.0 ); if ( alpha > 255.0 ) { alpha = 255.0; } else if ( alpha < 0.0 ) { alpha = 0.0; } tess.svars.colors[i][3] = (byte)( alpha ); continue; } if ( dot < highest ) { if ( dot > lowest ) { if ( dot < lowest + range / 2 ) { alpha = ( (float)pStage->constantColor[3] * ( ( dot - lowest ) / ( range / 2 ) ) ); } else { alpha = ( (float)pStage->constantColor[3] * ( 1.0 - ( ( dot - lowest - range / 2 ) / ( range / 2 ) ) ) ); } if ( alpha > 255.0 ) { alpha = 255.0; } else if ( alpha < 0.0 ) { alpha = 0.0; } // finally, scale according to the entity's alpha if ( backEnd.currentEntity->e.hModel ) { alpha *= (float)backEnd.currentEntity->e.shaderRGBA[3] / 255.0; } tess.svars.colors[i][3] = (byte)( alpha ); } else { tess.svars.colors[i][3] = 0; } } else { tess.svars.colors[i][3] = 0; } } } break; // done. case AGEN_VERTEX: if ( pStage->rgbGen != CGEN_VERTEX ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = tess.vertexColors[i].v[3]; } } break; case AGEN_ONE_MINUS_VERTEX: for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = 255 - tess.vertexColors[i].v[3]; } break; case AGEN_PORTAL: { unsigned char alpha; for ( i = 0; i < tess.numVertexes; i++ ) { float len; vec3_t v; VectorSubtract( tess.xyz[i].v, backEnd.viewParms.orientation.origin, v ); len = VectorLength( v ); len /= tess.shader->portalRange; if ( len < 0 ) { alpha = 0; } else if ( len > 1 ) { alpha = 0xff; } else { alpha = len * 0xff; } tess.svars.colors[i][3] = alpha; } } break; } // // fog adjustment for colors to fade out as fog increases // if ( tess.fogNum && !tess.shader->noFog ) { switch ( pStage->adjustColorsForFog ) { case ACFF_MODULATE_RGB: RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_MODULATE_ALPHA: RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_MODULATE_RGBA: RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_NONE: break; } } }
static void ComputeColors( shaderStage_t *pStage, int forceRGBGen ) { int i; color4ub_t *colors = tess.svars.colors; qboolean killGen = qfalse; alphaGen_t forceAlphaGen = pStage->alphaGen;//set this up so we can override below if ( tess.shader != tr.projectionShadowShader && tess.shader != tr.shadowShader && ( backEnd.currentEntity->e.renderfx & (RF_DISINTEGRATE1|RF_DISINTEGRATE2))) { RB_CalcDisintegrateColors( (unsigned char *)tess.svars.colors ); RB_CalcDisintegrateVertDeform(); // We've done some custom alpha and color stuff, so we can skip the rest. Let it do fog though killGen = qtrue; } // // rgbGen // if ( !forceRGBGen ) { forceRGBGen = pStage->rgbGen; } if ( backEnd.currentEntity->e.renderfx & RF_VOLUMETRIC ) // does not work for rotated models, technically, this should also be a CGEN type, but that would entail adding new shader commands....which is too much work for one thing { int i; float *normal, dot; unsigned char *color; int numVertexes; normal = tess.normal[0]; color = tess.svars.colors[0]; numVertexes = tess.numVertexes; for ( i = 0 ; i < numVertexes ; i++, normal += 4, color += 4) { dot = DotProduct( normal, backEnd.refdef.viewaxis[0] ); dot *= dot * dot * dot; if ( dot < 0.2f ) // so low, so just clamp it { dot = 0.0f; } color[0] = color[1] = color[2] = color[3] = Q_ftol( backEnd.currentEntity->e.shaderRGBA[0] * (1-dot) ); } killGen = qtrue; } if (killGen) { goto avoidGen; } // // rgbGen // switch ( forceRGBGen ) { case CGEN_IDENTITY: memset( tess.svars.colors, 0xff, tess.numVertexes * 4 ); break; default: case CGEN_IDENTITY_LIGHTING: memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 ); break; case CGEN_LIGHTING_DIFFUSE: RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors ); break; case CGEN_LIGHTING_DIFFUSE_ENTITY: RB_CalcDiffuseEntityColor( ( unsigned char * ) tess.svars.colors ); if ( forceAlphaGen == AGEN_IDENTITY && backEnd.currentEntity->e.shaderRGBA[3] == 0xff ) { forceAlphaGen = AGEN_SKIP; //already got it in this set since it does all 4 components } break; case CGEN_EXACT_VERTEX: memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); break; case CGEN_CONST: for ( i = 0; i < tess.numVertexes; i++ ) { byteAlias_t *baDest = (byteAlias_t *)&tess.svars.colors[i], *baSource = (byteAlias_t *)&pStage->constantColor; baDest->i = baSource->i; } break; case CGEN_VERTEX: if ( tr.identityLight == 1 ) { memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) ); } else { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight; tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight; tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight; tess.svars.colors[i][3] = tess.vertexColors[i][3]; } } break; case CGEN_ONE_MINUS_VERTEX: if ( tr.identityLight == 1 ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0]; tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1]; tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2]; } } else { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight; tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight; tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight; } } break; case CGEN_FOG: { fog_t *fog; fog = tr.world->fogs + tess.fogNum; for ( i = 0; i < tess.numVertexes; i++ ) { byteAlias_t *ba = (byteAlias_t *)&tess.svars.colors[i]; ba->i = fog->colorInt; } } break; case CGEN_WAVEFORM: RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors ); break; case CGEN_ENTITY: RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors ); if ( forceAlphaGen == AGEN_IDENTITY && backEnd.currentEntity->e.shaderRGBA[3] == 0xff ) { forceAlphaGen = AGEN_SKIP; //already got it in this set since it does all 4 components } break; case CGEN_ONE_MINUS_ENTITY: RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; case CGEN_LIGHTMAPSTYLE: for ( i = 0; i < tess.numVertexes; i++ ) { byteAlias_t *baDest = (byteAlias_t *)&tess.svars.colors[i], *baSource = (byteAlias_t *)&styleColors[pStage->lightmapStyle]; baDest->i = baSource->i; } break; } // // alphaGen // switch ( pStage->alphaGen ) { case AGEN_SKIP: break; case AGEN_IDENTITY: if ( forceRGBGen != CGEN_IDENTITY ) { if ( ( forceRGBGen == CGEN_VERTEX && tr.identityLight != 1 ) || forceRGBGen != CGEN_VERTEX ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = 0xff; } } } break; case AGEN_CONST: if ( forceRGBGen != CGEN_CONST ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = pStage->constantColor[3]; } } break; case AGEN_WAVEFORM: RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors ); break; case AGEN_LIGHTING_SPECULAR: RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors ); break; case AGEN_ENTITY: RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors ); break; case AGEN_ONE_MINUS_ENTITY: RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors ); break; case AGEN_VERTEX: if ( forceRGBGen != CGEN_VERTEX ) { for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = tess.vertexColors[i][3]; } } break; case AGEN_ONE_MINUS_VERTEX: for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3]; } break; case AGEN_PORTAL: { unsigned char alpha; for ( i = 0; i < tess.numVertexes; i++ ) { float len; vec3_t v; VectorSubtract( tess.xyz[i], backEnd.viewParms.ori.origin, v ); len = VectorLength( v ); len /= tess.shader->portalRange; if ( len < 0 ) { alpha = 0; } else if ( len > 1 ) { alpha = 0xff; } else { alpha = len * 0xff; } tess.svars.colors[i][3] = alpha; } } break; case AGEN_BLEND: if ( forceRGBGen != CGEN_VERTEX ) { for ( i = 0; i < tess.numVertexes; i++ ) { colors[i][3] = tess.vertexAlphas[i][pStage->index]; //rwwRMG - added support } } break; default: break; } avoidGen: // // fog adjustment for colors to fade out as fog increases // if ( tess.fogNum ) { switch ( pStage->adjustColorsForFog ) { case ACFF_MODULATE_RGB: RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_MODULATE_ALPHA: RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_MODULATE_RGBA: RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors ); break; case ACFF_NONE: break; } } }
void RB_RenderFlare( flare_t *f ) { float size; vec3_t color; int iColor[3]; float distance, intensity, factor; byte fogFactors[3] = {255, 255, 255}; int ind=0; int alphcal; backEnd.pc.c_flareRenders++; flaredsize = backEnd.viewParms.viewportHeight * (f->radius * 0.06); float flaredsize2 = backEnd.viewParms.viewportHeight; // We don't want too big values anyways when dividing by distance. if(f->eyeZ > -1.0f) distance = 1.0f; else distance = -f->eyeZ; if ( (r_flaresDlightShrink->integer) && (f->type == 1) ) // leilei - dynamic light flares shrinking when close { float newd = distance / (48.0f); if (newd > 1) newd = 1.0f; flaredsize *= newd; } if(!f->radius) f->radius = 0.0f; // leilei - don't do a radius if there is no radius at all! // calculate the flare size.. /* * This is an alternative to intensity scaling. It changes the size of the flare on screen instead * with growing distance. See in the description at the top why this is not the way to go. */ // size will change ~ 1/r. if (r_flareMethod->integer == 1 || r_flareMethod->integer == 4 ){ // The "not the way to go" method. // seen in EF size = flaredsize * (r_flareSize->value / (distance * -2.0f)); } else if (r_flareMethod->integer == 2){ // Raven method size = flaredsize * ( r_flareSize->value/640.0f + 8 / -f->eyeZ ); } else { size = flaredsize * ( (r_flareSize->value) /640.0f + 8 / distance ); } /* * As flare sizes stay nearly constant with increasing distance we must decrease the intensity * to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be * got by considering the ratio of * (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare) * An important requirement is: * intensity <= 1 for all distances. * * The formula used here to compute the intensity is as follows: * intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2 * As you can see, the intensity will have a max. of 1 when the distance is 0. * The coefficient flareCoeff will determine the falloff speed with increasing distance. */ factor = distance + size * sqrt(flareCoeff); if (r_flareMethod->integer == 4) // leilei - EF didn't scale intensity on distance. Speed I guess intensity = 1; else intensity = flareCoeff * size * size / (factor * factor); if (r_flareMethod->integer == 1) // leilei - stupid hack to fix the not the way method { if (intensity > 1) intensity = 1; } if (pvrhack) VectorScale(f->color, 1, color ); else VectorScale(f->color, f->drawIntensity * intensity, color); // Calculations for fogging if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs) { tess.numVertexes = 1; VectorCopy(f->origin, tess.xyz[0]); tess.fogNum = f->fogNum; RB_CalcModulateColorsByFog(fogFactors); // We don't need to render the flare if colors are 0 anyways. if(!(fogFactors[0] || fogFactors[1] || fogFactors[2])) return; } iColor[0] = color[0] * fogFactors[0]; iColor[1] = color[1] * fogFactors[1]; iColor[2] = color[2] * fogFactors[2]; if (pvrhack) alphcal = f->drawIntensity * tr.identityLight * 255; // Calculate alphas from intensity instead else alphcal = 255; // Don't mess with alpha. float halfer = 1; if (f->ftype == 5 || f->ftype == 6 || f->ftype == 7 || f->ftype == 166){ RB_BeginSurface( tr.flareShaderAtlas, f->fogNum ); halfer = 0.5f; } else { if (r_flareQuality->integer) // leilei - high quality flares get no depth testing { int index; for(index = 0; index <f->theshader->numUnfoggedPasses; index++) { f->theshader->stages[index]->adjustColorsForFog = ACFF_NONE; f->theshader->stages[index]->stateBits |= GLS_DEPTHTEST_DISABLE; } } RB_BeginSurface( f->theshader, f->fogNum ); halfer = 1; } // FIXME: use quadstamp? tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = alphcal; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 0; tess.texCoords[tess.numVertexes][0][1] = 1 * halfer; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = alphcal; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY + size; tess.texCoords[tess.numVertexes][0][0] = 1 * halfer; tess.texCoords[tess.numVertexes][0][1] = 1 * halfer; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = alphcal; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY - size; tess.texCoords[tess.numVertexes][0][0] = 1 * halfer; tess.texCoords[tess.numVertexes][0][1] = 0; tess.vertexColors[tess.numVertexes][0] = iColor[0]; tess.vertexColors[tess.numVertexes][1] = iColor[1]; tess.vertexColors[tess.numVertexes][2] = iColor[2]; tess.vertexColors[tess.numVertexes][3] = alphcal; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; ind+=4; // reflections -- tcpparena if(f->ftype == 2 || f->ftype == 4){ // renders sharp lens flare. float cx, cy; float dx, dy; float size2; const float poses[]= {-.15f, 0.6f, -.1f, -.6f, -1.8f}; const float sizes[]= {0.14f, 0.2f, 0.1f, 0.2f, 1.0f}; int brightness1[]= {8,25, 40, 26, 10}; // red int brightness2[]= {15,23, 25, 30, 5}; // green int brightness3[]= {12,20, 30, 28, 10}; // blue const float r3_2=0.866025403784439f; int n; cx=backEnd.viewParms.viewportX+(backEnd.viewParms.viewportWidth>>1); cy=backEnd.viewParms.viewportY+(backEnd.viewParms.viewportHeight>>1); for(n=0;n<5;n++){ dx=(f->windowX-cx)*poses[n]+cx; dy=(f->windowY-cy)*poses[n]+cy; size2=sizes[n]*backEnd.viewParms.viewportWidth*.25f; brightness1[n]=(int)(brightness1[n]*r_lensReflectionBrightness->value); brightness2[n]=(int)(brightness2[n]*r_lensReflectionBrightness->value); brightness3[n]=(int)(brightness3[n]*r_lensReflectionBrightness->value); tess.xyz[tess.numVertexes][0] = dx-size2; tess.xyz[tess.numVertexes][1] = dy; tess.texCoords[tess.numVertexes][0][0] = .5f; tess.texCoords[tess.numVertexes][0][1] = .5f; tess.vertexColors[tess.numVertexes][0] = (iColor[0]*brightness1[n])>>8; tess.vertexColors[tess.numVertexes][1] = (iColor[1]*brightness2[n])>>8; tess.vertexColors[tess.numVertexes][2] = (iColor[2]*brightness3[n])>>8; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = dx-size2*.5f; tess.xyz[tess.numVertexes][1] = dy-size2*r3_2; tess.texCoords[tess.numVertexes][0][0] = .5f; tess.texCoords[tess.numVertexes][0][1] = .5f; tess.vertexColors[tess.numVertexes][0] = (iColor[0]*brightness1[n])>>8; tess.vertexColors[tess.numVertexes][1] = (iColor[1]*brightness2[n])>>8; tess.vertexColors[tess.numVertexes][2] = (iColor[2]*brightness3[n])>>8; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = dx+size2*.5f; tess.xyz[tess.numVertexes][1] = dy-size2*r3_2; tess.texCoords[tess.numVertexes][0][0] = .5f; tess.texCoords[tess.numVertexes][0][1] = .5f; tess.vertexColors[tess.numVertexes][0] = (iColor[0]*brightness1[n])>>8; tess.vertexColors[tess.numVertexes][1] = (iColor[1]*brightness2[n])>>8; tess.vertexColors[tess.numVertexes][2] = (iColor[2]*brightness3[n])>>8; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = dx+size2; tess.xyz[tess.numVertexes][1] = dy; tess.texCoords[tess.numVertexes][0][0] = .5f; tess.texCoords[tess.numVertexes][0][1] = .5f; tess.vertexColors[tess.numVertexes][0] = (iColor[0]*brightness1[n])>>8; tess.vertexColors[tess.numVertexes][1] = (iColor[1]*brightness2[n])>>8; tess.vertexColors[tess.numVertexes][2] = (iColor[2]*brightness3[n])>>8; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = dx+size2*.5f; tess.xyz[tess.numVertexes][1] = dy+size2*r3_2; tess.texCoords[tess.numVertexes][0][0] = .5f; tess.texCoords[tess.numVertexes][0][1] = .5f; tess.vertexColors[tess.numVertexes][0] = (iColor[0]*brightness1[n])>>8; tess.vertexColors[tess.numVertexes][1] = (iColor[1]*brightness2[n])>>8; tess.vertexColors[tess.numVertexes][2] = (iColor[2]*brightness3[n])>>8; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = dx-size2*.5f; tess.xyz[tess.numVertexes][1] = dy+size2*r3_2; tess.texCoords[tess.numVertexes][0][0] = .5f; tess.texCoords[tess.numVertexes][0][1] = .5f; tess.vertexColors[tess.numVertexes][0] = (iColor[0]*brightness1[n])>>8; tess.vertexColors[tess.numVertexes][1] = (iColor[1]*brightness2[n])>>8; tess.vertexColors[tess.numVertexes][2] = (iColor[2]*brightness3[n])>>8; tess.vertexColors[tess.numVertexes][3] = 255; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 2+ind; tess.indexes[tess.numIndexes++] = 1+ind; tess.indexes[tess.numIndexes++] = 0+ind; tess.indexes[tess.numIndexes++] = 3+ind; tess.indexes[tess.numIndexes++] = 2+ind; tess.indexes[tess.numIndexes++] = 0+ind; tess.indexes[tess.numIndexes++] = 4+ind; tess.indexes[tess.numIndexes++] = 3+ind; tess.indexes[tess.numIndexes++] = 0+ind; tess.indexes[tess.numIndexes++] = 5+ind; tess.indexes[tess.numIndexes++] = 4+ind; tess.indexes[tess.numIndexes++] = 0+ind; ind+=6; } }