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 #pragma comment(lib, "SDL_ttf.lib")
19 #pragma comment(lib, "SDL_image.lib")
20 #pragma comment(lib, "SDL_mixer.lib")
21 #pragma comment(lib, "SDL.lib")
22 #pragma comment(lib, "SDLmain.lib")
23 #pragma comment(lib, "opengl32.lib")
26 /*---------------------------------------------------------------------------*/
29 #include <SDL_image.h>
37 #include "base_config.h"
45 * The overall design of this map converter is very stupid, but very
46 * simple. It begins by assuming that every mtrl, vert, edge, side,
47 * and texc in the map is unique. It then makes an optimizing pass
48 * that discards redundant information. The result is optimal, though
49 * the process is terribly inefficient.
52 /*---------------------------------------------------------------------------*/
54 static int debug_output = 0;
56 /*---------------------------------------------------------------------------*/
58 /* Ohhhh... arbitrary! */
104 static int overflow(const char *s)
106 printf("%s overflow\n", s);
111 static int incm(struct s_file *fp)
113 return (fp->mc < MAXM) ? fp->mc++ : overflow("mtrl");
116 static int incv(struct s_file *fp)
118 return (fp->vc < MAXV) ? fp->vc++ : overflow("vert");
121 static int ince(struct s_file *fp)
123 return (fp->ec < MAXE) ? fp->ec++ : overflow("edge");
126 static int incs(struct s_file *fp)
128 return (fp->sc < MAXS) ? fp->sc++ : overflow("side");
131 static int inct(struct s_file *fp)
133 return (fp->tc < MAXT) ? fp->tc++ : overflow("texc");
136 static int incg(struct s_file *fp)
138 return (fp->gc < MAXG) ? fp->gc++ : overflow("geom");
141 static int incl(struct s_file *fp)
143 return (fp->lc < MAXL) ? fp->lc++ : overflow("lump");
146 static int incn(struct s_file *fp)
148 return (fp->nc < MAXN) ? fp->nc++ : overflow("node");
151 static int incp(struct s_file *fp)
153 return (fp->pc < MAXP) ? fp->pc++ : overflow("path");
156 static int incb(struct s_file *fp)
158 return (fp->bc < MAXB) ? fp->bc++ : overflow("body");
161 static int inch(struct s_file *fp)
163 return (fp->hc < MAXH) ? fp->hc++ : overflow("item");
166 static int incz(struct s_file *fp)
168 return (fp->zc < MAXZ) ? fp->zc++ : overflow("goal");
171 static int incj(struct s_file *fp)
173 return (fp->jc < MAXJ) ? fp->jc++ : overflow("jump");
176 static int incx(struct s_file *fp)
178 return (fp->xc < MAXX) ? fp->xc++ : overflow("swch");
181 static int incr(struct s_file *fp)
183 return (fp->rc < MAXR) ? fp->rc++ : overflow("bill");
186 static int incu(struct s_file *fp)
188 return (fp->uc < MAXU) ? fp->uc++ : overflow("ball");
191 static int incw(struct s_file *fp)
193 return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
196 static int incd(struct s_file *fp)
198 return (fp->dc < MAXD) ? fp->dc++ : overflow("dict");
201 static int inci(struct s_file *fp)
203 return (fp->ic < MAXI) ? fp->ic++ : overflow("indx");
206 static void init_file(struct s_file *fp)
229 fp->mv = (struct s_mtrl *) calloc(MAXM, sizeof (struct s_mtrl));
230 fp->vv = (struct s_vert *) calloc(MAXV, sizeof (struct s_vert));
231 fp->ev = (struct s_edge *) calloc(MAXE, sizeof (struct s_edge));
232 fp->sv = (struct s_side *) calloc(MAXS, sizeof (struct s_side));
233 fp->tv = (struct s_texc *) calloc(MAXT, sizeof (struct s_texc));
234 fp->gv = (struct s_geom *) calloc(MAXG, sizeof (struct s_geom));
235 fp->lv = (struct s_lump *) calloc(MAXL, sizeof (struct s_lump));
236 fp->nv = (struct s_node *) calloc(MAXN, sizeof (struct s_node));
237 fp->pv = (struct s_path *) calloc(MAXP, sizeof (struct s_path));
238 fp->bv = (struct s_body *) calloc(MAXB, sizeof (struct s_body));
239 fp->hv = (struct s_item *) calloc(MAXH, sizeof (struct s_item));
240 fp->zv = (struct s_goal *) calloc(MAXZ, sizeof (struct s_goal));
241 fp->jv = (struct s_jump *) calloc(MAXJ, sizeof (struct s_jump));
242 fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
243 fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
244 fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
245 fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
246 fp->dv = (struct s_dict *) calloc(MAXD, sizeof (struct s_dict));
247 fp->av = (char *) calloc(MAXA, sizeof (char));
248 fp->iv = (int *) calloc(MAXI, sizeof (int));
251 /*---------------------------------------------------------------------------*/
254 * The following is a small symbol table data structure. Symbols and
255 * their integer values are collected in symv and valv. References
256 * and pointers to their unsatisfied integer values are collected in
257 * refv and pntv. The resolve procedure matches references to symbols
258 * and fills waiting ints with the proper values.
263 static char symv[MAXSYM][MAXSTR];
264 static int valv[MAXSYM];
266 static char refv[MAXSYM][MAXSTR];
267 static int *pntv[MAXSYM];
272 static void make_sym(const char *s, int v)
274 strncpy(symv[strc], s, MAXSTR - 1);
279 static void make_ref(const char *r, int *p)
281 strncpy(refv[refc], r, MAXSTR - 1);
286 static void resolve(void)
290 for (i = 0; i < refc; i++)
291 for (j = 0; j < strc; j++)
292 if (strncmp(refv[i], symv[j], MAXSTR) == 0)
294 *(pntv[i]) = valv[j];
299 /*---------------------------------------------------------------------------*/
302 * The following globals are used to cache target_positions. They are
303 * targeted by various entities and must be resolved in a second pass.
306 static float targ_p [MAXW][3];
307 static int targ_wi[MAXW];
308 static int targ_ji[MAXW];
311 static void targets(struct s_file *fp)
315 for (i = 0; i < fp->wc; i++)
316 v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
318 for (i = 0; i < fp->jc; i++)
319 v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
322 /*---------------------------------------------------------------------------*/
325 * The following code caches image sizes. Textures are referenced by
326 * name, but their sizes are necessary when computing texture
327 * coordinates. This code allows each file to be accessed only once
328 * regardless of the number of surfaces referring to it.
337 static struct _imagedata *imagedata = NULL;
338 static int image_n = 0;
339 static int image_alloc = 0;
341 #define IMAGE_REALLOC 32
343 static void free_imagedata()
349 for (i = 0; i < image_n; i++)
350 free(imagedata[i].s);
354 image_n = image_alloc = 0;
357 static int size_load(const char *file, int *w, int *h)
361 if ((S = IMG_Load(file)))
373 static void size_image(const char *name, int *w, int *h)
381 for (i = 0; i < image_n; i++)
382 if (strncmp(imagedata[i].s, name, MAXSTR) == 0)
393 strcpy(jpg, name); strcat(jpg, ".jpg");
394 strcpy(tga, name); strcat(tga, ".tga");
395 strcpy(png, name); strcat(png, ".png");
397 if (size_load(config_data(png), w, h) ||
398 size_load(config_data(tga), w, h) ||
399 size_load(config_data(jpg), w, h))
402 if (image_n + 1 >= image_alloc)
404 struct _imagedata *tmp =
405 (struct _imagedata *) malloc(sizeof(struct _imagedata) * (image_alloc + IMAGE_REALLOC));
408 printf("malloc error\n");
413 (void) memcpy(tmp, imagedata, sizeof(struct _imagedata) * image_alloc);
417 image_alloc += IMAGE_REALLOC;
420 imagedata[image_n].s = (char *) calloc(strlen(name) + 1, 1);
421 imagedata[image_n].w = *w;
422 imagedata[image_n].h = *h;
423 strcpy(imagedata[image_n].s, name);
429 /*---------------------------------------------------------------------------*/
431 /* Read the given material file, adding a new material to the solid. */
433 static int read_mtrl(struct s_file *fp, const char *name)
439 for (mi = 0; mi < fp->mc; mi++)
440 if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
443 mp = fp->mv + incm(fp);
445 strncpy(mp->f, name, PATHMAX - 1);
447 mp->a[0] = mp->a[1] = mp->a[2] = mp->a[3] = 1.0f;
448 mp->d[0] = mp->d[1] = mp->d[2] = mp->d[3] = 1.0f;
449 mp->s[0] = mp->s[1] = mp->s[2] = mp->s[3] = 1.0f;
450 mp->e[0] = mp->e[1] = mp->e[2] = mp->e[3] = 1.0f;
454 if ((fin = fopen(config_data(name), "r")))
462 mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
463 mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
464 mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
465 mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
473 /*---------------------------------------------------------------------------*/
476 * All bodies with an associated path are assumed to be positioned at
477 * the beginning of that path. These bodies must be moved to the
478 * origin in order for their path transforms to behave correctly.
479 * This is how we get away with defining func_trains with no origin
483 static void move_side(struct s_side *sp, const float p[3])
485 sp->d -= v_dot(sp->n, p);
488 static void move_vert(struct s_vert *vp, const float p[3])
490 v_sub(vp->p, vp->p, p);
493 static void move_lump(struct s_file *fp,
494 struct s_lump *lp, const float p[3])
498 for (i = 0; i < lp->sc; i++)
499 move_side(fp->sv + fp->iv[lp->s0 + i], p);
500 for (i = 0; i < lp->vc; i++)
501 move_vert(fp->vv + fp->iv[lp->v0 + i], p);
504 static void move_body(struct s_file *fp,
509 for (i = 0; i < bp->lc; i++)
510 move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
513 static void move_file(struct s_file *fp)
517 for (i = 0; i < fp->bc; i++)
518 if (fp->bv[i].pi >= 0)
519 move_body(fp, fp->bv + i);
522 /*---------------------------------------------------------------------------*/
525 * This is a basic OBJ loader. It is by no means fully compliant with
526 * the OBJ specification, but it works well with the output of
527 * Wings3D. All faces must be triangles and all vertices must include
528 * normals and texture coordinates. Material names are taken to be
529 * references to Neverball materials, rather than MTL definitions.
532 static void read_vt(struct s_file *fp, const char *line)
534 struct s_texc *tp = fp->tv + inct(fp);
536 sscanf(line, "%f %f", tp->u, tp->u + 1);
539 static void read_vn(struct s_file *fp, const char *line)
541 struct s_side *sp = fp->sv + incs(fp);
543 sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
546 static void read_v(struct s_file *fp, const char *line)
548 struct s_vert *vp = fp->vv + incv(fp);
550 sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
553 static void read_f(struct s_file *fp, const char *line,
554 int v0, int t0, int s0, int mi)
556 struct s_geom *gp = fp->gv + incg(fp);
561 sscanf(line, "%d%c%d%c%d %d%c%d%c%d %d%c%d%c%d",
562 &gp->vi, &c1, &gp->ti, &c2, &gp->si,
563 &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
564 &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
579 static void read_obj(struct s_file *fp, const char *name)
590 if ((fin = fopen(config_data(name), "r")))
592 while (fgets(line, MAXSTR, fin))
594 if (strncmp(line, "usemtl", 6) == 0)
596 sscanf(line + 6, "%s", mtrl);
597 mi = read_mtrl(fp, mtrl);
600 else if (strncmp(line, "f", 1) == 0)
602 if (fp->mv[mi].d[3] > 0)
603 read_f(fp, line + 1, v0, t0, s0, mi);
606 else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
607 else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
608 else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
614 /*---------------------------------------------------------------------------*/
616 static float plane_d[MAXS];
617 static float plane_n[MAXS][3];
618 static float plane_p[MAXS][3];
619 static float plane_u[MAXS][3];
620 static float plane_v[MAXS][3];
621 static int plane_f[MAXS];
622 static int plane_m[MAXS];
624 static void make_plane(int pi, int x0, int y0, int z0,
625 int x1, int y1, int z1,
626 int x2, int y2, int z2,
627 int tu, int tv, int r,
628 float su, float sv, int fl, const char *s)
630 static const float base[6][3][3] = {
631 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
632 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
633 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
634 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
635 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
636 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
640 float p0[3], p1[3], p2[3];
641 float u[3], v[3], p[3];
646 size_image(s, &w, &h);
648 plane_f[pi] = fl ? L_DETAIL : 0;
650 p0[0] = +(float) x0 / SCALE;
651 p0[1] = +(float) z0 / SCALE;
652 p0[2] = -(float) y0 / SCALE;
654 p1[0] = +(float) x1 / SCALE;
655 p1[1] = +(float) z1 / SCALE;
656 p1[2] = -(float) y1 / SCALE;
658 p2[0] = +(float) x2 / SCALE;
659 p2[1] = +(float) z2 / SCALE;
660 p2[2] = -(float) y2 / SCALE;
665 v_crs(plane_n[pi], u, v);
666 v_nrm(plane_n[pi], plane_n[pi]);
668 plane_d[pi] = v_dot(plane_n[pi], p1);
670 for (i = 0; i < 6; i++)
671 if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
681 m_rot(R, base[n][0], V_RAD(r));
683 v_mad(p, p, base[n][1], su * tu / SCALE);
684 v_mad(p, p, base[n][2], sv * tv / SCALE);
686 m_vxfm(plane_u[pi], R, base[n][1]);
687 m_vxfm(plane_v[pi], R, base[n][2]);
688 m_vxfm(plane_p[pi], R, p);
690 v_scl(plane_u[pi], plane_u[pi], 64.f / w);
691 v_scl(plane_v[pi], plane_v[pi], 64.f / h);
693 v_scl(plane_u[pi], plane_u[pi], 1.f / su);
694 v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
697 /*---------------------------------------------------------------------------*/
706 static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
710 if (fgets(buf, MAXSTR, fin))
720 /* Scan the beginning or end of a block. */
722 if (buf[0] == '{') return T_BEG;
723 if (buf[0] == '}') return T_END;
725 /* Scan a key-value pair. */
729 strcpy(key, strtok(buf, "\""));
730 (void) strtok(NULL, "\"");
731 strcpy(val, strtok(NULL, "\""));
742 "%s %d %d %d %f %f %d",
743 &c, &x0, &y0, &z0, &c,
744 &c, &x1, &y1, &z1, &c,
745 &c, &x2, &y2, &z2, &c,
746 key, &tu, &tv, &r, &su, &sv, &fl) == 22)
748 make_plane(pi, x0, y0, z0,
751 tu, tv, r, su, sv, fl, key);
755 /* If it's not recognized, it must be uninteresting. */
762 /*---------------------------------------------------------------------------*/
764 /* Parse a lump from the given file and add it to the solid. */
766 static void read_lump(struct s_file *fp, FILE *fin)
772 struct s_lump *lp = fp->lv + incl(fp);
776 while ((t = map_token(fin, fp->sc, k, v)))
780 fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
781 fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
782 fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
783 fp->sv[fp->sc].d = plane_d[fp->sc];
785 plane_m[fp->sc] = read_mtrl(fp, k);
787 fp->iv[fp->ic] = fp->sc;
797 /*---------------------------------------------------------------------------*/
799 static void make_path(struct s_file *fp,
801 char v[][MAXSTR], int c)
803 int i, pi = incp(fp);
805 struct s_path *pp = fp->pv + pi;
814 for (i = 0; i < c; i++)
816 if (strcmp(k[i], "targetname") == 0)
819 if (strcmp(k[i], "target") == 0)
820 make_ref(v[i], &pp->pi);
822 if (strcmp(k[i], "state") == 0)
825 if (strcmp(k[i], "speed") == 0)
826 sscanf(v[i], "%f", &pp->t);
828 if (strcmp(k[i], "origin") == 0)
830 int x = 0, y = 0, z = 0;
832 sscanf(v[i], "%d %d %d", &x, &y, &z);
834 pp->p[0] = +(float) x / SCALE;
835 pp->p[1] = +(float) z / SCALE;
836 pp->p[2] = -(float) y / SCALE;
841 static void make_dict(struct s_file *fp,
845 int space_left, space_needed, di = incd(fp);
847 struct s_dict *dp = fp->dv + di;
849 space_left = MAXA - fp->ac;
850 space_needed = strlen(k) + 1 + strlen(v) + 1;
852 if (space_needed > space_left)
859 dp->aj = dp->ai + strlen(k) + 1;
860 fp->ac = dp->aj + strlen(v) + 1;
862 strncpy(fp->av + dp->ai, k, space_left);
863 strncpy(fp->av + dp->aj, v, space_left - strlen(k) - 1);
866 static void make_body(struct s_file *fp,
868 char v[][MAXSTR], int c, int l0)
870 int i, bi = incb(fp);
881 struct s_body *bp = fp->bv + bi;
887 for (i = 0; i < c; i++)
889 if (strcmp(k[i], "targetname") == 0)
892 else if (strcmp(k[i], "target") == 0)
893 make_ref(v[i], &bp->pi);
895 else if (strcmp(k[i], "model") == 0)
898 else if (strcmp(k[i], "origin") == 0)
899 sscanf(v[i], "%d %d %d", &x, &y, &z);
901 else if (strcmp(k[i], "classname") != 0)
902 make_dict(fp, k[i], v[i]);
906 bp->lc = fp->lc - l0;
908 bp->gc = fp->gc - g0;
910 for (i = 0; i < bp->gc; i++)
911 fp->iv[inci(fp)] = g0++;
913 p[0] = +(float) x / SCALE;
914 p[1] = +(float) z / SCALE;
915 p[2] = -(float) y / SCALE;
917 for (i = v0; i < fp->vc; i++)
918 v_add(fp->vv[i].p, fp->vv[i].p, p);
921 static void make_item(struct s_file *fp,
923 char v[][MAXSTR], int c)
925 int i, hi = inch(fp);
927 struct s_item *hp = fp->hv + hi;
936 for (i = 0; i < c; i++)
938 if (strcmp(k[i], "classname") == 0)
940 if (strcmp(v[i], "light") == 0)
942 else if (strcmp(v[i], "item_health_large") == 0)
944 else if (strcmp(v[i], "item_health_small") == 0)
948 if (strcmp(k[i], "light") == 0)
949 sscanf(v[i], "%d", &hp->n);
951 if (strcmp(k[i], "origin") == 0)
953 int x = 0, y = 0, z = 0;
955 sscanf(v[i], "%d %d %d", &x, &y, &z);
957 hp->p[0] = +(float) x / SCALE;
958 hp->p[1] = +(float) z / SCALE;
959 hp->p[2] = -(float) y / SCALE;
964 static void make_bill(struct s_file *fp,
966 char v[][MAXSTR], int c)
968 int i, ri = incr(fp);
970 struct s_bill *rp = fp->rv + ri;
972 memset(rp, 0, sizeof (struct s_bill));
975 for (i = 0; i < c; i++)
977 if (strcmp(k[i], "width") == 0)
978 sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
979 if (strcmp(k[i], "height") == 0)
980 sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
982 if (strcmp(k[i], "xrot") == 0)
983 sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
984 if (strcmp(k[i], "yrot") == 0)
985 sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
986 if (strcmp(k[i], "zrot") == 0)
987 sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
989 if (strcmp(k[i], "time") == 0)
990 sscanf(v[i], "%f", &rp->t);
991 if (strcmp(k[i], "dist") == 0)
992 sscanf(v[i], "%f", &rp->d);
993 if (strcmp(k[i], "flag") == 0)
994 sscanf(v[i], "%d", &rp->fl);
996 if (strcmp(k[i], "image") == 0)
998 rp->mi = read_mtrl(fp, v[i]);
999 fp->mv[rp->mi].fl |= M_CLAMPED;
1002 if (strcmp(k[i], "origin") == 0)
1004 int x = 0, y = 0, z = 0;
1007 sscanf(v[i], "%d %d %d", &x, &y, &z);
1009 p[0] = +(float) x / SCALE;
1010 p[1] = +(float) z / SCALE;
1011 p[2] = -(float) y / SCALE;
1014 rp->rx[0] = V_DEG(fatan2f(+p[1], rp->d));
1015 rp->ry[0] = V_DEG(fatan2f(+p[0], -p[2]));
1019 if (rp->fl & B_ADDITIVE)
1020 fp->mv[rp->mi].fl |= M_ADDITIVE;
1023 static void make_goal(struct s_file *fp,
1025 char v[][MAXSTR], int c)
1027 int i, zi = incz(fp);
1029 struct s_goal *zp = fp->zv + zi;
1038 for (i = 0; i < c; i++)
1040 if (strcmp(k[i], "radius") == 0)
1041 sscanf(v[i], "%f", &zp->r);
1042 if (strcmp(k[i], "skip") == 0)
1043 sscanf(v[i], "%d", &zp->s);
1044 if (strcmp(k[i], "special") == 0)
1045 sscanf(v[i], "%d", &zp->c);
1047 if (strcmp(k[i], "origin") == 0)
1049 int x = 0, y = 0, z = 0;
1051 sscanf(v[i], "%d %d %d", &x, &y, &z);
1053 zp->p[0] = +(float) (x) / SCALE;
1054 zp->p[1] = +(float) (z - 24) / SCALE;
1055 zp->p[2] = -(float) (y) / SCALE;
1060 static void make_view(struct s_file *fp,
1062 char v[][MAXSTR], int c)
1064 int i, wi = incw(fp);
1066 struct s_view *wp = fp->wv + wi;
1075 for (i = 0; i < c; i++)
1077 if (strcmp(k[i], "target") == 0)
1078 make_ref(v[i], targ_wi + wi);
1080 if (strcmp(k[i], "origin") == 0)
1082 int x = 0, y = 0, z = 0;
1084 sscanf(v[i], "%d %d %d", &x, &y, &z);
1086 wp->p[0] = +(float) x / SCALE;
1087 wp->p[1] = +(float) z / SCALE;
1088 wp->p[2] = -(float) y / SCALE;
1093 static void make_jump(struct s_file *fp,
1095 char v[][MAXSTR], int c)
1097 int i, ji = incj(fp);
1099 struct s_jump *jp = fp->jv + ji;
1109 for (i = 0; i < c; i++)
1111 if (strcmp(k[i], "radius") == 0)
1112 sscanf(v[i], "%f", &jp->r);
1114 if (strcmp(k[i], "target") == 0)
1115 make_ref(v[i], targ_ji + ji);
1117 if (strcmp(k[i], "origin") == 0)
1119 int x = 0, y = 0, z = 0;
1121 sscanf(v[i], "%d %d %d", &x, &y, &z);
1123 jp->p[0] = +(float) x / SCALE;
1124 jp->p[1] = +(float) z / SCALE;
1125 jp->p[2] = -(float) y / SCALE;
1130 static void make_swch(struct s_file *fp,
1132 char v[][MAXSTR], int c)
1134 int i, xi = incx(fp);
1136 struct s_swch *xp = fp->xv + xi;
1149 for (i = 0; i < c; i++)
1151 if (strcmp(k[i], "radius") == 0)
1152 sscanf(v[i], "%f", &xp->r);
1154 if (strcmp(k[i], "target") == 0)
1155 make_ref(v[i], &xp->pi);
1157 if (strcmp(k[i], "timer") == 0)
1158 sscanf(v[i], "%f", &xp->t0);
1160 if (strcmp(k[i], "state") == 0)
1163 if (strcmp(k[i], "invisible") == 0)
1166 if (strcmp(k[i], "origin") == 0)
1168 int x = 0, y = 0, z = 0;
1170 sscanf(v[i], "%d %d %d", &x, &y, &z);
1172 xp->p[0] = +(float) x / SCALE;
1173 xp->p[1] = +(float) z / SCALE;
1174 xp->p[2] = -(float) y / SCALE;
1179 static void make_targ(struct s_file *fp,
1181 char v[][MAXSTR], int c)
1185 targ_p[targ_n][0] = 0.f;
1186 targ_p[targ_n][1] = 0.f;
1187 targ_p[targ_n][3] = 0.f;
1189 for (i = 0; i < c; i++)
1191 if (strcmp(k[i], "targetname") == 0)
1192 make_sym(v[i], targ_n);
1194 if (strcmp(k[i], "origin") == 0)
1196 int x = 0, y = 0, z = 0;
1198 sscanf(v[i], "%d %d %d", &x, &y, &z);
1200 targ_p[targ_n][0] = +(float) x / SCALE;
1201 targ_p[targ_n][1] = +(float) z / SCALE;
1202 targ_p[targ_n][2] = -(float) y / SCALE;
1209 static void make_ball(struct s_file *fp,
1211 char v[][MAXSTR], int c)
1213 int i, ui = incu(fp);
1215 struct s_ball *up = fp->uv + ui;
1239 for (i = 0; i < c; i++)
1241 if (strcmp(k[i], "radius") == 0)
1242 sscanf(v[i], "%f", &up->r);
1244 if (strcmp(k[i], "origin") == 0)
1246 int x = 0, y = 0, z = 0;
1248 sscanf(v[i], "%d %d %d", &x, &y, &z);
1250 up->p[0] = +(float) (x) / SCALE;
1251 up->p[1] = +(float) (z - 24) / SCALE;
1252 up->p[2] = -(float) (y) / SCALE;
1256 up->p[1] += up->r + SMALL;
1259 /*---------------------------------------------------------------------------*/
1261 static void read_ent(struct s_file *fp, FILE *fin)
1263 char k[MAXKEY][MAXSTR];
1264 char v[MAXKEY][MAXSTR];
1265 int t, i = 0, c = 0;
1269 while ((t = map_token(fin, -1, k[c], v[c])))
1273 if (strcmp(k[c], "classname") == 0)
1277 if (t == T_BEG) read_lump(fp, fin);
1278 if (t == T_END) break;
1281 if (!strcmp(v[i], "light")) make_item(fp, k, v, c);
1282 if (!strcmp(v[i], "item_health_large")) make_item(fp, k, v, c);
1283 if (!strcmp(v[i], "item_health_small")) make_item(fp, k, v, c);
1284 if (!strcmp(v[i], "info_camp")) make_swch(fp, k, v, c);
1285 if (!strcmp(v[i], "info_null")) make_bill(fp, k, v, c);
1286 if (!strcmp(v[i], "path_corner")) make_path(fp, k, v, c);
1287 if (!strcmp(v[i], "info_player_start")) make_ball(fp, k, v, c);
1288 if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1289 if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
1290 if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
1291 if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
1292 if (!strcmp(v[i], "worldspawn")) make_body(fp, k, v, c, l0);
1293 if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
1294 if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
1297 static void read_map(struct s_file *fp, FILE *fin)
1303 while ((t = map_token(fin, -1, k, v)))
1308 /*---------------------------------------------------------------------------*/
1310 /* Test the location of a point with respect to a side plane. */
1312 static int fore_side(const float p[3], const struct s_side *sp)
1314 return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1317 static int on_side(const float p[3], const struct s_side *sp)
1319 float d = v_dot(p, sp->n) - sp->d;
1321 return (-SMALL < d && d < +SMALL) ? 1 : 0;
1324 /*---------------------------------------------------------------------------*/
1326 * Confirm that the addition of a vert would not result in degenerate
1330 static int ok_vert(const struct s_file *fp,
1331 const struct s_lump *lp, const float p[3])
1336 for (i = 0; i < lp->vc; i++)
1338 float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1342 if (v_len(r) < SMALL)
1348 /*---------------------------------------------------------------------------*/
1351 * The following functions take the set of planes defining a lump and
1352 * find the verts, edges, and geoms that describe its boundaries. To
1353 * do this, they first find the verts, and then search these verts for
1354 * valid edges and geoms. It may be more efficient to compute edges
1355 * and geoms directly by clipping down infinite line segments and
1356 * planes, but this would be more complex and prone to numerical
1361 * Given 3 side planes, compute the point of intersection, if any.
1362 * Confirm that this point falls within the current lump, and that it
1363 * is unique. Add it as a vert of the solid.
1365 static void clip_vert(struct s_file *fp,
1366 struct s_lump *lp, int si, int sj, int sk)
1368 float M[16], X[16], I[16];
1372 d[0] = fp->sv[si].d;
1373 d[1] = fp->sv[sj].d;
1374 d[2] = fp->sv[sk].d;
1376 m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1383 for (i = 0; i < lp->sc; i++)
1385 int si = fp->iv[lp->s0 + i];
1387 if (fore_side(p, fp->sv + si))
1391 if (ok_vert(fp, lp, p))
1393 v_cpy(fp->vv[fp->vc].p, p);
1395 fp->iv[fp->ic] = fp->vc;
1404 * Given two side planes, find an edge along their intersection by
1405 * finding a pair of vertices that fall on both planes. Add it to the
1408 static void clip_edge(struct s_file *fp,
1409 struct s_lump *lp, int si, int sj)
1413 for (i = 1; i < lp->vc; i++)
1414 for (j = 0; j < i; j++)
1416 int vi = fp->iv[lp->v0 + i];
1417 int vj = fp->iv[lp->v0 + j];
1419 if (on_side(fp->vv[vi].p, fp->sv + si) &&
1420 on_side(fp->vv[vj].p, fp->sv + si) &&
1421 on_side(fp->vv[vi].p, fp->sv + sj) &&
1422 on_side(fp->vv[vj].p, fp->sv + sj))
1424 fp->ev[fp->ec].vi = vi;
1425 fp->ev[fp->ec].vj = vj;
1427 fp->iv[fp->ic] = fp->ec;
1437 * Find all verts that lie on the given side of the lump. Sort these
1438 * verts to have a counter-clockwise winding about the plane normal.
1439 * Create geoms to tessellate the resulting convex polygon.
1441 static void clip_geom(struct s_file *fp,
1442 struct s_lump *lp, int si)
1444 int m[256], t[256], d, i, j, n = 0;
1449 struct s_side *sp = fp->sv + si;
1453 for (i = 0; i < lp->vc; i++)
1455 int vi = fp->iv[lp->v0 + i];
1457 if (on_side(fp->vv[vi].p, sp))
1462 v_add(v, fp->vv[vi].p, plane_p[si]);
1464 fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1465 fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1473 for (i = 1; i < n; i++)
1474 for (j = i + 1; j < n; j++)
1476 v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1477 v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1480 if (v_dot(w, sp->n) < 0.f)
1494 for (i = 0; i < n - 2; i++)
1496 fp->gv[fp->gc].mi = plane_m[si];
1498 fp->gv[fp->gc].ti = t[0];
1499 fp->gv[fp->gc].tj = t[i + 1];
1500 fp->gv[fp->gc].tk = t[i + 2];
1502 fp->gv[fp->gc].si = si;
1503 fp->gv[fp->gc].sj = si;
1504 fp->gv[fp->gc].sk = si;
1506 fp->gv[fp->gc].vi = m[0];
1507 fp->gv[fp->gc].vj = m[i + 1];
1508 fp->gv[fp->gc].vk = m[i + 2];
1510 fp->iv[fp->ic] = fp->gc;
1518 * Iterate the sides of the lump, attempting to generate a new vert for
1519 * each trio of planes, a new edge for each pair of planes, and a new
1520 * set of geom for each visible plane.
1522 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1529 for (i = 2; i < lp->sc; i++)
1530 for (j = 1; j < i; j++)
1531 for (k = 0; k < j; k++)
1535 fp->iv[lp->s0 + k]);
1540 for (i = 1; i < lp->sc; i++)
1541 for (j = 0; j < i; j++)
1544 fp->iv[lp->s0 + j]);
1549 for (i = 0; i < lp->sc; i++)
1550 if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0)
1552 fp->iv[lp->s0 + i]);
1554 for (i = 0; i < lp->sc; i++)
1555 if (plane_f[fp->iv[lp->s0 + i]])
1559 static void clip_file(struct s_file *fp)
1563 for (i = 0; i < fp->lc; i++)
1564 clip_lump(fp, fp->lv + i);
1567 /*---------------------------------------------------------------------------*/
1570 * For each body element type, determine if element 'p' is equivalent
1571 * to element 'q'. This is more than a simple memory compare. It
1572 * effectively snaps mtrls and verts together, and may reverse the
1573 * winding of an edge or a geom. This is done in order to maximize
1574 * the number of elements that can be eliminated.
1577 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1579 if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1580 if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1581 if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1582 if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1584 if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1585 if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1586 if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1587 if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1589 if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1590 if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1591 if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1592 if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1594 if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1595 if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1596 if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1597 if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1599 if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1601 if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1606 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1608 if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1609 if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1610 if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1615 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1617 if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1618 if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1623 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1625 if (fabs(sp->d - sq->d) > SMALL) return 0;
1626 if (v_dot(sp->n, sq->n) < 0.9999) return 0;
1631 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1633 if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1634 if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1639 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1641 if (gp->mi != gq->mi) return 0;
1643 if (gp->ti != gq->ti) return 0;
1644 if (gp->si != gq->si) return 0;
1645 if (gp->vi != gq->vi) return 0;
1647 if (gp->tj != gq->tj) return 0;
1648 if (gp->sj != gq->sj) return 0;
1649 if (gp->vj != gq->vj) return 0;
1651 if (gp->tk != gq->tk) return 0;
1652 if (gp->sk != gq->sk) return 0;
1653 if (gp->vk != gq->vk) return 0;
1658 /*---------------------------------------------------------------------------*/
1661 * For each file element type, replace all references to element 'i'
1662 * with a reference to element 'j'. These are used when optimizing
1663 * and sorting the file.
1666 static void swap_mtrl(struct s_file *fp, int mi, int mj)
1670 for (i = 0; i < fp->gc; i++)
1671 if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1672 for (i = 0; i < fp->rc; i++)
1673 if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1676 static void swap_vert(struct s_file *fp, int vi, int vj)
1680 for (i = 0; i < fp->ec; i++)
1682 if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1683 if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1686 for (i = 0; i < fp->gc; i++)
1688 if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1689 if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1690 if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1693 for (i = 0; i < fp->lc; i++)
1694 for (j = 0; j < fp->lv[i].vc; j++)
1695 if (fp->iv[fp->lv[i].v0 + j] == vi)
1696 fp->iv[fp->lv[i].v0 + j] = vj;
1699 static void swap_edge(struct s_file *fp, int ei, int ej)
1703 for (i = 0; i < fp->lc; i++)
1704 for (j = 0; j < fp->lv[i].ec; j++)
1705 if (fp->iv[fp->lv[i].e0 + j] == ei)
1706 fp->iv[fp->lv[i].e0 + j] = ej;
1709 static void swap_side(struct s_file *fp, int si, int sj)
1713 for (i = 0; i < fp->gc; i++)
1715 if (fp->gv[i].si == si) fp->gv[i].si = sj;
1716 if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1717 if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1719 for (i = 0; i < fp->nc; i++)
1720 if (fp->nv[i].si == si) fp->nv[i].si = sj;
1722 for (i = 0; i < fp->lc; i++)
1723 for (j = 0; j < fp->lv[i].sc; j++)
1724 if (fp->iv[fp->lv[i].s0 + j] == si)
1725 fp->iv[fp->lv[i].s0 + j] = sj;
1728 static void swap_texc(struct s_file *fp, int ti, int tj)
1732 for (i = 0; i < fp->gc; i++)
1734 if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1735 if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1736 if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1741 static void swap_geom(struct s_file *fp, int gi, int gj)
1745 for (i = 0; i < fp->lc; i++)
1746 for (j = 0; j < fp->lv[i].gc; j++)
1747 if (fp->iv[fp->lv[i].g0 + j] == gi)
1748 fp->iv[fp->lv[i].g0 + j] = gj;
1750 for (i = 0; i < fp->bc; i++)
1751 for (j = 0; j < fp->bv[i].gc; j++)
1752 if (fp->iv[fp->bv[i].g0 + j] == gi)
1753 fp->iv[fp->bv[i].g0 + j] = gj;
1756 /*---------------------------------------------------------------------------*/
1758 static void uniq_mtrl(struct s_file *fp)
1762 for (i = 0; i < fp->mc; i++)
1764 for (j = 0; j < k; j++)
1765 if (comp_mtrl(fp->mv + i, fp->mv + j))
1767 swap_mtrl(fp, i, j);
1775 fp->mv[k] = fp->mv[i];
1776 swap_mtrl(fp, i, k);
1785 static void uniq_vert(struct s_file *fp)
1789 for (i = 0; i < fp->vc; i++)
1791 for (j = 0; j < k; j++)
1792 if (comp_vert(fp->vv + i, fp->vv + j))
1794 swap_vert(fp, i, j);
1802 fp->vv[k] = fp->vv[i];
1803 swap_vert(fp, i, k);
1812 static void uniq_edge(struct s_file *fp)
1816 for (i = 0; i < fp->ec; i++)
1818 for (j = 0; j < k; j++)
1819 if (comp_edge(fp->ev + i, fp->ev + j))
1821 swap_edge(fp, i, j);
1829 fp->ev[k] = fp->ev[i];
1830 swap_edge(fp, i, k);
1839 static void uniq_geom(struct s_file *fp)
1843 for (i = 0; i < fp->gc; i++)
1845 for (j = 0; j < k; j++)
1846 if (comp_geom(fp->gv + i, fp->gv + j))
1848 swap_geom(fp, i, j);
1856 fp->gv[k] = fp->gv[i];
1857 swap_geom(fp, i, k);
1866 static void uniq_texc(struct s_file *fp)
1870 for (i = 0; i < fp->tc; i++)
1872 for (j = 0; j < k; j++)
1873 if (comp_texc(fp->tv + i, fp->tv + j))
1875 swap_texc(fp, i, j);
1883 fp->tv[k] = fp->tv[i];
1884 swap_texc(fp, i, k);
1893 static void uniq_side(struct s_file *fp)
1897 for (i = 0; i < fp->sc; i++)
1899 for (j = 0; j < k; j++)
1900 if (comp_side(fp->sv + i, fp->sv + j))
1902 swap_side(fp, i, j);
1910 fp->sv[k] = fp->sv[i];
1911 swap_side(fp, i, k);
1920 static void uniq_file(struct s_file *fp)
1933 /*---------------------------------------------------------------------------*/
1935 static void sort_file(struct s_file *fp)
1939 /* Sort billboards farthest to nearest. */
1941 for (i = 0; i < fp->rc; i++)
1942 for (j = i + 1; j < fp->rc; j++)
1943 if (fp->rv[j].d > fp->rv[i].d)
1948 fp->rv[i] = fp->rv[j];
1952 /* Ensure the first vertex is the lowest. */
1954 for (i = 0; i < fp->vc; i++)
1955 if (fp->vv[0].p[1] > fp->vv[i].p[1])
1960 fp->vv[0] = fp->vv[i];
1963 swap_vert(fp, 0, -1);
1964 swap_vert(fp, i, 0);
1965 swap_vert(fp, -1, i);
1969 /*---------------------------------------------------------------------------*/
1971 static int test_lump_side(const struct s_file *fp,
1972 const struct s_lump *lp,
1973 const struct s_side *sp)
1981 /* If the given side is part of the given lump, then the lump is behind. */
1983 for (si = 0; si < lp->sc; si++)
1984 if (fp->sv + fp->iv[lp->s0 + si] == sp)
1987 /* Check if each lump vertex is in front of, behind, on the side. */
1989 for (vi = 0; vi < lp->vc; vi++)
1991 float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
1997 /* If no verts are behind, the lump is in front, and vice versa. */
1999 if (f > 0 && b == 0) return +1;
2000 if (b > 0 && f == 0) return -1;
2002 /* Else, the lump crosses the side. */
2007 static int node_node(struct s_file *fp, int l0, int lc)
2011 /* Base case. Dump all given lumps into a leaf node. */
2013 fp->nv[fp->nc].si = -1;
2014 fp->nv[fp->nc].ni = -1;
2015 fp->nv[fp->nc].nj = -1;
2016 fp->nv[fp->nc].l0 = l0;
2017 fp->nv[fp->nc].lc = lc;
2027 int li = 0, lic = 0;
2028 int lj = 0, ljc = 0;
2029 int lk = 0, lkc = 0;
2032 /* Find the side that most evenly splits the given lumps. */
2034 for (si = 0; si < fp->sc; si++)
2040 for (li = 0; li < lc; li++)
2041 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
2048 if ((d < sjd) || (d == sjd && o < sjo))
2056 /* Flag each lump with its position WRT the side. */
2058 for (li = 0; li < lc; li++)
2061 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2065 switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
2068 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10;
2072 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2076 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40;
2081 /* Sort all lumps in the range by their flag values. */
2083 for (li = 1; li < lc; li++)
2084 for (lj = 0; lj < li; lj++)
2085 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
2089 l = fp->lv[l0 + li];
2090 fp->lv[l0 + li] = fp->lv[l0 + lj];
2091 fp->lv[l0 + lj] = l;
2094 /* Establish the in-front, on, and behind lump ranges. */
2100 for (i = lc - 1; i >= 0; i--)
2101 switch (fp->lv[l0 + i].fl & 0xf0)
2103 case 0x10: li = l0 + i; lic++; break;
2104 case 0x20: lj = l0 + i; ljc++; break;
2105 case 0x40: lk = l0 + i; lkc++; break;
2108 /* Add the lumps on the side to the node. */
2113 fp->nv[i].ni = node_node(fp, li, lic);
2115 fp->nv[i].nj = node_node(fp, lk, lkc);
2123 static void node_file(struct s_file *fp)
2127 /* Sort the lumps of each body into BSP nodes. */
2129 for (bi = 0; bi < fp->bc; bi++)
2130 fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
2133 /*---------------------------------------------------------------------------*/
2135 static void dump_file(struct s_file *p, const char *name)
2137 /* FIXME: Count visible geoms.
2139 * I'm afraid items break this (not sure though) so leaving it out.
2149 int m = p->rc + p->cc * 128 + (p->zc * p->jc + p->xc) * 32;
2152 /* Count the number of solid lumps. */
2154 for (i = 0; i < p->lc; i++)
2155 if ((p->lv[i].fl & 1) == 0)
2159 /* Count the number of visible geoms. */
2161 for (i = 0; i < p->bc; i++)
2163 for (j = 0; j < p->bv[i].lc; j++)
2164 m += p->lv[p->bv[i].l0 + j].gc;
2169 /* Count the total value of all coins. */
2171 for (i = 0; i < p->hc; i++)
2172 if (p->hv[i].t == ITEM_COIN)
2176 printf("%s (%d/%d/$%d)\n"
2178 printf("%s (%d/$%d)\n"
2179 " mtrl vert edge side texc"
2180 " geom lump path node body\n"
2181 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
2182 " item goal view jump swch"
2183 " bill ball char dict indx\n"
2184 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
2189 p->mc, p->vc, p->ec, p->sc, p->tc,
2190 p->gc, p->lc, p->pc, p->nc, p->bc,
2191 p->hc, p->zc, p->wc, p->jc, p->xc,
2192 p->rc, p->uc, p->ac, p->dc, p->ic);
2195 /* Skip the ugly SDL main substitution since we only need sdl_image. */
2200 int main(int argc, char *argv[])
2209 if (argc > 3 && strcmp(argv[3], "--debug") == 0)
2212 if (config_data_path(argv[2], NULL))
2214 strncpy(src, argv[1], MAXSTR);
2215 strncpy(dst, argv[1], MAXSTR);
2217 if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
2218 strcpy(dst + strlen(dst) - 4, ".sol");
2220 strcat(dst, ".sol");
2222 if ((fin = fopen(src, "r")))
2244 else fprintf(stderr, "Failure to establish data directory\n");
2246 else fprintf(stderr, "Usage: %s <map> <data> [--debug]\n", argv[0]);