📄 gl_rsurf.c
字号:
/*
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.
*/
// GL_RSURF.C: surface-related refresh code
#include <assert.h>
#include "gl_local.h"
static vec3_t modelorg; // relative to viewpoint
msurface_t *r_alpha_surfaces;
#define DYNAMIC_LIGHT_WIDTH 128
#define DYNAMIC_LIGHT_HEIGHT 128
#define LIGHTMAP_BYTES 4
#define BLOCK_WIDTH 128
#define BLOCK_HEIGHT 128
#define MAX_LIGHTMAPS 128
int c_visible_lightmaps;
int c_visible_textures;
#define GL_LIGHTMAP_FORMAT GL_RGBA
typedef struct
{
int internal_format;
int current_lightmap_texture;
msurface_t *lightmap_surfaces[MAX_LIGHTMAPS];
int allocated[BLOCK_WIDTH];
// 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;
static void LM_InitBlock( void );
static void LM_UploadBlock( qboolean dynamic );
static qboolean LM_AllocBlock (int w, int h, int *x, int *y);
extern void R_SetCacheState( msurface_t *surf );
extern void R_BuildLightMap (msurface_t *surf, byte *dest, int stride);
/*
=============================================================
BRUSH MODELS
=============================================================
*/
/*
===============
R_TextureAnimation
Returns the proper texture for a given time and base texture
===============
*/
image_t *R_TextureAnimation (mtexinfo_t *tex)
{
int c;
if (!tex->next)
return tex->image;
c = currententity->frame % tex->numframes;
while (c)
{
tex = tex->next;
c--;
}
return tex->image;
}
#if 0
/*
=================
WaterWarpPolyVerts
Mangles the x and y coordinates in a copy of the poly
so that any drawing routine can be water warped
=================
*/
glpoly_t *WaterWarpPolyVerts (glpoly_t *p)
{
int i;
float *v, *nv;
static byte buffer[1024];
glpoly_t *out;
out = (glpoly_t *)buffer;
out->numverts = p->numverts;
v = p->verts[0];
nv = out->verts[0];
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE, nv+=VERTEXSIZE)
{
nv[0] = v[0] + 4*sin(v[1]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time);
nv[1] = v[1] + 4*sin(v[0]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time);
nv[2] = v[2];
nv[3] = v[3];
nv[4] = v[4];
nv[5] = v[5];
nv[6] = v[6];
}
return out;
}
/*
================
DrawGLWaterPoly
Warp the vertex coordinates
================
*/
void DrawGLWaterPoly (glpoly_t *p)
{
int i;
float *v;
p = WaterWarpPolyVerts (p);
qglBegin (GL_TRIANGLE_FAN);
v = p->verts[0];
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
{
qglTexCoord2f (v[3], v[4]);
qglVertex3fv (v);
}
qglEnd ();
}
void DrawGLWaterPolyLightmap (glpoly_t *p)
{
int i;
float *v;
p = WaterWarpPolyVerts (p);
qglBegin (GL_TRIANGLE_FAN);
v = p->verts[0];
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
{
qglTexCoord2f (v[5], v[6]);
qglVertex3fv (v);
}
qglEnd ();
}
#endif
/*
================
DrawGLPoly
================
*/
void DrawGLPoly (glpoly_t *p)
{
int i;
float *v;
qglBegin (GL_POLYGON);
v = p->verts[0];
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
{
qglTexCoord2f (v[3], v[4]);
qglVertex3fv (v);
}
qglEnd ();
}
//============
//PGM
/*
================
DrawGLFlowingPoly -- version of DrawGLPoly that handles scrolling texture
================
*/
void DrawGLFlowingPoly (msurface_t *fa)
{
int i;
float *v;
glpoly_t *p;
float scroll;
p = fa->polys;
scroll = -64 * ( (r_newrefdef.time / 40.0) - (int)(r_newrefdef.time / 40.0) );
if(scroll == 0.0)
scroll = -64.0;
qglBegin (GL_POLYGON);
v = p->verts[0];
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
{
qglTexCoord2f ((v[3] + scroll), v[4]);
qglVertex3fv (v);
}
qglEnd ();
}
//PGM
//============
/*
** R_DrawTriangleOutlines
*/
void R_DrawTriangleOutlines (void)
{
int i, j;
glpoly_t *p;
if (!gl_showtris->value)
return;
qglDisable (GL_TEXTURE_2D);
qglDisable (GL_DEPTH_TEST);
qglColor4f (1,1,1,1);
for (i=0 ; i<MAX_LIGHTMAPS ; i++)
{
msurface_t *surf;
for ( surf = gl_lms.lightmap_surfaces[i]; surf != 0; surf = surf->lightmapchain )
{
p = surf->polys;
for ( ; p ; p=p->chain)
{
for (j=2 ; j<p->numverts ; j++ )
{
qglBegin (GL_LINE_STRIP);
qglVertex3fv (p->verts[0]);
qglVertex3fv (p->verts[j-1]);
qglVertex3fv (p->verts[j]);
qglVertex3fv (p->verts[0]);
qglEnd ();
}
}
}
}
qglEnable (GL_DEPTH_TEST);
qglEnable (GL_TEXTURE_2D);
}
/*
** DrawGLPolyChain
*/
void DrawGLPolyChain( glpoly_t *p, float soffset, float toffset )
{
if ( soffset == 0 && toffset == 0 )
{
for ( ; p != 0; p = p->chain )
{
float *v;
int j;
qglBegin (GL_POLYGON);
v = p->verts[0];
for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
{
qglTexCoord2f (v[5], v[6] );
qglVertex3fv (v);
}
qglEnd ();
}
}
else
{
for ( ; p != 0; p = p->chain )
{
float *v;
int j;
qglBegin (GL_POLYGON);
v = p->verts[0];
for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
{
qglTexCoord2f (v[5] - soffset, v[6] - toffset );
qglVertex3fv (v);
}
qglEnd ();
}
}
}
/*
** R_BlendLightMaps
**
** This routine takes all the given light mapped surfaces in the world and
** blends them into the framebuffer.
*/
void R_BlendLightmaps (void)
{
int i;
msurface_t *surf, *newdrawsurf = 0;
// don't bother if we're set to fullbright
if (r_fullbright->value)
return;
if (!r_worldmodel->lightdata)
return;
// don't bother writing Z
qglDepthMask( 0 );
/*
** set the appropriate blending mode unless we're only looking at the
** lightmaps.
*/
if (!gl_lightmap->value)
{
qglEnable (GL_BLEND);
if ( gl_saturatelighting->value )
{
qglBlendFunc( GL_ONE, GL_ONE );
}
else
{
if ( gl_monolightmap->string[0] != '0' )
{
switch ( toupper( gl_monolightmap->string[0] ) )
{
case 'I':
qglBlendFunc (GL_ZERO, GL_SRC_COLOR );
break;
case 'L':
qglBlendFunc (GL_ZERO, GL_SRC_COLOR );
break;
case 'A':
default:
qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
break;
}
}
else
{
qglBlendFunc (GL_ZERO, GL_SRC_COLOR );
}
}
}
if ( currentmodel == r_worldmodel )
c_visible_lightmaps = 0;
/*
** render static lightmaps first
*/
for ( i = 1; i < MAX_LIGHTMAPS; i++ )
{
if ( gl_lms.lightmap_surfaces[i] )
{
if (currentmodel == r_worldmodel)
c_visible_lightmaps++;
GL_Bind( gl_state.lightmap_textures + i);
for ( surf = gl_lms.lightmap_surfaces[i]; surf != 0; surf = surf->lightmapchain )
{
if ( surf->polys )
DrawGLPolyChain( surf->polys, 0, 0 );
}
}
}
/*
** render dynamic lightmaps
*/
if ( gl_dynamic->value )
{
LM_InitBlock();
GL_Bind( gl_state.lightmap_textures+0 );
if (currentmodel == r_worldmodel)
c_visible_lightmaps++;
newdrawsurf = gl_lms.lightmap_surfaces[0];
for ( surf = gl_lms.lightmap_surfaces[0]; surf != 0; surf = surf->lightmapchain )
{
int smax, tmax;
byte *base;
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;
R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES);
}
else
{
msurface_t *drawsurf;
// upload what we have so far
LM_UploadBlock( true );
// draw all surfaces that use this lightmap
for ( drawsurf = newdrawsurf; drawsurf != surf; drawsurf = drawsurf->lightmapchain )
{
if ( drawsurf->polys )
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;
// clear the block
LM_InitBlock();
// 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;
R_BuildLightMap (surf, base, BLOCK_WIDTH*LIGHTMAP_BYTES);
}
}
/*
** draw remainder of dynamic lightmaps that haven't been uploaded yet
*/
if ( newdrawsurf )
LM_UploadBlock( true );
for ( surf = newdrawsurf; surf != 0; surf = surf->lightmapchain )
{
if ( surf->polys )
DrawGLPolyChain( surf->polys, ( surf->light_s - surf->dlight_s ) * ( 1.0 / 128.0 ), ( surf->light_t - surf->dlight_t ) * ( 1.0 / 128.0 ) );
}
}
/*
** restore state
*/
qglDisable (GL_BLEND);
qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglDepthMask( 1 );
}
/*
================
R_RenderBrushPoly
================
*/
void R_RenderBrushPoly (msurface_t *fa)
{
int maps;
image_t *image;
qboolean is_dynamic = false;
c_brush_polys++;
image = R_TextureAnimation (fa->texinfo);
if (fa->flags & SURF_DRAWTURB)
{
GL_Bind( image->texnum );
// warp texture, no lightmaps
GL_TexEnv( GL_MODULATE );
qglColor4f( gl_state.inverse_intensity,
gl_state.inverse_intensity,
gl_state.inverse_intensity,
1.0F );
EmitWaterPolys (fa);
GL_TexEnv( GL_REPLACE );
return;
}
else
{
GL_Bind( image->texnum );
GL_TexEnv( GL_REPLACE );
}
//======
//PGM
if(fa->texinfo->flags & SURF_FLOWING)
DrawGLFlowingPoly (fa);
else
DrawGLPoly (fa->polys);
//PGM
//======
/*
** check for lightmap modification
*/
for ( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ )
{
if ( r_newrefdef.lightstyles[fa->styles[maps]].white != fa->cached_light[maps] )
goto dynamic;
}
// dynamic this frame or dynamic previously
if ( ( fa->dlightframe == r_framecount ) )
{
dynamic:
if ( gl_dynamic->value )
{
if (!( fa->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP ) ) )
{
is_dynamic = true;
}
}
}
if ( is_dynamic )
{
if ( ( fa->styles[maps] >= 32 || fa->styles[maps] == 0 ) && ( fa->dlightframe != r_framecount ) )
{
unsigned temp[34*34];
int smax, tmax;
smax = (fa->extents[0]>>4)+1;
tmax = (fa->extents[1]>>4)+1;
R_BuildLightMap( fa, (void *)temp, smax*4 );
R_SetCacheState( fa );
GL_Bind( gl_state.lightmap_textures + fa->lightmaptexturenum );
qglTexSubImage2D( GL_TEXTURE_2D, 0,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -