mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-30 12:40:42 +00:00
Split lightmaps off from surface drawing.
This commit is contained in:
parent
5f65a53e81
commit
85c7e43aef
7 changed files with 700 additions and 592 deletions
|
@ -1,5 +1,6 @@
|
||||||
AUTOMAKE_OPTIONS = foreign
|
AUTOMAKE_OPTIONS = foreign
|
||||||
includedir = $(prefix)/include/QF/GL
|
includedir = $(prefix)/include/QF/GL
|
||||||
include_HEADERS = defines.h extensions.h funcs.h qf_explosions.h \
|
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_funcs_list.h qf_lightmap.h qf_noisetextures.h qf_rlight.h \
|
||||||
qf_screen.h qf_sky.h qf_textures.h qf_vid.h types.h
|
qf_rmain.h qf_rsurf.h qf_screen.h qf_sky.h qf_textures.h qf_vid.h \
|
||||||
|
types.h
|
||||||
|
|
50
include/QF/GL/qf_lightmap.h
Normal file
50
include/QF/GL/qf_lightmap.h
Normal file
|
@ -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
|
|
@ -32,11 +32,11 @@
|
||||||
extern int skytexturenum; // index in cl.loadmodel, not gl texture object
|
extern int skytexturenum; // index in cl.loadmodel, not gl texture object
|
||||||
extern int mirrortexturenum; // quake texturenum, not gltexturenum
|
extern int mirrortexturenum; // quake texturenum, not gltexturenum
|
||||||
|
|
||||||
|
void gl_lightmap_init (void);
|
||||||
void GL_BuildLightmaps (struct model_s **models, int num_models);
|
void GL_BuildLightmaps (struct model_s **models, int num_models);
|
||||||
|
|
||||||
void R_DrawBrushModel (struct entity_s *e);
|
void R_DrawBrushModel (struct entity_s *e);
|
||||||
void R_DrawWorld (void);
|
void R_DrawWorld (void);
|
||||||
void R_RenderBrushPoly (msurface_t *fa);
|
void R_RenderBrushPoly (msurface_t *fa);
|
||||||
|
|
||||||
void glrsurf_init (void);
|
|
||||||
|
|
||||||
#endif // __QF_GL_rsurf_h
|
#endif // __QF_GL_rsurf_h
|
||||||
|
|
|
@ -10,7 +10,7 @@ endif
|
||||||
|
|
||||||
gl_src = \
|
gl_src = \
|
||||||
gl_draw.c gl_dyn_lights.c gl_dyn_part.c gl_dyn_textures.c \
|
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_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
|
gl_sky_clip.c gl_textures.c gl_warp.c noisetextures.c
|
||||||
|
|
||||||
|
|
|
@ -353,9 +353,9 @@ Draw_Init (void)
|
||||||
// get the other pics we need
|
// get the other pics we need
|
||||||
draw_backtile = Draw_PicFromWad ("backtile");
|
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 ();
|
glrmain_init ();
|
||||||
glrsurf_init ();
|
gl_lightmap_init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CELL_SIZE 0.0625
|
#define CELL_SIZE 0.0625
|
||||||
|
|
635
libs/video/renderer/gl/gl_lightmap.c
Normal file
635
libs/video/renderer/gl/gl_lightmap.c
Normal file
|
@ -0,0 +1,635 @@
|
||||||
|
/*
|
||||||
|
gl_lightmap.c
|
||||||
|
|
||||||
|
surface-related refresh code
|
||||||
|
|
||||||
|
Copyright (C) 1996-1997 Id Software, Inc.
|
||||||
|
Copyright (C) 2000 Joseph Carter <knghtbrd@debian.org>
|
||||||
|
|
||||||
|
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 <string.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_STRINGS_H
|
||||||
|
# include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
}
|
|
@ -46,6 +46,7 @@ static const char rcsid[] =
|
||||||
#include "QF/sys.h"
|
#include "QF/sys.h"
|
||||||
#include "QF/GL/defines.h"
|
#include "QF/GL/defines.h"
|
||||||
#include "QF/GL/funcs.h"
|
#include "QF/GL/funcs.h"
|
||||||
|
#include "QF/GL/qf_lightmap.h"
|
||||||
#include "QF/GL/qf_rmain.h"
|
#include "QF/GL/qf_rmain.h"
|
||||||
#include "QF/GL/qf_sky.h"
|
#include "QF/GL/qf_sky.h"
|
||||||
#include "QF/GL/qf_textures.h"
|
#include "QF/GL/qf_textures.h"
|
||||||
|
@ -56,36 +57,9 @@ static const char rcsid[] =
|
||||||
#include "r_local.h"
|
#include "r_local.h"
|
||||||
#include "r_shared.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;
|
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];
|
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 = NULL;
|
||||||
msurface_t **waterchain_tail = &waterchain;
|
msurface_t **waterchain_tail = &waterchain;
|
||||||
|
@ -111,348 +85,13 @@ msurface_t **sky_chain_tail;
|
||||||
# define CHAIN_SURF CHAIN_SURF_B2F
|
# define CHAIN_SURF CHAIN_SURF_B2F
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void (*R_AddDynamicLights) (msurface_t *surf);
|
extern int lightmap_textures;
|
||||||
void (*R_BuildLightMap) (msurface_t *surf);
|
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
|
R_TextureAnimation
|
||||||
|
@ -486,33 +125,6 @@ R_TextureAnimation (msurface_t *surf)
|
||||||
|
|
||||||
// BRUSH MODELS ===============================================================
|
// 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
|
#if 0
|
||||||
static void
|
static void
|
||||||
R_DrawMultitexturePoly (msurface_t *s)
|
R_DrawMultitexturePoly (msurface_t *s)
|
||||||
|
@ -575,44 +187,6 @@ R_DrawMultitexturePoly (msurface_t *s)
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
static void
|
||||||
R_RenderFullbrights (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;
|
int nColinElim;
|
||||||
model_t *currentmodel;
|
model_t *currentmodel;
|
||||||
mvertex_t *r_pcurrentvertbase;
|
mvertex_t *r_pcurrentvertbase;
|
||||||
|
|
||||||
static void
|
void
|
||||||
BuildSurfaceDisplayList (msurface_t *fa)
|
BuildSurfaceDisplayList (msurface_t *fa)
|
||||||
{
|
{
|
||||||
float s, t;
|
float s, t;
|
||||||
|
@ -1192,111 +722,3 @@ BuildSurfaceDisplayList (msurface_t *fa)
|
||||||
}
|
}
|
||||||
poly->numverts = lnumverts;
|
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
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue