quakeforge/libs/video/renderer/glsl/glsl_lightmap.c

260 lines
6.3 KiB
C

/*
glsl_lightmap.c
GLSL lightmaps
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 2000 Joseph Carter <knghtbrd@debian.org>
Copyright (C) 2012 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2012/1/6
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
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#define NH_DEFINE
#include "namehack.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include "QF/render.h"
#include "QF/sys.h"
#include "QF/GLSL/defines.h"
#include "QF/GLSL/funcs.h"
#include "QF/GLSL/qf_lightmap.h"
#include "QF/GLSL/qf_textures.h"
#include "QF/GLSL/qf_vid.h"
#include "r_internal.h"
#define BLOCK_SIZE (BLOCK_WIDTH * BLOCK_HEIGHT)
static scrap_t *light_scrap;
static byte *light_data;
static unsigned *blocklights;
static int bl_extents[2];
void (*glsl_R_BuildLightMap) (msurface_t *surf);
static void
R_AddDynamicLights_1 (msurface_t *surf)
{
unsigned lnum;
int sd, td;
float dist, rad, minlight;
vec3_t impact, local, lightorigin;
int s, t;
int smax, tmax;
mtexinfo_t *tex;
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
tex = surf->texinfo;
for (lnum = 0; lnum < r_maxdlights; lnum++) {
if (!(surf->dlightbits & (1 << lnum)))
continue; // not lit by this light
VectorSubtract (r_dlights[lnum].origin, currententity->origin,
lightorigin);
rad = r_dlights[lnum].radius;
dist = DotProduct (lightorigin, surf->plane->normal)
- surf->plane->dist;
rad -= fabs (dist);
minlight = r_dlights[lnum].minlight;
if (rad < minlight)
continue;
minlight = rad - minlight;
VectorMultSub (lightorigin, dist, surf->plane->normal, impact);
local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
local[0] -= surf->texturemins[0];
local[1] -= surf->texturemins[1];
for (t = 0; t < tmax; t++) {
td = local[1] - t * 16;
if (td < 0)
td = -td;
for (s = 0; s < smax; s++) {
sd = local[0] - s * 16;
if (sd < 0)
sd = -sd;
if (sd > td)
dist = sd + (td >> 1);
else
dist = td + (sd >> 1);
if (dist < minlight)
blocklights[t * smax + s] += (rad - dist) * 256;
}
}
}
}
static void
R_BuildLightMap_1 (msurface_t *surf)
{
int smax, tmax, size;
unsigned scale;
int i, t;
byte *out;
// If we add dlights this frame, make sure they get removed next frame
// if the dlights disappear suddenly
surf->cached_dlight = (surf->dlightframe == r_framecount);
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
size = smax * tmax;
// clear to no light
memset (blocklights, 0, size * sizeof (blocklights[0]));
if (!r_worldentity.model->lightdata) {
// because we by-pass the inversion, "no light" = "full bright"
GLSL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
return;
}
// add all the lightmaps
if (surf->samples) {
int lmap;
byte *lightmap = surf->samples;
for (lmap = 0; lmap < MAXLIGHTMAPS && surf->styles[lmap] != 255;
lmap++) {
unsigned int *bl;
scale = d_lightstylevalue[surf->styles[lmap]];
surf->cached_light[lmap] = scale;
bl = blocklights;
for (i = 0; i < size; i++)
*bl++ += *lightmap++ * scale;
}
}
// add all the dynamic lights
if (surf->dlightframe == r_framecount)
R_AddDynamicLights_1 (surf);
// bound, invert, and shift
out = (byte *) blocklights;
for (i = 0; i < size; i++) {
t = (255 * 256 - (int) blocklights[i]);
t = max (t, 1 << (14 - VID_CBITS));
t = ((unsigned) t) >> (16 - VID_CBITS);
*out++ = t;
}
GLSL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1);
}
static void
create_surf_lightmap (msurface_t *surf)
{
int smax, tmax;
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
surf->lightpic = GLSL_ScrapSubpic (light_scrap, smax, tmax);
if (!surf->lightpic)
Sys_Error ("FIXME taniwha is being lazy");
if (smax > bl_extents[0])
bl_extents[0] = smax;
if (tmax > bl_extents[1])
bl_extents[1] = tmax;
}
void
glsl_R_BuildLightmaps (model_t **models, int num_models)
{
int i, j, size;
model_t *m;
//FIXME RGB support
if (!light_scrap) {
light_scrap = GLSL_CreateScrap (2048, GL_LUMINANCE, 1);
light_data = malloc (BLOCK_SIZE * MAX_LIGHTMAPS);
} else {
GLSL_ScrapClear (light_scrap);
memset (light_data, 0, BLOCK_SIZE * MAX_LIGHTMAPS);
}
glsl_R_BuildLightMap = R_BuildLightMap_1;
bl_extents[1] = bl_extents[0] = 0;
for (j = 1; j < num_models; j++) {
m = models[j];
if (!m)
break;
if (m->name[0] == '*') {
// sub model surfaces are processed as part of the main model
continue;
}
// non-bsp models don't have surfaces.
for (i = 0; i < m->numsurfaces; i++) {
msurface_t *surf = m->surfaces + i;
surf->lightpic = 0; // paranoia
if (surf->flags & SURF_DRAWTURB)
continue;
if (surf->flags & SURF_DRAWSKY)
continue;
create_surf_lightmap (surf);
}
}
size = bl_extents[0] * bl_extents[1] * 3; // * 3 for rgb support
blocklights = realloc (blocklights, size * sizeof (blocklights[0]));
for (j = 1; j < num_models; j++) {
m = models[j];
if (!m)
break;
if (m->name[0] == '*') {
// sub model surfaces are processed as part of the main model
continue;
}
// non-bsp models don't have surfaces.
for (i = 0; i < m->numsurfaces; i++) {
msurface_t *surf = m->surfaces + i;
if (surf->lightpic)
glsl_R_BuildLightMap (surf);
}
}
}
int
glsl_R_LightmapTexture (void)
{
return GLSL_ScrapTexture (light_scrap);
}
void
glsl_R_FlushLightmaps (void)
{
GLSL_ScrapFlush (light_scrap);
}