diff --git a/include/QF/GL/Makefile.am b/include/QF/GL/Makefile.am index 37fe4c576..6b958f606 100644 --- a/include/QF/GL/Makefile.am +++ b/include/QF/GL/Makefile.am @@ -1,5 +1,6 @@ AUTOMAKE_OPTIONS = foreign includedir = $(prefix)/include/QF/GL include_HEADERS = defines.h extensions.h funcs.h qf_explosions.h \ - qf_funcs_list.h qf_noisetextures.h qf_rlight.h qf_rmain.h qf_rsurf.h \ - qf_screen.h qf_sky.h qf_textures.h qf_vid.h types.h + qf_funcs_list.h qf_lightmap.h qf_noisetextures.h qf_rlight.h \ + qf_rmain.h qf_rsurf.h qf_screen.h qf_sky.h qf_textures.h qf_vid.h \ + types.h diff --git a/include/QF/GL/qf_lightmap.h b/include/QF/GL/qf_lightmap.h new file mode 100644 index 000000000..a0f6541b8 --- /dev/null +++ b/include/QF/GL/qf_lightmap.h @@ -0,0 +1,50 @@ +/* + gl_lightmap.h + + GL lightmap stuff from the renderer. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifndef __QF_GL_lightmap_h +#define __QF_GL_lightmap_h + +// LordHavoc: since lightmaps are now allocated only as needed, allow a ridiculous number :) +#define MAX_LIGHTMAPS 1024 +#define BLOCK_WIDTH 128 +#define BLOCK_HEIGHT 128 + +typedef struct glRect_s { + unsigned short l, t, w, h; +} glRect_t; + +extern model_t *currentmodel; +extern mvertex_t *r_pcurrentvertbase; + +void BuildSurfaceDisplayList (msurface_t *fa); +void gl_lightmap_init (void); +void GL_BuildLightmaps (struct model_s **models, int num_models); +void R_BlendLightmaps (void); +extern void (*R_BuildLightMap) (msurface_t *surf); + +#endif // __QF_GL_lightmap_h diff --git a/include/QF/GL/qf_rsurf.h b/include/QF/GL/qf_rsurf.h index bf5aaee30..ba756c679 100644 --- a/include/QF/GL/qf_rsurf.h +++ b/include/QF/GL/qf_rsurf.h @@ -32,11 +32,11 @@ extern int skytexturenum; // index in cl.loadmodel, not gl texture object extern int mirrortexturenum; // quake texturenum, not gltexturenum +void gl_lightmap_init (void); void GL_BuildLightmaps (struct model_s **models, int num_models); + void R_DrawBrushModel (struct entity_s *e); void R_DrawWorld (void); void R_RenderBrushPoly (msurface_t *fa); -void glrsurf_init (void); - #endif // __QF_GL_rsurf_h diff --git a/libs/video/renderer/gl/Makefile.am b/libs/video/renderer/gl/Makefile.am index a247a43d2..56a7c35ab 100644 --- a/libs/video/renderer/gl/Makefile.am +++ b/libs/video/renderer/gl/Makefile.am @@ -10,7 +10,7 @@ endif gl_src = \ gl_draw.c gl_dyn_lights.c gl_dyn_part.c gl_dyn_textures.c \ - gl_graph.c gl_mod_alias.c gl_mod_sprite.c \ + gl_graph.c gl_lightmap.c gl_mod_alias.c gl_mod_sprite.c \ gl_rmain.c gl_rmisc.c gl_rsurf.c gl_screen.c gl_skin.c gl_sky.c \ gl_sky_clip.c gl_textures.c gl_warp.c noisetextures.c diff --git a/libs/video/renderer/gl/gl_draw.c b/libs/video/renderer/gl/gl_draw.c index 3b5b7ebae..5fa27e889 100644 --- a/libs/video/renderer/gl/gl_draw.c +++ b/libs/video/renderer/gl/gl_draw.c @@ -353,9 +353,9 @@ Draw_Init (void) // get the other pics we need draw_backtile = Draw_PicFromWad ("backtile"); - // LordHavoc: call init code for other GL renderer modules; + // LordHavoc: call init code for other GL renderer modules glrmain_init (); - glrsurf_init (); + gl_lightmap_init (); } #define CELL_SIZE 0.0625 diff --git a/libs/video/renderer/gl/gl_lightmap.c b/libs/video/renderer/gl/gl_lightmap.c new file mode 100644 index 000000000..3e7b662f8 --- /dev/null +++ b/libs/video/renderer/gl/gl_lightmap.c @@ -0,0 +1,635 @@ +/* + gl_lightmap.c + + surface-related refresh code + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2000 Joseph Carter + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +static const char rcsid[] = + "$Id$"; + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +#include "QF/cvar.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/GL/defines.h" +#include "QF/GL/funcs.h" +#include "QF/GL/qf_lightmap.h" +#include "QF/GL/qf_rmain.h" +#include "QF/GL/qf_sky.h" +#include "QF/GL/qf_textures.h" +#include "QF/GL/qf_vid.h" + +#include "compat.h" +#include "r_cvar.h" +#include "r_local.h" +#include "r_shared.h" + +int active_lightmaps; +int dlightdivtable[8192]; +int gl_internalformat; // 1 or 3 +int lightmap_bytes; // 1, 3, or 4 +int lightmap_textures; + +// keep lightmap texture data in main memory so texsubimage can update properly +// LordHavoc: changed to be allocated at runtime (typically lower memory usage) +byte *lightmaps[MAX_LIGHTMAPS]; + +unsigned int blocklights[18 * 18 * 3]; +int allocated[MAX_LIGHTMAPS][BLOCK_WIDTH]; + +glpoly_t *lightmap_modified[MAX_GLTEXTURES]; +glpoly_t *lightmap_polys[MAX_LIGHTMAPS]; +glRect_t lightmap_rectchange[MAX_LIGHTMAPS]; + +void (*R_AddDynamicLights) (msurface_t *surf); +void (*R_BuildLightMap) (msurface_t *surf); + + +void +gl_lightmap_init (void) +{ + int s; + + memset (&lightmaps, 0, sizeof (lightmaps)); + dlightdivtable[0] = 1048576 >> 7; + for (s = 1; s < 8192; s++) + dlightdivtable[s] = 1048576 / (s << 7); +} + +static void +R_RecursiveLightUpdate (mnode_t *node) +{ + int c; + msurface_t *surf; + + if (node->children[0]->contents >= 0) + R_RecursiveLightUpdate (node->children[0]); + if (node->children[1]->contents >= 0) + R_RecursiveLightUpdate (node->children[1]); + if ((c = node->numsurfaces)) + for (surf = r_worldentity.model->surfaces + node->firstsurface; c; + c--, surf++) + surf->cached_dlight = true; +} + +static void +R_AddDynamicLights_1 (msurface_t *surf) +{ + float dist; + int lnum, maxdist, maxdist2, maxdist3, smax, smax_bytes, tmax, + grey; + unsigned int td, i, j, s, t; + unsigned int sdtable[18]; + unsigned int *bl; + vec3_t impact, local; + + smax = (surf->extents[0] >> 4) + 1; + smax_bytes = smax * gl_internalformat; + tmax = (surf->extents[1] >> 4) + 1; + + for (lnum = 0; lnum < r_maxdlights; lnum++) { + if (!(surf->dlightbits & (1 << lnum))) + continue; // not lit by this light + + VectorSubtract (r_dlights[lnum].origin, currententity->origin, local); + dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; + VectorMA (r_dlights[lnum].origin, -dist, surf->plane->normal, impact); + + i = DotProduct (impact, surf->texinfo->vecs[0]) + + surf->texinfo->vecs[0][3] - surf->texturemins[0]; + + // reduce calculations + t = dist * dist; + for (s = 0; s < smax; s++, i -= 16) + sdtable[s] = i * i + t; + + i = DotProduct (impact, surf->texinfo->vecs[1]) + + surf->texinfo->vecs[1][3] - surf->texturemins[1]; + + // for comparisons to minimum acceptable light + maxdist = (int) ((r_dlights[lnum].radius * r_dlights[lnum].radius) * + 0.75); + + // clamp radius to avoid exceeding 8192 entry division table + if (maxdist > 1048576) + maxdist = 1048576; + maxdist3 = maxdist - t; + + // convert to 8.8 blocklights format + grey = (r_dlights[lnum].color[0] + r_dlights[lnum].color[1] + + r_dlights[lnum].color[2]) * maxdist / 3.0; + bl = blocklights; + for (t = 0; t < tmax; t++, i -= 16) { + td = i * i; + if (td < maxdist3) { // ensure part is visible on this line + maxdist2 = maxdist - td; + for (s = 0; s < smax; s++) { + if (sdtable[s] < maxdist2) { + j = dlightdivtable[(sdtable[s] + td) >> 7]; + *bl++ += (grey * j) >> 7; + } else + bl++; + } + } else + bl += smax_bytes; // skip line + } + } +} + +static void +R_AddDynamicLights_3 (msurface_t *surf) +{ + float dist; + int lnum, maxdist, maxdist2, maxdist3, smax, smax_bytes, tmax, + red, green, blue; + unsigned int td, i, j, s, t; + unsigned int sdtable[18]; + unsigned int *bl; + vec3_t impact, local; + + smax = (surf->extents[0] >> 4) + 1; + smax_bytes = smax * gl_internalformat; + tmax = (surf->extents[1] >> 4) + 1; + + for (lnum = 0; lnum < r_maxdlights; lnum++) { + if (!(surf->dlightbits & (1 << lnum))) + continue; // not lit by this light + + VectorSubtract (r_dlights[lnum].origin, currententity->origin, local); + dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; + VectorMA (r_dlights[lnum].origin, -dist, surf->plane->normal, impact); + + i = DotProduct (impact, surf->texinfo->vecs[0]) + + surf->texinfo->vecs[0][3] - surf->texturemins[0]; + + // reduce calculations + t = dist * dist; + for (s = 0; s < smax; s++, i -= 16) + sdtable[s] = i * i + t; + + i = DotProduct (impact, surf->texinfo->vecs[1]) + + surf->texinfo->vecs[1][3] - surf->texturemins[1]; + + // for comparisons to minimum acceptable light + maxdist = (int) ((r_dlights[lnum].radius * r_dlights[lnum].radius) * + 0.75); + + // clamp radius to avoid exceeding 8192 entry division table + if (maxdist > 1048576) + maxdist = 1048576; + maxdist3 = maxdist - t; + + // convert to 8.8 blocklights format + red = r_dlights[lnum].color[0] * maxdist; + green = r_dlights[lnum].color[1] * maxdist; + blue = r_dlights[lnum].color[2] * maxdist; + bl = blocklights; + for (t = 0; t < tmax; t++, i -= 16) { + td = i * i; + if (td < maxdist3) { // ensure part is visible on this line + maxdist2 = maxdist - td; + for (s = 0; s < smax; s++) { + if (sdtable[s] < maxdist2) { + j = dlightdivtable[(sdtable[s] + td) >> 7]; + *bl++ += (red * j) >> 7; + *bl++ += (green * j) >> 7; + *bl++ += (blue * j) >> 7; + } else + bl += 3; + } + } else + bl += smax_bytes; // skip line + } + } +} + +static void +R_BuildLightMap_1 (msurface_t *surf) +{ + byte *dest; + int maps, size, smax, tmax, i, j, stride; + unsigned int scale; + unsigned int *bl; + + surf->cached_dlight = (surf->dlightframe == r_framecount); + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + size = smax * tmax * gl_internalformat; + + // set to full bright if no light data + if (!r_worldentity.model->lightdata) { + memset (&blocklights[0], 0xff, size * sizeof(int)); + goto store; + } + + // clear to no light + memset (&blocklights[0], 0, size * sizeof(int)); + + // add all the lightmaps + if (surf->samples) { + byte *lightmap; + + lightmap = surf->samples; + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; + maps++) { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + bl = blocklights; + for (i = 0; i < size; i++) { + *bl++ += *lightmap++ * scale; + } + } + } + // add all the dynamic lights + if (surf->dlightframe == r_framecount) + R_AddDynamicLights (surf); + + store: + // bound and shift + stride = (BLOCK_WIDTH - smax) * lightmap_bytes; + bl = blocklights; + + dest = lightmaps[surf->lightmaptexturenum] + + (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes; + for (i = 0; i < tmax; i++, dest += stride) { + for (j = 0; j < smax; j++) { + *dest++ = min (*bl >> 8, 255); + bl++; + } + } +} + +static void +R_BuildLightMap_3 (msurface_t *surf) +{ + byte *dest; + int maps, size, smax, tmax, i, j, stride; + unsigned int scale; + unsigned int *bl; + + surf->cached_dlight = (surf->dlightframe == r_framecount); + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + size = smax * tmax * gl_internalformat; + + // set to full bright if no light data + if (!r_worldentity.model->lightdata) { + memset (&blocklights[0], 0xff, size * sizeof(int)); + goto store; + } + + // clear to no light + memset (&blocklights[0], 0, size * sizeof(int)); + + // add all the lightmaps + if (surf->samples) { + byte *lightmap; + + lightmap = surf->samples; + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; + maps++) { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + bl = blocklights; + for (i = 0; i < size; i++) { + *bl++ += *lightmap++ * scale; + } + } + } + // add all the dynamic lights + if (surf->dlightframe == r_framecount) + R_AddDynamicLights (surf); + + store: + // bound and shift + stride = (BLOCK_WIDTH - smax) * lightmap_bytes; + bl = blocklights; + + dest = lightmaps[surf->lightmaptexturenum] + + (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes; + for (i = 0; i < tmax; i++, dest += stride) { + for (j = 0; j < smax; j++) { + *dest++ = min (*bl >> 8, 255); + bl++; + *dest++ = min (*bl >> 8, 255); + bl++; + *dest++ = min (*bl >> 8, 255); + bl++; + } + } +} + +static void +R_BuildLightMap_4 (msurface_t *surf) +{ + byte *dest; + int maps, size, smax, tmax, i, j, stride; + unsigned int scale; + unsigned int *bl; + + surf->cached_dlight = (surf->dlightframe == r_framecount); + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + size = smax * tmax * gl_internalformat; + + // set to full bright if no light data + if (!r_worldentity.model->lightdata) { + memset (&blocklights[0], 0xff, size * sizeof(int)); + goto store; + } + + // clear to no light + memset (&blocklights[0], 0, size * sizeof(int)); + + // add all the lightmaps + if (surf->samples) { + byte *lightmap; + + lightmap = surf->samples; + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; + maps++) { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + bl = blocklights; + for (i = 0; i < size; i++) { + *bl++ += *lightmap++ * scale; + } + } + } + // add all the dynamic lights + if (surf->dlightframe == r_framecount) + R_AddDynamicLights (surf); + + store: + // bound and shift + stride = (BLOCK_WIDTH - smax) * lightmap_bytes; + bl = blocklights; + + dest = lightmaps[surf->lightmaptexturenum] + + (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes; + for (i = 0; i < tmax; i++, dest += stride) { + for (j = 0; j < smax; j++) { + *dest++ = min (*bl >> 8, 255); + bl++; + *dest++ = min (*bl >> 8, 255); + bl++; + *dest++ = min (*bl >> 8, 255); + bl++; + dest++; // `*dest++ = 255;` for RGBA internal format + // instead of RGB + } + } +} + +// BRUSH MODELS =============================================================== + +static void +GL_UploadLightmap (int i) +{ + switch (gl_lightmap_subimage->int_val) { + case 2: + qfglTexSubImage2D (GL_TEXTURE_2D, 0, lightmap_rectchange[i].l, + lightmap_rectchange[i].t, lightmap_rectchange[i].w, + lightmap_rectchange[i].h, gl_lightmap_format, + GL_UNSIGNED_BYTE, lightmaps[i] + + (lightmap_rectchange[i].t * BLOCK_WIDTH + + lightmap_rectchange[i].l) * lightmap_bytes); + break; + case 1: + qfglTexSubImage2D (GL_TEXTURE_2D, 0, 0, lightmap_rectchange[i].t, + BLOCK_WIDTH, lightmap_rectchange[i].h, + gl_lightmap_format, GL_UNSIGNED_BYTE, + lightmaps[i] + (lightmap_rectchange[i].t * + BLOCK_WIDTH) * lightmap_bytes); + break; + default: + case 0: + qfglTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, BLOCK_WIDTH, + BLOCK_HEIGHT, 0, gl_lightmap_format, GL_UNSIGNED_BYTE, + lightmaps[i]); + break; + } +} + +void +R_BlendLightmaps (void) +{ + float *v; + int i, j; + glpoly_t *p; + + qfglDepthMask (GL_FALSE); // don't bother writing Z + qfglBlendFunc (GL_DST_COLOR, GL_SRC_COLOR); + + for (i = 0; i < MAX_LIGHTMAPS; i++) { + p = lightmap_polys[i]; + if (!p) + continue; + qfglBindTexture (GL_TEXTURE_2D, lightmap_textures + i); + if (lightmap_modified[i]) { + GL_UploadLightmap (i); + lightmap_modified[i] = false; + } + for (; p; p = p->chain) { + qfglBegin (GL_POLYGON); + v = p->verts[0]; + for (j = 0; j < p->numverts; j++, v += VERTEXSIZE) { + qfglTexCoord2fv (&v[5]); + qfglVertex3fv (v); + } + qfglEnd (); + } + } + + // Return to normal blending --KB + qfglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + qfglDepthMask (GL_TRUE); // back to normal Z buffering +} + +// LIGHTMAP ALLOCATION ======================================================== + +// returns a texture number and the position inside it +static int +AllocBlock (int w, int h, int *x, int *y) +{ + int best, best2, texnum, i, j; + + 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; + + // LordHavoc: allocate lightmaps only as needed + if (!lightmaps[texnum]) + lightmaps[texnum] = calloc (BLOCK_WIDTH * BLOCK_HEIGHT, + lightmap_bytes); + for (i = 0; i < w; i++) + allocated[texnum][*x + i] = best + h; + + return texnum; + } + + Sys_Error ("AllocBlock: full"); + return 0; +} + +static void +GL_CreateSurfaceLightmap (msurface_t *surf) +{ + int smax, tmax; + + 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); + R_BuildLightMap (surf); +} + +/* + GL_BuildLightmaps + + Builds the lightmap texture with all the surfaces from all brush models +*/ +void +GL_BuildLightmaps (model_t **models, int num_models) +{ + 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; + } + + switch (r_lightmap_components->int_val) { + case 1: + gl_internalformat = 1; + gl_lightmap_format = GL_LUMINANCE; + lightmap_bytes = 1; + R_AddDynamicLights = R_AddDynamicLights_1; + R_BuildLightMap = R_BuildLightMap_1; + break; + case 3: + gl_internalformat = 3; + gl_lightmap_format = GL_RGB; + lightmap_bytes = 3; + R_AddDynamicLights = R_AddDynamicLights_3; + R_BuildLightMap = R_BuildLightMap_3; + break; + case 4: + default: + gl_internalformat = 3; + gl_lightmap_format = GL_RGBA; + lightmap_bytes = 4; + R_AddDynamicLights = R_AddDynamicLights_3; + R_BuildLightMap = R_BuildLightMap_4; + break; + } + + for (j = 1; j < num_models; j++) { + m = models[j]; + if (!m) + break; + if (m->name[0] == '*') + continue; + r_pcurrentvertbase = m->vertexes; + currentmodel = m; + for (i = 0; i < m->numsurfaces; i++) { + if (m->surfaces[i].flags & SURF_DRAWTURB) + continue; + if (gl_sky_divide->int_val && (m->surfaces[i].flags & + SURF_DRAWSKY)) + continue; + GL_CreateSurfaceLightmap (m->surfaces + i); + BuildSurfaceDisplayList (m->surfaces + i); + } + } + +#if 0 + if (gl_mtex_active) + qglActiveTexture (gl_mtex_enum + 1); +#endif + + // 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; + qfglBindTexture (GL_TEXTURE_2D, lightmap_textures + i); + qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qfglTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes, BLOCK_WIDTH, + BLOCK_HEIGHT, 0, gl_lightmap_format, + GL_UNSIGNED_BYTE, lightmaps[i]); + } + +#if 0 + if (gl_mtex_active) + qglActiveTexture (gl_mtex_enum + 0); +#endif +} diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index b934cf310..5fc37fb26 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -46,6 +46,7 @@ static const char rcsid[] = #include "QF/sys.h" #include "QF/GL/defines.h" #include "QF/GL/funcs.h" +#include "QF/GL/qf_lightmap.h" #include "QF/GL/qf_rmain.h" #include "QF/GL/qf_sky.h" #include "QF/GL/qf_textures.h" @@ -56,36 +57,9 @@ static const char rcsid[] = #include "r_local.h" #include "r_shared.h" -void EmitWaterPolys (msurface_t *fa); - -int active_lightmaps; -int dlightdivtable[8192]; -int gl_internalformat; // 1 or 3 -int lightmap_bytes; // 1, 3, or 4 -int lightmap_textures; int skytexturenum; -// LordHavoc: since lightmaps are now allocated only as needed, allow a ridiculous number :) -#define MAX_LIGHTMAPS 1024 -#define BLOCK_WIDTH 128 // 256 -#define BLOCK_HEIGHT 128 // 256 - -// keep lightmap texture data in main memory so texsubimage can update properly -// LordHavoc: changed to be allocated at runtime (typically lower memory usage) -byte *lightmaps[MAX_LIGHTMAPS]; - -// unsigned int blocklights[BLOCK_WIDTH * BLOCK_HEIGHT * 3]; -unsigned int blocklights[18 * 18 * 3]; -int allocated[MAX_LIGHTMAPS][BLOCK_WIDTH]; - -typedef struct glRect_s { - unsigned short l, t, w, h; -} glRect_t; - glpoly_t *fullbright_polys[MAX_GLTEXTURES]; -qboolean lightmap_modified[MAX_LIGHTMAPS]; -glpoly_t *lightmap_polys[MAX_LIGHTMAPS]; -glRect_t lightmap_rectchange[MAX_LIGHTMAPS]; msurface_t *waterchain = NULL; msurface_t **waterchain_tail = &waterchain; @@ -111,348 +85,13 @@ msurface_t **sky_chain_tail; # define CHAIN_SURF CHAIN_SURF_B2F #endif -void (*R_AddDynamicLights) (msurface_t *surf); -void (*R_BuildLightMap) (msurface_t *surf); +extern int lightmap_textures; +extern qboolean lightmap_modified[MAX_LIGHTMAPS]; +extern glpoly_t *lightmap_polys[MAX_LIGHTMAPS]; +extern glRect_t lightmap_rectchange[MAX_LIGHTMAPS]; +void EmitWaterPolys (msurface_t *fa); -// LordHavoc: place for gl_rsurf setup code -void -glrsurf_init (void) -{ - int s; - - memset (&lightmaps, 0, sizeof (lightmaps)); - dlightdivtable[0] = 1048576 >> 7; - for (s = 1; s < 8192; s++) - dlightdivtable[s] = 1048576 / (s << 7); -} - -static void -R_RecursiveLightUpdate (mnode_t *node) -{ - int c; - msurface_t *surf; - - if (node->children[0]->contents >= 0) - R_RecursiveLightUpdate (node->children[0]); - if (node->children[1]->contents >= 0) - R_RecursiveLightUpdate (node->children[1]); - if ((c = node->numsurfaces)) - for (surf = r_worldentity.model->surfaces + node->firstsurface; c; - c--, surf++) surf->cached_dlight = true; -} - -static void -R_AddDynamicLights_1 (msurface_t *surf) -{ - float dist; - int lnum, maxdist, maxdist2, maxdist3, smax, smax_bytes, tmax, - grey; - unsigned int td, i, j, s, t; - unsigned int sdtable[18]; - unsigned int *bl; - vec3_t impact, local; - - smax = (surf->extents[0] >> 4) + 1; - smax_bytes = smax * gl_internalformat; - tmax = (surf->extents[1] >> 4) + 1; - - for (lnum = 0; lnum < r_maxdlights; lnum++) { - if (!(surf->dlightbits & (1 << lnum))) - continue; // not lit by this light - - VectorSubtract (r_dlights[lnum].origin, currententity->origin, local); - dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; - VectorMA (r_dlights[lnum].origin, -dist, surf->plane->normal, impact); - - i = DotProduct (impact, surf->texinfo->vecs[0]) + - surf->texinfo->vecs[0][3] - surf->texturemins[0]; - - // reduce calculations - t = dist * dist; - for (s = 0; s < smax; s++, i -= 16) - sdtable[s] = i * i + t; - - i = DotProduct (impact, surf->texinfo->vecs[1]) + - surf->texinfo->vecs[1][3] - surf->texturemins[1]; - - // for comparisons to minimum acceptable light - maxdist = (int) ((r_dlights[lnum].radius * r_dlights[lnum].radius) * - 0.75); - - // clamp radius to avoid exceeding 8192 entry division table - if (maxdist > 1048576) - maxdist = 1048576; - maxdist3 = maxdist - t; - - // convert to 8.8 blocklights format - grey = (r_dlights[lnum].color[0] + r_dlights[lnum].color[1] + - r_dlights[lnum].color[2]) * maxdist / 3.0; - bl = blocklights; - for (t = 0; t < tmax; t++, i -= 16) { - td = i * i; - if (td < maxdist3) { // ensure part is visible on this line - maxdist2 = maxdist - td; - for (s = 0; s < smax; s++) { - if (sdtable[s] < maxdist2) { - j = dlightdivtable[(sdtable[s] + td) >> 7]; - *bl++ += (grey * j) >> 7; - } else - bl++; - } - } else - bl += smax_bytes; // skip line - } - } -} - -static void -R_AddDynamicLights_3 (msurface_t *surf) -{ - float dist; - int lnum, maxdist, maxdist2, maxdist3, smax, smax_bytes, tmax, - red, green, blue; - unsigned int td, i, j, s, t; - unsigned int sdtable[18]; - unsigned int *bl; - vec3_t impact, local; - - smax = (surf->extents[0] >> 4) + 1; - smax_bytes = smax * gl_internalformat; - tmax = (surf->extents[1] >> 4) + 1; - - for (lnum = 0; lnum < r_maxdlights; lnum++) { - if (!(surf->dlightbits & (1 << lnum))) - continue; // not lit by this light - - VectorSubtract (r_dlights[lnum].origin, currententity->origin, local); - dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; - VectorMA (r_dlights[lnum].origin, -dist, surf->plane->normal, impact); - - i = DotProduct (impact, surf->texinfo->vecs[0]) + - surf->texinfo->vecs[0][3] - surf->texturemins[0]; - - // reduce calculations - t = dist * dist; - for (s = 0; s < smax; s++, i -= 16) - sdtable[s] = i * i + t; - - i = DotProduct (impact, surf->texinfo->vecs[1]) + - surf->texinfo->vecs[1][3] - surf->texturemins[1]; - - // for comparisons to minimum acceptable light - maxdist = (int) ((r_dlights[lnum].radius * r_dlights[lnum].radius) * - 0.75); - - // clamp radius to avoid exceeding 8192 entry division table - if (maxdist > 1048576) - maxdist = 1048576; - maxdist3 = maxdist - t; - - // convert to 8.8 blocklights format - red = r_dlights[lnum].color[0] * maxdist; - green = r_dlights[lnum].color[1] * maxdist; - blue = r_dlights[lnum].color[2] * maxdist; - bl = blocklights; - for (t = 0; t < tmax; t++, i -= 16) { - td = i * i; - if (td < maxdist3) { // ensure part is visible on this line - maxdist2 = maxdist - td; - for (s = 0; s < smax; s++) { - if (sdtable[s] < maxdist2) { - j = dlightdivtable[(sdtable[s] + td) >> 7]; - *bl++ += (red * j) >> 7; - *bl++ += (green * j) >> 7; - *bl++ += (blue * j) >> 7; - } else - bl += 3; - } - } else - bl += smax_bytes; // skip line - } - } -} - -static void -R_BuildLightMap_1 (msurface_t *surf) -{ - byte *dest; - int maps, size, smax, tmax, i, j, stride; - unsigned int scale; - unsigned int *bl; - - surf->cached_dlight = (surf->dlightframe == r_framecount); - - smax = (surf->extents[0] >> 4) + 1; - tmax = (surf->extents[1] >> 4) + 1; - size = smax * tmax * gl_internalformat; - - // set to full bright if no light data - if (!r_worldentity.model->lightdata) { - memset (&blocklights[0], 0xff, size * sizeof(int)); - goto store; - } - - // clear to no light - memset (&blocklights[0], 0, size * sizeof(int)); - - // add all the lightmaps - if (surf->samples) { - byte *lightmap; - - lightmap = surf->samples; - for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; - maps++) { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction - bl = blocklights; - for (i = 0; i < size; i++) { - *bl++ += *lightmap++ * scale; - } - } - } - // add all the dynamic lights - if (surf->dlightframe == r_framecount) - R_AddDynamicLights (surf); - - store: - // bound and shift - stride = (BLOCK_WIDTH - smax) * lightmap_bytes; - bl = blocklights; - - dest = lightmaps[surf->lightmaptexturenum] - + (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes; - for (i = 0; i < tmax; i++, dest += stride) { - for (j = 0; j < smax; j++) { - *dest++ = min (*bl >> 8, 255); - bl++; - } - } -} - -static void -R_BuildLightMap_3 (msurface_t *surf) -{ - byte *dest; - int maps, size, smax, tmax, i, j, stride; - unsigned int scale; - unsigned int *bl; - - surf->cached_dlight = (surf->dlightframe == r_framecount); - - smax = (surf->extents[0] >> 4) + 1; - tmax = (surf->extents[1] >> 4) + 1; - size = smax * tmax * gl_internalformat; - - // set to full bright if no light data - if (!r_worldentity.model->lightdata) { - memset (&blocklights[0], 0xff, size * sizeof(int)); - goto store; - } - - // clear to no light - memset (&blocklights[0], 0, size * sizeof(int)); - - // add all the lightmaps - if (surf->samples) { - byte *lightmap; - - lightmap = surf->samples; - for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; - maps++) { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction - bl = blocklights; - for (i = 0; i < size; i++) { - *bl++ += *lightmap++ * scale; - } - } - } - // add all the dynamic lights - if (surf->dlightframe == r_framecount) - R_AddDynamicLights (surf); - - store: - // bound and shift - stride = (BLOCK_WIDTH - smax) * lightmap_bytes; - bl = blocklights; - - dest = lightmaps[surf->lightmaptexturenum] - + (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes; - for (i = 0; i < tmax; i++, dest += stride) { - for (j = 0; j < smax; j++) { - *dest++ = min (*bl >> 8, 255); - bl++; - *dest++ = min (*bl >> 8, 255); - bl++; - *dest++ = min (*bl >> 8, 255); - bl++; - } - } -} - -static void -R_BuildLightMap_4 (msurface_t *surf) -{ - byte *dest; - int maps, size, smax, tmax, i, j, stride; - unsigned int scale; - unsigned int *bl; - - surf->cached_dlight = (surf->dlightframe == r_framecount); - - smax = (surf->extents[0] >> 4) + 1; - tmax = (surf->extents[1] >> 4) + 1; - size = smax * tmax * gl_internalformat; - - // set to full bright if no light data - if (!r_worldentity.model->lightdata) { - memset (&blocklights[0], 0xff, size * sizeof(int)); - goto store; - } - - // clear to no light - memset (&blocklights[0], 0, size * sizeof(int)); - - // add all the lightmaps - if (surf->samples) { - byte *lightmap; - - lightmap = surf->samples; - for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; - maps++) { - scale = d_lightstylevalue[surf->styles[maps]]; - surf->cached_light[maps] = scale; // 8.8 fraction - bl = blocklights; - for (i = 0; i < size; i++) { - *bl++ += *lightmap++ * scale; - } - } - } - // add all the dynamic lights - if (surf->dlightframe == r_framecount) - R_AddDynamicLights (surf); - - store: - // bound and shift - stride = (BLOCK_WIDTH - smax) * lightmap_bytes; - bl = blocklights; - - dest = lightmaps[surf->lightmaptexturenum] - + (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes; - for (i = 0; i < tmax; i++, dest += stride) { - for (j = 0; j < smax; j++) { - *dest++ = min (*bl >> 8, 255); - bl++; - *dest++ = min (*bl >> 8, 255); - bl++; - *dest++ = min (*bl >> 8, 255); - bl++; - dest++; // `*dest++ = 255;` for RGBA internal format - // instead of RGB - } - } -} /* R_TextureAnimation @@ -486,33 +125,6 @@ R_TextureAnimation (msurface_t *surf) // BRUSH MODELS =============================================================== -static void -GL_UploadLightmap (int i, int x, int y, int w, int h) -{ -/* qfglTexSubImage2D (GL_TEXTURE_2D, 0, 0, y, BLOCK_WIDTH, h, - gl_lightmap_format, GL_UNSIGNED_BYTE, - lightmaps[i] + (y * BLOCK_WIDTH) * lightmap_bytes); -*/ - switch (gl_lightmap_subimage->int_val) { - case 2: - qfglTexSubImage2D (GL_TEXTURE_2D, 0, x, y, w, h, - gl_lightmap_format, GL_UNSIGNED_BYTE, - lightmaps[i] + (y * BLOCK_WIDTH) * lightmap_bytes); - break; - case 1: - qfglTexSubImage2D (GL_TEXTURE_2D, 0, 0, y, BLOCK_WIDTH, h, - gl_lightmap_format, GL_UNSIGNED_BYTE, - lightmaps[i] + (y * BLOCK_WIDTH) * lightmap_bytes); - break; - default: - case 0: - qfglTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, BLOCK_WIDTH, - BLOCK_HEIGHT, 0, gl_lightmap_format, GL_UNSIGNED_BYTE, - lightmaps[i]); - break; - } -} - #if 0 static void R_DrawMultitexturePoly (msurface_t *s) @@ -575,44 +187,6 @@ R_DrawMultitexturePoly (msurface_t *s) } #endif -static void -R_BlendLightmaps (void) -{ - float *v; - int i, j; - glpoly_t *p; - - qfglDepthMask (GL_FALSE); // don't bother writing Z - qfglBlendFunc (GL_DST_COLOR, GL_SRC_COLOR); - - for (i = 0; i < MAX_LIGHTMAPS; i++) { - p = lightmap_polys[i]; - if (!p) - continue; - qfglBindTexture (GL_TEXTURE_2D, lightmap_textures + i); - if (lightmap_modified[i]) { - GL_UploadLightmap (i, lightmap_rectchange[i].l, - lightmap_rectchange[i].t, - lightmap_rectchange[i].w, - lightmap_rectchange[i].h); - lightmap_modified[i] = false; - } - for (; p; p = p->chain) { - qfglBegin (GL_POLYGON); - v = p->verts[0]; - for (j = 0; j < p->numverts; j++, v += VERTEXSIZE) { - qfglTexCoord2fv (&v[5]); - qfglVertex3fv (v); - } - qfglEnd (); - } - } - - // Return to normal blending --KB - qfglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - qfglDepthMask (GL_TRUE); // back to normal Z buffering -} - static void R_RenderFullbrights (void) { @@ -1048,55 +622,11 @@ R_MarkLeaves (void) } } -// LIGHTMAP ALLOCATION ======================================================== - -// returns a texture number and the position inside it -static int -AllocBlock (int w, int h, int *x, int *y) -{ - int best, best2, texnum, i, j; - - 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; - - // LordHavoc: allocate lightmaps only as needed - if (!lightmaps[texnum]) - lightmaps[texnum] = calloc (BLOCK_WIDTH * BLOCK_HEIGHT, - lightmap_bytes); - for (i = 0; i < w; i++) - allocated[texnum][*x + i] = best + h; - - return texnum; - } - - Sys_Error ("AllocBlock: full"); - return 0; -} - int nColinElim; model_t *currentmodel; mvertex_t *r_pcurrentvertbase; -static void +void BuildSurfaceDisplayList (msurface_t *fa) { float s, t; @@ -1192,111 +722,3 @@ BuildSurfaceDisplayList (msurface_t *fa) } poly->numverts = lnumverts; } - -static void -GL_CreateSurfaceLightmap (msurface_t *surf) -{ - int smax, tmax; - - 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); - R_BuildLightMap (surf); -} - -/* - GL_BuildLightmaps - - Builds the lightmap texture with all the surfaces from all brush models -*/ -void -GL_BuildLightmaps (model_t **models, int num_models) -{ - 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; - } - - switch (r_lightmap_components->int_val) { - case 1: - gl_internalformat = 1; - gl_lightmap_format = GL_LUMINANCE; - lightmap_bytes = 1; - R_AddDynamicLights = R_AddDynamicLights_1; - R_BuildLightMap = R_BuildLightMap_1; - break; - case 3: - gl_internalformat = 3; - gl_lightmap_format = GL_RGB; - lightmap_bytes = 3; - R_AddDynamicLights = R_AddDynamicLights_3; - R_BuildLightMap = R_BuildLightMap_3; - break; - case 4: - default: - gl_internalformat = 3; - gl_lightmap_format = GL_RGBA; - lightmap_bytes = 4; - R_AddDynamicLights = R_AddDynamicLights_3; - R_BuildLightMap = R_BuildLightMap_4; - break; - } - - for (j = 1; j < num_models; j++) { - m = models[j]; - if (!m) - break; - if (m->name[0] == '*') - continue; - r_pcurrentvertbase = m->vertexes; - currentmodel = m; - for (i = 0; i < m->numsurfaces; i++) { - if (m->surfaces[i].flags & SURF_DRAWTURB) - continue; - if (gl_sky_divide->int_val && (m->surfaces[i].flags & - SURF_DRAWSKY)) - continue; - GL_CreateSurfaceLightmap (m->surfaces + i); - BuildSurfaceDisplayList (m->surfaces + i); - } - } - -#if 0 - if (gl_mtex_active) - qglActiveTexture (gl_mtex_enum + 1); -#endif - - // 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; - qfglBindTexture (GL_TEXTURE_2D, lightmap_textures + i); - qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qfglTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - qfglTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes, BLOCK_WIDTH, - BLOCK_HEIGHT, 0, gl_lightmap_format, - GL_UNSIGNED_BYTE, lightmaps[i]); - } - -#if 0 - if (gl_mtex_active) - qglActiveTexture (gl_mtex_enum + 0); -#endif -}