quakeforge/tools/qflight/source/properties.c
Bill Currie a3c1b2e992 [util] Rename qfplist.[ch]
The name is a hold-over from before the current quakeforge tree and the
QF include directory.
2021-03-21 16:13:03 +09:00

339 lines
7.5 KiB
C

/*
properties.c
Light properties handling.
Copyright (C) 2004 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2004/01/27
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
#ifdef HAVE_STRING_H
# include "string.h"
#endif
#ifdef HAVE_STRINGS_H
# include "strings.h"
#endif
#include <stdlib.h>
#include <errno.h>
#include "QF/mathlib.h"
#include "QF/plist.h"
#include "QF/quakeio.h"
#include "compat.h"
#include "tools/qflight/include/entities.h"
#include "tools/qflight/include/light.h"
#include "tools/qflight/include/options.h"
#include "tools/qflight/include/properties.h"
static plitem_t *properties;
float
parse_float (const char *str)
{
char *eptr;
double val = strtod (str, &eptr);
return val;
}
void
parse_vector (const char *str, vec3_t vec)
{
double tvec[3];
int count;
tvec[2] = 0; // assume 2 components is yaw and pitch
count = sscanf (str, "%lf %lf %lf", &tvec[0], &tvec[1], &tvec[2]);
if (count < 2 || count > 3) {
fprintf (stderr, "invalid vector");
VectorZero (tvec);
}
VectorCopy (tvec, vec);
}
void
parse_color (const char *str, vec3_t color)
{
double vec[3];
vec_t temp;
if (sscanf (str, "%lf %lf %lf", &vec[0], &vec[1], &vec[2]) != 3) {
fprintf (stderr, "not 3 values for color");
color[0] = color[1] = color[2] = 1.0;
return;
}
// scale the color to have at least one component at 1.0 (or -1.0)
temp = max (fabs (vec[0]), max (fabs (vec[1]), fabs (vec[2])));
if (temp != 0.0)
temp = 1.0 / temp;
VectorScale (vec, temp, color);
}
float
parse_light (const char *str, vec3_t color)
{
int i;
double vec[4];
i = sscanf (str, "%lf %lf %lf %lf", &vec[0], &vec[1], &vec[2], &vec[3]);
switch (i) {
case 4: // HalfLife light
VectorScale (vec, 1.0 / 255, color);
return vec[3];
break;
case 3:
VectorCopy (vec, color);
return 1.0;
break;
case 1:
color[0] = 1.0;
color[1] = 1.0;
color[2] = 1.0;
return vec[0];
break;
default:
fprintf (stderr, "_light (or light) key must "
"be 1 (Quake), 4 (HalfLife), or 3 (HLight) "
"values, \"%s\" is not valid\n", str);
color[0] = 1.0;
color[1] = 1.0;
color[2] = 1.0;
return DEFAULTLIGHTLEVEL;
}
}
int
parse_attenuation (const char *arg)
{
if (!strcmp(arg, "linear"))
return LIGHT_LINEAR;
else if (!strcmp(arg, "radius"))
return LIGHT_RADIUS;
else if (!strcmp(arg, "inverse"))
return LIGHT_INVERSE;
else if (!strcmp(arg, "realistic"))
return LIGHT_REALISTIC;
else if (!strcmp(arg, "none"))
return LIGHT_NO_ATTEN;
else if (!strcmp(arg, "havoc"))
return LIGHT_LH;
else {
char *eptr;
int val = strtol (arg, &eptr, 10);
if (eptr == arg || *eptr)
return -1;
return val;
}
}
int
parse_noise (const char *arg)
{
if (!strcmp(arg, "random"))
return NOISE_RANDOM;
else if (!strcmp(arg, "smooth"))
return NOISE_SMOOTH;
else if (!strcmp(arg, "perlin"))
return NOISE_PERLIN;
else {
char *eptr;
int val = strtol (arg, &eptr, 10);
if (eptr == arg || *eptr)
return -1;
return val;
}
}
static plitem_t *
get_item (const char *key, plitem_t *d1, plitem_t *d2)
{
plitem_t *p;
if ((p = PL_ObjectForKey (d1, key)))
return p;
if (d2)
return PL_ObjectForKey (d2, key);
return 0;
}
void
set_sun_properties (entity_t *ent, plitem_t *dict)
{
plitem_t *prop = 0;
plitem_t *p;
const char *str;
if (properties) {
prop = PL_ObjectForKey (properties, "worldspawn");
}
if ((p = get_item ("sunlight", dict, prop))) {
if ((str = PL_String (p))) {
ent->sun_light[0] = parse_light (str, ent->sun_color[0]);
}
}
if ((p = get_item ("sunlight2", dict, prop))) {
if ((str = PL_String (p))) {
ent->sun_light[1] = parse_light (str, ent->sun_color[1]);
}
}
if ((p = get_item ("sunlight3", dict, prop))) {
if ((str = PL_String (p))) {
ent->sun_light[1] = parse_light (str, ent->sun_color[1]);
ent->shadow_sense = SHADOWSENSE;
}
}
if ((p = get_item ("sunlight_color", dict, prop))) {
if ((str = PL_String (p))) {
parse_color (str, ent->sun_color[0]);
}
}
if ((p = get_item ("sunlight_color2", dict, prop))) {
if ((str = PL_String (p))) {
parse_color (str, ent->sun_color[1]);
}
}
if ((p = get_item ("sunlight_color3", dict, prop))) {
if ((str = PL_String (p))) {
parse_color (str, ent->sun_color[1]);
}
}
if ((p = get_item ("sun_mangle", dict, prop))) {
if ((str = PL_String (p))) {
parse_vector (str, ent->sun_dir[0]);
}
}
}
void
set_properties (entity_t *ent, plitem_t *dict)
{
plitem_t *prop = 0;
plitem_t *p;
const char *str;
if (properties) {
if ((p = get_item ("light_name", dict, 0))
&& (str = PL_String (p)))
prop = PL_ObjectForKey (properties, str);
if (!prop)
prop = PL_ObjectForKey (properties, ent->classname);
if (!prop)
prop = PL_ObjectForKey (properties, "default");
}
if ((p = get_item ("light", dict, prop))) {
if ((str = PL_String (p))) {
ent->light = parse_light (str, ent->color);
}
}
if ((p = get_item ("style", dict, prop))) {
if ((str = PL_String (p))) {
ent->style = atoi (str);
if ((unsigned) ent->style > 254)
fprintf (stderr, "Bad light style %i (must be 0-254)",
ent->style);
}
}
if ((p = get_item ("angle", dict, prop))) {
if ((str = PL_String (p))) {
ent->angle = parse_float (str);
}
}
if ((p = get_item ("wait", dict, prop))) {
if ((str = PL_String (p))) {
ent->falloff = parse_float (str);
ent->falloff *= ent->falloff; // presquared
}
}
if ((p = get_item ("lightradius", dict, prop))) {
if ((str = PL_String (p))) {
ent->lightradius = parse_float (str);
}
}
if ((p = get_item ("color", dict, prop))) {
if ((str = PL_String (p))) {
parse_color (str, ent->color2);
}
}
if ((p = get_item ("attenuation", dict, prop))) {
if ((str = PL_String (p))) {
ent->attenuation = parse_attenuation (str);
if (ent->attenuation == -1) {
ent->attenuation = options.attenuation;
fprintf (stderr, "Bad light light attenuation: %s\n",
str);
}
}
}
if ((p = get_item ("radius", dict, prop))) {
if ((str = PL_String (p))) {
ent->radius = parse_float (str);
}
}
if ((p = get_item ("noise", dict, prop))) {
if ((str = PL_String (p))) {
ent->noise = parse_float (str);
}
}
if ((p = get_item ("noisetype", dict, prop))) {
if ((str = PL_String (p))) {
ent->noisetype = parse_noise (str);
}
}
if ((p = get_item ("persistence", dict, prop))) {
if ((str = PL_String (p))) {
ent->persistence = parse_float (str);
}
}
if ((p = get_item ("resolution", dict, prop))) {
if ((str = PL_String (p))) {
ent->resolution = parse_float (str);
}
}
}
void
LoadProperties (const char *filename)
{
QFile *f;
char *buf;
int len;
f = Qopen (filename, "rt");
if (!f) {
perror (filename);
exit (1);
}
len = Qfilesize (f);
buf = malloc (len + 1);
Qread (f, buf, len);
Qclose (f);
buf[len] = 0;
properties = PL_GetPropertyList (buf, 0);
free (buf);
}