mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2025-02-03 06:20:57 +00:00
112c8b68b8
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices). Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call. Special thanks to MH for some of the code from RMQEngine and the general concept. git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
1314 lines
31 KiB
C
1314 lines
31 KiB
C
/*
|
|
Copyright (C) 1996-2001 Id Software, Inc.
|
|
Copyright (C) 2002-2009 John Fitzgibbons and others
|
|
Copyright (C) 2007-2008 Kristian Duske
|
|
Copyright (C) 2010-2014 QuakeSpasm developers
|
|
|
|
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_brush.c: brush model rendering. renamed from r_surf.c
|
|
|
|
#include "quakedef.h"
|
|
|
|
extern cvar_t gl_fullbrights, r_drawflat, gl_overbright, r_oldwater; //johnfitz
|
|
extern cvar_t gl_zfix; // QuakeSpasm z-fighting fix
|
|
|
|
int gl_lightmap_format;
|
|
int lightmap_bytes;
|
|
|
|
#define BLOCK_WIDTH 128
|
|
#define BLOCK_HEIGHT 128
|
|
|
|
gltexture_t *lightmap_textures[MAX_LIGHTMAPS]; //johnfitz -- changed to an array
|
|
|
|
unsigned blocklights[BLOCK_WIDTH*BLOCK_HEIGHT*3]; //johnfitz -- was 18*18, added lit support (*3) and loosened surface extents maximum (BLOCK_WIDTH*BLOCK_HEIGHT)
|
|
|
|
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];
|
|
int last_lightmap_allocated; //ericw -- optimization: remember the index of the last lightmap AllocBlock stored a surf in
|
|
|
|
// 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];
|
|
|
|
|
|
/*
|
|
===============
|
|
R_TextureAnimation -- johnfitz -- added "frame" param to eliminate use of "currententity" global
|
|
|
|
Returns the proper texture for a given time and base texture
|
|
===============
|
|
*/
|
|
texture_t *R_TextureAnimation (texture_t *base, int frame)
|
|
{
|
|
int relative;
|
|
int count;
|
|
|
|
if (frame)
|
|
if (base->alternate_anims)
|
|
base = base->alternate_anims;
|
|
|
|
if (!base->anim_total)
|
|
return base;
|
|
|
|
relative = (int)(cl.time*10) % base->anim_total;
|
|
|
|
count = 0;
|
|
while (base->anim_min > relative || base->anim_max <= relative)
|
|
{
|
|
base = base->anim_next;
|
|
if (!base)
|
|
Sys_Error ("R_TextureAnimation: broken cycle");
|
|
if (++count > 100)
|
|
Sys_Error ("R_TextureAnimation: infinite cycle");
|
|
}
|
|
|
|
return base;
|
|
}
|
|
|
|
/*
|
|
================
|
|
DrawGLPoly
|
|
================
|
|
*/
|
|
void DrawGLPoly (glpoly_t *p)
|
|
{
|
|
float *v;
|
|
int i;
|
|
|
|
glBegin (GL_POLYGON);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[3], v[4]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
}
|
|
|
|
/*
|
|
================
|
|
DrawGLTriangleFan -- johnfitz -- like DrawGLPoly but for r_showtris
|
|
================
|
|
*/
|
|
void DrawGLTriangleFan (glpoly_t *p)
|
|
{
|
|
float *v;
|
|
int i;
|
|
|
|
glBegin (GL_TRIANGLE_FAN);
|
|
v = p->verts[0];
|
|
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
}
|
|
|
|
/*
|
|
=============================================================
|
|
|
|
BRUSH MODELS
|
|
|
|
=============================================================
|
|
*/
|
|
|
|
#if 0
|
|
/*
|
|
================
|
|
R_DrawSequentialPoly -- johnfitz -- rewritten
|
|
================
|
|
*/
|
|
void R_DrawSequentialPoly (msurface_t *s)
|
|
{
|
|
glpoly_t *p;
|
|
texture_t *t;
|
|
float *v;
|
|
float entalpha;
|
|
int i;
|
|
|
|
t = R_TextureAnimation (s->texinfo->texture, currententity->frame);
|
|
entalpha = ENTALPHA_DECODE(currententity->alpha);
|
|
|
|
// drawflat
|
|
if (r_drawflat_cheatsafe)
|
|
{
|
|
if ((s->flags & SURF_DRAWTURB) && r_oldwater.value)
|
|
{
|
|
for (p = s->polys->next; p; p = p->next)
|
|
{
|
|
srand((unsigned int) (uintptr_t) p);
|
|
glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0);
|
|
DrawGLPoly (p);
|
|
rs_brushpasses++;
|
|
}
|
|
return;
|
|
}
|
|
|
|
srand((unsigned int) (uintptr_t) s->polys);
|
|
glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0);
|
|
DrawGLPoly (s->polys);
|
|
rs_brushpasses++;
|
|
return;
|
|
}
|
|
|
|
// fullbright
|
|
if ((r_fullbright_cheatsafe) && !(s->flags & SURF_DRAWTILED))
|
|
{
|
|
if (entalpha < 1)
|
|
{
|
|
glDepthMask(GL_FALSE);
|
|
glEnable(GL_BLEND);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glColor4f(1, 1, 1, entalpha);
|
|
}
|
|
|
|
if (s->flags & SURF_DRAWFENCE)
|
|
glEnable (GL_ALPHA_TEST); // Flip on alpha test
|
|
|
|
GL_Bind (t->gltexture);
|
|
DrawGLPoly (s->polys);
|
|
rs_brushpasses++;
|
|
|
|
if (s->flags & SURF_DRAWFENCE)
|
|
glDisable (GL_ALPHA_TEST); // Flip alpha test back off
|
|
|
|
if (entalpha < 1)
|
|
{
|
|
glDepthMask(GL_TRUE);
|
|
glDisable(GL_BLEND);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glColor3f(1, 1, 1);
|
|
}
|
|
goto fullbrights;
|
|
}
|
|
|
|
// r_lightmap
|
|
if (r_lightmap_cheatsafe)
|
|
{
|
|
if (s->flags & SURF_DRAWTILED)
|
|
{
|
|
glDisable (GL_TEXTURE_2D);
|
|
DrawGLPoly (s->polys);
|
|
glEnable (GL_TEXTURE_2D);
|
|
rs_brushpasses++;
|
|
return;
|
|
}
|
|
|
|
R_RenderDynamicLightmaps (s);
|
|
GL_Bind (lightmap_textures[s->lightmaptexturenum]);
|
|
if (!gl_overbright.value)
|
|
{
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glColor3f(0.5, 0.5, 0.5);
|
|
}
|
|
glBegin (GL_POLYGON);
|
|
v = s->polys->verts[0];
|
|
for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[5], v[6]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
if (!gl_overbright.value)
|
|
{
|
|
glColor3f(1,1,1);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
}
|
|
rs_brushpasses++;
|
|
return;
|
|
}
|
|
|
|
// sky poly -- skip it, already handled in gl_sky.c
|
|
if (s->flags & SURF_DRAWSKY)
|
|
return;
|
|
|
|
// water poly
|
|
if (s->flags & SURF_DRAWTURB)
|
|
{
|
|
if (currententity->alpha == ENTALPHA_DEFAULT)
|
|
entalpha = CLAMP(0.0,r_wateralpha.value,1.0);
|
|
|
|
if (entalpha < 1)
|
|
{
|
|
glDepthMask(GL_FALSE);
|
|
glEnable(GL_BLEND);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glColor4f(1, 1, 1, entalpha);
|
|
}
|
|
if (r_oldwater.value)
|
|
{
|
|
GL_Bind (s->texinfo->texture->gltexture);
|
|
for (p = s->polys->next; p; p = p->next)
|
|
{
|
|
DrawWaterPoly (p);
|
|
rs_brushpasses++;
|
|
}
|
|
rs_brushpasses++;
|
|
}
|
|
else
|
|
{
|
|
GL_Bind (s->texinfo->texture->warpimage);
|
|
s->texinfo->texture->update_warp = true; // FIXME: one frame too late!
|
|
DrawGLPoly (s->polys);
|
|
rs_brushpasses++;
|
|
}
|
|
if (entalpha < 1)
|
|
{
|
|
glDepthMask(GL_TRUE);
|
|
glDisable(GL_BLEND);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glColor3f(1, 1, 1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// missing texture
|
|
if (s->flags & SURF_NOTEXTURE)
|
|
{
|
|
if (entalpha < 1)
|
|
{
|
|
glDepthMask(GL_FALSE);
|
|
glEnable(GL_BLEND);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glColor4f(1, 1, 1, entalpha);
|
|
}
|
|
GL_Bind (t->gltexture);
|
|
DrawGLPoly (s->polys);
|
|
rs_brushpasses++;
|
|
if (entalpha < 1)
|
|
{
|
|
glDepthMask(GL_TRUE);
|
|
glDisable(GL_BLEND);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glColor3f(1, 1, 1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// lightmapped poly
|
|
if (entalpha < 1)
|
|
{
|
|
glDepthMask(GL_FALSE);
|
|
glEnable(GL_BLEND);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glColor4f(1, 1, 1, entalpha);
|
|
}
|
|
else
|
|
glColor3f(1, 1, 1);
|
|
|
|
if (s->flags & SURF_DRAWFENCE)
|
|
glEnable (GL_ALPHA_TEST); // Flip on alpha test
|
|
|
|
if (gl_overbright.value)
|
|
{
|
|
if (gl_texture_env_combine && gl_mtexable) //case 1: texture and lightmap in one pass, overbright using texture combiners
|
|
{
|
|
GL_DisableMultitexture(); // selects TEXTURE0
|
|
GL_Bind (t->gltexture);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
GL_EnableMultitexture(); // selects TEXTURE1
|
|
GL_Bind (lightmap_textures[s->lightmaptexturenum]);
|
|
R_RenderDynamicLightmaps (s);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
|
|
glBegin(GL_POLYGON);
|
|
v = s->polys->verts[0];
|
|
for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]);
|
|
GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
GL_DisableMultitexture ();
|
|
rs_brushpasses++;
|
|
}
|
|
else if (entalpha < 1 || (s->flags & SURF_DRAWFENCE)) //case 2: can't do multipass if entity has alpha, so just draw the texture
|
|
{
|
|
GL_Bind (t->gltexture);
|
|
DrawGLPoly (s->polys);
|
|
rs_brushpasses++;
|
|
}
|
|
else //case 3: texture in one pass, lightmap in second pass using 2x modulation blend func, fog in third pass
|
|
{
|
|
//first pass -- texture with no fog
|
|
Fog_DisableGFog ();
|
|
GL_Bind (t->gltexture);
|
|
DrawGLPoly (s->polys);
|
|
Fog_EnableGFog ();
|
|
rs_brushpasses++;
|
|
|
|
//second pass -- lightmap with black fog, modulate blended
|
|
R_RenderDynamicLightmaps (s);
|
|
GL_Bind (lightmap_textures[s->lightmaptexturenum]);
|
|
glDepthMask (GL_FALSE);
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); //2x modulate
|
|
Fog_StartAdditive ();
|
|
glBegin (GL_POLYGON);
|
|
v = s->polys->verts[0];
|
|
for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[5], v[6]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
Fog_StopAdditive ();
|
|
rs_brushpasses++;
|
|
|
|
//third pass -- black geo with normal fog, additive blended
|
|
if (Fog_GetDensity() > 0)
|
|
{
|
|
glBlendFunc(GL_ONE, GL_ONE); //add
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glColor3f(0,0,0);
|
|
DrawGLPoly (s->polys);
|
|
glColor3f(1,1,1);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
rs_brushpasses++;
|
|
}
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDisable (GL_BLEND);
|
|
glDepthMask (GL_TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gl_mtexable) //case 4: texture and lightmap in one pass, regular modulation
|
|
{
|
|
GL_DisableMultitexture(); // selects TEXTURE0
|
|
GL_Bind (t->gltexture);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
GL_EnableMultitexture(); // selects TEXTURE1
|
|
GL_Bind (lightmap_textures[s->lightmaptexturenum]);
|
|
R_RenderDynamicLightmaps (s);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glBegin(GL_POLYGON);
|
|
v = s->polys->verts[0];
|
|
for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]);
|
|
GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
GL_DisableMultitexture ();
|
|
rs_brushpasses++;
|
|
}
|
|
else if (entalpha < 1 || (s->flags & SURF_DRAWFENCE)) //case 5: can't do multipass if entity has alpha, so just draw the texture
|
|
{
|
|
GL_Bind (t->gltexture);
|
|
DrawGLPoly (s->polys);
|
|
rs_brushpasses++;
|
|
}
|
|
else //case 6: texture in one pass, lightmap in a second pass, fog in third pass
|
|
{
|
|
//first pass -- texture with no fog
|
|
Fog_DisableGFog ();
|
|
GL_Bind (t->gltexture);
|
|
DrawGLPoly (s->polys);
|
|
Fog_EnableGFog ();
|
|
rs_brushpasses++;
|
|
|
|
//second pass -- lightmap with black fog, modulate blended
|
|
R_RenderDynamicLightmaps (s);
|
|
GL_Bind (lightmap_textures[s->lightmaptexturenum]);
|
|
glDepthMask (GL_FALSE);
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_ZERO, GL_SRC_COLOR); //modulate
|
|
Fog_StartAdditive ();
|
|
glBegin (GL_POLYGON);
|
|
v = s->polys->verts[0];
|
|
for (i=0 ; i<s->polys->numverts ; i++, v+= VERTEXSIZE)
|
|
{
|
|
glTexCoord2f (v[5], v[6]);
|
|
glVertex3fv (v);
|
|
}
|
|
glEnd ();
|
|
Fog_StopAdditive ();
|
|
rs_brushpasses++;
|
|
|
|
//third pass -- black geo with normal fog, additive blended
|
|
if (Fog_GetDensity() > 0)
|
|
{
|
|
glBlendFunc(GL_ONE, GL_ONE); //add
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glColor3f(0,0,0);
|
|
DrawGLPoly (s->polys);
|
|
glColor3f(1,1,1);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
rs_brushpasses++;
|
|
}
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDisable (GL_BLEND);
|
|
glDepthMask (GL_TRUE);
|
|
|
|
}
|
|
}
|
|
if (entalpha < 1)
|
|
{
|
|
glDepthMask(GL_TRUE);
|
|
glDisable(GL_BLEND);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glColor3f(1, 1, 1);
|
|
}
|
|
|
|
if (s->flags & SURF_DRAWFENCE)
|
|
glDisable (GL_ALPHA_TEST); // Flip alpha test back off
|
|
|
|
fullbrights:
|
|
if (gl_fullbrights.value && t->fullbright)
|
|
{
|
|
glDepthMask (GL_FALSE);
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glColor3f (entalpha, entalpha, entalpha);
|
|
GL_Bind (t->fullbright);
|
|
Fog_StartAdditive ();
|
|
DrawGLPoly (s->polys);
|
|
Fog_StopAdditive ();
|
|
glColor3f(1, 1, 1);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glDisable (GL_BLEND);
|
|
glDepthMask (GL_TRUE);
|
|
rs_brushpasses++;
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
=================
|
|
R_DrawBrushModel
|
|
=================
|
|
*/
|
|
void R_DrawBrushModel (entity_t *e)
|
|
{
|
|
int i, k;
|
|
msurface_t *psurf;
|
|
float dot;
|
|
mplane_t *pplane;
|
|
qmodel_t *clmodel;
|
|
|
|
if (R_CullModelForEntity(e))
|
|
return;
|
|
|
|
currententity = e;
|
|
clmodel = e->model;
|
|
|
|
VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
|
|
if (e->angles[0] || e->angles[1] || e->angles[2])
|
|
{
|
|
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], k,
|
|
clmodel->nodes + clmodel->hulls[0].firstclipnode);
|
|
}
|
|
}
|
|
|
|
glPushMatrix ();
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
if (gl_zfix.value)
|
|
{
|
|
e->origin[0] -= DIST_EPSILON;
|
|
e->origin[1] -= DIST_EPSILON;
|
|
e->origin[2] -= DIST_EPSILON;
|
|
}
|
|
R_RotateForEntity (e->origin, e->angles);
|
|
if (gl_zfix.value)
|
|
{
|
|
e->origin[0] += DIST_EPSILON;
|
|
e->origin[1] += DIST_EPSILON;
|
|
e->origin[2] += DIST_EPSILON;
|
|
}
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
|
|
R_ClearTextureChains (clmodel, chain_model);
|
|
for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
|
|
{
|
|
pplane = psurf->plane;
|
|
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
|
|
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
|
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
|
{
|
|
R_ChainSurface (psurf, chain_model);
|
|
rs_brushpolys++;
|
|
}
|
|
}
|
|
|
|
R_DrawTextureChains (clmodel, e, chain_model);
|
|
R_DrawTextureChains_Water (clmodel, e, chain_model);
|
|
|
|
glPopMatrix ();
|
|
}
|
|
|
|
/*
|
|
=================
|
|
R_DrawBrushModel_ShowTris -- johnfitz
|
|
=================
|
|
*/
|
|
void R_DrawBrushModel_ShowTris (entity_t *e)
|
|
{
|
|
int i;
|
|
msurface_t *psurf;
|
|
float dot;
|
|
mplane_t *pplane;
|
|
qmodel_t *clmodel;
|
|
glpoly_t *p;
|
|
|
|
if (R_CullModelForEntity(e))
|
|
return;
|
|
|
|
currententity = e;
|
|
clmodel = e->model;
|
|
|
|
VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
|
|
if (e->angles[0] || e->angles[1] || e->angles[2])
|
|
{
|
|
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];
|
|
|
|
glPushMatrix ();
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
R_RotateForEntity (e->origin, e->angles);
|
|
e->angles[0] = -e->angles[0]; // stupid quake bug
|
|
|
|
//
|
|
// draw it
|
|
//
|
|
for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
|
|
{
|
|
pplane = psurf->plane;
|
|
dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
|
|
if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
|
(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
|
{
|
|
if ((psurf->flags & SURF_DRAWTURB) && r_oldwater.value)
|
|
for (p = psurf->polys->next; p; p = p->next)
|
|
DrawGLTriangleFan (p);
|
|
else
|
|
DrawGLTriangleFan (psurf->polys);
|
|
}
|
|
}
|
|
|
|
glPopMatrix ();
|
|
}
|
|
|
|
/*
|
|
=============================================================
|
|
|
|
LIGHTMAPS
|
|
|
|
=============================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
R_RenderDynamicLightmaps
|
|
called during rendering
|
|
================
|
|
*/
|
|
void R_RenderDynamicLightmaps (msurface_t *fa)
|
|
{
|
|
byte *base;
|
|
int maps;
|
|
glRect_t *theRect;
|
|
int smax, tmax;
|
|
|
|
if (fa->flags & SURF_DRAWTILED) //johnfitz -- not a lightmapped surface
|
|
return;
|
|
|
|
// add to 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
AllocBlock -- 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;
|
|
|
|
// ericw -- rather than searching starting at lightmap 0 every time,
|
|
// start at the last lightmap we allocated a surface in.
|
|
// This makes AllocBlock much faster on large levels (can shave off 3+ seconds
|
|
// of load time on a level with 180 lightmaps), at a cost of not quite packing
|
|
// lightmaps as tightly vs. not doing this (uses ~5% more lightmaps)
|
|
for (texnum=last_lightmap_allocated ; texnum<MAX_LIGHTMAPS ; texnum++, last_lightmap_allocated++)
|
|
{
|
|
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; //johnfitz -- shut up compiler
|
|
}
|
|
|
|
|
|
mvertex_t *r_pcurrentvertbase;
|
|
qmodel_t *currentmodel;
|
|
|
|
int nColinElim;
|
|
|
|
/*
|
|
========================
|
|
GL_CreateSurfaceLightmap
|
|
========================
|
|
*/
|
|
void GL_CreateSurfaceLightmap (msurface_t *surf)
|
|
{
|
|
int smax, tmax;
|
|
byte *base;
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
================
|
|
BuildSurfaceDisplayList -- called at level load time
|
|
================
|
|
*/
|
|
void BuildSurfaceDisplayList (msurface_t *fa)
|
|
{
|
|
int i, lindex, lnumverts;
|
|
medge_t *pedges, *r_pedge;
|
|
float *vec;
|
|
float s, t;
|
|
glpoly_t *poly;
|
|
|
|
// reconstruct the polygon
|
|
pedges = currentmodel->edges;
|
|
lnumverts = fa->numedges;
|
|
|
|
//
|
|
// draw texture
|
|
//
|
|
poly = (glpoly_t *) Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float));
|
|
poly->next = fa->polys;
|
|
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;
|
|
}
|
|
|
|
//johnfitz -- removed gl_keeptjunctions code
|
|
|
|
poly->numverts = lnumverts;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
GL_BuildLightmaps -- called at level load time
|
|
|
|
Builds the lightmap texture
|
|
with all the surfaces from all brush models
|
|
==================
|
|
*/
|
|
void GL_BuildLightmaps (void)
|
|
{
|
|
char name[16];
|
|
byte *data;
|
|
int i, j;
|
|
qmodel_t *m;
|
|
|
|
memset (allocated, 0, sizeof(allocated));
|
|
last_lightmap_allocated = 0;
|
|
|
|
r_framecount = 1; // no dlightcache
|
|
|
|
//johnfitz -- null out array (the gltexture objects themselves were already freed by Mod_ClearAll)
|
|
for (i=0; i < MAX_LIGHTMAPS; i++)
|
|
lightmap_textures[i] = NULL;
|
|
//johnfitz
|
|
|
|
gl_lightmap_format = GL_RGBA;//FIXME: hardcoded for now!
|
|
|
|
switch (gl_lightmap_format)
|
|
{
|
|
case GL_RGBA:
|
|
lightmap_bytes = 4;
|
|
break;
|
|
case GL_BGRA:
|
|
lightmap_bytes = 4;
|
|
break;
|
|
default:
|
|
Sys_Error ("GL_BuildLightmaps: bad lightmap format");
|
|
}
|
|
|
|
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++)
|
|
{
|
|
//johnfitz -- rewritten to use SURF_DRAWTILED instead of the sky/water flags
|
|
if (m->surfaces[i].flags & SURF_DRAWTILED)
|
|
continue;
|
|
GL_CreateSurfaceLightmap (m->surfaces + i);
|
|
BuildSurfaceDisplayList (m->surfaces + i);
|
|
//johnfitz
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
|
|
//johnfitz -- use texture manager
|
|
sprintf(name, "lightmap%03i",i);
|
|
data = lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes;
|
|
lightmap_textures[i] = TexMgr_LoadImage (cl.worldmodel, name, BLOCK_WIDTH, BLOCK_HEIGHT,
|
|
SRC_LIGHTMAP, data, "", (src_offset_t)data, TEXPREF_LINEAR | TEXPREF_NOPICMIP);
|
|
//johnfitz
|
|
}
|
|
|
|
//johnfitz -- warn about exceeding old limits
|
|
if (i >= 64)
|
|
Con_Warning ("%i lightmaps exceeds standard limit of 64.\n", i);
|
|
//johnfitz
|
|
}
|
|
|
|
/*
|
|
=============================================================
|
|
|
|
VBO support
|
|
|
|
=============================================================
|
|
*/
|
|
|
|
GLuint gl_bmodel_vbo = 0;
|
|
|
|
/*
|
|
==================
|
|
GL_BuildVBOs
|
|
|
|
Deletes gl_bmodel_vbo if it already exists, then rebuilds it with all
|
|
surfaces from world + all brush models
|
|
==================
|
|
*/
|
|
void GL_BuildVBOs (void)
|
|
{
|
|
unsigned int numverts, varray_bytes, varray_index;
|
|
int i, j;
|
|
qmodel_t *m;
|
|
float *varray;
|
|
|
|
if (!(gl_vbo_able && gl_mtexable && gl_max_texture_units >= 3))
|
|
return;
|
|
|
|
// ask GL for a name for our VBO
|
|
GL_DeleteBuffersFunc (1, &gl_bmodel_vbo);
|
|
GL_GenBuffersFunc (1, &gl_bmodel_vbo);
|
|
|
|
// count all verts in all models
|
|
numverts = 0;
|
|
for (j=1 ; j<MAX_MODELS ; j++)
|
|
{
|
|
m = cl.model_precache[j];
|
|
if (!m || m->name[0] == '*' || m->type != mod_brush)
|
|
continue;
|
|
|
|
for (i=0 ; i<m->numsurfaces ; i++)
|
|
{
|
|
numverts += m->surfaces[i].numedges;
|
|
}
|
|
}
|
|
|
|
// build vertex array
|
|
varray_bytes = VERTEXSIZE * sizeof(float) * numverts;
|
|
varray = (float *) malloc (varray_bytes);
|
|
varray_index = 0;
|
|
|
|
for (j=1 ; j<MAX_MODELS ; j++)
|
|
{
|
|
m = cl.model_precache[j];
|
|
if (!m || m->name[0] == '*' || m->type != mod_brush)
|
|
continue;
|
|
|
|
for (i=0 ; i<m->numsurfaces ; i++)
|
|
{
|
|
msurface_t *s = &m->surfaces[i];
|
|
s->vbo_firstvert = varray_index;
|
|
memcpy (&varray[VERTEXSIZE * varray_index], s->polys->verts, VERTEXSIZE * sizeof(float) * s->numedges);
|
|
varray_index += s->numedges;
|
|
}
|
|
}
|
|
|
|
// upload to GPU
|
|
GL_BindBufferFunc (GL_ARRAY_BUFFER, gl_bmodel_vbo);
|
|
GL_BufferDataFunc (GL_ARRAY_BUFFER, varray_bytes, varray, GL_STATIC_DRAW);
|
|
free (varray);
|
|
|
|
// invalidate the cached bindings
|
|
GL_ClearBufferBindings ();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
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;
|
|
//johnfitz -- lit support via lordhavoc
|
|
float cred, cgreen, cblue, brightness;
|
|
unsigned *bl;
|
|
//johnfitz
|
|
|
|
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[lnum >> 5] & (1U << (lnum & 31))))
|
|
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];
|
|
|
|
//johnfitz -- lit support via lordhavoc
|
|
bl = blocklights;
|
|
cred = cl_dlights[lnum].color[0] * 256.0f;
|
|
cgreen = cl_dlights[lnum].color[1] * 256.0f;
|
|
cblue = cl_dlights[lnum].color[2] * 256.0f;
|
|
//johnfitz
|
|
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)
|
|
//johnfitz -- lit support via lordhavoc
|
|
{
|
|
brightness = rad - dist;
|
|
bl[0] += (int) (brightness * cred);
|
|
bl[1] += (int) (brightness * cgreen);
|
|
bl[2] += (int) (brightness * cblue);
|
|
}
|
|
bl += 3;
|
|
//johnfitz
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
R_BuildLightMap -- johnfitz -- revised for lit support via lordhavoc
|
|
|
|
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 r,g,b;
|
|
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;
|
|
|
|
if (cl.worldmodel->lightdata)
|
|
{
|
|
// clear to no light
|
|
memset (&blocklights[0], 0, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc
|
|
|
|
// 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
|
|
//johnfitz -- lit support via lordhavoc
|
|
bl = blocklights;
|
|
for (i=0 ; i<size ; i++)
|
|
{
|
|
*bl++ += *lightmap++ * scale;
|
|
*bl++ += *lightmap++ * scale;
|
|
*bl++ += *lightmap++ * scale;
|
|
}
|
|
//johnfitz
|
|
}
|
|
|
|
// add all the dynamic lights
|
|
if (surf->dlightframe == r_framecount)
|
|
R_AddDynamicLights (surf);
|
|
}
|
|
else
|
|
{
|
|
// set to full bright if no light data
|
|
memset (&blocklights[0], 255, size * 3 * sizeof (unsigned int)); //johnfitz -- lit support via lordhavoc
|
|
}
|
|
|
|
// bound, invert, and shift
|
|
// store:
|
|
switch (gl_lightmap_format)
|
|
{
|
|
case GL_RGBA:
|
|
stride -= smax * 4;
|
|
bl = blocklights;
|
|
for (i=0 ; i<tmax ; i++, dest += stride)
|
|
{
|
|
for (j=0 ; j<smax ; j++)
|
|
{
|
|
if (gl_overbright.value)
|
|
{
|
|
r = *bl++ >> 8;
|
|
g = *bl++ >> 8;
|
|
b = *bl++ >> 8;
|
|
}
|
|
else
|
|
{
|
|
r = *bl++ >> 7;
|
|
g = *bl++ >> 7;
|
|
b = *bl++ >> 7;
|
|
}
|
|
if (r > 255) r = 255; *dest++ = r;
|
|
if (g > 255) g = 255; *dest++ = g;
|
|
if (b > 255) b = 255; *dest++ = b;
|
|
*dest++ = 255;
|
|
}
|
|
}
|
|
break;
|
|
case GL_BGRA:
|
|
stride -= smax * 4;
|
|
bl = blocklights;
|
|
for (i=0 ; i<tmax ; i++, dest += stride)
|
|
{
|
|
for (j=0 ; j<smax ; j++)
|
|
{
|
|
if (gl_overbright.value)
|
|
{
|
|
r = *bl++ >> 8;
|
|
g = *bl++ >> 8;
|
|
b = *bl++ >> 8;
|
|
}
|
|
else
|
|
{
|
|
r = *bl++ >> 7;
|
|
g = *bl++ >> 7;
|
|
b = *bl++ >> 7;
|
|
}
|
|
if (b > 255) b = 255; *dest++ = b;
|
|
if (g > 255) g = 255; *dest++ = g;
|
|
if (r > 255) r = 255; *dest++ = r;
|
|
*dest++ = 255;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Sys_Error ("R_BuildLightMap: bad lightmap format");
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
R_UploadLightmap -- johnfitz -- uploads the modified lightmap to opengl if necessary
|
|
|
|
assumes lightmap texture is already bound
|
|
===============
|
|
*/
|
|
static void R_UploadLightmap(int lmap)
|
|
{
|
|
glRect_t *theRect;
|
|
|
|
if (!lightmap_modified[lmap])
|
|
return;
|
|
|
|
lightmap_modified[lmap] = false;
|
|
|
|
theRect = &lightmap_rectchange[lmap];
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, BLOCK_WIDTH, theRect->h, gl_lightmap_format,
|
|
GL_UNSIGNED_BYTE, lightmaps+(lmap* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = BLOCK_WIDTH;
|
|
theRect->t = BLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
|
|
rs_dynamiclightmaps++;
|
|
}
|
|
|
|
void R_UploadLightmaps (void)
|
|
{
|
|
int lmap;
|
|
|
|
for (lmap = 0; lmap < MAX_LIGHTMAPS; lmap++)
|
|
{
|
|
if (!lightmap_modified[lmap])
|
|
continue;
|
|
|
|
GL_Bind (lightmap_textures[lmap]);
|
|
R_UploadLightmap(lmap);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
R_RebuildAllLightmaps -- johnfitz -- called when gl_overbright gets toggled
|
|
================
|
|
*/
|
|
void R_RebuildAllLightmaps (void)
|
|
{
|
|
int i, j;
|
|
qmodel_t *mod;
|
|
msurface_t *fa;
|
|
byte *base;
|
|
|
|
if (!cl.worldmodel) // is this the correct test?
|
|
return;
|
|
|
|
//for each surface in each model, rebuild lightmap with new scale
|
|
for (i=1; i<MAX_MODELS; i++)
|
|
{
|
|
if (!(mod = cl.model_precache[i]))
|
|
continue;
|
|
fa = &mod->surfaces[mod->firstmodelsurface];
|
|
for (j=0; j<mod->nummodelsurfaces; j++, fa++)
|
|
{
|
|
if (fa->flags & SURF_DRAWTILED)
|
|
continue;
|
|
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);
|
|
}
|
|
}
|
|
|
|
//for each lightmap, upload it
|
|
for (i=0; i<MAX_LIGHTMAPS; i++)
|
|
{
|
|
if (!allocated[i][0])
|
|
break;
|
|
GL_Bind (lightmap_textures[i]);
|
|
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, BLOCK_WIDTH, BLOCK_HEIGHT, gl_lightmap_format,
|
|
GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
|
|
}
|
|
}
|