Group key config symbols together
[neverball] / share / mapc.c
index ae2a2b1..ab3b580 100644 (file)
@@ -23,6 +23,8 @@
 #include "solid.h"
 #include "base_image.h"
 #include "base_config.h"
+#include "fs.h"
+#include "common.h"
 
 #define MAXSTR 256
 #define MAXKEY 16
@@ -39,7 +41,8 @@
 
 /*---------------------------------------------------------------------------*/
 
-static int debug_output = 0;
+static const char *input_file;
+static int         debug_output = 0;
 
 /*---------------------------------------------------------------------------*/
 
@@ -51,9 +54,9 @@ 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
@@ -64,7 +67,7 @@ static int debug_output = 0;
 #define MAXW    1024
 #define MAXD    1024
 #define MAXA    16384
-#define MAXI    131072
+#define MAXI    262144
 
 static int overflow(const char *s)
 {
@@ -223,7 +226,7 @@ static void init_file(struct s_file *fp)
  * and fills waiting ints with the proper values.
  */
 
-#define MAXSYM 1024
+#define MAXSYM 2048
 
 static char symv[MAXSYM][MAXSTR];
 static int  valv[MAXSYM];
@@ -353,8 +356,8 @@ static void size_image(const char *name, int *w, int *h)
     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)
@@ -388,10 +391,15 @@ static void size_image(const char *name, int *w, int *h)
 
 /* 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++)
@@ -411,25 +419,32 @@ static int read_mtrl(struct s_file *fp, const char *name)
     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
+
 /*---------------------------------------------------------------------------*/
 
 /*
@@ -564,15 +579,15 @@ static void read_obj(struct s_file *fp, const char *name, int mi)
 {
     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)
             {
@@ -590,7 +605,7 @@ static void read_obj(struct s_file *fp, const char *name, int mi)
             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);
     }
 }
 
@@ -611,12 +626,12 @@ static void make_plane(int   pi, float x0, float y0, float      z0,
                        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];
@@ -661,10 +676,12 @@ static void make_plane(int   pi, float x0, float y0, float      z0,
     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]);
@@ -686,11 +703,11 @@ static void make_plane(int   pi, float x0, float y0, float      z0,
 #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;
@@ -746,7 +763,7 @@ static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
 
 /* 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];
@@ -1138,7 +1155,10 @@ static void make_swch(struct s_file *fp,
             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)
         {
@@ -1227,7 +1247,7 @@ static void make_ball(struct s_file *fp,
 
 /*---------------------------------------------------------------------------*/
 
-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];
@@ -1267,7 +1287,7 @@ static void read_ent(struct s_file *fp, FILE *fin)
     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];
@@ -1384,14 +1404,18 @@ static void clip_edge(struct s_file *fp,
     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;
@@ -1404,6 +1428,7 @@ static void clip_edge(struct s_file *fp,
                 lp->ec++;
             }
         }
+    }
 }
 
 /*
@@ -1648,7 +1673,7 @@ static void swap_mtrl(struct s_file *fp, int mi, int mj)
 
 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;
 
@@ -1695,7 +1720,7 @@ static void swap_vert(struct s_file *fp, int vi, int vj)
 
 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;
 
@@ -1706,7 +1731,7 @@ static void swap_edge(struct s_file *fp)
 
 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;
 
@@ -1726,7 +1751,7 @@ static void swap_side(struct s_file *fp)
 
 static int texc_swaps[MAXT];
 
-static void swap_texc(struct s_file *fp)
+static void apply_texc_swaps(struct s_file *fp)
 {
     int i;
 
@@ -1740,7 +1765,7 @@ static void swap_texc(struct s_file *fp)
 
 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;
 
@@ -1793,6 +1818,7 @@ static void uniq_vert(struct s_file *fp)
                 break;
 
         vert_swaps[i] = j;
+
         if (j == k)
         {
             if (i != k)
@@ -1800,7 +1826,8 @@ static void uniq_vert(struct s_file *fp)
             k++;
         }
     }
-    swap_vert2(fp);
+
+    apply_vert_swaps(fp);
 
     fp->vc = k;
 }
@@ -1816,6 +1843,7 @@ static void uniq_edge(struct s_file *fp)
                 break;
 
         edge_swaps[i] = j;
+
         if (j == k)
         {
             if (i != k)
@@ -1823,30 +1851,43 @@ static void uniq_edge(struct s_file *fp)
             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;
 }
@@ -1862,6 +1903,7 @@ static void uniq_texc(struct s_file *fp)
                 break;
 
         texc_swaps[i] = j;
+
         if (j == k)
         {
             if (i != k)
@@ -1869,7 +1911,8 @@ static void uniq_texc(struct s_file *fp)
             k++;
         }
     }
-    swap_texc(fp);
+
+    apply_texc_swaps(fp);
 
     fp->tc = k;
 }
@@ -1885,6 +1928,7 @@ static void uniq_side(struct s_file *fp)
                 break;
 
         side_swaps[i] = j;
+
         if (j == k)
         {
             if (i != k)
@@ -1892,7 +1936,8 @@ static void uniq_side(struct s_file *fp)
             k++;
         }
     }
-    swap_side(fp);
+
+    apply_side_swaps(fp);
 
     fp->sc = k;
 }
@@ -2104,7 +2149,8 @@ static void sort_file(struct s_file *fp)
 
 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;
@@ -2112,6 +2158,18 @@ static int test_lump_side(const struct s_file *fp,
     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++)
@@ -2138,7 +2196,7 @@ static int test_lump_side(const struct s_file *fp,
     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)
     {
@@ -2172,7 +2230,10 @@ static int node_node(struct s_file *fp, int l0, int lc)
             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++;
@@ -2196,7 +2257,10 @@ static int node_node(struct s_file *fp, int l0, int lc)
             }
             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;
@@ -2219,6 +2283,15 @@ static int node_node(struct s_file *fp, int l0, int lc)
                 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];
@@ -2244,9 +2317,9 @@ static int node_node(struct s_file *fp, int l0, int lc)
         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;
 
@@ -2254,14 +2327,63 @@ static int node_node(struct s_file *fp, int l0, int lc)
     }
 }
 
+/*
+ * 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);
 }
 
 /*---------------------------------------------------------------------------*/
@@ -2328,50 +2450,66 @@ static void dump_file(struct s_file *p, const char *name)
 
 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]);