void BindAnimatedImage(textureBundle_t *bundle) { int index; if (bundle->isVideoMap) { ri.CIN_RunCinematic(bundle->videoMapHandle); ri.CIN_UploadCinematic(bundle->videoMapHandle); return; } if (bundle->numImages <= 1) { GL_Bind(bundle->image[0]); return; } // it is necessary to do this messy calc to make sure animations line up // exactly with waveforms of the same frequency index = Q_ftol(backEnd.refdef.floatTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); index >>= FUNCTABLE_SIZE2; if (index < 0) { index = 0; // may happen with shader time offsets } index %= bundle->numImages; GL_Bind(bundle->image[index]); }
/* ============= EmitWaterPolys Does a water warp on the pre-fragmented glpoly_t chain ============= */ void EmitWaterPolys (msurface_t *fa) { glpoly_t *p, *bp; float *v; int i; float s, t, os, ot; float scroll; float rdt = r_newrefdef.time; if (fa->texinfo->flags & SURF_FLOWING) scroll = -64 * ( (r_newrefdef.time*0.5) - (int)(r_newrefdef.time*0.5) ); else scroll = 0; for (bp=fa->polys ; bp ; bp=bp->next) { p = bp; qglBegin (GL_TRIANGLE_FAN); for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE) { os = v[3]; ot = v[4]; #if !id386 s = os + r_turbsin[(int)((ot*0.125+r_newrefdef.time) * TURBSCALE) & 255]; #else s = os + r_turbsin[Q_ftol( ((ot*0.125+rdt) * TURBSCALE) ) & 255]; #endif s += scroll; s *= (1.0/64); #if !id386 t = ot + r_turbsin[(int)((os*0.125+rdt) * TURBSCALE) & 255]; #else t = ot + r_turbsin[Q_ftol( ((os*0.125+rdt) * TURBSCALE) ) & 255]; #endif t *= (1.0/64); qglTexCoord2f (s, t); qglVertex3fv (v); } qglEnd (); } }
void EmitWaterPolys_original (msurface_t *fa) // jitwater - old code { glpoly_t *p, *bp; float *v; int i; float s, t; float scroll; float rdt = r_newrefdef.time; if (fa->texinfo->flags & SURF_FLOWING) scroll = -64 * ((r_newrefdef.time*0.5f) - (int)(r_newrefdef.time*0.5f)); else scroll = 0; for (bp=fa->polys; bp; bp=bp->next) { p = bp; qgl.Begin(GL_TRIANGLE_FAN); for (i=0, v=p->verts[0]; i<p->numverts; i++, v+=VERTEXSIZE) { #if !id386 s = v[3] + r_turbsin[(int)((v[4]*0.125f+r_newrefdef.time) * TURBSCALE) & 255]; t = v[4] + r_turbsin[(int)((v[3]*0.125f+rdt) * TURBSCALE) & 255]; #else s = v[3] + r_turbsin[Q_ftol(((v[4]*0.125f+rdt) * TURBSCALE)) & 255]; t = v[4] + r_turbsin[Q_ftol(((v[3]*0.125f+rdt) * TURBSCALE)) & 255]; #endif s += scroll; s *= 0.015625; // divide by empatpuluh enam t *= 0.015625; // ditto // dont we love multilingual comments? :) qgl.TexCoord2f(s,t); qgl.Vertex3fv(v); } qgl.End(); } }
// de-static'd because tr_quicksprite wants it void R_BindAnimatedImage( textureBundle_t *bundle ) { int index; if ( bundle->isVideoMap ) { ri->CIN_RunCinematic(bundle->videoMapHandle); ri->CIN_UploadCinematic(bundle->videoMapHandle); return; } if ((r_fullbright->value /*|| tr.refdef.doFullbright */) && bundle->isLightmap) { GL_Bind( tr.whiteImage ); return; } if ( bundle->numImageAnimations <= 1 ) { GL_Bind( bundle->image ); return; } if (backEnd.currentEntity->e.renderfx & RF_SETANIMINDEX ) { index = backEnd.currentEntity->e.skinNum; } else { // it is necessary to do this messy calc to make sure animations line up // exactly with waveforms of the same frequency index = Q_ftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE ); index >>= FUNCTABLE_SIZE2; if ( index < 0 ) { index = 0; // may happen with shader time offsets } } if ( bundle->oneShotAnimMap ) { if ( index >= bundle->numImageAnimations ) { // stick on last frame index = bundle->numImageAnimations - 1; } } else { // loop index %= bundle->numImageAnimations; } GL_Bind( *((image_t**)bundle->image + index) ); }
void GL_UpdateSwapInterval( void ) { if ( gl_swapinterval->modified ) { gl_swapinterval->modified = false; { #if 0 //def _WIN32 if ( qwglSwapIntervalEXT ) { qwglSwapIntervalEXT( Q_ftol(gl_swapinterval->value) ); } #endif } } }
/* ================= R_ComputeLOD ================= */ static int R_ComputeLOD( trRefEntity_t *ent ) { float radius; float flod; float projectedRadius; int lod; if ( tr.currentModel->numLods < 2 ) { // model has only 1 LOD level, skip computations and bias return(0); } // multiple LODs exist, so compute projected bounding sphere // and use that as a criteria for selecting LOD // if ( tr.currentModel->md3[0] ) { //normal md3 md3Frame_t *frame; frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames ); frame += ent->e.frame; radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] ); } if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) { flod = 1.0f - projectedRadius * r_lodscale->value; flod *= tr.currentModel->numLods; } else { // object intersects near view plane, e.g. view weapon flod = 0; } lod = Q_ftol( flod ); if ( lod < 0 ) { lod = 0; } else if ( lod >= tr.currentModel->numLods ) { lod = tr.currentModel->numLods - 1; } lod += r_lodbias->integer; if ( lod >= tr.currentModel->numLods ) lod = tr.currentModel->numLods - 1; if ( lod < 0 ) lod = 0; return lod; }
void GL_UpdateSwapInterval( void ) { if ( gl_swapinterval->modified ) { gl_swapinterval->modified = false; #ifdef STEREO_SUPPORT if ( !gl_state.stereo_enabled ) #endif { #ifdef _WIN32 if ( qwglSwapIntervalEXT ) { qwglSwapIntervalEXT( Q_ftol(gl_swapinterval->value) ); } #endif } } }
// Helper function //------------------------- void ClampVec( vec3_t dat, byte *res ) { int r; // clamp all vec values, then multiply the normalized values by 255 to maximize the result for ( int i = 0; i < 3; i++ ) { r = Q_ftol(dat[i] * 255.0f); if ( r < 0 ) { r = 0; } else if ( r > 255 ) { r = 255; } res[i] = (unsigned char)r; } }
static void FillCloudBox( const shader_t *shader, int stage ) { int i; for ( i =0; i < 6; i++ ) { int sky_mins_subd[2], sky_maxs_subd[2]; int s, t; float MIN_T; if ( 1 ) // FIXME? shader->sky->fullClouds ) { MIN_T = -HALF_SKY_SUBDIVISIONS; // still don't want to draw the bottom, even if fullClouds if ( i == 5 ) continue; } else { switch( i ) { case 0: case 1: case 2: case 3: MIN_T = -1; break; case 5: // don't draw clouds beneath you continue; case 4: // top default: MIN_T = -HALF_SKY_SUBDIVISIONS; break; } } sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || ( sky_mins[1][i] >= sky_maxs[1][i] ) ) { continue; } sky_mins_subd[0] = Q_ftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ); sky_mins_subd[1] = Q_ftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ); sky_maxs_subd[0] = Q_ftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ); sky_maxs_subd[1] = Q_ftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ); if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; if ( sky_mins_subd[1] < MIN_T ) sky_mins_subd[1] = MIN_T; else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; if ( sky_maxs_subd[1] < MIN_T ) sky_maxs_subd[1] = MIN_T; else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; // // iterate through the subdivisions // for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) { for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) { MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, i, NULL, s_skyPoints[t][s] ); s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0]; s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1]; } } // only add indexes for first stage FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) ); } }
/* ================= R_SetupEntityLighting Calculates all the lighting values that will be used by the Calc_* functions ================= */ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { #ifndef VV_LIGHTING int i; dlight_t *dl; float power; vec3_t dir; float d; vec3_t lightDir; vec3_t lightOrigin; // lighting calculations if ( ent->lightingCalculated ) { return; } ent->lightingCalculated = qtrue; // // trace a sample point down to find ambient light // if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { // seperate lightOrigins are needed so an object that is // sinking into the ground can still be lit, and so // multi-part models can be lit identically VectorCopy( ent->e.lightingOrigin, lightOrigin ); } else { VectorCopy( ent->e.origin, lightOrigin ); } // if NOWORLDMODEL, only use dynamic lights (menu system, etc) if ( !(refdef->rdflags & RDF_NOWORLDMODEL ) && tr.world->lightGridData ) { R_SetupEntityLightingGrid( ent ); } else { ent->ambientLight[0] = ent->ambientLight[1] = ent->ambientLight[2] = tr.identityLight * 150; ent->directedLight[0] = ent->directedLight[1] = ent->directedLight[2] = tr.identityLight * 150; VectorCopy( tr.sunDirection, ent->lightDir ); } // bonus items and view weapons have a fixed minimum add if ( ent->e.renderfx & RF_MORELIGHT ) { ent->ambientLight[0] += tr.identityLight * 96; ent->ambientLight[1] += tr.identityLight * 96; ent->ambientLight[2] += tr.identityLight * 96; } else { // give everything a minimum light add ent->ambientLight[0] += tr.identityLight * 32; ent->ambientLight[1] += tr.identityLight * 32; ent->ambientLight[2] += tr.identityLight * 32; } // // modify the light by dynamic lights // d = VectorLength( ent->directedLight ); VectorScale( ent->lightDir, d, lightDir ); for ( i = 0 ; i < refdef->num_dlights ; i++ ) { dl = &refdef->dlights[i]; VectorSubtract( dl->origin, lightOrigin, dir ); d = VectorNormalize( dir ); power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius ); if ( d < DLIGHT_MINIMUM_RADIUS ) { d = DLIGHT_MINIMUM_RADIUS; } d = power / ( d * d ); VectorMA( ent->directedLight, d, dl->color, ent->directedLight ); VectorMA( lightDir, d, dir, lightDir ); } // clamp ambient for ( i = 0 ; i < 3 ; i++ ) { if ( ent->ambientLight[i] > tr.identityLightByte ) { ent->ambientLight[i] = tr.identityLightByte; } } if ( r_debugLight->integer ) { LogLight( ent ); } // save out the byte packet version ((byte *)&ent->ambientLightInt)[0] = Q_ftol( ent->ambientLight[0] ); ((byte *)&ent->ambientLightInt)[1] = Q_ftol( ent->ambientLight[1] ); ((byte *)&ent->ambientLightInt)[2] = Q_ftol( ent->ambientLight[2] ); ((byte *)&ent->ambientLightInt)[3] = 0xff; // transform the direction to local space VectorNormalize( lightDir ); ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] ); ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] ); ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] ); #endif // VV_LIGHTING }
// MPO : this is my version... void EmitWaterPolys (msurface_t *fa) { //============================== glpoly_t *p; glpoly_t *bp; float *v; int i; float s; float t; float os; float ot; float scroll; float rdt = r_newrefdef.time; float zValue = 0.0; // height of water qboolean waterNotFlat = false; qboolean flowing; //============================== if (g_drawing_refl) return; // we don't want any water drawn while we are doing our reflection if (fa->texinfo->flags & SURF_FLOWING) { scroll = -64.0f * ((r_newrefdef.time * 0.5f) - (int)(r_newrefdef.time * 0.5f)); flowing = true; } else { scroll = 0.0f; flowing = false; } // skip the water texture on transparent surfaces if (r_reflectivewater->value && (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))) { for (bp = fa->polys; bp; bp = bp->next) { p = bp; for (i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE) { // if it hasn't been initalized before if (zValue == 0.0f) zValue = v[2]; // Make sure polygons are on the same plane // Fix for not perfectly flat water on base1 - strange .. else if (fabs(zValue - v[2]) > 8.0f) waterNotFlat = true; } } } if (waterNotFlat || !r_reflectivewater->value || !(fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))) { for (bp = fa->polys; bp; bp = bp->next) { p = bp; qgl.Begin(GL_TRIANGLE_FAN); c_brush_polys += p->numverts / 3; // jitrspeeds for (i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE) { os = v[3]; ot = v[4]; #if !id386 s = os + r_turbsin[(int)((ot * 0.125f + r_newrefdef.time) * TURBSCALE) & 255]; #else s = os + r_turbsin[Q_ftol(((ot * 0.125f + rdt) * TURBSCALE)) & 255]; #endif s += scroll; s *= 0.015625f; // 1/64 #if !id386 t = ot + r_turbsin[(int)((os * 0.125f + rdt) * TURBSCALE) & 255]; #else t = ot + r_turbsin[Q_ftol(((os * 0.125f + rdt) * TURBSCALE)) & 255]; #endif t *= 0.015625f; // 1/64 // if it hasn't been initalized before if (zValue == 0.0f) zValue = v[2]; // Make sure polygons are on the same plane // Fix for not perfectly flat water on base1 - strange .. else if (fabs(zValue - v[2]) > 0.1f) waterNotFlat = true; qgl.TexCoord2f(s, t); qgl.Vertex3f(v[0], v[1], v[2]); } qgl.End(); } } if (waterNotFlat) return; if (r_reflectivewater->value) { #if 0 //==================== vec3_t distanceVector; float distance; //==================== #endif v = p->verts[0]; #if 0 VectorSubtract(v, r_newrefdef.vieworg, distanceVector); distance = VectorLength(distanceVector); //R_add_refl(zValue, distance); #endif R_add_refl(v[0], v[1], zValue); g_refl_enabled = true; } // find out which reflection we have that corresponds to the surface that we're drawing for (g_active_refl = 0; g_active_refl < g_num_refl; g_active_refl++) { // if we find which reflection to bind if (fabs(g_refl_Z[g_active_refl] - zValue) < 8.0f) { // === jitwater if (gl_state.fragment_program) { qgl.Enable(GL_VERTEX_PROGRAM_ARB); qgl.BindProgramARB(GL_VERTEX_PROGRAM_ARB, g_water_vertex_program_id); qgl.Enable(GL_FRAGMENT_PROGRAM_ARB); qgl.BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_water_fragment_program_id); GL_MBind(QGL_TEXTURE1, distort_tex->texnum); // Distortion texture GL_MBind(QGL_TEXTURE2, water_normal_tex->texnum); // Normal texture } GL_MBind(QGL_TEXTURE0, g_refl_images[g_active_refl]->texnum); // Reflection texture // jitwater === break; } } // if we found a reflective surface correctly, then go ahead and draw it if (g_active_refl != g_num_refl) { qgl.Color4f(1.0f, 1.0f, 1.0f, 1.0f); if (!gl_state.blend) qgl.Enable(GL_BLEND); GL_TexEnv(GL_MODULATE); qgl.ShadeModel(GL_SMOOTH); if (gl_state.fragment_program) { float w, h; R_GetReflTexScale(&w, &h); // Probably unnecessary qgl.ProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, w, h, rs_realtime * (flowing ? -0.3f : 0.2f), rs_realtime * -0.2f); qgl.ProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 1, r_newrefdef.vieworg[0], r_newrefdef.vieworg[1], r_newrefdef.vieworg[2], 1.0f); } else { // Put UV coords in screen space for rendering the reflection texture. Only need to do this when fragment programs are disabled. It's handled in the vertex shader otherwise. R_LoadReflMatrix(); } // draw reflected water layer on top of regular for (bp = fa->polys; bp; bp = bp->next) { p = bp; qgl.Begin(GL_TRIANGLE_FAN); c_brush_polys += p->numverts / 3; // jitrspeeds for (i = 0, v = p->verts[0]; i < p->numverts; ++i, v += VERTEXSIZE) { if (gl_state.fragment_program) { qgl.MultiTexCoord3fvARB(QGL_TEXTURE0, v); // Used for world space qgl.MultiTexCoord3fvARB(QGL_TEXTURE1, v + 3); // Actual texture UV's. } else { vec3_t vAngle; qgl.TexCoord3f(v[0], v[1] + CalcWave(v[0], v[1]), v[2]); if (r_newrefdef.rdflags & RDF_UNDERWATER) { VectorSubtract(v, r_newrefdef.vieworg, vAngle); VectorNormalize(vAngle); if (vAngle[2] > 0.55f) vAngle[2] = 0.55f; qgl.Color4f(1.0f, 1.0f, 1.0f, 0.9f - (vAngle[2] * 1.0f)); } else { VectorSubtract(r_newrefdef.vieworg, v, vAngle); VectorNormalize(vAngle); if (vAngle[2] > 0.55f) vAngle[2] = 0.55f; qgl.Color4f(1.0f, 1.0f, 1.0f, 0.9f - (vAngle[2] * 1.0f)); } } qgl.Vertex3f(v[0], v[1], v[2]); } qgl.End(); } R_ClearReflMatrix(); if (!gl_state.blend) qgl.Disable(GL_BLEND); if (gl_state.fragment_program) // jitwater { qgl.Disable(GL_FRAGMENT_PROGRAM_ARB); qgl.Disable(GL_VERTEX_PROGRAM_ARB); } } }
static void ProjectDecalOntoWinding( decalProjector_t *dp, int numPoints, vec3_t points[ 2 ][ MAX_DECAL_VERTS ], bspSurface_t *surf, bspModel_t *bmodel ) { int i, pingPong, count, axis; float pd, d, d2, alpha = 1.f; vec4_t plane; vec3_t absNormal; decal_t *decal, *oldest; polyVert_t *vert; /* make a plane from the winding */ if ( !PlaneFromPoints( plane, points[ 0 ][ 0 ], points[ 0 ][ 1 ], points[ 0 ][ 2 ] ) ) { return; } /* omnidirectional projectors need plane type */ if ( dp->omnidirectional ) { /* compiler warnings be gone */ pd = 1.0f; /* fade by distance from plane */ d = DotProduct( dp->center, plane ) - plane[ 3 ]; alpha = 1.0f - ( fabs( d ) / dp->radius ); if ( alpha < 0.0f ) { return; } if ( alpha > 1.0f ) { alpha = 1.0f; } /* set projection axis */ absNormal[ 0 ] = fabs( plane[ 0 ] ); absNormal[ 1 ] = fabs( plane[ 1 ] ); absNormal[ 2 ] = fabs( plane[ 2 ] ); if ( absNormal[ 2 ] >= absNormal[ 0 ] && absNormal[ 2 ] >= absNormal[ 1 ] ) { axis = 2; } else if ( absNormal[ 0 ] >= absNormal[ 1 ] && absNormal[ 0 ] >= absNormal[ 2 ] ) { axis = 0; } else { axis = 1; } } else { /* backface check */ pd = DotProduct( dp->planes[ 0 ], plane ); if ( pd < -0.0001f ) { return; } /* directional decals use first texture matrix */ axis = 0; } /* chop the winding by all the projector planes */ pingPong = 0; for ( i = 0; i < dp->numPlanes; i++ ) //% dp->numPlanes { ChopWindingBehindPlane( numPoints, points[ pingPong ], &numPoints, points[ !pingPong ], dp->planes[ i ], 0.0f ); pingPong ^= 1; if ( numPoints < 3 ) { return; } if ( numPoints == MAX_DECAL_VERTS ) { break; } } /* find first free decal (fixme: optimize this) */ count = ( bmodel == tr.world->models ? MAX_WORLD_DECALS : MAX_ENTITY_DECALS ); oldest = &bmodel->decals[ 0 ]; decal = bmodel->decals; for ( i = 0; i < count; i++, decal++ ) { /* try to find an empty decal slot */ if ( decal->shader == NULL ) { break; } /* find oldest decal */ if ( decal->fadeEndTime < oldest->fadeEndTime ) { oldest = decal; } } /* guess we have to use the oldest decal */ if ( i >= count ) { decal = oldest; } /* r_speeds useful info */ tr.pc.c_decalSurfacesCreated++; /* set it up (fixme: get the shader before this happens) */ decal->parent = surf; decal->shader = dp->shader; decal->fadeStartTime = dp->fadeStartTime; decal->fadeEndTime = dp->fadeEndTime; decal->fogIndex = surf->fogIndex; /* add points */ decal->numVerts = numPoints; vert = decal->verts; for ( i = 0; i < numPoints; i++, vert++ ) { /* set xyz */ VectorCopy( points[ pingPong ][ i ], vert->xyz ); /* set st */ vert->st[ 0 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 0 ] ) + dp->texMat[ axis ][ 0 ][ 3 ]; vert->st[ 1 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 1 ] ) + dp->texMat[ axis ][ 1 ][ 3 ]; /* unidirectional decals fade by half distance from front->back planes */ if ( !dp->omnidirectional ) { /* set alpha */ d = DotProduct( vert->xyz, dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ]; d2 = DotProduct( vert->xyz, dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ]; alpha = 2.0f * d2 / ( d + d2 ); if ( alpha > 1.0f ) { alpha = 1.0f; } else if ( alpha < 0.0f ) { alpha = 0.0f; } } /* set color */ vert->modulate[ 0 ] = Q_ftol( pd * alpha * dp->color[ 0 ] ); vert->modulate[ 1 ] = Q_ftol( pd * alpha * dp->color[ 1 ] ); vert->modulate[ 2 ] = Q_ftol( pd * alpha * dp->color[ 2 ] ); vert->modulate[ 3 ] = Q_ftol( alpha * dp->color[ 3 ] ); } }
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] = 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; } 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; } }
/* ============= EmitWaterPolys Does a water warp on the pre-fragmented glpoly_t chain NeVo - cleaned this function up ============= */ void EmitWaterPolys (msurface_t *fa) { glpoly_t *p, *bp; float *v; int i; float s, t, os, ot; float scroll; float rdt = r_newrefdef.time; if (fa->texinfo->flags & SURF_FLOWING) scroll = -64 * ( (rdt*0.5) - (int)(rdt*0.5) ); else scroll = 0; for (bp=fa->polys ; bp ; bp=bp->next) { p = bp; qglBegin (GL_TRIANGLE_FAN); for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE) { os = v[3]; ot = v[4]; #if !id386 s = os + r_turbsin[(int)((ot*0.125+rdt) * TURBSCALE) & 255]; #else s = os + r_turbsin[Q_ftol( ((ot*0.125+rdt) * TURBSCALE) ) & 255]; #endif s += scroll; s *= (1.0/64); #if !id386 t = ot + r_turbsin[(int)((os*0.125+rdt) * TURBSCALE) & 255]; #else t = ot + r_turbsin[Q_ftol( ((os*0.125+rdt) * TURBSCALE) ) & 255]; #endif t *= (1.0/64); // --==OBSIDIAN UPDATE==-- //Adding this glColor call to lessen the alpha transparency on the water. Murky //water should not be so see through. //qglColor4f(1.0, 1.0, 1.0, 0.75); qglColor4f ( 1 - 0.3333, 1 - 0.4511, 1 - 0.5451, 0.75); // NeVo - made color match murky fog qglTexCoord2f (s, t); //=============== Water waves ============ //if (!(fa->texinfo->flags & SURF_FLOWING)) // NeVo - allow warping while flowing if (r_fluidwaves->value > 1.0) { vec3_t nv; nv[0] = v[0]; nv[1] = v[1]; nv[2] = v[2] + r_fluidwaves->value * sin( v[0] * 0.025 + rdt ) * sin( v[2] * 0.05 + rdt ) + r_fluidwaves->value *sin( v[1] * 0.025 + rdt * 2 ) *sin( v[2] * 0.05 + rdt ); qglVertex3fv (nv); } else //============= Water waves end. ============== qglVertex3fv (v); } qglEnd (); } }
/* =================== 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( 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; } }
static void FillCloudBox( const shader_t *shader, int stage ) { int i; for ( i = 0; i < 6; i++ ) { int sky_mins_subd[ 2 ], sky_maxs_subd[ 2 ]; int s, t; float MIN_T; { MIN_T = -HALF_SKY_SUBDIVISIONS; // still don't want to draw the bottom, even if fullClouds if ( i == 5 ) { continue; } } sky_mins[ 0 ][ i ] = floor( sky_mins[ 0 ][ i ] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; sky_mins[ 1 ][ i ] = floor( sky_mins[ 1 ][ i ] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; sky_maxs[ 0 ][ i ] = ceil( sky_maxs[ 0 ][ i ] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; sky_maxs[ 1 ][ i ] = ceil( sky_maxs[ 1 ][ i ] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; if ( ( sky_mins[ 0 ][ i ] >= sky_maxs[ 0 ][ i ] ) || ( sky_mins[ 1 ][ i ] >= sky_maxs[ 1 ][ i ] ) ) { continue; } sky_mins_subd[ 0 ] = Q_ftol( sky_mins[ 0 ][ i ] * HALF_SKY_SUBDIVISIONS ); sky_mins_subd[ 1 ] = Q_ftol( sky_mins[ 1 ][ i ] * HALF_SKY_SUBDIVISIONS ); sky_maxs_subd[ 0 ] = Q_ftol( sky_maxs[ 0 ][ i ] * HALF_SKY_SUBDIVISIONS ); sky_maxs_subd[ 1 ] = Q_ftol( sky_maxs[ 1 ][ i ] * HALF_SKY_SUBDIVISIONS ); if ( sky_mins_subd[ 0 ] < -HALF_SKY_SUBDIVISIONS ) { sky_mins_subd[ 0 ] = -HALF_SKY_SUBDIVISIONS; } else if ( sky_mins_subd[ 0 ] > HALF_SKY_SUBDIVISIONS ) { sky_mins_subd[ 0 ] = HALF_SKY_SUBDIVISIONS; } if ( sky_mins_subd[ 1 ] < MIN_T ) { sky_mins_subd[ 1 ] = MIN_T; } else if ( sky_mins_subd[ 1 ] > HALF_SKY_SUBDIVISIONS ) { sky_mins_subd[ 1 ] = HALF_SKY_SUBDIVISIONS; } if ( sky_maxs_subd[ 0 ] < -HALF_SKY_SUBDIVISIONS ) { sky_maxs_subd[ 0 ] = -HALF_SKY_SUBDIVISIONS; } else if ( sky_maxs_subd[ 0 ] > HALF_SKY_SUBDIVISIONS ) { sky_maxs_subd[ 0 ] = HALF_SKY_SUBDIVISIONS; } if ( sky_maxs_subd[ 1 ] < MIN_T ) { sky_maxs_subd[ 1 ] = MIN_T; } else if ( sky_maxs_subd[ 1 ] > HALF_SKY_SUBDIVISIONS ) { sky_maxs_subd[ 1 ] = HALF_SKY_SUBDIVISIONS; } // iterate through the subdivisions for ( t = sky_mins_subd[ 1 ] + HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[ 1 ] + HALF_SKY_SUBDIVISIONS; t++ ) { for ( s = sky_mins_subd[ 0 ] + HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[ 0 ] + HALF_SKY_SUBDIVISIONS; s++ ) { MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, i, NULL, s_skyPoints[ t ][ s ] ); s_skyTexCoords[ t ][ s ][ 0 ] = s_cloudTexCoords[ i ][ t ][ s ][ 0 ]; s_skyTexCoords[ t ][ s ][ 1 ] = s_cloudTexCoords[ i ][ t ][ s ][ 1 ]; } } // only add indexes for first stage FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( qboolean )( stage == 0 ) ); } }
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; } } }
/** * @brief R_ComputeLOD * @param[in] ent * @return */ int R_ComputeLOD(trRefEntity_t *ent) { float radius; float flod, lodscale; float projectedRadius; mdvFrame_t *frame; int lod; if (tr.currentModel->numLods < 2) { // model has only 1 LOD level, skip computations and bias lod = 0; } else { // multiple LODs exist, so compute projected bounding sphere // and use that as a criteria for selecting LOD frame = tr.currentModel->mdv[0]->frames; frame += ent->e.frame; radius = RadiusFromBounds(frame->bounds[0], frame->bounds[1]); if ((projectedRadius = R_ProjectRadius(radius, ent->e.origin)) != 0.f) { lodscale = r_lodScale->value; if (lodscale > 20) { lodscale = 20; } flod = 1.0f - projectedRadius * lodscale; } else { // object intersects near view plane, e.g. view weapon flod = 0; } flod *= tr.currentModel->numLods; lod = Q_ftol(flod); if (lod < 0) { lod = 0; } else if (lod >= tr.currentModel->numLods) { lod = tr.currentModel->numLods - 1; } } lod += r_lodBias->integer; if (lod >= tr.currentModel->numLods) { lod = tr.currentModel->numLods - 1; } if (lod < 0) { lod = 0; } return lod; }
/* ============= R_DrawWarpSurface Does a water warp on the pre-fragmented glpoly_t chain. added Psychospaz's lightmaps on alpha surfaces ============= */ void R_DrawWarpSurface (msurface_t *fa, float alpha, qboolean render) { glpoly_t *p, *bp; float *v, s, t, scroll, dstscroll, rdt = r_newrefdef.time; vec3_t point; int i; qboolean light = r_warp_lighting->value && !r_fullbright->value && !(fa->texinfo->flags & SURF_NOLIGHTENV); qboolean texShaderNV = glConfig.NV_texshaders && glConfig.multitexture && ( (!glConfig.arb_fragment_program && r_pixel_shader_warp->value) || (glConfig.arb_fragment_program && r_pixel_shader_warp->value > 1) ); c_brush_surfs++; dstscroll = -64 * ( (r_newrefdef.time*0.15) - (int)(r_newrefdef.time*0.15) ); if (fa->texinfo->flags & SURF_FLOWING) scroll = -64 * ( (r_newrefdef.time*0.5) - (int)(r_newrefdef.time*0.5) ); else scroll = 0.0f; // rb_vertex = rb_index = 0; for (bp = fa->polys; bp; bp = bp->next) { c_brush_polys += (bp->numverts-2); p = bp; if (RB_CheckArrayOverflow (p->numverts, (p->numverts-2)*3)) RB_RenderWarpSurface (fa); for (i = 0; i < p->numverts-2; i++) { indexArray[rb_index++] = rb_vertex; indexArray[rb_index++] = rb_vertex+i+1; indexArray[rb_index++] = rb_vertex+i+2; } for (i=0, v=p->verts[0]; i<p->numverts; i++, v+=VERTEXSIZE) { #if !id386 s = v[3] + r_turbsin[(int)((v[4]*0.125+rdt) * TURBSCALE) & 255]; t = v[4] + r_turbsin[(int)((v[3]*0.125+rdt) * TURBSCALE) & 255]; #else s = v[3] + r_turbsin[Q_ftol( ((v[4]*0.125+rdt) * TURBSCALE) ) & 255]; t = v[4] + r_turbsin[Q_ftol( ((v[3]*0.125+rdt) * TURBSCALE) ) & 255]; #endif s += scroll; s *= DIV64; t *= DIV64; //=============== Water waves ======================== VectorCopy(v, point); if ( r_waterwave->value > 0 && !(fa->texinfo->flags & SURF_FLOWING) && fa->plane->normal[2] > 0 && fa->plane->normal[2] > fa->plane->normal[0] && fa->plane->normal[2] > fa->plane->normal[1] ) point[2] = v[2] + r_waterwave->value * sin(v[0]*0.025+rdt) * sin(v[2]*0.05+rdt); //=============== End water waves ==================== // MrG - texture shader waterwarp if (texShaderNV) { VA_SetElem2(texCoordArray[0][rb_vertex], (v[3]+dstscroll)*DIV64, v[4]*DIV64); VA_SetElem2(texCoordArray[1][rb_vertex], s, t); } else { VA_SetElem2(texCoordArray[0][rb_vertex], s, t); VA_SetElem2(texCoordArray[1][rb_vertex], (v[3]+dstscroll)*DIV64, v[4]*DIV64); } if (light && p->vertexlight && p->vertexlightset) VA_SetElem4(colorArray[rb_vertex], (float)(p->vertexlight[i*3+0]*DIV255), (float)(p->vertexlight[i*3+1]*DIV255), (float)(p->vertexlight[i*3+2]*DIV255), alpha); else VA_SetElem4(colorArray[rb_vertex], glState.inverse_intensity, glState.inverse_intensity, glState.inverse_intensity, alpha); VA_SetElem3(vertexArray[rb_vertex], point[0], point[1], point[2]); rb_vertex++; } } if (render) RB_RenderWarpSurface (fa); }
void GL_ScreenShot_JPG (byte *buffer) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW s[1]; FILE *f; char picname[80], checkname[MAX_OSPATH]; int i, offset, w3; // create the scrnshots directory if it doesn't exist Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/", FS_Gamedir()); FS_CreatePath (checkname); for (i = 0; i < 999; i++) { sprintf (picname, "%s/scrnshot/quake%.3d.jpg", FS_Gamedir(), i); f = fopen (picname, "rb"); if (!f) break; fclose (f); } f = fopen (picname, "wb"); if (!f) { VID_Printf (PRINT_ALL, "Couldn't open %s for writing.\n", picname); return; } // Initialise the JPEG compression object cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, f); // Setup JPEG Parameters cinfo.image_width = viddef.width; cinfo.image_height = viddef.height; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; jpeg_set_defaults(&cinfo); // Niceass: 85 is the quality. 0-100 jpeg_set_quality(&cinfo, Q_ftol(gl_jpg_quality->value), TRUE); // Start Compression jpeg_start_compress(&cinfo, true); // Feed scanline data w3 = cinfo.image_width * 3; offset = w3 * cinfo.image_height - w3; while (cinfo.next_scanline < cinfo.image_height) { s[0] = &buffer[offset - cinfo.next_scanline * w3]; jpeg_write_scanlines(&cinfo, s, 1); } // Finish Compression jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(f); free(buffer); VID_Printf (PRINT_ALL, "Wrote %s\n", picname); }