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

576 lines
14 KiB
C
Raw Normal View History

2011-05-09 22:00:00 +02:00
/*
gl_rlight.c - dynamic and static lights
Copyright (C) 2010 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
2010-12-02 22:00:00 +01:00
#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
/*
==================
2016-11-22 22:00:00 +01:00
CL_RunLightStyles
2010-12-11 22:00:00 +01:00
==================
*/
2016-11-22 22:00:00 +01:00
void CL_RunLightStyles( void )
2010-12-11 22:00:00 +01:00
{
int i, k, flight, clight;
2010-12-16 22:00:00 +01:00
float l, c, lerpfrac, backlerp;
2017-02-15 22:00:00 +01:00
float frametime = (cl.time - cl.oldtime);
2011-04-12 22:00:00 +02:00
float scale;
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;
2011-04-12 22:00:00 +02:00
scale = r_lighting_modulate->value;
2010-12-11 22:00:00 +01:00
// light animations
// 'm' is normal light, 'a' is no light, 'z' is double bright
for( i = 0, ls = cl.lightstyles; i < MAX_LIGHTSTYLES; i++, ls++ )
{
2017-02-12 22:00:00 +01:00
if( r_fullbright->value || !cl.worldmodel->lightdata )
2010-12-11 22:00:00 +01:00
{
2016-11-22 22:00:00 +01:00
tr.lightstylevalue[i] = 256 * 256;
tr.lightcache[i] = 3.0f;
2010-12-11 22:00:00 +01:00
continue;
}
2017-02-15 22:00:00 +01:00
if( !cl.paused && frametime <= 0.1f )
ls->time += frametime; // evaluate local time
2013-09-14 22:00:00 +02:00
2016-11-22 22:00:00 +01:00
flight = (int)Q_floor( ls->time * 10 );
clight = (int)Q_ceil( ls->time * 10 );
2013-09-14 22:00:00 +02:00
lerpfrac = ( ls->time * 10 ) - flight;
backlerp = 1.0f - lerpfrac;
2010-12-11 22:00:00 +01:00
if( !ls->length )
{
2016-11-22 22:00:00 +01:00
tr.lightstylevalue[i] = 256 * scale;
tr.lightcache[i] = 3.0f * scale;
2010-12-11 22:00:00 +01:00
continue;
}
else if( ls->length == 1 )
{
// single length style so don't bother interpolating
2016-11-22 22:00:00 +01:00
tr.lightstylevalue[i] = ls->map[0] * 22 * scale;
tr.lightcache[i] = ( ls->map[0] / 12.0f ) * 3.0f * scale;
2010-12-11 22:00:00 +01:00
continue;
}
2017-02-12 22:00:00 +01:00
else if( !ls->interp || !cl_lightstyle_lerping->value )
2010-12-11 22:00:00 +01:00
{
2016-11-22 22:00:00 +01:00
tr.lightstylevalue[i] = ls->map[flight%ls->length] * 22 * scale;
tr.lightcache[i] = ( ls->map[flight%ls->length] / 12.0f ) * 3.0f * scale;
2010-12-11 22:00:00 +01:00
continue;
}
// interpolate animating light
// frame just gone
k = ls->map[flight % ls->length];
2011-04-12 22:00:00 +02:00
l = (float)( k * 22.0f ) * backlerp;
c = (float)( k / 12.0f ) * backlerp;
2010-12-11 22:00:00 +01:00
// upcoming frame
k = ls->map[clight % ls->length];
2011-04-12 22:00:00 +02:00
l += (float)( k * 22.0f ) * lerpfrac;
c += (float)( k / 12.0f ) * lerpfrac;
2010-12-11 22:00:00 +01:00
2016-11-22 22:00:00 +01:00
tr.lightstylevalue[i] = (int)l * scale;
tr.lightcache[i] = c * 3.0f * scale;
2010-12-11 22:00:00 +01:00
}
}
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
2011-07-07 22:00:00 +02:00
surf = RI.currentmodel->surfaces + node->firstsurface;
2010-12-06 22:00:00 +01:00
for( i = 0; i < node->numsurfaces; i++, surf++ )
{
2011-07-07 22:00:00 +02:00
mextrasurf_t *info = SURF_INFO( surf, RI.currentmodel );
2011-04-12 22:00:00 +02:00
if( !BoundsAndSphereIntersect( info->mins, info->maxs, light->origin, light->radius ))
continue; // no intersection
2010-12-06 22:00:00 +01:00
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;
2011-08-14 22:00:00 +02:00
tr.dlightframecount = tr.framecount;
2010-12-06 22:00:00 +01:00
l = cl_dlights;
2011-07-07 22:00:00 +02:00
RI.currententity = clgame.entities;
RI.currentmodel = RI.currententity->model;
2010-12-06 22:00:00 +01:00
for( i = 0; i < MAX_DLIGHTS; i++, l++ )
{
if( l->die < cl.time || !l->radius )
continue;
2011-04-12 22:00:00 +02:00
if( R_CullSphere( l->origin, l->radius, 15 ))
continue;
2011-07-07 22:00:00 +02:00
R_MarkLights( l, 1<<i, RI.currentmodel->nodes );
2010-12-06 22:00:00 +01:00
}
}
2010-12-16 22:00:00 +01:00
2011-11-02 21:00:00 +01:00
/*
=============
R_CountDlights
=============
*/
int R_CountDlights( void )
{
dlight_t *l;
int i, numDlights = 0;
for( i = 0, l = cl_dlights; i < MAX_DLIGHTS; i++, l++ )
{
if( l->die < cl.time || !l->radius )
continue;
numDlights++;
}
return numDlights;
}
/*
=============
R_CountSurfaceDlights
=============
*/
int R_CountSurfaceDlights( msurface_t *surf )
{
int i, numDlights = 0;
2011-12-04 21:00:00 +01:00
for( i = 0; i < MAX_DLIGHTS; i++ )
2011-11-02 21:00:00 +01:00
{
if(!( surf->dlightbits & BIT( i )))
continue; // not lit by this light
numDlights++;
}
return numDlights;
}
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
=======================================================================
*/
2017-03-06 22:00:00 +01:00
static float g_trace_fraction;
static vec3_t g_trace_lightspot;
2010-12-16 22:00:00 +01:00
/*
=================
R_RecursiveLightPoint
=================
*/
2017-03-06 22:00:00 +01:00
static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, float p2f, colorVec *cv, const vec3_t start, const vec3_t end )
2010-12-16 22:00:00 +01:00
{
2017-03-06 22:00:00 +01:00
float front, back, frac, midf;
2010-12-16 22:00:00 +01:00
int i, map, side, size, s, t;
2016-11-28 22:00:00 +01:00
int sample_size;
2010-12-16 22:00:00 +01:00
msurface_t *surf;
mtexinfo_t *tex;
color24 *lm;
vec3_t mid;
// didn't hit anything
2011-03-31 22:00:00 +02:00
if( !node || node->contents < 0 )
2017-03-06 22:00:00 +01:00
{
cv->r = cv->g = cv->b = cv->a = 0;
2010-12-16 22:00:00 +01:00
return false;
2017-03-06 22:00:00 +01:00
}
2010-12-16 22:00:00 +01:00
// calculate mid point
front = PlaneDiff( start, node->plane );
back = PlaneDiff( end, node->plane );
side = front < 0;
if(( back < 0 ) == side )
2017-03-06 22:00:00 +01:00
return R_RecursiveLightPoint( model, node->children[side], p1f, p2f, cv, start, end );
2010-12-16 22:00:00 +01:00
frac = front / ( front - back );
VectorLerp( start, frac, end, mid );
2017-03-06 22:00:00 +01:00
midf = p1f + ( p2f - p1f ) * frac;
2010-12-16 22:00:00 +01:00
// co down front side
2017-03-06 22:00:00 +01:00
if( R_RecursiveLightPoint( model, node->children[side], p1f, midf, cv, start, mid ))
2010-12-16 22:00:00 +01:00
return true; // hit something
if(( back < 0 ) == side )
2017-03-06 22:00:00 +01:00
{
cv->r = cv->g = cv->b = cv->a = 0;
return false; // didn't hit anything
}
2011-08-14 22:00:00 +02:00
2010-12-16 22:00:00 +01:00
// check for impact on this node
surf = model->surfaces + node->firstsurface;
2016-11-28 22:00:00 +01:00
sample_size = Mod_SampleSizeForFace( surf );
2017-03-06 22:00:00 +01:00
VectorCopy( mid, g_trace_lightspot );
2010-12-16 22:00:00 +01:00
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;
2016-11-28 22:00:00 +01:00
s /= sample_size;
t /= sample_size;
2010-12-16 22:00:00 +01:00
2017-03-06 22:00:00 +01:00
cv->r = cv->g = cv->b = cv->a = 0;
2010-12-16 22:00:00 +01:00
if( !surf->samples )
return true;
2016-11-28 22:00:00 +01:00
lm = surf->samples + (t * ((surf->extents[0] / sample_size) + 1) + s);
2017-03-06 22:00:00 +01:00
size = ((surf->extents[0] / sample_size) + 1) * ((surf->extents[1] / sample_size) + 1);
g_trace_fraction = midf;
2010-12-16 22:00:00 +01:00
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
{
2016-11-22 22:00:00 +01:00
uint scale = tr.lightstylevalue[surf->styles[map]];
2010-12-16 22:00:00 +01:00
2017-03-07 22:00:00 +01:00
cv->r += LightToTexGamma( lm->r ) * scale;
cv->g += LightToTexGamma( lm->g ) * scale;
cv->b += LightToTexGamma( lm->b ) * scale;
2010-12-16 22:00:00 +01:00
lm += size; // skip to next lightmap
}
2017-03-06 22:00:00 +01:00
2010-12-16 22:00:00 +01:00
return true;
}
// go down back side
2017-03-06 22:00:00 +01:00
return R_RecursiveLightPoint( model, node->children[!side], midf, p2f, cv, mid, end );
2010-12-16 22:00:00 +01:00
}
2012-02-11 21:00:00 +01:00
int R_LightTraceFilter( physent_t *pe )
{
2012-06-25 22:00:00 +02:00
if( !pe || pe->solid != SOLID_BSP || pe->info == 0 )
2012-02-11 21:00:00 +01:00
return 1;
return 0;
}
2010-12-16 22:00:00 +01:00
/*
=================
R_LightForPoint
=================
*/
2011-07-07 22:00:00 +02:00
void R_LightForPoint( const vec3_t point, color24 *ambientLight, qboolean invLight, qboolean useAmbient, float radius )
2010-12-16 22:00:00 +01:00
{
2010-12-25 22:00:00 +01:00
dlight_t *dl;
pmtrace_t trace;
2017-03-06 22:00:00 +01:00
colorVec light;
2010-12-25 22:00:00 +01:00
cl_entity_t *m_pGround;
2011-03-30 22:00:00 +02:00
vec3_t start, end, dir;
2012-06-25 22:00:00 +02:00
qboolean secondpass = false;
2010-12-25 22:00:00 +01:00
float dist, add;
model_t *pmodel;
mnode_t *pnodes;
// set to full bright if no light data
if( !cl.worldmodel || !cl.worldmodel->lightdata )
{
2017-03-07 22:00:00 +01:00
ambientLight->r = LightToTexGamma( clgame.movevars.skycolor_r );
ambientLight->g = LightToTexGamma( clgame.movevars.skycolor_g );
ambientLight->b = LightToTexGamma( clgame.movevars.skycolor_b );
2010-12-25 22:00:00 +01:00
return;
}
2012-06-25 22:00:00 +02:00
get_light:
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 )
{
2012-12-18 21:00:00 +01:00
start[2] = point[2] - 64.0f;
end[2] = point[2] + world.size[2];
2011-03-30 22:00:00 +02:00
}
else
{
2012-12-18 21:00:00 +01:00
start[2] = point[2] + 64.0f;
end[2] = point[2] - world.size[2];
2011-03-30 22:00:00 +02:00
}
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;
2017-02-12 22:00:00 +01:00
if( r_lighting_extended->value && !secondpass )
2010-12-25 22:00:00 +01:00
{
2012-02-11 21:00:00 +01:00
CL_SetTraceHull( 2 );
CL_PlayerTraceExt( start, end, PM_STUDIO_IGNORE, R_LightTraceFilter, &trace );
2010-12-25 22:00:00 +01:00
m_pGround = CL_GetEntityByIndex( pfnIndexFromTrace( &trace ));
2012-06-25 22:00:00 +02:00
if( trace.startsolid || trace.allsolid ) m_pGround = NULL; // trace in solid
2010-12-25 22:00:00 +01:00
}
2012-02-11 21:00:00 +01:00
if( m_pGround && m_pGround->model && m_pGround->model->type == mod_brush )
2010-12-25 22:00:00 +01:00
{
2011-04-09 22:00:00 +02:00
matrix4x4 matrix;
hull_t *hull;
vec3_t start_l, end_l;
vec3_t offset;
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-04-09 22:00:00 +02:00
hull = &pmodel->hulls[0];
VectorSubtract( hull->clip_mins, vec3_origin, offset );
VectorAdd( offset, m_pGround->origin, offset );
VectorSubtract( start, offset, start_l );
VectorSubtract( end, offset, end_l );
// rotate start and end into the models frame of reference
if( !VectorIsNull( m_pGround->angles ))
{
Matrix4x4_CreateFromEntity( matrix, m_pGround->angles, offset, 1.0f );
2011-12-09 21:00:00 +01:00
Matrix4x4_VectorITransform( matrix, start, start_l );
Matrix4x4_VectorITransform( matrix, end, end_l );
2011-04-09 22:00:00 +02:00
}
// copy transformed pos back
VectorCopy( start_l, start );
VectorCopy( end_l, end );
2011-03-03 22:00:00 +01:00
}
2010-12-25 22:00:00 +01:00
2017-03-06 22:00:00 +01:00
if( R_RecursiveLightPoint( pmodel, pnodes, 0.0f, 1.0f, &light, start, end ))
2010-12-25 22:00:00 +01:00
{
2017-03-06 22:00:00 +01:00
ambientLight->r = Q_min(( light.r >> 7 ), 255 );
ambientLight->g = Q_min(( light.g >> 7 ), 255 );
ambientLight->b = Q_min(( light.b >> 7 ), 255 );
2010-12-25 22:00:00 +01:00
}
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 );
2011-07-07 22:00:00 +02:00
if( !useAmbient ) ambient = 0.0f; // clear ambient
2011-03-03 22:00:00 +01:00
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
2012-06-25 22:00:00 +02:00
if( ambientLight->r == 0 && ambientLight->g == 0 && ambientLight->b == 0 && !secondpass )
{
// in some cases r_lighting_extended 1 does a wrong results
// make another pass and try to get lighting info from world
secondpass = true;
goto get_light;
}
2010-12-16 22:00:00 +01:00
// add dynamic lights
2017-02-12 22:00:00 +01:00
if( radius && r_dynamic->value )
2010-12-16 22:00:00 +01:00
{
2011-03-01 22:00:00 +01:00
int lnum, total;
float f;
2017-03-06 22:00:00 +01:00
light.r = light.g = light.b = light.a = 0;
2011-03-01 22:00:00 +01:00
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 ));
2017-03-07 22:00:00 +01:00
light.r += LightToTexGamma( dl->color.r ) * add;
light.g += LightToTexGamma( dl->color.g ) * add;
light.b += LightToTexGamma( dl->color.b ) * add;
2011-03-01 22:00:00 +01:00
total++;
}
if( total != 0 )
{
2017-03-06 22:00:00 +01:00
light.r += ambientLight->r;
light.g += ambientLight->g;
light.b += ambientLight->b;
f = max( max( light.r, light.g ), light.b );
if( f > 1.0f )
{
light.r *= (255.0f / f);
light.r *= (255.0f / f);
light.r *= ( 255.0f / f);
}
ambientLight->r = light.r;
ambientLight->g = light.g;
ambientLight->b = light.b;
2010-12-16 22:00:00 +01:00
}
}
}
2011-08-14 22:00:00 +02:00
/*
=================
2017-03-06 22:00:00 +01:00
R_LightVec
2011-08-14 22:00:00 +02:00
2017-03-06 22:00:00 +01:00
check bspmodels to get light from
2011-08-14 22:00:00 +02:00
=================
*/
2017-03-06 22:00:00 +01:00
colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lspot )
2011-08-14 22:00:00 +02:00
{
2017-03-06 22:00:00 +01:00
float last_fraction;
int i, maxEnts = 1;
colorVec light, cv;
2012-02-11 21:00:00 +01:00
2017-03-06 22:00:00 +01:00
if( cl.worldmodel->lightdata )
2010-12-16 22:00:00 +01:00
{
2017-03-06 22:00:00 +01:00
light.r = light.b = light.b = light.a = 0;
last_fraction = 1.0f;
2010-12-16 22:00:00 +01:00
2017-03-06 22:00:00 +01:00
// get light from bmodels too
if( r_lighting_extended->value )
maxEnts = clgame.pmove->numphysent;
2010-12-16 22:00:00 +01:00
2017-03-06 22:00:00 +01:00
// check al the bsp-models
for( i = 0; i < maxEnts; i++ )
2011-03-20 22:00:00 +01:00
{
2017-03-06 22:00:00 +01:00
physent_t *pe = &clgame.pmove->physents[i];
vec3_t offset, start_l, end_l;
mnode_t *pnodes;
matrix4x4 matrix;
if( !pe->model || pe->model->type != mod_brush )
continue; // skip non-bsp models
pnodes = &pe->model->nodes[pe->model->hulls[0].firstclipnode];
VectorSubtract( pe->model->hulls[0].clip_mins, vec3_origin, offset );
VectorAdd( offset, pe->origin, offset );
VectorSubtract( start, offset, start_l );
VectorSubtract( end, offset, end_l );
// rotate start and end into the models frame of reference
if( !VectorIsNull( pe->angles ))
{
Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
Matrix4x4_VectorITransform( matrix, start, start_l );
Matrix4x4_VectorITransform( matrix, end, end_l );
}
VectorClear( g_trace_lightspot );
g_trace_fraction = 1.0f;
if( !R_RecursiveLightPoint( pe->model, pnodes, 0.0f, 1.0f, &cv, start_l, end_l ))
continue; // didn't hit anything
if( g_trace_fraction < last_fraction )
{
if( lspot ) VectorCopy( g_trace_lightspot, lspot );
light.r = Q_min(( cv.r >> 7 ), 255 );
light.g = Q_min(( cv.g >> 7 ), 255 );
light.b = Q_min(( cv.b >> 7 ), 255 );
last_fraction = g_trace_fraction;
}
2011-03-20 22:00:00 +01:00
}
2010-12-16 22:00:00 +01:00
}
2017-03-06 22:00:00 +01:00
else
{
light.r = light.g = light.b = 255;
light.a = 0;
}
return light;
2017-03-07 22:00:00 +01:00
}
/*
=================
R_LightPoint
light from floor
=================
*/
colorVec R_LightPoint( const vec3_t p0 )
{
vec3_t p1;
VectorSet( p1, p0[0], p0[1], p0[2] - 2048.0f );
return R_LightVec( p0, p1, NULL );
2010-12-02 22:00:00 +01:00
}