2003-09-09 08:13:33 +00:00
|
|
|
/*
|
|
|
|
vis.c
|
|
|
|
|
|
|
|
PVS support to speed lighting calcs
|
|
|
|
|
|
|
|
Copyright (C) 2003 Bill Currie
|
|
|
|
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
Date: 2003/9/8
|
|
|
|
|
|
|
|
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 <stdlib.h>
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
2011-08-25 13:35:20 +00:00
|
|
|
#if defined(_WIN32) && defined(HAVE_MALLOC_H)
|
2007-03-22 23:20:57 +00:00
|
|
|
# include <malloc.h>
|
|
|
|
#endif
|
2003-09-09 08:13:33 +00:00
|
|
|
|
2013-01-22 05:09:41 +00:00
|
|
|
#include "qfalloca.h"
|
|
|
|
|
2003-09-09 08:13:33 +00:00
|
|
|
#include "QF/bspfile.h"
|
|
|
|
#include "QF/mathlib.h"
|
|
|
|
|
|
|
|
#include "entities.h"
|
|
|
|
#include "light.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "threads.h"
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
int empty;
|
|
|
|
int solid;
|
|
|
|
int water;
|
|
|
|
int slime;
|
|
|
|
int lava;
|
|
|
|
int sky;
|
|
|
|
int misc;
|
|
|
|
|
|
|
|
int lights;
|
|
|
|
int cast;
|
|
|
|
} counts;
|
|
|
|
|
|
|
|
static lightchain_t *free_lightchains;
|
|
|
|
lightchain_t **surfacelightchain;
|
2003-09-10 15:48:46 +00:00
|
|
|
vec3_t *surfaceorgs;
|
2003-09-09 08:13:33 +00:00
|
|
|
entity_t **alllights;
|
|
|
|
int num_alllights;
|
|
|
|
entity_t **novislights;
|
|
|
|
int num_novislights;
|
|
|
|
|
2018-10-09 03:35:01 +00:00
|
|
|
static __attribute__((pure)) dleaf_t *
|
2003-09-09 08:13:33 +00:00
|
|
|
Light_PointInLeaf (vec3_t point)
|
|
|
|
{
|
|
|
|
int num = 0, side;
|
|
|
|
dnode_t *node;
|
|
|
|
dplane_t *plane;
|
|
|
|
|
|
|
|
while (num >= 0) {
|
|
|
|
node = bsp->nodes + num;
|
|
|
|
plane = bsp->planes + node->planenum;
|
|
|
|
side = DotProduct (point, plane->normal) < plane->dist;
|
|
|
|
num = node->children[side];
|
|
|
|
}
|
|
|
|
return bsp->leafs + (-1 - num);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DecompressVis (byte *in, byte *out, int size)
|
|
|
|
{
|
|
|
|
byte *end = out + size;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
while (out < end) {
|
|
|
|
n = *in++;
|
|
|
|
if (n) {
|
|
|
|
*out++ = n;
|
|
|
|
} else {
|
|
|
|
n = *in++;
|
|
|
|
while (n-- && out < end)
|
|
|
|
*out++ = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static lightchain_t *
|
|
|
|
get_lightchain (void)
|
|
|
|
{
|
|
|
|
lightchain_t *lc;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!free_lightchains) {
|
|
|
|
lc = free_lightchains = malloc (1024 * sizeof (lightchain_t));
|
|
|
|
for (i = 0; i < 1023; i++, lc++)
|
|
|
|
lc->next = lc + 1;
|
|
|
|
lc->next = 0;
|
|
|
|
}
|
|
|
|
lc = free_lightchains;
|
|
|
|
free_lightchains = lc->next;
|
|
|
|
return lc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
mark_face (int surfnum, byte *surfacehit, entity_t *entity)
|
|
|
|
{
|
|
|
|
lightchain_t *lc;
|
|
|
|
|
|
|
|
if (surfacehit[surfnum >> 3] & (1 << (surfnum & 7)))
|
|
|
|
return;
|
|
|
|
surfacehit[surfnum >> 3] |= (1 << (surfnum & 7));
|
|
|
|
counts.cast++;
|
|
|
|
lc = get_lightchain ();
|
|
|
|
lc->next = surfacelightchain[surfnum];
|
|
|
|
lc->light = entity;
|
|
|
|
surfacelightchain[surfnum] = lc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VisEntity (int ent_index)
|
|
|
|
{
|
|
|
|
entity_t *entity = entities + ent_index;
|
|
|
|
dleaf_t *leaf;
|
|
|
|
int ignorevis = false;
|
2012-09-07 07:09:24 +00:00
|
|
|
int i;
|
|
|
|
unsigned j;
|
|
|
|
uint32_t *mark;
|
2003-09-09 08:13:33 +00:00
|
|
|
byte *vis, *surfacehit;
|
|
|
|
int vis_size;
|
|
|
|
|
|
|
|
if (!entity->light)
|
|
|
|
return;
|
|
|
|
|
|
|
|
counts.lights++;
|
|
|
|
|
|
|
|
leaf = Light_PointInLeaf (entity->origin);
|
|
|
|
|
|
|
|
switch (leaf->contents) {
|
|
|
|
case CONTENTS_EMPTY:
|
|
|
|
counts.empty++;
|
|
|
|
break;
|
|
|
|
case CONTENTS_SOLID:
|
|
|
|
counts.solid++;
|
|
|
|
ignorevis = true;
|
|
|
|
break;
|
|
|
|
case CONTENTS_WATER:
|
|
|
|
counts.water++;
|
|
|
|
break;
|
|
|
|
case CONTENTS_SLIME:
|
|
|
|
counts.slime++;
|
|
|
|
break;
|
|
|
|
case CONTENTS_LAVA:
|
|
|
|
counts.lava++;
|
|
|
|
break;
|
|
|
|
case CONTENTS_SKY:
|
|
|
|
counts.sky++;
|
|
|
|
ignorevis = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
counts.misc++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (leaf->visofs == -1 || ignorevis || options.novis) {
|
|
|
|
counts.cast += bsp->numfaces;
|
|
|
|
novislights[num_novislights++] = entity;
|
|
|
|
} else {
|
|
|
|
vis_size = (bsp->numleafs + 7) / 8;
|
|
|
|
vis = alloca (vis_size + (bsp->numfaces + 7) / 8);
|
|
|
|
surfacehit = vis + vis_size;
|
|
|
|
memset (surfacehit, 0, (bsp->numfaces + 7) / 8);
|
|
|
|
|
2003-09-09 15:29:14 +00:00
|
|
|
DecompressVis (bsp->visdata + leaf->visofs, vis, vis_size);
|
|
|
|
for (i = 0, leaf = bsp->leafs + 1; i < bsp->models[0].visleafs;
|
|
|
|
i++, leaf++) {
|
2003-09-09 08:13:33 +00:00
|
|
|
if (!leaf->nummarksurfaces)
|
|
|
|
continue;
|
|
|
|
if (vis[i >> 3] & (1 << (i & 7))) {
|
|
|
|
for (j = 0, mark = bsp->marksurfaces + leaf->firstmarksurface;
|
|
|
|
j < leaf->nummarksurfaces; j++, mark++) {
|
|
|
|
mark_face (*mark, surfacehit, entity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 1; i < bsp->nummodels; i++) {
|
2012-09-07 07:09:24 +00:00
|
|
|
for (j = 0; (int) j < bsp->models[i].numfaces; j++) {
|
2003-09-09 08:13:33 +00:00
|
|
|
//FIXME vis
|
|
|
|
mark_face (bsp->models[i].firstface + j, surfacehit, entity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VisStats (void)
|
|
|
|
{
|
|
|
|
int i, count;
|
|
|
|
|
|
|
|
printf ("%4i lights\n", counts.lights);
|
|
|
|
printf ("%4i air\n", counts.empty);
|
|
|
|
printf ("%4i solid\n", counts.solid);
|
|
|
|
printf ("%4i water\n", counts.water);
|
|
|
|
printf ("%4i slime\n", counts.slime);
|
|
|
|
printf ("%4i lava\n", counts.lava);
|
|
|
|
printf ("%4i sky\n", counts.sky);
|
|
|
|
printf ("%4i unknown\n", counts.misc);
|
|
|
|
|
|
|
|
for (i = count = 0; i < bsp->numfaces; i++)
|
|
|
|
if (surfacelightchain[i])
|
|
|
|
count++;
|
|
|
|
printf ("%i faces, %i (%i%%) may receive light\n", bsp->numfaces,
|
|
|
|
count, count * 100 / bsp->numfaces);
|
|
|
|
if (counts.solid || counts.sky)
|
|
|
|
printf ("warning: %i lights of %i lights (%i%%) were found in sky\n"
|
|
|
|
"or solid and will not be accelerated using vis, move them\n"
|
|
|
|
"out of the solid or sky to accelerate compiling\n",
|
|
|
|
counts.solid + counts.sky, counts.lights,
|
|
|
|
(counts.solid + counts.sky) * 100 / counts.lights);
|
2003-09-10 21:09:23 +00:00
|
|
|
printf ("%i lights will be cast onto %i surfaces, %i casts will "
|
2003-09-09 08:13:33 +00:00
|
|
|
"be performed\n", counts.lights, bsp->numfaces, counts.cast);
|
|
|
|
}
|