bring in OpenQuartz's extentions (except -ikmap: got tired:)

go back to id's lighting model being default. LordHavoc's is selectable
via --attentuation havoc. Also selectable on a per-light basis.
This commit is contained in:
Bill Currie 2004-01-26 07:39:29 +00:00
parent 31aca31d17
commit 5ee1b1d9ca
9 changed files with 346 additions and 36 deletions

View file

@ -33,6 +33,19 @@
#define DEFAULTLIGHTLEVEL 300
#define DEFAULTFALLOFF 1.0f
// Open Quartz - attenuation types
#define LIGHT_LINEAR 0 // regular attenuation (light - distance)
#define LIGHT_RADIUS 1 // light * (distance - radius) / radius
#define LIGHT_INVERSE 2 // light / distance
#define LIGHT_REALISTIC 3 // light / (distance * distance)
#define LIGHT_NO_ATTEN 4 // no attenuation
#define LIGHT_LH 5 // LordHavocs version of realistic
// Open Quartz - noise type flags
#define NOISE_RANDOM 0 // completely random noise (default)
#define NOISE_SMOOTH 1 // low res noise with interpolation
#define NOISE_PERLIN 2 // combines several noise frequencies
typedef struct epair_s {
struct epair_s *next;
const char *key;
@ -57,6 +70,17 @@ typedef struct entity_s {
// the visdata for the leaf this light
// is in
int style;
// Open Quartz - special light feilds
int noisetype; // random noise type
float noise; // noise intensity
float resolution; // noise blockiness
float persistence; // perlin noise decay per octave
int attenuation; // light attenuation type
float radius; // the light's maximum range, minimum
// of cutoff range and _radius key, 0
// for no maximum
const char *target;
const char *targetname;
struct epair_s *epairs;

View file

@ -0,0 +1,5 @@
float noise3d (vec3_t v, int num);
float noiseXYZ (float x, float y, float z, int num);
float noise_scaled (vec3_t v, float s, int num);
float noise_perlin (vec3_t v, float p, int num);
void snap_vector (vec3_t v_old, vec3_t v_new, float scale);

View file

@ -36,10 +36,13 @@ typedef struct {
int threads;
int novis;
int extrabit;
int attenuation;
vec_t extrascale;
vec_t distance;
vec_t range;
vec_t globallightscale;
vec_t noise;
vec_t cutoff;
const char *lightsfilename;
} options_t;

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 vis.c
qflight_SOURCES= entities.c ltface.c noise.c options.c qflight.c threads.c trace.c vis.c
qflight_LDFLAGS= $(PTHREAD_LDFLAGS)
qflight_LDADD= $(QFLIGHT_LIBS)

View file

@ -172,6 +172,8 @@ LoadEntities (void)
entity_t *entity;
epair_t *epair;
int i;
float cutoff_range;
float intensity;
data = bsp->entdata;
@ -202,6 +204,7 @@ LoadEntities (void)
entity->falloff = DEFAULTFALLOFF * DEFAULTFALLOFF;
entity->lightradius = 0;
entity->lightoffset = LIGHTDISTBIAS;
entity->attenuation = options.attenuation;
// go through all the keys in this entity
while (1) {
@ -295,15 +298,53 @@ LoadEntities (void)
temp = 1.0 / temp;
VectorScale (vec, temp, color2);
}
// Open Quartz - new keys
else if (!strcmp(key, "_attenuation")) {
if (!strcmp(com_token, "linear"))
entity->attenuation = LIGHT_LINEAR;
else if (!strcmp(com_token, "radius"))
entity->attenuation = LIGHT_RADIUS;
else if (!strcmp(com_token, "inverse"))
entity->attenuation = LIGHT_INVERSE;
else if (!strcmp(com_token, "realistic"))
entity->attenuation = LIGHT_REALISTIC;
else if (!strcmp(com_token, "none"))
entity->attenuation = LIGHT_NO_ATTEN;
else if (!strcmp(com_token, "havoc"))
entity->attenuation = LIGHT_REALISTIC;
else
entity->attenuation = atoi (com_token);
} else if (!strcmp(key, "_radius"))
entity->radius = atof (com_token);
else if (!strcmp(key, "_noise"))
entity->noise = atof (com_token);
else if (!strcmp(key, "_noisetype")) {
if (!strcmp(com_token, "random"))
entity->noisetype = NOISE_RANDOM;
else if (!strcmp(com_token, "smooth"))
entity->noisetype = NOISE_SMOOTH;
else if (!strcmp(com_token, "perlin"))
entity->noisetype = NOISE_PERLIN;
else
entity->noisetype = atoi (com_token);
} else if (!strcmp(key, "_persistence"))
entity->persistence = atof (com_token);
else if (!strcmp(key, "_resolution"))
entity->resolution = atof (com_token);
}
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->classname && !strncmp (entity->classname, "light", 5)) {
if (!entity->light)
entity->light = DEFAULTLIGHTLEVEL;
if (!entity->noise)
entity->noise = options.noise;
if (!entity->persistence)
entity->persistence = 1;
}
if (entity->light) {
// convert to subtraction to the brightness for the whole light,
@ -322,6 +363,38 @@ LoadEntities (void)
+ LIGHTDISTBIAS);
if (entity->subbrightness < (1.0 / 1048576.0))
entity->subbrightness = (1.0 / 1048576.0);
intensity = entity->light;
if (intensity < 0)
intensity = -intensity;
switch (entity->attenuation) {
case LIGHT_RADIUS:
// default radius is intensity (same as LIGHT_LINEAR)
if (!entity->radius)
entity->radius = intensity;
break;
case LIGHT_LINEAR:
// don't allow radius to be greater than intensity
if (entity->radius > intensity || entity->radius == 0)
entity->radius = intensity;
break;
case LIGHT_REALISTIC:
if (options.cutoff) {
// approximate limit for faster lighting
cutoff_range = sqrt (intensity / options.cutoff);
if (!entity->radius || cutoff_range < entity->radius)
entity->radius = cutoff_range;
}
break;
case LIGHT_INVERSE:
if (options.cutoff) {
// approximate limit for faster lighting
cutoff_range = intensity / options.cutoff;
if (!entity->radius || cutoff_range < entity->radius)
entity->radius = cutoff_range;
}
break;
}
}
if (entity->classname && !strcmp (entity->classname, "light")) {

View file

@ -57,6 +57,7 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "light.h"
#include "entities.h"
#include "noise.h"
#include "options.h"
#include "threads.h"
@ -275,7 +276,8 @@ SingleLightFace (entity_t *light, lightinfo_t *l)
int mapnum, i;
qboolean hit;
vec3_t incoming, spotvec;
vec_t add, dist, idist, lightfalloff, lightsubtract, spotcone;
vec_t add, angle, dist, idist, lightfalloff, lightsubtract, spotcone;
vec_t intensity;
lightpoint_t *point;
lightsample_t *sample;
@ -290,17 +292,14 @@ SingleLightFace (entity_t *light, lightinfo_t *l)
lightsubtract = light->subbrightness;
// don't bother with light too far away
#if 0
if (dist > light->light) {
if (light->radius && dist > light->radius) {
c_culldistplane++;
return;
}
#else
if (lightsubtract > (1.0 / (dist * dist * lightfalloff + LIGHTDISTBIAS))) {
c_culldistplane++;
return;
}
#endif
for (mapnum = 0; mapnum < MAXLIGHTMAPS; mapnum++) {
if (l->lightstyles[mapnum] == light->style)
@ -330,41 +329,96 @@ SingleLightFace (entity_t *light, lightinfo_t *l)
idist = 1.0 / dist;
VectorScale (incoming, idist, incoming);
if (light->radius && dist > light->radius)
continue;
// 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);
switch (light->attenuation) {
case LIGHT_LINEAR:
add = light->light - dist;
break;
case LIGHT_RADIUS:
add = light->light * (light->radius - dist) / light->radius;
break;
case LIGHT_INVERSE:
add = light->light / dist;
break;
case LIGHT_REALISTIC:
add = light->light / (dist * dist);
break;
case LIGHT_LH:
add = 1 / (dist * dist * lightfalloff + LIGHTDISTBIAS);
// LordHavoc: changed to be more realistic (entirely different
// lighting model)
// LordHavoc: use subbrightness on all lights, simply to have
//some distance culling
add -= lightsubtract;
break;
}
if (light->noise) {
int seed = light - entities;
vec3_t snap;
lightpoint_t *noise_point = point;
if (options.extrascale) {
// FIXME not correct for extrascale > 2
// We don't want to oversample noise because that just
// waters it down. So we "undersample" noise by using
// the same surf coord for every group of 4 lightmap pixels
// ("undersampling", "pixelation", "anti-interpolation" :-)
int width = (l->texsize[0] + 1) * 2;
int x = i % width;
int y = i / width;
if (x % 2 && y % 2)
noise_point -= width * 3 + 3;
else if (y % 2)
noise_point -= width * 3;
else if (x % 2)
noise_point -= 3;
}
if (light->noisetype == NOISE_SMOOTH)
snap_vector (noise_point->v, snap, 0);
else
snap_vector (noise_point->v, snap, light->resolution);
if (light->noisetype == NOISE_RANDOM)
intensity = noise3d (snap, seed);
if (light->noisetype == NOISE_SMOOTH)
intensity = noise_scaled (snap, light->resolution, seed);
if (light->noisetype == NOISE_PERLIN)
intensity = noise_perlin (snap, light->persistence, seed);
add *= intensity * light->noise + 1.0 - light->noise;
}
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);
if (light->attenuation == LIGHT_LH) {
// LordHavoc: FIXME: decide this 0.5 bias based on shader
// properties (some are dull, some are shiny)
add *= angle * 0.5 + 0.5;
} else {
add *= angle;
}
add *= options.extrascale;
if (light->light < 0)
add *= -1; // negative light
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

View file

@ -0,0 +1,107 @@
#include <math.h>
#include "QF/qtypes.h"
#include "noise.h"
// returns the 3D noise value for a point in space
float
noise3d (vec3_t v, int num)
{
int n;
n = floor (v[0]) + floor (v[1]) * 57 + floor (v[2]) * 3251;
n = (n << 13) ^ n;
n = n * (n * n * 15731 + 789221) + 1376312589;
return (n & 0x7fffffff) / 2147483648.0;
}
// a variation of Noise3D that takes 3 floats
float
noiseXYZ (float x, float y, float z, int num)
{
vec3_t v;
v[0] = x;
v[1] = y;
v[2] = z;
return noise3d (v, num);
}
// returns a noise value from a scaled up noise pattern
//
// Actually created by sampling points on a certain grid
// and interpolating the inbetween value, making the noise smooth
float
noise_scaled (vec3_t v, float s, int num)
{
float n = 0;
vec3_t a, b, c, d;
a[0] = floor (v[0] / s) * s;
b[0] = a[0] + s;
c[0] = (v[0] - a[0]) / s;
d[0] = 1 - c[0];
a[1] = floor (v[1] / s) * s;
b[1] = a[1] + s;
c[1] = (v[1] - a[1]) / s;
d[1] = 1 - c[1];
a[2] = floor (v[2] / s) * s;
b[2] = a[2] + s;
c[2] = (v[2] - a[2]) / s;
d[2] = 1 - c[2];
n += noiseXYZ (a[0], a[1], a[2], num) * d[0] * d[1] * d[2];
n += noiseXYZ (a[0], a[1], b[2], num) * d[0] * d[1] * c[2];
n += noiseXYZ (a[0], b[1], a[2], num) * d[0] * c[1] * d[2];
n += noiseXYZ (a[0], b[1], b[2], num) * d[0] * c[1] * c[2];
n += noiseXYZ (b[0], a[1], a[2], num) * c[0] * d[1] * d[2];
n += noiseXYZ (b[0], a[1], b[2], num) * c[0] * d[1] * c[2];
n += noiseXYZ (b[0], b[1], a[2], num) * c[0] * c[1] * d[2];
n += noiseXYZ (b[0], b[1], b[2], num) * c[0] * c[1] * c[2];
return n;
}
// returns a Perlin noise value for a point in 3D space
//
// This noise function combines noise at several different scales
// which makes it slower than just using one layer of noise
float
noise_perlin (vec3_t v, float p, int num)
{
float n = 0;
n += noise_scaled (v, 1024, num);
n += 0.5 + (noise_scaled (v, 256, num) - 0.5) * p;
n += 0.5 + (noise_scaled (v, 64, num) - 0.5) * p * p;
n += 0.5 + (noise_scaled (v, 16, num) - 0.5) * p * p * p;
return n / 2 - 0.5;
}
// Use to create low-res noise patterns without interpolation
// A good strategy for avoiding seams on terrain and curves
// when called with a scale value of about 32
//
// This is because surfaces have some texture pixels which are
// actually not in the polygon at all so their edges don't
// perfectly fit together.
//
// Creates a random pattern of light and dark squares on flat
// axis aligned surfaces, which is usually not what you want
// but it may have interesting applications
void
snap_vector (vec3_t v_old, vec3_t v_new, float scale)
{
if (scale <= 0) {
v_new[0] = v_old[0];
v_new[1] = v_old[1];
v_new[2] = v_old[2];
} else {
v_new[0] = floor (v_old[0] / scale + 0.5) * scale;
v_new[1] = floor (v_old[1] / scale + 0.5) * scale;
v_new[2] = floor (v_old[2] / scale + 0.5) * scale;
}
}

View file

@ -45,6 +45,7 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "compat.h"
#include "entities.h"
#include "options.h"
const char *this_program;
@ -55,6 +56,9 @@ static struct option const long_options[] = {
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"threads", required_argument, 0, 't'},
{"attenuation", required_argument, 0, 'a'},
{"noise", required_argument, 0, 'n'},
{"cutoff", required_argument, 0, 'c'},
{"extra", required_argument, 0, 'e'},
{"novis", no_argument, 0, 'N'},
{"distance", required_argument, 0, 'd'},
@ -70,6 +74,9 @@ static const char *short_options =
"V" // version
"N" // novis
"t:" // threads
"a:" // attenuation
"n:" // noise
"c:" // cutoff
"e:" // extra sampling
"d:" // scale distance
"r:" // scale range
@ -92,6 +99,10 @@ usage (int status)
" -e, --extra [num] Apply extra sampling\n"
" -d, --distance [scale] Scale distance\n"
" -r, --range [scale] Scale range\n"
" -a, --attenuation [type] linear,radius,inverse,realistic,none,\n"
" havoc\n"
" -n, --noise [factor] Scale noise. 0 (default) to disable\n"
" -c, --cutoff [scale] Scale cutoff. 0 to disable\n"
" -f, --file [bspfile] BSP file\n\n");
exit (status);
}
@ -108,6 +119,8 @@ DecodeArgs (int argc, char **argv)
options.distance = 1.0;
options.range = 0.5;
options.globallightscale = 1.0;
options.cutoff = 1.0;
options.attenuation = LIGHT_LINEAR;
bspfile = NULL;
while ((c = getopt_long (argc, argv, short_options, long_options, 0))
@ -134,6 +147,37 @@ DecodeArgs (int argc, char **argv)
if (eptr == optarg || *eptr)
usage (1);
break;
case 'a':
if (!strcmp(optarg, "linear"))
options.attenuation = LIGHT_LINEAR;
else if (!strcmp(optarg, "radius"))
options.attenuation = LIGHT_RADIUS;
else if (!strcmp(optarg, "inverse"))
options.attenuation = LIGHT_INVERSE;
else if (!strcmp(optarg, "realistic"))
options.attenuation = LIGHT_REALISTIC;
else if (!strcmp(optarg, "none"))
options.attenuation = LIGHT_NO_ATTEN;
else if (!strcmp(optarg, "havoc"))
options.attenuation = LIGHT_REALISTIC;
else {
options.attenuation = strtol (optarg, &eptr, 10);
if (eptr == optarg || *eptr)
usage (1);
}
break;
case 'n': // noise
options.noise = strtod (optarg, &eptr);
if (eptr == optarg || *eptr)
usage (1);
options.noise = bound (0, options.extrabit, 2);
break;
case 'c': // cutoff
options.cutoff = strtod (optarg, &eptr);
if (eptr == optarg || *eptr)
usage (1);
options.cutoff = bound (0, options.extrabit, 2);
break;
case 'e': // extra
options.extrabit = strtol (optarg, &eptr, 10);
if (eptr == optarg || *eptr)

View file

@ -55,17 +55,17 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "light.h"
typedef struct {
int type;
vec3_t normal;
float dist;
int children[2];
int pad;
int type;
vec3_t normal;
float dist;
int children[2];
int pad;
} tnode_t;
typedef struct {
vec3_t backpt;
int side;
int node;
vec3_t backpt;
int side;
int node;
} tracestack_t;
tnode_t *tnodes, *tnode_p;