2022-02-08 19:06:54 +00:00
/*
Copyright ( C ) 1996 - 2001 Id Software , Inc .
Copyright ( C ) 2002 - 2009 John Fitzgibbons and others
Copyright ( C ) 2007 - 2008 Kristian Duske
Copyright ( C ) 2010 - 2014 QuakeSpasm developers
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 .
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 .
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 .
*/
// r_brush.c: brush model rendering. renamed from r_surf.c
# include "quakedef.h"
extern cvar_t gl_fullbrights , r_drawflat , gl_overbright , r_oldwater ; //johnfitz
extern cvar_t gl_zfix ; // QuakeSpasm z-fighting fix
extern int gl_lightmap_format ;
int lightmap_bytes ;
# define BLOCK_WIDTH 128
# define BLOCK_HEIGHT 128
gltexture_t * lightmap_textures [ MAX_LIGHTMAPS ] ; //johnfitz -- changed to an array
unsigned blocklights [ BLOCK_WIDTH * BLOCK_HEIGHT * 3 ] ; //johnfitz -- was 18*18, added lit support (*3) and loosened surface extents maximum (BLOCK_WIDTH*BLOCK_HEIGHT)
typedef struct glRect_s {
unsigned char l , t , w , h ;
} glRect_t ;
glpoly_t * lightmap_polys [ MAX_LIGHTMAPS ] ;
qboolean lightmap_modified [ MAX_LIGHTMAPS ] ;
glRect_t lightmap_rectchange [ MAX_LIGHTMAPS ] ;
int allocated [ MAX_LIGHTMAPS ] [ BLOCK_WIDTH ] ;
int last_lightmap_allocated ; //ericw -- optimization: remember the index of the last lightmap AllocBlock stored a surf in
// the lightmap texture data needs to be kept in
// main memory so texsubimage can update properly
byte lightmaps [ 4 * MAX_LIGHTMAPS * BLOCK_WIDTH * BLOCK_HEIGHT ] ;
/*
= = = = = = = = = = = = = = =
R_TextureAnimation - - johnfitz - - added " frame " param to eliminate use of " currententity " global
Returns the proper texture for a given time and base texture
= = = = = = = = = = = = = = =
*/
texture_t * R_TextureAnimation ( texture_t * base , int frame )
{
int relative ;
int count ;
if ( frame )
if ( base - > alternate_anims )
base = base - > alternate_anims ;
if ( ! base - > anim_total )
return base ;
relative = ( int ) ( cl . time * 10 ) % base - > anim_total ;
count = 0 ;
while ( base - > anim_min > relative | | base - > anim_max < = relative )
{
base = base - > anim_next ;
if ( ! base )
Sys_Error ( " R_TextureAnimation: broken cycle " ) ;
if ( + + count > 100 )
Sys_Error ( " R_TextureAnimation: infinite cycle " ) ;
}
return base ;
}
/*
= = = = = = = = = = = = = = = =
DrawGLPoly
= = = = = = = = = = = = = = = =
*/
void DrawGLPoly ( glpoly_t * p )
{
float * v ;
int i ;
# ifdef VITA
glBegin ( GL_TRIANGLE_FAN ) ;
# else
glBegin ( GL_POLYGON ) ;
# endif
v = p - > verts [ 0 ] ;
for ( i = 0 ; i < p - > numverts ; i + + , v + = VERTEXSIZE )
{
glTexCoord2f ( v [ 3 ] , v [ 4 ] ) ;
glVertex3fv ( v ) ;
}
glEnd ( ) ;
}
/*
= = = = = = = = = = = = = = = =
DrawGLTriangleFan - - johnfitz - - like DrawGLPoly but for r_showtris
= = = = = = = = = = = = = = = =
*/
void DrawGLTriangleFan ( glpoly_t * p )
{
float * v ;
int i ;
glBegin ( GL_TRIANGLE_FAN ) ;
v = p - > verts [ 0 ] ;
for ( i = 0 ; i < p - > numverts ; i + + , v + = VERTEXSIZE )
{
glVertex3fv ( v ) ;
}
glEnd ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BRUSH MODELS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
#if 0
/*
= = = = = = = = = = = = = = = =
R_DrawSequentialPoly - - johnfitz - - rewritten
= = = = = = = = = = = = = = = =
*/
void R_DrawSequentialPoly ( msurface_t * s )
{
glpoly_t * p ;
texture_t * t ;
float * v ;
float entalpha ;
int i ;
t = R_TextureAnimation ( s - > texinfo - > texture , currententity - > frame ) ;
entalpha = ENTALPHA_DECODE ( currententity - > alpha ) ;
// drawflat
if ( r_drawflat_cheatsafe )
{
if ( ( s - > flags & SURF_DRAWTURB ) & & r_oldwater . value )
{
for ( p = s - > polys - > next ; p ; p = p - > next )
{
srand ( ( unsigned int ) ( uintptr_t ) p ) ;
glColor3f ( rand ( ) % 256 / 255.0 , rand ( ) % 256 / 255.0 , rand ( ) % 256 / 255.0 ) ;
DrawGLPoly ( p ) ;
rs_brushpasses + + ;
}
return ;
}
srand ( ( unsigned int ) ( uintptr_t ) s - > polys ) ;
glColor3f ( rand ( ) % 256 / 255.0 , rand ( ) % 256 / 255.0 , rand ( ) % 256 / 255.0 ) ;
DrawGLPoly ( s - > polys ) ;
rs_brushpasses + + ;
return ;
}
// fullbright
if ( ( r_fullbright_cheatsafe ) & & ! ( s - > flags & SURF_DRAWTILED ) )
{
if ( entalpha < 1 )
{
glDepthMask ( GL_FALSE ) ;
glEnable ( GL_BLEND ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
glColor4f ( 1 , 1 , 1 , entalpha ) ;
}
if ( s - > flags & SURF_DRAWFENCE )
glEnable ( GL_ALPHA_TEST ) ; // Flip on alpha test
GL_Bind ( t - > gltexture ) ;
DrawGLPoly ( s - > polys ) ;
rs_brushpasses + + ;
if ( s - > flags & SURF_DRAWFENCE )
glDisable ( GL_ALPHA_TEST ) ; // Flip alpha test back off
if ( entalpha < 1 )
{
glDepthMask ( GL_TRUE ) ;
glDisable ( GL_BLEND ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
glColor3f ( 1 , 1 , 1 ) ;
}
goto fullbrights ;
}
// r_lightmap
if ( r_lightmap_cheatsafe )
{
if ( s - > flags & SURF_DRAWTILED )
{
glDisable ( GL_TEXTURE_2D ) ;
DrawGLPoly ( s - > polys ) ;
glEnable ( GL_TEXTURE_2D ) ;
rs_brushpasses + + ;
return ;
}
R_RenderDynamicLightmaps ( s ) ;
GL_Bind ( lightmap_textures [ s - > lightmaptexturenum ] ) ;
if ( ! gl_overbright . value )
{
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
glColor3f ( 0.5 , 0.5 , 0.5 ) ;
}
# ifdef VITA
glBegin ( GL_TRIANGLE_FAN ) ;
# else
glBegin ( GL_POLYGON ) ;
# endif
v = s - > polys - > verts [ 0 ] ;
for ( i = 0 ; i < s - > polys - > numverts ; i + + , v + = VERTEXSIZE )
{
glTexCoord2f ( v [ 5 ] , v [ 6 ] ) ;
glVertex3fv ( v ) ;
}
glEnd ( ) ;
if ( ! gl_overbright . value )
{
glColor3f ( 1 , 1 , 1 ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
}
rs_brushpasses + + ;
return ;
}
// sky poly -- skip it, already handled in gl_sky.c
if ( s - > flags & SURF_DRAWSKY )
return ;
// water poly
if ( s - > flags & SURF_DRAWTURB )
{
if ( currententity - > alpha = = ENTALPHA_DEFAULT )
entalpha = CLAMP ( 0.0 , GL_WaterAlphaForSurface ( s ) , 1.0 ) ;
if ( entalpha < 1 )
{
glDepthMask ( GL_FALSE ) ;
glEnable ( GL_BLEND ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
glColor4f ( 1 , 1 , 1 , entalpha ) ;
}
if ( r_oldwater . value )
{
GL_Bind ( s - > texinfo - > texture - > gltexture ) ;
for ( p = s - > polys - > next ; p ; p = p - > next )
{
DrawWaterPoly ( p ) ;
rs_brushpasses + + ;
}
rs_brushpasses + + ;
}
else
{
GL_Bind ( s - > texinfo - > texture - > warpimage ) ;
s - > texinfo - > texture - > update_warp = true ; // FIXME: one frame too late!
DrawGLPoly ( s - > polys ) ;
rs_brushpasses + + ;
}
if ( entalpha < 1 )
{
glDepthMask ( GL_TRUE ) ;
glDisable ( GL_BLEND ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
glColor3f ( 1 , 1 , 1 ) ;
}
return ;
}
// missing texture
if ( s - > flags & SURF_NOTEXTURE )
{
if ( entalpha < 1 )
{
glDepthMask ( GL_FALSE ) ;
glEnable ( GL_BLEND ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
glColor4f ( 1 , 1 , 1 , entalpha ) ;
}
GL_Bind ( t - > gltexture ) ;
DrawGLPoly ( s - > polys ) ;
rs_brushpasses + + ;
if ( entalpha < 1 )
{
glDepthMask ( GL_TRUE ) ;
glDisable ( GL_BLEND ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
glColor3f ( 1 , 1 , 1 ) ;
}
return ;
}
// lightmapped poly
if ( entalpha < 1 )
{
glDepthMask ( GL_FALSE ) ;
glEnable ( GL_BLEND ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
glColor4f ( 1 , 1 , 1 , entalpha ) ;
}
else
glColor3f ( 1 , 1 , 1 ) ;
if ( s - > flags & SURF_DRAWFENCE )
glEnable ( GL_ALPHA_TEST ) ; // Flip on alpha test
if ( gl_overbright . value )
{
if ( gl_texture_env_combine & & gl_mtexable ) //case 1: texture and lightmap in one pass, overbright using texture combiners
{
GL_DisableMultitexture ( ) ; // selects TEXTURE0
GL_Bind ( t - > gltexture ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
GL_EnableMultitexture ( ) ; // selects TEXTURE1
GL_Bind ( lightmap_textures [ s - > lightmaptexturenum ] ) ;
R_RenderDynamicLightmaps ( s ) ;
glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_COMBINE_EXT ) ;
glTexEnvi ( GL_TEXTURE_ENV , GL_COMBINE_RGB_EXT , GL_MODULATE ) ;
glTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE0_RGB_EXT , GL_PREVIOUS_EXT ) ;
glTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_EXT , GL_TEXTURE ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_RGB_SCALE_EXT , 2.0f ) ;
# ifdef VITA
glBegin ( GL_TRIANGLE_FAN ) ;
# else
glBegin ( GL_POLYGON ) ;
# endif
v = s - > polys - > verts [ 0 ] ;
for ( i = 0 ; i < s - > polys - > numverts ; i + + , v + = VERTEXSIZE )
{
GL_MTexCoord2fFunc ( GL_TEXTURE0_ARB , v [ 3 ] , v [ 4 ] ) ;
GL_MTexCoord2fFunc ( GL_TEXTURE1_ARB , v [ 5 ] , v [ 6 ] ) ;
glVertex3fv ( v ) ;
}
glEnd ( ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_RGB_SCALE_EXT , 1.0f ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
GL_DisableMultitexture ( ) ;
rs_brushpasses + + ;
}
else if ( entalpha < 1 | | ( s - > flags & SURF_DRAWFENCE ) ) //case 2: can't do multipass if entity has alpha, so just draw the texture
{
GL_Bind ( t - > gltexture ) ;
DrawGLPoly ( s - > polys ) ;
rs_brushpasses + + ;
}
else //case 3: texture in one pass, lightmap in second pass using 2x modulation blend func, fog in third pass
{
//first pass -- texture with no fog
2023-02-26 03:06:12 +00:00
# ifndef VITA
2022-02-08 19:06:54 +00:00
Fog_DisableGFog ( ) ;
2023-02-26 03:06:12 +00:00
# endif VITA
2022-02-08 19:06:54 +00:00
GL_Bind ( t - > gltexture ) ;
DrawGLPoly ( s - > polys ) ;
2023-02-26 03:06:12 +00:00
# ifndef VITA
2023-01-15 20:20:52 +00:00
Fog_EnableGFog ( ) ;
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
rs_brushpasses + + ;
//second pass -- lightmap with black fog, modulate blended
R_RenderDynamicLightmaps ( s ) ;
GL_Bind ( lightmap_textures [ s - > lightmaptexturenum ] ) ;
glDepthMask ( GL_FALSE ) ;
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_DST_COLOR , GL_SRC_COLOR ) ; //2x modulate
2023-02-26 03:06:12 +00:00
# ifndef VITA
2023-01-15 20:20:52 +00:00
Fog_StartAdditive ( ) ;
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
# ifdef VITA
glBegin ( GL_TRIANGLE_FAN ) ;
# else
glBegin ( GL_POLYGON ) ;
# endif
v = s - > polys - > verts [ 0 ] ;
for ( i = 0 ; i < s - > polys - > numverts ; i + + , v + = VERTEXSIZE )
{
glTexCoord2f ( v [ 5 ] , v [ 6 ] ) ;
glVertex3fv ( v ) ;
}
glEnd ( ) ;
2023-02-26 03:06:12 +00:00
# ifndef VITA
2023-01-15 20:20:52 +00:00
Fog_StopAdditive ( ) ;
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
rs_brushpasses + + ;
//third pass -- black geo with normal fog, additive blended
2023-02-26 03:06:12 +00:00
# ifndef VITA
2023-01-15 20:20:52 +00:00
if ( Fog_GetDensity ( ) > 0 )
2022-02-08 19:06:54 +00:00
{
glBlendFunc ( GL_ONE , GL_ONE ) ; //add
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
glColor3f ( 0 , 0 , 0 ) ;
DrawGLPoly ( s - > polys ) ;
glColor3f ( 1 , 1 , 1 ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
rs_brushpasses + + ;
2023-01-15 20:20:52 +00:00
}
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glDisable ( GL_BLEND ) ;
glDepthMask ( GL_TRUE ) ;
}
}
else
{
if ( gl_mtexable ) //case 4: texture and lightmap in one pass, regular modulation
{
GL_DisableMultitexture ( ) ; // selects TEXTURE0
GL_Bind ( t - > gltexture ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
GL_EnableMultitexture ( ) ; // selects TEXTURE1
GL_Bind ( lightmap_textures [ s - > lightmaptexturenum ] ) ;
R_RenderDynamicLightmaps ( s ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
# ifdef VITA
glBegin ( GL_TRIANGLE_FAN ) ;
# else
glBegin ( GL_POLYGON ) ;
# endif
v = s - > polys - > verts [ 0 ] ;
for ( i = 0 ; i < s - > polys - > numverts ; i + + , v + = VERTEXSIZE )
{
GL_MTexCoord2fFunc ( GL_TEXTURE0_ARB , v [ 3 ] , v [ 4 ] ) ;
GL_MTexCoord2fFunc ( GL_TEXTURE1_ARB , v [ 5 ] , v [ 6 ] ) ;
glVertex3fv ( v ) ;
}
glEnd ( ) ;
GL_DisableMultitexture ( ) ;
rs_brushpasses + + ;
}
else if ( entalpha < 1 | | ( s - > flags & SURF_DRAWFENCE ) ) //case 5: can't do multipass if entity has alpha, so just draw the texture
{
GL_Bind ( t - > gltexture ) ;
DrawGLPoly ( s - > polys ) ;
rs_brushpasses + + ;
}
else //case 6: texture in one pass, lightmap in a second pass, fog in third pass
{
//first pass -- texture with no fog
2023-02-26 03:06:12 +00:00
# ifndef VITA
2022-02-08 19:06:54 +00:00
Fog_DisableGFog ( ) ;
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
GL_Bind ( t - > gltexture ) ;
DrawGLPoly ( s - > polys ) ;
2023-02-26 03:06:12 +00:00
# ifndef VITA
2023-01-15 20:20:52 +00:00
Fog_EnableGFog ( ) ;
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
rs_brushpasses + + ;
//second pass -- lightmap with black fog, modulate blended
R_RenderDynamicLightmaps ( s ) ;
GL_Bind ( lightmap_textures [ s - > lightmaptexturenum ] ) ;
glDepthMask ( GL_FALSE ) ;
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_ZERO , GL_SRC_COLOR ) ; //modulate
2023-02-26 03:06:12 +00:00
# ifndef VITA
2023-01-15 20:20:52 +00:00
Fog_StartAdditive ( ) ;
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
# ifdef VITA
glBegin ( GL_TRIANGLE_FAN ) ;
# else
glBegin ( GL_POLYGON ) ;
# endif
v = s - > polys - > verts [ 0 ] ;
for ( i = 0 ; i < s - > polys - > numverts ; i + + , v + = VERTEXSIZE )
{
glTexCoord2f ( v [ 5 ] , v [ 6 ] ) ;
glVertex3fv ( v ) ;
}
glEnd ( ) ;
2023-02-26 03:06:12 +00:00
# ifndef VITA
2023-01-15 20:20:52 +00:00
Fog_StopAdditive ( ) ;
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
rs_brushpasses + + ;
2023-02-26 03:06:12 +00:00
# ifndef VITA
2022-02-08 19:06:54 +00:00
//third pass -- black geo with normal fog, additive blended
2023-01-15 20:20:52 +00:00
if ( Fog_GetDensity ( ) > 0 )
2022-02-08 19:06:54 +00:00
{
glBlendFunc ( GL_ONE , GL_ONE ) ; //add
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
glColor3f ( 0 , 0 , 0 ) ;
DrawGLPoly ( s - > polys ) ;
glColor3f ( 1 , 1 , 1 ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
rs_brushpasses + + ;
2023-01-15 20:20:52 +00:00
}
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glDisable ( GL_BLEND ) ;
glDepthMask ( GL_TRUE ) ;
}
}
if ( entalpha < 1 )
{
glDepthMask ( GL_TRUE ) ;
glDisable ( GL_BLEND ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
glColor3f ( 1 , 1 , 1 ) ;
}
if ( s - > flags & SURF_DRAWFENCE )
glDisable ( GL_ALPHA_TEST ) ; // Flip alpha test back off
fullbrights :
if ( gl_fullbrights . value & & t - > fullbright )
{
glDepthMask ( GL_FALSE ) ;
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_ONE , GL_ONE ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ;
glColor3f ( entalpha , entalpha , entalpha ) ;
GL_Bind ( t - > fullbright ) ;
2023-02-26 03:06:12 +00:00
# ifndef VITA
2023-01-15 20:20:52 +00:00
Fog_StartAdditive ( ) ;
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
DrawGLPoly ( s - > polys ) ;
2023-02-26 03:06:12 +00:00
# ifndef VITA
2023-01-15 20:20:52 +00:00
Fog_StopAdditive ( ) ;
2023-02-26 03:06:12 +00:00
# endif
2022-02-08 19:06:54 +00:00
glColor3f ( 1 , 1 , 1 ) ;
glTexEnvf ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_REPLACE ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glDisable ( GL_BLEND ) ;
glDepthMask ( GL_TRUE ) ;
rs_brushpasses + + ;
}
}
# endif
/*
= = = = = = = = = = = = = = = = =
R_DrawBrushModel
= = = = = = = = = = = = = = = = =
*/
void R_DrawBrushModel ( entity_t * e )
{
int i , k ;
msurface_t * psurf ;
float dot ;
mplane_t * pplane ;
qmodel_t * clmodel ;
if ( R_CullModelForEntity ( e ) )
return ;
currententity = e ;
clmodel = e - > model ;
VectorSubtract ( r_refdef . vieworg , e - > origin , modelorg ) ;
if ( e - > angles [ 0 ] | | e - > angles [ 1 ] | | e - > angles [ 2 ] )
{
vec3_t temp ;
vec3_t forward , right , up ;
VectorCopy ( modelorg , temp ) ;
AngleVectors ( e - > angles , forward , right , up ) ;
modelorg [ 0 ] = DotProduct ( temp , forward ) ;
modelorg [ 1 ] = - DotProduct ( temp , right ) ;
modelorg [ 2 ] = DotProduct ( temp , up ) ;
}
psurf = & clmodel - > surfaces [ clmodel - > firstmodelsurface ] ;
// calculate dynamic lighting for bmodel if it's not an
// instanced model
if ( clmodel - > firstmodelsurface ! = 0 & & ! gl_flashblend . value )
{
for ( k = 0 ; k < MAX_DLIGHTS ; k + + )
{
if ( ( cl_dlights [ k ] . die < cl . time ) | |
( ! cl_dlights [ k ] . radius ) )
continue ;
R_MarkLights ( & cl_dlights [ k ] , k ,
clmodel - > nodes + clmodel - > hulls [ 0 ] . firstclipnode ) ;
}
}
glPushMatrix ( ) ;
e - > angles [ 0 ] = - e - > angles [ 0 ] ; // stupid quake bug
if ( gl_zfix . value )
{
e - > origin [ 0 ] - = DIST_EPSILON ;
e - > origin [ 1 ] - = DIST_EPSILON ;
e - > origin [ 2 ] - = DIST_EPSILON ;
}
2023-12-29 22:10:12 +00:00
R_RotateForEntity ( e - > origin , e - > angles , e - > scale ) ;
2022-02-08 19:06:54 +00:00
if ( gl_zfix . value )
{
e - > origin [ 0 ] + = DIST_EPSILON ;
e - > origin [ 1 ] + = DIST_EPSILON ;
e - > origin [ 2 ] + = DIST_EPSILON ;
}
e - > angles [ 0 ] = - e - > angles [ 0 ] ; // stupid quake bug
R_ClearTextureChains ( clmodel , chain_model ) ;
for ( i = 0 ; i < clmodel - > nummodelsurfaces ; i + + , psurf + + )
{
pplane = psurf - > plane ;
dot = DotProduct ( modelorg , pplane - > normal ) - pplane - > dist ;
if ( ( ( psurf - > flags & SURF_PLANEBACK ) & & ( dot < - BACKFACE_EPSILON ) ) | |
( ! ( psurf - > flags & SURF_PLANEBACK ) & & ( dot > BACKFACE_EPSILON ) ) )
{
R_ChainSurface ( psurf , chain_model ) ;
rs_brushpolys + + ;
}
}
R_DrawTextureChains ( clmodel , e , chain_model ) ;
R_DrawTextureChains_Water ( clmodel , e , chain_model ) ;
glPopMatrix ( ) ;
}
/*
= = = = = = = = = = = = = = = = =
R_DrawBrushModel_ShowTris - - johnfitz
= = = = = = = = = = = = = = = = =
*/
void R_DrawBrushModel_ShowTris ( entity_t * e )
{
int i ;
msurface_t * psurf ;
float dot ;
mplane_t * pplane ;
qmodel_t * clmodel ;
glpoly_t * p ;
if ( R_CullModelForEntity ( e ) )
return ;
currententity = e ;
clmodel = e - > model ;
VectorSubtract ( r_refdef . vieworg , e - > origin , modelorg ) ;
if ( e - > angles [ 0 ] | | e - > angles [ 1 ] | | e - > angles [ 2 ] )
{
vec3_t temp ;
vec3_t forward , right , up ;
VectorCopy ( modelorg , temp ) ;
AngleVectors ( e - > angles , forward , right , up ) ;
modelorg [ 0 ] = DotProduct ( temp , forward ) ;
modelorg [ 1 ] = - DotProduct ( temp , right ) ;
modelorg [ 2 ] = DotProduct ( temp , up ) ;
}
psurf = & clmodel - > surfaces [ clmodel - > firstmodelsurface ] ;
glPushMatrix ( ) ;
e - > angles [ 0 ] = - e - > angles [ 0 ] ; // stupid quake bug
2023-12-29 22:10:12 +00:00
R_RotateForEntity ( e - > origin , e - > angles , e - > scale ) ;
2022-02-08 19:06:54 +00:00
e - > angles [ 0 ] = - e - > angles [ 0 ] ; // stupid quake bug
//
// draw it
//
for ( i = 0 ; i < clmodel - > nummodelsurfaces ; i + + , psurf + + )
{
pplane = psurf - > plane ;
dot = DotProduct ( modelorg , pplane - > normal ) - pplane - > dist ;
if ( ( ( psurf - > flags & SURF_PLANEBACK ) & & ( dot < - BACKFACE_EPSILON ) ) | |
( ! ( psurf - > flags & SURF_PLANEBACK ) & & ( dot > BACKFACE_EPSILON ) ) )
{
if ( ( psurf - > flags & SURF_DRAWTURB ) & & r_oldwater . value )
for ( p = psurf - > polys - > next ; p ; p = p - > next )
DrawGLTriangleFan ( p ) ;
else
DrawGLTriangleFan ( psurf - > polys ) ;
}
}
glPopMatrix ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
LIGHTMAPS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
R_RenderDynamicLightmaps
called during rendering
= = = = = = = = = = = = = = = =
*/
void R_RenderDynamicLightmaps ( msurface_t * fa )
{
byte * base ;
int maps ;
glRect_t * theRect ;
int smax , tmax ;
if ( fa - > flags & SURF_DRAWTILED ) //johnfitz -- not a lightmapped surface
return ;
// add to lightmap chain
fa - > polys - > chain = lightmap_polys [ fa - > lightmaptexturenum ] ;
lightmap_polys [ fa - > lightmaptexturenum ] = fa - > polys ;
// check for lightmap modification
for ( maps = 0 ; maps < MAXLIGHTMAPS & & fa - > styles [ maps ] ! = 255 ; maps + + )
if ( d_lightstylevalue [ fa - > styles [ maps ] ] ! = fa - > cached_light [ maps ] )
goto dynamic ;
if ( fa - > dlightframe = = r_framecount // dynamic this frame
| | fa - > cached_dlight ) // dynamic previously
{
dynamic :
if ( r_dynamic . value )
{
lightmap_modified [ fa - > lightmaptexturenum ] = true ;
theRect = & lightmap_rectchange [ fa - > lightmaptexturenum ] ;
if ( fa - > light_t < theRect - > t ) {
if ( theRect - > h )
theRect - > h + = theRect - > t - fa - > light_t ;
theRect - > t = fa - > light_t ;
}
if ( fa - > light_s < theRect - > l ) {
if ( theRect - > w )
theRect - > w + = theRect - > l - fa - > light_s ;
theRect - > l = fa - > light_s ;
}
smax = ( fa - > extents [ 0 ] > > 4 ) + 1 ;
tmax = ( fa - > extents [ 1 ] > > 4 ) + 1 ;
if ( ( theRect - > w + theRect - > l ) < ( fa - > light_s + smax ) )
theRect - > w = ( fa - > light_s - theRect - > l ) + smax ;
if ( ( theRect - > h + theRect - > t ) < ( fa - > light_t + tmax ) )
theRect - > h = ( fa - > light_t - theRect - > t ) + tmax ;
base = lightmaps + fa - > lightmaptexturenum * lightmap_bytes * BLOCK_WIDTH * BLOCK_HEIGHT ;
base + = fa - > light_t * BLOCK_WIDTH * lightmap_bytes + fa - > light_s * lightmap_bytes ;
R_BuildLightMap ( fa , base , BLOCK_WIDTH * lightmap_bytes ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
AllocBlock - - returns a texture number and the position inside it
= = = = = = = = = = = = = = = = = = = = = = = =
*/
int AllocBlock ( int w , int h , int * x , int * y )
{
int i , j ;
int best , best2 ;
int texnum ;
// ericw -- rather than searching starting at lightmap 0 every time,
// start at the last lightmap we allocated a surface in.
// This makes AllocBlock much faster on large levels (can shave off 3+ seconds
// of load time on a level with 180 lightmaps), at a cost of not quite packing
// lightmaps as tightly vs. not doing this (uses ~5% more lightmaps)
for ( texnum = last_lightmap_allocated ; texnum < MAX_LIGHTMAPS ; texnum + + , last_lightmap_allocated + + )
{
best = BLOCK_HEIGHT ;
for ( i = 0 ; i < BLOCK_WIDTH - w ; i + + )
{
best2 = 0 ;
for ( j = 0 ; j < w ; j + + )
{
if ( allocated [ texnum ] [ i + j ] > = best )
break ;
if ( allocated [ texnum ] [ i + j ] > best2 )
best2 = allocated [ texnum ] [ i + j ] ;
}
if ( j = = w )
{ // this is a valid spot
* x = i ;
* y = best = best2 ;
}
}
if ( best + h > BLOCK_HEIGHT )
continue ;
for ( i = 0 ; i < w ; i + + )
allocated [ texnum ] [ * x + i ] = best + h ;
return texnum ;
}
Sys_Error ( " AllocBlock: full " ) ;
return 0 ; //johnfitz -- shut up compiler
}
mvertex_t * r_pcurrentvertbase ;
qmodel_t * currentmodel ;
int nColinElim ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
GL_CreateSurfaceLightmap
= = = = = = = = = = = = = = = = = = = = = = = =
*/
void GL_CreateSurfaceLightmap ( msurface_t * surf )
{
int smax , tmax ;
byte * base ;
smax = ( surf - > extents [ 0 ] > > 4 ) + 1 ;
tmax = ( surf - > extents [ 1 ] > > 4 ) + 1 ;
surf - > lightmaptexturenum = AllocBlock ( smax , tmax , & surf - > light_s , & surf - > light_t ) ;
base = lightmaps + surf - > lightmaptexturenum * lightmap_bytes * BLOCK_WIDTH * BLOCK_HEIGHT ;
base + = ( surf - > light_t * BLOCK_WIDTH + surf - > light_s ) * lightmap_bytes ;
R_BuildLightMap ( surf , base , BLOCK_WIDTH * lightmap_bytes ) ;
}
/*
= = = = = = = = = = = = = = = =
BuildSurfaceDisplayList - - called at level load time
= = = = = = = = = = = = = = = =
*/
void BuildSurfaceDisplayList ( msurface_t * fa )
{
int i , lindex , lnumverts ;
medge_t * pedges , * r_pedge ;
float * vec ;
float s , t ;
glpoly_t * poly ;
// reconstruct the polygon
pedges = currentmodel - > edges ;
lnumverts = fa - > numedges ;
//
// draw texture
//
poly = ( glpoly_t * ) Hunk_Alloc ( sizeof ( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof ( float ) ) ;
poly - > next = fa - > polys ;
fa - > polys = poly ;
poly - > numverts = lnumverts ;
for ( i = 0 ; i < lnumverts ; i + + )
{
lindex = currentmodel - > surfedges [ fa - > firstedge + i ] ;
if ( lindex > 0 )
{
r_pedge = & pedges [ lindex ] ;
vec = r_pcurrentvertbase [ r_pedge - > v [ 0 ] ] . position ;
}
else
{
r_pedge = & pedges [ - lindex ] ;
vec = r_pcurrentvertbase [ r_pedge - > v [ 1 ] ] . position ;
}
s = DotProduct ( vec , fa - > texinfo - > vecs [ 0 ] ) + fa - > texinfo - > vecs [ 0 ] [ 3 ] ;
s / = fa - > texinfo - > texture - > width ;
t = DotProduct ( vec , fa - > texinfo - > vecs [ 1 ] ) + fa - > texinfo - > vecs [ 1 ] [ 3 ] ;
t / = fa - > texinfo - > texture - > height ;
VectorCopy ( vec , poly - > verts [ i ] ) ;
poly - > verts [ i ] [ 3 ] = s ;
poly - > verts [ i ] [ 4 ] = t ;
//
// lightmap texture coordinates
//
s = DotProduct ( vec , fa - > texinfo - > vecs [ 0 ] ) + fa - > texinfo - > vecs [ 0 ] [ 3 ] ;
s - = fa - > texturemins [ 0 ] ;
s + = fa - > light_s * 16 ;
s + = 8 ;
s / = BLOCK_WIDTH * 16 ; //fa->texinfo->texture->width;
t = DotProduct ( vec , fa - > texinfo - > vecs [ 1 ] ) + fa - > texinfo - > vecs [ 1 ] [ 3 ] ;
t - = fa - > texturemins [ 1 ] ;
t + = fa - > light_t * 16 ;
t + = 8 ;
t / = BLOCK_HEIGHT * 16 ; //fa->texinfo->texture->height;
poly - > verts [ i ] [ 5 ] = s ;
poly - > verts [ i ] [ 6 ] = t ;
}
//johnfitz -- removed gl_keeptjunctions code
poly - > numverts = lnumverts ;
}
/*
= = = = = = = = = = = = = = = = = =
GL_BuildLightmaps - - called at level load time
Builds the lightmap texture
with all the surfaces from all brush models
= = = = = = = = = = = = = = = = = =
*/
void GL_BuildLightmaps ( void )
{
char name [ 16 ] ;
byte * data ;
int i , j ;
qmodel_t * m ;
memset ( allocated , 0 , sizeof ( allocated ) ) ;
last_lightmap_allocated = 0 ;
r_framecount = 1 ; // no dlightcache
//johnfitz -- null out array (the gltexture objects themselves were already freed by Mod_ClearAll)
for ( i = 0 ; i < MAX_LIGHTMAPS ; i + + )
lightmap_textures [ i ] = NULL ;
//johnfitz
gl_lightmap_format = GL_RGBA ; //FIXME: hardcoded for now!
switch ( gl_lightmap_format )
{
case GL_RGBA :
lightmap_bytes = 4 ;
break ;
case GL_BGRA :
lightmap_bytes = 4 ;
break ;
default :
Sys_Error ( " GL_BuildLightmaps: bad lightmap format " ) ;
}
for ( j = 1 ; j < MAX_MODELS ; j + + )
{
m = cl . model_precache [ j ] ;
if ( ! m )
break ;
if ( m - > name [ 0 ] = = ' * ' )
continue ;
r_pcurrentvertbase = m - > vertexes ;
currentmodel = m ;
for ( i = 0 ; i < m - > numsurfaces ; i + + )
{
//johnfitz -- rewritten to use SURF_DRAWTILED instead of the sky/water flags
if ( m - > surfaces [ i ] . flags & SURF_DRAWTILED )
continue ;
GL_CreateSurfaceLightmap ( m - > surfaces + i ) ;
BuildSurfaceDisplayList ( m - > surfaces + i ) ;
//johnfitz
}
}
//
// upload all lightmaps that were filled
//
for ( i = 0 ; i < MAX_LIGHTMAPS ; i + + )
{
if ( ! allocated [ i ] [ 0 ] )
break ; // no more used
lightmap_modified [ i ] = false ;
lightmap_rectchange [ i ] . l = BLOCK_WIDTH ;
lightmap_rectchange [ i ] . t = BLOCK_HEIGHT ;
lightmap_rectchange [ i ] . w = 0 ;
lightmap_rectchange [ i ] . h = 0 ;
//johnfitz -- use texture manager
sprintf ( name , " lightmap%03i " , i ) ;
data = lightmaps + i * BLOCK_WIDTH * BLOCK_HEIGHT * lightmap_bytes ;
lightmap_textures [ i ] = TexMgr_LoadImage ( cl . worldmodel , name , BLOCK_WIDTH , BLOCK_HEIGHT ,
SRC_LIGHTMAP , data , " " , ( src_offset_t ) data , TEXPREF_LINEAR | TEXPREF_NOPICMIP ) ;
//johnfitz
}
//johnfitz -- warn about exceeding old limits
if ( i > = 64 )
Con_DWarning ( " %i lightmaps exceeds standard limit of 64 (max = %d). \n " , i , MAX_LIGHTMAPS ) ;
//johnfitz
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
VBO support
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
GLuint gl_bmodel_vbo = 0 ;
void GL_DeleteBModelVertexBuffer ( void )
{
if ( ! ( gl_vbo_able & & gl_mtexable & & gl_max_texture_units > = 3 ) )
return ;
GL_DeleteBuffersFunc ( 1 , & gl_bmodel_vbo ) ;
gl_bmodel_vbo = 0 ;
GL_ClearBufferBindings ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
GL_BuildBModelVertexBuffer
Deletes gl_bmodel_vbo if it already exists , then rebuilds it with all
surfaces from world + all brush models
= = = = = = = = = = = = = = = = = =
*/
void GL_BuildBModelVertexBuffer ( void )
{
unsigned int numverts , varray_bytes , varray_index ;
int i , j ;
qmodel_t * m ;
float * varray ;
if ( ! ( gl_vbo_able & & gl_mtexable & & gl_max_texture_units > = 3 ) )
return ;
// ask GL for a name for our VBO
GL_DeleteBuffersFunc ( 1 , & gl_bmodel_vbo ) ;
GL_GenBuffersFunc ( 1 , & gl_bmodel_vbo ) ;
// count all verts in all models
numverts = 0 ;
for ( j = 1 ; j < MAX_MODELS ; j + + )
{
m = cl . model_precache [ j ] ;
if ( ! m | | m - > name [ 0 ] = = ' * ' | | m - > type ! = mod_brush )
continue ;
for ( i = 0 ; i < m - > numsurfaces ; i + + )
{
numverts + = m - > surfaces [ i ] . numedges ;
}
}
// build vertex array
varray_bytes = VERTEXSIZE * sizeof ( float ) * numverts ;
varray = ( float * ) malloc ( varray_bytes ) ;
varray_index = 0 ;
for ( j = 1 ; j < MAX_MODELS ; j + + )
{
m = cl . model_precache [ j ] ;
if ( ! m | | m - > name [ 0 ] = = ' * ' | | m - > type ! = mod_brush )
continue ;
for ( i = 0 ; i < m - > numsurfaces ; i + + )
{
msurface_t * s = & m - > surfaces [ i ] ;
s - > vbo_firstvert = varray_index ;
memcpy ( & varray [ VERTEXSIZE * varray_index ] , s - > polys - > verts , VERTEXSIZE * sizeof ( float ) * s - > numedges ) ;
varray_index + = s - > numedges ;
}
}
// upload to GPU
GL_BindBufferFunc ( GL_ARRAY_BUFFER , gl_bmodel_vbo ) ;
GL_BufferDataFunc ( GL_ARRAY_BUFFER , varray_bytes , varray , GL_STATIC_DRAW ) ;
free ( varray ) ;
// invalidate the cached bindings
GL_ClearBufferBindings ( ) ;
}
/*
= = = = = = = = = = = = = = =
R_AddDynamicLights
= = = = = = = = = = = = = = =
*/
void R_AddDynamicLights ( msurface_t * surf )
{
int lnum ;
int sd , td ;
float dist , rad , minlight ;
vec3_t impact , local ;
int s , t ;
int i ;
int smax , tmax ;
mtexinfo_t * tex ;
//johnfitz -- lit support via lordhavoc
float cred , cgreen , cblue , brightness ;
unsigned * bl ;
//johnfitz
smax = ( surf - > extents [ 0 ] > > 4 ) + 1 ;
tmax = ( surf - > extents [ 1 ] > > 4 ) + 1 ;
tex = surf - > texinfo ;
for ( lnum = 0 ; lnum < MAX_DLIGHTS ; lnum + + )
{
if ( ! ( surf - > dlightbits [ lnum > > 5 ] & ( 1U < < ( lnum & 31 ) ) ) )
continue ; // not lit by this light
rad = cl_dlights [ lnum ] . radius ;
dist = DotProduct ( cl_dlights [ lnum ] . origin , surf - > plane - > normal ) -
surf - > plane - > dist ;
rad - = fabs ( dist ) ;
minlight = cl_dlights [ lnum ] . minlight ;
if ( rad < minlight )
continue ;
minlight = rad - minlight ;
for ( i = 0 ; i < 3 ; i + + )
{
impact [ i ] = cl_dlights [ lnum ] . origin [ i ] -
surf - > plane - > normal [ i ] * dist ;
}
local [ 0 ] = DotProduct ( impact , tex - > vecs [ 0 ] ) + tex - > vecs [ 0 ] [ 3 ] ;
local [ 1 ] = DotProduct ( impact , tex - > vecs [ 1 ] ) + tex - > vecs [ 1 ] [ 3 ] ;
local [ 0 ] - = surf - > texturemins [ 0 ] ;
local [ 1 ] - = surf - > texturemins [ 1 ] ;
//johnfitz -- lit support via lordhavoc
bl = blocklights ;
cred = cl_dlights [ lnum ] . color [ 0 ] * 256.0f ;
cgreen = cl_dlights [ lnum ] . color [ 1 ] * 256.0f ;
cblue = cl_dlights [ lnum ] . color [ 2 ] * 256.0f ;
//johnfitz
for ( t = 0 ; t < tmax ; t + + )
{
td = local [ 1 ] - t * 16 ;
if ( td < 0 )
td = - td ;
for ( s = 0 ; s < smax ; s + + )
{
sd = local [ 0 ] - s * 16 ;
if ( sd < 0 )
sd = - sd ;
if ( sd > td )
dist = sd + ( td > > 1 ) ;
else
dist = td + ( sd > > 1 ) ;
if ( dist < minlight )
//johnfitz -- lit support via lordhavoc
{
brightness = rad - dist ;
bl [ 0 ] + = ( int ) ( brightness * cred ) ;
bl [ 1 ] + = ( int ) ( brightness * cgreen ) ;
bl [ 2 ] + = ( int ) ( brightness * cblue ) ;
}
bl + = 3 ;
//johnfitz
}
}
}
}
/*
= = = = = = = = = = = = = = =
R_BuildLightMap - - johnfitz - - revised for lit support via lordhavoc
Combine and scale multiple lightmaps into the 8.8 format in blocklights
= = = = = = = = = = = = = = =
*/
void R_BuildLightMap ( msurface_t * surf , byte * dest , int stride )
{
int smax , tmax ;
int r , g , b ;
int i , j , size ;
byte * lightmap ;
unsigned scale ;
int maps ;
unsigned * bl ;
surf - > cached_dlight = ( surf - > dlightframe = = r_framecount ) ;
smax = ( surf - > extents [ 0 ] > > 4 ) + 1 ;
tmax = ( surf - > extents [ 1 ] > > 4 ) + 1 ;
size = smax * tmax ;
lightmap = surf - > samples ;
if ( cl . worldmodel - > lightdata )
{
// clear to no light
memset ( & blocklights [ 0 ] , 0 , size * 3 * sizeof ( unsigned int ) ) ; //johnfitz -- lit support via lordhavoc
// add all the lightmaps
if ( lightmap )
{
for ( maps = 0 ; maps < MAXLIGHTMAPS & & surf - > styles [ maps ] ! = 255 ;
maps + + )
{
scale = d_lightstylevalue [ surf - > styles [ maps ] ] ;
surf - > cached_light [ maps ] = scale ; // 8.8 fraction
//johnfitz -- lit support via lordhavoc
bl = blocklights ;
for ( i = 0 ; i < size ; i + + )
{
* bl + + + = * lightmap + + * scale ;
* bl + + + = * lightmap + + * scale ;
* bl + + + = * lightmap + + * scale ;
}
//johnfitz
}
}
// add all the dynamic lights
if ( surf - > dlightframe = = r_framecount )
R_AddDynamicLights ( surf ) ;
}
else
{
// set to full bright if no light data
memset ( & blocklights [ 0 ] , 255 , size * 3 * sizeof ( unsigned int ) ) ; //johnfitz -- lit support via lordhavoc
}
// bound, invert, and shift
// store:
switch ( gl_lightmap_format )
{
case GL_RGBA :
stride - = smax * 4 ;
bl = blocklights ;
for ( i = 0 ; i < tmax ; i + + , dest + = stride )
{
for ( j = 0 ; j < smax ; j + + )
{
if ( gl_overbright . value )
{
r = * bl + + > > 8 ;
g = * bl + + > > 8 ;
b = * bl + + > > 8 ;
}
else
{
r = * bl + + > > 7 ;
g = * bl + + > > 7 ;
b = * bl + + > > 7 ;
}
* dest + + = ( r > 255 ) ? 255 : r ;
* dest + + = ( g > 255 ) ? 255 : g ;
* dest + + = ( b > 255 ) ? 255 : b ;
* dest + + = 255 ;
}
}
break ;
case GL_BGRA :
stride - = smax * 4 ;
bl = blocklights ;
for ( i = 0 ; i < tmax ; i + + , dest + = stride )
{
for ( j = 0 ; j < smax ; j + + )
{
if ( gl_overbright . value )
{
r = * bl + + > > 8 ;
g = * bl + + > > 8 ;
b = * bl + + > > 8 ;
}
else
{
r = * bl + + > > 7 ;
g = * bl + + > > 7 ;
b = * bl + + > > 7 ;
}
* dest + + = ( b > 255 ) ? 255 : b ;
* dest + + = ( g > 255 ) ? 255 : g ;
* dest + + = ( r > 255 ) ? 255 : r ;
* dest + + = 255 ;
}
}
break ;
default :
Sys_Error ( " R_BuildLightMap: bad lightmap format " ) ;
}
}
/*
= = = = = = = = = = = = = = =
R_UploadLightmap - - johnfitz - - uploads the modified lightmap to opengl if necessary
assumes lightmap texture is already bound
= = = = = = = = = = = = = = =
*/
static void R_UploadLightmap ( int lmap )
{
glRect_t * theRect ;
if ( ! lightmap_modified [ lmap ] )
return ;
lightmap_modified [ lmap ] = false ;
theRect = & lightmap_rectchange [ lmap ] ;
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , theRect - > t , BLOCK_WIDTH , theRect - > h , gl_lightmap_format ,
GL_UNSIGNED_BYTE , lightmaps + ( lmap * BLOCK_HEIGHT + theRect - > t ) * BLOCK_WIDTH * lightmap_bytes ) ;
theRect - > l = BLOCK_WIDTH ;
theRect - > t = BLOCK_HEIGHT ;
theRect - > h = 0 ;
theRect - > w = 0 ;
rs_dynamiclightmaps + + ;
}
void R_UploadLightmaps ( void )
{
int lmap ;
for ( lmap = 0 ; lmap < MAX_LIGHTMAPS ; lmap + + )
{
if ( ! lightmap_modified [ lmap ] )
continue ;
GL_Bind ( lightmap_textures [ lmap ] ) ;
R_UploadLightmap ( lmap ) ;
}
}
/*
= = = = = = = = = = = = = = = =
R_RebuildAllLightmaps - - johnfitz - - called when gl_overbright gets toggled
= = = = = = = = = = = = = = = =
*/
void R_RebuildAllLightmaps ( void )
{
int i , j ;
qmodel_t * mod ;
msurface_t * fa ;
byte * base ;
if ( ! cl . worldmodel ) // is this the correct test?
return ;
//for each surface in each model, rebuild lightmap with new scale
for ( i = 1 ; i < MAX_MODELS ; i + + )
{
if ( ! ( mod = cl . model_precache [ i ] ) )
continue ;
fa = & mod - > surfaces [ mod - > firstmodelsurface ] ;
for ( j = 0 ; j < mod - > nummodelsurfaces ; j + + , fa + + )
{
if ( fa - > flags & SURF_DRAWTILED )
continue ;
base = lightmaps + fa - > lightmaptexturenum * lightmap_bytes * BLOCK_WIDTH * BLOCK_HEIGHT ;
base + = fa - > light_t * BLOCK_WIDTH * lightmap_bytes + fa - > light_s * lightmap_bytes ;
R_BuildLightMap ( fa , base , BLOCK_WIDTH * lightmap_bytes ) ;
}
}
//for each lightmap, upload it
for ( i = 0 ; i < MAX_LIGHTMAPS ; i + + )
{
if ( ! allocated [ i ] [ 0 ] )
break ;
GL_Bind ( lightmap_textures [ i ] ) ;
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , BLOCK_WIDTH , BLOCK_HEIGHT , gl_lightmap_format ,
GL_UNSIGNED_BYTE , lightmaps + i * BLOCK_WIDTH * BLOCK_HEIGHT * lightmap_bytes ) ;
}
}