This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/client/gl_rlight.c

428 lines
9.9 KiB
C
Raw Normal View History

2010-12-02 22:00:00 +01:00
//=======================================================================
// Copyright XashXT Group 2010 <20>
// gl_rlight.c - dynamic and static lights
//=======================================================================
#include "common.h"
#include "client.h"
2010-12-22 22:00:00 +01:00
#include "mathlib.h"
2010-12-02 22:00:00 +01:00
#include "gl_local.h"
2010-12-25 22:00:00 +01:00
#include "pm_local.h"
2010-12-16 22:00:00 +01:00
#include "studio.h"
2010-12-02 22:00:00 +01:00
2010-12-06 22:00:00 +01:00
/*
=============================================================================
DYNAMIC LIGHTS
=============================================================================
*/
2010-12-11 22:00:00 +01:00
/*
==================
R_AnimateLight
==================
*/
void R_AnimateLight( void )
{
int i, k, flight, clight;
2010-12-16 22:00:00 +01:00
float l, c, lerpfrac, backlerp;
2010-12-11 22:00:00 +01:00
lightstyle_t *ls;
2010-12-22 22:00:00 +01:00
if( !RI.drawWorld || !cl.worldmodel )
return;
2010-12-11 22:00:00 +01:00
// light animations
// 'm' is normal light, 'a' is no light, 'z' is double bright
flight = (int)floor( cl.time * 10 );
clight = (int)ceil( cl.time * 10 );
lerpfrac = ( cl.time * 10 ) - flight;
backlerp = 1.0f - lerpfrac;
for( i = 0, ls = cl.lightstyles; i < MAX_LIGHTSTYLES; i++, ls++ )
{
if( r_fullbright->integer || !cl.worldmodel->lightdata )
{
RI.lightstylevalue[i] = 256 * 256;
continue;
}
if( !ls->length )
{
RI.lightstylevalue[i] = 256 * r_lighting_modulate->value;
continue;
}
else if( ls->length == 1 )
{
// single length style so don't bother interpolating
RI.lightstylevalue[i] = ls->map[0] * 22 * r_lighting_modulate->value;
continue;
}
else if( !ls->interp || !cl_lightstyle_lerping->integer )
{
RI.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * r_lighting_modulate->value;
continue;
}
// interpolate animating light
// frame just gone
k = ls->map[flight % ls->length];
l = (float)( k * 22 ) * backlerp;
2010-12-16 22:00:00 +01:00
c = (float)( k / 12 ) * backlerp;
2010-12-11 22:00:00 +01:00
// upcoming frame
k = ls->map[clight % ls->length];
l += (float)( k * 22 ) * lerpfrac;
2010-12-16 22:00:00 +01:00
c += (float)( k / 12 ) * lerpfrac;
2010-12-11 22:00:00 +01:00
RI.lightstylevalue[i] = (int)l * r_lighting_modulate->value;
}
}
2010-12-06 22:00:00 +01:00
/*
=============
R_MarkLights
=============
*/
void R_MarkLights( dlight_t *light, int bit, mnode_t *node )
2010-12-02 22:00:00 +01:00
{
2010-12-06 22:00:00 +01:00
float dist;
msurface_t *surf;
int i;
if( node->contents < 0 )
return;
2010-12-11 22:00:00 +01:00
dist = PlaneDiff( light->origin, node->plane );
2010-12-06 22:00:00 +01:00
if( dist > light->radius )
{
R_MarkLights( light, bit, node->children[0] );
return;
}
if( dist < -light->radius )
{
R_MarkLights( light, bit, node->children[1] );
return;
}
// mark the polygons
surf = cl.worldmodel->surfaces + node->firstsurface;
for( i = 0; i < node->numsurfaces; i++, surf++ )
{
if( surf->dlightframe != tr.dlightframecount )
{
surf->dlightbits = 0;
surf->dlightframe = tr.dlightframecount;
}
surf->dlightbits |= bit;
}
R_MarkLights( light, bit, node->children[0] );
R_MarkLights( light, bit, node->children[1] );
2010-12-02 22:00:00 +01:00
}
2010-12-06 22:00:00 +01:00
/*
=============
R_PushDlights
=============
*/
void R_PushDlights( void )
{
dlight_t *l;
int i;
tr.dlightframecount = tr.framecount + 1; // because the count hasn't
// advanced yet for this frame
l = cl_dlights;
for( i = 0; i < MAX_DLIGHTS; i++, l++ )
{
if( l->die < cl.time || !l->radius )
continue;
R_MarkLights( l, 1<<i, cl.worldmodel->nodes );
}
}
2010-12-16 22:00:00 +01:00
/*
=======================================================================
2011-03-03 22:00:00 +01:00
AMBIENT LIGHTING
2010-12-16 22:00:00 +01:00
=======================================================================
*/
static uint r_pointColor[3];
static vec3_t r_lightColors[MAXSTUDIOVERTS];
/*
=================
R_RecursiveLightPoint
=================
*/
static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3_t start, const vec3_t end )
{
float front, back, frac;
int i, map, side, size, s, t;
msurface_t *surf;
mtexinfo_t *tex;
color24 *lm;
vec3_t mid;
// didn't hit anything
if( node->contents < 0 )
return false;
// calculate mid point
front = PlaneDiff( start, node->plane );
back = PlaneDiff( end, node->plane );
side = front < 0;
if(( back < 0 ) == side )
return R_RecursiveLightPoint( model, node->children[side], start, end );
frac = front / ( front - back );
VectorLerp( start, frac, end, mid );
// co down front side
if( R_RecursiveLightPoint( model, node->children[side], start, mid ))
return true; // hit something
if(( back < 0 ) == side )
return false;// didn't hit anything
// check for impact on this node
surf = model->surfaces + node->firstsurface;
for( i = 0; i < node->numsurfaces; i++, surf++ )
{
tex = surf->texinfo;
2010-12-25 22:00:00 +01:00
if( surf->flags & ( SURF_DRAWSKY|SURF_DRAWTURB ))
2010-12-16 22:00:00 +01:00
continue; // no lightmaps
s = DotProduct( mid, tex->vecs[0] ) + tex->vecs[0][3] - surf->texturemins[0];
t = DotProduct( mid, tex->vecs[1] ) + tex->vecs[1][3] - surf->texturemins[1];
if(( s < 0 || s > surf->extents[0] ) || ( t < 0 || t > surf->extents[1] ))
continue;
s >>= 4;
t >>= 4;
if( !surf->samples )
return true;
VectorClear( r_pointColor );
lm = surf->samples + (t * ((surf->extents[0] >> 4) + 1) + s);
size = ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1);
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
{
uint scale = RI.lightstylevalue[surf->styles[map]];
r_pointColor[0] += lm->r * scale;
r_pointColor[1] += lm->g * scale;
r_pointColor[2] += lm->b * scale;
lm += size; // skip to next lightmap
}
return true;
}
// go down back side
return R_RecursiveLightPoint( model, node->children[!side], mid, end );
}
/*
=================
R_LightForPoint
=================
*/
2010-12-20 22:00:00 +01:00
void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLight, float radius )
2010-12-16 22:00:00 +01:00
{
2010-12-25 22:00:00 +01:00
dlight_t *dl;
pmtrace_t trace;
cl_entity_t *m_pGround;
2011-03-30 22:00:00 +02:00
vec3_t start, end, dir;
2010-12-25 22:00:00 +01:00
float dist, add;
model_t *pmodel;
mnode_t *pnodes;
if( !RI.refdef.movevars )
2010-12-16 22:00:00 +01:00
{
ambientLight->r = 255;
ambientLight->g = 255;
ambientLight->b = 255;
return;
}
2010-12-25 22:00:00 +01:00
// set to full bright if no light data
if( !cl.worldmodel || !cl.worldmodel->lightdata )
{
ambientLight->r = RI.refdef.movevars->skycolor_r;
ambientLight->g = RI.refdef.movevars->skycolor_g;
ambientLight->b = RI.refdef.movevars->skycolor_b;
return;
}
2010-12-16 22:00:00 +01:00
// Get lighting at this point
2011-03-30 22:00:00 +02:00
VectorCopy( point, start );
2010-12-16 22:00:00 +01:00
VectorCopy( point, end );
2011-03-30 22:00:00 +02:00
if( invLight )
{
start[2] = point[2] - 64;
end[2] = point[2] + 8192;
}
else
{
start[2] = point[2] + 64;
end[2] = point[2] - 8192;
}
2010-12-16 22:00:00 +01:00
2010-12-25 22:00:00 +01:00
// always have valid model
pmodel = cl.worldmodel;
pnodes = pmodel->nodes;
m_pGround = NULL;
2011-02-25 22:00:00 +01:00
if( r_lighting_extended->integer )
2010-12-25 22:00:00 +01:00
{
2011-03-30 22:00:00 +02:00
trace = PM_PlayerTrace( clgame.pmove, start, end, PM_STUDIO_IGNORE, 0, -1, NULL );
2010-12-25 22:00:00 +01:00
m_pGround = CL_GetEntityByIndex( pfnIndexFromTrace( &trace ));
}
2011-03-30 22:00:00 +02:00
if( m_pGround && m_pGround->model )
2010-12-25 22:00:00 +01:00
{
pmodel = m_pGround->model;
pnodes = &pmodel->nodes[pmodel->hulls[0].firstclipnode];
}
2010-12-16 22:00:00 +01:00
2011-03-03 22:00:00 +01:00
if( RI.isSkyVisible )
{
r_pointColor[0] = RI.refdef.movevars->skycolor_r;
r_pointColor[1] = RI.refdef.movevars->skycolor_g;
r_pointColor[2] = RI.refdef.movevars->skycolor_b;
}
else
{
VectorClear( r_pointColor );
}
2010-12-25 22:00:00 +01:00
2011-03-30 22:00:00 +02:00
if( R_RecursiveLightPoint( pmodel, pnodes, start, end ))
2010-12-25 22:00:00 +01:00
{
ambientLight->r = min((r_pointColor[0] >> 7), 255 );
ambientLight->g = min((r_pointColor[1] >> 7), 255 );
ambientLight->b = min((r_pointColor[2] >> 7), 255 );
}
else
{
2011-03-03 22:00:00 +01:00
float ambient;
// R_RecursiveLightPoint didn't hit anything, so use default value
ambient = bound( 0.1f, r_lighting_ambient->value, 1.0f );
ambientLight->r = 255 * ambient;
ambientLight->g = 255 * ambient;
ambientLight->b = 255 * ambient;
2010-12-25 22:00:00 +01:00
}
2010-12-16 22:00:00 +01:00
// add dynamic lights
2010-12-20 22:00:00 +01:00
if( radius && r_dynamic->integer )
2010-12-16 22:00:00 +01:00
{
2011-03-01 22:00:00 +01:00
int lnum, total;
float f;
VectorClear( r_pointColor );
for( total = lnum = 0, dl = cl_dlights; lnum < MAX_DLIGHTS; lnum++, dl++ )
2010-12-16 22:00:00 +01:00
{
if( dl->die < cl.time || !dl->radius )
continue;
VectorSubtract( dl->origin, point, dir );
dist = VectorLength( dir );
2010-12-20 22:00:00 +01:00
if( !dist || dist > dl->radius + radius )
2010-12-16 22:00:00 +01:00
continue;
2011-03-01 22:00:00 +01:00
add = 1.0f - (dist / ( dl->radius + radius ));
r_pointColor[0] += dl->color.r * add;
r_pointColor[1] += dl->color.g * add;
r_pointColor[2] += dl->color.b * add;
total++;
}
if( total != 0 )
{
r_pointColor[0] += ambientLight->r;
r_pointColor[1] += ambientLight->g;
r_pointColor[2] += ambientLight->b;
f = max( max( r_pointColor[0], r_pointColor[1] ), r_pointColor[2] );
if( f > 1.0f ) VectorScale( r_pointColor, ( 255.0f / f ), r_pointColor );
ambientLight->r = r_pointColor[0];
ambientLight->g = r_pointColor[1];
ambientLight->b = r_pointColor[2];
2010-12-16 22:00:00 +01:00
}
}
}
/*
=================
R_LightDir
=================
*/
void R_LightDir( const vec3_t origin, vec3_t lightDir, float radius )
{
dlight_t *dl;
vec3_t dir;
float dist;
int lnum;
2011-03-27 22:00:00 +02:00
if( RI.refdef.movevars )
2010-12-16 22:00:00 +01:00
{
2011-03-03 22:00:00 +01:00
// pre-defined light vector
lightDir[0] = RI.refdef.movevars->skyvec_x;
lightDir[1] = RI.refdef.movevars->skyvec_y;
lightDir[2] = RI.refdef.movevars->skyvec_z;
2010-12-16 22:00:00 +01:00
}
else
{
2011-03-27 22:00:00 +02:00
VectorSet( lightDir, 0.0f, 0.0f, -1.0f );
2010-12-16 22:00:00 +01:00
}
// add dynamic lights
2011-03-03 22:00:00 +01:00
if( radius > 0.0f && r_dynamic->integer )
2010-12-16 22:00:00 +01:00
{
for( lnum = 0, dl = cl_dlights; lnum < MAX_DLIGHTS; lnum++, dl++ )
{
if( dl->die < cl.time || !dl->radius )
continue;
2011-03-03 22:00:00 +01:00
VectorSubtract( dl->origin, origin, dir );
2010-12-16 22:00:00 +01:00
dist = VectorLength( dir );
if( !dist || dist > dl->radius + radius )
continue;
2011-03-03 22:00:00 +01:00
VectorAdd( lightDir, dir, lightDir );
2010-12-16 22:00:00 +01:00
}
2011-03-20 22:00:00 +01:00
for( lnum = 0, dl = cl_elights; lnum < MAX_ELIGHTS; lnum++, dl++ )
{
if( dl->die < cl.time || !dl->radius )
continue;
VectorSubtract( dl->origin, origin, dir );
dist = VectorLength( dir );
if( !dist || dist > dl->radius + radius )
continue;
VectorAdd( lightDir, dir, lightDir );
}
2010-12-16 22:00:00 +01:00
}
2011-03-03 22:00:00 +01:00
// normalize final direction
2011-03-20 22:00:00 +01:00
VectorNormalize( lightDir );
2010-12-02 22:00:00 +01:00
}