2005-02-28 07:16:19 +00:00
# include "quakedef.h"
2004-09-08 13:34:51 +00:00
# ifdef RUNTIMELIGHTING
2015-04-14 23:12:17 +00:00
typedef struct mentity_s {
vec3_t origin ;
float light ;
float angle ;
float cone ;
int style ;
vec3_t colour ;
char classname [ 64 ] ;
char target [ 64 ] ;
char targetname [ 64 ] ;
int targetentnum ;
} mentity_t ;
struct relight_ctx_s
{
unsigned int nummodels ;
2020-02-11 18:06:10 +00:00
model_t * models [ 2048 ] ; //0 is the worldmodel and must be valid
qboolean parsed ; //ents have been parsed okay.
qboolean loaded ; //needed models are all loaded.
2015-04-14 23:12:17 +00:00
2021-08-09 23:06:23 +00:00
double starttime ;
2019-08-03 01:58:03 +00:00
float minlight ;
2017-03-06 14:06:12 +00:00
qboolean skiplit ; //lux only
2015-04-14 23:12:17 +00:00
qboolean shadows ;
mentity_t * entities ;
unsigned int num_entities ;
unsigned int max_entities ;
2020-02-11 18:06:10 +00:00
size_t lightmapsamples ;
unsigned long nextface ;
2015-04-14 23:12:17 +00:00
} ;
2004-09-08 13:34:51 +00:00
# define bsptexinfo(i) (*i)
# define dsurfedges lightmodel->surfedges
# define dvertexes lightmodel->vertexes
# define dedges lightmodel->edges
# define texinfo_t mtexinfo_t
# define Q_PI M_PI
# define dfaces lightmodel->surfaces
# define dplanes lightmodel->planes
# define dface_t msurface_t
# define dvertex_t mvertex_t
# define side flags & SURF_PLANEBACK
# define scaledist 1
# define rangescale 0.5
2019-08-03 01:58:03 +00:00
# define extrasamples 1
2004-09-08 13:34:51 +00:00
# define scalecos 0.5
# define bsp_origin vec3_origin
/*
= = = = = = = = = = = =
CastRay
Returns the distance between the points , or - 1 if blocked
= = = = = = = = = = = = =
*/
2015-04-14 23:12:17 +00:00
static vec_t CastRay ( struct relight_ctx_s * ctx , vec3_t p1 , vec3_t p2 )
2004-09-08 13:34:51 +00:00
{
trace_t trace ;
vec3_t move ;
2015-04-14 23:12:17 +00:00
if ( ctx - > shadows )
{
2017-01-29 13:10:53 +00:00
ctx - > models [ 0 ] - > funcs . NativeTrace ( ctx - > models [ 0 ] , 0 , NULLFRAMESTATE , NULL , p1 , p2 , vec3_origin , vec3_origin , false , FTECONTENTS_SOLID , & trace ) ;
2015-04-14 23:12:17 +00:00
if ( trace . fraction < 1 )
return - 1 ;
}
2005-07-16 00:53:08 +00:00
2004-09-08 13:34:51 +00:00
VectorSubtract ( p1 , p2 , move ) ;
return VectorLength ( move ) ;
}
static void ParseEpair ( mentity_t * mapent , char * key , char * value )
{
double vec [ 3 ] ;
if ( ! strcmp ( key , " classname " ) )
strcpy ( mapent - > classname , value ) ;
else if ( ! strcmp ( key , " target " ) )
strcpy ( mapent - > target , value ) ;
else if ( ! strcmp ( key , " targetname " ) )
strcpy ( mapent - > targetname , value ) ;
else if ( ! strcmp ( key , " light " ) | | ! strcmp ( key , " _light " ) )
mapent - > light = atoi ( value ) ;
else if ( ! strcmp ( key , " style " ) | | ! strcmp ( key , " _style " ) )
mapent - > style = atoi ( value ) ;
else if ( ! strcmp ( key , " angle " ) | | ! strcmp ( key , " _angle " ) )
mapent - > angle = atof ( value ) ;
else if ( ! strcmp ( key , " cone " ) | | ! strcmp ( key , " _cone " ) )
mapent - > cone = atof ( value ) ;
else if ( ! strcmp ( key , " origin " ) )
{
sscanf ( value , " %lf %lf %lf " , & vec [ 0 ] , & vec [ 1 ] , & vec [ 2 ] ) ;
mapent - > origin [ 0 ] = vec [ 0 ] ;
mapent - > origin [ 1 ] = vec [ 1 ] ;
mapent - > origin [ 2 ] = vec [ 2 ] ;
}
else if ( ! strcmp ( key , " colour " ) | | ! strcmp ( key , " color " ) | | ! strcmp ( key , " _colour " ) | | ! strcmp ( key , " _color " ) )
{
sscanf ( value , " %lf %lf %lf " , & vec [ 0 ] , & vec [ 1 ] , & vec [ 2 ] ) ;
mapent - > colour [ 0 ] = vec [ 0 ] ;
mapent - > colour [ 1 ] = vec [ 1 ] ;
mapent - > colour [ 2 ] = vec [ 2 ] ;
}
}
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
void LightShutdown ( struct relight_ctx_s * ctx , model_t * model )
2015-04-14 23:12:17 +00:00
{
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
unsigned int u ;
for ( u = 0 ; u < ctx - > nummodels ; u + + )
if ( ctx - > models [ u ] = = model )
{
if ( u < ctx - > nummodels - 1 ) //swap it out.
ctx - > models [ u ] = ctx - > models [ ctx - > nummodels - 1 ] ;
ctx - > nummodels - = 1 ;
if ( ctx - > nummodels )
return ; //other models still refer to it!
Z_Free ( ctx - > entities ) ;
Z_Free ( ctx ) ;
break ;
}
2015-04-14 23:12:17 +00:00
}
2017-03-06 14:06:12 +00:00
struct relight_ctx_s * LightStartup ( struct relight_ctx_s * ctx , model_t * model , qboolean shadows , qboolean skiplit )
2015-04-14 23:12:17 +00:00
{
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
unsigned int u ;
2015-04-14 23:12:17 +00:00
if ( ! ctx )
{
ctx = Z_Malloc ( sizeof ( * ctx ) ) ;
ctx - > shadows = shadows ;
2017-03-06 14:06:12 +00:00
ctx - > skiplit = skiplit ;
2015-04-14 23:12:17 +00:00
}
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
for ( u = 0 ; u < ctx - > nummodels ; u + + )
if ( ctx - > models [ u ] = = model )
break ;
if ( u = = ctx - > nummodels )
if ( ctx - > nummodels < countof ( ctx - > models ) )
ctx - > models [ ctx - > nummodels + + ] = model ;
2021-08-09 23:06:23 +00:00
ctx - > starttime = Sys_DoubleTime ( ) ;
2015-04-14 23:12:17 +00:00
return ctx ;
}
2016-11-25 08:14:54 +00:00
void LightReloadEntities ( struct relight_ctx_s * ctx , const char * entstring , qboolean ignorestyles )
2004-09-08 13:34:51 +00:00
{
# define DEFAULTLIGHTLEVEL 300
mentity_t * mapent ;
char key [ 1024 ] ;
2015-03-03 00:14:43 +00:00
char value [ 1024 ] ;
2004-09-08 13:34:51 +00:00
int i ;
int switchedstyle = 32 ;
2015-04-14 23:12:17 +00:00
ctx - > num_entities = 0 ;
2004-09-08 13:34:51 +00:00
while ( 1 )
{
2015-03-03 00:14:43 +00:00
entstring = COM_ParseOut ( entstring , key , sizeof ( key ) ) ;
if ( ! entstring | | ! * key )
2004-09-08 13:34:51 +00:00
break ;
2015-03-03 00:14:43 +00:00
if ( strcmp ( key , " { " ) )
2005-08-11 04:14:33 +00:00
{ //someone messed up. Stop parsing.
Con_Printf ( " token wasn't an open brace \n " ) ;
break ;
}
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
if ( ctx - > num_entities = = ctx - > max_entities )
{
ctx - > max_entities = ctx - > max_entities + 128 ;
ctx - > entities = BZ_Realloc ( ctx - > entities , sizeof ( * ctx - > entities ) * ctx - > max_entities ) ;
}
mapent = & ctx - > entities [ ctx - > num_entities ] ;
2004-09-08 13:34:51 +00:00
memset ( mapent , 0 , sizeof ( * mapent ) ) ;
mapent - > colour [ 0 ] = 0 ;
mapent - > colour [ 1 ] = 0 ;
mapent - > colour [ 2 ] = 0 ;
2015-04-14 23:12:17 +00:00
mapent - > targetentnum = - 1 ;
2015-09-06 03:30:28 +00:00
while ( entstring )
2004-09-08 13:34:51 +00:00
{
2015-03-03 00:14:43 +00:00
entstring = COM_ParseOut ( entstring , key , sizeof ( key ) ) ;
if ( ! strcmp ( key , " } " ) )
2004-09-08 13:34:51 +00:00
break ;
2015-03-03 00:14:43 +00:00
entstring = COM_ParseOut ( entstring , value , sizeof ( value ) ) ;
ParseEpair ( mapent , key , value ) ;
2004-09-08 13:34:51 +00:00
}
if ( ! mapent - > colour [ 0 ] & & ! mapent - > colour [ 1 ] & & ! mapent - > colour [ 2 ] )
{
int cont ;
vec3_t v ;
v [ 0 ] = mapent - > origin [ 0 ] ;
v [ 1 ] = mapent - > origin [ 1 ] ;
cont = 0 ;
for ( i = 0 ; i < 256 ; i + = 16 )
{
v [ 2 ] = mapent - > origin [ 2 ] - i ;
2015-04-14 23:12:17 +00:00
cont = ctx - > models [ 0 ] - > funcs . PointContents ( ctx - > models [ 0 ] , NULL , v ) ;
2004-09-08 13:34:51 +00:00
if ( cont & ( FTECONTENTS_LAVA | FTECONTENTS_SLIME | FTECONTENTS_SOLID ) )
break ;
}
if ( cont & FTECONTENTS_LAVA )
{
mapent - > colour [ 0 ] = 1 ;
mapent - > colour [ 1 ] = i / 256.0 ;
mapent - > colour [ 2 ] = i / 256.0 ;
}
else if ( cont & FTECONTENTS_SLIME )
{
mapent - > colour [ 0 ] = 0.5 + 0.5 * i / 256.0 ;
mapent - > colour [ 1 ] = 1 ;
mapent - > colour [ 2 ] = 0.5 + 0.5 * i / 256.0 ;
}
else
{
if ( mapent - > style = = 9 ) //hmm..
{
mapent - > colour [ 1 ] = 1 ;
}
else
{
if ( ! strncmp ( mapent - > classname , " light_torch_small_walltorch " , 12 ) )
{
mapent - > colour [ 0 ] = 1 ;
mapent - > colour [ 1 ] = 0.7 ;
mapent - > colour [ 2 ] = 0.7 ;
}
else
{
mapent - > colour [ 0 ] = 1 ;
mapent - > colour [ 1 ] = 1 ;
if ( strncmp ( mapent - > classname , " light_fluoro " , 12 ) )
mapent - > colour [ 2 ] = 1 ;
}
}
}
}
if ( ! mapent - > light & & ! strncmp ( mapent - > classname , " light " , 5 ) )
mapent - > light = DEFAULTLIGHTLEVEL ;
if ( * mapent - > targetname & & ! mapent - > style & & ! strcmp ( mapent - > classname , " light " ) )
{
2015-04-14 23:12:17 +00:00
for ( i = 0 ; i < = ctx - > num_entities ; i + + )
2004-09-08 13:34:51 +00:00
{
2015-04-14 23:12:17 +00:00
if ( ctx - > entities [ i ] . style > = 32 & & ! strcmp ( ctx - > entities [ i ] . targetname , mapent - > targetname ) )
2004-09-08 13:34:51 +00:00
{
2015-04-14 23:12:17 +00:00
mapent - > style = ctx - > entities [ i ] . style ;
2004-09-08 13:34:51 +00:00
break ;
}
}
2015-04-14 23:12:17 +00:00
if ( i = = ctx - > num_entities )
2004-09-08 13:34:51 +00:00
mapent - > style = switchedstyle + + ;
}
2015-09-18 20:30:10 +00:00
if ( ignorestyles )
mapent - > style = 0 ;
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
ctx - > num_entities + + ;
2004-09-08 13:34:51 +00:00
}
2019-08-03 01:58:03 +00:00
if ( ctx - > num_entities )
if ( ctx - > entities [ 0 ] . light )
ctx - > minlight = ctx - > entities [ 0 ] . light ;
2015-04-14 23:12:17 +00:00
for ( mapent = ctx - > entities ; mapent < & ctx - > entities [ ctx - > num_entities ] ; mapent + + )
2004-09-08 13:34:51 +00:00
{
if ( * mapent - > target )
{
2015-04-14 23:12:17 +00:00
for ( i = 0 ; i < ctx - > num_entities ; i + + )
2004-09-08 13:34:51 +00:00
{
2015-04-14 23:12:17 +00:00
if ( mapent = = & ctx - > entities [ i ] )
2004-09-08 13:34:51 +00:00
continue ;
2015-04-14 23:12:17 +00:00
if ( ! strcmp ( mapent - > target , ctx - > entities [ i ] . targetname ) )
2004-09-08 13:34:51 +00:00
{
2015-04-14 23:12:17 +00:00
mapent - > targetentnum = i ;
2004-09-08 13:34:51 +00:00
break ;
}
}
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
SAMPLE POINT DETERMINATION
void SetupBlock ( dface_t * f ) Returns with surfpt [ ] set
This is a little tricky because the lightmap covers more area than the face .
If done in the straightforward fashion , some of the
sample points will be inside walls or on the other side of walls , causing
false shadows and light bleeds .
To solve this , I only consider a sample point valid if a line can be drawn
between it and the exact midpoint of the face . If invalid , it is adjusted
towards the center until it is valid .
( this doesn ' t completely work )
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2015-04-14 23:12:17 +00:00
# define MAXIMUMEXTENT 128
# define SINGLEMAP (MAXIMUMEXTENT*MAXIMUMEXTENT*4)
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
typedef struct llightinfo_s
2004-09-08 13:34:51 +00:00
{
2015-04-14 23:12:17 +00:00
struct relight_ctx_s * ctx ; //relight context, shared between threads.
2020-03-25 21:29:30 +00:00
vec3_t lightmaps [ MAXCPULIGHTMAPS ] [ SINGLEMAP ] ;
vec3_t lightnorm [ MAXCPULIGHTMAPS ] [ SINGLEMAP ] ;
2004-09-08 13:34:51 +00:00
int numlightstyles ;
vec_t * light ;
vec_t facedist ;
vec3_t facenormal ;
int numsurfpt ;
vec3_t surfpt [ SINGLEMAP ] ;
vec3_t texorg ;
vec3_t worldtotex [ 2 ] ; // s = (world - texorg) . worldtotex[0]
vec3_t textoworld [ 2 ] ; // world = texorg + s * textoworld[0]
vec_t exactmins [ 2 ] , exactmaxs [ 2 ] ;
int texmins [ 2 ] , texsize [ 2 ] ;
2020-03-25 21:29:30 +00:00
int lightstyles [ MAXCPULIGHTMAPS ] ;
2004-09-08 13:34:51 +00:00
} llightinfo_t ;
2015-04-14 23:12:17 +00:00
const size_t lightthreadctxsize = sizeof ( llightinfo_t ) ;
2004-09-08 13:34:51 +00:00
/*
= = = = = = = = = = = = = = = =
CalcFaceVectors
Fills in texorg , worldtotex . and textoworld
= = = = = = = = = = = = = = = =
*/
2015-04-14 23:12:17 +00:00
static void LightCalcFaceVectors ( llightinfo_t * l , vec4_t surf_texplanes [ 2 ] )
2004-09-08 13:34:51 +00:00
{
int i , j ;
vec3_t texnormal ;
float distscale ;
vec_t dist , len ;
// convert from float to vec_t
for ( i = 0 ; i < 2 ; i + + )
for ( j = 0 ; j < 3 ; j + + )
2015-04-14 23:12:17 +00:00
l - > worldtotex [ i ] [ j ] = surf_texplanes [ i ] [ j ] ;
2004-09-08 13:34:51 +00:00
// calculate a normal to the texture axis. points can be moved along this
// without changing their S/T
2015-04-14 23:12:17 +00:00
texnormal [ 0 ] = surf_texplanes [ 1 ] [ 1 ] * surf_texplanes [ 0 ] [ 2 ]
- surf_texplanes [ 1 ] [ 2 ] * surf_texplanes [ 0 ] [ 1 ] ;
texnormal [ 1 ] = surf_texplanes [ 1 ] [ 2 ] * surf_texplanes [ 0 ] [ 0 ]
- surf_texplanes [ 1 ] [ 0 ] * surf_texplanes [ 0 ] [ 2 ] ;
texnormal [ 2 ] = surf_texplanes [ 1 ] [ 0 ] * surf_texplanes [ 0 ] [ 1 ]
- surf_texplanes [ 1 ] [ 1 ] * surf_texplanes [ 0 ] [ 0 ] ;
2004-09-08 13:34:51 +00:00
VectorNormalize ( texnormal ) ;
// flip it towards plane normal
distscale = DotProduct ( texnormal , l - > facenormal ) ;
if ( ! distscale )
2015-04-14 23:12:17 +00:00
{
VectorCopy ( l - > facenormal , texnormal ) ;
distscale = 1 ;
Con_Printf ( " Texture axis perpendicular to face \n " ) ;
}
2004-09-08 13:34:51 +00:00
if ( distscale < 0 )
{
distscale = - distscale ;
2006-05-29 04:50:24 +00:00
VectorNegate ( texnormal , texnormal ) ;
2004-09-08 13:34:51 +00:00
}
// distscale is the ratio of the distance along the texture normal to
// the distance along the plane normal
distscale = 1 / distscale ;
for ( i = 0 ; i < 2 ; i + + )
{
len = VectorLength ( l - > worldtotex [ i ] ) ;
dist = DotProduct ( l - > worldtotex [ i ] , l - > facenormal ) ;
dist * = distscale ;
VectorMA ( l - > worldtotex [ i ] , - dist , texnormal , l - > textoworld [ i ] ) ;
VectorScale ( l - > textoworld [ i ] , ( 1 / len ) * ( 1 / len ) , l - > textoworld [ i ] ) ;
}
// calculate texorg on the texture plane
for ( i = 0 ; i < 3 ; i + + )
2015-04-14 23:12:17 +00:00
l - > texorg [ i ] = - surf_texplanes [ 0 ] [ 3 ] * l - > textoworld [ 0 ] [ i ] - surf_texplanes [ 1 ] [ 3 ] * l - > textoworld [ 1 ] [ i ] ;
2004-09-08 13:34:51 +00:00
// project back to the face plane
dist = DotProduct ( l - > texorg , l - > facenormal ) - l - > facedist - 1 ;
dist * = distscale ;
VectorMA ( l - > texorg , - dist , texnormal , l - > texorg ) ;
}
/*
= = = = = = = = = = = = = = = =
CalcFaceExtents
Fills in s - > texmins [ ] and s - > texsize [ ]
also sets exactmins [ ] and exactmaxs [ ]
= = = = = = = = = = = = = = = =
*/
2015-04-14 23:12:17 +00:00
static void LightCalcFaceExtents ( model_t * lightmodel , dface_t * s , vec2_t exactmins , vec2_t exactmaxs , int texmins [ 2 ] , int texsize [ 2 ] )
2004-09-08 13:34:51 +00:00
{
vec_t mins [ 2 ] , maxs [ 2 ] , val ;
int i , j , e ;
dvertex_t * v ;
texinfo_t * tex ;
mins [ 0 ] = mins [ 1 ] = 999999 ;
2015-04-14 23:12:17 +00:00
maxs [ 0 ] = maxs [ 1 ] = - 999999 ;
2004-09-08 13:34:51 +00:00
tex = & bsptexinfo ( s - > texinfo ) ;
for ( i = 0 ; i < s - > numedges ; i + + )
{
e = dsurfedges [ s - > firstedge + i ] ;
if ( e > = 0 )
v = dvertexes + dedges [ e ] . v [ 0 ] ;
else
v = dvertexes + dedges [ - e ] . v [ 1 ] ;
for ( j = 0 ; j < 2 ; j + + )
{
2015-04-14 23:12:17 +00:00
val = v - > position [ 0 ] * tex - > vecs [ j ] [ 0 ] +
v - > position [ 1 ] * tex - > vecs [ j ] [ 1 ] +
v - > position [ 2 ] * tex - > vecs [ j ] [ 2 ] +
2004-09-08 13:34:51 +00:00
tex - > vecs [ j ] [ 3 ] ;
if ( val < mins [ j ] )
mins [ j ] = val ;
if ( val > maxs [ j ] )
maxs [ j ] = val ;
}
}
for ( i = 0 ; i < 2 ; i + + )
{
2015-04-14 23:12:17 +00:00
exactmins [ i ] = mins [ i ] ;
exactmaxs [ i ] = maxs [ i ] ;
2004-09-08 13:34:51 +00:00
2015-03-05 22:14:21 +00:00
mins [ i ] = floor ( mins [ i ] / ( 1 < < s - > lmshift ) ) ;
maxs [ i ] = ceil ( maxs [ i ] / ( 1 < < s - > lmshift ) ) ;
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
texmins [ i ] = mins [ i ] ;
texsize [ i ] = maxs [ i ] - mins [ i ] ;
if ( texsize [ i ] > MAXIMUMEXTENT - 1 )
2015-03-05 22:14:21 +00:00
{
2015-04-14 23:12:17 +00:00
texsize [ i ] = MAXIMUMEXTENT - 1 ;
2015-03-05 22:14:21 +00:00
Con_Printf ( " Bad surface extents " ) ;
}
2004-09-08 13:34:51 +00:00
}
}
/*
= = = = = = = = = = = = = = = = =
CalcPoints
For each texture aligned grid point , back project onto the plane
to get the world xyz value of the sample point
= = = = = = = = = = = = = = = = =
*/
2015-04-14 23:12:17 +00:00
static void LightCalcPoints ( llightinfo_t * l , float lmscale )
2004-09-08 13:34:51 +00:00
{
int i ;
int s , t , j ;
2015-04-14 23:12:17 +00:00
int w , h ;
vec_t step ;
2004-09-08 13:34:51 +00:00
vec_t starts , startt , us , ut ;
vec_t * surf ;
vec_t mids , midt ;
vec3_t facemid , move ;
//
// fill in surforg
// the points are biased towards the center of the surface
// to help avoid edge cases just inside walls
//
surf = l - > surfpt [ 0 ] ;
mids = ( l - > exactmaxs [ 0 ] + l - > exactmins [ 0 ] ) / 2 ;
midt = ( l - > exactmaxs [ 1 ] + l - > exactmins [ 1 ] ) / 2 ;
for ( j = 0 ; j < 3 ; j + + )
facemid [ j ] = l - > texorg [ j ] + l - > textoworld [ 0 ] [ j ] * mids + l - > textoworld [ 1 ] [ j ] * midt ;
if ( extrasamples )
{ // extra filtering
h = ( l - > texsize [ 1 ] + 1 ) * 2 ;
w = ( l - > texsize [ 0 ] + 1 ) * 2 ;
2015-04-14 23:12:17 +00:00
starts = ( l - > texmins [ 0 ] - 0.5 ) * lmscale ;
startt = ( l - > texmins [ 1 ] - 0.5 ) * lmscale ;
step = 0.5 * lmscale ;
2004-09-08 13:34:51 +00:00
}
else
{
h = l - > texsize [ 1 ] + 1 ;
w = l - > texsize [ 0 ] + 1 ;
2015-04-14 23:12:17 +00:00
starts = l - > texmins [ 0 ] * lmscale ;
startt = l - > texmins [ 1 ] * lmscale ;
step = lmscale ;
2004-09-08 13:34:51 +00:00
}
l - > numsurfpt = w * h ;
for ( t = 0 ; t < h ; t + + )
{
for ( s = 0 ; s < w ; s + + , surf + = 3 )
{
us = starts + s * step ;
ut = startt + t * step ;
// if a line can be traced from surf to facemid, the point is good
for ( i = 0 ; i < 6 ; i + + )
{
// calculate texture point
for ( j = 0 ; j < 3 ; j + + )
surf [ j ] = l - > texorg [ j ] + l - > textoworld [ 0 ] [ j ] * us
+ l - > textoworld [ 1 ] [ j ] * ut ;
2015-04-14 23:12:17 +00:00
if ( CastRay ( l - > ctx , facemid , surf ) ! = - 1 )
2004-09-08 13:34:51 +00:00
break ; // got it
if ( i & 1 )
{
if ( us > mids )
{
2015-04-14 23:12:17 +00:00
us - = lmscale * 0.5 ;
2004-09-08 13:34:51 +00:00
if ( us < mids )
us = mids ;
}
else
{
2015-04-14 23:12:17 +00:00
us + = lmscale * 0.5 ;
2004-09-08 13:34:51 +00:00
if ( us > mids )
us = mids ;
}
}
else
{
if ( ut > midt )
{
2015-04-14 23:12:17 +00:00
ut - = lmscale * 0.5 ;
2004-09-08 13:34:51 +00:00
if ( ut < midt )
ut = midt ;
}
else
{
2015-04-14 23:12:17 +00:00
ut + = lmscale * 0.5 ;
2004-09-08 13:34:51 +00:00
if ( ut > midt )
ut = midt ;
}
}
// move surf 8 pixels towards the center
VectorSubtract ( facemid , surf , move ) ;
VectorNormalize ( move ) ;
VectorMA ( surf , 8 , move , surf ) ;
}
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
FACE LIGHTING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
SingleLightFace
= = = = = = = = = = = = = = = =
*/
static void SingleLightFace ( mentity_t * light , llightinfo_t * l )
{
vec_t dist ;
vec3_t incoming ;
vec_t angle ;
vec_t add ;
vec_t * surf ;
qboolean hit ;
int mapnum ;
2015-04-14 23:12:17 +00:00
int c ;
2004-09-08 13:34:51 +00:00
vec3_t rel ;
vec3_t spotvec ;
vec_t falloff ;
vec3_t * lightsamp ;
vec3_t * norms ;
VectorSubtract ( light - > origin , bsp_origin , rel ) ;
dist = scaledist * ( DotProduct ( rel , l - > facenormal ) - l - > facedist ) ;
// don't bother with lights behind the surface
if ( dist < = 0 )
return ;
// don't bother with light too far away
if ( dist > light - > light )
return ;
2015-04-14 23:12:17 +00:00
if ( light - > targetentnum > = 0 )
2004-09-08 13:34:51 +00:00
{
2015-04-14 23:12:17 +00:00
VectorSubtract ( l - > ctx - > entities [ light - > targetentnum ] . origin , light - > origin , spotvec ) ;
2004-09-08 13:34:51 +00:00
VectorNormalize ( spotvec ) ;
if ( ! light - > angle )
falloff = - cos ( 20 * Q_PI / 180 ) ;
else
falloff = - cos ( light - > angle / 2 * Q_PI / 180 ) ;
}
else
falloff = 0 ; // shut up compiler warnings
mapnum = 0 ;
for ( mapnum = 0 ; mapnum < l - > numlightstyles ; mapnum + + )
if ( l - > lightstyles [ mapnum ] = = light - > style )
break ;
lightsamp = l - > lightmaps [ mapnum ] ;
norms = l - > lightnorm [ mapnum ] ;
if ( mapnum = = l - > numlightstyles )
{ // init a new light map
2015-04-14 23:12:17 +00:00
# ifdef UTILITY
2020-03-25 21:29:30 +00:00
if ( mapnum = = MAXCPULIGHTMAPS )
2004-09-08 13:34:51 +00:00
{
printf ( " WARNING: Too many light styles on a face \n " ) ;
return ;
}
size = ( l - > texsize [ 1 ] + 1 ) * ( l - > texsize [ 0 ] + 1 ) ;
for ( i = 0 ; i < size ; i + + )
{
lightsamp [ i ] [ 0 ] = 0 ;
lightsamp [ i ] [ 1 ] = 0 ;
lightsamp [ i ] [ 2 ] = 0 ;
norms [ i ] [ 0 ] = 0 ;
norms [ i ] [ 1 ] = 0 ;
norms [ i ] [ 2 ] = 0 ;
}
2015-04-14 23:12:17 +00:00
# else
return ; //can't light a surface with a lightstyle that did not previously exist, due to lightmap space limits.
# endif
2004-09-08 13:34:51 +00:00
}
//
// check it for real
//
hit = false ;
surf = l - > surfpt [ 0 ] ;
for ( c = 0 ; c < l - > numsurfpt ; c + + , surf + = 3 )
{
2015-04-14 23:12:17 +00:00
dist = CastRay ( l - > ctx , light - > origin , surf ) * scaledist ;
2004-09-08 13:34:51 +00:00
if ( dist < 0 )
continue ; // light doesn't reach
VectorSubtract ( light - > origin , surf , incoming ) ;
VectorNormalize ( incoming ) ;
2015-04-14 23:12:17 +00:00
if ( light - > targetentnum > = 0 )
2004-09-08 13:34:51 +00:00
{ // spotlight cutoff
if ( DotProduct ( spotvec , incoming ) > falloff )
continue ;
}
angle = DotProduct ( incoming , l - > facenormal ) ;
angle = ( 1.0 - scalecos ) + scalecos * angle ;
add = light - > light - dist ;
add * = angle ;
if ( add < 0 )
continue ;
lightsamp [ c ] [ 0 ] + = add * light - > colour [ 0 ] ;
lightsamp [ c ] [ 1 ] + = add * light - > colour [ 1 ] ;
lightsamp [ c ] [ 2 ] + = add * light - > colour [ 2 ] ;
2015-04-14 23:12:17 +00:00
norms [ c ] [ 0 ] + = add * incoming [ 0 ] ;
2015-03-03 00:14:43 +00:00
norms [ c ] [ 1 ] + = add * incoming [ 1 ] ;
norms [ c ] [ 2 ] + = add * incoming [ 2 ] ;
2004-09-08 13:34:51 +00:00
if ( add > 1 ) // ignore real tiny lights
hit = true ;
}
2015-04-14 23:12:17 +00:00
2004-09-08 13:34:51 +00:00
if ( mapnum = = l - > numlightstyles & & hit )
{
l - > lightstyles [ mapnum ] = light - > style ;
l - > numlightstyles + + ; // the style has some real data now
}
}
/*
= = = = = = = = = = = =
FixMinlight
= = = = = = = = = = = =
*/
static void FixMinlight ( llightinfo_t * l )
{
int i , j ;
2019-08-03 01:58:03 +00:00
float minlight = l - > ctx - > minlight ;
2004-09-08 13:34:51 +00:00
// if minlight is set, there must be a style 0 light map
if ( ! minlight )
return ;
for ( i = 0 ; i < l - > numlightstyles ; i + + )
{
if ( l - > lightstyles [ i ] = = 0 )
break ;
}
if ( i = = l - > numlightstyles )
{
2020-03-25 21:29:30 +00:00
if ( l - > numlightstyles = = MAXCPULIGHTMAPS )
2004-09-08 13:34:51 +00:00
return ; // oh well..
for ( j = 0 ; j < l - > numsurfpt ; j + + )
{
l - > lightmaps [ i ] [ j ] [ 0 ] = minlight ;
l - > lightmaps [ i ] [ j ] [ 1 ] = minlight ;
l - > lightmaps [ i ] [ j ] [ 2 ] = minlight ;
}
l - > lightstyles [ i ] = 0 ;
l - > numlightstyles + + ;
}
else
{
for ( j = 0 ; j < l - > numsurfpt ; j + + )
{
if ( l - > lightmaps [ i ] [ j ] [ 0 ] < minlight )
l - > lightmaps [ i ] [ j ] [ 0 ] = minlight ;
if ( l - > lightmaps [ i ] [ j ] [ 1 ] < minlight )
l - > lightmaps [ i ] [ j ] [ 1 ] = minlight ;
if ( l - > lightmaps [ i ] [ j ] [ 2 ] < minlight )
l - > lightmaps [ i ] [ j ] [ 2 ] = minlight ;
}
}
}
2019-08-03 01:58:03 +00:00
static unsigned int PackE5BRG9 ( vec3_t rgb )
{ //5 bits exponent, 3*9 bits of mantissa. no sign bit.
int e = 0 ;
float m = max ( max ( rgb [ 0 ] , rgb [ 1 ] ) , rgb [ 2 ] ) ;
float scale ;
unsigned int hdr ;
if ( m > = 0.5 )
{ //positive exponent
while ( m > = ( 1 < < ( e ) ) & & e < 30 - 15 ) //don't do nans.
e + + ;
}
else
{ //negative exponent...
while ( m < 1 / ( 1 < < - e ) & & e > - 15 ) //don't do denormals.
e - - ;
}
scale = pow ( 2 , e - 9 ) ;
hdr = ( ( e + 15 ) < < 27 ) ;
hdr | = bound ( 0 , ( int ) ( rgb [ 0 ] / scale + 0.5 ) , 0x1ff ) < < 0 ;
hdr | = bound ( 0 , ( int ) ( rgb [ 1 ] / scale + 0.5 ) , 0x1ff ) < < 9 ;
hdr | = bound ( 0 , ( int ) ( rgb [ 2 ] / scale + 0.5 ) , 0x1ff ) < < 18 ;
return hdr ;
}
2004-09-08 13:34:51 +00:00
/*
= = = = = = = = = = = =
LightFace
= = = = = = = = = = = =
*/
2020-03-25 21:29:30 +00:00
void LightPlane ( struct relight_ctx_s * ctx , struct llightinfo_s * l , lightstyleindex_t surf_styles [ MAXCPULIGHTMAPS ] , unsigned int * surf_expsamples , qbyte * surf_rgbsamples , qbyte * surf_deluxesamples , vec4_t surf_plane , vec4_t surf_texplanes [ 2 ] , vec2_t exactmins , vec2_t exactmaxs , int texmins [ 2 ] , int texsize [ 2 ] , float lmscale )
2004-09-08 13:34:51 +00:00
{
int s , t ;
2015-04-14 23:12:17 +00:00
int i , c , ch ;
2004-09-08 13:34:51 +00:00
vec_t total , mean ;
int size ;
2013-05-11 05:03:07 +00:00
int lightmapwidth ;
2004-09-08 13:34:51 +00:00
# ifdef UTILITY
2013-05-11 05:03:07 +00:00
int lightmapsize ;
2004-09-08 13:34:51 +00:00
byte * out ;
# endif
2019-08-03 01:58:03 +00:00
unsigned int * expout ;
2015-04-14 23:12:17 +00:00
qbyte * rgbout ;
qbyte * dulout ;
2004-09-08 13:34:51 +00:00
vec3_t * light , * norm ;
2009-11-04 21:16:50 +00:00
vec3_t wnorm , temp , svector , tvector ;
2013-05-11 05:03:07 +00:00
int w ;
2004-09-08 13:34:51 +00:00
//
// some surfaces don't need lightmaps
//
2019-08-03 01:58:03 +00:00
if ( ! surf_rgbsamples & & ! surf_expsamples )
2004-09-08 13:34:51 +00:00
return ;
2015-09-18 20:30:10 +00:00
// memset (l, 0, sizeof(*l));
2015-04-14 23:12:17 +00:00
l - > ctx = ctx ;
2004-09-08 13:34:51 +00:00
//
// rotate plane
//
2015-04-14 23:12:17 +00:00
VectorCopy ( surf_plane , l - > facenormal ) ;
l - > facedist = surf_plane [ 3 ] ;
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
LightCalcFaceVectors ( l , surf_texplanes ) ;
Vector2Copy ( exactmins , l - > exactmins ) ;
Vector2Copy ( exactmaxs , l - > exactmaxs ) ;
Vector2Copy ( texmins , l - > texmins ) ;
Vector2Copy ( texsize , l - > texsize ) ;
LightCalcPoints ( l , lmscale ) ;
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
lightmapwidth = l - > texsize [ 0 ] + 1 ;
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
size = lightmapwidth * ( l - > texsize [ 1 ] + 1 ) ;
2004-09-08 13:34:51 +00:00
if ( size > SINGLEMAP )
2015-04-14 23:12:17 +00:00
Host_Error ( " Bad lightmap size " ) ;
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
i = 0 ;
# ifndef UTILITY
2020-03-25 21:29:30 +00:00
for ( ; surf_styles [ i ] ! = INVALID_LIGHTSTYLE & & i < MAXCPULIGHTMAPS ; i + + )
2015-09-18 20:30:10 +00:00
{
2015-04-14 23:12:17 +00:00
l - > lightstyles [ i ] = surf_styles [ i ] ;
2015-09-18 20:30:10 +00:00
memset ( & l - > lightmaps [ i ] , 0 , sizeof ( l - > lightmaps [ i ] [ 0 ] ) * l - > numsurfpt ) ;
memset ( & l - > lightnorm [ i ] , 0 , sizeof ( l - > lightnorm [ i ] [ 0 ] ) * l - > numsurfpt ) ;
}
2015-04-14 23:12:17 +00:00
# endif
l - > numlightstyles = i ;
2020-03-25 21:29:30 +00:00
for ( ; i < MAXCPULIGHTMAPS ; i + + )
2019-09-10 15:40:04 +00:00
l - > lightstyles [ i ] = INVALID_LIGHTSTYLE ;
2004-09-08 13:34:51 +00:00
//
// cast all lights
//
2015-04-14 23:12:17 +00:00
for ( i = 0 ; i < ctx - > num_entities ; i + + )
2004-09-08 13:34:51 +00:00
{
2015-04-14 23:12:17 +00:00
if ( ctx - > entities [ i ] . light )
SingleLightFace ( & ctx - > entities [ i ] , l ) ;
2004-09-08 13:34:51 +00:00
}
2015-04-14 23:12:17 +00:00
FixMinlight ( l ) ;
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
if ( ! l - > numlightstyles )
2004-09-08 13:34:51 +00:00
{ // no light hitting it
# ifdef UTILITY
f - > lightofs = - 1 ;
# endif
return ;
}
2004-10-19 16:10:14 +00:00
2004-09-08 13:34:51 +00:00
//
// save out the values
//
2020-03-25 21:29:30 +00:00
for ( i = 0 ; i < MAXCPULIGHTMAPS ; i + + )
2015-04-14 23:12:17 +00:00
surf_styles [ i ] = l - > lightstyles [ i ] ;
2004-09-08 13:34:51 +00:00
# ifdef UTILITY
2015-04-14 23:12:17 +00:00
lightmapsize = size * l - > numlightstyles ;
2004-09-08 13:34:51 +00:00
if ( runningrgblightdatabase )
{
2013-05-11 05:03:07 +00:00
out = GetFakeFileSpace ( & f - > lightofs , lightmapsize ) ;
2019-08-03 01:58:03 +00:00
expout = NULL ;
2004-09-08 13:34:51 +00:00
rgbout = runningrgblightdatabase + f - > lightofs * 3 ;
dulout = runninglightnormbase + f - > lightofs * 3 ;
}
else
{
out = GetFileSpace ( & f - > lightofs , lightmapsize ) ;
2019-08-03 01:58:03 +00:00
expout = NULL ;
2004-09-08 13:34:51 +00:00
rgbout = GetRGBFileSpace ( f - > lightofs , lightmapsize ) ;
dulout = GetNormFileSpace ( f - > lightofs , lightmapsize ) ;
}
# else
2017-03-06 14:06:12 +00:00
if ( ! ctx - > skiplit )
2019-08-03 01:58:03 +00:00
{
expout = surf_expsamples ;
2017-03-06 14:06:12 +00:00
rgbout = surf_rgbsamples ;
2019-08-03 01:58:03 +00:00
}
2017-03-06 14:06:12 +00:00
else
2019-08-03 01:58:03 +00:00
{
expout = NULL ;
2017-03-06 14:06:12 +00:00
rgbout = NULL ;
2019-08-03 01:58:03 +00:00
}
2015-04-14 23:12:17 +00:00
if ( l - > ctx - > models [ 0 ] - > deluxdata )
2009-11-04 21:16:50 +00:00
{
2015-04-14 23:12:17 +00:00
dulout = surf_deluxesamples ;
2009-11-04 21:16:50 +00:00
2015-04-14 23:12:17 +00:00
VectorCopy ( surf_texplanes [ 0 ] , svector ) ;
VectorNegate ( surf_texplanes [ 1 ] , tvector ) ;
2009-11-04 21:16:50 +00:00
VectorNormalize ( svector ) ;
VectorNormalize ( tvector ) ;
}
2004-09-08 13:34:51 +00:00
else
dulout = NULL ;
# endif
// extra filtering
2013-05-11 05:03:07 +00:00
// h = (l.texsize[1]+1)*2;
2015-04-14 23:12:17 +00:00
w = l - > texsize [ 0 ] + 1 ;
if ( extrasamples )
w * = 2 ;
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
for ( i = 0 ; i < l - > numlightstyles ; i + + )
2004-09-08 13:34:51 +00:00
{
2015-04-14 23:12:17 +00:00
if ( l - > lightstyles [ i ] = = 0xff )
Host_Error ( " Wrote empty lightmap " ) ;
light = l - > lightmaps [ i ] ;
norm = l - > lightnorm [ i ] ;
2004-09-08 13:34:51 +00:00
c = 0 ;
2015-04-14 23:12:17 +00:00
for ( t = 0 ; t < = l - > texsize [ 1 ] ; t + + )
2004-09-08 13:34:51 +00:00
{
2015-04-14 23:12:17 +00:00
for ( s = 0 ; s < = l - > texsize [ 0 ] ; s + + , c + + )
2004-09-08 13:34:51 +00:00
{
mean = 0 ;
for ( ch = 0 ; ch < 3 ; ch + + )
{
if ( extrasamples )
{ // filtered sample
total = light [ t * 2 * w + s * 2 ] [ ch ] + light [ t * 2 * w + s * 2 + 1 ] [ ch ]
+ light [ ( t * 2 + 1 ) * w + s * 2 ] [ ch ] + light [ ( t * 2 + 1 ) * w + s * 2 + 1 ] [ ch ] ;
total * = 0.25 ;
wnorm [ ch ] = norm [ t * 2 * w + s * 2 ] [ ch ] + norm [ t * 2 * w + s * 2 + 1 ] [ ch ]
+ norm [ ( t * 2 + 1 ) * w + s * 2 ] [ ch ] + norm [ ( t * 2 + 1 ) * w + s * 2 + 1 ] [ ch ] ;
}
else
{
total = light [ c ] [ ch ] ;
wnorm [ ch ] = norm [ c ] [ ch ] ;
}
total * = rangescale ; // scale before clamping
2019-08-03 01:58:03 +00:00
temp [ ch ] = total / 0x80 ; // quake bsps store logical light values between 0 and 2 for overbrights. normalise it appropriately.
2012-05-09 15:30:53 +00:00
# ifndef UTILITY
2015-04-14 23:12:17 +00:00
// if (total > *rgbout) //sorry - for qw
// total = *rgbout;
2004-09-08 13:34:51 +00:00
# endif
if ( total < 0 )
2015-04-14 23:12:17 +00:00
total = 0 ;
if ( total > 0xff )
total = 0xff ;
2004-09-08 13:34:51 +00:00
2017-03-06 14:06:12 +00:00
if ( rgbout )
* rgbout + + = total ;
2004-09-08 13:34:51 +00:00
mean + = total ;
}
2019-08-03 01:58:03 +00:00
if ( expout )
* expout + + = PackE5BRG9 ( temp ) ;
2004-09-08 13:34:51 +00:00
# ifdef UTILITY
* out + + = mean / 3 ;
# endif
if ( dulout )
{
2009-11-04 21:16:50 +00:00
temp [ 0 ] = DotProduct ( wnorm , svector ) ;
temp [ 1 ] = DotProduct ( wnorm , tvector ) ;
2015-04-14 23:12:17 +00:00
temp [ 2 ] = DotProduct ( wnorm , l - > facenormal ) ;
2015-03-03 00:14:43 +00:00
if ( ! temp [ 0 ] & & ! temp [ 1 ] & & ! temp [ 2 ] )
VectorSet ( temp , 0 , 0 , 1 ) ;
else
VectorNormalize ( temp ) ;
2017-03-06 14:06:12 +00:00
* dulout + + = ( temp [ 0 ] + 1 ) * 127 ;
* dulout + + = ( temp [ 1 ] + 1 ) * 127 ;
* dulout + + = ( temp [ 2 ] + 1 ) * 127 ;
2004-09-08 13:34:51 +00:00
}
}
}
}
}
2020-02-11 18:06:10 +00:00
static void LightFace ( struct relight_ctx_s * ctx , struct llightinfo_s * threadctx , int facenum )
2015-04-14 23:12:17 +00:00
{
dface_t * f = ctx - > models [ 0 ] - > surfaces + facenum ;
vec4_t plane ;
vec2_t exactmins ;
vec2_t exactmaxs ;
int texmins [ 2 ] , texsize [ 2 ] ;
VectorCopy ( f - > plane - > normal , plane ) ;
plane [ 3 ] = f - > plane - > dist ;
if ( f - > flags & SURF_PLANEBACK )
{
VectorNegate ( plane , plane ) ;
plane [ 3 ] = - plane [ 3 ] ;
}
2004-09-08 13:34:51 +00:00
2015-04-14 23:12:17 +00:00
//no lighting on these.
if ( f - > texinfo - > flags & TEX_SPECIAL )
return ;
LightCalcFaceExtents ( ctx - > models [ 0 ] , f , exactmins , exactmaxs , texmins , texsize ) ;
2019-08-03 01:58:03 +00:00
if ( ctx - > models [ 0 ] - > lightmaps . fmt = = LM_E5BGR9 )
LightPlane ( ctx , threadctx , f - > styles , ( unsigned int * ) f - > samples , NULL , 3 * ( f - > samples - ctx - > models [ 0 ] - > lightdata ) / 4 + ctx - > models [ 0 ] - > deluxdata , plane , f - > texinfo - > vecs , exactmins , exactmaxs , texmins , texsize , 1 < < f - > lmshift ) ;
else
LightPlane ( ctx , threadctx , f - > styles , NULL , f - > samples , f - > samples - ctx - > models [ 0 ] - > lightdata + ctx - > models [ 0 ] - > deluxdata , plane , f - > texinfo - > vecs , exactmins , exactmaxs , texmins , texsize , 1 < < f - > lmshift ) ;
2015-04-14 23:12:17 +00:00
}
2020-02-11 18:06:10 +00:00
2020-02-12 12:15:56 +00:00
static struct relight_ctx_s * lightcontext ;
2020-02-11 18:06:10 +00:00
# if defined(MULTITHREAD)
# ifdef _WIN32
# include <windows.h>
# elif defined(__linux__)
# include <unistd.h>
# endif
static void * relightthread [ 8 ] ;
static unsigned int relightthreads ;
static volatile qboolean wantrelight ;
static int RelightThread ( void * ctx )
{
int surf ;
struct relight_ctx_s * lightcontext = ctx ;
model_t * lightmodel = lightcontext - > models [ 0 ] ;
void * threadctx = malloc ( lightthreadctxsize ) ;
while ( wantrelight )
{
# ifdef _WIN32
surf = InterlockedIncrement ( & lightcontext - > nextface ) ;
# elif defined(__GNUC__)
surf = __sync_add_and_fetch ( & lightcontext - > nextface , 1 ) ;
# else
surf = relitsurface + + ;
# endif
if ( surf > = lightmodel - > numsurfaces )
break ;
LightFace ( lightcontext , threadctx , surf ) ;
lightmodel - > surfaces [ surf ] . cached_dlight = - 1 ; //invalidate it (slightly racey buy w/e
}
free ( threadctx ) ;
return 0 ;
}
# else
static void * lightmainthreadctx ;
# endif
void RelightTerminate ( model_t * mod )
{
model_t * lightmodel ;
size_t u ;
if ( ! lightcontext )
return ;
//if one of the models we're using is being purged then we have to abort the relight to avoid caching partial results (especially if its the model we're actually relighting)
if ( mod )
{
for ( u = 0 ; u < lightcontext - > nummodels ; u + + )
if ( lightcontext - > models [ u ] = = mod )
break ;
}
else
u = 0 ;
if ( u < lightcontext - > nummodels )
{
lightmodel = lightcontext - > models [ 0 ] ;
# ifdef MULTITHREAD
wantrelight = false ;
if ( relightthreads )
{
int i ;
wantrelight = false ;
for ( i = 0 ; i < relightthreads ; i + + )
{
Sys_WaitOnThread ( relightthread [ i ] ) ;
relightthread [ i ] = NULL ;
}
relightthreads = 0 ;
}
# else
free ( lightmainthreadctx ) ;
lightmainthreadctx = NULL ;
# endif
if ( lightcontext - > nextface > = lightmodel - > numsurfaces )
{
vfsfile_t * f ;
char filename [ MAX_QPATH ] ;
if ( lightmodel - > deluxdata )
{
COM_StripExtension ( lightmodel - > name , filename , sizeof ( filename ) ) ;
COM_DefaultExtension ( filename , " .lux " , sizeof ( filename ) ) ;
f = FS_OpenVFS ( filename , " wb " , FS_GAME ) ;
if ( f )
{
VFS_WRITE ( f , " QLIT \1 \0 \0 \0 " , 8 ) ;
VFS_WRITE ( f , lightmodel - > deluxdata , lightcontext - > lightmapsamples * 3 ) ;
VFS_CLOSE ( f ) ;
}
else
Con_Printf ( " Unable to write \" %s \" \n " , filename ) ;
}
if ( ! lightcontext - > skiplit ) //the user might already have a lit file (don't overwrite it).
{
COM_StripExtension ( lightmodel - > name , filename , sizeof ( filename ) ) ;
COM_DefaultExtension ( filename , " .lit " , sizeof ( filename ) ) ;
f = FS_OpenVFS ( filename , " wb " , FS_GAME ) ;
if ( f )
{
if ( lightmodel - > lightmaps . fmt = = LM_E5BGR9 )
{
VFS_WRITE ( f , " QLIT \x01 \0 \x01 \0 " , 8 ) ;
VFS_WRITE ( f , lightmodel - > lightdata , lightcontext - > lightmapsamples * 4 ) ;
}
else
{
VFS_WRITE ( f , " QLIT \1 \0 \0 \0 " , 8 ) ;
VFS_WRITE ( f , lightmodel - > lightdata , lightcontext - > lightmapsamples * 3 ) ;
}
VFS_CLOSE ( f ) ;
}
else
Con_Printf ( " Unable to write \" %s \" \n " , filename ) ;
}
}
else
Con_Printf ( " Relighting aborted before completion \n " ) ;
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
LightShutdown ( lightcontext , mod ) ;
2020-02-11 18:06:10 +00:00
lightcontext = NULL ;
}
}
qboolean RelightSetup ( model_t * model , size_t lightsamples , qboolean generatelit )
{
2021-08-09 23:06:23 +00:00
qboolean ret = false ;
2020-02-11 18:06:10 +00:00
Sys_LockMutex ( com_resourcemutex ) ; //models can be loaded on different threads, so no race conditions please.
if ( ! lightcontext )
{
lightcontext = LightStartup ( NULL , model , true , ! generatelit ) ;
lightcontext - > lightmapsamples = lightsamples ;
2021-08-09 23:06:23 +00:00
ret = true ;
2020-02-11 18:06:10 +00:00
}
Sys_UnlockMutex ( com_resourcemutex ) ;
2021-08-09 23:06:23 +00:00
return ret ;
2020-02-11 18:06:10 +00:00
}
const char * RelightGetProgress ( float * progress )
{
char filename [ MAX_QPATH ] ;
if ( ! lightcontext )
return NULL ;
* progress = ( lightcontext - > nextface * 100.0f ) / lightcontext - > models [ 0 ] - > numsurfaces ;
COM_StripExtension ( lightcontext - > models [ 0 ] - > name , filename , sizeof ( filename ) ) ;
COM_DefaultExtension ( filename , lightcontext - > skiplit ? " .lux " : " .lit " , sizeof ( filename ) ) ;
return va ( " %s " , filename ) ;
}
void RelightThink ( void )
{
if ( lightcontext )
{
model_t * lightmodel = lightcontext - > models [ 0 ] ;
if ( ! lightcontext - > loaded )
{ //make sure everything finished loading properly before we start poking things.
size_t u ;
if ( ! lightcontext - > parsed )
{
if ( lightcontext - > models [ 0 ] - > loadstate ! = MLS_LOADED )
return ; //not ready yet...
LightReloadEntities ( lightcontext , Mod_GetEntitiesString ( lightmodel ) , false ) ;
lightcontext - > parsed = true ;
}
for ( u = 0 ; u < lightcontext - > nummodels ; u + + )
if ( lightcontext - > models [ u ] - > loadstate ! = MLS_LOADED )
return ;
lightcontext - > loaded = true ;
}
# ifdef MULTITHREAD
if ( ! relightthreads )
{
int i ;
# if defined(_WIN32) && !defined(WINRT)
HANDLE me = GetCurrentProcess ( ) ;
DWORD_PTR proc , sys ;
/*count cpus*/
GetProcessAffinityMask ( me , & proc , & sys ) ;
relightthreads = 0 ;
for ( i = 0 ; i < sizeof ( proc ) * 8 ; i + + )
if ( proc & ( ( size_t ) 1u < < i ) )
relightthreads + + ;
/*subtract 1*/
if ( relightthreads < = 1 )
relightthreads = 1 ;
else
relightthreads - - ;
# elif defined(__GNUC__)
# ifdef __linux__
relightthreads = sysconf ( _SC_NPROCESSORS_ONLN ) - 1 ;
if ( relightthreads < 1 )
relightthreads = 1 ;
# else
relightthreads = 2 ; //erm, lets hope...
# endif
# else
/*can't do atomics*/
relightthreads = 1 ;
# endif
if ( relightthreads > sizeof ( relightthread ) / sizeof ( relightthread [ 0 ] ) )
relightthreads = sizeof ( relightthread ) / sizeof ( relightthread [ 0 ] ) ;
wantrelight = true ;
for ( i = 0 ; i < relightthreads ; i + + )
relightthread [ i ] = Sys_CreateThread ( " relight " , RelightThread , lightcontext , THREADP_NORMAL , 0 ) ;
}
if ( lightcontext - > nextface < lightmodel - > numsurfaces )
{
return ;
}
# else
if ( ! lightmainthreadctx )
lightmainthreadctx = malloc ( lightthreadctxsize ) ;
2020-02-12 12:15:56 +00:00
LightFace ( lightcontext , lightmainthreadctx , lightcontext - > nextface ) ;
lightmodel - > surfaces [ lightcontext - > nextface ] . cached_dlight = - 1 ;
2020-02-11 18:06:10 +00:00
2020-02-12 12:15:56 +00:00
lightcontext - > nextface + + ;
2020-02-11 18:06:10 +00:00
# endif
if ( lightcontext - > nextface > = lightmodel - > numsurfaces )
{
2021-08-09 23:06:23 +00:00
double starttime = lightcontext - > starttime ;
2020-02-11 18:06:10 +00:00
RelightTerminate ( lightmodel ) ;
2021-08-09 23:06:23 +00:00
Con_Printf ( " Finished lighting %s, took %.1f seconds \n " , lightmodel - > name , Sys_DoubleTime ( ) - starttime ) ;
2020-02-11 18:06:10 +00:00
}
}
}
2004-09-08 13:34:51 +00:00
# endif