mirror of
https://git.code.sf.net/p/quake/quakeforge-old
synced 2024-11-25 21:31:18 +00:00
54501eaed7
Relevant cvar to change the name of the skybox is r_skyname which defaults to "sky". If you don't have the files you'll get an ugly red background in place of the sky. I'll fix that shortly. Sorry software people, this is just the Q2 code I'm turning on which doesn not work for software. The code is pretty simple though and most of it's written already in gl_warp.c---just move that to r_sky and use the pcx's instead of the tga's..
1670 lines
34 KiB
C
1670 lines
34 KiB
C
/*
|
|
gl_rsurf.c - surrface-related refresh code
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
Copyright (C) 1999,2000 contributors of the QuakeForge project
|
|
Please see the file "AUTHORS" for a list of contributors
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
#include <qtypes.h>
|
|
#include <quakedef.h>
|
|
#include <glquake.h>
|
|
#include <mathlib.h>
|
|
#include <sys.h>
|
|
|
|
int skytexturenum;
|
|
|
|
#ifndef GL_RGBA4
|
|
#define GL_RGBA4 0
|
|
#endif
|
|
|
|
|
|
int lightmap_bytes; // 1, 2, or 4
|
|
|
|
int lightmap_textures;
|
|
|
|
unsigned blocklights[18*18];
|
|
|
|
#define BLOCK_WIDTH 128
|
|
#define BLOCK_HEIGHT 128
|
|
|
|
#define MAX_LIGHTMAPS 64
|
|
int active_lightmaps;
|
|
|
|
typedef struct glRect_s {
|
|
unsigned char l,t,w,h;
|
|
} glRect_t;
|
|
|
|
glpoly_t *lightmap_polys[MAX_LIGHTMAPS];
|
|
qboolean lightmap_modified[MAX_LIGHTMAPS];
|
|
glRect_t lightmap_rectchange[MAX_LIGHTMAPS];
|
|
|
|
int allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
|
|
|
|
// the lightmap texture data needs to be kept in
|
|
// main memory so texsubimage can update properly
|
|
byte lightmaps[4*MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT];
|
|
|
|
// For gl_texsort 0
|
|
msurface_t *skychain = NULL;
|
|
msurface_t *waterchain = NULL;
|
|
|
|
void R_RenderDynamicLightmaps (msurface_t *fa);
|
|
|
|
/*
|
|
===============
|
|
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;
|
|
|
|
smax = (surf->extents[0]>>4)+1;
|
|
tmax = (surf->extents[1]>>4)+1;
|
|
tex = surf->texinfo;
|
|
|
|
for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
|
|
{
|
|
if ( !(surf->dlightbits & (1<<lnum) ) )
|
|
continue; // not lit by this light
|
|
|
|
rad = cl_dlights[lnum].radius;
|
|
dist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) -
|
|
surf->plane->dist;
|
|
rad -= fabs(dist);
|
|
minlight = cl_dlights[lnum].minlight;
|
|
if (rad < minlight)
|
|
continue;
|
|
minlight = rad - minlight;
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
impact[i] = cl_dlights[lnum].origin[i] -
|
|
surf->plane->normal[i]*dist;
|
|
}
|
|
|
|
local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
|
|
local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
|
|
|
|
local[0] -= surf->texturemins[0];
|
|
local[1] -= surf->texturemins[1];
|
|
|
|
for (t = 0 ; t<tmax ; t++)
|
|
{
|
|
td = local[1] - t*16;
|
|
if (td < 0)
|
|
td = -td;
|
|
for (s=0 ; s<smax ; s++)
|
|
{
|
|
sd = local[0] - s*16;
|
|
if (sd < 0)
|
|
sd = -sd;
|
|
if (sd > td)
|
|
dist = sd + (td>>1);
|
|
else
|
|
dist = td + (sd>>1);
|
|
if (dist < minlight)
|
|
blocklights[t*smax + s] += (rad - dist)*256;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
R_BuildLightMap
|
|
|
|
Combine and scale multiple lightmaps into the 8.8 format in blocklights
|
|
===============
|
|
*/
|
|
void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
|
|
{
|
|
int smax, tmax;
|
|
int t;
|
|
int i, j, size;
|
|
byte *lightmap;
|
|
unsigned scale;
|
|
int maps;
|
|
unsigned *bl;
|
|
|
|
surf->cached_dlight = (surf->dlightframe == r_framecount);
|
|
|
|
smax = (surf->extents[0]>>4)+1;
|
|
tmax = (surf->extents[1]>>4)+1;
|
|
size = smax*tmax;
|
|
lightmap = surf->samples;
|
|
|
|
// set to full bright if no light data
|
|
if (/* r_fullbright->value || */ !cl.worldmodel->lightdata)
|
|
{
|
|
for (i=0 ; i<size ; i++)
|
|
blocklights[i] = 255*256;
|
|
goto store;
|
|
}
|
|
|
|
// clear to no light
|
|
for (i=0 ; i<size ; i++)
|
|
blocklights[i] = 0;
|
|
|
|
// add all the lightmaps
|
|
if (lightmap)
|
|
for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
|
|
maps++)
|
|
{
|
|
scale = d_lightstylevalue[surf->styles[maps]];
|
|
surf->cached_light[maps] = scale; // 8.8 fraction
|
|
for (i=0 ; i<size ; i++)
|
|
blocklights[i] += lightmap[i] * scale;
|
|
lightmap += size; // skip to next lightmap
|
|
}
|
|
|
|
// add all the dynamic lights
|
|
if (surf->dlightframe == r_framecount)
|
|
R_AddDynamicLights (surf);
|
|
|
|
// bound, invert, and shift
|
|
store:
|
|
switch (gl_lightmap_format)
|
|
{
|
|
case GL_RGBA:
|
|
stride -= (smax<<2);
|
|
bl = blocklights;
|
|
for (i=0 ; i<tmax ; i++, dest += stride)
|
|
{
|
|
for (j=0 ; j<smax ; j++)
|
|
{
|
|
t = *bl++;
|
|
t >>= 7;
|
|
if (t > 255)
|
|
t = 255;
|
|
dest[3] = 255-t;
|
|
dest += 4;
|
|
}
|
|
}
|
|
break;
|
|
case GL_ALPHA:
|
|
case GL_LUMINANCE:
|
|
case GL_INTENSITY:
|
|
bl = blocklights;
|
|
for (i=0 ; i<tmax ; i++, dest += stride)
|
|
{
|
|
for (j=0 ; j<smax ; j++)
|
|
{
|
|
t = *bl++;
|
|
t >>= 7;
|
|
if (t > 255)
|
|
t = 255;
|
|
dest[j] = 255-t;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Sys_Error ("Bad lightmap format");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
R_TextureAnimation
|
|
|
|
Returns the proper texture for a given time and base texture
|
|
===============
|
|
*/
|
|
texture_t *R_TextureAnimation (texture_t *base)
|
|
{
|
|
int reletive;
|
|
int count;
|
|
|
|
if (currententity->frame)
|
|
{
|
|
if (base->alternate_anims)
|
|
base = base->alternate_anims;
|
|
}
|
|
|
|
if (!base->anim_total)
|
|
return base;
|
|
|
|
reletive = (int)(cl.time*10) % base->anim_total;
|
|
|
|
count = 0;
|
|
while (base->anim_min > reletive || base->anim_max <= reletive)
|
|
{
|
|
base = base->anim_next;
|
|
if (!base)
|
|
Sys_Error ("R_TextureAnimation: broken cycle");
|
|
if (++count > 100)
|
|
Sys_Error ("R_TextureAnimation: infinite cycle");
|
|
}
|
|
|
|
return base;
|
|
}
|
|
|
|
|
|
/*
|
|
=============================================================
|
|
|
|
BRUSH MODELS
|
|
|
|
=============================================================
|
|
*/
|
|
|
|
|
|
extern int solidskytexture;
|
|
extern int alphaskytexture;
|
|
extern float speedscale; // for top sky and bottom sky
|
|
|
|
void DrawGLWaterPoly (glpoly_t *p);
|
|
void DrawGLWaterPolyLightmap (glpoly_t *p);
|
|
|
|
lpMTexFUNC qglMTexCoord2fSGIS = NULL;
|
|
lpSelTexFUNC qglSelectTextureSGIS = NULL;
|
|
|
|
qboolean mtexenabled = false;
|
|
|
|
void GL_SelectTexture (GLenum target);
|
|
|
|
void GL_DisableMultitexture(void)
|
|
{
|
|
if (mtexenabled) {
|
|
glDisable(GL_TEXTURE_2D);
|
|
GL_SelectTexture(TEXTURE0_SGIS);
|
|
mtexenabled = false;
|
|
}
|
|
}
|
|
|
|
void GL_EnableMultitexture(void)
|
|
{
|
|
if (gl_mtexable) {
|
|
GL_SelectTexture(TEXTURE1_SGIS);
|
|
glEnable(GL_TEXTURE_2D);
|
|
mtexenabled = true;
|
|
}
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
/*
|
|
================
|
|
R_DrawSequentialPoly
|
|
|
|
Systems that have fast state and texture changes can
|
|
just do everything as it passes with no need to sort
|
|
================
|
|
*/
|
|
void R_DrawSequentialPoly (msurface_t *s)
|
|
{
|
|
glpoly_t *p;
|
|
float *v;
|
|
int i;
|
|
texture_t *t;
|
|
|
|
//
|
|
// normal lightmaped poly
|
|
//
|
|
// if ((!(s->flags & (SURF_DRAWSKY|SURF_DRAWTURB)))
|
|
// && ((r_viewleaf->contents!=CONTENTS_EMPTY && (s->flags & SURF_UNDERWATER)) ||
|
|
// (r_viewleaf->contents==CONTENTS_EMPTY && !(s->flags & SURF_UNDERWATER))))
|
|
if (0)
|
|
{
|
|
p = s->polys;
|
|
|
|
t = R_TextureAnimation (s->texinfo->texture);
|
|
GL_Bind (t->gl_texturenum);
|
|
glBegin (GL_POLYGON);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[3], v[4]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
|
|
GL_Bind (lightmap_textures + s->lightmaptexturenum);
|
|
glEnable (GL_BLEND);
|
|
glBegin (GL_POLYGON);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[5], v[6]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// subdivided water surface warp
|
|
//
|
|
if (s->flags & SURF_DRAWTURB)
|
|
{
|
|
GL_Bind (s->texinfo->texture->gl_texturenum);
|
|
EmitWaterPolys (s);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// subdivided sky warp
|
|
//
|
|
if (s->flags & SURF_DRAWSKY)
|
|
{
|
|
GL_Bind (solidskytexture);
|
|
speedscale = realtime*8;
|
|
speedscale -= (int)speedscale;
|
|
|
|
EmitSkyPolys (s);
|
|
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
GL_Bind (alphaskytexture);
|
|
speedscale = realtime*16;
|
|
speedscale -= (int)speedscale;
|
|
EmitSkyPolys (s);
|
|
if (gl_lightmap_format == GL_LUMINANCE)
|
|
glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
}
|
|
|
|
//
|
|
// underwater warped with lightmap
|
|
//
|
|
p = s->polys;
|
|
|
|
t = R_TextureAnimation (s->texinfo->texture);
|
|
GL_Bind (t->gl_texturenum);
|
|
DrawGLWaterPoly (p);
|
|
|
|
GL_Bind (lightmap_textures + s->lightmaptexturenum);
|
|
glEnable (GL_BLEND);
|
|
DrawGLWaterPolyLightmap (p);
|
|
glDisable (GL_BLEND);
|
|
}
|
|
#else
|
|
/*
|
|
================
|
|
R_DrawSequentialPoly
|
|
|
|
Systems that have fast state and texture changes can
|
|
just do everything as it passes with no need to sort
|
|
================
|
|
*/
|
|
void R_DrawSequentialPoly (msurface_t *s)
|
|
{
|
|
glpoly_t *p;
|
|
float *v;
|
|
int i;
|
|
texture_t *t;
|
|
vec3_t nv;
|
|
glRect_t *theRect;
|
|
|
|
//
|
|
// normal lightmaped poly
|
|
//
|
|
|
|
if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB|SURF_UNDERWATER) ) )
|
|
{
|
|
R_RenderDynamicLightmaps (s);
|
|
if (gl_mtexable) {
|
|
p = s->polys;
|
|
|
|
t = R_TextureAnimation (s->texinfo->texture);
|
|
// Binds world to texture env 0
|
|
GL_SelectTexture(TEXTURE0_SGIS);
|
|
GL_Bind (t->gl_texturenum);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
// Binds lightmap to texenv 1
|
|
GL_EnableMultitexture(); // Same as SelectTexture (TEXTURE1)
|
|
GL_Bind (lightmap_textures + s->lightmaptexturenum);
|
|
i = s->lightmaptexturenum;
|
|
if (lightmap_modified[i])
|
|
{
|
|
lightmap_modified[i] = false;
|
|
theRect = &lightmap_rectchange[i];
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = BLOCK_WIDTH;
|
|
theRect->t = BLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
|
|
glBegin(GL_POLYGON);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
|
|
qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
return;
|
|
} else {
|
|
p = s->polys;
|
|
|
|
t = R_TextureAnimation (s->texinfo->texture);
|
|
GL_Bind (t->gl_texturenum);
|
|
glBegin (GL_POLYGON);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[3], v[4]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
|
|
GL_Bind (lightmap_textures + s->lightmaptexturenum);
|
|
glEnable (GL_BLEND);
|
|
glBegin (GL_POLYGON);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[5], v[6]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
|
|
glDisable (GL_BLEND);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// subdivided water surface warp
|
|
//
|
|
|
|
if (s->flags & SURF_DRAWTURB)
|
|
{
|
|
GL_DisableMultitexture();
|
|
GL_Bind (s->texinfo->texture->gl_texturenum);
|
|
EmitWaterPolys (s);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// subdivided sky warp
|
|
//
|
|
if (s->flags & SURF_DRAWSKY)
|
|
{
|
|
GL_DisableMultitexture();
|
|
GL_Bind (solidskytexture);
|
|
speedscale = realtime*8;
|
|
speedscale -= (int)speedscale & ~127;
|
|
|
|
EmitSkyPolys (s);
|
|
|
|
glEnable (GL_BLEND);
|
|
GL_Bind (alphaskytexture);
|
|
speedscale = realtime*16;
|
|
speedscale -= (int)speedscale & ~127;
|
|
EmitSkyPolys (s);
|
|
|
|
glDisable (GL_BLEND);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// underwater warped with lightmap
|
|
//
|
|
R_RenderDynamicLightmaps (s);
|
|
if (gl_mtexable) {
|
|
p = s->polys;
|
|
|
|
t = R_TextureAnimation (s->texinfo->texture);
|
|
GL_SelectTexture(TEXTURE0_SGIS);
|
|
GL_Bind (t->gl_texturenum);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
GL_EnableMultitexture();
|
|
GL_Bind (lightmap_textures + s->lightmaptexturenum);
|
|
i = s->lightmaptexturenum;
|
|
if (lightmap_modified[i])
|
|
{
|
|
lightmap_modified[i] = false;
|
|
theRect = &lightmap_rectchange[i];
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = BLOCK_WIDTH;
|
|
theRect->t = BLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
|
|
glBegin (GL_TRIANGLE_FAN);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
|
|
qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
|
|
|
|
nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
|
|
nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
|
|
nv[2] = v[2];
|
|
|
|
glVertex3fv (nv);
|
|
}
|
|
glEnd ();
|
|
|
|
} else {
|
|
p = s->polys;
|
|
|
|
t = R_TextureAnimation (s->texinfo->texture);
|
|
GL_Bind (t->gl_texturenum);
|
|
DrawGLWaterPoly (p);
|
|
|
|
GL_Bind (lightmap_textures + s->lightmaptexturenum);
|
|
glEnable (GL_BLEND);
|
|
DrawGLWaterPolyLightmap (p);
|
|
glDisable (GL_BLEND);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
================
|
|
DrawGLWaterPoly
|
|
|
|
Warp the vertex coordinates
|
|
================
|
|
*/
|
|
void DrawGLWaterPoly (glpoly_t *p)
|
|
{
|
|
int i;
|
|
float *v;
|
|
vec3_t nv;
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
glBegin (GL_TRIANGLE_FAN);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[3], v[4]);
|
|
|
|
nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
|
|
nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
|
|
nv[2] = v[2];
|
|
|
|
glVertex3fv (nv);
|
|
}
|
|
glEnd ();
|
|
}
|
|
|
|
void DrawGLWaterPolyLightmap (glpoly_t *p)
|
|
{
|
|
int i;
|
|
float *v;
|
|
vec3_t nv;
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
glBegin (GL_TRIANGLE_FAN);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[5], v[6]);
|
|
|
|
nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
|
|
nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
|
|
nv[2] = v[2];
|
|
|
|
glVertex3fv (nv);
|
|
}
|
|
glEnd ();
|
|
}
|
|
|
|
/*
|
|
================
|
|
DrawGLPoly
|
|
================
|
|
*/
|
|
void DrawGLPoly (glpoly_t *p)
|
|
{
|
|
int i;
|
|
float *v;
|
|
|
|
glBegin (GL_POLYGON);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[3], v[4]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
R_BlendLightmaps
|
|
================
|
|
*/
|
|
void R_BlendLightmaps (void)
|
|
{
|
|
int i, j;
|
|
glpoly_t *p;
|
|
float *v;
|
|
glRect_t *theRect;
|
|
|
|
#if 0
|
|
if (r_fullbright->value)
|
|
return;
|
|
#endif
|
|
if (!gl_texsort->value)
|
|
return;
|
|
|
|
glDepthMask (0); // don't bother writing Z
|
|
|
|
if (gl_lightmap_format == GL_LUMINANCE)
|
|
glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
|
|
else if (gl_lightmap_format == GL_INTENSITY)
|
|
{
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glColor4f (0,0,0,1);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
|
|
if (!r_lightmap->value)
|
|
{
|
|
glEnable (GL_BLEND);
|
|
}
|
|
|
|
for (i=0 ; i<MAX_LIGHTMAPS ; i++)
|
|
{
|
|
p = lightmap_polys[i];
|
|
if (!p)
|
|
continue;
|
|
GL_Bind(lightmap_textures+i);
|
|
if (lightmap_modified[i])
|
|
{
|
|
lightmap_modified[i] = false;
|
|
theRect = &lightmap_rectchange[i];
|
|
// theRect->l = 0;
|
|
// theRect->t = 0;
|
|
// theRect->w = BLOCK_WIDTH;
|
|
// theRect->h = BLOCK_HEIGHT;
|
|
// glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes
|
|
// , BLOCK_WIDTH, BLOCK_HEIGHT, 0,
|
|
// gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
|
|
// glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes
|
|
// , BLOCK_WIDTH, theRect->h, 0,
|
|
// gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+(i*BLOCK_HEIGHT+theRect->t)*BLOCK_WIDTH*lightmap_bytes);
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = BLOCK_WIDTH;
|
|
theRect->t = BLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
for ( ; p ; p=p->chain)
|
|
{
|
|
|
|
if (r_waterwarp->value && (p->flags & SURF_UNDERWATER)) {
|
|
DrawGLWaterPolyLightmap (p);
|
|
// if (r_waterwarp->value && ((r_viewleaf->contents==CONTENTS_EMPTY && (p->flags & SURF_UNDERWATER)))
|
|
// && !(p->flags & SURF_DONTWARP)) {
|
|
DrawGLWaterPolyLightmap (p);
|
|
}
|
|
else
|
|
{
|
|
glBegin (GL_POLYGON);
|
|
v = p->verts[0];
|
|
for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[5], v[6]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
}
|
|
}
|
|
}
|
|
|
|
glDisable (GL_BLEND);
|
|
if (gl_lightmap_format == GL_LUMINANCE)
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
else if (gl_lightmap_format == GL_INTENSITY)
|
|
{
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glColor4f (1,1,1,1);
|
|
}
|
|
|
|
glDepthMask (1); // back to normal Z buffering
|
|
}
|
|
|
|
/*
|
|
================
|
|
R_RenderBrushPoly
|
|
================
|
|
*/
|
|
void R_RenderBrushPoly (msurface_t *fa)
|
|
{
|
|
texture_t *t;
|
|
byte *base;
|
|
int maps;
|
|
glRect_t *theRect;
|
|
int smax, tmax;
|
|
|
|
c_brush_polys++;
|
|
|
|
if (fa->flags & SURF_DRAWSKY)
|
|
{ // warp texture, no lightmaps
|
|
EmitBothSkyLayers (fa);
|
|
return;
|
|
}
|
|
|
|
t = R_TextureAnimation (fa->texinfo->texture);
|
|
GL_Bind (t->gl_texturenum);
|
|
|
|
if (fa->flags & SURF_DRAWTURB)
|
|
{ // warp texture, no lightmaps
|
|
EmitWaterPolys (fa);
|
|
return;
|
|
}
|
|
|
|
if (r_waterwarp->value&&(fa->flags & SURF_UNDERWATER))
|
|
DrawGLWaterPoly (fa->polys);
|
|
else
|
|
DrawGLPoly (fa->polys);
|
|
|
|
// add the poly to the proper lightmap chain
|
|
|
|
fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
|
|
lightmap_polys[fa->lightmaptexturenum] = fa->polys;
|
|
|
|
// check for lightmap modification
|
|
for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
|
|
maps++)
|
|
if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
|
|
goto dynamic;
|
|
|
|
if (fa->dlightframe == r_framecount // dynamic this frame
|
|
|| fa->cached_dlight) // dynamic previously
|
|
{
|
|
dynamic:
|
|
if (r_dynamic->value)
|
|
{
|
|
lightmap_modified[fa->lightmaptexturenum] = true;
|
|
theRect = &lightmap_rectchange[fa->lightmaptexturenum];
|
|
if (fa->light_t < theRect->t) {
|
|
if (theRect->h)
|
|
theRect->h += theRect->t - fa->light_t;
|
|
theRect->t = fa->light_t;
|
|
}
|
|
if (fa->light_s < theRect->l) {
|
|
if (theRect->w)
|
|
theRect->w += theRect->l - fa->light_s;
|
|
theRect->l = fa->light_s;
|
|
}
|
|
smax = (fa->extents[0]>>4)+1;
|
|
tmax = (fa->extents[1]>>4)+1;
|
|
if ((theRect->w + theRect->l) < (fa->light_s + smax))
|
|
theRect->w = (fa->light_s-theRect->l)+smax;
|
|
if ((theRect->h + theRect->t) < (fa->light_t + tmax))
|
|
theRect->h = (fa->light_t-theRect->t)+tmax;
|
|
base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
|
|
base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
|
|
R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
R_RenderDynamicLightmaps
|
|
Multitexture
|
|
================
|
|
*/
|
|
void R_RenderDynamicLightmaps (msurface_t *fa)
|
|
{
|
|
byte *base;
|
|
int maps;
|
|
glRect_t *theRect;
|
|
int smax, tmax;
|
|
|
|
c_brush_polys++;
|
|
|
|
if (fa->flags & ( SURF_DRAWSKY | SURF_DRAWTURB) )
|
|
return;
|
|
|
|
fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
|
|
lightmap_polys[fa->lightmaptexturenum] = fa->polys;
|
|
|
|
// check for lightmap modification
|
|
for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
|
|
maps++)
|
|
if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
|
|
goto dynamic;
|
|
|
|
if (fa->dlightframe == r_framecount // dynamic this frame
|
|
|| fa->cached_dlight) // dynamic previously
|
|
{
|
|
dynamic:
|
|
if (r_dynamic->value)
|
|
{
|
|
lightmap_modified[fa->lightmaptexturenum] = true;
|
|
theRect = &lightmap_rectchange[fa->lightmaptexturenum];
|
|
if (fa->light_t < theRect->t) {
|
|
if (theRect->h)
|
|
theRect->h += theRect->t - fa->light_t;
|
|
theRect->t = fa->light_t;
|
|
}
|
|
if (fa->light_s < theRect->l) {
|
|
if (theRect->w)
|
|
theRect->w += theRect->l - fa->light_s;
|
|
theRect->l = fa->light_s;
|
|
}
|
|
smax = (fa->extents[0]>>4)+1;
|
|
tmax = (fa->extents[1]>>4)+1;
|
|
if ((theRect->w + theRect->l) < (fa->light_s + smax))
|
|
theRect->w = (fa->light_s-theRect->l)+smax;
|
|
if ((theRect->h + theRect->t) < (fa->light_t + tmax))
|
|
theRect->h = (fa->light_t-theRect->t)+tmax;
|
|
base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
|
|
base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
|
|
R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
================
|
|
R_DrawWaterSurfaces
|
|
================
|
|
*/
|
|
void R_DrawWaterSurfaces (void)
|
|
{
|
|
int i;
|
|
msurface_t *s;
|
|
texture_t *t;
|
|
|
|
if (r_wateralpha->value == 1.0)
|
|
return;
|
|
|
|
//
|
|
// go back to the world matrix
|
|
//
|
|
glLoadMatrixf (r_world_matrix);
|
|
|
|
glEnable (GL_BLEND);
|
|
glColor4f (1,1,1,r_wateralpha->value);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
|
|
{
|
|
t = cl.worldmodel->textures[i];
|
|
if (!t)
|
|
continue;
|
|
s = t->texturechain;
|
|
if (!s)
|
|
continue;
|
|
if ( !(s->flags & SURF_DRAWTURB) )
|
|
continue;
|
|
|
|
// set modulate mode explicitly
|
|
GL_Bind (t->gl_texturenum);
|
|
|
|
for ( ; s ; s=s->texturechain)
|
|
R_RenderBrushPoly (s);
|
|
|
|
t->texturechain = NULL;
|
|
}
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glColor4f (1,1,1,1);
|
|
glDisable (GL_BLEND);
|
|
}
|
|
#else
|
|
/*
|
|
================
|
|
R_DrawWaterSurfaces
|
|
================
|
|
*/
|
|
void R_DrawWaterSurfaces (void)
|
|
{
|
|
int i;
|
|
msurface_t *s;
|
|
texture_t *t;
|
|
|
|
if (r_wateralpha->value == 1.0 && gl_texsort->value)
|
|
return;
|
|
|
|
//
|
|
// go back to the world matrix
|
|
//
|
|
|
|
glLoadMatrixf (r_world_matrix);
|
|
|
|
if (r_wateralpha->value < 1.0) {
|
|
glEnable (GL_BLEND);
|
|
glColor4f (1,1,1,r_wateralpha->value);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
}
|
|
|
|
if (!gl_texsort->value) {
|
|
if (!waterchain)
|
|
return;
|
|
|
|
for ( s = waterchain ; s ; s=s->texturechain) {
|
|
GL_Bind (s->texinfo->texture->gl_texturenum);
|
|
EmitWaterPolys (s);
|
|
}
|
|
|
|
waterchain = NULL;
|
|
} else {
|
|
|
|
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
|
|
{
|
|
t = cl.worldmodel->textures[i];
|
|
if (!t)
|
|
continue;
|
|
s = t->texturechain;
|
|
if (!s)
|
|
continue;
|
|
if ( !(s->flags & SURF_DRAWTURB ) )
|
|
continue;
|
|
|
|
// set modulate mode explicitly
|
|
|
|
GL_Bind (t->gl_texturenum);
|
|
|
|
for ( ; s ; s=s->texturechain)
|
|
EmitWaterPolys (s);
|
|
|
|
t->texturechain = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if (r_wateralpha->value < 1.0) {
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glColor4f (1,1,1,1);
|
|
glDisable (GL_BLEND);
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
================
|
|
DrawTextureChains
|
|
================
|
|
*/
|
|
void DrawTextureChains (void)
|
|
{
|
|
int i;
|
|
msurface_t *s;
|
|
texture_t *t;
|
|
|
|
if (!gl_texsort->value) {
|
|
GL_DisableMultitexture();
|
|
|
|
if (skychain) {
|
|
R_DrawSkyChain(skychain);
|
|
skychain = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
|
|
{
|
|
t = cl.worldmodel->textures[i];
|
|
if (!t)
|
|
continue;
|
|
s = t->texturechain;
|
|
if (!s)
|
|
continue;
|
|
if (i == skytexturenum)
|
|
R_DrawSkyChain (s);
|
|
else
|
|
{
|
|
if ((s->flags & SURF_DRAWTURB) &&
|
|
r_wateralpha->value != 1.0)
|
|
continue; // draw translucent water later
|
|
for ( ; s ; s=s->texturechain)
|
|
R_RenderBrushPoly (s);
|
|
}
|
|
|
|
t->texturechain = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
R_DrawBrushModel
|
|
=================
|
|
*/
|
|
void R_DrawBrushModel (entity_t *e)
|
|
{
|
|
int i;
|
|
int k;
|
|
vec3_t mins, maxs;
|
|
msurface_t *psurf;
|
|
float dot;
|
|
mplane_t *pplane;
|
|
model_t *clmodel;
|
|
qboolean rotated;
|
|
|
|
currententity = e;
|
|
currenttexture = -1;
|
|
|
|
clmodel = e->model;
|
|
|
|
if (e->angles[0] || e->angles[1] || e->angles[2])
|
|
{
|
|
rotated = true;
|
|
for (i=0 ; i<3 ; i++)
|
|
{
|
|
mins[i] = e->origin[i] - clmodel->radius;
|
|
maxs[i] = e->origin[i] + clmodel->radius;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rotated = false;
|
|
VectorAdd (e->origin, clmodel->mins, mins);
|
|
VectorAdd (e->origin, clmodel->maxs, maxs);
|
|
}
|
|
|
|
if (R_CullBox (mins, maxs))
|
|
return;
|
|
|
|
glColor3f (1,1,1);
|
|
memset (lightmap_polys, 0, sizeof(lightmap_polys));
|
|
|
|
VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
|
|
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);
|
|
}
|
|
|
|
psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
|
|
|
|
// calculate dynamic lighting for bmodel if it's not an
|
|
// instanced model
|
|
if (clmodel->firstmodelsurface != 0 && !gl_flashblend->value)
|
|
{
|
|
for (k=0 ; k<MAX_DLIGHTS ; k++)
|
|
{
|
|
if ((cl_dlights[k].die < cl.time) ||
|
|
(!cl_dlights[k].radius))
|
|
continue;
|
|
|
|
R_MarkLights (&cl_dlights[k], 1<<k,
|
|
clmodel->nodes + clmodel->hulls[0].firstclipnode);
|
|
}
|
|
}
|
|
|
|
glPushMatrix ();
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
R_RotateForEntity (e);
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
|
|
//
|
|
// draw texture
|
|
//
|
|
for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
|
|
{
|
|
// find which side of the node we are on
|
|
pplane = psurf->plane;
|
|
|
|
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
|
|
|
|
// draw the polygon
|
|
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
|
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
|
{
|
|
if (gl_texsort->value)
|
|
R_RenderBrushPoly (psurf);
|
|
else
|
|
R_DrawSequentialPoly (psurf);
|
|
}
|
|
}
|
|
|
|
R_BlendLightmaps ();
|
|
|
|
glPopMatrix ();
|
|
}
|
|
|
|
/*
|
|
=============================================================
|
|
|
|
WORLD MODEL
|
|
|
|
=============================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
R_RecursiveWorldNode
|
|
================
|
|
*/
|
|
void R_RecursiveWorldNode (mnode_t *node)
|
|
{
|
|
int c, side;
|
|
mplane_t *plane;
|
|
msurface_t *surf, **mark;
|
|
mleaf_t *pleaf;
|
|
double dot;
|
|
|
|
if (node->contents == CONTENTS_SOLID)
|
|
return; // solid
|
|
|
|
if (node->visframe != r_visframecount)
|
|
return;
|
|
if (R_CullBox (node->minmaxs, node->minmaxs+3))
|
|
return;
|
|
|
|
// if a leaf node, draw stuff
|
|
if (node->contents < 0)
|
|
{
|
|
pleaf = (mleaf_t *)node;
|
|
|
|
mark = pleaf->firstmarksurface;
|
|
c = pleaf->nummarksurfaces;
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
(*mark)->visframe = r_framecount;
|
|
mark++;
|
|
} while (--c);
|
|
}
|
|
|
|
// deal with model fragments in this leaf
|
|
if (pleaf->efrags)
|
|
R_StoreEfrags (&pleaf->efrags);
|
|
|
|
return;
|
|
}
|
|
|
|
// node is just a decision point, so go down the apropriate sides
|
|
|
|
// find which side of the node we are on
|
|
plane = node->plane;
|
|
|
|
switch (plane->type)
|
|
{
|
|
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;
|
|
}
|
|
|
|
if (dot >= 0)
|
|
side = 0;
|
|
else
|
|
side = 1;
|
|
|
|
// recurse down the children, front side first
|
|
R_RecursiveWorldNode (node->children[side]);
|
|
|
|
// draw stuff
|
|
c = node->numsurfaces;
|
|
|
|
if (c)
|
|
{
|
|
surf = cl.worldmodel->surfaces + node->firstsurface;
|
|
|
|
if (dot < 0 -BACKFACE_EPSILON)
|
|
side = SURF_PLANEBACK;
|
|
else if (dot > BACKFACE_EPSILON)
|
|
side = 0;
|
|
{
|
|
for ( ; c ; c--, surf++)
|
|
{
|
|
if (surf->visframe != r_framecount)
|
|
continue;
|
|
|
|
// don't backface underwater surfaces, because they warp
|
|
if (r_waterwarp->value && !(surf->flags & SURF_UNDERWATER) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) )
|
|
continue; // wrong side
|
|
|
|
/* if (r_waterwarp->value && !(((r_viewleaf->contents==CONTENTS_EMPTY && (surf->flags & SURF_UNDERWATER)) ||
|
|
(r_viewleaf->contents!=CONTENTS_EMPTY && !(surf->flags & SURF_UNDERWATER)))
|
|
&& !(surf->flags & SURF_DONTWARP)) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) )
|
|
continue; // wrong side
|
|
*/
|
|
|
|
// if sorting by texture, just store it out
|
|
if (gl_texsort->value)
|
|
{
|
|
surf->texturechain = surf->texinfo->texture->texturechain;
|
|
surf->texinfo->texture->texturechain = surf;
|
|
} else if (surf->flags & SURF_DRAWSKY) {
|
|
surf->texturechain = skychain;
|
|
skychain = surf;
|
|
} else if (surf->flags & SURF_DRAWTURB) {
|
|
surf->texturechain = waterchain;
|
|
waterchain = surf;
|
|
} else
|
|
R_DrawSequentialPoly (surf);
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// recurse down the back side
|
|
R_RecursiveWorldNode (node->children[!side]);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
=============
|
|
R_DrawWorld
|
|
=============
|
|
*/
|
|
void R_DrawWorld (void)
|
|
{
|
|
entity_t ent;
|
|
|
|
memset (&ent, 0, sizeof(ent));
|
|
ent.model = cl.worldmodel;
|
|
|
|
VectorCopy (r_refdef.vieworg, modelorg);
|
|
|
|
currententity = &ent;
|
|
currenttexture = -1;
|
|
|
|
glColor3f (1,1,1);
|
|
memset (lightmap_polys, 0, sizeof(lightmap_polys));
|
|
R_ClearSkyBox ();
|
|
|
|
R_RecursiveWorldNode (cl.worldmodel->nodes);
|
|
|
|
DrawTextureChains ();
|
|
|
|
R_BlendLightmaps ();
|
|
|
|
R_DrawSkyBox ();
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
R_MarkLeaves
|
|
===============
|
|
*/
|
|
void R_MarkLeaves (void)
|
|
{
|
|
byte *vis;
|
|
mnode_t *node;
|
|
int i;
|
|
byte solid[4096];
|
|
|
|
if (r_oldviewleaf == r_viewleaf && !r_novis->value)
|
|
return;
|
|
|
|
r_visframecount++;
|
|
r_oldviewleaf = r_viewleaf;
|
|
|
|
if (r_novis->value)
|
|
{
|
|
vis = solid;
|
|
memset (solid, 0xff, (cl.worldmodel->numleafs+7)>>3);
|
|
}
|
|
else
|
|
vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
|
|
|
|
for (i=0 ; i<cl.worldmodel->numleafs ; i++)
|
|
{
|
|
if (vis[i>>3] & (1<<(i&7)))
|
|
{
|
|
node = (mnode_t *)&cl.worldmodel->leafs[i+1];
|
|
do
|
|
{
|
|
if (node->visframe == r_visframecount)
|
|
break;
|
|
node->visframe = r_visframecount;
|
|
node = node->parent;
|
|
} while (node);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
LIGHTMAP ALLOCATION
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
// 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;
|
|
|
|
for (texnum=0 ; texnum<MAX_LIGHTMAPS ; texnum++)
|
|
{
|
|
best = BLOCK_HEIGHT;
|
|
|
|
for (i=0 ; i<BLOCK_WIDTH-w ; i++)
|
|
{
|
|
best2 = 0;
|
|
|
|
for (j=0 ; j<w ; j++)
|
|
{
|
|
if (allocated[texnum][i+j] >= best)
|
|
break;
|
|
if (allocated[texnum][i+j] > best2)
|
|
best2 = allocated[texnum][i+j];
|
|
}
|
|
if (j == w)
|
|
{ // this is a valid spot
|
|
*x = i;
|
|
*y = best = best2;
|
|
}
|
|
}
|
|
|
|
if (best + h > BLOCK_HEIGHT)
|
|
continue;
|
|
|
|
for (i=0 ; i<w ; i++)
|
|
allocated[texnum][*x + i] = best + h;
|
|
|
|
return texnum;
|
|
}
|
|
|
|
Sys_Error ("AllocBlock: full");
|
|
return 0;
|
|
}
|
|
|
|
|
|
mvertex_t *r_pcurrentvertbase;
|
|
model_t *currentmodel;
|
|
|
|
int nColinElim;
|
|
|
|
/*
|
|
================
|
|
BuildSurfaceDisplayList
|
|
================
|
|
*/
|
|
void BuildSurfaceDisplayList (msurface_t *fa)
|
|
{
|
|
int i, lindex, lnumverts;
|
|
medge_t *pedges, *r_pedge;
|
|
int vertpage;
|
|
float *vec;
|
|
float s, t;
|
|
glpoly_t *poly;
|
|
|
|
// reconstruct the polygon
|
|
pedges = currentmodel->edges;
|
|
lnumverts = fa->numedges;
|
|
vertpage = 0;
|
|
|
|
//
|
|
// 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;
|
|
|
|
for (i=0 ; i<lnumverts ; i++)
|
|
{
|
|
lindex = currentmodel->surfedges[fa->firstedge + i];
|
|
|
|
if (lindex > 0)
|
|
{
|
|
r_pedge = &pedges[lindex];
|
|
vec = r_pcurrentvertbase[r_pedge->v[0]].position;
|
|
}
|
|
else
|
|
{
|
|
r_pedge = &pedges[-lindex];
|
|
vec = r_pcurrentvertbase[r_pedge->v[1]].position;
|
|
}
|
|
s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
|
|
s /= fa->texinfo->texture->width;
|
|
|
|
t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
|
|
t /= fa->texinfo->texture->height;
|
|
|
|
VectorCopy (vec, poly->verts[i]);
|
|
poly->verts[i][3] = s;
|
|
poly->verts[i][4] = t;
|
|
|
|
//
|
|
// lightmap texture coordinates
|
|
//
|
|
s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
|
|
s -= fa->texturemins[0];
|
|
s += fa->light_s*16;
|
|
s += 8;
|
|
s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
|
|
|
|
t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
|
|
t -= fa->texturemins[1];
|
|
t += fa->light_t*16;
|
|
t += 8;
|
|
t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
|
|
|
|
poly->verts[i][5] = s;
|
|
poly->verts[i][6] = t;
|
|
}
|
|
|
|
//
|
|
// remove co-linear points - Ed
|
|
//
|
|
if (!gl_keeptjunctions->value && !(fa->flags & SURF_UNDERWATER) )
|
|
{
|
|
for (i = 0 ; i < lnumverts ; ++i)
|
|
{
|
|
vec3_t v1, v2;
|
|
float *prev, *this, *next;
|
|
|
|
prev = poly->verts[(i + lnumverts - 1) % lnumverts];
|
|
this = poly->verts[i];
|
|
next = poly->verts[(i + 1) % lnumverts];
|
|
|
|
VectorSubtract( this, prev, v1 );
|
|
VectorNormalize( v1 );
|
|
VectorSubtract( next, prev, v2 );
|
|
VectorNormalize( v2 );
|
|
|
|
// skip co-linear points
|
|
#define COLINEAR_EPSILON 0.001
|
|
if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
|
|
(fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) &&
|
|
(fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
|
|
{
|
|
int j;
|
|
for (j = i + 1; j < lnumverts; ++j)
|
|
{
|
|
int k;
|
|
for (k = 0; k < VERTEXSIZE; ++k)
|
|
poly->verts[j - 1][k] = poly->verts[j][k];
|
|
}
|
|
--lnumverts;
|
|
++nColinElim;
|
|
// retry next vertex next time, which is now current vertex
|
|
--i;
|
|
}
|
|
}
|
|
}
|
|
poly->numverts = lnumverts;
|
|
|
|
}
|
|
|
|
/*
|
|
========================
|
|
GL_CreateSurfaceLightmap
|
|
========================
|
|
*/
|
|
void GL_CreateSurfaceLightmap (msurface_t *surf)
|
|
{
|
|
int smax, tmax;
|
|
byte *base;
|
|
|
|
if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
|
|
return;
|
|
|
|
smax = (surf->extents[0]>>4)+1;
|
|
tmax = (surf->extents[1]>>4)+1;
|
|
|
|
surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
|
|
base = lightmaps + surf->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
|
|
base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
|
|
R_BuildLightMap (surf, base, BLOCK_WIDTH*lightmap_bytes);
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
GL_BuildLightmaps
|
|
|
|
Builds the lightmap texture
|
|
with all the surfaces from all brush models
|
|
==================
|
|
*/
|
|
void GL_BuildLightmaps (void)
|
|
{
|
|
int i, j;
|
|
model_t *m;
|
|
|
|
memset (allocated, 0, sizeof(allocated));
|
|
|
|
r_framecount = 1; // no dlightcache
|
|
|
|
if (!lightmap_textures)
|
|
{
|
|
lightmap_textures = texture_extension_number;
|
|
texture_extension_number += MAX_LIGHTMAPS;
|
|
}
|
|
|
|
gl_lightmap_format = GL_LUMINANCE;
|
|
if (COM_CheckParm ("-lm_1"))
|
|
gl_lightmap_format = GL_LUMINANCE;
|
|
if (COM_CheckParm ("-lm_a"))
|
|
gl_lightmap_format = GL_ALPHA;
|
|
if (COM_CheckParm ("-lm_i"))
|
|
gl_lightmap_format = GL_INTENSITY;
|
|
if (COM_CheckParm ("-lm_2"))
|
|
gl_lightmap_format = GL_RGBA4;
|
|
if (COM_CheckParm ("-lm_4"))
|
|
gl_lightmap_format = GL_RGBA;
|
|
|
|
switch (gl_lightmap_format)
|
|
{
|
|
case GL_RGBA:
|
|
lightmap_bytes = 4;
|
|
break;
|
|
case GL_RGBA4:
|
|
lightmap_bytes = 2;
|
|
break;
|
|
case GL_LUMINANCE:
|
|
case GL_INTENSITY:
|
|
case GL_ALPHA:
|
|
lightmap_bytes = 1;
|
|
break;
|
|
}
|
|
|
|
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++)
|
|
{
|
|
GL_CreateSurfaceLightmap (m->surfaces + i);
|
|
if ( m->surfaces[i].flags & SURF_DRAWTURB )
|
|
continue;
|
|
if ( m->surfaces[i].flags & SURF_DRAWSKY )
|
|
continue;
|
|
BuildSurfaceDisplayList (m->surfaces + i);
|
|
}
|
|
}
|
|
|
|
if (!gl_texsort->value)
|
|
GL_SelectTexture(TEXTURE1_SGIS);
|
|
|
|
//
|
|
// upload all lightmaps that were filled
|
|
//
|
|
for (i=0 ; i<MAX_LIGHTMAPS ; i++)
|
|
{
|
|
if (!allocated[i][0])
|
|
break; // no more used
|
|
lightmap_modified[i] = false;
|
|
lightmap_rectchange[i].l = BLOCK_WIDTH;
|
|
lightmap_rectchange[i].t = BLOCK_HEIGHT;
|
|
lightmap_rectchange[i].w = 0;
|
|
lightmap_rectchange[i].h = 0;
|
|
GL_Bind(lightmap_textures + i);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes
|
|
, BLOCK_WIDTH, BLOCK_HEIGHT, 0,
|
|
gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
|
|
}
|
|
|
|
if (!gl_texsort->value)
|
|
GL_SelectTexture(TEXTURE0_SGIS);
|
|
|
|
}
|
|
|