LordHavoc's colored lighting support (not his relight stuff (yet?) though)

This commit is contained in:
Bill Currie 2003-09-10 15:48:46 +00:00
parent 392902f5af
commit 6eef62cff8
10 changed files with 366 additions and 355 deletions

View file

@ -69,7 +69,7 @@ extern int num_entities;
const char *ValueForKey (entity_t *ent, const char *key); const char *ValueForKey (entity_t *ent, const char *key);
void SetKeyValue (entity_t *ent, const char *key, const char *value); void SetKeyValue (entity_t *ent, const char *key, const char *value);
float FloatForKey (entity_t *ent, const char *key); float FloatForKey (entity_t *ent, const char *key);
entity_t *FindEntityWithKeyPair(char *key, char *value); entity_t *FindEntityWithKeyPair(const char *key, const char *value);
void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec); void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec);
void LoadEntities (void); void LoadEntities (void);

View file

@ -30,9 +30,46 @@
#ifndef __light_h #ifndef __light_h
#define __light_h #define __light_h
#include "QF/bspfile.h"
#define ON_EPSILON 0.1 #define ON_EPSILON 0.1
#define MAXLIGHTS 1024 #define MAXLIGHTS 1024
#define LIGHTDISTBIAS 65536.0 #define LIGHTDISTBIAS 65536.0
#define BOGUS_RANGE 1000000000
#define SINGLEMAP (256*256)
typedef struct {
vec3_t v;
int samplepos; // offset into lightmap contributed to
} lightpoint_t;
typedef struct {
vec3_t c;
} lightsample_t;
typedef struct {
vec_t facedist;
vec3_t facenormal;
vec3_t testlineimpact;
int numpoints;
int numsamples;
// *16 for -extra4x4
lightpoint_t point[SINGLEMAP*16];
lightsample_t sample[MAXLIGHTMAPS][SINGLEMAP];
vec3_t texorg;
vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0]
vec3_t textoworld[2]; // world = texorg + s * textoworld[0]
vec_t exactmins[2], exactmaxs[2];
int texmins[2], texsize[2];
int lightstyles[MAXLIGHTMAPS];
dface_t *face;
} lightinfo_t;
extern float scaledist; extern float scaledist;
extern float scalecos; extern float scalecos;
@ -50,10 +87,10 @@ extern qboolean extrasamples;
extern float minlights[MAX_MAP_FACES]; extern float minlights[MAX_MAP_FACES];
void LoadNodes (char *file); void LoadNodes (const char *file);
qboolean TestLine (vec3_t start, vec3_t stop); qboolean TestLine (lightinfo_t *l, vec3_t start, vec3_t stop);
void LightFace (int surfnum); void LightFace (lightinfo_t *l, int surfnum);
void LightLeaf (dleaf_t *leaf); void LightLeaf (dleaf_t *leaf);
void MakeTnodes (dmodel_t *bm); void MakeTnodes (dmodel_t *bm);
@ -66,6 +103,7 @@ void VisStats (void);
extern struct bsp_s *bsp; extern struct bsp_s *bsp;
extern struct dstring_s *lightdata; extern struct dstring_s *lightdata;
extern struct dstring_s *rgblightdata;
typedef struct lightchain_s { typedef struct lightchain_s {
struct lightchain_s *next; struct lightchain_s *next;
@ -73,6 +111,7 @@ typedef struct lightchain_s {
} lightchain_t; } lightchain_t;
extern lightchain_t **surfacelightchain; extern lightchain_t **surfacelightchain;
extern vec3_t *surfaceorgs;
extern struct entity_s **novislights; extern struct entity_s **novislights;
extern int num_novislights; extern int num_novislights;

View file

@ -35,7 +35,8 @@ typedef struct {
int verbosity; // 0=silent int verbosity; // 0=silent
int threads; int threads;
int novis; int novis;
qboolean extra; int extrabit;
vec_t extrascale;
vec_t distance; vec_t distance;
vec_t range; vec_t range;
vec_t globallightscale; vec_t globallightscale;

View file

@ -297,6 +297,9 @@ LoadEntities (void)
} }
} }
if (entity->targetname)
printf ("%s %d %d\n", entity->targetname, entity->light, entity->style);
// all fields have been parsed // all fields have been parsed
if (entity->classname && !strncmp (entity->classname, "light", 5)) if (entity->classname && !strncmp (entity->classname, "light", 5))
if (!entity->light) if (!entity->light)
@ -382,7 +385,7 @@ FloatForKey (entity_t *ent, const char *key)
} }
entity_t * entity_t *
FindEntityWithKeyPair (char *key, char *value) FindEntityWithKeyPair (const char *key, const char *value)
{ {
entity_t *ent; entity_t *ent;
epair_t *ep; epair_t *ep;

View file

@ -53,64 +53,16 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "QF/quakefs.h" #include "QF/quakefs.h"
#include "QF/sys.h" #include "QF/sys.h"
#include "compat.h"
#include "light.h" #include "light.h"
#include "entities.h" #include "entities.h"
#include "options.h" #include "options.h"
#include "threads.h" #include "threads.h"
#define SINGLEMAP (18*18*4)
typedef struct {
vec_t lightmaps[MAXLIGHTMAPS][SINGLEMAP];
int numlightstyles;
vec_t *light;
vec_t facedist;
vec3_t facenormal;
int numsurfpt;
vec3_t surfpt[SINGLEMAP];
vec3_t texorg;
vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0]
vec3_t textoworld[2]; // world = texorg + s * textoworld[0]
vec_t exactmins[2], exactmaxs[2];
int texmins[2], texsize[2];
int lightstyles[256];
int surfnum;
dface_t *face;
} lightinfo_t;
int c_bad; int c_bad;
int c_culldistplane, c_proper; int c_culldistplane, c_proper;
/*
CastRay
Returns the distance between the points, or -1 if blocked
*/
static vec_t
CastRay (vec3_t p1, vec3_t p2)
{
int i;
qboolean trace;
vec_t t;
trace = TestLine (p1, p2);
if (!trace)
return -1; // ray was blocked
t = 0;
for (i = 0; i < 3; i++)
t += (p2[i] - p1[i]) * (p2[i] - p1[i]);
if (t == 0)
t = 1; // don't blow up...
return sqrt (t);
}
/* /*
SAMPLE POINT DETERMINATION SAMPLE POINT DETERMINATION
@ -135,7 +87,7 @@ towards the center until it is valid.
Fills in texorg, worldtotex. and textoworld Fills in texorg, worldtotex. and textoworld
*/ */
static void static void
CalcFaceVectors (lightinfo_t *l) CalcFaceVectors (lightinfo_t *l, vec3_t faceorg)
{ {
texinfo_t *tex; texinfo_t *tex;
int i, j; int i, j;
@ -187,6 +139,8 @@ CalcFaceVectors (lightinfo_t *l)
l->texorg[i] = -tex->vecs[0][3] * l->textoworld[0][i] - l->texorg[i] = -tex->vecs[0][3] * l->textoworld[0][i] -
tex->vecs[1][3] * l->textoworld[1][i]; tex->vecs[1][3] * l->textoworld[1][i];
VectorAdd (l->texorg, faceorg, l->texorg);
// project back to the face plane // project back to the face plane
dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1; dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1;
dist *= distscale; dist *= distscale;
@ -210,8 +164,8 @@ CalcFaceExtents (lightinfo_t *l)
s = l->face; s = l->face;
mins[0] = mins[1] = 999999; mins[0] = mins[1] = BOGUS_RANGE;
maxs[0] = maxs[1] = -99999; maxs[0] = maxs[1] = -BOGUS_RANGE;
tex = &bsp->texinfo[s->texinfo]; tex = &bsp->texinfo[s->texinfo];
@ -223,9 +177,7 @@ CalcFaceExtents (lightinfo_t *l)
v = bsp->vertexes + bsp->edges[-e].v[1]; v = bsp->vertexes + bsp->edges[-e].v[1];
for (j = 0; j < 2; j++) { for (j = 0; j < 2; j++) {
val = v->point[0] * tex->vecs[j][0] + val = DotProduct (v->point, tex->vecs[j]) + tex->vecs[j][3];
v->point[1] * tex->vecs[j][1] +
v->point[2] * tex->vecs[j][2] + tex->vecs[j][3];
if (val < mins[j]) if (val < mins[j])
mins[j] = val; mins[j] = val;
if (val > maxs[j]) if (val > maxs[j])
@ -241,12 +193,18 @@ CalcFaceExtents (lightinfo_t *l)
maxs[i] = ceil (maxs[i] / 16); maxs[i] = ceil (maxs[i] / 16);
l->texmins[i] = mins[i]; l->texmins[i] = mins[i];
l->texsize[i] = maxs[i] - mins[i]; l->texsize[i] = maxs[i] - mins[i] + 1;
if (l->texsize[i] > 17) if (l->texsize[i] > 256)
fprintf (stderr, "Bad surface extents"); fprintf (stderr, "Bad surface extents");
} }
} }
static void
CalcSamples (lightinfo_t *l)
{
l->numsamples = l->texsize[0] * l->texsize[1];
}
/* /*
CalcPoints CalcPoints
@ -256,15 +214,14 @@ CalcFaceExtents (lightinfo_t *l)
static void static void
CalcPoints (lightinfo_t *l) CalcPoints (lightinfo_t *l)
{ {
int step, i, j , s, t, w, h; int j , s, t, w, h, realw, realh, stepbit;
vec_t mids, midt, starts, startt, us, ut; vec_t mids, midt, starts, startt, us, ut;
vec_t *surf; vec3_t facemid, v;
vec3_t facemid, move; lightpoint_t *point;
// fill in surforg // fill in surforg
// the points are biased towards the center of the surface // the points are biased towards the center of the surface
// to help avoid edge cases just inside walls // to help avoid edge cases just inside walls
surf = l->surfpt[0];
mids = (l->exactmaxs[0] + l->exactmins[0]) / 2; mids = (l->exactmaxs[0] + l->exactmins[0]) / 2;
midt = (l->exactmaxs[1] + l->exactmins[1]) / 2; midt = (l->exactmaxs[1] + l->exactmins[1]) / 2;
@ -273,67 +230,41 @@ CalcPoints (lightinfo_t *l)
l->textoworld[0][j] * mids + l->textoworld[0][j] * mids +
l->textoworld[1][j] * midt; l->textoworld[1][j] * midt;
if (extrasamples) { realw = l->texsize[0];
// extra filtering realh = l->texsize[1];
h = (l->texsize[1] + 1) * 2;
w = (l->texsize[0] + 1) * 2;
starts = (l->texmins[0] - 0.5) * 16;
startt = (l->texmins[1] - 0.5) * 16;
step = 8;
} else {
h = l->texsize[1] + 1;
w = l->texsize[0] + 1;
starts = l->texmins[0] * 16; starts = l->texmins[0] * 16;
startt = l->texmins[1] * 16; startt = l->texmins[1] * 16;
step = 16;
stepbit = 4 - options.extrabit;
w = realw << options.extrabit;
h = realh << options.extrabit;
if (stepbit < 4) {
starts -= 1 << stepbit;
startt -= 1 << stepbit;
} }
l->numsurfpt = w * h; point = l->point;
l->numpoints = w * h;
for (t = 0; t < h; t++) { for (t = 0; t < h; t++) {
for (s = 0; s < w; s++, surf += 3) { for (s = 0; s < w; s++, point++) {
us = starts + s * step; us = starts + (s << stepbit);
ut = startt + t * step; ut = startt + (t << stepbit);
point->samplepos = ((t >> options.extrabit) * realw
+ (s >> options.extrabit));
// if a line can be traced from surf to facemid,
// the point is good
for (i = 0; i < 6; i++) {
// calculate texture point // calculate texture point
for (j = 0; j < 3; j++) for (j = 0; j < 3; j++)
surf[j] = l->texorg[j] + point->v[j] = l->texorg[j] +
l->textoworld[0][j] * us + l->textoworld[0][j] * us + l->textoworld[1][j] * ut;
l->textoworld[1][j] * ut;
if (CastRay (facemid, surf) != -1) if (!TestLine (l, facemid, point->v)) {
break; // got it VectorCopy(l->testlineimpact, point->v);
if (i & 1) { VectorSubtract(facemid, point->v, v);
if (us > mids) { VectorNormalize(v);
us -= 8; VectorMultAdd (point->v, 0.25, v, point->v);
if (us < mids)
us = mids;
} else {
us += 8;
if (us > mids)
us = mids;
} }
} else {
if (ut > midt) {
ut -= 8;
if (ut < midt)
ut = midt;
} else {
ut += 8;
if (ut > midt)
ut = midt;
}
}
// move surf 8 pixels towards the center
VectorSubtract (facemid, surf, move);
_VectorNormalize (move);
VectorMultAdd (surf, 8, move, surf);
}
if (i == 2)
c_bad++;
} }
} }
} }
@ -341,69 +272,69 @@ CalcPoints (lightinfo_t *l)
static void static void
SingleLightFace (entity_t *light, lightinfo_t *l) SingleLightFace (entity_t *light, lightinfo_t *l)
{ {
int mapnum, size, c, i; int mapnum, i;
qboolean hit; qboolean hit;
vec3_t incoming, rel, spotvec; vec3_t incoming, spotvec;
vec_t add, angle, dist, falloff; vec_t add, dist, idist, lightfalloff, lightsubtract, spotcone;
vec_t *lightsamp, *surf; lightpoint_t *point;
lightsample_t *sample;
VectorSubtract (light->origin, bsp_origin, rel); dist = DotProduct (light->origin, l->facenormal) - l->facedist;
dist = options.distance * (DotProduct (rel, l->facenormal) - l->facedist); dist *= options.distance;
// don't bother with lights behind the surface // don't bother with lights behind the surface
if (dist <= 0) if (dist <= -0.25)
return; return;
lightfalloff = light->falloff;
lightsubtract = light->subbrightness;
// don't bother with light too far away // don't bother with light too far away
#if 0
if (dist > light->light) { if (dist > light->light) {
c_culldistplane++; c_culldistplane++;
return; return;
} }
#else
if (lightsubtract > (1.0 / (dist * dist * lightfalloff + LIGHTDISTBIAS))) {
c_culldistplane++;
return;
}
#endif
if (light->targetent) { for (mapnum = 0; mapnum < MAXLIGHTMAPS; mapnum++) {
VectorSubtract (light->targetent->origin, light->origin, spotvec);
_VectorNormalize (spotvec);
if (!light->angle)
falloff = -cos (20 * M_PI / 180);
else
falloff = -cos (light->angle / 2 * M_PI / 180);
} else
falloff = 0;
mapnum = 0;
for (mapnum = 0; mapnum < l->numlightstyles; mapnum++)
if (l->lightstyles[mapnum] == light->style) if (l->lightstyles[mapnum] == light->style)
break; break;
lightsamp = l->lightmaps[mapnum]; if (l->lightstyles[mapnum] == 255) {
if (mapnum == l->numlightstyles) { memset (l->sample[mapnum], 0,
// init a new light map sizeof (lightsample_t) * l->numsamples);
break;
}
}
if (mapnum == MAXLIGHTMAPS) { if (mapnum == MAXLIGHTMAPS) {
printf ("WARNING: Too many light styles on a face\n"); printf ("WARNING: Too many light styles on a face\n");
return; return;
} }
size = (l->texsize[1] + 1) * (l->texsize[0] + 1);
for (i = 0; i < size; i++) spotcone = light->spotcone;
lightsamp[i] = 0; VectorCopy(light->spotdir, spotvec);
}
// check it for real // check it for real
hit = false; hit = false;
c_proper++; c_proper++;
surf = l->surfpt[0]; for (i = 0, point = l->point; i < l->numpoints; i++, point++) {
for (c = 0; c < l->numsurfpt; c++, surf += 3) { VectorSubtract (light->origin, point->v, incoming);
dist = CastRay (light->origin, surf) * options.distance; // avoid float roundoff
if (dist < 0) dist = sqrt (DotProduct(incoming, incoming));
continue; // light doesn't reach idist = 1.0 / dist;
VectorScale (incoming, idist, incoming);
VectorSubtract (light->origin, surf, incoming);
_VectorNormalize (incoming);
angle = DotProduct (incoming, l->facenormal);
if (light->targetent) {
// spotlight cutoff // spotlight cutoff
if (DotProduct (spotvec, incoming) > falloff) if (spotcone > 0 && DotProduct (spotvec, incoming) > spotcone)
continue; continue;
} #if 0
angle = DotProduct (incoming, l->facenormal);
angle = (1.0 - scalecos) + scalecos * angle; angle = (1.0 - scalecos) + scalecos * angle;
add = light->light - dist; add = light->light - dist;
add *= angle; add *= angle;
@ -413,14 +344,35 @@ SingleLightFace (entity_t *light, lightinfo_t *l)
if (lightsamp[c] > 1) if (lightsamp[c] > 1)
// ignore real tiny lights // ignore real tiny lights
hit = true; hit = true;
#else
// LordHavoc: changed to be more realistic (entirely different
// lighting model)
// LordHavoc: use subbrightness on all lights, simply to have
//some distance culling
add = (1.0 / (dist * dist * lightfalloff + LIGHTDISTBIAS)
- lightsubtract);
if (add <= 0)
continue;
if (!TestLine (l, point->v, light->origin))
continue;
// LordHavoc: FIXME: decide this 0.5 bias based on shader properties
// (some are dull, some are shiny)
add *= (DotProduct (incoming, l->facenormal) * 0.5 + 0.5);
add *= options.extrascale;
sample = &l->sample[mapnum][point->samplepos];
VectorMultAdd (sample->c, add, light->color, sample->c);
if (!hit && ((sample->c[0] + sample->c[1] + sample->c[2]) >= 1))
hit = true;
#endif
} }
if (mapnum == l->numlightstyles && hit) { // if the style has some data now, make sure it is in the list
if (hit)
l->lightstyles[mapnum] = light->style; l->lightstyles[mapnum] = light->style;
l->numlightstyles++; // the style has some real data now
}
} }
#if 0
static void static void
FixMinlight (lightinfo_t *l) FixMinlight (lightinfo_t *l)
{ {
@ -450,113 +402,102 @@ FixMinlight (lightinfo_t *l)
l->lightmaps[i][j] = minlight; l->lightmaps[i][j] = minlight;
} }
} }
#endif
void void
LightFace (int surfnum) LightFace (lightinfo_t *l, int surfnum)
{ {
int ofs; byte *out, *lit;
byte *out, *outdata; byte *outdata, *rgbdata;
dface_t *f; dface_t *f;
int lightmapwidth, lightmapsize, size, c, i, j, s, t, w, h; int i, j, ofs, size;
lightinfo_t l; int red, green, blue, white;
vec_t total;
vec_t *light;
lightchain_t *lightchain; lightchain_t *lightchain;
lightsample_t *sample;
memset (l, 0, sizeof(lightinfo_t));
f = bsp->faces + surfnum; f = bsp->faces + surfnum;
l->face = f;
// some surfaces don't need lightmaps // some surfaces don't need lightmaps
f->lightofs = -1; f->lightofs = -1;
for (j = 0; j < MAXLIGHTMAPS; j++) for (i = 0; i < MAXLIGHTMAPS; i++)
f->styles[j] = 255; f->styles[i] = l->lightstyles[i] = 255;
if (bsp->texinfo[f->texinfo].flags & TEX_SPECIAL) if (bsp->texinfo[f->texinfo].flags & TEX_SPECIAL)
// non-lit texture // non-lit texture
return; return;
memset(&l, 0, sizeof (l));
l.surfnum = surfnum;
l.face = f;
// rotate plane // rotate plane
VectorCopy (bsp->planes[f->planenum].normal, l.facenormal); VectorCopy (bsp->planes[f->planenum].normal, l->facenormal);
l.facedist = bsp->planes[f->planenum].dist; l->facedist = bsp->planes[f->planenum].dist;
if (f->side) { if (f->side) {
VectorNegate (l.facenormal, l.facenormal); VectorNegate (l->facenormal, l->facenormal);
l.facedist = -l.facedist; l->facedist = -l->facedist;
} }
CalcFaceVectors (&l); CalcFaceVectors (l, surfaceorgs[surfnum]);
CalcFaceExtents (&l); CalcFaceExtents (l);
CalcPoints (&l); CalcSamples (l);
CalcPoints (l);
lightmapwidth = l.texsize[0] + 1; if (l->numsamples > SINGLEMAP)
size = lightmapwidth * (l.texsize[1] + 1);
if (size > SINGLEMAP)
fprintf (stderr, "Bad lightmap size"); fprintf (stderr, "Bad lightmap size");
for (i = 0; i < MAXLIGHTMAPS; i++)
l.lightstyles[i] = 255;
// cast all lights // cast all lights
l.numlightstyles = 0;
for (lightchain = surfacelightchain[surfnum]; lightchain; for (lightchain = surfacelightchain[surfnum]; lightchain;
lightchain = lightchain->next) { lightchain = lightchain->next) {
SingleLightFace (lightchain->light, &l); SingleLightFace (lightchain->light, l);
} }
for (i = 0; i < num_novislights; i++) { for (i = 0; i < num_novislights; i++) {
SingleLightFace (novislights[i], &l); SingleLightFace (novislights[i], l);
} }
FixMinlight (&l); //FixMinlight (&l);
if (!l.numlightstyles) for (i = 0; i < MAXLIGHTMAPS; i++)
// no light hitting it if (l->lightstyles[i] == 255)
break;
size = l->numsamples * i;
if (!size) {
// no light styles
return; return;
}
// save out the values // save out the values
for (i = 0; i < MAXLIGHTMAPS; i++) for (i = 0; i < MAXLIGHTMAPS; i++)
f->styles[i] = l.lightstyles[i]; f->styles[i] = l->lightstyles[i];
lightmapsize = size * l.numlightstyles;
LOCK; LOCK;
outdata = out = malloc (lightmapsize); outdata = out = malloc (size * 4);
UNLOCK; UNLOCK;
ofs = GetFileSpace (lightmapsize); rgbdata = lit = outdata + size;
ofs = GetFileSpace (size);
f->lightofs = ofs; f->lightofs = ofs;
// extra filtering for (i = 0; i < MAXLIGHTMAPS && f->styles[i] != 255; i++) {
h = (l.texsize[1] + 1) * 2; for (j = 0, sample = l->sample[i]; j < l->numsamples; j++, sample++) {
w = (l.texsize[0] + 1) * 2; red = (int) sample->c[0];
green = (int) sample->c[1];
blue = (int) sample->c[2];
white = (int) ((sample->c[0] + sample->c[1] + sample->c[2])
* (1.0 / 3.0));
for (i = 0; i < l.numlightstyles; i++) { red = bound (0, red, 255);
if (l.lightstyles[i] == 0xff) green = bound (0, green, 255);
fprintf (stderr, "Wrote empty lightmap"); blue = bound (0, blue, 255);
light = l.lightmaps[i]; white = bound (0, white, 255);
c = 0; *lit++ = red;
for (t = 0; t <= l.texsize[1]; t++) *lit++ = green;
for (s = 0; s <= l.texsize[0]; s++, c++) { *lit++ = blue;
if (extrasamples) { *out++ = white;
// filtered sample
total = light[t * 2 * w + s * 2] +
light[t * 2 * w + s * 2 + 1] +
light[(t * 2 + 1) * w + s * 2] +
light[(t * 2 + 1) * w + s * 2 + 1];
total *= 0.25;
} else
total = light[c];
total *= options.range; // scale before clamping
if (total > 255)
total = 255;
if (total < 0)
fprintf (stderr, "light < 0");
*out++ = total;
} }
} }
LOCK; LOCK;
memcpy (lightdata->str + ofs, outdata, lightmapsize); memcpy (lightdata->str + ofs, outdata, size);
memcpy (rgblightdata->str + ofs * 3, rgbdata, size * 3);
free (outdata); free (outdata);
UNLOCK; UNLOCK;
} }

View file

@ -43,6 +43,8 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "QF/qtypes.h" #include "QF/qtypes.h"
#include "compat.h"
#include "options.h" #include "options.h"
const char *this_program; const char *this_program;
@ -53,7 +55,7 @@ static struct option const long_options[] = {
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'}, {"version", no_argument, 0, 'V'},
{"threads", required_argument, 0, 't'}, {"threads", required_argument, 0, 't'},
{"extra", no_argument, 0, 'e'}, {"extra", required_argument, 0, 'e'},
{"novis", no_argument, 0, 'N'}, {"novis", no_argument, 0, 'N'},
{"distance", required_argument, 0, 'd'}, {"distance", required_argument, 0, 'd'},
{"range", required_argument, 0, 'r'}, {"range", required_argument, 0, 'r'},
@ -68,7 +70,7 @@ static const char *short_options =
"V" // version "V" // version
"N" // novis "N" // novis
"t:" // threads "t:" // threads
"e" // extra sampling "e:" // extra sampling
"d:" // scale distance "d:" // scale distance
"r:" // scale range "r:" // scale range
"f:" "f:"
@ -87,7 +89,7 @@ usage (int status)
" -V, --version Output version information and exit\n" " -V, --version Output version information and exit\n"
" -N, --novis Don't use vis data\n" " -N, --novis Don't use vis data\n"
" -t, --threads [num] Number of threads to use\n" " -t, --threads [num] Number of threads to use\n"
" -e, --extra Apply extra sampling\n" " -e, --extra [num] Apply extra sampling\n"
" -d, --distance [scale] Scale distance\n" " -d, --distance [scale] Scale distance\n"
" -r, --range [scale] Scale range\n" " -r, --range [scale] Scale range\n"
" -f, --file [bspfile] BSP file\n\n"); " -f, --file [bspfile] BSP file\n\n");
@ -102,7 +104,6 @@ DecodeArgs (int argc, char **argv)
memset (&options, 0, sizeof (options)); memset (&options, 0, sizeof (options));
options.verbosity = 0; options.verbosity = 0;
options.threads = 1; options.threads = 1;
options.extra = false;
options.distance = 1.0; options.distance = 1.0;
options.range = 0.5; options.range = 0.5;
options.globallightscale = 1.0; options.globallightscale = 1.0;
@ -131,7 +132,8 @@ DecodeArgs (int argc, char **argv)
options.threads = atoi (optarg); options.threads = atoi (optarg);
break; break;
case 'e': // extra case 'e': // extra
options.extra = true; options.extrabit = atoi (optarg);
options.extrabit = bound (0, options.extrabit, 2);
break; break;
case 'd': // scale distance case 'd': // scale distance
options.distance = atof (optarg); options.distance = atof (optarg);
@ -146,6 +148,7 @@ DecodeArgs (int argc, char **argv)
usage (1); usage (1);
} }
} }
options.extrascale = 1.0 / (1 << (options.extrabit * 2));
if ((!bspfile) && argv[optind] && *(argv[optind])) if ((!bspfile) && argv[optind] && *(argv[optind]))
bspfile = strdup (argv[optind++]); bspfile = strdup (argv[optind++]);

View file

@ -54,6 +54,7 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "QF/qtypes.h" #include "QF/qtypes.h"
#include "QF/quakefs.h" #include "QF/quakefs.h"
#include "QF/sys.h" #include "QF/sys.h"
#include "QF/va.h"
#include "light.h" #include "light.h"
#include "threads.h" #include "threads.h"
@ -64,10 +65,12 @@ options_t options;
bsp_t *bsp; bsp_t *bsp;
char *bspfile; char *bspfile;
dstring_t *litfile;
float scalecos = 0.5; float scalecos = 0.5;
dstring_t *lightdata; dstring_t *lightdata;
dstring_t *rgblightdata;
dmodel_t *bspmodel; dmodel_t *bspmodel;
int bspfileface; // next surface to dispatch int bspfileface; // next surface to dispatch
@ -90,6 +93,9 @@ GetFileSpace (int size)
ofs = lightdata->size; ofs = lightdata->size;
lightdata->size += size; lightdata->size += size;
dstring_adjust (lightdata); dstring_adjust (lightdata);
rgblightdata->size = (ofs + size) * 3;
dstring_adjust (rgblightdata);
UNLOCK; UNLOCK;
return ofs; return ofs;
} }
@ -110,7 +116,7 @@ VisThread (void *junk)
} }
static void * static void *
LightThread (void *junk) LightThread (void *l)
{ {
int i; int i;
@ -121,16 +127,37 @@ LightThread (void *junk)
if (i >= bsp->numfaces) if (i >= bsp->numfaces)
return 0; return 0;
LightFace (i); printf ("%5d / %d\r", i, bsp->numfaces);
fflush (stdout);
LightFace (l, i);
} }
} }
static void static void
LightWorld (void) LightWorld (void)
{ {
int i, j;
vec3_t org;
entity_t *ent;
const char *name;
lightdata = dstring_new (); lightdata = dstring_new ();
rgblightdata = dstring_new ();
surfacelightchain = (lightchain_t **) calloc (bsp->numfaces, surfacelightchain = (lightchain_t **) calloc (bsp->numfaces,
sizeof (lightchain_t *)); sizeof (lightchain_t *));
surfaceorgs = (vec3_t *) calloc (bsp->numfaces, sizeof (vec3_t));
for (i = 1; i < bsp->nummodels; i++) {
ent = FindEntityWithKeyPair ("model", name = va ("*%d", i));
VectorZero (org);
if (!ent)
Sys_Error ("FindFaceOffsets: Couldn't find entity for model %s.\n",
name);
if (!strncmp (ValueForKey (ent, "classname"), "rotate_", 7))
GetVectorForKey (ent, "origin", org);
for (j = 0; j < bsp->models[i].numfaces; j++)
VectorCopy (org, surfaceorgs[i]);
}
VisThread (0); // not worth threading :/ VisThread (0); // not worth threading :/
VisStats (); VisStats ();
@ -146,6 +173,7 @@ int
main (int argc, char **argv) main (int argc, char **argv)
{ {
double start, stop; double start, stop;
char *e;
QFile *f; QFile *f;
start = Sys_DoubleTime (); start = Sys_DoubleTime ();
@ -164,6 +192,11 @@ main (int argc, char **argv)
QFS_StripExtension (bspfile, bspfile); QFS_StripExtension (bspfile, bspfile);
QFS_DefaultExtension (bspfile, ".bsp"); QFS_DefaultExtension (bspfile, ".bsp");
litfile = dstring_new ();
dstring_copystr (litfile, bspfile);
e = strrchr (litfile->str, '.');
dstring_replace (litfile, e - litfile->str, -1, ".lit", 5);
f = Qopen (bspfile, "rb"); f = Qopen (bspfile, "rb");
bsp = LoadBSPFile (f, Qfilesize (f)); bsp = LoadBSPFile (f, Qfilesize (f));
Qclose (f); Qclose (f);
@ -179,6 +212,12 @@ main (int argc, char **argv)
WriteBSPFile (bsp, f); WriteBSPFile (bsp, f);
Qclose (f); Qclose (f);
dstring_insert (rgblightdata, 0, "QLIT\x01\x00\x00\x00", 8);
f = Qopen (litfile->str, "wb");
Qwrite (f, rgblightdata->str, rgblightdata->size);
Qclose (f);
stop = Sys_DoubleTime (); stop = Sys_DoubleTime ();
if (options.verbosity >= 0) if (options.verbosity >= 0)

View file

@ -1,5 +1,5 @@
/* /*
trace.c threads.c
(description) (description)
@ -49,6 +49,7 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "QF/qtypes.h" #include "QF/qtypes.h"
#include "QF/qendian.h" #include "QF/qendian.h"
#include "light.h"
#include "options.h" #include "options.h"
#include "threads.h" #include "threads.h"
@ -82,6 +83,7 @@ RunThreadsOn (threadfunc_t *func)
pthread_t work_threads[256]; pthread_t work_threads[256];
void *status; void *status;
pthread_attr_t attrib; pthread_attr_t attrib;
lightinfo_t *l[256];
long i; long i;
if (pthread_attr_init (&attrib) == -1) if (pthread_attr_init (&attrib) == -1)
@ -90,17 +92,20 @@ RunThreadsOn (threadfunc_t *func)
fprintf (stderr, "pthread_attr_setstacksize failed"); fprintf (stderr, "pthread_attr_setstacksize failed");
for (i = 0; i < options.threads; i++) { for (i = 0; i < options.threads; i++) {
if (pthread_create (&work_threads[i], &attrib, func, l[i] = malloc (sizeof (lightinfo_t));
(void *) i) == -1) if (pthread_create (&work_threads[i], &attrib, func, l[i]) == -1)
fprintf (stderr, "pthread_create failed"); fprintf (stderr, "pthread_create failed");
} }
for (i = 0; i < options.threads; i++) { for (i = 0; i < options.threads; i++) {
if (pthread_join (work_threads[i], &status) == -1) if (pthread_join (work_threads[i], &status) == -1)
fprintf (stderr, "pthread_join failed"); fprintf (stderr, "pthread_join failed");
free (l[i]);
} }
return;
} }
#endif #endif
func (NULL); else {
lightinfo_t *l = malloc (sizeof (lightinfo_t));
func (l);
}
} }

View file

@ -123,102 +123,81 @@ MakeTnodes (dmodel_t *bm)
MakeTnode (0); MakeTnode (0);
} }
qboolean /* LordHavoc: this function operates by doing depth-first front-to-back
TestLine (vec3_t start, vec3_t stop) recursion through the BSP tree, checking at every split for a empty to
solid transition (impact) in the children, and returns false if one is
found.
note: 'no impact' does not mean it is empty, it occurs when there is no
transition from empty to solid; all solid or a transition from solid to
empty are not considered impacts. (this does mean that tracing is not
symmetrical; point A to point B may have different results than point B to
point A, if either start in solid)
*/
#define TESTLINESTATE_BLOCKED 0
#define TESTLINESTATE_EMPTY 1
#define TESTLINESTATE_SOLID 2
static qboolean
RecursiveTestLine (lightinfo_t *l, int num, vec3_t p1, vec3_t p2)
{ {
float front, back, frontx, fronty, frontz, backx, backy, backz; int side, ret;
int node, side; vec_t t1, t2, frac;
tracestack_t *tstack_p; vec3_t mid;
tracestack_t tracestack[64];
tnode_t *tnode; tnode_t *tnode;
frontx = start[0]; // check for empty
fronty = start[1]; loc0:
frontz = start[2]; if (num < 0) {
backx = stop[0]; if (num == CONTENTS_SOLID)
backy = stop[1]; return TESTLINESTATE_SOLID;
backz = stop[2]; else
return TESTLINESTATE_EMPTY;
tstack_p = tracestack;
node = 0;
while (1) {
while (node < 0 && node != CONTENTS_SOLID) {
// pop up the stack for a back side
tstack_p--;
if (tstack_p < tracestack)
return true;
node = tstack_p->node;
// set the hit point for this plane
frontx = backx;
fronty = backy;
frontz = backz;
// go down the back side
backx = tstack_p->backpt[0];
backy = tstack_p->backpt[1];
backz = tstack_p->backpt[2];
node = tnodes[tstack_p->node].children[!tstack_p->side];
} }
if (node == CONTENTS_SOLID) // find the point distances
return false; // DONE! tnode = tnodes + num;
tnode = &tnodes[node]; if (tnode->type < 3) {
t1 = p1[tnode->type] - tnode->dist;
switch (tnode->type) { t2 = p2[tnode->type] - tnode->dist;
case PLANE_X: } else {
front = frontx - tnode->dist; t1 = DotProduct (tnode->normal, p1) - tnode->dist;
back = backx - tnode->dist; t2 = DotProduct (tnode->normal, p2) - tnode->dist;
break;
case PLANE_Y:
front = fronty - tnode->dist;
back = backy - tnode->dist;
break;
case PLANE_Z:
front = frontz - tnode->dist;
back = backz - tnode->dist;
break;
default:
front = (frontx * tnode->normal[0] +
fronty * tnode->normal[1] +
frontz * tnode->normal[2]) - tnode->dist;
back = (backx * tnode->normal[0] +
backy * tnode->normal[1] +
backz * tnode->normal[2]) - tnode->dist;
break;
} }
if (front > -ON_EPSILON && back > -ON_EPSILON) { if (t1 >= 0) {
// if (front > 0 && back > 0) { if (t2 >= 0) {
node = tnode->children[0]; num = tnode->children[0];
continue; goto loc0;
}
side = 0;
} else {
if (t2 < 0) {
num = tnode->children[1];
goto loc0;
}
side = 1;
} }
if (front < ON_EPSILON && back < ON_EPSILON) { frac = t1 / (t1 - t2);
// if (front <= 0 && back <= 0) { mid[0] = p1[0] + frac * (p2[0] - p1[0]);
node = tnode->children[1]; mid[1] = p1[1] + frac * (p2[1] - p1[1]);
continue; mid[2] = p1[2] + frac * (p2[2] - p1[2]);
// front side first
ret = RecursiveTestLine (l, tnode->children[side], p1, mid);
if (ret != TESTLINESTATE_EMPTY)
return ret; // solid or blocked
ret = RecursiveTestLine (l, tnode->children[!side], mid, p2);
if (ret != TESTLINESTATE_SOLID)
return ret; // empty or blocked
VectorCopy (mid, l->testlineimpact);
return TESTLINESTATE_BLOCKED;
} }
side = front < 0; qboolean
TestLine (lightinfo_t *l, vec3_t start, vec3_t end)
front = front / (front - back); {
return RecursiveTestLine (l, 0, start, end) != TESTLINESTATE_BLOCKED;
tstack_p->node = node;
tstack_p->side = side;
tstack_p->backpt[0] = backx;
tstack_p->backpt[1] = backy;
tstack_p->backpt[2] = backz;
tstack_p++;
backx = frontx + front * (backx - frontx);
backy = fronty + front * (backy - fronty);
backz = frontz + front * (backz - frontz);
node = tnode->children[side];
}
} }

View file

@ -65,6 +65,7 @@ static struct {
static lightchain_t *free_lightchains; static lightchain_t *free_lightchains;
lightchain_t **surfacelightchain; lightchain_t **surfacelightchain;
vec3_t *surfaceorgs;
entity_t **alllights; entity_t **alllights;
int num_alllights; int num_alllights;
entity_t **novislights; entity_t **novislights;