2 * Copyright (C) 2003 Robert Kooima
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
15 /*---------------------------------------------------------------------------*/
24 #include "base_image.h"
25 #include "base_config.h"
33 * The overall design of this map converter is very stupid, but very
34 * simple. It begins by assuming that every mtrl, vert, edge, side,
35 * and texc in the map is unique. It then makes an optimizing pass
36 * that discards redundant information. The result is optimal, though
37 * the process is terribly inefficient.
40 /*---------------------------------------------------------------------------*/
42 static int debug_output = 0;
44 /*---------------------------------------------------------------------------*/
46 /* Ohhhh... arbitrary! */
69 static int overflow(const char *s)
71 printf("%s overflow\n", s);
76 static int incm(struct s_file *fp)
78 return (fp->mc < MAXM) ? fp->mc++ : overflow("mtrl");
81 static int incv(struct s_file *fp)
83 return (fp->vc < MAXV) ? fp->vc++ : overflow("vert");
86 static int ince(struct s_file *fp)
88 return (fp->ec < MAXE) ? fp->ec++ : overflow("edge");
91 static int incs(struct s_file *fp)
93 return (fp->sc < MAXS) ? fp->sc++ : overflow("side");
96 static int inct(struct s_file *fp)
98 return (fp->tc < MAXT) ? fp->tc++ : overflow("texc");
101 static int incg(struct s_file *fp)
103 return (fp->gc < MAXG) ? fp->gc++ : overflow("geom");
106 static int incl(struct s_file *fp)
108 return (fp->lc < MAXL) ? fp->lc++ : overflow("lump");
111 static int incn(struct s_file *fp)
113 return (fp->nc < MAXN) ? fp->nc++ : overflow("node");
116 static int incp(struct s_file *fp)
118 return (fp->pc < MAXP) ? fp->pc++ : overflow("path");
121 static int incb(struct s_file *fp)
123 return (fp->bc < MAXB) ? fp->bc++ : overflow("body");
126 static int inch(struct s_file *fp)
128 return (fp->hc < MAXH) ? fp->hc++ : overflow("item");
131 static int incz(struct s_file *fp)
133 return (fp->zc < MAXZ) ? fp->zc++ : overflow("goal");
136 static int incj(struct s_file *fp)
138 return (fp->jc < MAXJ) ? fp->jc++ : overflow("jump");
141 static int incx(struct s_file *fp)
143 return (fp->xc < MAXX) ? fp->xc++ : overflow("swch");
146 static int incr(struct s_file *fp)
148 return (fp->rc < MAXR) ? fp->rc++ : overflow("bill");
151 static int incu(struct s_file *fp)
153 return (fp->uc < MAXU) ? fp->uc++ : overflow("ball");
156 static int incw(struct s_file *fp)
158 return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
161 static int incd(struct s_file *fp)
163 return (fp->dc < MAXD) ? fp->dc++ : overflow("dict");
166 static int inci(struct s_file *fp)
168 return (fp->ic < MAXI) ? fp->ic++ : overflow("indx");
171 static void init_file(struct s_file *fp)
194 fp->mv = (struct s_mtrl *) calloc(MAXM, sizeof (struct s_mtrl));
195 fp->vv = (struct s_vert *) calloc(MAXV, sizeof (struct s_vert));
196 fp->ev = (struct s_edge *) calloc(MAXE, sizeof (struct s_edge));
197 fp->sv = (struct s_side *) calloc(MAXS, sizeof (struct s_side));
198 fp->tv = (struct s_texc *) calloc(MAXT, sizeof (struct s_texc));
199 fp->gv = (struct s_geom *) calloc(MAXG, sizeof (struct s_geom));
200 fp->lv = (struct s_lump *) calloc(MAXL, sizeof (struct s_lump));
201 fp->nv = (struct s_node *) calloc(MAXN, sizeof (struct s_node));
202 fp->pv = (struct s_path *) calloc(MAXP, sizeof (struct s_path));
203 fp->bv = (struct s_body *) calloc(MAXB, sizeof (struct s_body));
204 fp->hv = (struct s_item *) calloc(MAXH, sizeof (struct s_item));
205 fp->zv = (struct s_goal *) calloc(MAXZ, sizeof (struct s_goal));
206 fp->jv = (struct s_jump *) calloc(MAXJ, sizeof (struct s_jump));
207 fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
208 fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
209 fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
210 fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
211 fp->dv = (struct s_dict *) calloc(MAXD, sizeof (struct s_dict));
212 fp->av = (char *) calloc(MAXA, sizeof (char));
213 fp->iv = (int *) calloc(MAXI, sizeof (int));
216 /*---------------------------------------------------------------------------*/
219 * The following is a small symbol table data structure. Symbols and
220 * their integer values are collected in symv and valv. References
221 * and pointers to their unsatisfied integer values are collected in
222 * refv and pntv. The resolve procedure matches references to symbols
223 * and fills waiting ints with the proper values.
228 static char symv[MAXSYM][MAXSTR];
229 static int valv[MAXSYM];
231 static char refv[MAXSYM][MAXSTR];
232 static int *pntv[MAXSYM];
237 static void make_sym(const char *s, int v)
239 strncpy(symv[strc], s, MAXSTR - 1);
244 static void make_ref(const char *r, int *p)
246 strncpy(refv[refc], r, MAXSTR - 1);
251 static void resolve(void)
255 for (i = 0; i < refc; i++)
256 for (j = 0; j < strc; j++)
257 if (strncmp(refv[i], symv[j], MAXSTR) == 0)
259 *(pntv[i]) = valv[j];
264 /*---------------------------------------------------------------------------*/
267 * The following globals are used to cache target_positions. They are
268 * targeted by various entities and must be resolved in a second pass.
271 static float targ_p [MAXW][3];
272 static int targ_wi[MAXW];
273 static int targ_ji[MAXW];
276 static void targets(struct s_file *fp)
280 for (i = 0; i < fp->wc; i++)
281 v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
283 for (i = 0; i < fp->jc; i++)
284 v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
287 /*---------------------------------------------------------------------------*/
290 * The following code caches image sizes. Textures are referenced by
291 * name, but their sizes are necessary when computing texture
292 * coordinates. This code allows each file to be accessed only once
293 * regardless of the number of surfaces referring to it.
302 static struct _imagedata *imagedata = NULL;
303 static int image_n = 0;
304 static int image_alloc = 0;
306 #define IMAGE_REALLOC 32
308 static void free_imagedata()
314 for (i = 0; i < image_n; i++)
315 free(imagedata[i].s);
319 image_n = image_alloc = 0;
322 static int size_load(const char *file, int *w, int *h)
326 if ((p = image_load(file, w, h, NULL)))
334 static void size_image(const char *name, int *w, int *h)
341 for (i = 0; i < image_n; i++)
342 if (strncmp(imagedata[i].s, name, MAXSTR) == 0)
353 strcpy(jpg, name); strcat(jpg, ".jpg");
354 strcpy(png, name); strcat(png, ".png");
356 if (size_load(config_data(png), w, h) ||
357 size_load(config_data(jpg), w, h))
360 if (image_n + 1 >= image_alloc)
362 struct _imagedata *tmp =
363 (struct _imagedata *) malloc(sizeof(struct _imagedata) * (image_alloc + IMAGE_REALLOC));
366 printf("malloc error\n");
371 (void) memcpy(tmp, imagedata, sizeof(struct _imagedata) * image_alloc);
375 image_alloc += IMAGE_REALLOC;
378 imagedata[image_n].s = (char *) calloc(strlen(name) + 1, 1);
379 imagedata[image_n].w = *w;
380 imagedata[image_n].h = *h;
381 strcpy(imagedata[image_n].s, name);
387 /*---------------------------------------------------------------------------*/
389 /* Read the given material file, adding a new material to the solid. */
391 static int read_mtrl(struct s_file *fp, const char *name)
397 for (mi = 0; mi < fp->mc; mi++)
398 if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
401 mp = fp->mv + incm(fp);
403 strncpy(mp->f, name, PATHMAX - 1);
405 mp->a[0] = mp->a[1] = mp->a[2] = mp->a[3] = 1.0f;
406 mp->d[0] = mp->d[1] = mp->d[2] = mp->d[3] = 1.0f;
407 mp->s[0] = mp->s[1] = mp->s[2] = mp->s[3] = 1.0f;
408 mp->e[0] = mp->e[1] = mp->e[2] = mp->e[3] = 1.0f;
412 if ((fin = fopen(config_data(name), "r")))
420 mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
421 mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
422 mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
423 mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
431 /*---------------------------------------------------------------------------*/
434 * All bodies with an associated path are assumed to be positioned at
435 * the beginning of that path. These bodies must be moved to the
436 * origin in order for their path transforms to behave correctly.
437 * This is how we get away with defining func_trains with no origin
441 static void move_side(struct s_side *sp, const float p[3])
443 sp->d -= v_dot(sp->n, p);
446 static void move_vert(struct s_vert *vp, const float p[3])
448 v_sub(vp->p, vp->p, p);
451 static void move_lump(struct s_file *fp,
452 struct s_lump *lp, const float p[3])
456 for (i = 0; i < lp->sc; i++)
457 move_side(fp->sv + fp->iv[lp->s0 + i], p);
458 for (i = 0; i < lp->vc; i++)
459 move_vert(fp->vv + fp->iv[lp->v0 + i], p);
462 static void move_body(struct s_file *fp,
467 /* Move the lumps. */
469 for (i = 0; i < bp->lc; i++)
470 move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
472 /* Create an array to mark any verts referenced by moved geoms. */
474 if (bp->gc > 0 && (b = (int *) calloc(fp->vc, sizeof (int))))
476 /* Mark the verts. */
478 for (i = 0; i < bp->gc; i++)
480 b[fp->gv[fp->iv[bp->g0 + i]].vi] = 1;
481 b[fp->gv[fp->iv[bp->g0 + i]].vj] = 1;
482 b[fp->gv[fp->iv[bp->g0 + i]].vk] = 1;
485 /* Apply the motion to the marked vertices. */
487 for (i = 0; i < fp->vc; ++i)
489 move_vert(fp->vv + i, fp->pv[bp->pi].p);
495 static void move_file(struct s_file *fp)
499 for (i = 0; i < fp->bc; i++)
500 if (fp->bv[i].pi >= 0)
501 move_body(fp, fp->bv + i);
504 /*---------------------------------------------------------------------------*/
507 * This is a basic OBJ loader. It is by no means fully compliant with
508 * the OBJ specification, but it works well with the output of
509 * Wings3D. All faces must be triangles and all vertices must include
510 * normals and texture coordinates. Material names are taken to be
511 * references to Neverball materials, rather than MTL definitions.
514 static void read_vt(struct s_file *fp, const char *line)
516 struct s_texc *tp = fp->tv + inct(fp);
518 sscanf(line, "%f %f", tp->u, tp->u + 1);
521 static void read_vn(struct s_file *fp, const char *line)
523 struct s_side *sp = fp->sv + incs(fp);
525 sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
528 static void read_v(struct s_file *fp, const char *line)
530 struct s_vert *vp = fp->vv + incv(fp);
532 sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
535 static void read_f(struct s_file *fp, const char *line,
536 int v0, int t0, int s0, int mi)
538 struct s_geom *gp = fp->gv + incg(fp);
543 sscanf(line, "%d%c%d%c%d %d%c%d%c%d %d%c%d%c%d",
544 &gp->vi, &c1, &gp->ti, &c2, &gp->si,
545 &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
546 &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
561 static void read_obj(struct s_file *fp, const char *name)
572 if ((fin = fopen(config_data(name), "r")))
574 while (fgets(line, MAXSTR, fin))
576 if (strncmp(line, "usemtl", 6) == 0)
578 sscanf(line + 6, "%s", mtrl);
579 mi = read_mtrl(fp, mtrl);
582 else if (strncmp(line, "f", 1) == 0)
584 if (fp->mv[mi].d[3] > 0)
585 read_f(fp, line + 1, v0, t0, s0, mi);
588 else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
589 else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
590 else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
596 /*---------------------------------------------------------------------------*/
598 static float plane_d[MAXS];
599 static float plane_n[MAXS][3];
600 static float plane_p[MAXS][3];
601 static float plane_u[MAXS][3];
602 static float plane_v[MAXS][3];
603 static int plane_f[MAXS];
604 static int plane_m[MAXS];
606 static void make_plane(int pi, int x0, int y0, int z0,
607 int x1, int y1, int z1,
608 int x2, int y2, int z2,
609 int tu, int tv, int r,
610 float su, float sv, int fl, const char *s)
612 static const float base[6][3][3] = {
613 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
614 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
615 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
616 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
617 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
618 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
622 float p0[3], p1[3], p2[3];
623 float u[3], v[3], p[3];
628 size_image(s, &w, &h);
630 plane_f[pi] = fl ? L_DETAIL : 0;
632 p0[0] = +(float) x0 / SCALE;
633 p0[1] = +(float) z0 / SCALE;
634 p0[2] = -(float) y0 / SCALE;
636 p1[0] = +(float) x1 / SCALE;
637 p1[1] = +(float) z1 / SCALE;
638 p1[2] = -(float) y1 / SCALE;
640 p2[0] = +(float) x2 / SCALE;
641 p2[1] = +(float) z2 / SCALE;
642 p2[2] = -(float) y2 / SCALE;
647 v_crs(plane_n[pi], u, v);
648 v_nrm(plane_n[pi], plane_n[pi]);
650 plane_d[pi] = v_dot(plane_n[pi], p1);
652 for (i = 0; i < 6; i++)
653 if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
663 m_rot(R, base[n][0], V_RAD(r));
665 v_mad(p, p, base[n][1], su * tu / SCALE);
666 v_mad(p, p, base[n][2], sv * tv / SCALE);
668 m_vxfm(plane_u[pi], R, base[n][1]);
669 m_vxfm(plane_v[pi], R, base[n][2]);
670 m_vxfm(plane_p[pi], R, p);
672 v_scl(plane_u[pi], plane_u[pi], 64.f / w);
673 v_scl(plane_v[pi], plane_v[pi], 64.f / h);
675 v_scl(plane_u[pi], plane_u[pi], 1.f / su);
676 v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
679 /*---------------------------------------------------------------------------*/
688 static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
692 if (fgets(buf, MAXSTR, fin))
702 /* Scan the beginning or end of a block. */
704 if (buf[0] == '{') return T_BEG;
705 if (buf[0] == '}') return T_END;
707 /* Scan a key-value pair. */
711 strcpy(key, strtok(buf, "\""));
712 (void) strtok(NULL, "\"");
713 strcpy(val, strtok(NULL, "\""));
724 "%s %d %d %d %f %f %d",
725 &c, &x0, &y0, &z0, &c,
726 &c, &x1, &y1, &z1, &c,
727 &c, &x2, &y2, &z2, &c,
728 key, &tu, &tv, &r, &su, &sv, &fl) == 22)
730 make_plane(pi, x0, y0, z0,
733 tu, tv, r, su, sv, fl, key);
737 /* If it's not recognized, it must be uninteresting. */
744 /*---------------------------------------------------------------------------*/
746 /* Parse a lump from the given file and add it to the solid. */
748 static void read_lump(struct s_file *fp, FILE *fin)
754 struct s_lump *lp = fp->lv + incl(fp);
758 while ((t = map_token(fin, fp->sc, k, v)))
762 fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
763 fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
764 fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
765 fp->sv[fp->sc].d = plane_d[fp->sc];
767 plane_m[fp->sc] = read_mtrl(fp, k);
769 fp->iv[fp->ic] = fp->sc;
779 /*---------------------------------------------------------------------------*/
781 static void make_path(struct s_file *fp,
783 char v[][MAXSTR], int c)
785 int i, pi = incp(fp);
787 struct s_path *pp = fp->pv + pi;
797 for (i = 0; i < c; i++)
799 if (strcmp(k[i], "targetname") == 0)
802 if (strcmp(k[i], "target") == 0)
803 make_ref(v[i], &pp->pi);
805 if (strcmp(k[i], "state") == 0)
808 if (strcmp(k[i], "speed") == 0)
809 sscanf(v[i], "%f", &pp->t);
811 if (strcmp(k[i], "smooth") == 0)
814 if (strcmp(k[i], "origin") == 0)
816 int x = 0, y = 0, z = 0;
818 sscanf(v[i], "%d %d %d", &x, &y, &z);
820 pp->p[0] = +(float) x / SCALE;
821 pp->p[1] = +(float) z / SCALE;
822 pp->p[2] = -(float) y / SCALE;
827 static void make_dict(struct s_file *fp,
831 int space_left, space_needed, di = incd(fp);
833 struct s_dict *dp = fp->dv + di;
835 space_left = MAXA - fp->ac;
836 space_needed = strlen(k) + 1 + strlen(v) + 1;
838 if (space_needed > space_left)
845 dp->aj = dp->ai + strlen(k) + 1;
846 fp->ac = dp->aj + strlen(v) + 1;
848 strncpy(fp->av + dp->ai, k, space_left);
849 strncpy(fp->av + dp->aj, v, space_left - strlen(k) - 1);
852 static int read_dict_entries = 0;
854 static void make_body(struct s_file *fp,
856 char v[][MAXSTR], int c, int l0)
858 int i, bi = incb(fp);
869 struct s_body *bp = fp->bv + bi;
875 for (i = 0; i < c; i++)
877 if (strcmp(k[i], "targetname") == 0)
880 else if (strcmp(k[i], "target") == 0)
881 make_ref(v[i], &bp->pi);
883 else if (strcmp(k[i], "model") == 0)
886 else if (strcmp(k[i], "origin") == 0)
887 sscanf(v[i], "%d %d %d", &x, &y, &z);
889 else if (read_dict_entries && strcmp(k[i], "classname") != 0)
890 make_dict(fp, k[i], v[i]);
894 bp->lc = fp->lc - l0;
896 bp->gc = fp->gc - g0;
898 for (i = 0; i < bp->gc; i++)
899 fp->iv[inci(fp)] = g0++;
901 p[0] = +(float) x / SCALE;
902 p[1] = +(float) z / SCALE;
903 p[2] = -(float) y / SCALE;
905 for (i = v0; i < fp->vc; i++)
906 v_add(fp->vv[i].p, fp->vv[i].p, p);
908 read_dict_entries = 0;
911 static void make_item(struct s_file *fp,
913 char v[][MAXSTR], int c)
915 int i, hi = inch(fp);
917 struct s_item *hp = fp->hv + hi;
926 for (i = 0; i < c; i++)
928 if (strcmp(k[i], "classname") == 0)
930 if (strcmp(v[i], "light") == 0)
932 else if (strcmp(v[i], "item_health_large") == 0)
934 else if (strcmp(v[i], "item_health_small") == 0)
938 if (strcmp(k[i], "light") == 0)
939 sscanf(v[i], "%d", &hp->n);
941 if (strcmp(k[i], "origin") == 0)
943 int x = 0, y = 0, z = 0;
945 sscanf(v[i], "%d %d %d", &x, &y, &z);
947 hp->p[0] = +(float) x / SCALE;
948 hp->p[1] = +(float) z / SCALE;
949 hp->p[2] = -(float) y / SCALE;
954 static void make_bill(struct s_file *fp,
956 char v[][MAXSTR], int c)
958 int i, ri = incr(fp);
960 struct s_bill *rp = fp->rv + ri;
962 memset(rp, 0, sizeof (struct s_bill));
965 for (i = 0; i < c; i++)
967 if (strcmp(k[i], "width") == 0)
968 sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
969 if (strcmp(k[i], "height") == 0)
970 sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
972 if (strcmp(k[i], "xrot") == 0)
973 sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
974 if (strcmp(k[i], "yrot") == 0)
975 sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
976 if (strcmp(k[i], "zrot") == 0)
977 sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
979 if (strcmp(k[i], "time") == 0)
980 sscanf(v[i], "%f", &rp->t);
981 if (strcmp(k[i], "dist") == 0)
982 sscanf(v[i], "%f", &rp->d);
983 if (strcmp(k[i], "flag") == 0)
984 sscanf(v[i], "%d", &rp->fl);
986 if (strcmp(k[i], "image") == 0)
988 rp->mi = read_mtrl(fp, v[i]);
989 fp->mv[rp->mi].fl |= M_CLAMPED;
992 if (strcmp(k[i], "origin") == 0)
994 int x = 0, y = 0, z = 0;
997 sscanf(v[i], "%d %d %d", &x, &y, &z);
999 p[0] = +(float) x / SCALE;
1000 p[1] = +(float) z / SCALE;
1001 p[2] = -(float) y / SCALE;
1004 rp->rx[0] = V_DEG(fatan2f(+p[1], rp->d));
1005 rp->ry[0] = V_DEG(fatan2f(+p[0], -p[2]));
1009 if (rp->fl & B_ADDITIVE)
1010 fp->mv[rp->mi].fl |= M_ADDITIVE;
1013 static void make_goal(struct s_file *fp,
1015 char v[][MAXSTR], int c)
1017 int i, zi = incz(fp);
1019 struct s_goal *zp = fp->zv + zi;
1026 for (i = 0; i < c; i++)
1028 if (strcmp(k[i], "radius") == 0)
1029 sscanf(v[i], "%f", &zp->r);
1031 if (strcmp(k[i], "origin") == 0)
1033 int x = 0, y = 0, z = 0;
1035 sscanf(v[i], "%d %d %d", &x, &y, &z);
1037 zp->p[0] = +(float) (x) / SCALE;
1038 zp->p[1] = +(float) (z - 24) / SCALE;
1039 zp->p[2] = -(float) (y) / SCALE;
1044 static void make_view(struct s_file *fp,
1046 char v[][MAXSTR], int c)
1048 int i, wi = incw(fp);
1050 struct s_view *wp = fp->wv + wi;
1059 for (i = 0; i < c; i++)
1061 if (strcmp(k[i], "target") == 0)
1062 make_ref(v[i], targ_wi + wi);
1064 if (strcmp(k[i], "origin") == 0)
1066 int x = 0, y = 0, z = 0;
1068 sscanf(v[i], "%d %d %d", &x, &y, &z);
1070 wp->p[0] = +(float) x / SCALE;
1071 wp->p[1] = +(float) z / SCALE;
1072 wp->p[2] = -(float) y / SCALE;
1077 static void make_jump(struct s_file *fp,
1079 char v[][MAXSTR], int c)
1081 int i, ji = incj(fp);
1083 struct s_jump *jp = fp->jv + ji;
1093 for (i = 0; i < c; i++)
1095 if (strcmp(k[i], "radius") == 0)
1096 sscanf(v[i], "%f", &jp->r);
1098 if (strcmp(k[i], "target") == 0)
1099 make_ref(v[i], targ_ji + ji);
1101 if (strcmp(k[i], "origin") == 0)
1103 int x = 0, y = 0, z = 0;
1105 sscanf(v[i], "%d %d %d", &x, &y, &z);
1107 jp->p[0] = +(float) x / SCALE;
1108 jp->p[1] = +(float) z / SCALE;
1109 jp->p[2] = -(float) y / SCALE;
1114 static void make_swch(struct s_file *fp,
1116 char v[][MAXSTR], int c)
1118 int i, xi = incx(fp);
1120 struct s_swch *xp = fp->xv + xi;
1133 for (i = 0; i < c; i++)
1135 if (strcmp(k[i], "radius") == 0)
1136 sscanf(v[i], "%f", &xp->r);
1138 if (strcmp(k[i], "target") == 0)
1139 make_ref(v[i], &xp->pi);
1141 if (strcmp(k[i], "timer") == 0)
1142 sscanf(v[i], "%f", &xp->t0);
1144 if (strcmp(k[i], "state") == 0)
1147 xp->f0 = atoi(v[i]);
1150 if (strcmp(k[i], "invisible") == 0)
1153 if (strcmp(k[i], "origin") == 0)
1155 int x = 0, y = 0, z = 0;
1157 sscanf(v[i], "%d %d %d", &x, &y, &z);
1159 xp->p[0] = +(float) x / SCALE;
1160 xp->p[1] = +(float) z / SCALE;
1161 xp->p[2] = -(float) y / SCALE;
1166 static void make_targ(struct s_file *fp,
1168 char v[][MAXSTR], int c)
1172 targ_p[targ_n][0] = 0.f;
1173 targ_p[targ_n][1] = 0.f;
1174 targ_p[targ_n][3] = 0.f;
1176 for (i = 0; i < c; i++)
1178 if (strcmp(k[i], "targetname") == 0)
1179 make_sym(v[i], targ_n);
1181 if (strcmp(k[i], "origin") == 0)
1183 int x = 0, y = 0, z = 0;
1185 sscanf(v[i], "%d %d %d", &x, &y, &z);
1187 targ_p[targ_n][0] = +(float) x / SCALE;
1188 targ_p[targ_n][1] = +(float) z / SCALE;
1189 targ_p[targ_n][2] = -(float) y / SCALE;
1196 static void make_ball(struct s_file *fp,
1198 char v[][MAXSTR], int c)
1200 int i, ui = incu(fp);
1202 struct s_ball *up = fp->uv + ui;
1226 for (i = 0; i < c; i++)
1228 if (strcmp(k[i], "radius") == 0)
1229 sscanf(v[i], "%f", &up->r);
1231 if (strcmp(k[i], "origin") == 0)
1233 int x = 0, y = 0, z = 0;
1235 sscanf(v[i], "%d %d %d", &x, &y, &z);
1237 up->p[0] = +(float) (x) / SCALE;
1238 up->p[1] = +(float) (z - 24) / SCALE;
1239 up->p[2] = -(float) (y) / SCALE;
1243 up->p[1] += up->r + SMALL;
1246 /*---------------------------------------------------------------------------*/
1248 static void read_ent(struct s_file *fp, FILE *fin)
1250 char k[MAXKEY][MAXSTR];
1251 char v[MAXKEY][MAXSTR];
1252 int t, i = 0, c = 0;
1256 while ((t = map_token(fin, -1, k[c], v[c])))
1260 if (strcmp(k[c], "classname") == 0)
1264 if (t == T_BEG) read_lump(fp, fin);
1265 if (t == T_END) break;
1268 if (!strcmp(v[i], "light")) make_item(fp, k, v, c);
1269 if (!strcmp(v[i], "item_health_large")) make_item(fp, k, v, c);
1270 if (!strcmp(v[i], "item_health_small")) make_item(fp, k, v, c);
1271 if (!strcmp(v[i], "info_camp")) make_swch(fp, k, v, c);
1272 if (!strcmp(v[i], "info_null")) make_bill(fp, k, v, c);
1273 if (!strcmp(v[i], "path_corner")) make_path(fp, k, v, c);
1274 if (!strcmp(v[i], "info_player_start")) make_ball(fp, k, v, c);
1275 if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1276 if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
1277 if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
1278 if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
1279 if (!strcmp(v[i], "worldspawn"))
1281 read_dict_entries = 1;
1282 make_body(fp, k, v, c, l0);
1284 if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
1285 if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
1288 static void read_map(struct s_file *fp, FILE *fin)
1294 while ((t = map_token(fin, -1, k, v)))
1299 /*---------------------------------------------------------------------------*/
1301 /* Test the location of a point with respect to a side plane. */
1303 static int fore_side(const float p[3], const struct s_side *sp)
1305 return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1308 static int on_side(const float p[3], const struct s_side *sp)
1310 float d = v_dot(p, sp->n) - sp->d;
1312 return (-SMALL < d && d < +SMALL) ? 1 : 0;
1315 /*---------------------------------------------------------------------------*/
1317 * Confirm that the addition of a vert would not result in degenerate
1321 static int ok_vert(const struct s_file *fp,
1322 const struct s_lump *lp, const float p[3])
1327 for (i = 0; i < lp->vc; i++)
1329 float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1333 if (v_len(r) < SMALL)
1339 /*---------------------------------------------------------------------------*/
1342 * The following functions take the set of planes defining a lump and
1343 * find the verts, edges, and geoms that describe its boundaries. To
1344 * do this, they first find the verts, and then search these verts for
1345 * valid edges and geoms. It may be more efficient to compute edges
1346 * and geoms directly by clipping down infinite line segments and
1347 * planes, but this would be more complex and prone to numerical
1352 * Given 3 side planes, compute the point of intersection, if any.
1353 * Confirm that this point falls within the current lump, and that it
1354 * is unique. Add it as a vert of the solid.
1356 static void clip_vert(struct s_file *fp,
1357 struct s_lump *lp, int si, int sj, int sk)
1359 float M[16], X[16], I[16];
1363 d[0] = fp->sv[si].d;
1364 d[1] = fp->sv[sj].d;
1365 d[2] = fp->sv[sk].d;
1367 m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1374 for (i = 0; i < lp->sc; i++)
1376 int si = fp->iv[lp->s0 + i];
1378 if (fore_side(p, fp->sv + si))
1382 if (ok_vert(fp, lp, p))
1384 v_cpy(fp->vv[fp->vc].p, p);
1386 fp->iv[fp->ic] = fp->vc;
1395 * Given two side planes, find an edge along their intersection by
1396 * finding a pair of vertices that fall on both planes. Add it to the
1399 static void clip_edge(struct s_file *fp,
1400 struct s_lump *lp, int si, int sj)
1404 for (i = 1; i < lp->vc; i++)
1405 for (j = 0; j < i; j++)
1407 int vi = fp->iv[lp->v0 + i];
1408 int vj = fp->iv[lp->v0 + j];
1410 if (on_side(fp->vv[vi].p, fp->sv + si) &&
1411 on_side(fp->vv[vj].p, fp->sv + si) &&
1412 on_side(fp->vv[vi].p, fp->sv + sj) &&
1413 on_side(fp->vv[vj].p, fp->sv + sj))
1415 fp->ev[fp->ec].vi = vi;
1416 fp->ev[fp->ec].vj = vj;
1418 fp->iv[fp->ic] = fp->ec;
1428 * Find all verts that lie on the given side of the lump. Sort these
1429 * verts to have a counter-clockwise winding about the plane normal.
1430 * Create geoms to tessellate the resulting convex polygon.
1432 static void clip_geom(struct s_file *fp,
1433 struct s_lump *lp, int si)
1435 int m[256], t[256], d, i, j, n = 0;
1440 struct s_side *sp = fp->sv + si;
1444 for (i = 0; i < lp->vc; i++)
1446 int vi = fp->iv[lp->v0 + i];
1448 if (on_side(fp->vv[vi].p, sp))
1453 v_add(v, fp->vv[vi].p, plane_p[si]);
1455 fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1456 fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1464 for (i = 1; i < n; i++)
1465 for (j = i + 1; j < n; j++)
1467 v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1468 v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1471 if (v_dot(w, sp->n) < 0.f)
1485 for (i = 0; i < n - 2; i++)
1487 fp->gv[fp->gc].mi = plane_m[si];
1489 fp->gv[fp->gc].ti = t[0];
1490 fp->gv[fp->gc].tj = t[i + 1];
1491 fp->gv[fp->gc].tk = t[i + 2];
1493 fp->gv[fp->gc].si = si;
1494 fp->gv[fp->gc].sj = si;
1495 fp->gv[fp->gc].sk = si;
1497 fp->gv[fp->gc].vi = m[0];
1498 fp->gv[fp->gc].vj = m[i + 1];
1499 fp->gv[fp->gc].vk = m[i + 2];
1501 fp->iv[fp->ic] = fp->gc;
1509 * Iterate the sides of the lump, attempting to generate a new vert for
1510 * each trio of planes, a new edge for each pair of planes, and a new
1511 * set of geom for each visible plane.
1513 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1520 for (i = 2; i < lp->sc; i++)
1521 for (j = 1; j < i; j++)
1522 for (k = 0; k < j; k++)
1526 fp->iv[lp->s0 + k]);
1531 for (i = 1; i < lp->sc; i++)
1532 for (j = 0; j < i; j++)
1535 fp->iv[lp->s0 + j]);
1540 for (i = 0; i < lp->sc; i++)
1541 if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0)
1543 fp->iv[lp->s0 + i]);
1545 for (i = 0; i < lp->sc; i++)
1546 if (plane_f[fp->iv[lp->s0 + i]])
1550 static void clip_file(struct s_file *fp)
1554 for (i = 0; i < fp->lc; i++)
1555 clip_lump(fp, fp->lv + i);
1558 /*---------------------------------------------------------------------------*/
1561 * For each body element type, determine if element 'p' is equivalent
1562 * to element 'q'. This is more than a simple memory compare. It
1563 * effectively snaps mtrls and verts together, and may reverse the
1564 * winding of an edge or a geom. This is done in order to maximize
1565 * the number of elements that can be eliminated.
1568 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1570 if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1571 if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1572 if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1573 if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1575 if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1576 if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1577 if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1578 if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1580 if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1581 if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1582 if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1583 if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1585 if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1586 if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1587 if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1588 if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1590 if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1592 if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1597 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1599 if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1600 if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1601 if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1606 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1608 if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1609 if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1614 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1616 if (fabs(sp->d - sq->d) > SMALL) return 0;
1617 if (v_dot(sp->n, sq->n) < 0.9999) return 0;
1622 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1624 if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1625 if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1630 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1632 if (gp->mi != gq->mi) return 0;
1634 if (gp->ti != gq->ti) return 0;
1635 if (gp->si != gq->si) return 0;
1636 if (gp->vi != gq->vi) return 0;
1638 if (gp->tj != gq->tj) return 0;
1639 if (gp->sj != gq->sj) return 0;
1640 if (gp->vj != gq->vj) return 0;
1642 if (gp->tk != gq->tk) return 0;
1643 if (gp->sk != gq->sk) return 0;
1644 if (gp->vk != gq->vk) return 0;
1649 /*---------------------------------------------------------------------------*/
1652 * For each file element type, replace all references to element 'i'
1653 * with a reference to element 'j'. These are used when optimizing
1654 * and sorting the file.
1657 static void swap_mtrl(struct s_file *fp, int mi, int mj)
1661 for (i = 0; i < fp->gc; i++)
1662 if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1663 for (i = 0; i < fp->rc; i++)
1664 if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1667 static void swap_vert(struct s_file *fp, int vi, int vj)
1671 for (i = 0; i < fp->ec; i++)
1673 if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1674 if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1677 for (i = 0; i < fp->gc; i++)
1679 if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1680 if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1681 if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1684 for (i = 0; i < fp->lc; i++)
1685 for (j = 0; j < fp->lv[i].vc; j++)
1686 if (fp->iv[fp->lv[i].v0 + j] == vi)
1687 fp->iv[fp->lv[i].v0 + j] = vj;
1690 static void swap_edge(struct s_file *fp, int ei, int ej)
1694 for (i = 0; i < fp->lc; i++)
1695 for (j = 0; j < fp->lv[i].ec; j++)
1696 if (fp->iv[fp->lv[i].e0 + j] == ei)
1697 fp->iv[fp->lv[i].e0 + j] = ej;
1700 static void swap_side(struct s_file *fp, int si, int sj)
1704 for (i = 0; i < fp->gc; i++)
1706 if (fp->gv[i].si == si) fp->gv[i].si = sj;
1707 if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1708 if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1710 for (i = 0; i < fp->nc; i++)
1711 if (fp->nv[i].si == si) fp->nv[i].si = sj;
1713 for (i = 0; i < fp->lc; i++)
1714 for (j = 0; j < fp->lv[i].sc; j++)
1715 if (fp->iv[fp->lv[i].s0 + j] == si)
1716 fp->iv[fp->lv[i].s0 + j] = sj;
1719 static void swap_texc(struct s_file *fp, int ti, int tj)
1723 for (i = 0; i < fp->gc; i++)
1725 if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1726 if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1727 if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1732 static void swap_geom(struct s_file *fp, int gi, int gj)
1736 for (i = 0; i < fp->lc; i++)
1737 for (j = 0; j < fp->lv[i].gc; j++)
1738 if (fp->iv[fp->lv[i].g0 + j] == gi)
1739 fp->iv[fp->lv[i].g0 + j] = gj;
1741 for (i = 0; i < fp->bc; i++)
1742 for (j = 0; j < fp->bv[i].gc; j++)
1743 if (fp->iv[fp->bv[i].g0 + j] == gi)
1744 fp->iv[fp->bv[i].g0 + j] = gj;
1747 /*---------------------------------------------------------------------------*/
1749 static void uniq_mtrl(struct s_file *fp)
1753 for (i = 0; i < fp->mc; i++)
1755 for (j = 0; j < k; j++)
1756 if (comp_mtrl(fp->mv + i, fp->mv + j))
1758 swap_mtrl(fp, i, j);
1766 fp->mv[k] = fp->mv[i];
1767 swap_mtrl(fp, i, k);
1776 static void uniq_vert(struct s_file *fp)
1780 for (i = 0; i < fp->vc; i++)
1782 for (j = 0; j < k; j++)
1783 if (comp_vert(fp->vv + i, fp->vv + j))
1785 swap_vert(fp, i, j);
1793 fp->vv[k] = fp->vv[i];
1794 swap_vert(fp, i, k);
1803 static void uniq_edge(struct s_file *fp)
1807 for (i = 0; i < fp->ec; i++)
1809 for (j = 0; j < k; j++)
1810 if (comp_edge(fp->ev + i, fp->ev + j))
1812 swap_edge(fp, i, j);
1820 fp->ev[k] = fp->ev[i];
1821 swap_edge(fp, i, k);
1830 static void uniq_geom(struct s_file *fp)
1834 for (i = 0; i < fp->gc; i++)
1836 for (j = 0; j < k; j++)
1837 if (comp_geom(fp->gv + i, fp->gv + j))
1839 swap_geom(fp, i, j);
1847 fp->gv[k] = fp->gv[i];
1848 swap_geom(fp, i, k);
1857 static void uniq_texc(struct s_file *fp)
1861 for (i = 0; i < fp->tc; i++)
1863 for (j = 0; j < k; j++)
1864 if (comp_texc(fp->tv + i, fp->tv + j))
1866 swap_texc(fp, i, j);
1874 fp->tv[k] = fp->tv[i];
1875 swap_texc(fp, i, k);
1884 static void uniq_side(struct s_file *fp)
1888 for (i = 0; i < fp->sc; i++)
1890 for (j = 0; j < k; j++)
1891 if (comp_side(fp->sv + i, fp->sv + j))
1893 swap_side(fp, i, j);
1901 fp->sv[k] = fp->sv[i];
1902 swap_side(fp, i, k);
1911 static void uniq_file(struct s_file *fp)
1913 /* Debug mode skips optimization, producing oversized output files. */
1915 if (debug_output == 0)
1926 /*---------------------------------------------------------------------------*/
1928 static void sort_file(struct s_file *fp)
1932 /* Sort billboards farthest to nearest. */
1934 for (i = 0; i < fp->rc; i++)
1935 for (j = i + 1; j < fp->rc; j++)
1936 if (fp->rv[j].d > fp->rv[i].d)
1941 fp->rv[i] = fp->rv[j];
1945 /* Ensure the first vertex is the lowest. */
1947 for (i = 0; i < fp->vc; i++)
1948 if (fp->vv[0].p[1] > fp->vv[i].p[1])
1953 fp->vv[0] = fp->vv[i];
1956 swap_vert(fp, 0, -1);
1957 swap_vert(fp, i, 0);
1958 swap_vert(fp, -1, i);
1962 /*---------------------------------------------------------------------------*/
1964 static int test_lump_side(const struct s_file *fp,
1965 const struct s_lump *lp,
1966 const struct s_side *sp)
1974 /* If the given side is part of the given lump, then the lump is behind. */
1976 for (si = 0; si < lp->sc; si++)
1977 if (fp->sv + fp->iv[lp->s0 + si] == sp)
1980 /* Check if each lump vertex is in front of, behind, on the side. */
1982 for (vi = 0; vi < lp->vc; vi++)
1984 float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
1990 /* If no verts are behind, the lump is in front, and vice versa. */
1992 if (f > 0 && b == 0) return +1;
1993 if (b > 0 && f == 0) return -1;
1995 /* Else, the lump crosses the side. */
2000 static int node_node(struct s_file *fp, int l0, int lc)
2004 /* Base case. Dump all given lumps into a leaf node. */
2006 fp->nv[fp->nc].si = -1;
2007 fp->nv[fp->nc].ni = -1;
2008 fp->nv[fp->nc].nj = -1;
2009 fp->nv[fp->nc].l0 = l0;
2010 fp->nv[fp->nc].lc = lc;
2020 int li = 0, lic = 0;
2021 int lj = 0, ljc = 0;
2022 int lk = 0, lkc = 0;
2025 /* Find the side that most evenly splits the given lumps. */
2027 for (si = 0; si < fp->sc; si++)
2033 for (li = 0; li < lc; li++)
2034 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
2041 if ((d < sjd) || (d == sjd && o < sjo))
2049 /* Flag each lump with its position WRT the side. */
2051 for (li = 0; li < lc; li++)
2054 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2058 switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
2061 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10;
2065 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2069 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40;
2074 /* Sort all lumps in the range by their flag values. */
2076 for (li = 1; li < lc; li++)
2077 for (lj = 0; lj < li; lj++)
2078 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
2082 l = fp->lv[l0 + li];
2083 fp->lv[l0 + li] = fp->lv[l0 + lj];
2084 fp->lv[l0 + lj] = l;
2087 /* Establish the in-front, on, and behind lump ranges. */
2093 for (i = lc - 1; i >= 0; i--)
2094 switch (fp->lv[l0 + i].fl & 0xf0)
2096 case 0x10: li = l0 + i; lic++; break;
2097 case 0x20: lj = l0 + i; ljc++; break;
2098 case 0x40: lk = l0 + i; lkc++; break;
2101 /* Add the lumps on the side to the node. */
2106 fp->nv[i].ni = node_node(fp, li, lic);
2108 fp->nv[i].nj = node_node(fp, lk, lkc);
2116 static void node_file(struct s_file *fp)
2120 /* Sort the lumps of each body into BSP nodes. */
2122 for (bi = 0; bi < fp->bc; bi++)
2123 fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
2126 /*---------------------------------------------------------------------------*/
2128 static void dump_file(struct s_file *p, const char *name)
2130 /* FIXME: Count visible geoms.
2132 * I'm afraid items break this (not sure though) so leaving it out.
2142 int m = p->rc + p->cc * 128 + (p->zc * p->jc + p->xc) * 32;
2145 /* Count the number of solid lumps. */
2147 for (i = 0; i < p->lc; i++)
2148 if ((p->lv[i].fl & 1) == 0)
2152 /* Count the number of visible geoms. */
2154 for (i = 0; i < p->bc; i++)
2156 for (j = 0; j < p->bv[i].lc; j++)
2157 m += p->lv[p->bv[i].l0 + j].gc;
2162 /* Count the total value of all coins. */
2164 for (i = 0; i < p->hc; i++)
2165 if (p->hv[i].t == ITEM_COIN)
2169 printf("%s (%d/%d/$%d)\n"
2171 printf("%s (%d/$%d)\n"
2172 " mtrl vert edge side texc"
2173 " geom lump path node body\n"
2174 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
2175 " item goal view jump swch"
2176 " bill ball char dict indx\n"
2177 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
2182 p->mc, p->vc, p->ec, p->sc, p->tc,
2183 p->gc, p->lc, p->pc, p->nc, p->bc,
2184 p->hc, p->zc, p->wc, p->jc, p->xc,
2185 p->rc, p->uc, p->ac, p->dc, p->ic);
2188 int main(int argc, char *argv[])
2197 if (argc > 3 && strcmp(argv[3], "--debug") == 0)
2200 if (config_data_path(argv[2], NULL))
2202 strncpy(src, argv[1], MAXSTR);
2203 strncpy(dst, argv[1], MAXSTR);
2205 if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
2206 strcpy(dst + strlen(dst) - 4, ".sol");
2208 strcat(dst, ".sol");
2210 if ((fin = fopen(src, "r")))
2232 else fprintf(stderr, "Failure to establish data directory\n");
2234 else fprintf(stderr, "Usage: %s <map> <data> [--debug]\n", argv[0]);