quakeforge/libs/video/renderer/sw/sw_rsurf.c
Bill Currie 35ec2ebb4c [scene] Move dynamic lights into the scene ECS
While the insertion of dlights into the BSP might wind up being overly
expensive, the automatic management of the component pool cleans up the
various loops in the renderers.

Unfortunately, (current bug) lights on entities cause the entity to
disappear due to how the entity queue system works, and the doubled
efrag chain causes crashes when changing maps, meaning lights should be
on their own entities, not additional components on entities with
visible models.

Also, the vulkan renderer segfaults on dlights (fix incoming, along with
shadows for dlights).
2023-08-04 15:08:56 +09:00

473 lines
11 KiB
C

/*
sw_rsurf.c
surface-related refresh code
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
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "QF/render.h"
#include "QF/sys.h"
#include "QF/scene/entity.h"
#include "r_internal.h"
#ifdef PIC
# undef USE_INTEL_ASM //XXX asm pic hack
#endif
drawsurf_t r_drawsurf;
int sourcesstep, sourcetstep;
#ifndef USE_INTEL_ASM
static int lightleft;
#endif
static int blocksize;
int lightdelta, lightdeltastep;
int lightright, lightleftstep, lightrightstep, blockdivshift;
static unsigned int blockdivmask;
void *prowdestbase;
byte *pbasesource;
int surfrowbytes; // used by ASM files
unsigned int *r_lightptr;
int r_stepback;
int r_lightwidth;
static int r_numhblocks;
int r_numvblocks;
static byte *r_source;
byte *r_sourcemax;
void R_DrawSurfaceBlock_mip0 (void);
void R_DrawSurfaceBlock_mip1 (void);
void R_DrawSurfaceBlock_mip2 (void);
void R_DrawSurfaceBlock_mip3 (void);
static void (*surfmiptable[4]) (void) = {
R_DrawSurfaceBlock_mip0, R_DrawSurfaceBlock_mip1,
R_DrawSurfaceBlock_mip2, R_DrawSurfaceBlock_mip3};
static unsigned int blocklights[34 * 34]; //FIXME make dynamic
static void
R_AddDynamicLights (uint32_t render_id)
{
msurface_t *surf;
int sd, td;
float dist, rad, minlight;
vec3_t impact, local, lightorigin;
vec4f_t entorigin = { 0, 0, 0, 1 };
int s, t;
int smax, tmax;
mtexinfo_t *tex;
surf = r_drawsurf.surf;
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
tex = surf->texinfo;
if (render_id) {
//FIXME give world entity a transform
vec4f_t *transform = SW_COMP (scene_sw_matrix, render_id);
entorigin = transform[3];
}
auto dlight_pool = &r_refdef.registry->comp_pools[scene_dynlight];
auto dlight_data = (dlight_t *) dlight_pool->data;
for (uint32_t k = 0; k < dlight_pool->count; k++) {
auto dlight = &dlight_data[k];
//FIXME
if (!(surf->dlightbits[k / 32] & (1 << (k % 32))))
continue; // not lit by this light
VectorSubtract (dlight->origin, entorigin, lightorigin);
rad = dlight->radius;
dist = DotProduct (lightorigin, surf->plane->normal) -
surf->plane->dist;
rad -= fabs (dist);
minlight = dlight->minlight;
if (rad < minlight)
continue;
minlight = rad - minlight;
for (int i = 0; i < 3; i++)
impact[i] = lightorigin[i] - surf->plane->normal[i] * dist;
local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
local[0] -= surf->texturemins[0];
local[1] -= surf->texturemins[1];
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;
}
}
}
}
/*
R_BuildLightMap
Combine and scale multiple lightmaps into the 8.8 format in blocklights
*/
static void
R_BuildLightMap (uint32_t render_id)
{
int smax, tmax;
int t;
int i, size;
byte *lightmap;
unsigned int scale;
int maps;
msurface_t *surf;
surf = r_drawsurf.surf;
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
size = smax * tmax;
lightmap = surf->samples;
if (!r_refdef.worldmodel->brush.lightdata) {
for (i = 0; i < size; i++)
blocklights[i] = 0;
return;
}
// clear to ambient
for (i = 0; i < size; i++)
blocklights[i] = r_refdef.ambientlight << 8;
// add all the lightmaps
if (lightmap)
for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) {
scale = r_drawsurf.lightadj[maps]; // 8.8 fraction
for (i = 0; i < size; i++)
blocklights[i] += lightmap[i] * scale;
lightmap += size; // skip to next lightmap
}
// add all the dynamic lights
if (surf->dlightframe == r_framecount)
R_AddDynamicLights (render_id);
// bound, invert, and shift
for (i = 0; i < size; i++) {
t = (255 * 256 - (int) blocklights[i]) >> (8 - VID_CBITS);
if (t < (1 << 6))
t = (1 << 6);
blocklights[i] = t;
}
}
void
R_DrawSurface (uint32_t render_id)
{
byte *basetptr;
int smax, tmax, twidth;
int u;
int soffset, basetoffset, texwidth;
int horzblockstep;
byte *pcolumndest;
void (*pblockdrawer) (void);
texture_t *mt;
// calculate the lightings
R_BuildLightMap (render_id);
surfrowbytes = r_drawsurf.rowbytes;
mt = r_drawsurf.texture;
r_source = (byte *) mt + mt->offsets[r_drawsurf.surfmip];
// the fractional light values should range from 0 to
// (VID_GRADES - 1) << 16 from a source range of 0 - 255
texwidth = mt->width >> r_drawsurf.surfmip;
blocksize = 16 >> r_drawsurf.surfmip;
blockdivshift = 4 - r_drawsurf.surfmip;
blockdivmask = (1 << blockdivshift) - 1;
r_lightwidth = (r_drawsurf.surf->extents[0] >> 4) + 1;
r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
//==============================
pblockdrawer = surfmiptable[r_drawsurf.surfmip];
// TODO: needs to be set only when there is a display settings change
horzblockstep = blocksize;
smax = mt->width >> r_drawsurf.surfmip;
twidth = texwidth;
tmax = mt->height >> r_drawsurf.surfmip;
sourcetstep = texwidth;
r_stepback = tmax * twidth;
r_sourcemax = r_source + (tmax * smax);
soffset = r_drawsurf.surf->texturemins[0];
basetoffset = r_drawsurf.surf->texturemins[1];
// << 16 components are to guarantee positive values for %
soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip)
+ (tmax << 16)) % tmax) * twidth)];
pcolumndest = r_drawsurf.surfdat;
for (u = 0; u < r_numhblocks; u++) {
r_lightptr = blocklights + u;
prowdestbase = pcolumndest;
pbasesource = basetptr + soffset;
(*pblockdrawer) ();
soffset = soffset + blocksize;
if (soffset >= smax)
soffset = 0;
pcolumndest += horzblockstep;
}
}
#ifndef USE_INTEL_ASM
void
R_DrawSurfaceBlock_mip0 (void)
{
int v, i, b, lightstep, lighttemp, light;
byte pix, *psource, *prowdest;
psource = pbasesource;
prowdest = prowdestbase;
for (v = 0; v < r_numvblocks; v++) {
// FIXME: make these locals?
// FIXME: use delta rather than both right and left, like ASM?
lightleft = r_lightptr[0];
lightright = r_lightptr[1];
r_lightptr += r_lightwidth;
lightleftstep = (r_lightptr[0] - lightleft) >> 4;
lightrightstep = (r_lightptr[1] - lightright) >> 4;
for (i = 0; i < 16; i++) {
lighttemp = lightleft - lightright;
lightstep = lighttemp >> 4;
light = lightright;
for (b = 15; b >= 0; b--) {
pix = psource[b];
prowdest[b] = r_colormap[(light & 0xFF00) + pix];
light += lightstep;
}
psource += sourcetstep;
lightright += lightrightstep;
lightleft += lightleftstep;
prowdest += surfrowbytes;
}
if (psource >= r_sourcemax)
psource -= r_stepback;
}
}
void
R_DrawSurfaceBlock_mip1 (void)
{
int v, i, b, lightstep, lighttemp, light;
byte pix, *psource, *prowdest;
psource = pbasesource;
prowdest = prowdestbase;
for (v = 0; v < r_numvblocks; v++) {
// FIXME: make these locals?
// FIXME: use delta rather than both right and left, like ASM?
lightleft = r_lightptr[0];
lightright = r_lightptr[1];
r_lightptr += r_lightwidth;
lightleftstep = (r_lightptr[0] - lightleft) >> 3;
lightrightstep = (r_lightptr[1] - lightright) >> 3;
for (i = 0; i < 8; i++) {
lighttemp = lightleft - lightright;
lightstep = lighttemp >> 3;
light = lightright;
for (b = 7; b >= 0; b--) {
pix = psource[b];
prowdest[b] = r_colormap[(light & 0xFF00) + pix];
light += lightstep;
}
psource += sourcetstep;
lightright += lightrightstep;
lightleft += lightleftstep;
prowdest += surfrowbytes;
}
if (psource >= r_sourcemax)
psource -= r_stepback;
}
}
void
R_DrawSurfaceBlock_mip2 (void)
{
int v, i, b, lightstep, lighttemp, light;
byte pix, *psource, *prowdest;
psource = pbasesource;
prowdest = prowdestbase;
for (v = 0; v < r_numvblocks; v++) {
// FIXME: make these locals?
// FIXME: use delta rather than both right and left, like ASM?
lightleft = r_lightptr[0];
lightright = r_lightptr[1];
r_lightptr += r_lightwidth;
lightleftstep = (r_lightptr[0] - lightleft) >> 2;
lightrightstep = (r_lightptr[1] - lightright) >> 2;
for (i = 0; i < 4; i++) {
lighttemp = lightleft - lightright;
lightstep = lighttemp >> 2;
light = lightright;
for (b = 3; b >= 0; b--) {
pix = psource[b];
prowdest[b] = r_colormap[(light & 0xFF00) + pix];
light += lightstep;
}
psource += sourcetstep;
lightright += lightrightstep;
lightleft += lightleftstep;
prowdest += surfrowbytes;
}
if (psource >= r_sourcemax)
psource -= r_stepback;
}
}
void
R_DrawSurfaceBlock_mip3 (void)
{
int v, i, b, lightstep, lighttemp, light;
byte pix, *psource, *prowdest;
psource = pbasesource;
prowdest = prowdestbase;
for (v = 0; v < r_numvblocks; v++) {
// FIXME: make these locals?
// FIXME: use delta rather than both right and left, like ASM?
lightleft = r_lightptr[0];
lightright = r_lightptr[1];
r_lightptr += r_lightwidth;
lightleftstep = (r_lightptr[0] - lightleft) >> 1;
lightrightstep = (r_lightptr[1] - lightright) >> 1;
for (i = 0; i < 2; i++) {
lighttemp = lightleft - lightright;
lightstep = lighttemp >> 1;
light = lightright;
for (b = 1; b >= 0; b--) {
pix = psource[b];
prowdest[b] = r_colormap[(light & 0xFF00) + pix];
light += lightstep;
}
psource += sourcetstep;
lightright += lightrightstep;
lightleft += lightleftstep;
prowdest += surfrowbytes;
}
if (psource >= r_sourcemax)
psource -= r_stepback;
}
}
#endif
static void
R_GenTurbTile (byte *pbasetex, void *pdest)
{
int *turb;
int i, j, s, t;
byte *pd;
turb = sintable + ((int) (vr_data.realtime * SPEED) & (CYCLE - 1));
pd = (byte *) pdest;
for (i = 0; i < TILE_SIZE; i++) {
for (j = 0; j < TILE_SIZE; j++) {
s = (((j << 16) + turb[i & (CYCLE - 1)]) >> 16) & 63;
t = (((i << 16) + turb[j & (CYCLE - 1)]) >> 16) & 63;
*pd++ = *(pbasetex + (t << 6) + s);
}
}
}
void
R_GenTile (msurface_t *psurf, void *pdest)
{
if (psurf->flags & SURF_DRAWTURB) {
R_GenTurbTile (((byte *) psurf->texinfo->texture +
psurf->texinfo->texture->offsets[0]), pdest);
} else if (psurf->flags & SURF_DRAWSKY) {
R_GenSkyTile (pdest);
} else {
Sys_Error ("Unknown tile type");
}
}