mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-23 04:42:32 +00:00
LordHavoc's colored lighting support (not his relight stuff (yet?) though)
This commit is contained in:
parent
392902f5af
commit
6eef62cff8
10 changed files with 366 additions and 355 deletions
|
@ -69,7 +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);
|
||||
entity_t *FindEntityWithKeyPair(const char *key, const char *value);
|
||||
void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec);
|
||||
|
||||
void LoadEntities (void);
|
||||
|
|
|
@ -30,9 +30,46 @@
|
|||
#ifndef __light_h
|
||||
#define __light_h
|
||||
|
||||
#include "QF/bspfile.h"
|
||||
|
||||
#define ON_EPSILON 0.1
|
||||
#define MAXLIGHTS 1024
|
||||
#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 scalecos;
|
||||
|
@ -50,10 +87,10 @@ extern qboolean extrasamples;
|
|||
|
||||
extern float minlights[MAX_MAP_FACES];
|
||||
|
||||
void LoadNodes (char *file);
|
||||
qboolean TestLine (vec3_t start, vec3_t stop);
|
||||
void LoadNodes (const char *file);
|
||||
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 MakeTnodes (dmodel_t *bm);
|
||||
|
@ -66,6 +103,7 @@ void VisStats (void);
|
|||
|
||||
extern struct bsp_s *bsp;
|
||||
extern struct dstring_s *lightdata;
|
||||
extern struct dstring_s *rgblightdata;
|
||||
|
||||
typedef struct lightchain_s {
|
||||
struct lightchain_s *next;
|
||||
|
@ -73,6 +111,7 @@ typedef struct lightchain_s {
|
|||
} lightchain_t;
|
||||
|
||||
extern lightchain_t **surfacelightchain;
|
||||
extern vec3_t *surfaceorgs;
|
||||
extern struct entity_s **novislights;
|
||||
extern int num_novislights;
|
||||
|
||||
|
|
|
@ -35,7 +35,8 @@ typedef struct {
|
|||
int verbosity; // 0=silent
|
||||
int threads;
|
||||
int novis;
|
||||
qboolean extra;
|
||||
int extrabit;
|
||||
vec_t extrascale;
|
||||
vec_t distance;
|
||||
vec_t range;
|
||||
vec_t globallightscale;
|
||||
|
|
|
@ -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
|
||||
if (entity->classname && !strncmp (entity->classname, "light", 5))
|
||||
if (!entity->light)
|
||||
|
@ -382,7 +385,7 @@ FloatForKey (entity_t *ent, const char *key)
|
|||
}
|
||||
|
||||
entity_t *
|
||||
FindEntityWithKeyPair (char *key, char *value)
|
||||
FindEntityWithKeyPair (const char *key, const char *value)
|
||||
{
|
||||
entity_t *ent;
|
||||
epair_t *ep;
|
||||
|
|
|
@ -53,64 +53,16 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "QF/quakefs.h"
|
||||
#include "QF/sys.h"
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include "light.h"
|
||||
#include "entities.h"
|
||||
#include "options.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_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
|
||||
|
||||
|
@ -135,7 +87,7 @@ towards the center until it is valid.
|
|||
Fills in texorg, worldtotex. and textoworld
|
||||
*/
|
||||
static void
|
||||
CalcFaceVectors (lightinfo_t *l)
|
||||
CalcFaceVectors (lightinfo_t *l, vec3_t faceorg)
|
||||
{
|
||||
texinfo_t *tex;
|
||||
int i, j;
|
||||
|
@ -187,6 +139,8 @@ CalcFaceVectors (lightinfo_t *l)
|
|||
l->texorg[i] = -tex->vecs[0][3] * l->textoworld[0][i] -
|
||||
tex->vecs[1][3] * l->textoworld[1][i];
|
||||
|
||||
VectorAdd (l->texorg, faceorg, l->texorg);
|
||||
|
||||
// project back to the face plane
|
||||
dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1;
|
||||
dist *= distscale;
|
||||
|
@ -210,8 +164,8 @@ CalcFaceExtents (lightinfo_t *l)
|
|||
|
||||
s = l->face;
|
||||
|
||||
mins[0] = mins[1] = 999999;
|
||||
maxs[0] = maxs[1] = -99999;
|
||||
mins[0] = mins[1] = BOGUS_RANGE;
|
||||
maxs[0] = maxs[1] = -BOGUS_RANGE;
|
||||
|
||||
tex = &bsp->texinfo[s->texinfo];
|
||||
|
||||
|
@ -223,9 +177,7 @@ CalcFaceExtents (lightinfo_t *l)
|
|||
v = bsp->vertexes + bsp->edges[-e].v[1];
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
val = v->point[0] * tex->vecs[j][0] +
|
||||
v->point[1] * tex->vecs[j][1] +
|
||||
v->point[2] * tex->vecs[j][2] + tex->vecs[j][3];
|
||||
val = DotProduct (v->point, tex->vecs[j]) + tex->vecs[j][3];
|
||||
if (val < mins[j])
|
||||
mins[j] = val;
|
||||
if (val > maxs[j])
|
||||
|
@ -241,12 +193,18 @@ CalcFaceExtents (lightinfo_t *l)
|
|||
maxs[i] = ceil (maxs[i] / 16);
|
||||
|
||||
l->texmins[i] = mins[i];
|
||||
l->texsize[i] = maxs[i] - mins[i];
|
||||
if (l->texsize[i] > 17)
|
||||
l->texsize[i] = maxs[i] - mins[i] + 1;
|
||||
if (l->texsize[i] > 256)
|
||||
fprintf (stderr, "Bad surface extents");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CalcSamples (lightinfo_t *l)
|
||||
{
|
||||
l->numsamples = l->texsize[0] * l->texsize[1];
|
||||
}
|
||||
|
||||
/*
|
||||
CalcPoints
|
||||
|
||||
|
@ -256,15 +214,14 @@ CalcFaceExtents (lightinfo_t *l)
|
|||
static void
|
||||
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 *surf;
|
||||
vec3_t facemid, move;
|
||||
vec3_t facemid, v;
|
||||
lightpoint_t *point;
|
||||
|
||||
// fill in surforg
|
||||
// the points are biased towards the center of the surface
|
||||
// to help avoid edge cases just inside walls
|
||||
surf = l->surfpt[0];
|
||||
mids = (l->exactmaxs[0] + l->exactmins[0]) / 2;
|
||||
midt = (l->exactmaxs[1] + l->exactmins[1]) / 2;
|
||||
|
||||
|
@ -273,67 +230,41 @@ CalcPoints (lightinfo_t *l)
|
|||
l->textoworld[0][j] * mids +
|
||||
l->textoworld[1][j] * midt;
|
||||
|
||||
if (extrasamples) {
|
||||
// extra filtering
|
||||
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;
|
||||
startt = l->texmins[1] * 16;
|
||||
step = 16;
|
||||
realw = l->texsize[0];
|
||||
realh = l->texsize[1];
|
||||
starts = l->texmins[0] * 16;
|
||||
startt = l->texmins[1] * 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 (s = 0; s < w; s++, surf += 3) {
|
||||
us = starts + s * step;
|
||||
ut = startt + t * step;
|
||||
for (s = 0; s < w; s++, point++) {
|
||||
us = starts + (s << stepbit);
|
||||
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
|
||||
for (j = 0; j < 3; j++)
|
||||
surf[j] = l->texorg[j] +
|
||||
l->textoworld[0][j] * us +
|
||||
l->textoworld[1][j] * ut;
|
||||
for (j = 0; j < 3; j++)
|
||||
point->v[j] = l->texorg[j] +
|
||||
l->textoworld[0][j] * us + l->textoworld[1][j] * ut;
|
||||
|
||||
if (CastRay (facemid, surf) != -1)
|
||||
break; // got it
|
||||
if (i & 1) {
|
||||
if (us > mids) {
|
||||
us -= 8;
|
||||
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 (!TestLine (l, facemid, point->v)) {
|
||||
VectorCopy(l->testlineimpact, point->v);
|
||||
VectorSubtract(facemid, point->v, v);
|
||||
VectorNormalize(v);
|
||||
VectorMultAdd (point->v, 0.25, v, point->v);
|
||||
}
|
||||
if (i == 2)
|
||||
c_bad++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -341,86 +272,107 @@ CalcPoints (lightinfo_t *l)
|
|||
static void
|
||||
SingleLightFace (entity_t *light, lightinfo_t *l)
|
||||
{
|
||||
int mapnum, size, c, i;
|
||||
int mapnum, i;
|
||||
qboolean hit;
|
||||
vec3_t incoming, rel, spotvec;
|
||||
vec_t add, angle, dist, falloff;
|
||||
vec_t *lightsamp, *surf;
|
||||
vec3_t incoming, spotvec;
|
||||
vec_t add, dist, idist, lightfalloff, lightsubtract, spotcone;
|
||||
lightpoint_t *point;
|
||||
lightsample_t *sample;
|
||||
|
||||
VectorSubtract (light->origin, bsp_origin, rel);
|
||||
dist = options.distance * (DotProduct (rel, l->facenormal) - l->facedist);
|
||||
dist = DotProduct (light->origin, l->facenormal) - l->facedist;
|
||||
dist *= options.distance;
|
||||
|
||||
// don't bother with lights behind the surface
|
||||
if (dist <= 0)
|
||||
if (dist <= -0.25)
|
||||
return;
|
||||
|
||||
lightfalloff = light->falloff;
|
||||
lightsubtract = light->subbrightness;
|
||||
|
||||
// don't bother with light too far away
|
||||
#if 0
|
||||
if (dist > light->light) {
|
||||
c_culldistplane++;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (lightsubtract > (1.0 / (dist * dist * lightfalloff + LIGHTDISTBIAS))) {
|
||||
c_culldistplane++;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (light->targetent) {
|
||||
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)
|
||||
break;
|
||||
lightsamp = l->lightmaps[mapnum];
|
||||
if (mapnum == l->numlightstyles) {
|
||||
// init a new light map
|
||||
if (mapnum == MAXLIGHTMAPS) {
|
||||
printf ("WARNING: Too many light styles on a face\n");
|
||||
return;
|
||||
}
|
||||
size = (l->texsize[1] + 1) * (l->texsize[0] + 1);
|
||||
for (i = 0; i < size; i++)
|
||||
lightsamp[i] = 0;
|
||||
for (mapnum = 0; mapnum < MAXLIGHTMAPS; mapnum++) {
|
||||
if (l->lightstyles[mapnum] == light->style)
|
||||
break;
|
||||
if (l->lightstyles[mapnum] == 255) {
|
||||
memset (l->sample[mapnum], 0,
|
||||
sizeof (lightsample_t) * l->numsamples);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mapnum == MAXLIGHTMAPS) {
|
||||
printf ("WARNING: Too many light styles on a face\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// check it for real
|
||||
hit = false;
|
||||
c_proper++;
|
||||
spotcone = light->spotcone;
|
||||
VectorCopy(light->spotdir, spotvec);
|
||||
|
||||
surf = l->surfpt[0];
|
||||
for (c = 0; c < l->numsurfpt; c++, surf += 3) {
|
||||
dist = CastRay (light->origin, surf) * options.distance;
|
||||
if (dist < 0)
|
||||
continue; // light doesn't reach
|
||||
// check it for real
|
||||
hit = false;
|
||||
c_proper++;
|
||||
|
||||
VectorSubtract (light->origin, surf, incoming);
|
||||
_VectorNormalize (incoming);
|
||||
angle = DotProduct (incoming, l->facenormal);
|
||||
if (light->targetent) {
|
||||
// spotlight cutoff
|
||||
if (DotProduct (spotvec, incoming) > falloff)
|
||||
continue;
|
||||
}
|
||||
for (i = 0, point = l->point; i < l->numpoints; i++, point++) {
|
||||
VectorSubtract (light->origin, point->v, incoming);
|
||||
// avoid float roundoff
|
||||
dist = sqrt (DotProduct(incoming, incoming));
|
||||
idist = 1.0 / dist;
|
||||
VectorScale (incoming, idist, incoming);
|
||||
|
||||
angle = (1.0 - scalecos) + scalecos * angle;
|
||||
add = light->light - dist;
|
||||
add *= angle;
|
||||
if (add < 0)
|
||||
continue;
|
||||
lightsamp[c] += add;
|
||||
if (lightsamp[c] > 1)
|
||||
// ignore real tiny lights
|
||||
hit = true;
|
||||
}
|
||||
// spotlight cutoff
|
||||
if (spotcone > 0 && DotProduct (spotvec, incoming) > spotcone)
|
||||
continue;
|
||||
#if 0
|
||||
angle = DotProduct (incoming, l->facenormal);
|
||||
angle = (1.0 - scalecos) + scalecos * angle;
|
||||
add = light->light - dist;
|
||||
add *= angle;
|
||||
if (add < 0)
|
||||
continue;
|
||||
lightsamp[c] += add;
|
||||
if (lightsamp[c] > 1)
|
||||
// ignore real tiny lights
|
||||
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;
|
||||
|
||||
if (mapnum == l->numlightstyles && hit) {
|
||||
l->lightstyles[mapnum] = light->style;
|
||||
l->numlightstyles++; // the style has some real data now
|
||||
}
|
||||
// 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 the style has some data now, make sure it is in the list
|
||||
if (hit)
|
||||
l->lightstyles[mapnum] = light->style;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
FixMinlight (lightinfo_t *l)
|
||||
{
|
||||
|
@ -450,113 +402,102 @@ FixMinlight (lightinfo_t *l)
|
|||
l->lightmaps[i][j] = minlight;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
LightFace (int surfnum)
|
||||
LightFace (lightinfo_t *l, int surfnum)
|
||||
{
|
||||
int ofs;
|
||||
byte *out, *outdata;
|
||||
dface_t *f;
|
||||
int lightmapwidth, lightmapsize, size, c, i, j, s, t, w, h;
|
||||
lightinfo_t l;
|
||||
vec_t total;
|
||||
vec_t *light;
|
||||
byte *out, *lit;
|
||||
byte *outdata, *rgbdata;
|
||||
dface_t *f;
|
||||
int i, j, ofs, size;
|
||||
int red, green, blue, white;
|
||||
lightchain_t *lightchain;
|
||||
lightsample_t *sample;
|
||||
|
||||
memset (l, 0, sizeof(lightinfo_t));
|
||||
|
||||
f = bsp->faces + surfnum;
|
||||
|
||||
l->face = f;
|
||||
|
||||
// some surfaces don't need lightmaps
|
||||
f->lightofs = -1;
|
||||
for (j = 0; j < MAXLIGHTMAPS; j++)
|
||||
f->styles[j] = 255;
|
||||
for (i = 0; i < MAXLIGHTMAPS; i++)
|
||||
f->styles[i] = l->lightstyles[i] = 255;
|
||||
|
||||
if (bsp->texinfo[f->texinfo].flags & TEX_SPECIAL)
|
||||
// non-lit texture
|
||||
return;
|
||||
|
||||
memset(&l, 0, sizeof (l));
|
||||
l.surfnum = surfnum;
|
||||
l.face = f;
|
||||
|
||||
// rotate plane
|
||||
VectorCopy (bsp->planes[f->planenum].normal, l.facenormal);
|
||||
l.facedist = bsp->planes[f->planenum].dist;
|
||||
VectorCopy (bsp->planes[f->planenum].normal, l->facenormal);
|
||||
l->facedist = bsp->planes[f->planenum].dist;
|
||||
if (f->side) {
|
||||
VectorNegate (l.facenormal, l.facenormal);
|
||||
l.facedist = -l.facedist;
|
||||
VectorNegate (l->facenormal, l->facenormal);
|
||||
l->facedist = -l->facedist;
|
||||
}
|
||||
|
||||
CalcFaceVectors (&l);
|
||||
CalcFaceExtents (&l);
|
||||
CalcPoints (&l);
|
||||
CalcFaceVectors (l, surfaceorgs[surfnum]);
|
||||
CalcFaceExtents (l);
|
||||
CalcSamples (l);
|
||||
CalcPoints (l);
|
||||
|
||||
lightmapwidth = l.texsize[0] + 1;
|
||||
|
||||
size = lightmapwidth * (l.texsize[1] + 1);
|
||||
if (size > SINGLEMAP)
|
||||
if (l->numsamples > SINGLEMAP)
|
||||
fprintf (stderr, "Bad lightmap size");
|
||||
|
||||
for (i = 0; i < MAXLIGHTMAPS; i++)
|
||||
l.lightstyles[i] = 255;
|
||||
|
||||
// cast all lights
|
||||
l.numlightstyles = 0;
|
||||
for (lightchain = surfacelightchain[surfnum]; lightchain;
|
||||
lightchain = lightchain->next) {
|
||||
SingleLightFace (lightchain->light, &l);
|
||||
SingleLightFace (lightchain->light, l);
|
||||
}
|
||||
for (i = 0; i < num_novislights; i++) {
|
||||
SingleLightFace (novislights[i], &l);
|
||||
SingleLightFace (novislights[i], l);
|
||||
}
|
||||
|
||||
FixMinlight (&l);
|
||||
//FixMinlight (&l);
|
||||
|
||||
if (!l.numlightstyles)
|
||||
// no light hitting it
|
||||
for (i = 0; i < MAXLIGHTMAPS; i++)
|
||||
if (l->lightstyles[i] == 255)
|
||||
break;
|
||||
size = l->numsamples * i;
|
||||
if (!size) {
|
||||
// no light styles
|
||||
return;
|
||||
}
|
||||
|
||||
// save out the values
|
||||
for (i = 0; i < MAXLIGHTMAPS; i++)
|
||||
f->styles[i] = l.lightstyles[i];
|
||||
|
||||
lightmapsize = size * l.numlightstyles;
|
||||
f->styles[i] = l->lightstyles[i];
|
||||
|
||||
LOCK;
|
||||
outdata = out = malloc (lightmapsize);
|
||||
outdata = out = malloc (size * 4);
|
||||
UNLOCK;
|
||||
ofs = GetFileSpace (lightmapsize);
|
||||
rgbdata = lit = outdata + size;
|
||||
ofs = GetFileSpace (size);
|
||||
f->lightofs = ofs;
|
||||
|
||||
// extra filtering
|
||||
h = (l.texsize[1] + 1) * 2;
|
||||
w = (l.texsize[0] + 1) * 2;
|
||||
for (i = 0; i < MAXLIGHTMAPS && f->styles[i] != 255; i++) {
|
||||
for (j = 0, sample = l->sample[i]; j < l->numsamples; j++, sample++) {
|
||||
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++) {
|
||||
if (l.lightstyles[i] == 0xff)
|
||||
fprintf (stderr, "Wrote empty lightmap");
|
||||
light = l.lightmaps[i];
|
||||
c = 0;
|
||||
for (t = 0; t <= l.texsize[1]; t++)
|
||||
for (s = 0; s <= l.texsize[0]; s++, c++) {
|
||||
if (extrasamples) {
|
||||
// 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;
|
||||
}
|
||||
red = bound (0, red, 255);
|
||||
green = bound (0, green, 255);
|
||||
blue = bound (0, blue, 255);
|
||||
white = bound (0, white, 255);
|
||||
*lit++ = red;
|
||||
*lit++ = green;
|
||||
*lit++ = blue;
|
||||
*out++ = white;
|
||||
}
|
||||
}
|
||||
LOCK;
|
||||
memcpy (lightdata->str + ofs, outdata, lightmapsize);
|
||||
memcpy (lightdata->str + ofs, outdata, size);
|
||||
memcpy (rgblightdata->str + ofs * 3, rgbdata, size * 3);
|
||||
free (outdata);
|
||||
UNLOCK;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
|
||||
#include "QF/qtypes.h"
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include "options.h"
|
||||
|
||||
const char *this_program;
|
||||
|
@ -53,7 +55,7 @@ static struct option const long_options[] = {
|
|||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{"threads", required_argument, 0, 't'},
|
||||
{"extra", no_argument, 0, 'e'},
|
||||
{"extra", required_argument, 0, 'e'},
|
||||
{"novis", no_argument, 0, 'N'},
|
||||
{"distance", required_argument, 0, 'd'},
|
||||
{"range", required_argument, 0, 'r'},
|
||||
|
@ -68,7 +70,7 @@ static const char *short_options =
|
|||
"V" // version
|
||||
"N" // novis
|
||||
"t:" // threads
|
||||
"e" // extra sampling
|
||||
"e:" // extra sampling
|
||||
"d:" // scale distance
|
||||
"r:" // scale range
|
||||
"f:"
|
||||
|
@ -87,7 +89,7 @@ usage (int status)
|
|||
" -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"
|
||||
" -e, --extra [num] Apply extra sampling\n"
|
||||
" -d, --distance [scale] Scale distance\n"
|
||||
" -r, --range [scale] Scale range\n"
|
||||
" -f, --file [bspfile] BSP file\n\n");
|
||||
|
@ -102,7 +104,6 @@ DecodeArgs (int argc, char **argv)
|
|||
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;
|
||||
|
@ -131,7 +132,8 @@ DecodeArgs (int argc, char **argv)
|
|||
options.threads = atoi (optarg);
|
||||
break;
|
||||
case 'e': // extra
|
||||
options.extra = true;
|
||||
options.extrabit = atoi (optarg);
|
||||
options.extrabit = bound (0, options.extrabit, 2);
|
||||
break;
|
||||
case 'd': // scale distance
|
||||
options.distance = atof (optarg);
|
||||
|
@ -146,6 +148,7 @@ DecodeArgs (int argc, char **argv)
|
|||
usage (1);
|
||||
}
|
||||
}
|
||||
options.extrascale = 1.0 / (1 << (options.extrabit * 2));
|
||||
if ((!bspfile) && argv[optind] && *(argv[optind]))
|
||||
bspfile = strdup (argv[optind++]);
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "QF/qtypes.h"
|
||||
#include "QF/quakefs.h"
|
||||
#include "QF/sys.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "light.h"
|
||||
#include "threads.h"
|
||||
|
@ -64,10 +65,12 @@ options_t options;
|
|||
bsp_t *bsp;
|
||||
|
||||
char *bspfile;
|
||||
dstring_t *litfile;
|
||||
|
||||
float scalecos = 0.5;
|
||||
|
||||
dstring_t *lightdata;
|
||||
dstring_t *rgblightdata;
|
||||
|
||||
dmodel_t *bspmodel;
|
||||
int bspfileface; // next surface to dispatch
|
||||
|
@ -90,6 +93,9 @@ GetFileSpace (int size)
|
|||
ofs = lightdata->size;
|
||||
lightdata->size += size;
|
||||
dstring_adjust (lightdata);
|
||||
|
||||
rgblightdata->size = (ofs + size) * 3;
|
||||
dstring_adjust (rgblightdata);
|
||||
UNLOCK;
|
||||
return ofs;
|
||||
}
|
||||
|
@ -110,7 +116,7 @@ VisThread (void *junk)
|
|||
}
|
||||
|
||||
static void *
|
||||
LightThread (void *junk)
|
||||
LightThread (void *l)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -121,16 +127,37 @@ LightThread (void *junk)
|
|||
if (i >= bsp->numfaces)
|
||||
return 0;
|
||||
|
||||
LightFace (i);
|
||||
printf ("%5d / %d\r", i, bsp->numfaces);
|
||||
fflush (stdout);
|
||||
LightFace (l, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
LightWorld (void)
|
||||
{
|
||||
int i, j;
|
||||
vec3_t org;
|
||||
entity_t *ent;
|
||||
const char *name;
|
||||
|
||||
lightdata = dstring_new ();
|
||||
rgblightdata = dstring_new ();
|
||||
surfacelightchain = (lightchain_t **) calloc (bsp->numfaces,
|
||||
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 :/
|
||||
VisStats ();
|
||||
|
@ -146,6 +173,7 @@ int
|
|||
main (int argc, char **argv)
|
||||
{
|
||||
double start, stop;
|
||||
char *e;
|
||||
QFile *f;
|
||||
|
||||
start = Sys_DoubleTime ();
|
||||
|
@ -164,6 +192,11 @@ main (int argc, char **argv)
|
|||
QFS_StripExtension (bspfile, bspfile);
|
||||
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");
|
||||
bsp = LoadBSPFile (f, Qfilesize (f));
|
||||
Qclose (f);
|
||||
|
@ -179,6 +212,12 @@ main (int argc, char **argv)
|
|||
WriteBSPFile (bsp, 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 ();
|
||||
|
||||
if (options.verbosity >= 0)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
trace.c
|
||||
threads.c
|
||||
|
||||
(description)
|
||||
|
||||
|
@ -49,6 +49,7 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "QF/qtypes.h"
|
||||
#include "QF/qendian.h"
|
||||
|
||||
#include "light.h"
|
||||
#include "options.h"
|
||||
#include "threads.h"
|
||||
|
||||
|
@ -82,6 +83,7 @@ RunThreadsOn (threadfunc_t *func)
|
|||
pthread_t work_threads[256];
|
||||
void *status;
|
||||
pthread_attr_t attrib;
|
||||
lightinfo_t *l[256];
|
||||
long i;
|
||||
|
||||
if (pthread_attr_init (&attrib) == -1)
|
||||
|
@ -90,17 +92,20 @@ RunThreadsOn (threadfunc_t *func)
|
|||
fprintf (stderr, "pthread_attr_setstacksize failed");
|
||||
|
||||
for (i = 0; i < options.threads; i++) {
|
||||
if (pthread_create (&work_threads[i], &attrib, func,
|
||||
(void *) i) == -1)
|
||||
l[i] = malloc (sizeof (lightinfo_t));
|
||||
if (pthread_create (&work_threads[i], &attrib, func, l[i]) == -1)
|
||||
fprintf (stderr, "pthread_create failed");
|
||||
}
|
||||
|
||||
for (i = 0; i < options.threads; i++) {
|
||||
if (pthread_join (work_threads[i], &status) == -1)
|
||||
fprintf (stderr, "pthread_join failed");
|
||||
free (l[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
func (NULL);
|
||||
else {
|
||||
lightinfo_t *l = malloc (sizeof (lightinfo_t));
|
||||
func (l);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,102 +123,81 @@ MakeTnodes (dmodel_t *bm)
|
|||
MakeTnode (0);
|
||||
}
|
||||
|
||||
qboolean
|
||||
TestLine (vec3_t start, vec3_t stop)
|
||||
/* LordHavoc: this function operates by doing depth-first front-to-back
|
||||
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 node, side;
|
||||
tracestack_t *tstack_p;
|
||||
tracestack_t tracestack[64];
|
||||
tnode_t *tnode;
|
||||
int side, ret;
|
||||
vec_t t1, t2, frac;
|
||||
vec3_t mid;
|
||||
tnode_t *tnode;
|
||||
|
||||
frontx = start[0];
|
||||
fronty = start[1];
|
||||
frontz = start[2];
|
||||
backx = stop[0];
|
||||
backy = stop[1];
|
||||
backz = stop[2];
|
||||
|
||||
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)
|
||||
return false; // DONE!
|
||||
|
||||
tnode = &tnodes[node];
|
||||
|
||||
switch (tnode->type) {
|
||||
case PLANE_X:
|
||||
front = frontx - tnode->dist;
|
||||
back = backx - 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 (front > 0 && back > 0) {
|
||||
node = tnode->children[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (front < ON_EPSILON && back < ON_EPSILON) {
|
||||
// if (front <= 0 && back <= 0) {
|
||||
node = tnode->children[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
side = front < 0;
|
||||
|
||||
front = front / (front - back);
|
||||
|
||||
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];
|
||||
// check for empty
|
||||
loc0:
|
||||
if (num < 0) {
|
||||
if (num == CONTENTS_SOLID)
|
||||
return TESTLINESTATE_SOLID;
|
||||
else
|
||||
return TESTLINESTATE_EMPTY;
|
||||
}
|
||||
|
||||
// find the point distances
|
||||
tnode = tnodes + num;
|
||||
|
||||
if (tnode->type < 3) {
|
||||
t1 = p1[tnode->type] - tnode->dist;
|
||||
t2 = p2[tnode->type] - tnode->dist;
|
||||
} else {
|
||||
t1 = DotProduct (tnode->normal, p1) - tnode->dist;
|
||||
t2 = DotProduct (tnode->normal, p2) - tnode->dist;
|
||||
}
|
||||
|
||||
if (t1 >= 0) {
|
||||
if (t2 >= 0) {
|
||||
num = tnode->children[0];
|
||||
goto loc0;
|
||||
}
|
||||
side = 0;
|
||||
} else {
|
||||
if (t2 < 0) {
|
||||
num = tnode->children[1];
|
||||
goto loc0;
|
||||
}
|
||||
side = 1;
|
||||
}
|
||||
|
||||
frac = t1 / (t1 - t2);
|
||||
mid[0] = p1[0] + frac * (p2[0] - p1[0]);
|
||||
mid[1] = p1[1] + frac * (p2[1] - p1[1]);
|
||||
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;
|
||||
}
|
||||
|
||||
qboolean
|
||||
TestLine (lightinfo_t *l, vec3_t start, vec3_t end)
|
||||
{
|
||||
return RecursiveTestLine (l, 0, start, end) != TESTLINESTATE_BLOCKED;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ static struct {
|
|||
|
||||
static lightchain_t *free_lightchains;
|
||||
lightchain_t **surfacelightchain;
|
||||
vec3_t *surfaceorgs;
|
||||
entity_t **alllights;
|
||||
int num_alllights;
|
||||
entity_t **novislights;
|
||||
|
|
Loading…
Reference in a new issue