yquake2remaster/src/refresh/r_surf.c

951 lines
18 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.
2010-10-22 08:04:31 +00:00
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
2010-10-22 08:04:31 +00:00
* 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.
2010-10-22 08:04:31 +00:00
*
* =======================================================================
*
* Surface generation and drawing
*
* =======================================================================
*/
2009-03-05 13:08:47 +00:00
#include <assert.h>
2009-03-05 11:03:08 +00:00
#include "header/local.h"
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;
gllightmapstate_t gl_lms;
void LM_InitBlock ( void );
void LM_UploadBlock ( qboolean dynamic );
qboolean LM_AllocBlock ( int w, int h, int *x, int *y );
void R_SetCacheState ( msurface_t *surf );
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
R_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
R_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
R_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: R_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 */
2010-10-24 08:50:01 +00:00
if ( gl_fullbright->value )
2010-10-22 08:04:31 +00:00
{
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
{
R_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
{
R_DrawGLPolyChain( drawsurf->polys,
2010-10-22 08:04:31 +00:00
( 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
{
R_DrawGLPolyChain( surf->polys, ( surf->light_s - surf->dlight_s ) * ( 1.0 / 128.0 ),
2010-10-22 08:04:31 +00:00
( 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 );
R_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 )
{
R_DrawGLFlowingPoly( fa );
2010-10-22 08:04:31 +00:00
}
else
2010-10-22 08:04:31 +00:00
{
R_DrawGLPoly( fa->polys );
2010-10-22 08:04:31 +00:00
}
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 )
{
R_EmitWaterPolys( s );
2010-10-22 08:04:31 +00:00
}
else if ( s->texinfo->flags & SURF_FLOWING )
{
R_DrawGLFlowingPoly( s );
2010-10-22 08:04:31 +00:00
}
else
2010-10-22 08:04:31 +00:00
{
R_DrawGLPoly( s->polys );
2010-10-22 08:04:31 +00:00
}
}
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
R_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-24 08:50:01 +00:00
if ( !gl_drawworld->value )
2010-10-22 08:04:31 +00:00
{
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 );
R_DrawTextureChains();
2010-10-22 08:04:31 +00:00
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;
2010-10-24 08:50:01 +00:00
if ( ( r_oldviewcluster == r_viewcluster ) && ( r_oldviewcluster2 == r_viewcluster2 ) && !gl_novis->value &&
2010-10-22 08:04:31 +00:00
( 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-24 08:50:01 +00:00
if ( gl_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 );
}
}
}