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/vid_gl/r_light.c

1027 lines
24 KiB
C
Raw Normal View History

2009-07-12 22:00:00 +02:00
/*
Copyright (C) 1997-2001 Id Software, Inc.
Copyright (C) 2002-2007 Victor Luchits
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
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 2
of the License, or (at your option) any later version.
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
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.
2008-11-17 22:00:00 +01:00
2009-07-12 22:00:00 +02:00
See the GNU General Public License for more details.
2008-11-17 22:00:00 +01:00
2009-07-12 22:00:00 +02:00
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2008-11-17 22:00:00 +01:00
2009-07-12 22:00:00 +02:00
*/
2008-11-17 22:00:00 +01:00
2009-07-12 22:00:00 +02:00
// r_light.c
#include "r_local.h"
#include "mathlib.h"
2009-08-07 22:00:00 +02:00
#include "matrix_lib.h"
2008-11-17 22:00:00 +01:00
2008-08-25 22:00:00 +02:00
/*
2009-07-12 22:00:00 +02:00
=============================================================================
2008-08-25 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
DYNAMIC LIGHTS
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
=============================================================================
2008-08-25 22:00:00 +02:00
*/
2009-07-12 22:00:00 +02:00
2010-05-22 22:00:00 +02:00
/*
=============
R_RecursiveLightNode
=============
*/
void R_RecursiveLightNode( dlight_t *light, int bit, mnode_t *node )
{
float dist;
msurface_t *surf;
cplane_t *splitplane;
int i, sidebit;
2010-06-01 22:00:00 +02:00
if( !node->plane ) return;
2010-05-22 22:00:00 +02:00
splitplane = node->plane;
if( splitplane->type < 3 ) dist = light->origin[splitplane->type] - splitplane->dist;
else dist = DotProduct( light->origin, splitplane->normal ) - splitplane->dist;
if( dist > light->intensity )
{
R_RecursiveLightNode( light, bit, node->children[0] );
return;
}
if( dist < -light->intensity )
{
R_RecursiveLightNode( light, bit, node->children[1] );
return;
}
// mark the polygons
surf = node->firstface;
for( i = 0; i < node->numfaces; i++, surf++ )
{
if( surf->plane->type < 3 ) dist = light->origin[surf->plane->type] - surf->plane->dist;
else dist = DotProduct( light->origin, surf->plane->normal ) - surf->plane->dist;
if( dist >= 0 ) sidebit = 0;
else sidebit = SURF_PLANEBACK;
if(( surf->flags & SURF_PLANEBACK ) != sidebit )
continue;
if( surf->dlightFrame != r_framecount )
{
surf->dlightBits = bit; // was 0
surf->dlightFrame = r_framecount;
}
else surf->dlightBits |= bit;
}
R_RecursiveLightNode( light, bit, node->children[0] );
R_RecursiveLightNode( light, bit, node->children[1] );
}
2008-11-10 22:00:00 +01:00
/*
2009-07-12 22:00:00 +02:00
=============
R_SurfPotentiallyLit
=============
2008-11-10 22:00:00 +01:00
*/
2009-07-12 22:00:00 +02:00
bool R_SurfPotentiallyLit( msurface_t *surf )
2008-11-10 22:00:00 +01:00
{
2009-07-12 22:00:00 +02:00
ref_shader_t *shader;
2008-11-10 22:00:00 +01:00
2010-05-22 22:00:00 +02:00
if( surf->flags & ( SURF_DRAWSKY|SURF_DRAWTURB ))
return false;
if( !surf->samples )
2009-07-12 22:00:00 +02:00
return false;
2008-11-10 22:00:00 +01:00
2009-07-12 22:00:00 +02:00
shader = surf->shader;
2009-07-29 22:00:00 +02:00
if( shader->flags & SHADER_SKYPARMS || shader->type == SHADER_FLARE || !shader->num_stages )
2009-07-12 22:00:00 +02:00
return false;
2008-11-10 22:00:00 +01:00
2010-05-22 22:00:00 +02:00
return true;
2009-07-12 22:00:00 +02:00
}
2008-11-10 22:00:00 +01:00
2009-07-12 22:00:00 +02:00
/*
=============
R_LightBounds
=============
*/
void R_LightBounds( const vec3_t origin, float intensity, vec3_t mins, vec3_t maxs )
{
2010-05-22 22:00:00 +02:00
VectorSet( mins, origin[0] - intensity, origin[1] - intensity, origin[2] - intensity );
VectorSet( maxs, origin[0] + intensity, origin[1] + intensity, origin[2] + intensity );
}
/*
=================
R_MarkLights
=================
*/
void R_MarkLights( uint clipflags )
{
dlight_t *dl;
int l;
if( !r_dynamiclight->integer || !r_numDlights )
return;
for( l = 0, dl = r_dlights; l < r_numDlights; l++, dl++ )
{
if( R_CullSphere( dl->origin, dl->intensity, clipflags ))
continue;
R_RecursiveLightNode( dl, BIT( l ), r_worldbrushmodel->nodes );
}
2009-07-12 22:00:00 +02:00
}
2008-11-10 22:00:00 +01:00
2009-07-12 22:00:00 +02:00
//===================================================================
static ref_shader_t *r_coronaShader;
/*
=================
R_InitCoronas
=================
*/
void R_InitCoronas( void )
{
2009-07-27 22:00:00 +02:00
r_coronaShader = R_LoadShader( "*corona", SHADER_FLARE, true, TF_NOMIPMAP|TF_NOPICMIP|TF_UNCOMPRESSED|TF_CLAMP, SHADER_INVALID );
2008-08-25 22:00:00 +02:00
}
/*
=================
2009-07-12 22:00:00 +02:00
R_DrawCoronas
2008-08-25 22:00:00 +02:00
=================
*/
2009-07-12 22:00:00 +02:00
void R_DrawCoronas( void )
2008-08-25 22:00:00 +02:00
{
2009-10-28 22:00:00 +01:00
uint i;
float dist;
dlight_t *light;
meshbuffer_t *mb;
2009-11-02 22:00:00 +01:00
trace_t tr;
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
if( r_dynamiclight->integer != 2 )
2008-10-19 22:00:00 +02:00
return;
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
for( i = 0, light = r_dlights; i < r_numDlights; i++, light++ )
2008-10-19 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
dist = RI.vpn[0] * ( light->origin[0] - RI.viewOrigin[0] ) +
2009-07-12 22:00:00 +02:00
RI.vpn[1] * ( light->origin[1] - RI.viewOrigin[1] ) +
RI.vpn[2] * ( light->origin[2] - RI.viewOrigin[2] );
2010-05-31 22:00:00 +02:00
if( dist < 24.0f ) continue;
2009-07-12 22:00:00 +02:00
dist -= light->intensity;
2008-08-25 22:00:00 +02:00
2010-05-22 22:00:00 +02:00
R_TraceLine( &tr, light->origin, RI.viewOrigin );
2009-10-28 22:00:00 +01:00
if( tr.flFraction != 1.0f )
2009-07-12 22:00:00 +02:00
continue;
2009-10-28 22:00:00 +01:00
mb = R_AddMeshToList( MB_CORONA, NULL, r_coronaShader, -((signed int)i + 1 ));
2010-05-31 22:00:00 +02:00
if( mb ) mb->shaderkey |= ( bound( 1, 0x4000 - (uint)dist, 0x4000 - 1 ) << 12 );
2008-08-25 22:00:00 +02:00
}
}
2009-07-12 22:00:00 +02:00
//===================================================================
2008-08-25 22:00:00 +02:00
/*
2009-07-12 22:00:00 +02:00
===============
R_LightForOrigin
===============
2008-08-25 22:00:00 +02:00
*/
2009-07-12 22:00:00 +02:00
void R_LightForOrigin( const vec3_t origin, vec3_t dir, vec4_t ambient, vec4_t diffuse, float radius )
2008-08-25 22:00:00 +02:00
{
2009-08-17 22:00:00 +02:00
int i, j;
int k, s;
float dot, t[8];
vec3_t vf, vf2, tdir;
2009-09-01 22:00:00 +02:00
int vi[3], elem[4];
2009-08-17 22:00:00 +02:00
vec3_t ambientLocal, diffuseLocal;
vec_t *gridSize, *gridMins;
int *gridBounds;
mgridlight_t **lightarray;
2008-10-19 22:00:00 +02:00
2009-08-17 22:00:00 +02:00
if( !r_worldmodel || !r_worldbrushmodel->lightgrid || !r_worldbrushmodel->numlightgridelems )
2008-08-25 22:00:00 +02:00
{
2009-09-28 22:00:00 +02:00
// get fullbright
2010-03-06 22:00:00 +01:00
VectorSet( ambientLocal, 255, 255, 255 );
VectorSet( diffuseLocal, 255, 255, 255 );
2009-07-12 22:00:00 +02:00
VectorSet( dir, 0.5f, 0.2f, -1.0f );
goto dynamic;
2008-08-25 22:00:00 +02:00
}
2009-09-28 22:00:00 +02:00
else
{
VectorSet( ambientLocal, 0, 0, 0 );
VectorSet( diffuseLocal, 0, 0, 0 );
}
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
lightarray = r_worldbrushmodel->lightarray;
gridSize = r_worldbrushmodel->gridSize;
gridMins = r_worldbrushmodel->gridMins;
gridBounds = r_worldbrushmodel->gridBounds;
2008-08-25 22:00:00 +02:00
for( i = 0; i < 3; i++ )
{
2009-07-12 22:00:00 +02:00
vf[i] = ( origin[i] - gridMins[i] ) / gridSize[i];
vi[i] = (int)vf[i];
vf[i] = vf[i] - floor( vf[i] );
vf2[i] = 1.0f - vf[i];
2008-08-25 22:00:00 +02:00
}
2009-07-12 22:00:00 +02:00
elem[0] = vi[2] * gridBounds[3] + vi[1] * gridBounds[0] + vi[0];
elem[1] = elem[0] + gridBounds[0];
elem[2] = elem[0] + gridBounds[3];
elem[3] = elem[2] + gridBounds[0];
2008-08-25 22:00:00 +02:00
for( i = 0; i < 4; i++ )
{
2009-09-01 22:00:00 +02:00
if( elem[i] < 0 || elem[i] >= ( r_worldbrushmodel->numlightarrayelems - 1 ))
2008-08-25 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
VectorSet( dir, 0.5f, 0.2f, -1.0f );
goto dynamic;
2008-08-25 22:00:00 +02:00
}
}
2009-07-12 22:00:00 +02:00
t[0] = vf2[0] * vf2[1] * vf2[2];
t[1] = vf[0] * vf2[1] * vf2[2];
t[2] = vf2[0] * vf[1] * vf2[2];
t[3] = vf[0] * vf[1] * vf2[2];
t[4] = vf2[0] * vf2[1] * vf[2];
t[5] = vf[0] * vf2[1] * vf[2];
t[6] = vf2[0] * vf[1] * vf[2];
t[7] = vf[0] * vf[1] * vf[2];
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
VectorClear( dir );
2008-08-25 22:00:00 +02:00
for( i = 0; i < 4; i++ )
{
2009-07-12 22:00:00 +02:00
R_LatLongToNorm( lightarray[elem[i]]->direction, tdir );
VectorScale( tdir, t[i *2], tdir );
for( k = 0; k < LM_STYLES && ( s = lightarray[elem[i]]->styles[k] ) != 255; k++ )
2008-08-25 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
dir[0] += r_lightStyles[s].rgb[0] * tdir[0];
dir[1] += r_lightStyles[s].rgb[1] * tdir[1];
dir[2] += r_lightStyles[s].rgb[2] * tdir[2];
2008-08-25 22:00:00 +02:00
}
2008-10-19 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
R_LatLongToNorm( lightarray[elem[i] + 1]->direction, tdir );
VectorScale( tdir, t[i *2+1], tdir );
for( k = 0; k < LM_STYLES && ( s = lightarray[elem[i] + 1]->styles[k] ) != 255; k++ )
2008-08-25 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
dir[0] += r_lightStyles[s].rgb[0] * tdir[0];
dir[1] += r_lightStyles[s].rgb[1] * tdir[1];
dir[2] += r_lightStyles[s].rgb[2] * tdir[2];
2008-10-12 22:00:00 +02:00
}
2008-10-19 22:00:00 +02:00
}
2009-07-12 22:00:00 +02:00
for( j = 0; j < 3; j++ )
2008-10-19 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
if( ambient )
2008-10-12 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
for( i = 0; i < 4; i++ )
{
for( k = 0; k < LM_STYLES; k++ )
{
if( ( s = lightarray[elem[i]]->styles[k] ) != 255 )
ambientLocal[j] += t[i*2] * lightarray[elem[i]]->ambient[k][j] * r_lightStyles[s].rgb[j];
if( ( s = lightarray[elem[i] + 1]->styles[k] ) != 255 )
ambientLocal[j] += t[i*2+1] * lightarray[elem[i] + 1]->ambient[k][j] * r_lightStyles[s].rgb[j];
}
}
}
if( diffuse || radius )
{
for( i = 0; i < 4; i++ )
{
for( k = 0; k < LM_STYLES; k++ )
{
if( ( s = lightarray[elem[i]]->styles[k] ) != 255 )
diffuseLocal[j] += t[i*2] * lightarray[elem[i]]->diffuse[k][j] * r_lightStyles[s].rgb[j];
if( ( s = lightarray[elem[i] + 1]->styles[k] ) != 255 )
diffuseLocal[j] += t[i*2+1] * lightarray[elem[i] + 1]->diffuse[k][j] * r_lightStyles[s].rgb[j];
}
}
2008-08-25 22:00:00 +02:00
}
}
2009-07-12 22:00:00 +02:00
dynamic:
2008-08-25 22:00:00 +02:00
// add dynamic lights
2009-07-12 22:00:00 +02:00
if( radius && r_dynamiclight->integer && r_numDlights )
2008-08-25 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
unsigned int lnum;
dlight_t *dl;
float dist, dist2, add;
vec3_t direction;
bool anyDlights = false;
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
for( lnum = 0, dl = r_dlights; lnum < r_numDlights; lnum++, dl++ )
2008-08-25 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
if( !BoundsAndSphereIntersect( dl->mins, dl->maxs, origin, radius ) )
continue;
VectorSubtract( dl->origin, origin, direction );
dist = VectorLength( direction );
2008-08-25 22:00:00 +02:00
if( !dist || dist > dl->intensity + radius )
continue;
2009-07-12 22:00:00 +02:00
if( !anyDlights )
{
VectorNormalizeFast( dir );
anyDlights = true;
}
2010-03-15 22:00:00 +01:00
add = 1.0f - (dist / (dl->intensity + radius));
dist2 = add * 0.5f / dist;
2009-07-12 22:00:00 +02:00
for( i = 0; i < 3; i++ )
{
dot = dl->color[i] * add;
diffuseLocal[i] += dot;
ambientLocal[i] += dot * 0.05;
dir[i] += direction[i] * dist2;
}
2008-08-25 22:00:00 +02:00
}
}
2009-07-12 22:00:00 +02:00
VectorNormalizeFast( dir );
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
if( ambient )
2008-08-25 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
dot = bound( 0.0f, r_lighting_ambientscale->value, 1.0f ) * ( 1 << mapConfig.pow2MapOvrbr ) * ( 1.0 / 255.0 );
for( i = 0; i < 3; i++ )
{
ambient[i] = ambientLocal[i] * dot;
ambient[i] = bound( 0, ambient[i], 1 );
}
ambient[3] = 1.0f;
2008-08-25 22:00:00 +02:00
}
2009-07-12 22:00:00 +02:00
if( diffuse )
2008-10-19 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
dot = bound( 0.0f, r_lighting_directedscale->value, 1.0f ) * ( 1 << mapConfig.pow2MapOvrbr ) * ( 1.0 / 255.0 );
for( i = 0; i < 3; i++ )
2008-10-19 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
diffuse[i] = diffuseLocal[i] * dot;
diffuse[i] = bound( 0, diffuse[i], 1 );
2008-10-19 22:00:00 +02:00
}
2009-07-12 22:00:00 +02:00
diffuse[3] = 1.0f;
2008-10-19 22:00:00 +02:00
}
2009-07-12 22:00:00 +02:00
}
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
/*
===============
R_LightForEntity
===============
*/
void R_LightForEntity( ref_entity_t *e, byte *bArray )
{
2009-11-29 22:00:00 +01:00
dlight_t *dl;
uint i, lnum;
uint dlightbits;
float dot, dist;
vec3_t lightDirs[MAX_DLIGHTS], direction, temp;
vec4_t ambient, diffuse;
2009-07-12 22:00:00 +02:00
2009-08-04 22:00:00 +02:00
if(( e->flags & EF_FULLBRIGHT ) || r_fullbright->value )
2009-07-12 22:00:00 +02:00
return;
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
// probably weird shader, see mpteam4 for example
2009-08-04 22:00:00 +02:00
if( !e->model || ( e->model->type == mod_brush ) || (e->model->type == mod_world ))
2009-07-12 22:00:00 +02:00
return;
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
R_LightForOrigin( e->lightingOrigin, temp, ambient, diffuse, 0 );
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
if( e->flags & EF_MINLIGHT )
2008-08-25 22:00:00 +02:00
{
2008-10-19 22:00:00 +02:00
for( i = 0; i < 3; i++ )
2009-09-06 22:00:00 +02:00
if( ambient[i] > 0.01 )
2008-10-19 22:00:00 +02:00
break;
2009-07-12 22:00:00 +02:00
if( i == 3 )
2009-09-06 22:00:00 +02:00
VectorSet( ambient, 0.01f, 0.01f, 0.01f );
2008-08-25 22:00:00 +02:00
}
2009-07-12 22:00:00 +02:00
// rotate direction
2009-08-07 22:00:00 +02:00
Matrix3x3_Transform( e->axis, temp, direction );
2008-10-12 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
// see if we are affected by dynamic lights
dlightbits = 0;
if( r_dynamiclight->integer == 1 && r_numDlights )
2008-10-19 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
for( lnum = 0, dl = r_dlights; lnum < r_numDlights; lnum++, dl++ )
2008-08-25 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
// translate
VectorSubtract( dl->origin, e->origin, lightDirs[lnum] );
dist = VectorLength( lightDirs[lnum] );
if( !dist || dist > dl->intensity + e->model->radius * e->scale )
continue;
dlightbits |= ( 1<<lnum );
2008-08-25 22:00:00 +02:00
}
}
2009-07-12 22:00:00 +02:00
if( !dlightbits )
2008-10-19 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
vec3_t color;
2008-10-12 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
for( i = 0; i < r_backacc.numColors; i++, bArray += 4 )
2008-10-12 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
dot = DotProduct( normalsArray[i], direction );
if( dot <= 0 )
VectorCopy( ambient, color );
else
VectorMA( ambient, dot, diffuse, color );
bArray[0] = R_FloatToByte( color[0] );
bArray[1] = R_FloatToByte( color[1] );
bArray[2] = R_FloatToByte( color[2] );
}
}
else
{
float add, intensity8, dot, *cArray, *dir;
vec3_t dlorigin, tempColorsArray[MAX_ARRAY_VERTS];
cArray = tempColorsArray[0];
for( i = 0; i < r_backacc.numColors; i++, cArray += 3 )
{
dot = DotProduct( normalsArray[i], direction );
if( dot <= 0 )
VectorCopy( ambient, cArray );
else
VectorMA( ambient, dot, diffuse, cArray );
}
for( lnum = 0, dl = r_dlights; lnum < r_numDlights; lnum++, dl++ )
{
if( !( dlightbits & ( 1<<lnum ) ) )
2008-08-25 22:00:00 +02:00
continue;
2009-07-12 22:00:00 +02:00
// translate
dir = lightDirs[lnum];
// rotate
2009-08-07 22:00:00 +02:00
Matrix3x3_Transform( e->axis, dir, dlorigin );
2009-07-12 22:00:00 +02:00
intensity8 = dl->intensity * 8 * e->scale;
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
cArray = tempColorsArray[0];
for( i = 0; i < r_backacc.numColors; i++, cArray += 3 )
2008-08-25 22:00:00 +02:00
{
2009-07-12 22:00:00 +02:00
VectorSubtract( dlorigin, vertsArray[i], dir );
add = DotProduct( normalsArray[i], dir );
2008-08-25 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
if( add > 0 )
{
dot = DotProduct( dir, dir );
2009-08-07 22:00:00 +02:00
add *= ( intensity8 / dot ) * rsqrt( dot );
2009-07-12 22:00:00 +02:00
VectorMA( cArray, add, dl->color, cArray );
}
2008-08-25 22:00:00 +02:00
}
}
2008-10-19 22:00:00 +02:00
2009-07-12 22:00:00 +02:00
cArray = tempColorsArray[0];
for( i = 0; i < r_backacc.numColors; i++, bArray += 4, cArray += 3 )
{
bArray[0] = R_FloatToByte( cArray[0] );
bArray[1] = R_FloatToByte( cArray[1] );
bArray[2] = R_FloatToByte( cArray[2] );
}
}
2008-08-25 22:00:00 +02:00
}
/*
2010-05-31 22:00:00 +02:00
=======================================================================
2008-10-19 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
LIGHT SAMPLING
2008-08-25 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
=======================================================================
*/
2010-06-01 22:00:00 +02:00
static vec3_t r_blockLights[LIGHTMAP_TEXTURE_WIDTH*LIGHTMAP_TEXTURE_HEIGHT];
2010-05-31 22:00:00 +02:00
/*
=================
R_SetCacheState
=================
2008-08-25 22:00:00 +02:00
*/
2010-05-31 22:00:00 +02:00
static void R_SetCacheState( msurface_t *surf )
{
int map;
2008-08-25 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
for( map = 0; map < surf->numstyles; map++ )
surf->cached[map] = r_lightStyles[surf->styles[map]].white;
}
2008-10-19 22:00:00 +02:00
/*
2010-05-31 22:00:00 +02:00
=================
R_AddDynamicLights
=================
2008-10-19 22:00:00 +02:00
*/
2010-05-31 22:00:00 +02:00
static void R_AddDynamicLights( msurface_t *surf )
2008-10-19 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
int l, s, t, sd, td;
float sl, tl, sacc, tacc;
float dist, rad, scale;
vec3_t origin, tmp, impact;
mtexinfo_t *tex = surf->texinfo;
ref_entity_t *e = RI.currententity;
cplane_t *plane;
dlight_t *dl;
float *bl;
2010-06-01 22:00:00 +02:00
// invalid entity ?
if( !e ) return;
2010-05-31 22:00:00 +02:00
for (l = 0, dl = r_dlights; l < r_numDlights; l++, dl++ )
{
if( !( surf->dlightBits & ( 1<<l )))
continue; // not lit by this light
if( !Matrix3x3_Compare( e->axis, matrix3x3_identity ))
{
VectorSubtract( dl->origin, e->origin, tmp );
Matrix3x3_Transform( e->axis, tmp, origin );
}
else VectorSubtract( dl->origin, e->origin, origin );
2008-10-19 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
plane = surf->plane;
if( plane->type < 3 )
dist = origin[plane->type] - plane->dist;
else dist = DotProduct( origin, plane->normal ) - plane->dist;
// rad is now the highest intensity on the plane
rad = dl->intensity - fabs( dist );
if( rad < 0.0f ) continue;
if( plane->type < 3 )
2008-08-25 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
VectorCopy( origin, impact );
impact[plane->type] -= dist;
2008-08-25 22:00:00 +02:00
}
2010-05-31 22:00:00 +02:00
else VectorMA( origin, -dist, plane->normal, impact );
2010-06-01 22:00:00 +02:00
sl = DotProduct( impact, tex->vecs[0] ) + tex->vecs[0][3] - surf->textureMins[0];
tl = DotProduct( impact, tex->vecs[1] ) + tex->vecs[1][3] - surf->textureMins[1];
2010-05-31 22:00:00 +02:00
bl = (float *)r_blockLights;
2010-06-01 22:00:00 +02:00
for( t = 0, tacc = 0; t < surf->lmHeight; t++, tacc += LM_SAMPLE_SIZE )
2008-08-25 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
td = tl - tacc;
if( td < 0 ) td = -td;
2010-06-01 22:00:00 +02:00
for( s = 0, sacc = 0; s < surf->lmWidth; s++, sacc += LM_SAMPLE_SIZE )
2010-05-31 22:00:00 +02:00
{
sd = sl - sacc;
if( sd < 0 ) sd = -sd;
if( sd > td ) dist = sd + (td >> 1);
else dist = td + (sd >> 1);
if( dist < rad )
{
scale = rad - dist;
bl[0] += dl->color[0] * scale;
bl[1] += dl->color[1] * scale;
bl[2] += dl->color[2] * scale;
}
bl += 3;
}
2008-08-25 22:00:00 +02:00
}
2009-07-12 22:00:00 +02:00
}
2010-05-31 22:00:00 +02:00
}
/*
=================
R_BuildLightmap
combine and scale multiple lightmaps into the
floating format in r_blockLights
=================
*/
static void R_BuildLightmap( msurface_t *surf, byte *dest, int stride )
{
int i, map, size, s, t;
byte *lm;
vec3_t scale;
float *bl, max;
lm = surf->samples;
size = surf->lmWidth * surf->lmHeight;
2008-08-25 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
if( !lm )
2009-07-12 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
// set to full bright if no light data
for( i = 0, bl = (float *)r_blockLights; i < size; i++, bl += 3 )
{
bl[0] = 255;
bl[1] = 255;
bl[2] = 255;
}
2009-07-12 22:00:00 +02:00
}
else
{
2010-05-31 22:00:00 +02:00
// add all the lightmaps
VectorScale( r_lightStyles[surf->styles[0]].rgb, r_lighting_modulate->value, scale );
2008-10-19 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
for( i = 0, bl = (float *)r_blockLights; i < size; i++, bl += 3, lm += 3 )
{
bl[0] = lm[0] * scale[0];
bl[1] = lm[1] * scale[1];
bl[2] = lm[2] * scale[2];
}
if( surf->numstyles > 1 )
2008-08-25 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
for( map = 1; map < surf->numstyles; map++ )
2008-08-25 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
VectorScale( r_lightStyles[surf->styles[map]].rgb, r_lighting_modulate->value, scale );
2008-08-25 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
for( i = 0, bl = (float *)r_blockLights; i < size; i++, bl += 3, lm += 3 )
2008-08-25 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
bl[0] += lm[0] * scale[0];
bl[1] += lm[1] * scale[1];
bl[2] += lm[2] * scale[2];
2008-08-25 22:00:00 +02:00
}
2009-07-12 22:00:00 +02:00
}
}
2010-05-31 22:00:00 +02:00
// add all the dynamic lights
if( surf->dlightFrame == r_framecount )
R_AddDynamicLights( surf );
2009-07-12 22:00:00 +02:00
}
2010-05-31 22:00:00 +02:00
// put into texture format
stride -= (surf->lmWidth << 2);
bl = (float *)r_blockLights;
for( t = 0; t < surf->lmHeight; t++ )
2009-07-12 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
for( s = 0; s < surf->lmWidth; s++ )
2009-07-12 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
// catch negative lights
if( bl[0] < 0.0f ) bl[0] = 0.0f;
if( bl[1] < 0.0f ) bl[1] = 0.0f;
if( bl[2] < 0.0f ) bl[2] = 0.0f;
// Determine the brightest of the three color components
max = VectorMax( bl );
// rescale all the color components if the intensity of the
// greatest channel exceeds 255
if( max > 255.0f )
{
max = 255.0f / max;
dest[0] = bl[0] * max;
dest[1] = bl[1] * max;
dest[2] = bl[2] * max;
dest[3] = 255;
}
else
2009-07-12 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
dest[0] = bl[0];
dest[1] = bl[1];
dest[2] = bl[2];
dest[3] = 255;
2008-08-25 22:00:00 +02:00
}
2010-05-31 22:00:00 +02:00
bl += 3;
dest += 4;
2008-08-25 22:00:00 +02:00
}
2010-05-31 22:00:00 +02:00
dest += stride;
2008-08-25 22:00:00 +02:00
}
}
2010-06-01 22:00:00 +02:00
/*
=======================================================================
LIGHTSTYLE HANDLING
=======================================================================
*/
/*
=======================
R_AddSuperLightStyle
=======================
*/
int R_AddSuperLightStyle( const int lightmapNum, const byte *lightmapStyles )
{
int i, j;
ref_style_t *sls;
for( i = 0, sls = tr.superLightStyles; i < tr.numSuperLightStyles; i++, sls++ )
{
if( sls->lightmapNum != lightmapNum )
continue;
for( j = 0; j < LM_STYLES; j++ )
{
if( sls->lightmapStyles[j] != lightmapStyles[j] )
break;
}
if( j == LM_STYLES )
return i;
}
if( tr.numSuperLightStyles == MAX_SUPER_STYLES )
Host_Error( "R_AddSuperLightStyle: MAX_SUPERSTYLES limit exceeded\n" );
// create new style
sls->features = 0;
sls->lightmapNum = lightmapNum;
for( j = 0; j < LM_STYLES; j++ )
{
sls->lightmapStyles[j] = lightmapStyles[j];
if( j )
{
if( lightmapStyles[j] != 255 )
sls->features |= ( MF_LMCOORDS << j );
}
}
return tr.numSuperLightStyles++;
}
/*
=======================
R_SuperLightStylesCmp
Compare function for qsort
=======================
*/
static int R_SuperLightStylesCmp( ref_style_t *sls1, ref_style_t *sls2 )
{
int i;
if( sls2->lightmapNum > sls1->lightmapNum )
return 1;
else if( sls1->lightmapNum > sls2->lightmapNum )
return -1;
for( i = 0; i < LM_STYLES; i++ )
{
// compare lightmap styles
if( sls2->lightmapStyles[i] > sls1->lightmapStyles[i] )
return 1;
else if( sls1->lightmapStyles[i] > sls2->lightmapStyles[i] )
return -1;
}
return 0; // equal
}
/*
=======================
R_SortSuperLightStyles
=======================
*/
void R_SortSuperLightStyles( void )
{
qsort( tr.superLightStyles, tr.numSuperLightStyles, sizeof( ref_style_t ), ( int ( * )( const void *, const void * ))R_SuperLightStylesCmp );
}
2008-08-25 22:00:00 +02:00
/*
2010-05-31 22:00:00 +02:00
=======================================================================
LIGHTMAP ALLOCATION
=======================================================================
2008-08-25 22:00:00 +02:00
*/
2010-05-31 22:00:00 +02:00
typedef struct
2008-08-25 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
int glFormat;
int currentNum;
int allocated[LIGHTMAP_TEXTURE_WIDTH];
byte buffer[LIGHTMAP_TEXTURE_WIDTH*LIGHTMAP_TEXTURE_HEIGHT*4];
} lmState_t;
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
static lmState_t r_lmState;
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
/*
=================
R_UploadLightmap
=================
*/
static void R_UploadLightmap( void )
{
string lmName;
rgbdata_t r_image;
texture_t *image;
2009-07-12 22:00:00 +02:00
2010-06-01 22:00:00 +02:00
if( r_lmState.currentNum == MAX_LIGHTMAPS - 1 )
2010-05-31 22:00:00 +02:00
Host_Error( "R_UploadLightmap: MAX_LIGHTMAPS limit exceeded\n" );
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
com.snprintf( lmName, sizeof( lmName ), "*lightmap%i", r_lmState.currentNum );
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
Mem_Set( &r_image, 0, sizeof( r_image ));
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
r_image.width = LIGHTMAP_TEXTURE_WIDTH;
r_image.height = LIGHTMAP_TEXTURE_HEIGHT;
2010-06-01 22:00:00 +02:00
r_image.type = PF_RGBA_GN;
2010-05-31 22:00:00 +02:00
r_image.size = r_image.width * r_image.height * 4;
r_image.depth = r_image.numMips = 1;
r_image.flags = IMAGE_HAS_COLOR; // FIXME: detecting grayscale lightmaps for quake1
r_image.buffer = r_lmState.buffer;
2009-07-12 22:00:00 +02:00
2010-06-01 22:00:00 +02:00
image = R_LoadTexture( lmName, &r_image, 4, TF_LIGHTMAP|TF_NOPICMIP|TF_UNCOMPRESSED|TF_CLAMP|TF_NOMIPMAP );
2010-05-31 22:00:00 +02:00
tr.lightmapTextures[r_lmState.currentNum++] = image;
r_lmState.glFormat = image->format;
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
// reset
Mem_Set( r_lmState.allocated, 0, sizeof( r_lmState.allocated ));
Mem_Set( r_lmState.buffer, 255, sizeof( r_lmState.buffer ));
}
2008-10-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
/*
=================
R_AllocLightmapBlock
=================
*/
static byte *R_AllocLightmapBlock( int width, int height, int *s, int *t )
{
int i, j;
int best1, best2;
2008-10-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
best1 = LIGHTMAP_TEXTURE_HEIGHT;
2008-10-19 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
for( i = 0; i < LIGHTMAP_TEXTURE_WIDTH - width; i++ )
2009-07-12 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
best2 = 0;
2008-08-25 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
for( j = 0; j < width; j++ )
2008-10-19 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
if( r_lmState.allocated[i+j] >= best1 )
break;
if( r_lmState.allocated[i+j] > best2 )
best2 = r_lmState.allocated[i+j];
}
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
if( j == width )
{
// this is a valid spot
*s = i;
*t = best1 = best2;
2008-10-19 22:00:00 +02:00
}
2008-08-25 22:00:00 +02:00
}
2010-05-31 22:00:00 +02:00
if( best1 + height > LIGHTMAP_TEXTURE_HEIGHT )
return NULL;
2008-10-19 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
for( i = 0; i < width; i++ )
r_lmState.allocated[*s + i] = best1 + height;
2008-10-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
return r_lmState.buffer + (( *t * LIGHTMAP_TEXTURE_WIDTH + *s ) * 4 );
2009-07-12 22:00:00 +02:00
}
2008-10-12 22:00:00 +02:00
2008-11-10 22:00:00 +01:00
/*
2010-05-31 22:00:00 +02:00
=================
R_BeginBuildingLightmaps
=================
2008-11-10 22:00:00 +01:00
*/
2010-05-31 22:00:00 +02:00
void R_BeginBuildingLightmaps( void )
2008-11-10 22:00:00 +01:00
{
2010-05-31 22:00:00 +02:00
int i;
2008-11-10 22:00:00 +01:00
2010-05-31 22:00:00 +02:00
// setup the base lightstyles so the lightmaps won't have to be
// regenerated the first time they're seen
for( i = 0; i < MAX_LIGHTSTYLES; i++ )
2009-07-12 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
r_lightStyles[i].white = 3;
r_lightStyles[i].rgb[0] = 1;
r_lightStyles[i].rgb[1] = 1;
r_lightStyles[i].rgb[2] = 1;
2009-07-12 22:00:00 +02:00
}
2008-11-10 22:00:00 +01:00
2010-05-31 22:00:00 +02:00
// release old lightmaps
for( i = 0; i < r_lmState.currentNum; i++ )
2008-11-10 22:00:00 +01:00
{
2010-06-01 22:00:00 +02:00
if( tr.lightmapTextures[i] && tr.lightmapTextures[i] != tr.dlightTexture )
R_FreeImage( tr.lightmapTextures[i] );
2008-11-10 22:00:00 +01:00
}
2010-05-31 22:00:00 +02:00
r_lmState.currentNum = -1;
2008-11-10 22:00:00 +01:00
2010-05-31 22:00:00 +02:00
Mem_Set( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
Mem_Set( r_lmState.allocated, 0, sizeof( r_lmState.allocated ));
Mem_Set( r_lmState.buffer, 255, sizeof( r_lmState.buffer ));
2010-06-01 22:00:00 +02:00
tr.lightmapTextures[DLIGHT_TEXTURE] = tr.dlightTexture;
2008-11-10 22:00:00 +01:00
}
2008-08-25 22:00:00 +02:00
/*
2010-05-31 22:00:00 +02:00
=================
R_EndBuildingLightmaps
=================
2009-07-12 22:00:00 +02:00
*/
2010-05-31 22:00:00 +02:00
void R_EndBuildingLightmaps( void )
{
if( r_lmState.currentNum == -1 )
return;
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
R_UploadLightmap();
}
2009-07-12 22:00:00 +02:00
/*
2010-05-31 22:00:00 +02:00
=================
R_BuildSurfaceLightmap
=================
2008-08-25 22:00:00 +02:00
*/
2010-05-31 22:00:00 +02:00
void R_BuildSurfaceLightmap( msurface_t *surf )
2008-08-25 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
byte *base;
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
if( !( surf->shader->flags & SHADER_HASLIGHTMAP ))
return; // no lightmaps
base = R_AllocLightmapBlock( surf->lmWidth, surf->lmHeight, &surf->lmS, &surf->lmT );
if( !base )
2008-08-25 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
if( r_lmState.currentNum != -1 ) R_UploadLightmap();
base = R_AllocLightmapBlock( surf->lmWidth, surf->lmHeight, &surf->lmS, &surf->lmT );
if( !base ) Host_Error( "AllocBlock: full\n" );
2008-08-25 22:00:00 +02:00
}
2010-05-31 22:00:00 +02:00
if( r_lmState.currentNum == -1 )
r_lmState.currentNum = 0;
surf->lmNum = r_lmState.currentNum;
surf->lightmapTexnum = -1;
surf->lightmapFrame = r_framecount - 1;
R_SetCacheState( surf );
R_BuildLightmap( surf, base, LIGHTMAP_TEXTURE_WIDTH * 4 );
2008-08-25 22:00:00 +02:00
}
/*
2010-05-31 22:00:00 +02:00
=================
R_UpdateSurfaceLightmap
=================
2008-08-25 22:00:00 +02:00
*/
2010-05-31 22:00:00 +02:00
void R_UpdateSurfaceLightmap( msurface_t *surf )
2008-08-25 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
int map;
2008-08-25 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
Com_Assert( surf == NULL );
2008-08-25 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
// Don't attempt a surface more than once a frame
// FIXME: This is just a nasty work-around at best
if( surf->lightmapFrame == r_framecount )
return;
surf->lightmapFrame = r_framecount;
2008-10-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
// is this surface allowed to have a lightmap?
if( surf->flags & ( SURF_DRAWSKY|SURF_DRAWTURB ))
2008-11-10 22:00:00 +01:00
{
2010-05-31 22:00:00 +02:00
surf->lightmapTexnum = -1;
return;
}
2008-11-10 22:00:00 +01:00
2010-05-31 22:00:00 +02:00
// dynamic this frame or dynamic previously
if( r_dynamiclight->integer )
{
for( map = 0; map < surf->numstyles; map++ )
2009-07-12 22:00:00 +02:00
{
2010-05-31 22:00:00 +02:00
if( r_lightStyles[surf->styles[map]].white != surf->cached[map] )
goto update_lightmap;
2009-07-12 22:00:00 +02:00
}
2008-11-10 22:00:00 +01:00
2010-05-31 22:00:00 +02:00
if( surf->dlightFrame == r_framecount )
goto update_lightmap;
2009-07-12 22:00:00 +02:00
}
2008-10-19 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
// no need to update
surf->lightmapTexnum = surf->lmNum;
return;
2008-08-25 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
update_lightmap:
// update texture
R_BuildLightmap( surf, r_lmState.buffer, surf->lmWidth * 4 );
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
if(( surf->styles[map] >= 32 || surf->styles[map] == 0 ) && surf->dlightFrame != r_framecount )
{
R_SetCacheState( surf );
2009-07-12 22:00:00 +02:00
2010-05-31 22:00:00 +02:00
GL_Bind( 0, tr.lightmapTextures[surf->lmNum] );
surf->lightmapTexnum = surf->lmNum;
2008-10-19 22:00:00 +02:00
}
2010-05-31 22:00:00 +02:00
else
{
2010-06-01 22:00:00 +02:00
GL_Bind( 0, tr.dlightTexture );
surf->lightmapTexnum = DLIGHT_TEXTURE;
2009-07-12 22:00:00 +02:00
}
2010-05-31 22:00:00 +02:00
pglTexSubImage2D( GL_TEXTURE_2D, 0, surf->lmS, surf->lmT, surf->lmWidth, surf->lmHeight,
r_lmState.glFormat, GL_UNSIGNED_BYTE, r_lmState.buffer );
}