/* ================= R_BindAnimatedImage ================= */ static void R_BindAnimatedImage( textureBundle_t *bundle ) { int index; if ( bundle->isVideoMap ) { ri.CIN_RunCinematic( bundle->videoMapHandle ); ri.CIN_UploadCinematic( bundle->videoMapHandle ); return; } if ( bundle->numImageAnimations <= 1 ) { if ( bundle->isLightmap && ( backEnd.refdef.rdflags & RDF_SNOOPERVIEW ) ) { GL_Bind( tr.whiteImage ); } else { 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 = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE ); index >>= FUNCTABLE_SIZE2; if ( index < 0 ) { index = 0; // may happen with shader time offsets } index %= bundle->numImageAnimations; if ( bundle->isLightmap && ( backEnd.refdef.rdflags & RDF_SNOOPERVIEW ) ) { GL_Bind( tr.whiteImage ); } else { GL_Bind( bundle->image[ index ] ); } }
/* ================= R_BindAnimatedImage ================= */ static void R_BindAnimatedImage( textureBundle_t *bundle ) { int index; if ( bundle->isVideoMap ) { ri.CIN_RunCinematic(bundle->videoMapHandle); ri.CIN_UploadCinematic(bundle->videoMapHandle); return; } if ( bundle->isRenderTarget ) { qglBindTexture (GL_TEXTURE_2D, bundle->renderTarget); return; } if ( bundle->numImageAnimations <= 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 = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE ); index >>= FUNCTABLE_SIZE2; if ( index < 0 ) { index = 0; // may happen with shader time offsets } index %= bundle->numImageAnimations; GL_Bind( bundle->image[ index ] ); }
static const d3dImage_t* GetAnimatedImage( textureBundle_t *bundle, float shaderTime ) { int index; if ( bundle->isVideoMap ) { ri.CIN_RunCinematic(bundle->videoMapHandle); ri.CIN_UploadCinematic(bundle->videoMapHandle); return GetImageRenderInfo( tr.scratchImage[bundle->videoMapHandle] ); } if ( bundle->numImageAnimations <= 1 ) { return GetImageRenderInfo( bundle->image[0] ); } // it is necessary to do this messy calc to make sure animations line up // exactly with waveforms of the same frequency index = myftol( shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE ); index >>= FUNCTABLE_SIZE2; if ( index < 0 ) { index = 0; // may happen with shader time offsets } index %= bundle->numImageAnimations; return GetImageRenderInfo( bundle->image[index] ); }
void foo(unsigned char *colors) { int v; float glow = g; v = myftol(255*glow); colors[0] = colors[1] = colors[2] = v; }
/* ================= R_ComputeLOD ================= */ int R_ComputeLOD( trRefEntity_t *ent ) { float radius; float flod, lodscale; float projectedRadius; md3Frame_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 = ( 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 ) { 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 = myftol( 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; }
float BG_GetGroundHeightAtPoint(vec3_t pos) { int i, j; vec2_t point; if (!tracemap.loaded) { return MIN_WORLD_HEIGHT; } BG_ClampPointToTracemapExtends(pos, point); i = myftol((point[0] - tracemap.world_mins[0]) * one_over_mapgrid_factor[0]); j = myftol((point[1] - tracemap.world_mins[1]) * one_over_mapgrid_factor[1]); // rain - re-clamp the points, because a rounding error can cause // them to go outside the array etpro_FinalizeTracemapClamp(&i, &j); return(tracemap.ground[j][i]); }
// 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 = myftol(dat[i] * 255.0f); if ( r < 0 ) { r = 0; } else if ( r > 255 ) { r = 255; } res[i] = (unsigned char)r; } }
static void DynamicLightPass( void ) { int i, l, a, b, c, color, *intColors; vec3_t origin; byte *colors; unsigned hitIndexes[ SHADER_MAX_INDEXES ]; int numIndexes; float radius, radiusInverseCubed; float intensity, remainder, modulate; vec3_t floatColor, dir; dlight_t *dl; // early out if ( backEnd.refdef.num_dlights == 0 ) { return; } // walk light list for ( l = 0; l < backEnd.refdef.num_dlights; l++ ) { // early out if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; } // clear colors Com_Memset( tess.svars.colors, 0, sizeof( tess.svars.colors ) ); // setup dl = &backEnd.refdef.dlights[ l ]; VectorCopy( dl->transformed, origin ); radius = dl->radius; radiusInverseCubed = dl->radiusInverseCubed; intensity = dl->intensity; floatColor[ 0 ] = dl->color[ 0 ] * 255.0f; floatColor[ 1 ] = dl->color[ 1 ] * 255.0f; floatColor[ 2 ] = dl->color[ 2 ] * 255.0f; // directional lights have max intensity and washout remainder intensity if ( dl->flags & REF_DIRECTED_DLIGHT ) { remainder = intensity * 0.125; } else { remainder = 0.0f; } // illuminate vertexes colors = tess.svars.colors[ 0 ]; for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) { backEnd.pc.c_dlightVertexes++; // directional dlight, origin is a directional normal if ( dl->flags & REF_DIRECTED_DLIGHT ) { // twosided surfaces use absolute value of the calculated lighting modulate = intensity * DotProduct( dl->origin, tess.normal[ i ].v ); if ( tess.shader->cullType == CT_TWO_SIDED ) { modulate = fabs( modulate ); } modulate += remainder; } // ball dlight else { dir[ 0 ] = radius - fabs( origin[ 0 ] - tess.xyz[ i ].v[ 0 ] ); if ( dir[ 0 ] <= 0.0f ) { continue; } dir[ 1 ] = radius - fabs( origin[ 1 ] - tess.xyz[ i ].v[ 1 ] ); if ( dir[ 1 ] <= 0.0f ) { continue; } dir[ 2 ] = radius - fabs( origin[ 2 ] - tess.xyz[ i ].v[ 2 ] ); if ( dir[ 2 ] <= 0.0f ) { continue; } modulate = intensity * dir[ 0 ] * dir[ 1 ] * dir[ 2 ] * radiusInverseCubed; } // optimizations if ( modulate < ( 1.0f / 128.0f ) ) { continue; } else if ( modulate > 1.0f ) { modulate = 1.0f; } // set color color = myftol( floatColor[ 0 ] * modulate ); colors[ 0 ] = color > 255 ? 255 : color; color = myftol( floatColor[ 1 ] * modulate ); colors[ 1 ] = color > 255 ? 255 : color; color = myftol( floatColor[ 2 ] * modulate ); colors[ 2 ] = color > 255 ? 255 : color; } // build a list of triangles that need light intColors = (int*) tess.svars.colors; numIndexes = 0; for ( i = 0; i < tess.numIndexes; i += 3 ) { a = tess.indexes[ i ]; b = tess.indexes[ i + 1 ]; c = tess.indexes[ i + 2 ]; if ( !( intColors[ a ] | intColors[ b ] | intColors[ c ] ) ) { continue; } hitIndexes[ numIndexes++ ] = a; hitIndexes[ numIndexes++ ] = b; hitIndexes[ numIndexes++ ] = c; } if ( numIndexes == 0 ) { continue; } // debug code (fixme, there's a bug in this function!) //% for( i = 0; i < numIndexes; i++ ) //% intColors[ hitIndexes[ i ] ] = 0x000000FF; qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors ); R_FogOff(); GL_Bind( tr.whiteImage ); GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; R_FogOn(); } }
/* ================= 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 ) { 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 ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) { // give everything a minimum light add ent->ambientLight[0] += tr.identityLight * 32; ent->ambientLight[1] += tr.identityLight * 32; ent->ambientLight[2] += tr.identityLight * 32; } if (ent->e.renderfx & RF_MINLIGHT) { //the minlight flag is now for items rotating on their holo thing if (ent->e.shaderRGBA[0] == 255 && ent->e.shaderRGBA[1] == 255 && ent->e.shaderRGBA[2] == 0) { ent->ambientLight[0] += tr.identityLight * 255; ent->ambientLight[1] += tr.identityLight * 255; ent->ambientLight[2] += tr.identityLight * 0; } else { ent->ambientLight[0] += tr.identityLight * 16; ent->ambientLight[1] += tr.identityLight * 96; ent->ambientLight[2] += tr.identityLight * 150; } } // // 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] = myftol( ent->ambientLight[0] ); ((byte *)&ent->ambientLightInt)[1] = myftol( ent->ambientLight[1] ); ((byte *)&ent->ambientLightInt)[2] = myftol( 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] ); }
/* ================= R_ComputeLOD ================= */ static int R_ComputeLOD( trRefEntity_t *ent ) { float radius; float flod, lodscale; float projectedRadius; md3Frame_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 // RF, checked for a forced lowest LOD if ( ent->e.reFlags & REFLAG_FORCE_LOD ) { return ( tr.currentModel->numLods - 1 ); } frame = ( md3Frame_t * )( ( ( unsigned char * ) tr.currentModel->mdc[0] ) + tr.currentModel->mdc[0]->ofsFrames ); frame += ent->e.frame; radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] ); //----(SA) testing if ( ent->e.reFlags & REFLAG_ORIENT_LOD ) { // right now this is for trees, and pushes the lod distance way in. // this is not the intended purpose, but is helpful for the new // terrain level that has loads of trees // radius = radius/2.0f; } //----(SA) end if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) { 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 = myftol( 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; }
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 = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3; floatColor[0] = floatColor[1] = floatColor[2] = luminance; } 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] = myftol(floatColor[0] * modulate); colors[1] = myftol(floatColor[1] * modulate); colors[2] = myftol(floatColor[2] * modulate); colors[3] = 255; } // build a list of triangles that need light numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { int a, b, c; a = tess.indexes[i]; b = tess.indexes[i+1]; c = tess.indexes[i+2]; if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } 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; } }
/* ================= R_ComputeLOD ================= */ int R_ComputeLOD( trRefEntity_t *ent ) { float radius; float flod, lodscale; float projectedRadius; md3Frame_t *frame; #ifdef RAVENMD4 mdrHeader_t *mdr; mdrFrame_t *mdrframe; #endif 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 #ifdef RAVENMD4 if(tr.currentModel->type == MOD_MDR) { int frameSize; mdr = (mdrHeader_t *) tr.currentModel->modelData; frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]); mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame); radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]); } else #endif { 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 ) { 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 = myftol( 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; }
/* =================== ProjectDlightTexture Perform dynamic lighting with another rendering pass =================== */ static void ProjectDlightTexture( void ) { int i, l; vec3_t origin; float *texCoords; byte *colors; byte clipBits[SHADER_MAX_VERTEXES]; MAC_STATIC float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; glIndex_t hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; vec3_t floatColor; if ( !backEnd.refdef.num_dlights ) { return; } if ( backEnd.refdef.rdflags & RDF_SNOOPERVIEW ) { // no dlights for snooper return; } for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } texCoords = texCoordsArray[0]; colors = colorArray[0]; dl = &backEnd.refdef.dlights[l]; VectorCopy( dl->transformed, origin ); radius = dl->radius; scale = 1.0f / radius; floatColor[0] = dl->color[0] * 255.0f; floatColor[1] = dl->color[1] * 255.0f; floatColor[2] = dl->color[2] * 255.0f; for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { vec3_t dist; int clip; float modulate; if ( 0 ) { clipBits[i] = 255; // definately not dlighted continue; } VectorSubtract( origin, tess.xyz[i], dist ); // if(!r_dlightBacks->integer) { // vec3_t dir; // VectorNormalize2(dist, dir); // if( DotProduct( tess.normal[i], dir) < 0) { // clipBits[i] = 255; // not lighted (backface) // continue; // } // } backEnd.pc.c_dlightVertexes++; texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[1] * scale; clip = 0; if ( texCoords[0] < 0.0f ) { clip |= 1; } else if ( texCoords[0] > 1.0f ) { clip |= 2; } if ( texCoords[1] < 0.0f ) { clip |= 4; } else if ( texCoords[1] > 1.0f ) { clip |= 8; } // modulate the strength based on the height and color if ( dist[2] > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist[2] < -radius ) { clip |= 32; modulate = 0.0f; } else { modulate = dist[2] * scale; modulate = 1 - modulate * modulate; } clipBits[i] = clip; colors[0] = myftol( floatColor[0] * modulate ); colors[1] = myftol( floatColor[1] * modulate ); colors[2] = myftol( floatColor[2] * modulate ); colors[3] = 255; } // build a list of triangles that need light numIndexes = 0; for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { glIndex_t a, b, c; a = tess.indexes[i]; b = tess.indexes[i + 1]; c = tess.indexes[i + 2]; if ( clipBits[a] & clipBits[b] & clipBits[c] ) { continue; // not lighted } // if(!r_dlightBacks->integer) { // vec3_t dir; // VectorSubtract( origin, tess.xyz[a], dir ); // VectorNormalize(dir); // if( DotProduct( tess.normal[i], dir) < 0) { // continue; // not lighted (backface) // } // } vec3_t va,vb,vc,vx; VectorSubtract( origin, tess.xyz[a], va ); VectorSubtract( tess.xyz[a], tess.xyz[b], vb ); VectorSubtract( tess.xyz[a], tess.xyz[c], vc ); CrossProduct(vb,vc,vx); if (DotProduct( vx, va ) > 0) continue; hitIndexes[numIndexes] = a; hitIndexes[numIndexes + 1] = b; hitIndexes[numIndexes + 2] = c; numIndexes += 3; } if ( !numIndexes ) { continue; } qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); //----(SA) creating dlight shader to allow for special blends or alternate dlight texture { shader_t *dls = dl->dlshader; if ( dls ) { // if (!qglActiveTextureARB || dls->numUnfoggedPasses < 2) { for ( i = 0; i < dls->numUnfoggedPasses; i++ ) { shaderStage_t *stage = dls->stages[i]; R_BindAnimatedImage( &dls->stages[i]->bundle[0] ); GL_State( stage->stateBits | GLS_DEPTHFUNC_EQUAL ); R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } /* } else { // optimize for multitexture for(i=0;i<dls->numUnfoggedPasses;) { shaderStage_t *stage = dls->stages[i]; GL_State(stage->stateBits | GLS_DEPTHFUNC_EQUAL); // setup each TMU for (tmu=0; tmu<glConfig.maxActiveTextures && i<dls->numUnfoggedPasses; tmu++, i++) { GL_SelectTexture( tmu ); if (tmu) { qglEnable( GL_TEXTURE_2D ); } R_BindAnimatedImage( &dls->stages[i]->bundle[0] ); } // draw the elements R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } // turn off unused TMU's for (tmu=1; tmu<glConfig.maxActiveTextures; tmu++) { // set back to default state GL_SelectTexture( tmu ); qglDisable( GL_TEXTURE_2D ); } // return to TEXTURE0 GL_SelectTexture( 0 ); } */ } else { R_FogOff(); // if (!dl->overdraw || !qglActiveTextureARB) { GL_Bind( tr.dlightImage ); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; // Ridah, overdraw lights several times, rather than sending // multiple lights through for ( i = 0; i < dl->overdraw; i++ ) { R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } /* } else { // optimize for multitexture GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); // setup each TMU (use all available TMU's) for (tmu=0; tmu<glConfig.maxActiveTextures && tmu<(dl->overdraw+1); tmu++) { GL_SelectTexture( tmu ); if (tmu) { qglEnable( GL_TEXTURE_2D ); GL_TexEnv( GL_ADD ); GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); } GL_Bind( tr.dlightImage ); } // draw each bundle for(i=0; i<(dl->overdraw+1); i+=glConfig.maxActiveTextures) { // make sure we dont draw with too many TMU's if (i+glConfig.maxActiveTextures>(dl->overdraw+1)) { for (tmu=0; tmu<glConfig.maxActiveTextures; tmu++) { if (tmu+i>=(dl->overdraw+1)) { GL_SelectTexture( tmu ); qglDisable( GL_TEXTURE_2D ); } } } // draw the elements R_DrawElements( numIndexes, hitIndexes ); backEnd.pc.c_totalIndexes += numIndexes; backEnd.pc.c_dlightIndexes += numIndexes; } // turn off unused TMU's for (tmu=1; tmu<glConfig.maxActiveTextures; tmu++) { // set back to default state GL_SelectTexture( tmu ); qglDisable( GL_TEXTURE_2D ); } // return to TEXTURE0 GL_SelectTexture( 0 ); } */ //R_FogOn(); } } } }
/* ================= 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) { int i; dlight_t *dl; float power; vec3_t dir; float d; vec3_t lightDir; vec3_t lightOrigin; // qboolean highlighted = qfalse; // TTimo: unused // 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); } if(ent->e.hilightIntensity) { // level of intensity was set because the item was looked at ent->ambientLight[0] += tr.identityLight * 128 * ent->e.hilightIntensity; ent->ambientLight[1] += tr.identityLight * 128 * ent->e.hilightIntensity; ent->ambientLight[2] += tr.identityLight * 128 * ent->e.hilightIntensity; } else if(ent->e.renderfx & RF_MINLIGHT) { // give everything a minimum light add ent->ambientLight[0] += tr.identityLight * 32; ent->ambientLight[1] += tr.identityLight * 32; ent->ambientLight[2] += tr.identityLight * 32; } if(ent->e.entityNum < MAX_CLIENTS && (refdef->rdflags & RDF_SNOOPERVIEW)) { VectorSet(ent->ambientLight, 245, 245, 245); // allow a little room for flicker from directed light } // // 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]; if(dl->dlshader) //----(SA) if the dlight has a diff shader specified, you don't know what it does, so don't let it affect entities lighting { continue; } 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] = myftol(ent->ambientLight[0]); ((byte *)&ent->ambientLightInt)[1] = myftol(ent->ambientLight[1]); ((byte *)&ent->ambientLightInt)[2] = myftol(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]); }
/* =================== ProjectDlightTexture Perform dynamic lighting with another rendering pass =================== */ static void ProjectDlightTexture( void ) { int i, l; #if idppc_altivec 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 = (vector unsigned char)(0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff); #else vec3_t origin; #endif float *texCoords; byte *colors; byte clipBits[SHADER_MAX_VERTEXES]; MAC_STATIC float texCoordsArray[SHADER_MAX_VERTEXES][2]; byte colorArray[SHADER_MAX_VERTEXES][4]; unsigned hitIndexes[SHADER_MAX_INDEXES]; int numIndexes; float scale; float radius; vec3_t floatColor; float modulate; if ( !backEnd.refdef.num_dlights ) { return; } #if idppc_altivec // 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); #endif 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]; #if idppc_altivec origin0 = dl->transformed[0]; origin1 = dl->transformed[1]; origin2 = dl->transformed[2]; #else VectorCopy( dl->transformed, origin ); #endif 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; #if idppc_altivec floatColorVec0 = vec_ld(0, floatColor); floatColorVec1 = vec_ld(11, floatColor); floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); #endif for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { #if idppc_altivec vec_t dist0, dist1, dist2; #else vec3_t dist; #endif int clip; backEnd.pc.c_dlightVertexes++; #if idppc_altivec //VectorSubtract( origin, tess.xyz[i], dist ); dist0 = origin0 - tess.xyz[i][0]; dist1 = origin1 - tess.xyz[i][1]; dist2 = origin2 - tess.xyz[i][2]; texCoords0 = 0.5f + dist0 * scale; texCoords1 = 0.5f + dist1 * scale; clip = 0; if ( texCoords0 < 0.0f ) { clip |= 1; } else if ( texCoords0 > 1.0f ) { clip |= 2; } if ( texCoords1 < 0.0f ) { clip |= 4; } else if ( texCoords1 > 1.0f ) { clip |= 8; } texCoords[0] = texCoords0; texCoords[1] = texCoords1; // modulate the strength based on the height and color if ( dist2 > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist2 < -radius ) { clip |= 32; modulate = 0.0f; } else { dist2 = Q_fabs(dist2); if ( dist2 < radius * 0.5f ) { modulate = 1.0f; } else { modulate = 2.0f * (radius - dist2) * scale; } } clipBits[i] = clip; modulateVec = vec_ld(0,(float *)&modulate); modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); colorVec = vec_madd(floatColorVec0,modulateVec,zero); colorInt = vec_cts(colorVec,0); // RGBx colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color #else VectorSubtract( origin, tess.xyz[i], dist ); texCoords[0] = 0.5f + dist[0] * scale; texCoords[1] = 0.5f + dist[1] * scale; clip = 0; if ( texCoords[0] < 0.0f ) { clip |= 1; } else if ( texCoords[0] > 1.0f ) { clip |= 2; } if ( texCoords[1] < 0.0f ) { clip |= 4; } else if ( texCoords[1] > 1.0f ) { clip |= 8; } // modulate the strength based on the height and color if ( dist[2] > radius ) { clip |= 16; modulate = 0.0f; } else if ( dist[2] < -radius ) { clip |= 32; modulate = 0.0f; } else { dist[2] = Q_fabs(dist[2]); if ( dist[2] < radius * 0.5f ) { modulate = 1.0f; } else { modulate = 2.0f * (radius - dist[2]) * scale; } } clipBits[i] = clip; colors[0] = myftol(floatColor[0] * modulate); colors[1] = myftol(floatColor[1] * modulate); colors[2] = myftol(floatColor[2] * modulate); colors[3] = 255; #endif } // 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; } }
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] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ); sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ); sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ); sky_maxs_subd[1] = myftol( 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 ) ); } }
static void ProjectDecalOntoWinding(decalProjector_t * dp, int numPoints, vec3_t points[2][MAX_DECAL_VERTS], msurface_t * surf, bmodel_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->bmodels ? 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] = myftol(pd * alpha * dp->color[0]); vert->modulate[1] = myftol(pd * alpha * dp->color[1]); vert->modulate[2] = myftol(pd * alpha * dp->color[2]); vert->modulate[3] = myftol(alpha * dp->color[3]); } }