mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +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
|
||||
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
|
||||
|
|
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 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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
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/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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue