#include "gl_local.h"
int r_dlightframecount;
#define DLIGHT_CUTOFF 64
void R_MarkLights(model_t *model, dlight_t *light, int bit, mnode_t *node) {
cplane_t *splitplane;
float dist;
msurface_t *surf;
int i;
if(model->type != mod_brush)
return;
if(node->contents != -1)
return;
splitplane = node->plane;
dist = DotProduct(light->origin, splitplane->normal) - splitplane->dist;
if(dist > light->intensity - DLIGHT_CUTOFF) {
R_MarkLights(model, light, bit, node->children[0]);
return;
}
if(dist < -light->intensity + DLIGHT_CUTOFF) {
R_MarkLights(model, light, bit, node->children[1]);
return;
}
surf = model->surfaces + node->firstsurface;
for(i = 0; i < node->numsurfaces; i++, surf++) {
if(surf->dlightframe != r_dlightframecount) {
surf->dlightbits = 0;
surf->dlightframe = r_dlightframecount;
}
surf->dlightbits |= bit;
}
R_MarkLights(model, light, bit, node->children[0]);
R_MarkLights(model, light, bit, node->children[1]);
}
void R_PushDlights(model_t *model) {
int i;
dlight_t *l;
if(gl_flashblend->value)
return;
r_dlightframecount = r_framecount + 1; l = r_newrefdef.dlights;
for(i = 0; i < r_newrefdef.num_dlights; i++, l++)
R_MarkLights(model, l, 1 << i, model->nodes);
}
struct SH1 pointcolor;
cplane_t *lightplane; vec3_t lightspot;
int RecursiveLightPoint(model_t *model, mnode_t *node, vec3_t start, vec3_t end) {
float front, back, frac;
int side;
cplane_t *plane;
vec3_t mid;
msurface_t *surf;
int s, t, ds, dt;
int i;
mtexinfo_t *tex;
byte *lightmap;
int maps;
int r;
if(node->contents != -1)
return -1;
plane = node->plane;
front = DotProduct(start, plane->normal) - plane->dist;
back = DotProduct(end, plane->normal) - plane->dist;
side = front < 0;
if((back < 0) == side)
return RecursiveLightPoint(model, node->children[side], start, end);
frac = front / (front - back);
mid[0] = start[0] + (end[0] - start[0]) * frac;
mid[1] = start[1] + (end[1] - start[1]) * frac;
mid[2] = start[2] + (end[2] - start[2]) * frac;
r = RecursiveLightPoint(model, node->children[side], start, mid);
if(r >= 0)
return r;
if((back < 0) == side)
return -1;
VectorCopy(mid, lightspot);
lightplane = plane;
surf = model->surfaces + node->firstsurface;
for(i = 0; i < node->numsurfaces; i++, surf++) {
if(surf->flags & (SURF_DRAWTURB | SURF_DRAWSKY))
continue;
tex = surf->texinfo;
s = DotProduct(mid, tex->vecs[0]) + tex->vecs[0][3];
t = DotProduct(mid, tex->vecs[1]) + tex->vecs[1][3];
if(s < surf->texturemins[0] || t < surf->texturemins[1])
continue;
ds = s - surf->texturemins[0];
dt = t - surf->texturemins[1];
if(ds > surf->extents[0] || dt > surf->extents[1])
continue;
if(!surf->samples)
return 0;
int smax = (surf->extents[0] >> 4) + 1;
int tmax = (surf->extents[1] >> 4) + 1;
int size = smax * tmax;
ds >>= 4;
dt >>= 4;
lightmap = surf->samples;
pointcolor = SH1_Clear();
if(lightmap) {
vec3_t scale;
lightmap += 3 * (dt * smax + ds);
for(maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) {
for(i = 0; i < 3; i++)
scale[i] = gl_modulate->value * r_newrefdef.lightstyles[surf->styles[maps]].rgb[i];
pointcolor.f[0] += lightmap[0] * scale[0] * (1.0 / 255);
pointcolor.f[4] += lightmap[1] * scale[1] * (1.0 / 255);
pointcolor.f[8] += lightmap[2] * scale[2] * (1.0 / 255);
lightmap += 3 * size;
if(!model->old_lightmap) {
pointcolor.f[1] += lightmap[0] * scale[0] * (1.0 / 255) * 2.0f - 1.0f;
pointcolor.f[2] += lightmap[1] * scale[1] * (1.0 / 255) * 2.0f - 1.0f;
pointcolor.f[3] += lightmap[2] * scale[2] * (1.0 / 255) * 2.0f - 1.0f;
lightmap += 3 * size;
pointcolor.f[5] += lightmap[0] * scale[0] * (1.0 / 255) * 2.0f - 1.0f;
pointcolor.f[6] += lightmap[1] * scale[1] * (1.0 / 255) * 2.0f - 1.0f;
pointcolor.f[7] += lightmap[2] * scale[2] * (1.0 / 255) * 2.0f - 1.0f;
lightmap += 3 * size;
pointcolor.f[9] += (lightmap[0] * scale[0] * (1.0 / 255)) * 2.0f - 1.0f;
pointcolor.f[10] += (lightmap[1] * scale[1] * (1.0 / 255)) * 2.0f - 1.0f;
pointcolor.f[11] += (lightmap[2] * scale[2] * (1.0 / 255)) * 2.0f - 1.0f;
lightmap += 3 * size;
}
}
}
return 1;
}
return RecursiveLightPoint(model, node->children[!side], mid, end);
}
struct SH1 R_LightPoint(model_t *model, vec3_t p) {
vec3_t end;
float r;
int lnum;
dlight_t *dl;
vec3_t dist;
float add;
struct SH1 color;
if(!model->lightdata) {
return SH1_FromDirectionalLight(vec3_origin, (float[]){1, 1, 1});
}
end[0] = p[0];
end[1] = p[1];
end[2] = p[2] - 2048;
r = RecursiveLightPoint(model, model->nodes, p, end);
if(r == -1) {
return SH1_Clear();
} else {
color = pointcolor;
}
dl = r_newrefdef.dlights;
for(lnum = 0; lnum < r_newrefdef.num_dlights; lnum++, dl++) {
VectorSubtract(currententity->origin, dl->origin, dist);
float length = VectorNormalize(dist);
add = dl->intensity - length;
add *= (1.0 / 256);
if(add > 0) {
color = SH1_Add(color, SH1_FromDirectionalLight(dist, dl->color));
}
}
return SH1_Scale(color, gl_modulate->value);
}
static struct {
uint32_t num_blocklights;
struct SH1 *blocklights;
} _ = {0};
void R_AddDynamicLights(msurface_t *surf) {
int lnum;
int sd, td;
float fdist, frad, fminlight;
vec3_t impact, local;
int s, t;
int i;
int smax, tmax;
mtexinfo_t *tex;
dlight_t *dl;
struct SH1 *pfBL;
float fsacc, ftacc;
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
tex = surf->texinfo;
for(lnum = 0; lnum < r_newrefdef.num_dlights; lnum++) {
if(!(surf->dlightbits & (1 << lnum)))
continue;
dl = &r_newrefdef.dlights[lnum];
frad = dl->intensity;
fdist = DotProduct(dl->origin, surf->plane->normal) - surf->plane->dist;
frad -= fabs(fdist);
fminlight = DLIGHT_CUTOFF; if(frad < fminlight)
continue;
fminlight = frad - fminlight;
for(i = 0; i < 3; i++) {
impact[i] = dl->origin[i] - surf->plane->normal[i] * fdist;
}
local[0] = DotProduct(impact, tex->vecs[0]) + tex->vecs[0][3] - surf->texturemins[0];
local[1] = DotProduct(impact, tex->vecs[1]) + tex->vecs[1][3] - surf->texturemins[1];
pfBL = _.blocklights;
for(t = 0, ftacc = 0; t < tmax; t++, ftacc += 16) {
td = local[1] - ftacc;
if(td < 0)
td = -td;
for(s = 0, fsacc = 0; s < smax; s++, fsacc += 16, pfBL++) {
sd = (int)(local[0] - fsacc);
if(sd < 0)
sd = -sd;
if(sd > td)
fdist = sd + (td >> 1);
else
fdist = td + (sd >> 1);
if(fdist < fminlight) {
*pfBL = SH1_Add(*pfBL, SH1_Scale(SH1_FromDirectionalLight(vec3_origin, dl->color), frad - fdist));
}
}
}
}
}
void R_SetCacheState(model_t *model, msurface_t *surf) {
int maps;
for(maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) {
surf->cached_light[maps] = r_newrefdef.lightstyles[surf->styles[maps]].white;
}
}
void R_BuildLightMap(model_t *model, msurface_t *surf, byte *dest_rgb0, byte *dest_r1, byte *dest_g1, byte *dest_b1, int stride) {
int smax, tmax;
int i, j, size;
byte *lightmap_rgb0, *lightmap_r1, *lightmap_g1, *lightmap_b1;
float scale[4];
int nummaps;
struct SH1 *bl;
smax = (surf->extents[0] >> 4) + 1;
tmax = (surf->extents[1] >> 4) + 1;
size = smax * tmax;
if(size > _.num_blocklights) {
_.num_blocklights = size + 1;
_.num_blocklights += _.num_blocklights >> 1;
_.blocklights = realloc(_.blocklights, _.num_blocklights * sizeof(*_.blocklights));
}
if(!surf->samples) {
for(i = 0; i < size; i++) {
_.blocklights[i].f[0] = _.blocklights[i].f[4] = _.blocklights[i].f[8] = 127;
_.blocklights[i].f[1] = _.blocklights[i].f[2] = _.blocklights[i].f[3] = 0;
_.blocklights[i].f[5] = _.blocklights[i].f[6] = _.blocklights[i].f[7] = 0;
_.blocklights[i].f[9] = _.blocklights[i].f[10] = _.blocklights[i].f[11] = 0;
}
goto store;
}
for(nummaps = 0; nummaps < MAXLIGHTMAPS && surf->styles[nummaps] != 255; nummaps++)
;
int newsize = model->old_lightmap ? 0 : size * 3;
int newstride = model->old_lightmap ? 1 : 4;
lightmap_rgb0 = surf->samples + newsize * 0;
lightmap_r1 = surf->samples + newsize * 1;
lightmap_g1 = surf->samples + newsize * 2;
lightmap_b1 = surf->samples + newsize * 3;
int maps;
for(maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) {
bl = _.blocklights;
for(i = 0; i < 3; i++)
scale[i] = gl_modulate->value * r_newrefdef.lightstyles[surf->styles[maps]].rgb[i];
for(i = 0; i < size; i++) {
struct SH1 color;
color.f[0] = lightmap_rgb0[i * 3 + 0] - 0.5f;
color.f[4] = lightmap_rgb0[i * 3 + 1] - 0.5f;
color.f[8] = lightmap_rgb0[i * 3 + 2] - 0.5f;
if(!model->old_lightmap) {
color.f[1] = lightmap_r1[i * 3 + 0] - 0.5f;
color.f[2] = lightmap_r1[i * 3 + 1] - 0.5f;
color.f[3] = lightmap_r1[i * 3 + 2] - 0.5f;
color.f[5] = lightmap_g1[i * 3 + 0] - 0.5f;
color.f[6] = lightmap_g1[i * 3 + 1] - 0.5f;
color.f[7] = lightmap_g1[i * 3 + 2] - 0.5f;
color.f[9] = lightmap_b1[i * 3 + 0] - 0.5f;
color.f[10] = lightmap_b1[i * 3 + 1] - 0.5f;
color.f[11] = lightmap_b1[i * 3 + 2] - 0.5f;
for(int component = 0; component < 3; component++) {
for(int basis = 0; basis < 3; basis++) {
color.f[component * 4 + basis + 1] -= 127.0f;
color.f[component * 4 + basis + 1] *= 2;
}
}
} else {
color.f[1] = 0.0f;
color.f[2] = 0.0f;
color.f[3] = 0.0f;
color.f[5] = 0.0f;
color.f[6] = 0.0f;
color.f[7] = 0.0f;
color.f[9] = 0.0f;
color.f[10] = 0.0f;
color.f[11] = 0.0f;
}
color = SH1_ColorScale(color, scale);
if(maps != 0) {
bl[i] = SH1_Add(bl[i], color);
} else {
bl[i] = color;
}
}
lightmap_rgb0 += size * 3 * newstride;
if(!model->old_lightmap) {
lightmap_r1 += size * 3 * newstride;
lightmap_g1 += size * 3 * newstride;
lightmap_b1 += size * 3 * newstride;
}
}
if(surf->dlightframe == r_framecount)
R_AddDynamicLights(surf);
store:
bl = _.blocklights;
for(i = 0; i < tmax; i++, dest_rgb0 += stride, dest_r1 += stride, dest_g1 += stride, dest_b1 += stride) {
for(j = 0; j < smax; j++) {
struct SH1 color = SH1_NormalizeMaximum(*bl, 254.5f, NULL);
for(int component = 0; component < 3; component++) {
for(int basis = 0; basis < 3; basis++) {
color.f[component * 4 + basis + 1] *= 0.5f;
color.f[component * 4 + basis + 1] += 127.0f;
}
}
dest_rgb0[j * 3 + 0] = (byte)(color.f[0] + 0.5f);
dest_rgb0[j * 3 + 1] = (byte)(color.f[4] + 0.5f);
dest_rgb0[j * 3 + 2] = (byte)(color.f[8] + 0.5f);
dest_r1[j * 3 + 0] = (byte)(color.f[1] + 0.5f);
dest_r1[j * 3 + 1] = (byte)(color.f[2] + 0.5f);
dest_r1[j * 3 + 2] = (byte)(color.f[3] + 0.5f);
dest_g1[j * 3 + 0] = (byte)(color.f[5] + 0.5f);
dest_g1[j * 3 + 1] = (byte)(color.f[6] + 0.5f);
dest_g1[j * 3 + 2] = (byte)(color.f[7] + 0.5f);
dest_b1[j * 3 + 0] = (byte)(color.f[9] + 0.5f);
dest_b1[j * 3 + 1] = (byte)(color.f[10] + 0.5f);
dest_b1[j * 3 + 2] = (byte)(color.f[11] + 0.5f);
bl++;
}
}
}