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 /*---------------------------------------------------------------------------*/
18 #include <SDL_image.h>
26 #include "base_config.h"
34 * The overall design of this map converter is very stupid, but very
35 * simple. It begins by assuming that every mtrl, vert, edge, side,
36 * and texc in the map is unique. It then makes an optimizing pass
37 * that discards redundant information. The result is optimal, though
38 * the process is terribly inefficient.
41 /*---------------------------------------------------------------------------*/
43 static int debug_output = 0;
45 /*---------------------------------------------------------------------------*/
47 /* Ohhhh... arbitrary! */
70 static int overflow(const char *s)
72 printf("%s overflow\n", s);
77 static int incm(struct s_file *fp)
79 return (fp->mc < MAXM) ? fp->mc++ : overflow("mtrl");
82 static int incv(struct s_file *fp)
84 return (fp->vc < MAXV) ? fp->vc++ : overflow("vert");
87 static int ince(struct s_file *fp)
89 return (fp->ec < MAXE) ? fp->ec++ : overflow("edge");
92 static int incs(struct s_file *fp)
94 return (fp->sc < MAXS) ? fp->sc++ : overflow("side");
97 static int inct(struct s_file *fp)
99 return (fp->tc < MAXT) ? fp->tc++ : overflow("texc");
102 static int incg(struct s_file *fp)
104 return (fp->gc < MAXG) ? fp->gc++ : overflow("geom");
107 static int incl(struct s_file *fp)
109 return (fp->lc < MAXL) ? fp->lc++ : overflow("lump");
112 static int incn(struct s_file *fp)
114 return (fp->nc < MAXN) ? fp->nc++ : overflow("node");
117 static int incp(struct s_file *fp)
119 return (fp->pc < MAXP) ? fp->pc++ : overflow("path");
122 static int incb(struct s_file *fp)
124 return (fp->bc < MAXB) ? fp->bc++ : overflow("body");
127 static int inch(struct s_file *fp)
129 return (fp->hc < MAXH) ? fp->hc++ : overflow("item");
132 static int incz(struct s_file *fp)
134 return (fp->zc < MAXZ) ? fp->zc++ : overflow("goal");
137 static int incj(struct s_file *fp)
139 return (fp->jc < MAXJ) ? fp->jc++ : overflow("jump");
142 static int incx(struct s_file *fp)
144 return (fp->xc < MAXX) ? fp->xc++ : overflow("swch");
147 static int incr(struct s_file *fp)
149 return (fp->rc < MAXR) ? fp->rc++ : overflow("bill");
152 static int incu(struct s_file *fp)
154 return (fp->uc < MAXU) ? fp->uc++ : overflow("ball");
157 static int incw(struct s_file *fp)
159 return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
162 static int incd(struct s_file *fp)
164 return (fp->dc < MAXD) ? fp->dc++ : overflow("dict");
167 static int inci(struct s_file *fp)
169 return (fp->ic < MAXI) ? fp->ic++ : overflow("indx");
172 static void init_file(struct s_file *fp)
195 fp->mv = (struct s_mtrl *) calloc(MAXM, sizeof (struct s_mtrl));
196 fp->vv = (struct s_vert *) calloc(MAXV, sizeof (struct s_vert));
197 fp->ev = (struct s_edge *) calloc(MAXE, sizeof (struct s_edge));
198 fp->sv = (struct s_side *) calloc(MAXS, sizeof (struct s_side));
199 fp->tv = (struct s_texc *) calloc(MAXT, sizeof (struct s_texc));
200 fp->gv = (struct s_geom *) calloc(MAXG, sizeof (struct s_geom));
201 fp->lv = (struct s_lump *) calloc(MAXL, sizeof (struct s_lump));
202 fp->nv = (struct s_node *) calloc(MAXN, sizeof (struct s_node));
203 fp->pv = (struct s_path *) calloc(MAXP, sizeof (struct s_path));
204 fp->bv = (struct s_body *) calloc(MAXB, sizeof (struct s_body));
205 fp->hv = (struct s_item *) calloc(MAXH, sizeof (struct s_item));
206 fp->zv = (struct s_goal *) calloc(MAXZ, sizeof (struct s_goal));
207 fp->jv = (struct s_jump *) calloc(MAXJ, sizeof (struct s_jump));
208 fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
209 fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
210 fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
211 fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
212 fp->dv = (struct s_dict *) calloc(MAXD, sizeof (struct s_dict));
213 fp->av = (char *) calloc(MAXA, sizeof (char));
214 fp->iv = (int *) calloc(MAXI, sizeof (int));
217 /*---------------------------------------------------------------------------*/
220 * The following is a small symbol table data structure. Symbols and
221 * their integer values are collected in symv and valv. References
222 * and pointers to their unsatisfied integer values are collected in
223 * refv and pntv. The resolve procedure matches references to symbols
224 * and fills waiting ints with the proper values.
229 static char symv[MAXSYM][MAXSTR];
230 static int valv[MAXSYM];
232 static char refv[MAXSYM][MAXSTR];
233 static int *pntv[MAXSYM];
238 static void make_sym(const char *s, int v)
240 strncpy(symv[strc], s, MAXSTR - 1);
245 static void make_ref(const char *r, int *p)
247 strncpy(refv[refc], r, MAXSTR - 1);
252 static void resolve(void)
256 for (i = 0; i < refc; i++)
257 for (j = 0; j < strc; j++)
258 if (strncmp(refv[i], symv[j], MAXSTR) == 0)
260 *(pntv[i]) = valv[j];
265 /*---------------------------------------------------------------------------*/
268 * The following globals are used to cache target_positions. They are
269 * targeted by various entities and must be resolved in a second pass.
272 static float targ_p [MAXW][3];
273 static int targ_wi[MAXW];
274 static int targ_ji[MAXW];
277 static void targets(struct s_file *fp)
281 for (i = 0; i < fp->wc; i++)
282 v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
284 for (i = 0; i < fp->jc; i++)
285 v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
288 /*---------------------------------------------------------------------------*/
291 * The following code caches image sizes. Textures are referenced by
292 * name, but their sizes are necessary when computing texture
293 * coordinates. This code allows each file to be accessed only once
294 * regardless of the number of surfaces referring to it.
303 static struct _imagedata *imagedata = NULL;
304 static int image_n = 0;
305 static int image_alloc = 0;
307 #define IMAGE_REALLOC 32
309 static void free_imagedata()
315 for (i = 0; i < image_n; i++)
316 free(imagedata[i].s);
320 image_n = image_alloc = 0;
323 static int size_load(const char *file, int *w, int *h)
327 if ((S = IMG_Load(file)))
339 static void size_image(const char *name, int *w, int *h)
347 for (i = 0; i < image_n; i++)
348 if (strncmp(imagedata[i].s, name, MAXSTR) == 0)
359 strcpy(jpg, name); strcat(jpg, ".jpg");
360 strcpy(tga, name); strcat(tga, ".tga");
361 strcpy(png, name); strcat(png, ".png");
363 if (size_load(config_data(png), w, h) ||
364 size_load(config_data(tga), w, h) ||
365 size_load(config_data(jpg), w, h))
368 if (image_n + 1 >= image_alloc)
370 struct _imagedata *tmp =
371 (struct _imagedata *) malloc(sizeof(struct _imagedata) * (image_alloc + IMAGE_REALLOC));
374 printf("malloc error\n");
379 (void) memcpy(tmp, imagedata, sizeof(struct _imagedata) * image_alloc);
383 image_alloc += IMAGE_REALLOC;
386 imagedata[image_n].s = (char *) calloc(strlen(name) + 1, 1);
387 imagedata[image_n].w = *w;
388 imagedata[image_n].h = *h;
389 strcpy(imagedata[image_n].s, name);
395 /*---------------------------------------------------------------------------*/
397 /* Read the given material file, adding a new material to the solid. */
399 static int read_mtrl(struct s_file *fp, const char *name)
405 for (mi = 0; mi < fp->mc; mi++)
406 if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
409 mp = fp->mv + incm(fp);
411 strncpy(mp->f, name, PATHMAX - 1);
413 mp->a[0] = mp->a[1] = mp->a[2] = mp->a[3] = 1.0f;
414 mp->d[0] = mp->d[1] = mp->d[2] = mp->d[3] = 1.0f;
415 mp->s[0] = mp->s[1] = mp->s[2] = mp->s[3] = 1.0f;
416 mp->e[0] = mp->e[1] = mp->e[2] = mp->e[3] = 1.0f;
420 if ((fin = fopen(config_data(name), "r")))
428 mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
429 mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
430 mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
431 mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
439 /*---------------------------------------------------------------------------*/
442 * All bodies with an associated path are assumed to be positioned at
443 * the beginning of that path. These bodies must be moved to the
444 * origin in order for their path transforms to behave correctly.
445 * This is how we get away with defining func_trains with no origin
449 static void move_side(struct s_side *sp, const float p[3])
451 sp->d -= v_dot(sp->n, p);
454 static void move_vert(struct s_vert *vp, const float p[3])
456 v_sub(vp->p, vp->p, p);
459 static void move_lump(struct s_file *fp,
460 struct s_lump *lp, const float p[3])
464 for (i = 0; i < lp->sc; i++)
465 move_side(fp->sv + fp->iv[lp->s0 + i], p);
466 for (i = 0; i < lp->vc; i++)
467 move_vert(fp->vv + fp->iv[lp->v0 + i], p);
470 static void move_body(struct s_file *fp,
475 /* Move the lumps. */
477 for (i = 0; i < bp->lc; i++)
478 move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
480 /* Create an array to mark any verts referenced by moved geoms. */
482 if (bp->gc > 0 && (b = (int *) calloc(fp->vc, sizeof (int))))
484 /* Mark the verts. */
486 for (i = 0; i < bp->gc; i++)
488 b[fp->gv[fp->iv[bp->g0 + i]].vi] = 1;
489 b[fp->gv[fp->iv[bp->g0 + i]].vj] = 1;
490 b[fp->gv[fp->iv[bp->g0 + i]].vk] = 1;
493 /* Apply the motion to the marked vertices. */
495 for (i = 0; i < fp->vc; ++i)
497 move_vert(fp->vv + i, fp->pv[bp->pi].p);
503 static void move_file(struct s_file *fp)
507 for (i = 0; i < fp->bc; i++)
508 if (fp->bv[i].pi >= 0)
509 move_body(fp, fp->bv + i);
512 /*---------------------------------------------------------------------------*/
515 * This is a basic OBJ loader. It is by no means fully compliant with
516 * the OBJ specification, but it works well with the output of
517 * Wings3D. All faces must be triangles and all vertices must include
518 * normals and texture coordinates. Material names are taken to be
519 * references to Neverball materials, rather than MTL definitions.
522 static void read_vt(struct s_file *fp, const char *line)
524 struct s_texc *tp = fp->tv + inct(fp);
526 sscanf(line, "%f %f", tp->u, tp->u + 1);
529 static void read_vn(struct s_file *fp, const char *line)
531 struct s_side *sp = fp->sv + incs(fp);
533 sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
536 static void read_v(struct s_file *fp, const char *line)
538 struct s_vert *vp = fp->vv + incv(fp);
540 sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
543 static void read_f(struct s_file *fp, const char *line,
544 int v0, int t0, int s0, int mi)
546 struct s_geom *gp = fp->gv + incg(fp);
551 sscanf(line, "%d%c%d%c%d %d%c%d%c%d %d%c%d%c%d",
552 &gp->vi, &c1, &gp->ti, &c2, &gp->si,
553 &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
554 &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
569 static void read_obj(struct s_file *fp, const char *name)
580 if ((fin = fopen(config_data(name), "r")))
582 while (fgets(line, MAXSTR, fin))
584 if (strncmp(line, "usemtl", 6) == 0)
586 sscanf(line + 6, "%s", mtrl);
587 mi = read_mtrl(fp, mtrl);
590 else if (strncmp(line, "f", 1) == 0)
592 if (fp->mv[mi].d[3] > 0)
593 read_f(fp, line + 1, v0, t0, s0, mi);
596 else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
597 else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
598 else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
604 /*---------------------------------------------------------------------------*/
606 static float plane_d[MAXS];
607 static float plane_n[MAXS][3];
608 static float plane_p[MAXS][3];
609 static float plane_u[MAXS][3];
610 static float plane_v[MAXS][3];
611 static int plane_f[MAXS];
612 static int plane_m[MAXS];
614 static void make_plane(int pi, int x0, int y0, int z0,
615 int x1, int y1, int z1,
616 int x2, int y2, int z2,
617 int tu, int tv, int r,
618 float su, float sv, int fl, const char *s)
620 static const float base[6][3][3] = {
621 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
622 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
623 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
624 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
625 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
626 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
630 float p0[3], p1[3], p2[3];
631 float u[3], v[3], p[3];
636 size_image(s, &w, &h);
638 plane_f[pi] = fl ? L_DETAIL : 0;
640 p0[0] = +(float) x0 / SCALE;
641 p0[1] = +(float) z0 / SCALE;
642 p0[2] = -(float) y0 / SCALE;
644 p1[0] = +(float) x1 / SCALE;
645 p1[1] = +(float) z1 / SCALE;
646 p1[2] = -(float) y1 / SCALE;
648 p2[0] = +(float) x2 / SCALE;
649 p2[1] = +(float) z2 / SCALE;
650 p2[2] = -(float) y2 / SCALE;
655 v_crs(plane_n[pi], u, v);
656 v_nrm(plane_n[pi], plane_n[pi]);
658 plane_d[pi] = v_dot(plane_n[pi], p1);
660 for (i = 0; i < 6; i++)
661 if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
671 m_rot(R, base[n][0], V_RAD(r));
673 v_mad(p, p, base[n][1], su * tu / SCALE);
674 v_mad(p, p, base[n][2], sv * tv / SCALE);
676 m_vxfm(plane_u[pi], R, base[n][1]);
677 m_vxfm(plane_v[pi], R, base[n][2]);
678 m_vxfm(plane_p[pi], R, p);
680 v_scl(plane_u[pi], plane_u[pi], 64.f / w);
681 v_scl(plane_v[pi], plane_v[pi], 64.f / h);
683 v_scl(plane_u[pi], plane_u[pi], 1.f / su);
684 v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
687 /*---------------------------------------------------------------------------*/
696 static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
700 if (fgets(buf, MAXSTR, fin))
710 /* Scan the beginning or end of a block. */
712 if (buf[0] == '{') return T_BEG;
713 if (buf[0] == '}') return T_END;
715 /* Scan a key-value pair. */
719 strcpy(key, strtok(buf, "\""));
720 (void) strtok(NULL, "\"");
721 strcpy(val, strtok(NULL, "\""));
732 "%s %d %d %d %f %f %d",
733 &c, &x0, &y0, &z0, &c,
734 &c, &x1, &y1, &z1, &c,
735 &c, &x2, &y2, &z2, &c,
736 key, &tu, &tv, &r, &su, &sv, &fl) == 22)
738 make_plane(pi, x0, y0, z0,
741 tu, tv, r, su, sv, fl, key);
745 /* If it's not recognized, it must be uninteresting. */
752 /*---------------------------------------------------------------------------*/
754 /* Parse a lump from the given file and add it to the solid. */
756 static void read_lump(struct s_file *fp, FILE *fin)
762 struct s_lump *lp = fp->lv + incl(fp);
766 while ((t = map_token(fin, fp->sc, k, v)))
770 fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
771 fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
772 fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
773 fp->sv[fp->sc].d = plane_d[fp->sc];
775 plane_m[fp->sc] = read_mtrl(fp, k);
777 fp->iv[fp->ic] = fp->sc;
787 /*---------------------------------------------------------------------------*/
789 static void make_path(struct s_file *fp,
791 char v[][MAXSTR], int c)
793 int i, pi = incp(fp);
795 struct s_path *pp = fp->pv + pi;
805 for (i = 0; i < c; i++)
807 if (strcmp(k[i], "targetname") == 0)
810 if (strcmp(k[i], "target") == 0)
811 make_ref(v[i], &pp->pi);
813 if (strcmp(k[i], "state") == 0)
816 if (strcmp(k[i], "speed") == 0)
817 sscanf(v[i], "%f", &pp->t);
819 if (strcmp(k[i], "smooth") == 0)
822 if (strcmp(k[i], "origin") == 0)
824 int x = 0, y = 0, z = 0;
826 sscanf(v[i], "%d %d %d", &x, &y, &z);
828 pp->p[0] = +(float) x / SCALE;
829 pp->p[1] = +(float) z / SCALE;
830 pp->p[2] = -(float) y / SCALE;
835 static void make_dict(struct s_file *fp,
839 int space_left, space_needed, di = incd(fp);
841 struct s_dict *dp = fp->dv + di;
843 space_left = MAXA - fp->ac;
844 space_needed = strlen(k) + 1 + strlen(v) + 1;
846 if (space_needed > space_left)
853 dp->aj = dp->ai + strlen(k) + 1;
854 fp->ac = dp->aj + strlen(v) + 1;
856 strncpy(fp->av + dp->ai, k, space_left);
857 strncpy(fp->av + dp->aj, v, space_left - strlen(k) - 1);
860 static int read_dict_entries = 0;
862 static void make_body(struct s_file *fp,
864 char v[][MAXSTR], int c, int l0)
866 int i, bi = incb(fp);
877 struct s_body *bp = fp->bv + bi;
883 for (i = 0; i < c; i++)
885 if (strcmp(k[i], "targetname") == 0)
888 else if (strcmp(k[i], "target") == 0)
889 make_ref(v[i], &bp->pi);
891 else if (strcmp(k[i], "model") == 0)
894 else if (strcmp(k[i], "origin") == 0)
895 sscanf(v[i], "%d %d %d", &x, &y, &z);
897 else if (read_dict_entries && strcmp(k[i], "classname") != 0)
898 make_dict(fp, k[i], v[i]);
902 bp->lc = fp->lc - l0;
904 bp->gc = fp->gc - g0;
906 for (i = 0; i < bp->gc; i++)
907 fp->iv[inci(fp)] = g0++;
909 p[0] = +(float) x / SCALE;
910 p[1] = +(float) z / SCALE;
911 p[2] = -(float) y / SCALE;
913 for (i = v0; i < fp->vc; i++)
914 v_add(fp->vv[i].p, fp->vv[i].p, p);
916 read_dict_entries = 0;
919 static void make_item(struct s_file *fp,
921 char v[][MAXSTR], int c)
923 int i, hi = inch(fp);
925 struct s_item *hp = fp->hv + hi;
934 for (i = 0; i < c; i++)
936 if (strcmp(k[i], "classname") == 0)
938 if (strcmp(v[i], "light") == 0)
940 else if (strcmp(v[i], "item_health_large") == 0)
942 else if (strcmp(v[i], "item_health_small") == 0)
946 if (strcmp(k[i], "light") == 0)
947 sscanf(v[i], "%d", &hp->n);
949 if (strcmp(k[i], "origin") == 0)
951 int x = 0, y = 0, z = 0;
953 sscanf(v[i], "%d %d %d", &x, &y, &z);
955 hp->p[0] = +(float) x / SCALE;
956 hp->p[1] = +(float) z / SCALE;
957 hp->p[2] = -(float) y / SCALE;
962 static void make_bill(struct s_file *fp,
964 char v[][MAXSTR], int c)
966 int i, ri = incr(fp);
968 struct s_bill *rp = fp->rv + ri;
970 memset(rp, 0, sizeof (struct s_bill));
973 for (i = 0; i < c; i++)
975 if (strcmp(k[i], "width") == 0)
976 sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
977 if (strcmp(k[i], "height") == 0)
978 sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
980 if (strcmp(k[i], "xrot") == 0)
981 sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
982 if (strcmp(k[i], "yrot") == 0)
983 sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
984 if (strcmp(k[i], "zrot") == 0)
985 sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
987 if (strcmp(k[i], "time") == 0)
988 sscanf(v[i], "%f", &rp->t);
989 if (strcmp(k[i], "dist") == 0)
990 sscanf(v[i], "%f", &rp->d);
991 if (strcmp(k[i], "flag") == 0)
992 sscanf(v[i], "%d", &rp->fl);
994 if (strcmp(k[i], "image") == 0)
996 rp->mi = read_mtrl(fp, v[i]);
997 fp->mv[rp->mi].fl |= M_CLAMPED;
1000 if (strcmp(k[i], "origin") == 0)
1002 int x = 0, y = 0, z = 0;
1005 sscanf(v[i], "%d %d %d", &x, &y, &z);
1007 p[0] = +(float) x / SCALE;
1008 p[1] = +(float) z / SCALE;
1009 p[2] = -(float) y / SCALE;
1012 rp->rx[0] = V_DEG(fatan2f(+p[1], rp->d));
1013 rp->ry[0] = V_DEG(fatan2f(+p[0], -p[2]));
1017 if (rp->fl & B_ADDITIVE)
1018 fp->mv[rp->mi].fl |= M_ADDITIVE;
1021 static void make_goal(struct s_file *fp,
1023 char v[][MAXSTR], int c)
1025 int i, zi = incz(fp);
1027 struct s_goal *zp = fp->zv + zi;
1034 for (i = 0; i < c; i++)
1036 if (strcmp(k[i], "radius") == 0)
1037 sscanf(v[i], "%f", &zp->r);
1039 if (strcmp(k[i], "origin") == 0)
1041 int x = 0, y = 0, z = 0;
1043 sscanf(v[i], "%d %d %d", &x, &y, &z);
1045 zp->p[0] = +(float) (x) / SCALE;
1046 zp->p[1] = +(float) (z - 24) / SCALE;
1047 zp->p[2] = -(float) (y) / SCALE;
1052 static void make_view(struct s_file *fp,
1054 char v[][MAXSTR], int c)
1056 int i, wi = incw(fp);
1058 struct s_view *wp = fp->wv + wi;
1067 for (i = 0; i < c; i++)
1069 if (strcmp(k[i], "target") == 0)
1070 make_ref(v[i], targ_wi + wi);
1072 if (strcmp(k[i], "origin") == 0)
1074 int x = 0, y = 0, z = 0;
1076 sscanf(v[i], "%d %d %d", &x, &y, &z);
1078 wp->p[0] = +(float) x / SCALE;
1079 wp->p[1] = +(float) z / SCALE;
1080 wp->p[2] = -(float) y / SCALE;
1085 static void make_jump(struct s_file *fp,
1087 char v[][MAXSTR], int c)
1089 int i, ji = incj(fp);
1091 struct s_jump *jp = fp->jv + ji;
1101 for (i = 0; i < c; i++)
1103 if (strcmp(k[i], "radius") == 0)
1104 sscanf(v[i], "%f", &jp->r);
1106 if (strcmp(k[i], "target") == 0)
1107 make_ref(v[i], targ_ji + ji);
1109 if (strcmp(k[i], "origin") == 0)
1111 int x = 0, y = 0, z = 0;
1113 sscanf(v[i], "%d %d %d", &x, &y, &z);
1115 jp->p[0] = +(float) x / SCALE;
1116 jp->p[1] = +(float) z / SCALE;
1117 jp->p[2] = -(float) y / SCALE;
1122 static void make_swch(struct s_file *fp,
1124 char v[][MAXSTR], int c)
1126 int i, xi = incx(fp);
1128 struct s_swch *xp = fp->xv + xi;
1141 for (i = 0; i < c; i++)
1143 if (strcmp(k[i], "radius") == 0)
1144 sscanf(v[i], "%f", &xp->r);
1146 if (strcmp(k[i], "target") == 0)
1147 make_ref(v[i], &xp->pi);
1149 if (strcmp(k[i], "timer") == 0)
1150 sscanf(v[i], "%f", &xp->t0);
1152 if (strcmp(k[i], "state") == 0)
1155 xp->f0 = atoi(v[i]);
1158 if (strcmp(k[i], "invisible") == 0)
1161 if (strcmp(k[i], "origin") == 0)
1163 int x = 0, y = 0, z = 0;
1165 sscanf(v[i], "%d %d %d", &x, &y, &z);
1167 xp->p[0] = +(float) x / SCALE;
1168 xp->p[1] = +(float) z / SCALE;
1169 xp->p[2] = -(float) y / SCALE;
1174 static void make_targ(struct s_file *fp,
1176 char v[][MAXSTR], int c)
1180 targ_p[targ_n][0] = 0.f;
1181 targ_p[targ_n][1] = 0.f;
1182 targ_p[targ_n][3] = 0.f;
1184 for (i = 0; i < c; i++)
1186 if (strcmp(k[i], "targetname") == 0)
1187 make_sym(v[i], targ_n);
1189 if (strcmp(k[i], "origin") == 0)
1191 int x = 0, y = 0, z = 0;
1193 sscanf(v[i], "%d %d %d", &x, &y, &z);
1195 targ_p[targ_n][0] = +(float) x / SCALE;
1196 targ_p[targ_n][1] = +(float) z / SCALE;
1197 targ_p[targ_n][2] = -(float) y / SCALE;
1204 static void make_ball(struct s_file *fp,
1206 char v[][MAXSTR], int c)
1208 int i, ui = incu(fp);
1210 struct s_ball *up = fp->uv + ui;
1234 for (i = 0; i < c; i++)
1236 if (strcmp(k[i], "radius") == 0)
1237 sscanf(v[i], "%f", &up->r);
1239 if (strcmp(k[i], "origin") == 0)
1241 int x = 0, y = 0, z = 0;
1243 sscanf(v[i], "%d %d %d", &x, &y, &z);
1245 up->p[0] = +(float) (x) / SCALE;
1246 up->p[1] = +(float) (z - 24) / SCALE;
1247 up->p[2] = -(float) (y) / SCALE;
1251 up->p[1] += up->r + SMALL;
1254 /*---------------------------------------------------------------------------*/
1256 static void read_ent(struct s_file *fp, FILE *fin)
1258 char k[MAXKEY][MAXSTR];
1259 char v[MAXKEY][MAXSTR];
1260 int t, i = 0, c = 0;
1264 while ((t = map_token(fin, -1, k[c], v[c])))
1268 if (strcmp(k[c], "classname") == 0)
1272 if (t == T_BEG) read_lump(fp, fin);
1273 if (t == T_END) break;
1276 if (!strcmp(v[i], "light")) make_item(fp, k, v, c);
1277 if (!strcmp(v[i], "item_health_large")) make_item(fp, k, v, c);
1278 if (!strcmp(v[i], "item_health_small")) make_item(fp, k, v, c);
1279 if (!strcmp(v[i], "info_camp")) make_swch(fp, k, v, c);
1280 if (!strcmp(v[i], "info_null")) make_bill(fp, k, v, c);
1281 if (!strcmp(v[i], "path_corner")) make_path(fp, k, v, c);
1282 if (!strcmp(v[i], "info_player_start")) make_ball(fp, k, v, c);
1283 if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1284 if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
1285 if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
1286 if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
1287 if (!strcmp(v[i], "worldspawn"))
1289 read_dict_entries = 1;
1290 make_body(fp, k, v, c, l0);
1292 if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
1293 if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
1296 static void read_map(struct s_file *fp, FILE *fin)
1302 while ((t = map_token(fin, -1, k, v)))
1307 /*---------------------------------------------------------------------------*/
1309 /* Test the location of a point with respect to a side plane. */
1311 static int fore_side(const float p[3], const struct s_side *sp)
1313 return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1316 static int on_side(const float p[3], const struct s_side *sp)
1318 float d = v_dot(p, sp->n) - sp->d;
1320 return (-SMALL < d && d < +SMALL) ? 1 : 0;
1323 /*---------------------------------------------------------------------------*/
1325 * Confirm that the addition of a vert would not result in degenerate
1329 static int ok_vert(const struct s_file *fp,
1330 const struct s_lump *lp, const float p[3])
1335 for (i = 0; i < lp->vc; i++)
1337 float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1341 if (v_len(r) < SMALL)
1347 /*---------------------------------------------------------------------------*/
1350 * The following functions take the set of planes defining a lump and
1351 * find the verts, edges, and geoms that describe its boundaries. To
1352 * do this, they first find the verts, and then search these verts for
1353 * valid edges and geoms. It may be more efficient to compute edges
1354 * and geoms directly by clipping down infinite line segments and
1355 * planes, but this would be more complex and prone to numerical
1360 * Given 3 side planes, compute the point of intersection, if any.
1361 * Confirm that this point falls within the current lump, and that it
1362 * is unique. Add it as a vert of the solid.
1364 static void clip_vert(struct s_file *fp,
1365 struct s_lump *lp, int si, int sj, int sk)
1367 float M[16], X[16], I[16];
1371 d[0] = fp->sv[si].d;
1372 d[1] = fp->sv[sj].d;
1373 d[2] = fp->sv[sk].d;
1375 m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1382 for (i = 0; i < lp->sc; i++)
1384 int si = fp->iv[lp->s0 + i];
1386 if (fore_side(p, fp->sv + si))
1390 if (ok_vert(fp, lp, p))
1392 v_cpy(fp->vv[fp->vc].p, p);
1394 fp->iv[fp->ic] = fp->vc;
1403 * Given two side planes, find an edge along their intersection by
1404 * finding a pair of vertices that fall on both planes. Add it to the
1407 static void clip_edge(struct s_file *fp,
1408 struct s_lump *lp, int si, int sj)
1412 for (i = 1; i < lp->vc; i++)
1413 for (j = 0; j < i; j++)
1415 int vi = fp->iv[lp->v0 + i];
1416 int vj = fp->iv[lp->v0 + j];
1418 if (on_side(fp->vv[vi].p, fp->sv + si) &&
1419 on_side(fp->vv[vj].p, fp->sv + si) &&
1420 on_side(fp->vv[vi].p, fp->sv + sj) &&
1421 on_side(fp->vv[vj].p, fp->sv + sj))
1423 fp->ev[fp->ec].vi = vi;
1424 fp->ev[fp->ec].vj = vj;
1426 fp->iv[fp->ic] = fp->ec;
1436 * Find all verts that lie on the given side of the lump. Sort these
1437 * verts to have a counter-clockwise winding about the plane normal.
1438 * Create geoms to tessellate the resulting convex polygon.
1440 static void clip_geom(struct s_file *fp,
1441 struct s_lump *lp, int si)
1443 int m[256], t[256], d, i, j, n = 0;
1448 struct s_side *sp = fp->sv + si;
1452 for (i = 0; i < lp->vc; i++)
1454 int vi = fp->iv[lp->v0 + i];
1456 if (on_side(fp->vv[vi].p, sp))
1461 v_add(v, fp->vv[vi].p, plane_p[si]);
1463 fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1464 fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1472 for (i = 1; i < n; i++)
1473 for (j = i + 1; j < n; j++)
1475 v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1476 v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1479 if (v_dot(w, sp->n) < 0.f)
1493 for (i = 0; i < n - 2; i++)
1495 fp->gv[fp->gc].mi = plane_m[si];
1497 fp->gv[fp->gc].ti = t[0];
1498 fp->gv[fp->gc].tj = t[i + 1];
1499 fp->gv[fp->gc].tk = t[i + 2];
1501 fp->gv[fp->gc].si = si;
1502 fp->gv[fp->gc].sj = si;
1503 fp->gv[fp->gc].sk = si;
1505 fp->gv[fp->gc].vi = m[0];
1506 fp->gv[fp->gc].vj = m[i + 1];
1507 fp->gv[fp->gc].vk = m[i + 2];
1509 fp->iv[fp->ic] = fp->gc;
1517 * Iterate the sides of the lump, attempting to generate a new vert for
1518 * each trio of planes, a new edge for each pair of planes, and a new
1519 * set of geom for each visible plane.
1521 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1528 for (i = 2; i < lp->sc; i++)
1529 for (j = 1; j < i; j++)
1530 for (k = 0; k < j; k++)
1534 fp->iv[lp->s0 + k]);
1539 for (i = 1; i < lp->sc; i++)
1540 for (j = 0; j < i; j++)
1543 fp->iv[lp->s0 + j]);
1548 for (i = 0; i < lp->sc; i++)
1549 if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0)
1551 fp->iv[lp->s0 + i]);
1553 for (i = 0; i < lp->sc; i++)
1554 if (plane_f[fp->iv[lp->s0 + i]])
1558 static void clip_file(struct s_file *fp)
1562 for (i = 0; i < fp->lc; i++)
1563 clip_lump(fp, fp->lv + i);
1566 /*---------------------------------------------------------------------------*/
1569 * For each body element type, determine if element 'p' is equivalent
1570 * to element 'q'. This is more than a simple memory compare. It
1571 * effectively snaps mtrls and verts together, and may reverse the
1572 * winding of an edge or a geom. This is done in order to maximize
1573 * the number of elements that can be eliminated.
1576 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1578 if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1579 if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1580 if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1581 if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1583 if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1584 if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1585 if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1586 if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1588 if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1589 if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1590 if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1591 if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1593 if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1594 if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1595 if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1596 if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1598 if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1600 if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1605 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1607 if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1608 if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1609 if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1614 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1616 if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1617 if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1622 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1624 if (fabs(sp->d - sq->d) > SMALL) return 0;
1625 if (v_dot(sp->n, sq->n) < 0.9999) return 0;
1630 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1632 if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1633 if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1638 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1640 if (gp->mi != gq->mi) return 0;
1642 if (gp->ti != gq->ti) return 0;
1643 if (gp->si != gq->si) return 0;
1644 if (gp->vi != gq->vi) return 0;
1646 if (gp->tj != gq->tj) return 0;
1647 if (gp->sj != gq->sj) return 0;
1648 if (gp->vj != gq->vj) return 0;
1650 if (gp->tk != gq->tk) return 0;
1651 if (gp->sk != gq->sk) return 0;
1652 if (gp->vk != gq->vk) return 0;
1657 /*---------------------------------------------------------------------------*/
1660 * For each file element type, replace all references to element 'i'
1661 * with a reference to element 'j'. These are used when optimizing
1662 * and sorting the file.
1665 static void swap_mtrl(struct s_file *fp, int mi, int mj)
1669 for (i = 0; i < fp->gc; i++)
1670 if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1671 for (i = 0; i < fp->rc; i++)
1672 if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1675 static void swap_vert(struct s_file *fp, int vi, int vj)
1679 for (i = 0; i < fp->ec; i++)
1681 if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1682 if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1685 for (i = 0; i < fp->gc; i++)
1687 if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1688 if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1689 if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1692 for (i = 0; i < fp->lc; i++)
1693 for (j = 0; j < fp->lv[i].vc; j++)
1694 if (fp->iv[fp->lv[i].v0 + j] == vi)
1695 fp->iv[fp->lv[i].v0 + j] = vj;
1698 static void swap_edge(struct s_file *fp, int ei, int ej)
1702 for (i = 0; i < fp->lc; i++)
1703 for (j = 0; j < fp->lv[i].ec; j++)
1704 if (fp->iv[fp->lv[i].e0 + j] == ei)
1705 fp->iv[fp->lv[i].e0 + j] = ej;
1708 static void swap_side(struct s_file *fp, int si, int sj)
1712 for (i = 0; i < fp->gc; i++)
1714 if (fp->gv[i].si == si) fp->gv[i].si = sj;
1715 if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1716 if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1718 for (i = 0; i < fp->nc; i++)
1719 if (fp->nv[i].si == si) fp->nv[i].si = sj;
1721 for (i = 0; i < fp->lc; i++)
1722 for (j = 0; j < fp->lv[i].sc; j++)
1723 if (fp->iv[fp->lv[i].s0 + j] == si)
1724 fp->iv[fp->lv[i].s0 + j] = sj;
1727 static void swap_texc(struct s_file *fp, int ti, int tj)
1731 for (i = 0; i < fp->gc; i++)
1733 if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1734 if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1735 if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1740 static void swap_geom(struct s_file *fp, int gi, int gj)
1744 for (i = 0; i < fp->lc; i++)
1745 for (j = 0; j < fp->lv[i].gc; j++)
1746 if (fp->iv[fp->lv[i].g0 + j] == gi)
1747 fp->iv[fp->lv[i].g0 + j] = gj;
1749 for (i = 0; i < fp->bc; i++)
1750 for (j = 0; j < fp->bv[i].gc; j++)
1751 if (fp->iv[fp->bv[i].g0 + j] == gi)
1752 fp->iv[fp->bv[i].g0 + j] = gj;
1755 /*---------------------------------------------------------------------------*/
1757 static void uniq_mtrl(struct s_file *fp)
1761 for (i = 0; i < fp->mc; i++)
1763 for (j = 0; j < k; j++)
1764 if (comp_mtrl(fp->mv + i, fp->mv + j))
1766 swap_mtrl(fp, i, j);
1774 fp->mv[k] = fp->mv[i];
1775 swap_mtrl(fp, i, k);
1784 static void uniq_vert(struct s_file *fp)
1788 for (i = 0; i < fp->vc; i++)
1790 for (j = 0; j < k; j++)
1791 if (comp_vert(fp->vv + i, fp->vv + j))
1793 swap_vert(fp, i, j);
1801 fp->vv[k] = fp->vv[i];
1802 swap_vert(fp, i, k);
1811 static void uniq_edge(struct s_file *fp)
1815 for (i = 0; i < fp->ec; i++)
1817 for (j = 0; j < k; j++)
1818 if (comp_edge(fp->ev + i, fp->ev + j))
1820 swap_edge(fp, i, j);
1828 fp->ev[k] = fp->ev[i];
1829 swap_edge(fp, i, k);
1838 static void uniq_geom(struct s_file *fp)
1842 for (i = 0; i < fp->gc; i++)
1844 for (j = 0; j < k; j++)
1845 if (comp_geom(fp->gv + i, fp->gv + j))
1847 swap_geom(fp, i, j);
1855 fp->gv[k] = fp->gv[i];
1856 swap_geom(fp, i, k);
1865 static void uniq_texc(struct s_file *fp)
1869 for (i = 0; i < fp->tc; i++)
1871 for (j = 0; j < k; j++)
1872 if (comp_texc(fp->tv + i, fp->tv + j))
1874 swap_texc(fp, i, j);
1882 fp->tv[k] = fp->tv[i];
1883 swap_texc(fp, i, k);
1892 static void uniq_side(struct s_file *fp)
1896 for (i = 0; i < fp->sc; i++)
1898 for (j = 0; j < k; j++)
1899 if (comp_side(fp->sv + i, fp->sv + j))
1901 swap_side(fp, i, j);
1909 fp->sv[k] = fp->sv[i];
1910 swap_side(fp, i, k);
1919 static void uniq_file(struct s_file *fp)
1932 /*---------------------------------------------------------------------------*/
1934 static void sort_file(struct s_file *fp)
1938 /* Sort billboards farthest to nearest. */
1940 for (i = 0; i < fp->rc; i++)
1941 for (j = i + 1; j < fp->rc; j++)
1942 if (fp->rv[j].d > fp->rv[i].d)
1947 fp->rv[i] = fp->rv[j];
1951 /* Ensure the first vertex is the lowest. */
1953 for (i = 0; i < fp->vc; i++)
1954 if (fp->vv[0].p[1] > fp->vv[i].p[1])
1959 fp->vv[0] = fp->vv[i];
1962 swap_vert(fp, 0, -1);
1963 swap_vert(fp, i, 0);
1964 swap_vert(fp, -1, i);
1968 /*---------------------------------------------------------------------------*/
1970 static int test_lump_side(const struct s_file *fp,
1971 const struct s_lump *lp,
1972 const struct s_side *sp)
1980 /* If the given side is part of the given lump, then the lump is behind. */
1982 for (si = 0; si < lp->sc; si++)
1983 if (fp->sv + fp->iv[lp->s0 + si] == sp)
1986 /* Check if each lump vertex is in front of, behind, on the side. */
1988 for (vi = 0; vi < lp->vc; vi++)
1990 float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
1996 /* If no verts are behind, the lump is in front, and vice versa. */
1998 if (f > 0 && b == 0) return +1;
1999 if (b > 0 && f == 0) return -1;
2001 /* Else, the lump crosses the side. */
2006 static int node_node(struct s_file *fp, int l0, int lc)
2010 /* Base case. Dump all given lumps into a leaf node. */
2012 fp->nv[fp->nc].si = -1;
2013 fp->nv[fp->nc].ni = -1;
2014 fp->nv[fp->nc].nj = -1;
2015 fp->nv[fp->nc].l0 = l0;
2016 fp->nv[fp->nc].lc = lc;
2026 int li = 0, lic = 0;
2027 int lj = 0, ljc = 0;
2028 int lk = 0, lkc = 0;
2031 /* Find the side that most evenly splits the given lumps. */
2033 for (si = 0; si < fp->sc; si++)
2039 for (li = 0; li < lc; li++)
2040 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
2047 if ((d < sjd) || (d == sjd && o < sjo))
2055 /* Flag each lump with its position WRT the side. */
2057 for (li = 0; li < lc; li++)
2060 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2064 switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
2067 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10;
2071 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2075 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40;
2080 /* Sort all lumps in the range by their flag values. */
2082 for (li = 1; li < lc; li++)
2083 for (lj = 0; lj < li; lj++)
2084 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
2088 l = fp->lv[l0 + li];
2089 fp->lv[l0 + li] = fp->lv[l0 + lj];
2090 fp->lv[l0 + lj] = l;
2093 /* Establish the in-front, on, and behind lump ranges. */
2099 for (i = lc - 1; i >= 0; i--)
2100 switch (fp->lv[l0 + i].fl & 0xf0)
2102 case 0x10: li = l0 + i; lic++; break;
2103 case 0x20: lj = l0 + i; ljc++; break;
2104 case 0x40: lk = l0 + i; lkc++; break;
2107 /* Add the lumps on the side to the node. */
2112 fp->nv[i].ni = node_node(fp, li, lic);
2114 fp->nv[i].nj = node_node(fp, lk, lkc);
2122 static void node_file(struct s_file *fp)
2126 /* Sort the lumps of each body into BSP nodes. */
2128 for (bi = 0; bi < fp->bc; bi++)
2129 fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
2132 /*---------------------------------------------------------------------------*/
2134 static void dump_file(struct s_file *p, const char *name)
2136 /* FIXME: Count visible geoms.
2138 * I'm afraid items break this (not sure though) so leaving it out.
2148 int m = p->rc + p->cc * 128 + (p->zc * p->jc + p->xc) * 32;
2151 /* Count the number of solid lumps. */
2153 for (i = 0; i < p->lc; i++)
2154 if ((p->lv[i].fl & 1) == 0)
2158 /* Count the number of visible geoms. */
2160 for (i = 0; i < p->bc; i++)
2162 for (j = 0; j < p->bv[i].lc; j++)
2163 m += p->lv[p->bv[i].l0 + j].gc;
2168 /* Count the total value of all coins. */
2170 for (i = 0; i < p->hc; i++)
2171 if (p->hv[i].t == ITEM_COIN)
2175 printf("%s (%d/%d/$%d)\n"
2177 printf("%s (%d/$%d)\n"
2178 " mtrl vert edge side texc"
2179 " geom lump path node body\n"
2180 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
2181 " item goal view jump swch"
2182 " bill ball char dict indx\n"
2183 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
2188 p->mc, p->vc, p->ec, p->sc, p->tc,
2189 p->gc, p->lc, p->pc, p->nc, p->bc,
2190 p->hc, p->zc, p->wc, p->jc, p->xc,
2191 p->rc, p->uc, p->ac, p->dc, p->ic);
2194 /* Skip the ugly SDL main substitution since we only need sdl_image. */
2199 int main(int argc, char *argv[])
2208 if (argc > 3 && strcmp(argv[3], "--debug") == 0)
2211 if (config_data_path(argv[2], NULL))
2213 strncpy(src, argv[1], MAXSTR);
2214 strncpy(dst, argv[1], MAXSTR);
2216 if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
2217 strcpy(dst + strlen(dst) - 4, ".sol");
2219 strcat(dst, ".sol");
2221 if ((fin = fopen(src, "r")))
2243 else fprintf(stderr, "Failure to establish data directory\n");
2245 else fprintf(stderr, "Usage: %s <map> <data> [--debug]\n", argv[0]);