2010-02-15 23:26:55 +00:00
/*
Copyright ( C ) 1996 - 2001 Id Software , Inc .
Copyright ( C ) 2002 - 2009 John Fitzgibbons and others
Copyright ( C ) 2007 - 2008 Kristian Duske
2014-09-22 08:55:46 +00:00
Copyright ( C ) 2010 - 2014 QuakeSpasm developers
2010-02-15 23:26:55 +00: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 .
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
2011-08-24 07:47:29 +00:00
extern cvar_t gl_zfix ; // QuakeSpasm z-fighting fix
2010-02-15 23:26:55 +00:00
int gl_lightmap_format ;
int lightmap_bytes ;
2019-09-12 06:49:35 +00:00
# define MAX_SANITY_LIGHTMAPS (1u<<20)
struct lightmap_s * lightmap ;
int lightmap_count ;
int last_lightmap_allocated ;
int allocated [ LMBLOCK_WIDTH ] ;
2010-04-22 19:02:29 +00:00
2019-09-12 06:49:27 +00:00
unsigned blocklights [ LMBLOCK_WIDTH * LMBLOCK_HEIGHT * 3 ] ; //johnfitz -- was 18*18, added lit support (*3) and loosened surface extents maximum (LMBLOCK_WIDTH*LMBLOCK_HEIGHT)
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = =
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 ;
glBegin ( GL_POLYGON ) ;
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
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2014-08-29 08:27:22 +00:00
#if 0
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = =
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 )
{
2011-04-01 14:55:45 +00:00
srand ( ( unsigned int ) ( uintptr_t ) p ) ;
2010-02-15 23:26:55 +00:00
glColor3f ( rand ( ) % 256 / 255.0 , rand ( ) % 256 / 255.0 , rand ( ) % 256 / 255.0 ) ;
DrawGLPoly ( p ) ;
rs_brushpasses + + ;
}
return ;
}
2011-04-01 14:55:45 +00:00
srand ( ( unsigned int ) ( uintptr_t ) s - > polys ) ;
2010-02-15 23:26:55 +00:00
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 ) ;
}
2014-08-19 02:20:12 +00:00
if ( s - > flags & SURF_DRAWFENCE )
glEnable ( GL_ALPHA_TEST ) ; // Flip on alpha test
2010-02-15 23:26:55 +00:00
GL_Bind ( t - > gltexture ) ;
DrawGLPoly ( s - > polys ) ;
rs_brushpasses + + ;
2014-08-19 02:20:12 +00:00
if ( s - > flags & SURF_DRAWFENCE )
glDisable ( GL_ALPHA_TEST ) ; // Flip alpha test back off
2010-02-15 23:26:55 +00:00
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 ) ;
}
glBegin ( GL_POLYGON ) ;
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 )
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
entalpha = CLAMP ( 0.0 , GL_WaterAlphaForSurface ( s ) , 1.0 ) ;
2010-02-15 23:26:55 +00:00
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 ) ;
2014-08-19 02:20:12 +00:00
if ( s - > flags & SURF_DRAWFENCE )
glEnable ( GL_ALPHA_TEST ) ; // Flip on alpha test
2010-02-15 23:26:55 +00:00
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 ) ;
glBegin ( GL_POLYGON ) ;
v = s - > polys - > verts [ 0 ] ;
for ( i = 0 ; i < s - > polys - > numverts ; i + + , v + = VERTEXSIZE )
{
2014-08-30 08:00:34 +00:00
GL_MTexCoord2fFunc ( GL_TEXTURE0_ARB , v [ 3 ] , v [ 4 ] ) ;
GL_MTexCoord2fFunc ( GL_TEXTURE1_ARB , v [ 5 ] , v [ 6 ] ) ;
2010-02-15 23:26:55 +00:00
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 + + ;
}
2014-08-19 02:20:12 +00:00
else if ( entalpha < 1 | | ( s - > flags & SURF_DRAWFENCE ) ) //case 2: can't do multipass if entity has alpha, so just draw the texture
2010-02-15 23:26:55 +00:00
{
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
Fog_DisableGFog ( ) ;
GL_Bind ( t - > gltexture ) ;
DrawGLPoly ( s - > polys ) ;
Fog_EnableGFog ( ) ;
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
Fog_StartAdditive ( ) ;
glBegin ( GL_POLYGON ) ;
v = s - > polys - > verts [ 0 ] ;
for ( i = 0 ; i < s - > polys - > numverts ; i + + , v + = VERTEXSIZE )
{
glTexCoord2f ( v [ 5 ] , v [ 6 ] ) ;
glVertex3fv ( v ) ;
}
glEnd ( ) ;
Fog_StopAdditive ( ) ;
rs_brushpasses + + ;
//third pass -- black geo with normal fog, additive blended
if ( Fog_GetDensity ( ) > 0 )
{
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 + + ;
}
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 ) ;
glBegin ( GL_POLYGON ) ;
v = s - > polys - > verts [ 0 ] ;
for ( i = 0 ; i < s - > polys - > numverts ; i + + , v + = VERTEXSIZE )
{
2014-08-30 08:00:34 +00:00
GL_MTexCoord2fFunc ( GL_TEXTURE0_ARB , v [ 3 ] , v [ 4 ] ) ;
GL_MTexCoord2fFunc ( GL_TEXTURE1_ARB , v [ 5 ] , v [ 6 ] ) ;
2010-02-15 23:26:55 +00:00
glVertex3fv ( v ) ;
}
glEnd ( ) ;
GL_DisableMultitexture ( ) ;
rs_brushpasses + + ;
}
2014-08-19 02:20:12 +00:00
else if ( entalpha < 1 | | ( s - > flags & SURF_DRAWFENCE ) ) //case 5: can't do multipass if entity has alpha, so just draw the texture
2010-02-15 23:26:55 +00:00
{
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
Fog_DisableGFog ( ) ;
GL_Bind ( t - > gltexture ) ;
DrawGLPoly ( s - > polys ) ;
Fog_EnableGFog ( ) ;
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
Fog_StartAdditive ( ) ;
glBegin ( GL_POLYGON ) ;
v = s - > polys - > verts [ 0 ] ;
for ( i = 0 ; i < s - > polys - > numverts ; i + + , v + = VERTEXSIZE )
{
glTexCoord2f ( v [ 5 ] , v [ 6 ] ) ;
glVertex3fv ( v ) ;
}
glEnd ( ) ;
Fog_StopAdditive ( ) ;
rs_brushpasses + + ;
//third pass -- black geo with normal fog, additive blended
if ( Fog_GetDensity ( ) > 0 )
{
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 + + ;
}
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 ) ;
}
2014-08-17 21:12:54 +00:00
2014-08-19 02:20:12 +00:00
if ( s - > flags & SURF_DRAWFENCE )
glDisable ( GL_ALPHA_TEST ) ; // Flip alpha test back off
2010-02-15 23:26:55 +00:00
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 ) ;
Fog_StartAdditive ( ) ;
DrawGLPoly ( s - > polys ) ;
Fog_StopAdditive ( ) ;
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 + + ;
}
}
2014-08-29 08:27:22 +00:00
# endif
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = = =
R_DrawBrushModel
= = = = = = = = = = = = = = = = =
*/
void R_DrawBrushModel ( entity_t * e )
{
chase.c, cl_input.c, cl_parse.c, client.h, common.c, common.h, console.h,
cvar.h, draw.h, gl_draw.c, gl_fog.c, gl_mesh.c, gl_model.c, gl_model.h,
gl_rmain.c, gl_rmisc.c, gl_screen.c, gl_sky.c, gl_texmgr.c, glquake.h,
host.c, keys.c, keys.h, main.c, menu.c, menu.h, pr_cmds.c, quakedef.h,
r_alias.c, r_brush.c, r_part.c, r_sprite.c, r_world.c, sbar.c, sbar.h,
screen.h, snd_dma.c, snd_mem.c, snd_mix.c, sv_main.c, sys_sdl.c, vid.h,
view.h, world.c, world.h: Loads of warning fixes about missing function
prototypes, missing parens around &, missing braces leading to ambiguous
else statements and unused and uninitialized variables. There are still a
couple of unitialised variables here and there, but not much. The warnings
about strict aliasing violations need taking care of.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@21 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-02-16 12:01:07 +00:00
int i , k ;
2010-02-15 23:26:55 +00:00
msurface_t * psurf ;
float dot ;
mplane_t * pplane ;
2012-05-30 08:56:06 +00:00
qmodel_t * clmodel ;
2018-05-25 10:54:33 +00:00
vec3_t lightorg ;
2010-02-15 23:26:55 +00:00
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 ;
2018-05-25 10:54:33 +00:00
VectorSubtract ( cl_dlights [ k ] . origin , e - > origin , lightorg ) ;
R_MarkLights ( & cl_dlights [ k ] , lightorg , k ,
2010-02-15 23:26:55 +00:00
clmodel - > nodes + clmodel - > hulls [ 0 ] . firstclipnode ) ;
}
}
2016-04-28 21:47:12 +00:00
glPushMatrix ( ) ;
2010-02-15 23:26:55 +00:00
e - > angles [ 0 ] = - e - > angles [ 0 ] ; // stupid quake bug
2011-08-24 07:47:29 +00:00
if ( gl_zfix . value )
{
e - > origin [ 0 ] - = DIST_EPSILON ;
e - > origin [ 1 ] - = DIST_EPSILON ;
e - > origin [ 2 ] - = DIST_EPSILON ;
}
2017-09-17 02:12:53 +00:00
R_RotateForEntity ( e - > origin , e - > angles , e - > netstate . scale ) ;
2011-08-24 07:47:29 +00:00
if ( gl_zfix . value )
{
e - > origin [ 0 ] + = DIST_EPSILON ;
e - > origin [ 1 ] + = DIST_EPSILON ;
e - > origin [ 2 ] + = DIST_EPSILON ;
}
2010-02-15 23:26:55 +00:00
e - > angles [ 0 ] = - e - > angles [ 0 ] ; // stupid quake bug
2014-08-29 08:27:22 +00:00
R_ClearTextureChains ( clmodel , chain_model ) ;
2010-02-15 23:26:55 +00:00
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 ) ) )
{
2014-08-29 08:27:22 +00:00
R_ChainSurface ( psurf , chain_model ) ;
2010-02-15 23:26:55 +00:00
rs_brushpolys + + ;
}
}
2014-08-29 08:27:22 +00:00
R_DrawTextureChains ( clmodel , e , chain_model ) ;
R_DrawTextureChains_Water ( clmodel , e , chain_model ) ;
2010-02-15 23:26:55 +00:00
glPopMatrix ( ) ;
}
/*
= = = = = = = = = = = = = = = = =
R_DrawBrushModel_ShowTris - - johnfitz
= = = = = = = = = = = = = = = = =
*/
void R_DrawBrushModel_ShowTris ( entity_t * e )
{
chase.c, cl_input.c, cl_parse.c, client.h, common.c, common.h, console.h,
cvar.h, draw.h, gl_draw.c, gl_fog.c, gl_mesh.c, gl_model.c, gl_model.h,
gl_rmain.c, gl_rmisc.c, gl_screen.c, gl_sky.c, gl_texmgr.c, glquake.h,
host.c, keys.c, keys.h, main.c, menu.c, menu.h, pr_cmds.c, quakedef.h,
r_alias.c, r_brush.c, r_part.c, r_sprite.c, r_world.c, sbar.c, sbar.h,
screen.h, snd_dma.c, snd_mem.c, snd_mix.c, sv_main.c, sys_sdl.c, vid.h,
view.h, world.c, world.h: Loads of warning fixes about missing function
prototypes, missing parens around &, missing braces leading to ambiguous
else statements and unused and uninitialized variables. There are still a
couple of unitialised variables here and there, but not much. The warnings
about strict aliasing violations need taking care of.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@21 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-02-16 12:01:07 +00:00
int i ;
2010-02-15 23:26:55 +00:00
msurface_t * psurf ;
float dot ;
mplane_t * pplane ;
2012-05-30 08:56:06 +00:00
qmodel_t * clmodel ;
2010-02-15 23:26:55 +00:00
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 ] ;
2013-02-20 06:22:42 +00:00
glPushMatrix ( ) ;
2010-02-15 23:26:55 +00:00
e - > angles [ 0 ] = - e - > angles [ 0 ] ; // stupid quake bug
2017-09-17 02:12:53 +00:00
R_RotateForEntity ( e - > origin , e - > angles , e - > netstate . scale ) ;
2010-02-15 23:26:55 +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
= = = = = = = = = = = = = = = =
*/
2017-09-17 02:12:53 +00:00
void R_RenderDynamicLightmaps ( qmodel_t * model , msurface_t * fa )
2010-02-15 23:26:55 +00:00
{
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
2019-09-12 06:49:35 +00:00
fa - > polys - > chain = lightmap [ fa - > lightmaptexturenum ] . polys ;
lightmap [ fa - > lightmaptexturenum ] . polys = fa - > polys ;
2010-02-15 23:26:55 +00:00
// check for lightmap modification
2019-09-10 14:41:11 +00:00
for ( maps = 0 ; maps < MAXLIGHTMAPS & & fa - > styles [ maps ] ! = INVALID_LIGHTSTYLE ; maps + + )
2010-02-15 23:26:55 +00:00
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 )
{
2019-09-12 06:49:35 +00:00
struct lightmap_s * lm = & lightmap [ fa - > lightmaptexturenum ] ;
lm - > modified = true ;
theRect = & lm - > rectchange ;
2010-02-15 23:26:55 +00:00
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 ;
}
2017-12-15 04:01:14 +00:00
smax = ( fa - > extents [ 0 ] > > fa - > lmshift ) + 1 ;
tmax = ( fa - > extents [ 1 ] > > fa - > lmshift ) + 1 ;
2010-02-15 23:26:55 +00:00
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 ;
2019-09-12 06:49:35 +00:00
base = lm - > data ;
2019-09-12 06:49:27 +00:00
base + = fa - > light_t * LMBLOCK_WIDTH * lightmap_bytes + fa - > light_s * lightmap_bytes ;
2017-09-17 02:12:53 +00:00
R_BuildLightMap ( model , fa , base , LMBLOCK_WIDTH * lightmap_bytes ) ;
2010-02-15 23:26:55 +00:00
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
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 ;
2014-08-05 18:22:58 +00:00
// 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)
2019-09-12 06:49:35 +00:00
for ( texnum = last_lightmap_allocated ; texnum < MAX_SANITY_LIGHTMAPS ; texnum + + )
2010-02-15 23:26:55 +00:00
{
2019-09-12 06:49:35 +00:00
if ( texnum = = lightmap_count )
{
lightmap_count + + ;
2019-09-16 11:00:38 +00:00
lightmap = ( struct lightmap_s * ) realloc ( lightmap , sizeof ( * lightmap ) * lightmap_count ) ;
2019-09-12 06:49:35 +00:00
memset ( & lightmap [ texnum ] , 0 , sizeof ( lightmap [ texnum ] ) ) ;
2019-11-11 09:35:19 +00:00
/* FIXME: we leave 'gaps' in malloc()ed data, CRC_Block() later accesses
* that uninitialized data and valgrind complains for it . use calloc ( ) ? */
2019-09-16 11:00:38 +00:00
lightmap [ texnum ] . data = ( byte * ) malloc ( 4 * LMBLOCK_WIDTH * LMBLOCK_HEIGHT ) ;
2019-09-12 06:49:35 +00:00
//as we're only tracking one texture, we don't need multiple copies of allocated any more.
memset ( allocated , 0 , sizeof ( allocated ) ) ;
}
2019-09-12 06:49:27 +00:00
best = LMBLOCK_HEIGHT ;
2010-02-15 23:26:55 +00:00
2019-09-12 06:49:27 +00:00
for ( i = 0 ; i < LMBLOCK_WIDTH - w ; i + + )
2010-02-15 23:26:55 +00:00
{
best2 = 0 ;
for ( j = 0 ; j < w ; j + + )
{
2019-09-12 06:49:35 +00:00
if ( allocated [ i + j ] > = best )
2010-02-15 23:26:55 +00:00
break ;
2019-09-12 06:49:35 +00:00
if ( allocated [ i + j ] > best2 )
best2 = allocated [ i + j ] ;
2010-02-15 23:26:55 +00:00
}
if ( j = = w )
{ // this is a valid spot
* x = i ;
* y = best = best2 ;
}
}
2019-09-12 06:49:27 +00:00
if ( best + h > LMBLOCK_HEIGHT )
2010-02-15 23:26:55 +00:00
continue ;
for ( i = 0 ; i < w ; i + + )
2019-09-12 06:49:35 +00:00
allocated [ * x + i ] = best + h ;
2010-02-15 23:26:55 +00:00
2019-09-12 06:49:35 +00:00
last_lightmap_allocated = texnum ;
2010-02-15 23:26:55 +00:00
return texnum ;
}
Sys_Error ( " AllocBlock: full " ) ;
return 0 ; //johnfitz -- shut up compiler
}
mvertex_t * r_pcurrentvertbase ;
2012-05-30 08:56:06 +00:00
qmodel_t * currentmodel ;
2010-02-15 23:26:55 +00:00
int nColinElim ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
GL_CreateSurfaceLightmap
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2017-09-17 02:12:53 +00:00
void GL_CreateSurfaceLightmap ( qmodel_t * model , msurface_t * surf )
2010-02-15 23:26:55 +00:00
{
int smax , tmax ;
byte * base ;
2017-12-15 04:01:14 +00:00
smax = ( surf - > extents [ 0 ] > > surf - > lmshift ) + 1 ;
tmax = ( surf - > extents [ 1 ] > > surf - > lmshift ) + 1 ;
2010-02-15 23:26:55 +00:00
surf - > lightmaptexturenum = AllocBlock ( smax , tmax , & surf - > light_s , & surf - > light_t ) ;
2019-09-12 06:49:35 +00:00
base = lightmap [ surf - > lightmaptexturenum ] . data ;
2019-09-12 06:49:27 +00:00
base + = ( surf - > light_t * LMBLOCK_WIDTH + surf - > light_s ) * lightmap_bytes ;
2017-09-17 02:12:53 +00:00
R_BuildLightMap ( model , surf , base , LMBLOCK_WIDTH * lightmap_bytes ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = = = = = =
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 ;
2017-12-15 04:01:14 +00:00
int lmscale = ( 1 < < fa - > lmshift ) ;
2010-02-15 23:26:55 +00:00
// reconstruct the polygon
pedges = currentmodel - > edges ;
lnumverts = fa - > numedges ;
//
// draw texture
//
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
poly = ( glpoly_t * ) Hunk_Alloc ( sizeof ( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof ( float ) ) ;
2010-02-15 23:26:55 +00:00
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 ] ;
2017-12-15 04:01:14 +00:00
s + = fa - > light_s * lmscale ;
s + = lmscale / 2.0 ;
s / = LMBLOCK_WIDTH * lmscale ; //fa->texinfo->texture->width;
2010-02-15 23:26:55 +00:00
t = DotProduct ( vec , fa - > texinfo - > vecs [ 1 ] ) + fa - > texinfo - > vecs [ 1 ] [ 3 ] ;
t - = fa - > texturemins [ 1 ] ;
2017-12-15 04:01:14 +00:00
t + = fa - > light_t * lmscale ;
t + = lmscale / 2.0 ;
t / = LMBLOCK_HEIGHT * lmscale ; //fa->texinfo->texture->height;
2010-02-15 23:26:55 +00:00
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 )
{
2019-09-18 09:17:24 +00:00
char name [ 24 ] ;
2010-02-15 23:26:55 +00:00
int i , j ;
2019-09-12 06:49:35 +00:00
struct lightmap_s * lm ;
2012-05-30 08:56:06 +00:00
qmodel_t * m ;
2010-02-15 23:26:55 +00:00
r_framecount = 1 ; // no dlightcache
2019-09-12 06:49:35 +00:00
//Spike -- wipe out all the lightmap data (johnfitz -- the gltexture objects were already freed by Mod_ClearAll)
for ( i = 0 ; i < lightmap_count ; i + + )
free ( lightmap [ i ] . data ) ;
free ( lightmap ) ;
lightmap = NULL ;
last_lightmap_allocated = 0 ;
lightmap_count = 0 ;
2010-02-15 23:26:55 +00:00
2013-02-20 06:22:42 +00:00
gl_lightmap_format = GL_RGBA ; //FIXME: hardcoded for now!
2010-02-15 23:26:55 +00:00
switch ( gl_lightmap_format )
{
2013-02-20 06:01:10 +00:00
case GL_RGBA :
lightmap_bytes = 4 ;
break ;
case GL_BGRA :
lightmap_bytes = 4 ;
2010-02-15 23:26:55 +00:00
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 ;
2017-09-17 02:12:53 +00:00
GL_CreateSurfaceLightmap ( m , m - > surfaces + i ) ;
2010-02-15 23:26:55 +00:00
BuildSurfaceDisplayList ( m - > surfaces + i ) ;
//johnfitz
}
}
//
// upload all lightmaps that were filled
//
2019-09-12 06:49:35 +00:00
for ( i = 0 ; i < lightmap_count ; i + + )
2010-02-15 23:26:55 +00:00
{
2019-09-12 06:49:35 +00:00
lm = & lightmap [ i ] ;
lm - > modified = false ;
lm - > rectchange . l = LMBLOCK_WIDTH ;
lm - > rectchange . t = LMBLOCK_HEIGHT ;
lm - > rectchange . w = 0 ;
lm - > rectchange . h = 0 ;
2010-02-15 23:26:55 +00:00
//johnfitz -- use texture manager
2019-09-18 09:17:24 +00:00
sprintf ( name , " lightmap%07i " , i ) ;
2019-09-12 06:49:35 +00:00
lm - > texture = TexMgr_LoadImage ( cl . worldmodel , name , LMBLOCK_WIDTH , LMBLOCK_HEIGHT ,
SRC_LIGHTMAP , lm - > data , " " , ( src_offset_t ) lm - > data , TEXPREF_LINEAR | TEXPREF_NOPICMIP ) ;
2010-02-15 23:26:55 +00:00
//johnfitz
}
//johnfitz -- warn about exceeding old limits
2019-09-18 09:17:24 +00:00
//GLQuake limit was 64 textures of 128x128. Estimate how many 128x128 textures we would need
//given that we are using lightmap_count of LMBLOCK_WIDTH x LMBLOCK_HEIGHT
i = lightmap_count * ( ( LMBLOCK_WIDTH / 128 ) * ( LMBLOCK_HEIGHT / 128 ) ) ;
if ( i > 64 )
Con_DWarning ( " %i lightmaps exceeds standard limit of 64. \n " , i ) ;
2010-02-15 23:26:55 +00:00
//johnfitz
}
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt.
Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo".
Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-11 04:55:16 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
VBO support
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
GLuint gl_bmodel_vbo = 0 ;
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt.
Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo".
Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-11 04:55:16 +00:00
2015-09-20 20:10:49 +00:00
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 ( ) ;
}
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt.
Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo".
Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-11 04:55:16 +00:00
/*
= = = = = = = = = = = = = = = = = =
2015-09-20 20:10:49 +00:00
GL_BuildBModelVertexBuffer
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt.
Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo".
Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-11 04:55:16 +00:00
Deletes gl_bmodel_vbo if it already exists , then rebuilds it with all
surfaces from world + all brush models
= = = = = = = = = = = = = = = = = =
*/
2015-09-20 20:10:49 +00:00
void GL_BuildBModelVertexBuffer ( void )
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt.
Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo".
Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-11 04:55:16 +00:00
{
unsigned int numverts , varray_bytes , varray_index ;
int i , j ;
qmodel_t * m ;
float * varray ;
2014-09-20 01:08:13 +00:00
if ( ! ( gl_vbo_able & & gl_mtexable & & gl_max_texture_units > = 3 ) )
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt.
Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo".
Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-11 04:55:16 +00:00
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 ) ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
// invalidate the cached bindings
GL_ClearBufferBindings ( ) ;
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt.
Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo".
Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-11 04:55:16 +00:00
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = =
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
2018-05-25 10:54:33 +00:00
vec3_t lightofs ; //Spike: light surfaces based upon where they are now instead of their default position.
2017-12-15 04:01:14 +00:00
int lmscale ;
2010-02-15 23:26:55 +00:00
2017-12-15 04:01:14 +00:00
smax = ( surf - > extents [ 0 ] > > surf - > lmshift ) + 1 ;
tmax = ( surf - > extents [ 1 ] > > surf - > lmshift ) + 1 ;
2010-02-15 23:26:55 +00:00
tex = surf - > texinfo ;
2017-12-15 04:01:14 +00:00
lmscale = 1 < < surf - > lmshift ;
2010-02-15 23:26:55 +00:00
for ( lnum = 0 ; lnum < MAX_DLIGHTS ; lnum + + )
{
2012-07-10 11:21:17 +00:00
if ( ! ( surf - > dlightbits [ lnum > > 5 ] & ( 1U < < ( lnum & 31 ) ) ) )
2010-02-15 23:26:55 +00:00
continue ; // not lit by this light
rad = cl_dlights [ lnum ] . radius ;
2018-05-25 10:54:33 +00:00
VectorSubtract ( cl_dlights [ lnum ] . origin , currententity - > origin , lightofs ) ;
dist = DotProduct ( lightofs , surf - > plane - > normal ) - surf - > plane - > dist ;
2010-02-15 23:26:55 +00:00
rad - = fabs ( dist ) ;
minlight = cl_dlights [ lnum ] . minlight ;
if ( rad < minlight )
continue ;
minlight = rad - minlight ;
for ( i = 0 ; i < 3 ; i + + )
{
2018-05-25 10:54:33 +00:00
impact [ i ] = lightofs [ i ] -
2010-02-15 23:26:55 +00:00
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 + + )
{
2017-12-15 04:01:14 +00:00
td = local [ 1 ] - t * lmscale ;
2010-02-15 23:26:55 +00:00
if ( td < 0 )
td = - td ;
for ( s = 0 ; s < smax ; s + + )
{
2017-12-15 04:01:14 +00:00
sd = local [ 0 ] - s * lmscale ;
2010-02-15 23:26:55 +00:00
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
= = = = = = = = = = = = = = =
*/
2017-09-17 02:12:53 +00:00
void R_BuildLightMap ( qmodel_t * model , msurface_t * surf , byte * dest , int stride )
2010-02-15 23:26:55 +00:00
{
int smax , tmax ;
2013-02-20 06:01:10 +00:00
int r , g , b ;
2010-02-15 23:26:55 +00:00
int i , j , size ;
byte * lightmap ;
unsigned scale ;
int maps ;
unsigned * bl ;
surf - > cached_dlight = ( surf - > dlightframe = = r_framecount ) ;
2017-12-15 04:01:14 +00:00
smax = ( surf - > extents [ 0 ] > > surf - > lmshift ) + 1 ;
tmax = ( surf - > extents [ 1 ] > > surf - > lmshift ) + 1 ;
2010-02-15 23:26:55 +00:00
size = smax * tmax ;
lightmap = surf - > samples ;
2017-09-17 02:12:53 +00:00
if ( model - > lightdata )
2010-02-15 23:26:55 +00:00
{
// clear to no light
memset ( & blocklights [ 0 ] , 0 , size * 3 * sizeof ( unsigned int ) ) ; //johnfitz -- lit support via lordhavoc
// add all the lightmaps
if ( lightmap )
2016-04-28 21:47:12 +00:00
{
2019-09-10 14:41:11 +00:00
for ( maps = 0 ; maps < MAXLIGHTMAPS & & surf - > styles [ maps ] ! = INVALID_LIGHTSTYLE ;
2010-02-15 23:26:55 +00:00
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
}
2016-04-28 21:47:12 +00:00
}
2010-02-15 23:26:55 +00:00
// 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
chase.c, cl_input.c, cl_parse.c, client.h, common.c, common.h, console.h,
cvar.h, draw.h, gl_draw.c, gl_fog.c, gl_mesh.c, gl_model.c, gl_model.h,
gl_rmain.c, gl_rmisc.c, gl_screen.c, gl_sky.c, gl_texmgr.c, glquake.h,
host.c, keys.c, keys.h, main.c, menu.c, menu.h, pr_cmds.c, quakedef.h,
r_alias.c, r_brush.c, r_part.c, r_sprite.c, r_world.c, sbar.c, sbar.h,
screen.h, snd_dma.c, snd_mem.c, snd_mix.c, sv_main.c, sys_sdl.c, vid.h,
view.h, world.c, world.h: Loads of warning fixes about missing function
prototypes, missing parens around &, missing braces leading to ambiguous
else statements and unused and uninitialized variables. There are still a
couple of unitialised variables here and there, but not much. The warnings
about strict aliasing violations need taking care of.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@21 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-02-16 12:01:07 +00:00
// store:
2010-02-15 23:26:55 +00:00
switch ( gl_lightmap_format )
{
2013-02-20 06:01:10 +00:00
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 ;
}
2016-04-28 21:47:12 +00:00
* dest + + = ( r > 255 ) ? 255 : r ;
* dest + + = ( g > 255 ) ? 255 : g ;
* dest + + = ( b > 255 ) ? 255 : b ;
2013-02-20 06:01:10 +00:00
* dest + + = 255 ;
}
}
break ;
case GL_BGRA :
stride - = smax * 4 ;
2010-02-15 23:26:55 +00:00
bl = blocklights ;
for ( i = 0 ; i < tmax ; i + + , dest + = stride )
{
for ( j = 0 ; j < smax ; j + + )
{
if ( gl_overbright . value )
{
2013-02-20 06:01:10 +00:00
r = * bl + + > > 8 ;
g = * bl + + > > 8 ;
b = * bl + + > > 8 ;
2010-02-15 23:26:55 +00:00
}
else
{
2013-02-20 06:01:10 +00:00
r = * bl + + > > 7 ;
g = * bl + + > > 7 ;
b = * bl + + > > 7 ;
2010-02-15 23:26:55 +00:00
}
2016-04-28 21:47:12 +00:00
* dest + + = ( b > 255 ) ? 255 : b ;
* dest + + = ( g > 255 ) ? 255 : g ;
* dest + + = ( r > 255 ) ? 255 : r ;
2013-02-20 06:01:10 +00:00
* dest + + = 255 ;
2010-02-15 23:26:55 +00:00
}
}
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
= = = = = = = = = = = = = = =
*/
2014-07-12 07:01:58 +00:00
static void R_UploadLightmap ( int lmap )
2010-02-15 23:26:55 +00:00
{
2019-09-12 06:49:35 +00:00
struct lightmap_s * lm = & lightmap [ lmap ] ;
2010-02-15 23:26:55 +00:00
2019-09-12 06:49:35 +00:00
if ( ! lm - > modified )
2010-02-15 23:26:55 +00:00
return ;
2019-09-12 06:49:35 +00:00
lm - > modified = false ;
2010-02-15 23:26:55 +00:00
2019-09-12 06:49:35 +00:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , lm - > rectchange . t , LMBLOCK_WIDTH , lm - > rectchange . h , gl_lightmap_format ,
GL_UNSIGNED_BYTE , lm - > data + lm - > rectchange . t * LMBLOCK_WIDTH * lightmap_bytes ) ;
lm - > rectchange . l = LMBLOCK_WIDTH ;
lm - > rectchange . t = LMBLOCK_HEIGHT ;
lm - > rectchange . h = 0 ;
lm - > rectchange . w = 0 ;
2010-02-15 23:26:55 +00:00
rs_dynamiclightmaps + + ;
}
2014-07-12 07:01:58 +00:00
void R_UploadLightmaps ( void )
{
int lmap ;
2019-09-12 06:49:35 +00:00
for ( lmap = 0 ; lmap < lightmap_count ; lmap + + )
2014-07-12 07:01:58 +00:00
{
2019-09-12 06:49:35 +00:00
if ( ! lightmap [ lmap ] . modified )
2014-07-12 07:01:58 +00:00
continue ;
2019-09-12 06:49:35 +00:00
GL_Bind ( lightmap [ lmap ] . texture ) ;
2014-07-12 07:01:58 +00:00
R_UploadLightmap ( lmap ) ;
}
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = =
R_RebuildAllLightmaps - - johnfitz - - called when gl_overbright gets toggled
= = = = = = = = = = = = = = = =
*/
void R_RebuildAllLightmaps ( void )
{
int i , j ;
2012-05-30 08:56:06 +00:00
qmodel_t * mod ;
2010-02-15 23:26:55 +00:00
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 ;
2019-09-12 06:49:35 +00:00
base = lightmap [ fa - > lightmaptexturenum ] . data ;
2019-09-12 06:49:27 +00:00
base + = fa - > light_t * LMBLOCK_WIDTH * lightmap_bytes + fa - > light_s * lightmap_bytes ;
2017-09-17 02:12:53 +00:00
R_BuildLightMap ( mod , fa , base , LMBLOCK_WIDTH * lightmap_bytes ) ;
2010-02-15 23:26:55 +00:00
}
}
//for each lightmap, upload it
2019-09-12 06:49:35 +00:00
for ( i = 0 ; i < lightmap_count ; i + + )
2010-02-15 23:26:55 +00:00
{
2019-09-12 06:49:35 +00:00
GL_Bind ( lightmap [ i ] . texture ) ;
2019-09-12 06:49:27 +00:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , LMBLOCK_WIDTH , LMBLOCK_HEIGHT , gl_lightmap_format ,
2019-09-12 06:49:35 +00:00
GL_UNSIGNED_BYTE , lightmap [ i ] . data ) ;
2010-02-15 23:26:55 +00:00
}
}