mirror of
https://git.code.sf.net/p/quake/quakeforge-old
synced 2024-11-14 16:31:17 +00:00
c3f5581b0a
Unchained, Ultimate, Ultra, Up Yours, Underworld, Underground, Unified, Unity, etc. You know the drill. This takes care of the "standalone" problem with the wrong name, and the recent snafu with multiple developers working on the same files simultaneously...expect me (and probably others) to start locking dirs when updates are taking place. And yes, this update is really as large as it looks. Software only at the moment, but I will have the makefile updated to build the GL builds as well.
1694 lines
34 KiB
C
1694 lines
34 KiB
C
/*
|
|
Copyright (C) 1996-1997 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.
|
|
|
|
*/
|
|
// r_surf.c: surface-related refresh code
|
|
|
|
#include "quakedef.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;
|
|
int lightadj[4];
|
|
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;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
================
|
|
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|SURF_UNDERWATER) ) )
|
|
{
|
|
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, dir;
|
|
float ss, ss2, length;
|
|
float s1, t1;
|
|
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;
|
|
float s, t, os, ot;
|
|
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;
|
|
float s, t, os, ot;
|
|
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 (r_fullbright.value)
|
|
return;
|
|
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];
|
|
// 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 (p->flags & SURF_UNDERWATER)
|
|
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 (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)
|
|
{
|
|
texture_t *t;
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
R_MirrorChain
|
|
================
|
|
*/
|
|
void R_MirrorChain (msurface_t *s)
|
|
{
|
|
if (mirror)
|
|
return;
|
|
mirror = true;
|
|
mirror_plane = s->plane;
|
|
}
|
|
|
|
|
|
#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 (i == mirrortexturenum && r_mirroralpha.value != 1.0)
|
|
{
|
|
R_MirrorChain (s);
|
|
continue;
|
|
}
|
|
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 j, k;
|
|
vec3_t mins, maxs;
|
|
int i, numsurfaces;
|
|
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 i, c, side, *pindex;
|
|
vec3_t acceptpt, rejectpt;
|
|
mplane_t *plane;
|
|
msurface_t *surf, **mark;
|
|
mleaf_t *pleaf;
|
|
double d, dot;
|
|
vec3_t mins, maxs;
|
|
|
|
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 ( !(surf->flags & SURF_UNDERWATER) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) )
|
|
continue; // wrong side
|
|
|
|
// if sorting by texture, just store it out
|
|
if (gl_texsort.value)
|
|
{
|
|
if (!mirror
|
|
|| surf->texinfo->texture != cl.worldmodel->textures[mirrortexturenum])
|
|
{
|
|
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;
|
|
int i;
|
|
|
|
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));
|
|
#ifdef QUAKE2
|
|
R_ClearSkyBox ();
|
|
#endif
|
|
|
|
R_RecursiveWorldNode (cl.worldmodel->nodes);
|
|
|
|
DrawTextureChains ();
|
|
|
|
R_BlendLightmaps ();
|
|
|
|
#ifdef QUAKE2
|
|
R_DrawSkyBox ();
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
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;
|
|
|
|
if (mirror)
|
|
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 bestx;
|
|
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");
|
|
}
|
|
|
|
|
|
mvertex_t *r_pcurrentvertbase;
|
|
model_t *currentmodel;
|
|
|
|
int nColinElim;
|
|
|
|
/*
|
|
================
|
|
BuildSurfaceDisplayList
|
|
================
|
|
*/
|
|
void BuildSurfaceDisplayList (msurface_t *fa)
|
|
{
|
|
int i, lindex, lnumverts, s_axis, t_axis;
|
|
float dist, lastdist, lzi, scale, u, v, frac;
|
|
unsigned mask;
|
|
vec3_t local, transformed;
|
|
medge_t *pedges, *r_pedge;
|
|
mplane_t *pplane;
|
|
int vertpage, newverts, newpage, lastvert;
|
|
qboolean visible;
|
|
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;
|
|
float f;
|
|
|
|
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, s, t, l, i;
|
|
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;
|
|
extern qboolean isPermedia;
|
|
|
|
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;
|
|
// default differently on the Permedia
|
|
if (isPermedia)
|
|
gl_lightmap_format = GL_RGBA;
|
|
|
|
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;
|
|
#ifndef QUAKE2
|
|
if ( m->surfaces[i].flags & SURF_DRAWSKY )
|
|
continue;
|
|
#endif
|
|
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);
|
|
|
|
}
|
|
|