bring in lordhavoc's vis data optimisations (doesn't work properly yet) and

parsing of his extra fields.
This commit is contained in:
Bill Currie 2003-09-09 08:13:33 +00:00
parent ba4ca3515d
commit 26f3839276
9 changed files with 436 additions and 16 deletions

View File

@ -31,6 +31,7 @@
#define __entities_h
#define DEFAULTLIGHTLEVEL 300
#define DEFAULTFALLOFF 1.0f
typedef struct epair_s {
struct epair_s *next;
@ -41,7 +42,7 @@ typedef struct epair_s {
typedef struct entity_s {
const char *classname;
vec3_t origin;
float angle;
vec_t angle;
int light;
// LordHavoc: added falloff (smaller fractions = bigger light area),
// color, and lightradius (also subbrightness to implement lightradius)
@ -68,6 +69,7 @@ extern int num_entities;
const char *ValueForKey (entity_t *ent, const char *key);
void SetKeyValue (entity_t *ent, const char *key, const char *value);
float FloatForKey (entity_t *ent, const char *key);
entity_t *FindEntityWithKeyPair(char *key, char *value);
void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec);
void LoadEntities (void);

View File

@ -32,6 +32,7 @@
#define ON_EPSILON 0.1
#define MAXLIGHTS 1024
#define LIGHTDISTBIAS 65536.0
extern float scaledist;
extern float scalecos;
@ -60,7 +61,19 @@ int GetFileSpace (int size);
void TransformSample (vec3_t in, vec3_t out);
void RotateSample (vec3_t in, vec3_t out);
void VisEntity (int ent_index);
void VisStats (void);
extern struct bsp_s *bsp;
extern struct dstring_s *lightdata;
typedef struct lightchain_s {
struct lightchain_s *next;
struct entity_s *light;
} lightchain_t;
extern lightchain_t **surfacelightchain;
extern struct entity_s **novislights;
extern int num_novislights;
#endif// __light_h

View File

@ -34,9 +34,12 @@
typedef struct {
int verbosity; // 0=silent
int threads;
int novis;
qboolean extra;
float distance;
float range;
vec_t distance;
vec_t range;
vec_t globallightscale;
const char *lightsfilename;
} options_t;
extern options_t options;

View File

@ -17,7 +17,7 @@ endif
bin_PROGRAMS= $(qflight)
EXTRA_PROGRAMS= qflight
qflight_SOURCES= entities.c ltface.c options.c qflight.c threads.c trace.c
qflight_SOURCES= entities.c ltface.c options.c qflight.c threads.c trace.c vis.c
qflight_LDFLAGS= $(PTHREAD_LDFLAGS)
qflight_LDADD= $(QFLIGHT_LIBS)

View File

@ -104,6 +104,14 @@ MatchTargets (void)
if (entities[j].targetname
&& !strcmp (entities[j].targetname, entities[i].target)) {
entities[i].targetent = &entities[j];
// set up spotlight values for lighting code to use
VectorSubtract (entities[i].targetent->origin,
entities[i].origin, entities[i].spotdir);
VectorNormalize (entities[i].spotdir);
if (!entities[i].angle)
entities[i].spotcone = -cos(20 * M_PI / 180);
else
entities[i].spotcone = -cos(entities[i].angle * M_PI / 360);
break;
}
if (j == num_entities) {
@ -121,17 +129,49 @@ MatchTargets (void)
sprintf (s, "%i", entities[i].style);
SetKeyValue (&entities[i], "style", s);
}
if (entities[i].spotcone <= 0) {
VectorZero (entities[i].spotdir);
entities[i].spotcone = 0;
}
}
}
static void
WriteLights (void)
{
int i;
FILE *f;
entity_t *e;
if (!options.lightsfilename)
return;
printf ("building .lights file\n");
f = fopen (options.lightsfilename, "wb");
for (i = 0; i < num_entities; i++) {
e = entities + i;
if (e->light)
fprintf(f, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d\n",
e->origin[0], e->origin[1], e->origin[2],
e->falloff,
e->color[0], e->color[1], e->color[2],
e->subbrightness,
e->spotdir[0], e->spotdir[1], e->spotdir[2],
e->spotcone, e->lightoffset, e->style);
}
fclose (f);
}
void
LoadEntities (void)
{
const char *data;
const char *key;
double vec[3];
double vec[4];
double temp, color2[3];
entity_t *entity;
epair_t *epair;
int i;
data = bsp->entdata;
@ -156,6 +196,13 @@ LoadEntities (void)
entity = &entities[num_entities];
num_entities++;
memset (entity, 0, sizeof (*entity));
entity->color[0] = entity->color[1] = entity->color[2] = 1.0f;
color2[0] = color2[1] = color2[2] = 1.0f;
entity->falloff = DEFAULTFALLOFF * DEFAULTFALLOFF;
entity->lightradius = 0;
entity->lightoffset = LIGHTDISTBIAS;
// go through all the keys in this entity
while (1) {
int c;
@ -196,7 +243,37 @@ LoadEntities (void)
fprintf (stderr, "LoadEntities: not 3 values for origin");
VectorCopy (vec, entity->origin);
} else if (!strncmp (key, "light", 5) || !strcmp (key, "_light")) {
entity->light = atof(com_token);
i = sscanf (com_token, "%lf %lf %lf %lf",
&vec[0], &vec[1], &vec[2], &vec[3]);
switch (i) {
case 4: // HalfLife light
entity->light = vec[3];
entity->color[0] = vec[0] * (1.0f / 255.0f);
entity->color[1] = vec[1] * (1.0f / 255.0f);
entity->color[2] = vec[2] * (1.0f / 255.0f);
break;
case 3:
entity->light = 1;
entity->color[0] = vec[0];
entity->color[1] = vec[1];
entity->color[2] = vec[2];
break;
case 1:
entity->light = vec[0];
entity->color[0] = 1.0f;
entity->color[1] = 1.0f;
entity->color[2] = 1.0f;
break;
default:
Sys_Error ("LoadEntities: _light (or light) key must "
"be 1 (Quake), 4 (HalfLife), or 3 (HLight) "
"values, \"%s\" is not valid\n", com_token);
}
} else if (!strcmp (key, "wait")) {
entity->falloff = atof (com_token);
entity->falloff *= entity->falloff; // presquared
} else if (!strcmp (key, "_lightradius")) {
entity->lightradius = atof (com_token);
} else if (!strcmp (key, "style")) {
entity->style = atof (com_token);
if ((unsigned) entity->style > 254)
@ -204,13 +281,45 @@ LoadEntities (void)
entity->style);
} else if (!strcmp (key, "angle")) {
entity->angle = atof(com_token);
} else if (!strcmp (key, "color") || !strcmp (key, "_color")) {
if (sscanf (com_token, "%lf %lf %lf",
&vec[0], &vec[1], &vec[2]) != 3)
Sys_Error ("LoadEntities: not 3 values for color");
// scale the color to have at least one component at 1.0
temp = vec[0];
if (vec[1] > temp)
temp = vec[1];
if (vec[2] > temp)
temp = vec[2];
if (temp != 0.0)
temp = 1.0 / temp;
VectorScale (vec, temp, color2);
}
}
// all fields have been parsed
if (entity->classname && !strncmp (entity->classname, "light", 5)
&& !entity->light)
entity->light = DEFAULTLIGHTLEVEL;
if (entity->classname && !strncmp (entity->classname, "light", 5))
if (!entity->light)
entity->light = DEFAULTLIGHTLEVEL;
if (entity->light) {
// convert to subtraction to the brightness for the whole light,
// so it will fade nicely, rather than being clipped off
VectorScale (color2,
entity->light * 16384.0 * options.globallightscale,
color2);
entity->color[0] *= color2[0];
entity->color[1] *= color2[1];
entity->color[2] *= color2[2];
if (entity->lightradius)
entity->subbrightness = 1.0 / (entity->lightradius
* entity->lightradius
* entity->falloff
+ LIGHTDISTBIAS);
if (entity->subbrightness < (1.0 / 1048576.0))
entity->subbrightness = (1.0 / 1048576.0);
}
if (entity->classname && !strcmp (entity->classname, "light")) {
if (entity->targetname && entity->targetname[0]
@ -229,6 +338,10 @@ LoadEntities (void)
printf ("%d entities read\n", num_entities);
MatchTargets ();
WriteLights();
novislights = (entity_t **)calloc (num_entities, sizeof (entity_t *));
}
const char *
@ -268,6 +381,26 @@ FloatForKey (entity_t *ent, const char *key)
return atof (k);
}
entity_t *
FindEntityWithKeyPair (char *key, char *value)
{
entity_t *ent;
epair_t *ep;
int i;
for (i = 0; i < num_entities; i++) {
ent = &entities[i];
for (ep = ent->epairs; ep; ep = ep->next) {
if (!strcmp (ep->key, key)) {
if (!strcmp (ep->value, value))
return ent;
break;
}
}
}
return 0;
}
void
GetVectorForKey (entity_t *ent, const char *key, vec3_t vec)
{
@ -281,7 +414,6 @@ void
WriteEntitiesToString (void)
{
dstring_t *buf;
char line[128];
epair_t *ep;
int i;
@ -298,8 +430,7 @@ WriteEntitiesToString (void)
dstring_appendstr (buf, "{\n");
for (ep = entities[i].epairs; ep; ep = ep->next) {
sprintf (line, "\"%s\" \"%s\"\n", ep->key, ep->value);
dstring_appendstr (buf, line);
dasprintf (buf, "\"%s\" \"%s\"\n", ep->key, ep->value);
}
dstring_appendstr (buf, "}\n");
}

View File

@ -461,6 +461,7 @@ LightFace (int surfnum)
lightinfo_t l;
vec_t total;
vec_t *light;
lightchain_t *lightchain;
f = bsp->faces + surfnum;
@ -500,9 +501,12 @@ LightFace (int surfnum)
// cast all lights
l.numlightstyles = 0;
for (i = 0; i < num_entities; i++) {
if (entities[i].light)
SingleLightFace (&entities[i], &l);
for (lightchain = surfacelightchain[surfnum]; lightchain;
lightchain = lightchain->next) {
SingleLightFace (lightchain->light, &l);
}
for (i = 0; i < num_novislights; i++) {
SingleLightFace (novislights[i], &l);
}
FixMinlight (&l);

View File

@ -54,6 +54,7 @@ static struct option const long_options[] = {
{"version", no_argument, 0, 'V'},
{"threads", required_argument, 0, 't'},
{"extra", no_argument, 0, 'e'},
{"novis", no_argument, 0, 'N'},
{"distance", required_argument, 0, 'd'},
{"range", required_argument, 0, 'r'},
{"file", required_argument, 0, 'f'},
@ -65,6 +66,7 @@ static const char *short_options =
"v" // verbose
"h" // help
"V" // version
"N" // novis
"t:" // threads
"e" // extra sampling
"d:" // scale distance
@ -83,6 +85,7 @@ usage (int status)
" -v, --verbose Display more output than usual\n"
" -h, --help Display this help and exit\n"
" -V, --version Output version information and exit\n"
" -N, --novis Don't use vis data\n"
" -t, --threads [num] Number of threads to use\n"
" -e, --extra Apply extra sampling\n"
" -d, --distance [scale] Scale distance\n"
@ -96,11 +99,13 @@ DecodeArgs (int argc, char **argv)
{
int c;
memset (&options, 0, sizeof (options));
options.verbosity = 0;
options.threads = 1;
options.extra = false;
options.distance = 1.0;
options.range = 0.5;
options.globallightscale = 1.0;
bspfile = NULL;
while ((c = getopt_long (argc, argv, short_options, long_options, 0))
@ -115,6 +120,9 @@ DecodeArgs (int argc, char **argv)
case 'h': // help
usage (0);
break;
case 'N': // novis
options.novis = 1;
break;
case 'V': // version
printf ("%s version %s\n", PACKAGE, VERSION);
exit (0);

View File

@ -71,6 +71,7 @@ dstring_t *lightdata;
dmodel_t *bspmodel;
int bspfileface; // next surface to dispatch
int bspfileent; // next entity to dispatch
vec3_t bsp_origin;
@ -93,10 +94,25 @@ GetFileSpace (int size)
return ofs;
}
static void *
VisThread (void *junk)
{
int i;
while (1) {
LOCK;
i = bspfileent++;
UNLOCK;
if (i >= num_entities)
return 0;
VisEntity (i);
}
}
static void *
LightThread (void *junk)
{
int i;
int i;
while (1) {
LOCK;
@ -113,7 +129,11 @@ static void
LightWorld (void)
{
lightdata = dstring_new ();
surfacelightchain = (lightchain_t **) calloc (bsp->numfaces,
sizeof (lightchain_t *));
VisThread (0); // not worth threading :/
VisStats ();
RunThreadsOn (LightThread);
BSP_AddLighting (bsp, lightdata->str, lightdata->size);

239
tools/qflight/source/vis.c Normal file
View File

@ -0,0 +1,239 @@
/*
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
static __attribute__ ((unused)) const char rcsid[] =
"$Id$";
#include <stdlib.h>
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#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;
entity_t **alllights;
int num_alllights;
entity_t **novislights;
int num_novislights;
static dleaf_t *
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;
int i, j;
unsigned short *mark;
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);
DecompressVis (bsp->visdata + leaf->visofs, vis,
(bsp->numleafs + 7) >> 3);
for (i = 1, leaf = bsp->leafs + 1; i < bsp->numleafs; i++, leaf++) {
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++) {
for (j = 0; j < bsp->models[i].numfaces; j++) {
//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);
printf ("%i lights will be cast onto %i surfaces, %i casts will\n"
"be performed\n", counts.lights, bsp->numfaces, counts.cast);
}