#include "solid.h"
#include "base_image.h"
#include "base_config.h"
+#include "fs.h"
+#include "common.h"
#define MAXSTR 256
#define MAXKEY 16
/*---------------------------------------------------------------------------*/
-static int debug_output = 0;
+static const char *input_file;
+static int debug_output = 0;
/*---------------------------------------------------------------------------*/
#define MAXS 65536
#define MAXT 131072
#define MAXG 65536
-#define MAXL 2048
+#define MAXL 4096
#define MAXN 2048
-#define MAXP 1024
+#define MAXP 2048
#define MAXB 1024
#define MAXH 2048
#define MAXZ 1024
#define MAXW 1024
#define MAXD 1024
#define MAXA 16384
-#define MAXI 131072
+#define MAXI 262144
static int overflow(const char *s)
{
* and fills waiting ints with the proper values.
*/
-#define MAXSYM 1024
+#define MAXSYM 2048
static char symv[MAXSYM][MAXSTR];
static int valv[MAXSYM];
strcpy(jpg, name); strcat(jpg, ".jpg");
strcpy(png, name); strcat(png, ".png");
- if (size_load(config_data(png), w, h) ||
- size_load(config_data(jpg), w, h))
+ if (size_load(png, w, h) ||
+ size_load(jpg, w, h))
{
if (image_n + 1 >= image_alloc)
/* Read the given material file, adding a new material to the solid. */
+#define scan_vec4(f, s, v) \
+ if (fs_gets((s), sizeof (s), (f))) \
+ sscanf((s), "%f %f %f %f", (v), (v) + 1, (v) + 2, (v) + 3)
+
static int read_mtrl(struct s_file *fp, const char *name)
{
+ static char line[MAXSTR];
struct s_mtrl *mp;
- FILE *fin;
+ fs_file fin;
int mi;
for (mi = 0; mi < fp->mc; mi++)
mp->fl = 0;
mp->angle = 45.0f;
- if ((fin = fopen(config_data(name), "r")))
+ if ((fin = fs_open(name, "r")))
{
- fscanf(fin,
- "%f %f %f %f "
- "%f %f %f %f "
- "%f %f %f %f "
- "%f %f %f %f "
- "%f %d %f",
- mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
- mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
- mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
- mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
- mp->h, &mp->fl, &mp->angle);
- fclose(fin);
+ scan_vec4(fin, line, mp->d);
+ scan_vec4(fin, line, mp->a);
+ scan_vec4(fin, line, mp->s);
+ scan_vec4(fin, line, mp->e);
+
+ if (fs_gets(line, sizeof (line), fin))
+ mp->h[0] = strtod(line, NULL);
+
+ if (fs_gets(line, sizeof (line), fin))
+ mp->fl = strtol(line, NULL, 10);
+
+ if (fs_gets(line, sizeof (line), fin))
+ mp->angle = strtod(line, NULL);
+
+ fs_close(fin);
}
+ else
+ fprintf(stderr, "%s: unknown material \"%s\"\n", input_file, name);
return mi;
}
+#undef scan_vec4
+
/*---------------------------------------------------------------------------*/
/*
{
char line[MAXSTR];
char mtrl[MAXSTR];
- FILE *fin;
+ fs_file fin;
int v0 = fp->vc;
int t0 = fp->tc;
int s0 = fp->sc;
- if ((fin = fopen(config_data(name), "r")))
+ if ((fin = fs_open(name, "r")))
{
- while (fgets(line, MAXSTR, fin))
+ while (fs_gets(line, MAXSTR, fin))
{
if (strncmp(line, "usemtl", 6) == 0)
{
else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
}
- fclose(fin);
+ fs_close(fin);
}
}
float su, float sv, int fl, const char *s)
{
static const float base[6][3][3] = {
- {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
- {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
- {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
- {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
- {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
- {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
+ {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, 1, 0 }},
+ {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, 1, 0 }},
+ {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, 1, 0 }},
+ {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, 1, 0 }},
+ {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, -1 }},
+ {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, -1 }},
};
float R[16];
p[1] = 0.f;
p[2] = 0.f;
- m_rot(R, base[n][0], V_RAD(r));
+ /* Always rotate around the positive axis */
+
+ m_rot(R, base[n - (n % 2)][0], V_RAD(r));
- v_mad(p, p, base[n][1], su * tu / SCALE);
- v_mad(p, p, base[n][2], sv * tv / SCALE);
+ v_mad(p, p, base[n][1], +su * tu / SCALE);
+ v_mad(p, p, base[n][2], -sv * tv / SCALE);
m_vxfm(plane_u[pi], R, base[n][1]);
m_vxfm(plane_v[pi], R, base[n][2]);
#define T_END 4
#define T_NOP 5
-static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
+static int map_token(fs_file fin, int pi, char key[MAXSTR], char val[MAXSTR])
{
char buf[MAXSTR];
- if (fgets(buf, MAXSTR, fin))
+ if (fs_gets(buf, MAXSTR, fin))
{
char c;
float x0, y0, z0;
/* Parse a lump from the given file and add it to the solid. */
-static void read_lump(struct s_file *fp, FILE *fin)
+static void read_lump(struct s_file *fp, fs_file fin)
{
char k[MAXSTR];
char v[MAXSTR];
make_ref(v[i], &xp->pi);
if (strcmp(k[i], "timer") == 0)
+ {
sscanf(v[i], "%f", &xp->t0);
+ xp->t = xp->t0;
+ }
if (strcmp(k[i], "state") == 0)
{
/*---------------------------------------------------------------------------*/
-static void read_ent(struct s_file *fp, FILE *fin)
+static void read_ent(struct s_file *fp, fs_file fin)
{
char k[MAXKEY][MAXSTR];
char v[MAXKEY][MAXSTR];
if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
}
-static void read_map(struct s_file *fp, FILE *fin)
+static void read_map(struct s_file *fp, fs_file fin)
{
char k[MAXSTR];
char v[MAXSTR];
int i, j;
for (i = 1; i < lp->vc; i++)
+ {
+ int vi = fp->iv[lp->v0 + i];
+
+ if (!on_side(fp->vv[vi].p, fp->sv + si) ||
+ !on_side(fp->vv[vi].p, fp->sv + sj))
+ continue;
+
for (j = 0; j < i; j++)
{
- int vi = fp->iv[lp->v0 + i];
int vj = fp->iv[lp->v0 + j];
- if (on_side(fp->vv[vi].p, fp->sv + si) &&
- on_side(fp->vv[vj].p, fp->sv + si) &&
- on_side(fp->vv[vi].p, fp->sv + sj) &&
+ if (on_side(fp->vv[vj].p, fp->sv + si) &&
on_side(fp->vv[vj].p, fp->sv + sj))
{
fp->ev[fp->ec].vi = vi;
lp->ec++;
}
}
+ }
}
/*
static int vert_swaps[MAXV];
-static void swap_vert2(struct s_file *fp)
+static void apply_vert_swaps(struct s_file *fp)
{
int i, j;
static int edge_swaps[MAXE];
-static void swap_edge(struct s_file *fp)
+static void apply_edge_swaps(struct s_file *fp)
{
int i, j;
static int side_swaps[MAXS];
-static void swap_side(struct s_file *fp)
+static void apply_side_swaps(struct s_file *fp)
{
int i, j;
static int texc_swaps[MAXT];
-static void swap_texc(struct s_file *fp)
+static void apply_texc_swaps(struct s_file *fp)
{
int i;
static int geom_swaps[MAXG];
-static void swap_geom(struct s_file *fp)
+static void apply_geom_swaps(struct s_file *fp)
{
int i, j;
break;
vert_swaps[i] = j;
+
if (j == k)
{
if (i != k)
k++;
}
}
- swap_vert2(fp);
+
+ apply_vert_swaps(fp);
fp->vc = k;
}
break;
edge_swaps[i] = j;
+
if (j == k)
{
if (i != k)
k++;
}
}
- swap_edge(fp);
+
+ apply_edge_swaps(fp);
fp->ec = k;
}
+static int geomlist[MAXV];
+static int nextgeom[MAXG];
+
static void uniq_geom(struct s_file *fp)
{
int i, j, k = 0;
+ for (i = 0; i < MAXV; i++)
+ geomlist[i] = -1;
+
for (i = 0; i < fp->gc; i++)
{
- for (j = 0; j < k; j++)
- if (comp_geom(fp->gv + i, fp->gv + j))
- break;
+ int key = fp->gv[i].vj;
+
+ for (j = geomlist[key]; j != -1; j = nextgeom[j])
+ if (comp_geom(fp->gv + i, fp->gv + j))
+ goto found;
+
+ fp->gv[k] = fp->gv[i];
+
+ nextgeom[k] = geomlist[key];
+ geomlist[key] = k;
+ j = k;
+ k++;
+
+found:
geom_swaps[i] = j;
- if (j == k)
- {
- if (i != k)
- fp->gv[k] = fp->gv[i];
- k++;
- }
}
- swap_geom(fp);
+
+ apply_geom_swaps(fp);
fp->gc = k;
}
break;
texc_swaps[i] = j;
+
if (j == k)
{
if (i != k)
k++;
}
}
- swap_texc(fp);
+
+ apply_texc_swaps(fp);
fp->tc = k;
}
break;
side_swaps[i] = j;
+
if (j == k)
{
if (i != k)
k++;
}
}
- swap_side(fp);
+
+ apply_side_swaps(fp);
fp->sc = k;
}
static int test_lump_side(const struct s_file *fp,
const struct s_lump *lp,
- const struct s_side *sp)
+ const struct s_side *sp,
+ float bsphere[4])
{
int si;
int vi;
int f = 0;
int b = 0;
+ float d;
+
+ if (!lp->vc)
+ return 0;
+
+ /* Check if the bounding sphere of the lump is completely on one side. */
+
+ d = v_dot(bsphere, sp->n) - sp->d;
+
+ if (fabs(d) > bsphere[3])
+ return d > 0 ? 1 : -1;
+
/* If the given side is part of the given lump, then the lump is behind. */
for (si = 0; si < lp->sc; si++)
return 0;
}
-static int node_node(struct s_file *fp, int l0, int lc)
+static int node_node(struct s_file *fp, int l0, int lc, float bsphere[][4])
{
if (lc < 8)
{
int k = 0;
for (li = 0; li < lc; li++)
- if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
+ if ((k = test_lump_side(fp,
+ fp->lv + l0 + li,
+ fp->sv + si,
+ bsphere[l0 + li])))
d += k;
else
o++;
}
else
{
- switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
+ switch (test_lump_side(fp,
+ fp->lv + l0 + li,
+ fp->sv + sj,
+ bsphere[l0 + li]))
{
case +1:
fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10;
if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
{
struct s_lump l;
+ float f;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ f = bsphere[l0 + li][i];
+ bsphere[l0 + li][i] = bsphere[l0 + lj][i];
+ bsphere[l0 + lj][i] = f;
+ }
l = fp->lv[l0 + li];
fp->lv[l0 + li] = fp->lv[l0 + lj];
i = incn(fp);
fp->nv[i].si = sj;
- fp->nv[i].ni = node_node(fp, li, lic);
+ fp->nv[i].ni = node_node(fp, li, lic, bsphere);
- fp->nv[i].nj = node_node(fp, lk, lkc);
+ fp->nv[i].nj = node_node(fp, lk, lkc, bsphere);
fp->nv[i].l0 = lj;
fp->nv[i].lc = ljc;
}
}
+/*
+ * Compute a bounding sphere for a lump (not optimal)
+ */
+static void lump_bounding_sphere(struct s_file *fp,
+ struct s_lump *lp,
+ float bsphere[4])
+{
+ float bbox[6];
+ float r;
+ int i;
+
+ if (!lp->vc)
+ return;
+
+ bbox[0] = bbox[3] = fp->vv[fp->iv[lp->v0]].p[0];
+ bbox[1] = bbox[4] = fp->vv[fp->iv[lp->v0]].p[1];
+ bbox[2] = bbox[5] = fp->vv[fp->iv[lp->v0]].p[2];
+
+ for (i = 1; i < lp->vc; i++)
+ {
+ struct s_vert *vp = fp->vv + fp->iv[lp->v0 + i];
+ int j;
+
+ for (j = 0; j < 3; j++)
+ if (vp->p[j] < bbox[j])
+ bbox[j] = vp->p[j];
+
+ for (j = 0; j < 3; j++)
+ if (vp->p[j] > bbox[j + 3])
+ bbox[j + 3] = vp->p[j];
+ }
+
+ r = 0;
+
+ for (i = 0; i < 3; i++)
+ {
+ bsphere[i] = (bbox[i] + bbox[i + 3]) / 2;
+ r += (bsphere[i] - bbox[i]) * (bsphere[i] - bbox[i]);
+ }
+
+ bsphere[3] = fsqrtf(r);
+}
+
static void node_file(struct s_file *fp)
{
- int bi;
+ float bsphere[MAXL][4];
+ int i;
+
+ /* Compute a bounding sphere for each lump. */
+
+ for (i = 0; i < fp->lc; i++)
+ lump_bounding_sphere(fp, fp->lv + i, bsphere[i]);
/* Sort the lumps of each body into BSP nodes. */
- for (bi = 0; bi < fp->bc; bi++)
- fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
+ for (i = 0; i < fp->bc; i++)
+ fp->bv[i].ni = node_node(fp, fp->bv[i].l0, fp->bv[i].lc, bsphere);
}
/*---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
- char src[MAXSTR];
- char dst[MAXSTR];
+ char src[MAXSTR] = "";
+ char dst[MAXSTR] = "";
struct s_file f;
- FILE *fin;
+ fs_file fin;
+
+ if (!fs_init(argv[0]))
+ {
+ fprintf(stderr, "Failure to initialize virtual file system: %s\n",
+ fs_error());
+ return 1;
+ }
if (argc > 2)
{
+ input_file = argv[1];
+
if (argc > 3 && strcmp(argv[3], "--debug") == 0)
debug_output = 1;
- if (config_data_path(argv[2], NULL))
- {
- strncpy(src, argv[1], MAXSTR);
- strncpy(dst, argv[1], MAXSTR);
+ strncpy(src, argv[1], MAXSTR - 1);
+ strncpy(dst, argv[1], MAXSTR - 1);
- if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
- strcpy(dst + strlen(dst) - 4, ".sol");
- else
- strcat(dst, ".sol");
+ if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
+ strcpy(dst + strlen(dst) - 4, ".sol");
+ else
+ strcat(dst, ".sol");
- if ((fin = fopen(src, "r")))
+ fs_add_path (dir_name(src));
+ fs_set_write_dir(dir_name(dst));
+
+ if ((fin = fs_open(base_name(src, NULL), "r")))
+ {
+ if (!fs_add_path_with_archives(argv[2]))
{
- init_file(&f);
- read_map(&f, fin);
+ fprintf(stderr, "Failure to establish data directory\n");
+ fs_close(fin);
+ fs_quit();
+ return 1;
+ }
- resolve();
- targets(&f);
+ init_file(&f);
+ read_map(&f, fin);
- clip_file(&f);
- move_file(&f);
- uniq_file(&f);
- smth_file(&f);
- sort_file(&f);
- node_file(&f);
- dump_file(&f, dst);
+ resolve();
+ targets(&f);
- sol_stor(&f, dst);
+ clip_file(&f);
+ move_file(&f);
+ uniq_file(&f);
+ smth_file(&f);
+ sort_file(&f);
+ node_file(&f);
+ dump_file(&f, dst);
- fclose(fin);
+ sol_stor(&f, base_name(dst, NULL));
- free_imagedata();
- }
+ fs_close(fin);
+
+ free_imagedata();
}
- else fprintf(stderr, "Failure to establish data directory\n");
}
else fprintf(stderr, "Usage: %s <map> <data> [--debug]\n", argv[0]);