yquake2remaster/src/refresh/gl_rsurf.c

1231 lines
24 KiB
C
Raw Normal View History

/*
2010-10-22 08:04:31 +00:00
* Copyright (C) 1997-2001 Id Software, Inc.
*
* 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.
*
*/
2009-03-05 13:08:47 +00:00
#include <assert.h>
2009-03-05 11:03:08 +00:00
#include "header/local.h"
#define DYNAMIC_LIGHT_WIDTH 128
#define DYNAMIC_LIGHT_HEIGHT 128
#define LIGHTMAP_BYTES 4
2010-10-22 08:04:31 +00:00
#define MAX_LIGHTMAPS 128
#define GL_LIGHTMAP_FORMAT GL_RGBA
2010-10-22 08:04:31 +00:00
int c_visible_lightmaps;
int c_visible_textures;
static vec3_t modelorg; /* relative to viewpoint */
msurface_t *r_alpha_surfaces;
typedef struct
{
int internal_format;
2010-10-22 08:04:31 +00:00
int current_lightmap_texture;
2010-10-22 08:04:31 +00:00
msurface_t *lightmap_surfaces [ MAX_LIGHTMAPS ];
2010-10-22 08:04:31 +00:00
int allocated [ BLOCK_WIDTH ];
2010-10-22 08:04:31 +00:00
/* the lightmap texture data needs to be kept in
main memory so texsubimage can update properly */
byte lightmap_buffer [ 4 * BLOCK_WIDTH * BLOCK_HEIGHT ];
} gllightmapstate_t;
static gllightmapstate_t gl_lms;
2010-10-22 08:04:31 +00:00
static void LM_InitBlock ( void );
static void LM_UploadBlock ( qboolean dynamic );
static qboolean LM_AllocBlock ( int w, int h, int *x, int *y );
2010-10-22 08:04:31 +00:00
extern void R_SetCacheState ( msurface_t *surf );
extern void R_BuildLightMap ( msurface_t *surf, byte *dest, int stride );
/*
2010-10-22 08:04:31 +00:00
* Returns the proper texture for a given time and base texture
*/
image_t *
R_TextureAnimation ( mtexinfo_t *tex )
{
2010-10-22 08:04:31 +00:00
int c;
2010-10-22 08:04:31 +00:00
if ( !tex->next )
{
return ( tex->image );
}
c = currententity->frame % tex->numframes;
2010-10-22 08:04:31 +00:00
while ( c )
{
tex = tex->next;
c--;
}
2010-10-22 08:04:31 +00:00
return ( tex->image );
}
2010-10-22 08:04:31 +00:00
void
DrawGLPoly ( glpoly_t *p )
{
2010-10-22 08:04:31 +00:00
int i;
float *v;
2010-10-22 08:04:31 +00:00
qglBegin( GL_POLYGON );
v = p->verts [ 0 ];
for ( i = 0; i < p->numverts; i++, v += VERTEXSIZE )
{
2010-10-22 08:04:31 +00:00
qglTexCoord2f( v [ 3 ], v [ 4 ] );
qglVertex3fv( v );
}
2010-10-22 08:04:31 +00:00
qglEnd();
}
2010-10-22 08:04:31 +00:00
void
DrawGLFlowingPoly ( msurface_t *fa )
{
2010-10-22 08:04:31 +00:00
int i;
float *v;
glpoly_t *p;
2010-10-22 08:04:31 +00:00
float scroll;
p = fa->polys;
2010-10-22 08:04:31 +00:00
scroll = -64 * ( ( r_newrefdef.time / 40.0 ) - (int) ( r_newrefdef.time / 40.0 ) );
if ( scroll == 0.0 )
{
scroll = -64.0;
2010-10-22 08:04:31 +00:00
}
2010-10-22 08:04:31 +00:00
qglBegin( GL_POLYGON );
v = p->verts [ 0 ];
for ( i = 0; i < p->numverts; i++, v += VERTEXSIZE )
{
2010-10-22 08:04:31 +00:00
qglTexCoord2f( ( v [ 3 ] + scroll ), v [ 4 ] );
qglVertex3fv( v );
}
2010-10-22 08:04:31 +00:00
qglEnd();
}
2010-10-22 08:04:31 +00:00
void
R_DrawTriangleOutlines ( void )
{
2010-10-22 08:04:31 +00:00
int i, j;
glpoly_t *p;
2010-10-22 08:04:31 +00:00
if ( !gl_showtris->value )
{
return;
2010-10-22 08:04:31 +00:00
}
2010-10-22 08:04:31 +00:00
qglDisable( GL_TEXTURE_2D );
qglDisable( GL_DEPTH_TEST );
qglColor4f( 1, 1, 1, 1 );
2010-10-22 08:04:31 +00:00
for ( i = 0; i < MAX_LIGHTMAPS; i++ )
{
msurface_t *surf;
2010-10-22 08:04:31 +00:00
for ( surf = gl_lms.lightmap_surfaces [ i ]; surf != 0; surf = surf->lightmapchain )
{
p = surf->polys;
2010-10-22 08:04:31 +00:00
for ( ; p; p = p->chain )
{
2010-10-22 08:04:31 +00:00
for ( j = 2; j < p->numverts; j++ )
{
2010-10-22 08:04:31 +00:00
qglBegin( GL_LINE_STRIP );
qglVertex3fv( p->verts [ 0 ] );
qglVertex3fv( p->verts [ j - 1 ] );
qglVertex3fv( p->verts [ j ] );
qglVertex3fv( p->verts [ 0 ] );
qglEnd();
}
}
}
}
2010-10-22 08:04:31 +00:00
qglEnable( GL_DEPTH_TEST );
qglEnable( GL_TEXTURE_2D );
}
2010-10-22 08:04:31 +00:00
void
DrawGLPolyChain ( glpoly_t *p, float soffset, float toffset )
{
2010-10-22 08:04:31 +00:00
if ( ( soffset == 0 ) && ( toffset == 0 ) )
{
for ( ; p != 0; p = p->chain )
{
float *v;
int j;
2010-10-22 08:04:31 +00:00
v = p->verts [ 0 ];
if ( v == NULL )
{
fprintf( stderr, "BUGFIX: DrawGLPolyChain: v==NULL\n" );
return;
}
2010-10-22 08:04:31 +00:00
qglBegin( GL_POLYGON );
for ( j = 0; j < p->numverts; j++, v += VERTEXSIZE )
{
2010-10-22 08:04:31 +00:00
qglTexCoord2f( v [ 5 ], v [ 6 ] );
qglVertex3fv( v );
}
2010-10-22 08:04:31 +00:00
qglEnd();
}
}
else
{
for ( ; p != 0; p = p->chain )
{
float *v;
int j;
2010-10-22 08:04:31 +00:00
qglBegin( GL_POLYGON );
v = p->verts [ 0 ];
for ( j = 0; j < p->numverts; j++, v += VERTEXSIZE )
{
2010-10-22 08:04:31 +00:00
qglTexCoord2f( v [ 5 ] - soffset, v [ 6 ] - toffset );
qglVertex3fv( v );
}
2010-10-22 08:04:31 +00:00
qglEnd();
}
}
}
/*
2010-10-22 08:04:31 +00:00
* This routine takes all the given light mapped surfaces in the world
* and blends them into the framebuffer.
*/
2010-10-22 08:04:31 +00:00
void
R_BlendLightmaps ( void )
{
2010-10-22 08:04:31 +00:00
int i;
msurface_t *surf, *newdrawsurf = 0;
2010-10-22 08:04:31 +00:00
/* don't bother if we're set to fullbright */
if ( r_fullbright->value )
{
return;
2010-10-22 08:04:31 +00:00
}
if ( !r_worldmodel->lightdata )
{
return;
2010-10-22 08:04:31 +00:00
}
2010-10-22 08:04:31 +00:00
/* don't bother writing Z */
qglDepthMask( 0 );
2010-10-22 08:04:31 +00:00
/* set the appropriate blending mode unless
we're only looking at the lightmaps. */
if ( !gl_lightmap->value )
{
2010-10-22 08:04:31 +00:00
qglEnable( GL_BLEND );
if ( gl_saturatelighting->value )
{
qglBlendFunc( GL_ONE, GL_ONE );
}
else
{
qglBlendFunc( GL_ZERO, GL_SRC_COLOR );
}
}
if ( currentmodel == r_worldmodel )
2010-10-22 08:04:31 +00:00
{
c_visible_lightmaps = 0;
2010-10-22 08:04:31 +00:00
}
2010-10-22 08:04:31 +00:00
/* render static lightmaps first */
for ( i = 1; i < MAX_LIGHTMAPS; i++ )
{
2010-10-22 08:04:31 +00:00
if ( gl_lms.lightmap_surfaces [ i ] )
{
2010-10-22 08:04:31 +00:00
if ( currentmodel == r_worldmodel )
{
c_visible_lightmaps++;
2010-10-22 08:04:31 +00:00
}
R_Bind( gl_state.lightmap_textures + i );
2010-10-22 08:04:31 +00:00
for ( surf = gl_lms.lightmap_surfaces [ i ]; surf != 0; surf = surf->lightmapchain )
{
if ( surf->polys )
2010-10-22 08:04:31 +00:00
{
DrawGLPolyChain( surf->polys, 0, 0 );
2010-10-22 08:04:31 +00:00
}
}
}
}
2010-10-22 08:04:31 +00:00
/* render dynamic lightmaps */
if ( gl_dynamic->value )
{
LM_InitBlock();
R_Bind( gl_state.lightmap_textures + 0 );
2010-10-22 08:04:31 +00:00
if ( currentmodel == r_worldmodel )
{
c_visible_lightmaps++;
2010-10-22 08:04:31 +00:00
}
2010-10-22 08:04:31 +00:00
newdrawsurf = gl_lms.lightmap_surfaces [ 0 ];
2010-10-22 08:04:31 +00:00
for ( surf = gl_lms.lightmap_surfaces [ 0 ]; surf != 0; surf = surf->lightmapchain )
{
2010-10-22 08:04:31 +00:00
int smax, tmax;
byte *base;
2010-10-22 08:04:31 +00:00
smax = ( surf->extents [ 0 ] >> 4 ) + 1;
tmax = ( surf->extents [ 1 ] >> 4 ) + 1;
if ( LM_AllocBlock( smax, tmax, &surf->dlight_s, &surf->dlight_t ) )
{
base = gl_lms.lightmap_buffer;
base += ( surf->dlight_t * BLOCK_WIDTH + surf->dlight_s ) * LIGHTMAP_BYTES;
2010-10-22 08:04:31 +00:00
R_BuildLightMap( surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES );
}
else
{
msurface_t *drawsurf;
2010-10-22 08:04:31 +00:00
/* upload what we have so far */
LM_UploadBlock( true );
2010-10-22 08:04:31 +00:00
/* draw all surfaces that use this lightmap */
for ( drawsurf = newdrawsurf; drawsurf != surf; drawsurf = drawsurf->lightmapchain )
{
if ( drawsurf->polys )
2010-10-22 08:04:31 +00:00
{
DrawGLPolyChain( drawsurf->polys,
( drawsurf->light_s - drawsurf->dlight_s ) * ( 1.0 / 128.0 ),
( drawsurf->light_t - drawsurf->dlight_t ) * ( 1.0 / 128.0 ) );
}
}
newdrawsurf = drawsurf;
2010-10-22 08:04:31 +00:00
/* clear the block */
LM_InitBlock();
2010-10-22 08:04:31 +00:00
/* try uploading the block now */
if ( !LM_AllocBlock( smax, tmax, &surf->dlight_s, &surf->dlight_t ) )
{
ri.Sys_Error( ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed (dynamic)\n", smax, tmax );
}
base = gl_lms.lightmap_buffer;
base += ( surf->dlight_t * BLOCK_WIDTH + surf->dlight_s ) * LIGHTMAP_BYTES;
2010-10-22 08:04:31 +00:00
R_BuildLightMap( surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES );
}
}
2010-10-22 08:04:31 +00:00
/* draw remainder of dynamic lightmaps that haven't been uploaded yet */
if ( newdrawsurf )
2010-10-22 08:04:31 +00:00
{
LM_UploadBlock( true );
2010-10-22 08:04:31 +00:00
}
for ( surf = newdrawsurf; surf != 0; surf = surf->lightmapchain )
{
if ( surf->polys )
2010-10-22 08:04:31 +00:00
{
DrawGLPolyChain( surf->polys, ( surf->light_s - surf->dlight_s ) * ( 1.0 / 128.0 ),
( surf->light_t - surf->dlight_t ) * ( 1.0 / 128.0 ) );
}
}
}
2010-10-22 08:04:31 +00:00
/* restore state */
qglDisable( GL_BLEND );
qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
qglDepthMask( 1 );
}
2010-10-22 08:04:31 +00:00
void
R_RenderBrushPoly ( msurface_t *fa )
{
2010-10-22 08:04:31 +00:00
int maps;
image_t *image;
qboolean is_dynamic = false;
c_brush_polys++;
2010-10-22 08:04:31 +00:00
image = R_TextureAnimation( fa->texinfo );
2010-10-22 08:04:31 +00:00
if ( fa->flags & SURF_DRAWTURB )
{
R_Bind( image->texnum );
2010-10-22 08:04:31 +00:00
/* warp texture, no lightmaps */
R_TexEnv( GL_MODULATE );
2010-10-22 08:04:31 +00:00
qglColor4f( gl_state.inverse_intensity,
gl_state.inverse_intensity,
gl_state.inverse_intensity,
1.0F );
EmitWaterPolys( fa );
R_TexEnv( GL_REPLACE );
return;
}
else
{
R_Bind( image->texnum );
R_TexEnv( GL_REPLACE );
}
2010-10-22 08:04:31 +00:00
if ( fa->texinfo->flags & SURF_FLOWING )
{
DrawGLFlowingPoly( fa );
}
else
2010-10-22 08:04:31 +00:00
{
DrawGLPoly( fa->polys );
}
2010-10-22 08:04:31 +00:00
/* check for lightmap modification */
for ( maps = 0; maps < MAXLIGHTMAPS && fa->styles [ maps ] != 255; maps++ )
{
2010-10-22 08:04:31 +00:00
if ( r_newrefdef.lightstyles [ fa->styles [ maps ] ].white != fa->cached_light [ maps ] )
{
goto dynamic;
2010-10-22 08:04:31 +00:00
}
}
2010-10-22 08:04:31 +00:00
/* dynamic this frame or dynamic previously */
if ( ( fa->dlightframe == r_framecount ) )
{
2010-10-22 08:04:31 +00:00
dynamic:
if ( gl_dynamic->value )
{
2010-10-22 08:04:31 +00:00
if ( !( fa->texinfo->flags & ( SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP ) ) )
{
is_dynamic = true;
}
}
}
if ( is_dynamic )
{
2010-10-22 08:04:31 +00:00
if ( ( ( fa->styles [ maps ] >= 32 ) || ( fa->styles [ maps ] == 0 ) ) && ( fa->dlightframe != r_framecount ) )
{
2010-10-22 08:04:31 +00:00
unsigned temp [ 34 * 34 ];
int smax, tmax;
2010-10-22 08:04:31 +00:00
smax = ( fa->extents [ 0 ] >> 4 ) + 1;
tmax = ( fa->extents [ 1 ] >> 4 ) + 1;
2010-10-22 08:04:31 +00:00
R_BuildLightMap( fa, (void *) temp, smax * 4 );
R_SetCacheState( fa );
R_Bind( gl_state.lightmap_textures + fa->lightmaptexturenum );
qglTexSubImage2D( GL_TEXTURE_2D, 0,
2010-10-22 08:04:31 +00:00
fa->light_s, fa->light_t,
smax, tmax,
GL_LIGHTMAP_FORMAT,
GL_UNSIGNED_BYTE, temp );
2010-10-22 08:04:31 +00:00
fa->lightmapchain = gl_lms.lightmap_surfaces [ fa->lightmaptexturenum ];
gl_lms.lightmap_surfaces [ fa->lightmaptexturenum ] = fa;
}
else
{
2010-10-22 08:04:31 +00:00
fa->lightmapchain = gl_lms.lightmap_surfaces [ 0 ];
gl_lms.lightmap_surfaces [ 0 ] = fa;
}
}
else
{
2010-10-22 08:04:31 +00:00
fa->lightmapchain = gl_lms.lightmap_surfaces [ fa->lightmaptexturenum ];
gl_lms.lightmap_surfaces [ fa->lightmaptexturenum ] = fa;
}
}
/*
2010-10-22 08:04:31 +00:00
* Draw water surfaces and windows.
* The BSP tree is waled front to back, so unwinding the chain
* of alpha_surfaces will draw back to front, giving proper ordering.
*/
void
R_DrawAlphaSurfaces ( void )
{
2010-10-22 08:04:31 +00:00
msurface_t *s;
float intens;
/* go back to the world matrix */
qglLoadMatrixf( r_world_matrix );
qglEnable( GL_BLEND );
R_TexEnv( GL_MODULATE );
2010-10-22 08:04:31 +00:00
/* the textures are prescaled up for a better lighting range,
so scale it back down */
intens = gl_state.inverse_intensity;
2010-10-22 08:04:31 +00:00
for ( s = r_alpha_surfaces; s; s = s->texturechain )
{
R_Bind( s->texinfo->image->texnum );
c_brush_polys++;
2010-10-22 08:04:31 +00:00
if ( s->texinfo->flags & SURF_TRANS33 )
{
qglColor4f( intens, intens, intens, 0.33 );
}
else if ( s->texinfo->flags & SURF_TRANS66 )
{
qglColor4f( intens, intens, intens, 0.66 );
}
else
2010-10-22 08:04:31 +00:00
{
qglColor4f( intens, intens, intens, 1 );
}
if ( s->flags & SURF_DRAWTURB )
{
EmitWaterPolys( s );
}
else if ( s->texinfo->flags & SURF_FLOWING )
{
DrawGLFlowingPoly( s );
}
else
2010-10-22 08:04:31 +00:00
{
DrawGLPoly( s->polys );
}
}
R_TexEnv( GL_REPLACE );
2010-10-22 08:04:31 +00:00
qglColor4f( 1, 1, 1, 1 );
qglDisable( GL_BLEND );
r_alpha_surfaces = NULL;
}
2010-10-22 08:04:31 +00:00
void
DrawTextureChains ( void )
{
2010-10-22 08:04:31 +00:00
int i;
msurface_t *s;
image_t *image;
c_visible_textures = 0;
2010-10-22 08:04:31 +00:00
for ( i = 0, image = gltextures; i < numgltextures; i++, image++ )
{
2010-10-22 08:04:31 +00:00
if ( !image->registration_sequence )
{
continue;
2010-10-22 08:04:31 +00:00
}
s = image->texturechain;
2010-10-22 08:04:31 +00:00
if ( !s )
{
continue;
2010-10-22 08:04:31 +00:00
}
c_visible_textures++;
2010-10-22 08:04:31 +00:00
for ( ; s; s = s->texturechain )
{
R_RenderBrushPoly( s );
}
image->texturechain = NULL;
}
R_TexEnv( GL_REPLACE );
}
2010-10-22 08:04:31 +00:00
void
R_DrawInlineBModel ( void )
{
2010-10-22 08:04:31 +00:00
int i, k;
cplane_t *pplane;
float dot;
msurface_t *psurf;
dlight_t *lt;
2010-10-22 08:04:31 +00:00
/* calculate dynamic lighting for bmodel */
if ( !gl_flashblend->value )
{
lt = r_newrefdef.dlights;
2010-10-22 08:04:31 +00:00
for ( k = 0; k < r_newrefdef.num_dlights; k++, lt++ )
{
2010-10-22 08:04:31 +00:00
R_MarkLights( lt, 1 << k, currentmodel->nodes + currentmodel->firstnode );
}
}
2010-10-22 08:04:31 +00:00
psurf = &currentmodel->surfaces [ currentmodel->firstmodelsurface ];
if ( currententity->flags & RF_TRANSLUCENT )
{
2010-10-22 08:04:31 +00:00
qglEnable( GL_BLEND );
qglColor4f( 1, 1, 1, 0.25 );
R_TexEnv( GL_MODULATE );
}
2010-10-22 08:04:31 +00:00
/* draw texture */
for ( i = 0; i < currentmodel->nummodelsurfaces; i++, psurf++ )
{
2010-10-22 08:04:31 +00:00
/* find which side of the node we are on */
pplane = psurf->plane;
2010-10-22 08:04:31 +00:00
dot = DotProduct( modelorg, pplane->normal ) - pplane->dist;
2010-10-22 08:04:31 +00:00
/* draw the polygon */
if ( ( ( psurf->flags & SURF_PLANEBACK ) && ( dot < -BACKFACE_EPSILON ) ) ||
( !( psurf->flags & SURF_PLANEBACK ) && ( dot > BACKFACE_EPSILON ) ) )
{
2010-10-22 08:04:31 +00:00
if ( psurf->texinfo->flags & ( SURF_TRANS33 | SURF_TRANS66 ) )
{
/* add to the translucent chain */
psurf->texturechain = r_alpha_surfaces;
r_alpha_surfaces = psurf;
}
else
{
R_RenderBrushPoly( psurf );
}
}
}
2010-10-22 08:04:31 +00:00
if ( !( currententity->flags & RF_TRANSLUCENT ) )
{
2010-10-22 08:04:31 +00:00
R_BlendLightmaps();
}
else
{
2010-10-22 08:04:31 +00:00
qglDisable( GL_BLEND );
qglColor4f( 1, 1, 1, 1 );
R_TexEnv( GL_REPLACE );
}
}
2010-10-22 08:04:31 +00:00
void
R_DrawBrushModel ( entity_t *e )
{
2010-10-22 08:04:31 +00:00
vec3_t mins, maxs;
int i;
qboolean rotated;
2010-10-22 08:04:31 +00:00
if ( currentmodel->nummodelsurfaces == 0 )
{
return;
2010-10-22 08:04:31 +00:00
}
currententity = e;
2010-10-22 08:04:31 +00:00
gl_state.currenttextures [ 0 ] = gl_state.currenttextures [ 1 ] = -1;
2010-10-22 08:04:31 +00:00
if ( e->angles [ 0 ] || e->angles [ 1 ] || e->angles [ 2 ] )
{
rotated = true;
2010-10-22 08:04:31 +00:00
for ( i = 0; i < 3; i++ )
{
2010-10-22 08:04:31 +00:00
mins [ i ] = e->origin [ i ] - currentmodel->radius;
maxs [ i ] = e->origin [ i ] + currentmodel->radius;
}
}
else
{
rotated = false;
2010-10-22 08:04:31 +00:00
VectorAdd( e->origin, currentmodel->mins, mins );
VectorAdd( e->origin, currentmodel->maxs, maxs );
}
2010-10-22 08:04:31 +00:00
if ( R_CullBox( mins, maxs ) )
{
return;
2010-10-22 08:04:31 +00:00
}
2010-10-22 08:04:31 +00:00
qglColor3f( 1, 1, 1 );
memset( gl_lms.lightmap_surfaces, 0, sizeof ( gl_lms.lightmap_surfaces ) );
2010-10-22 08:04:31 +00:00
VectorSubtract( r_newrefdef.vieworg, e->origin, modelorg );
2010-10-22 08:04:31 +00:00
if ( rotated )
{
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 );
}
2010-10-22 08:04:31 +00:00
qglPushMatrix();
e->angles [ 0 ] = -e->angles [ 0 ];
e->angles [ 2 ] = -e->angles [ 2 ];
R_RotateForEntity( e );
e->angles [ 0 ] = -e->angles [ 0 ];
e->angles [ 2 ] = -e->angles [ 2 ];
R_TexEnv( GL_REPLACE );
R_TexEnv( GL_MODULATE );
2010-10-22 08:04:31 +00:00
R_DrawInlineBModel();
2010-10-22 08:04:31 +00:00
qglPopMatrix();
}
2010-10-22 08:04:31 +00:00
void
R_RecursiveWorldNode ( mnode_t *node )
{
2010-10-22 08:04:31 +00:00
int c, side, sidebit;
cplane_t *plane;
msurface_t *surf, **mark;
mleaf_t *pleaf;
float dot;
image_t *image;
if ( node->contents == CONTENTS_SOLID )
{
return; /* solid */
}
2010-10-22 08:04:31 +00:00
if ( node->visframe != r_visframecount )
{
return;
2010-10-22 08:04:31 +00:00
}
if ( R_CullBox( node->minmaxs, node->minmaxs + 3 ) )
{
return;
2010-10-22 08:04:31 +00:00
}
/* if a leaf node, draw stuff */
if ( node->contents != -1 )
{
2010-10-22 08:04:31 +00:00
pleaf = (mleaf_t *) node;
2010-10-22 08:04:31 +00:00
/* check for door connected areas */
if ( r_newrefdef.areabits )
{
2010-10-22 08:04:31 +00:00
if ( !( r_newrefdef.areabits [ pleaf->area >> 3 ] & ( 1 << ( pleaf->area & 7 ) ) ) )
{
return; /* not visible */
}
}
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
2010-10-22 08:04:31 +00:00
if ( c )
{
do
{
2010-10-22 08:04:31 +00:00
( *mark )->visframe = r_framecount;
mark++;
2010-10-22 08:04:31 +00:00
}
while ( --c );
}
return;
}
2010-10-22 08:04:31 +00:00
/* node is just a decision point, so go down the apropriate sides
find which side of the node we are on */
plane = node->plane;
2010-10-22 08:04:31 +00:00
switch ( plane->type )
{
2010-10-22 08:04:31 +00:00
case PLANE_X:
dot = modelorg [ 0 ] - plane->dist;
break;
case PLANE_Y:
dot = modelorg [ 1 ] - plane->dist;
break;
case PLANE_Z:
dot = modelorg [ 2 ] - plane->dist;
break;
default:
dot = DotProduct( modelorg, plane->normal ) - plane->dist;
break;
}
2010-10-22 08:04:31 +00:00
if ( dot >= 0 )
{
side = 0;
sidebit = 0;
}
else
{
side = 1;
sidebit = SURF_PLANEBACK;
}
2010-10-22 08:04:31 +00:00
/* recurse down the children, front side first */
R_RecursiveWorldNode( node->children [ side ] );
2010-10-22 08:04:31 +00:00
/* draw stuff */
for ( c = node->numsurfaces, surf = r_worldmodel->surfaces + node->firstsurface; c; c--, surf++ )
{
2010-10-22 08:04:31 +00:00
if ( surf->visframe != r_framecount )
{
continue;
2010-10-22 08:04:31 +00:00
}
2010-10-22 08:04:31 +00:00
if ( ( surf->flags & SURF_PLANEBACK ) != sidebit )
{
continue; /* wrong side */
}
2010-10-22 08:04:31 +00:00
if ( surf->texinfo->flags & SURF_SKY )
{
/* just adds to visible sky bounds */
R_AddSkySurface( surf );
}
2010-10-22 08:04:31 +00:00
else if ( surf->texinfo->flags & ( SURF_TRANS33 | SURF_TRANS66 ) )
{
/* add to the translucent chain */
surf->texturechain = r_alpha_surfaces;
r_alpha_surfaces = surf;
}
else
{
2010-10-22 08:04:31 +00:00
/* the polygon is visible, so add it to the texture */
image = R_TextureAnimation( surf->texinfo );
surf->texturechain = image->texturechain;
image->texturechain = surf;
}
}
2010-10-22 08:04:31 +00:00
/* recurse down the back side */
R_RecursiveWorldNode( node->children [ !side ] );
}
2010-10-22 08:04:31 +00:00
void
R_DrawWorld ( void )
{
2010-10-22 08:04:31 +00:00
entity_t ent;
2010-10-22 08:04:31 +00:00
if ( !r_drawworld->value )
{
return;
2010-10-22 08:04:31 +00:00
}
if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
2010-10-22 08:04:31 +00:00
{
return;
2010-10-22 08:04:31 +00:00
}
currentmodel = r_worldmodel;
2010-10-22 08:04:31 +00:00
VectorCopy( r_newrefdef.vieworg, modelorg );
2010-10-22 08:04:31 +00:00
/* auto cycle the world frame for texture animation */
memset( &ent, 0, sizeof ( ent ) );
ent.frame = (int) ( r_newrefdef.time * 2 );
currententity = &ent;
2010-10-22 08:04:31 +00:00
gl_state.currenttextures [ 0 ] = gl_state.currenttextures [ 1 ] = -1;
2010-10-22 08:04:31 +00:00
qglColor3f( 1, 1, 1 );
memset( gl_lms.lightmap_surfaces, 0, sizeof ( gl_lms.lightmap_surfaces ) );
R_ClearSkyBox();
R_RecursiveWorldNode( r_worldmodel->nodes );
2010-10-22 08:04:31 +00:00
DrawTextureChains();
R_BlendLightmaps();
2010-10-22 08:04:31 +00:00
R_DrawSkyBox();
2010-10-22 08:04:31 +00:00
R_DrawTriangleOutlines();
}
/*
2010-10-22 08:04:31 +00:00
* Mark the leaves and nodes that are in the PVS for the current
* cluster
*/
void
R_MarkLeaves ( void )
{
2010-10-22 08:04:31 +00:00
byte *vis;
byte fatvis [ MAX_MAP_LEAFS / 8 ];
mnode_t *node;
int i, c;
mleaf_t *leaf;
int cluster;
if ( ( r_oldviewcluster == r_viewcluster ) && ( r_oldviewcluster2 == r_viewcluster2 ) && !r_novis->value &&
( r_viewcluster != -1 ) )
{
return;
2010-10-22 08:04:31 +00:00
}
2010-10-22 08:04:31 +00:00
/* development aid to let you run around and see exactly where
the pvs ends */
if ( gl_lockpvs->value )
{
return;
2010-10-22 08:04:31 +00:00
}
r_visframecount++;
r_oldviewcluster = r_viewcluster;
r_oldviewcluster2 = r_viewcluster2;
2010-10-22 08:04:31 +00:00
if ( r_novis->value || ( r_viewcluster == -1 ) || !r_worldmodel->vis )
{
2010-10-22 08:04:31 +00:00
/* mark everything */
for ( i = 0; i < r_worldmodel->numleafs; i++ )
{
r_worldmodel->leafs [ i ].visframe = r_visframecount;
}
for ( i = 0; i < r_worldmodel->numnodes; i++ )
{
r_worldmodel->nodes [ i ].visframe = r_visframecount;
}
return;
}
2010-10-22 08:04:31 +00:00
vis = Mod_ClusterPVS( r_viewcluster, r_worldmodel );
/* may have to combine two clusters because of solid water boundaries */
if ( r_viewcluster2 != r_viewcluster )
{
2010-10-22 08:04:31 +00:00
memcpy( fatvis, vis, ( r_worldmodel->numleafs + 7 ) / 8 );
vis = Mod_ClusterPVS( r_viewcluster2, r_worldmodel );
c = ( r_worldmodel->numleafs + 31 ) / 32;
for ( i = 0; i < c; i++ )
{
( (int *) fatvis ) [ i ] |= ( (int *) vis ) [ i ];
}
vis = fatvis;
}
2010-10-22 08:04:31 +00:00
for ( i = 0, leaf = r_worldmodel->leafs; i < r_worldmodel->numleafs; i++, leaf++ )
{
cluster = leaf->cluster;
2010-10-22 08:04:31 +00:00
if ( cluster == -1 )
{
continue;
2010-10-22 08:04:31 +00:00
}
if ( vis [ cluster >> 3 ] & ( 1 << ( cluster & 7 ) ) )
{
2010-10-22 08:04:31 +00:00
node = (mnode_t *) leaf;
do
{
2010-10-22 08:04:31 +00:00
if ( node->visframe == r_visframecount )
{
break;
2010-10-22 08:04:31 +00:00
}
node->visframe = r_visframecount;
node = node->parent;
2010-10-22 08:04:31 +00:00
}
while ( node );
}
}
}
2010-10-22 08:04:31 +00:00
static void
LM_InitBlock ( void )
{
2010-10-22 08:04:31 +00:00
memset( gl_lms.allocated, 0, sizeof ( gl_lms.allocated ) );
}
2010-10-22 08:04:31 +00:00
static void
LM_UploadBlock ( qboolean dynamic )
{
int texture;
int height = 0;
if ( dynamic )
{
texture = 0;
}
else
{
texture = gl_lms.current_lightmap_texture;
}
R_Bind( gl_state.lightmap_textures + texture );
2010-10-22 08:04:31 +00:00
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
if ( dynamic )
{
int i;
for ( i = 0; i < BLOCK_WIDTH; i++ )
{
2010-10-22 08:04:31 +00:00
if ( gl_lms.allocated [ i ] > height )
{
height = gl_lms.allocated [ i ];
}
}
2010-10-22 08:04:31 +00:00
qglTexSubImage2D( GL_TEXTURE_2D,
0,
0, 0,
BLOCK_WIDTH, height,
GL_LIGHTMAP_FORMAT,
GL_UNSIGNED_BYTE,
gl_lms.lightmap_buffer );
}
else
{
2010-10-22 08:04:31 +00:00
qglTexImage2D( GL_TEXTURE_2D,
0,
gl_lms.internal_format,
BLOCK_WIDTH, BLOCK_HEIGHT,
0,
GL_LIGHTMAP_FORMAT,
GL_UNSIGNED_BYTE,
gl_lms.lightmap_buffer );
if ( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS )
2010-10-22 08:04:31 +00:00
{
ri.Sys_Error( ERR_DROP, "LM_UploadBlock() - MAX_LIGHTMAPS exceeded\n" );
2010-10-22 08:04:31 +00:00
}
}
}
2010-10-22 08:04:31 +00:00
/* returns a texture number and the position inside it */
static qboolean
LM_AllocBlock ( int w, int h, int *x, int *y )
{
2010-10-22 08:04:31 +00:00
int i, j;
int best, best2;
best = BLOCK_HEIGHT;
2010-10-22 08:04:31 +00:00
for ( i = 0; i < BLOCK_WIDTH - w; i++ )
{
best2 = 0;
2010-10-22 08:04:31 +00:00
for ( j = 0; j < w; j++ )
{
2010-10-22 08:04:31 +00:00
if ( gl_lms.allocated [ i + j ] >= best )
{
break;
2010-10-22 08:04:31 +00:00
}
if ( gl_lms.allocated [ i + j ] > best2 )
{
best2 = gl_lms.allocated [ i + j ];
}
}
2010-10-22 08:04:31 +00:00
if ( j == w )
{
/* this is a valid spot */
*x = i;
*y = best = best2;
}
}
2010-10-22 08:04:31 +00:00
if ( best + h > BLOCK_HEIGHT )
{
return ( false );
}
2010-10-22 08:04:31 +00:00
for ( i = 0; i < w; i++ )
{
gl_lms.allocated [ *x + i ] = best + h;
}
2010-10-22 08:04:31 +00:00
return ( true );
}
2010-10-22 08:04:31 +00:00
void
GL_BuildPolygonFromSurface ( msurface_t *fa )
{
2010-10-22 08:04:31 +00:00
int i, lindex, lnumverts;
medge_t *pedges, *r_pedge;
int vertpage;
float *vec;
float s, t;
glpoly_t *poly;
vec3_t total;
/* reconstruct the polygon */
pedges = currentmodel->edges;
lnumverts = fa->numedges;
vertpage = 0;
2010-10-22 08:04:31 +00:00
VectorClear( total );
/* draw texture */
poly = Hunk_Alloc( sizeof ( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof ( float ) );
poly->next = fa->polys;
poly->flags = fa->flags;
fa->polys = poly;
poly->numverts = lnumverts;
2010-10-22 08:04:31 +00:00
for ( i = 0; i < lnumverts; i++ )
{
2010-10-22 08:04:31 +00:00
lindex = currentmodel->surfedges [ fa->firstedge + i ];
2010-10-22 08:04:31 +00:00
if ( lindex > 0 )
{
2010-10-22 08:04:31 +00:00
r_pedge = &pedges [ lindex ];
vec = currentmodel->vertexes [ r_pedge->v [ 0 ] ].position;
}
else
{
2010-10-22 08:04:31 +00:00
r_pedge = &pedges [ -lindex ];
vec = currentmodel->vertexes [ r_pedge->v [ 1 ] ].position;
}
2010-10-22 08:04:31 +00:00
s = DotProduct( vec, fa->texinfo->vecs [ 0 ] ) + fa->texinfo->vecs [ 0 ] [ 3 ];
s /= fa->texinfo->image->width;
2010-10-22 08:04:31 +00:00
t = DotProduct( vec, fa->texinfo->vecs [ 1 ] ) + fa->texinfo->vecs [ 1 ] [ 3 ];
t /= fa->texinfo->image->height;
2010-10-22 08:04:31 +00:00
VectorAdd( total, vec, total );
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;
2010-10-22 08:04:31 +00:00
s /= BLOCK_WIDTH * 16; /* fa->texinfo->texture->width; */
2010-10-22 08:04:31 +00:00
t = DotProduct( vec, fa->texinfo->vecs [ 1 ] ) + fa->texinfo->vecs [ 1 ] [ 3 ];
t -= fa->texturemins [ 1 ];
t += fa->light_t * 16;
t += 8;
2010-10-22 08:04:31 +00:00
t /= BLOCK_HEIGHT * 16; /* fa->texinfo->texture->height; */
2010-10-22 08:04:31 +00:00
poly->verts [ i ] [ 5 ] = s;
poly->verts [ i ] [ 6 ] = t;
}
poly->numverts = lnumverts;
}
2010-10-22 08:04:31 +00:00
void
GL_CreateSurfaceLightmap ( msurface_t *surf )
{
2010-10-22 08:04:31 +00:00
int smax, tmax;
byte *base;
2010-10-22 08:04:31 +00:00
if ( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB ) )
{
return;
2010-10-22 08:04:31 +00:00
}
2010-10-22 08:04:31 +00:00
smax = ( surf->extents [ 0 ] >> 4 ) + 1;
tmax = ( surf->extents [ 1 ] >> 4 ) + 1;
if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) )
{
LM_UploadBlock( false );
LM_InitBlock();
2010-10-22 08:04:31 +00:00
if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) )
{
ri.Sys_Error( ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed\n", smax, tmax );
}
}
surf->lightmaptexturenum = gl_lms.current_lightmap_texture;
base = gl_lms.lightmap_buffer;
2010-10-22 08:04:31 +00:00
base += ( surf->light_t * BLOCK_WIDTH + surf->light_s ) * LIGHTMAP_BYTES;
R_SetCacheState( surf );
2010-10-22 08:04:31 +00:00
R_BuildLightMap( surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES );
}
2010-10-22 08:04:31 +00:00
void
GL_BeginBuildingLightmaps ( model_t *m )
{
2010-10-22 08:04:31 +00:00
static lightstyle_t lightstyles [ MAX_LIGHTSTYLES ];
int i;
unsigned dummy [ 128 * 128 ];
2010-10-22 08:04:31 +00:00
memset( gl_lms.allocated, 0, sizeof ( gl_lms.allocated ) );
2010-10-22 08:04:31 +00:00
r_framecount = 1;/* no dlightcache */
2010-10-22 08:04:31 +00:00
/* setup the base lightstyles so the lightmaps won't have to be regenerated
the first time they're seen */
for ( i = 0; i < MAX_LIGHTSTYLES; i++ )
{
2010-10-22 08:04:31 +00:00
lightstyles [ i ].rgb [ 0 ] = 1;
lightstyles [ i ].rgb [ 1 ] = 1;
lightstyles [ i ].rgb [ 2 ] = 1;
lightstyles [ i ].white = 3;
}
2010-10-22 08:04:31 +00:00
r_newrefdef.lightstyles = lightstyles;
2010-10-22 08:04:31 +00:00
if ( !gl_state.lightmap_textures )
{
2010-10-22 08:04:31 +00:00
gl_state.lightmap_textures = TEXNUM_LIGHTMAPS;
}
gl_lms.current_lightmap_texture = 1;
gl_lms.internal_format = gl_tex_solid_format;
2010-10-22 08:04:31 +00:00
/* initialize the dynamic lightmap texture */
R_Bind( gl_state.lightmap_textures + 0 );
2010-10-22 08:04:31 +00:00
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
qglTexImage2D( GL_TEXTURE_2D,
0,
gl_lms.internal_format,
BLOCK_WIDTH, BLOCK_HEIGHT,
0,
GL_LIGHTMAP_FORMAT,
GL_UNSIGNED_BYTE,
dummy );
}
2010-10-22 08:04:31 +00:00
void
GL_EndBuildingLightmaps ( void )
{
LM_UploadBlock( false );
}