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 /* Ohhhh... arbitrary! */
78 static int overflow(const char *s)
80 printf("%s overflow\n", s);
85 static int incm(struct s_file *fp)
87 return (fp->mc < MAXM) ? fp->mc++ : overflow("mtrl");
90 static int incv(struct s_file *fp)
92 return (fp->vc < MAXV) ? fp->vc++ : overflow("vert");
95 static int ince(struct s_file *fp)
97 return (fp->ec < MAXE) ? fp->ec++ : overflow("edge");
100 static int incs(struct s_file *fp)
102 return (fp->sc < MAXS) ? fp->sc++ : overflow("side");
105 static int inct(struct s_file *fp)
107 return (fp->tc < MAXT) ? fp->tc++ : overflow("texc");
110 static int incg(struct s_file *fp)
112 return (fp->gc < MAXG) ? fp->gc++ : overflow("geom");
115 static int incl(struct s_file *fp)
117 return (fp->lc < MAXL) ? fp->lc++ : overflow("lump");
120 static int incn(struct s_file *fp)
122 return (fp->nc < MAXN) ? fp->nc++ : overflow("node");
125 static int incp(struct s_file *fp)
127 return (fp->pc < MAXP) ? fp->pc++ : overflow("path");
130 static int incb(struct s_file *fp)
132 return (fp->bc < MAXB) ? fp->bc++ : overflow("body");
135 static int incc(struct s_file *fp)
137 return (fp->cc < MAXC) ? fp->cc++ : overflow("coin");
140 static int inch(struct s_file *fp)
142 return (fp->hc < MAXH) ? fp->hc++ : overflow("item");
145 static int incz(struct s_file *fp)
147 return (fp->zc < MAXZ) ? fp->zc++ : overflow("geol");
150 static int incj(struct s_file *fp)
152 return (fp->jc < MAXJ) ? fp->jc++ : overflow("jump");
155 static int incx(struct s_file *fp)
157 return (fp->xc < MAXX) ? fp->xc++ : overflow("swch");
160 static int incr(struct s_file *fp)
162 return (fp->rc < MAXR) ? fp->rc++ : overflow("bill");
165 static int incu(struct s_file *fp)
167 return (fp->uc < MAXU) ? fp->uc++ : overflow("ball");
170 static int incw(struct s_file *fp)
172 return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
175 static int inci(struct s_file *fp)
177 return (fp->ic < MAXI) ? fp->ic++ : overflow("indx");
180 static void init_file(struct s_file *fp)
203 fp->mv = (struct s_mtrl *) calloc(MAXM, sizeof (struct s_mtrl));
204 fp->vv = (struct s_vert *) calloc(MAXV, sizeof (struct s_vert));
205 fp->ev = (struct s_edge *) calloc(MAXE, sizeof (struct s_edge));
206 fp->sv = (struct s_side *) calloc(MAXS, sizeof (struct s_side));
207 fp->tv = (struct s_texc *) calloc(MAXT, sizeof (struct s_texc));
208 fp->gv = (struct s_geom *) calloc(MAXG, sizeof (struct s_geom));
209 fp->lv = (struct s_lump *) calloc(MAXL, sizeof (struct s_lump));
210 fp->nv = (struct s_node *) calloc(MAXN, sizeof (struct s_node));
211 fp->pv = (struct s_path *) calloc(MAXP, sizeof (struct s_path));
212 fp->bv = (struct s_body *) calloc(MAXB, sizeof (struct s_body));
213 fp->cv = (struct s_coin *) calloc(MAXC, sizeof (struct s_coin));
214 fp->hv = (struct s_item *) calloc(MAXH, sizeof (struct s_item));
215 fp->zv = (struct s_goal *) calloc(MAXZ, sizeof (struct s_goal));
216 fp->jv = (struct s_jump *) calloc(MAXJ, sizeof (struct s_jump));
217 fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
218 fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
219 fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
220 fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
221 fp->av = (char *) calloc(MAXA, sizeof (char));
222 fp->iv = (int *) calloc(MAXI, sizeof (int));
225 /*---------------------------------------------------------------------------*/
228 * The following is a small symbol table data structure. Symbols and
229 * their integer values are collected in symv and valv. References
230 * and pointers to their unsatisfied integer values are collected in
231 * refv and pntv. The resolve procedure matches references to symbols
232 * and fills waiting ints with the proper values.
237 static char symv[MAXSYM][MAXSTR];
238 static int valv[MAXSYM];
240 static char refv[MAXSYM][MAXSTR];
241 static int *pntv[MAXSYM];
246 static void make_sym(const char *s, int v)
248 strncpy(symv[strc], s, MAXSTR - 1);
253 static void make_ref(const char *r, int *p)
255 strncpy(refv[refc], r, MAXSTR - 1);
260 static void resolve(void)
264 for (i = 0; i < refc; i++)
265 for (j = 0; j < strc; j++)
266 if (strncmp(refv[i], symv[j], MAXSTR) == 0)
268 *(pntv[i]) = valv[j];
273 /*---------------------------------------------------------------------------*/
276 * The following globals are used to cache target_positions. They are
277 * targeted by various entities and must be resolved in a second pass.
280 static float targ_p [MAXW][3];
281 static int targ_wi[MAXW];
282 static int targ_ji[MAXW];
285 static void targets(struct s_file *fp)
289 for (i = 0; i < fp->wc; i++)
290 v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
292 for (i = 0; i < fp->jc; i++)
293 v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
296 /*---------------------------------------------------------------------------*/
299 * The following code caches image sizes. Textures are referenced by
300 * name, but their sizes are necessary when computing texture
301 * coordinates. This code allows each file to be accessed only once
302 * regardless of the number of surfaces refering to it.
311 static struct _imagedata *imagedata = NULL;
312 static int image_n = 0;
313 static int image_alloc = 0;
315 #define IMAGE_REALLOC 32
317 static void free_imagedata()
323 for (i = 0; i < image_n; i++)
324 free(imagedata[i].s);
328 image_n = image_alloc = 0;
331 static int size_load(const char *file, int *w, int *h)
335 if ((S = IMG_Load(file)))
347 static void size_image(const char *name, int *w, int *h)
355 for (i = 0; i < image_n; i++)
356 if (strncmp(imagedata[i].s, name, MAXSTR) == 0)
367 strcpy(jpg, name); strcat(jpg, ".jpg");
368 strcpy(tga, name); strcat(tga, ".tga");
369 strcpy(png, name); strcat(png, ".png");
371 if (size_load(config_data(png), w, h) ||
372 size_load(config_data(tga), w, h) ||
373 size_load(config_data(jpg), w, h))
376 if (image_n + 1 >= image_alloc)
378 struct _imagedata *tmp =
379 (struct _imagedata *) malloc(sizeof(struct _imagedata) * (image_alloc + IMAGE_REALLOC));
382 printf("malloc error\n");
387 (void) memcpy(tmp, imagedata, sizeof(struct _imagedata) * image_alloc);
391 image_alloc += IMAGE_REALLOC;
394 imagedata[image_n].s = (char *) calloc(strlen(name) + 1, 1);
395 imagedata[image_n].w = *w;
396 imagedata[image_n].h = *h;
397 strcpy(imagedata[image_n].s, name);
403 /*---------------------------------------------------------------------------*/
405 /* Read the given material file, adding a new material to the solid. */
407 static int read_mtrl(struct s_file *fp, const char *name)
413 for (mi = 0; mi < fp->mc; mi++)
414 if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
417 mp = fp->mv + incm(fp);
419 strncpy(mp->f, name, PATHMAX - 1);
421 mp->a[0] = mp->a[1] = mp->a[2] = mp->a[3] = 1.0f;
422 mp->d[0] = mp->d[1] = mp->d[2] = mp->d[3] = 1.0f;
423 mp->s[0] = mp->s[1] = mp->s[2] = mp->s[3] = 1.0f;
424 mp->e[0] = mp->e[1] = mp->e[2] = mp->e[3] = 1.0f;
428 if ((fin = fopen(config_data(name), "r")))
436 mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
437 mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
438 mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
439 mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
447 /*---------------------------------------------------------------------------*/
450 * All bodies with an associated path are assumed to be positioned at
451 * the beginning of that path. These bodies must be moved to the
452 * origin in order for their path transforms to behave correctly.
453 * This is how we get away with defining func_trains with no origin
457 static void move_side(struct s_side *sp, const float p[3])
459 sp->d -= v_dot(sp->n, p);
462 static void move_vert(struct s_vert *vp, const float p[3])
464 v_sub(vp->p, vp->p, p);
467 static void move_lump(struct s_file *fp,
468 struct s_lump *lp, const float p[3])
472 for (i = 0; i < lp->sc; i++)
473 move_side(fp->sv + fp->iv[lp->s0 + i], p);
474 for (i = 0; i < lp->vc; i++)
475 move_vert(fp->vv + fp->iv[lp->v0 + i], p);
478 static void move_body(struct s_file *fp,
483 for (i = 0; i < bp->lc; i++)
484 move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
487 static void move_file(struct s_file *fp)
491 for (i = 0; i < fp->bc; i++)
492 if (fp->bv[i].pi >= 0)
493 move_body(fp, fp->bv + i);
496 /*---------------------------------------------------------------------------*/
499 * This is a basic OBJ loader. It is by no means fully compliant with
500 * the OBJ specification, but it works well with the output of
501 * Wings3D. All faces must be triangles and all vertices must include
502 * normals and texture coordinates. Material names are taken to be
503 * references to Neverball materials, rather than MTL definitions.
506 static void read_vt(struct s_file *fp, const char *line)
508 struct s_texc *tp = fp->tv + inct(fp);
510 sscanf(line, "%f %f", tp->u, tp->u + 1);
513 static void read_vn(struct s_file *fp, const char *line)
515 struct s_side *sp = fp->sv + incs(fp);
517 sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
520 static void read_v(struct s_file *fp, const char *line)
522 struct s_vert *vp = fp->vv + incv(fp);
524 sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
527 static void read_f(struct s_file *fp, const char *line,
528 int v0, int t0, int s0, int mi)
530 struct s_geom *gp = fp->gv + incg(fp);
535 sscanf(line, "%d%c%d%c%d %d%c%d%c%d %d%c%d%c%d",
536 &gp->vi, &c1, &gp->ti, &c2, &gp->si,
537 &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
538 &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
553 static void read_obj(struct s_file *fp, const char *name)
564 if ((fin = fopen(config_data(name), "r")))
566 while (fgets(line, MAXSTR, fin))
568 if (strncmp(line, "usemtl", 6) == 0)
570 sscanf(line + 6, "%s", mtrl);
571 mi = read_mtrl(fp, mtrl);
574 else if (strncmp(line, "f", 1) == 0)
576 if (fp->mv[mi].d[3] > 0)
577 read_f(fp, line + 1, v0, t0, s0, mi);
580 else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
581 else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
582 else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
588 /*---------------------------------------------------------------------------*/
590 static float plane_d[MAXS];
591 static float plane_n[MAXS][3];
592 static float plane_p[MAXS][3];
593 static float plane_u[MAXS][3];
594 static float plane_v[MAXS][3];
595 static int plane_f[MAXS];
596 static int plane_m[MAXS];
598 static void make_plane(int pi, int x0, int y0, int z0,
599 int x1, int y1, int z1,
600 int x2, int y2, int z2,
601 int tu, int tv, int r,
602 float su, float sv, int fl, const char *s)
604 static const float base[6][3][3] = {
605 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
606 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
607 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
608 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
609 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
610 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
614 float p0[3], p1[3], p2[3];
615 float u[3], v[3], p[3];
620 size_image(s, &w, &h);
622 plane_f[pi] = fl ? L_DETAIL : 0;
624 p0[0] = +(float) x0 / SCALE;
625 p0[1] = +(float) z0 / SCALE;
626 p0[2] = -(float) y0 / SCALE;
628 p1[0] = +(float) x1 / SCALE;
629 p1[1] = +(float) z1 / SCALE;
630 p1[2] = -(float) y1 / SCALE;
632 p2[0] = +(float) x2 / SCALE;
633 p2[1] = +(float) z2 / SCALE;
634 p2[2] = -(float) y2 / SCALE;
639 v_crs(plane_n[pi], u, v);
640 v_nrm(plane_n[pi], plane_n[pi]);
642 plane_d[pi] = v_dot(plane_n[pi], p1);
644 for (i = 0; i < 6; i++)
645 if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
655 m_rot(R, base[n][0], V_RAD(r));
657 v_mad(p, p, base[n][1], su * tu / SCALE);
658 v_mad(p, p, base[n][2], sv * tv / SCALE);
660 m_vxfm(plane_u[pi], R, base[n][1]);
661 m_vxfm(plane_v[pi], R, base[n][2]);
662 m_vxfm(plane_p[pi], R, p);
664 v_scl(plane_u[pi], plane_u[pi], 64.f / w);
665 v_scl(plane_v[pi], plane_v[pi], 64.f / h);
667 v_scl(plane_u[pi], plane_u[pi], 1.f / su);
668 v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
671 /*---------------------------------------------------------------------------*/
680 static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
684 if (fgets(buf, MAXSTR, fin))
694 /* Scan the beginning or end of a block. */
696 if (buf[0] == '{') return T_BEG;
697 if (buf[0] == '}') return T_END;
699 /* Scan a key-value pair. */
703 strcpy(key, strtok(buf, "\""));
704 (void) strtok(NULL, "\"");
705 strcpy(val, strtok(NULL, "\""));
716 "%s %d %d %d %f %f %d",
717 &c, &x0, &y0, &z0, &c,
718 &c, &x1, &y1, &z1, &c,
719 &c, &x2, &y2, &z2, &c,
720 key, &tu, &tv, &r, &su, &sv, &fl) == 22)
722 make_plane(pi, x0, y0, z0,
725 tu, tv, r, su, sv, fl, key);
729 /* If it's not recognized, it must be uninteresting. */
736 /*---------------------------------------------------------------------------*/
738 /* Parse a lump from the given file and add it to the solid. */
740 static void read_lump(struct s_file *fp, FILE *fin)
746 struct s_lump *lp = fp->lv + incl(fp);
750 while ((t = map_token(fin, fp->sc, k, v)))
754 fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
755 fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
756 fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
757 fp->sv[fp->sc].d = plane_d[fp->sc];
759 plane_m[fp->sc] = read_mtrl(fp, k);
761 fp->iv[fp->ic] = fp->sc;
771 /*---------------------------------------------------------------------------*/
773 static void make_path(struct s_file *fp,
775 char v[][MAXSTR], int c)
777 int i, pi = incp(fp);
779 struct s_path *pp = fp->pv + pi;
788 for (i = 0; i < c; i++)
790 if (strcmp(k[i], "targetname") == 0)
793 if (strcmp(k[i], "target") == 0)
794 make_ref(v[i], &pp->pi);
796 if (strcmp(k[i], "state") == 0)
799 if (strcmp(k[i], "speed") == 0)
800 sscanf(v[i], "%f", &pp->t);
802 if (strcmp(k[i], "origin") == 0)
804 int x = 0, y = 0, z = 0;
806 sscanf(v[i], "%d %d %d", &x, &y, &z);
808 pp->p[0] = +(float) x / SCALE;
809 pp->p[1] = +(float) z / SCALE;
810 pp->p[2] = -(float) y / SCALE;
815 static void make_body(struct s_file *fp,
817 char v[][MAXSTR], int c, int l0)
819 int i, bi = incb(fp);
830 struct s_body *bp = fp->bv + bi;
836 for (i = 0; i < c; i++)
838 if (strcmp(k[i], "targetname") == 0)
841 else if (strcmp(k[i], "target") == 0)
842 make_ref(v[i], &bp->pi);
844 else if (strcmp(k[i], "model") == 0)
847 else if (strcmp(k[i], "origin") == 0)
848 sscanf(v[i], "%d %d %d", &x, &y, &z);
850 else if (strcmp(k[i], "classname") != 0)
852 /* Considers other strings as metadata */
853 strcat(fp->av, k[i]);
855 strcat(fp->av, v[i]);
856 strcat(fp->av, "\n");
857 fp->ac += (int) (strlen(v[i]) + (strlen(k[i])) + 2);
862 bp->lc = fp->lc - l0;
864 bp->gc = fp->gc - g0;
866 for (i = 0; i < bp->gc; i++)
867 fp->iv[inci(fp)] = g0++;
869 p[0] = +(float) x / SCALE;
870 p[1] = +(float) z / SCALE;
871 p[2] = -(float) y / SCALE;
873 for (i = v0; i < fp->vc; i++)
874 v_add(fp->vv[i].p, fp->vv[i].p, p);
877 static void make_coin(struct s_file *fp,
879 char v[][MAXSTR], int c)
881 int i, ci = incc(fp);
883 struct s_coin *cp = fp->cv + ci;
890 for (i = 0; i < c; i++)
892 if (strcmp(k[i], "light") == 0)
893 sscanf(v[i], "%d", &cp->n);
895 if (strcmp(k[i], "origin") == 0)
897 int x = 0, y = 0, z = 0;
899 sscanf(v[i], "%d %d %d", &x, &y, &z);
901 cp->p[0] = +(float) x / SCALE;
902 cp->p[1] = +(float) z / SCALE;
903 cp->p[2] = -(float) y / SCALE;
908 static void make_item(struct s_file *fp,
910 char v[][MAXSTR], int c)
912 int i, hi = inch(fp);
914 struct s_item *hp = fp->hv + hi;
922 for (i = 0; i < c; i++)
924 if (strcmp(k[i], "classname") == 0)
926 if (strcmp(v[i], "item_health_large") == 0)
928 else if (strcmp(v[i], "item_health_small") == 0)
932 if (strcmp(k[i], "origin") == 0)
934 int x = 0, y = 0, z = 0;
936 sscanf(v[i], "%d %d %d", &x, &y, &z);
938 hp->p[0] = +(float) x / SCALE;
939 hp->p[1] = +(float) z / SCALE;
940 hp->p[2] = -(float) y / SCALE;
945 static void make_bill(struct s_file *fp,
947 char v[][MAXSTR], int c)
949 int i, ri = incr(fp);
951 struct s_bill *rp = fp->rv + ri;
953 memset(rp, 0, sizeof (struct s_bill));
956 for (i = 0; i < c; i++)
958 if (strcmp(k[i], "width") == 0)
959 sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
960 if (strcmp(k[i], "height") == 0)
961 sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
963 if (strcmp(k[i], "xrot") == 0)
964 sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
965 if (strcmp(k[i], "yrot") == 0)
966 sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
967 if (strcmp(k[i], "zrot") == 0)
968 sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
970 if (strcmp(k[i], "time") == 0)
971 sscanf(v[i], "%f", &rp->t);
972 if (strcmp(k[i], "dist") == 0)
973 sscanf(v[i], "%f", &rp->d);
974 if (strcmp(k[i], "flag") == 0)
975 sscanf(v[i], "%d", &rp->fl);
977 if (strcmp(k[i], "image") == 0)
979 rp->mi = read_mtrl(fp, v[i]);
980 fp->mv[rp->mi].fl |= M_CLAMPED;
983 if (strcmp(k[i], "origin") == 0)
985 int x = 0, y = 0, z = 0;
988 sscanf(v[i], "%d %d %d", &x, &y, &z);
990 p[0] = +(float) x / SCALE;
991 p[1] = +(float) z / SCALE;
992 p[2] = -(float) y / SCALE;
995 rp->rx[0] = V_DEG(fatan2f(+p[1], rp->d));
996 rp->ry[0] = V_DEG(fatan2f(+p[0], -p[2]));
1000 if (rp->fl & B_ADDITIVE)
1001 fp->mv[rp->mi].fl |= M_ADDITIVE;
1004 static void make_goal(struct s_file *fp,
1006 char v[][MAXSTR], int c)
1008 int i, zi = incz(fp);
1010 struct s_goal *zp = fp->zv + zi;
1019 for (i = 0; i < c; i++)
1021 if (strcmp(k[i], "radius") == 0)
1022 sscanf(v[i], "%f", &zp->r);
1023 if (strcmp(k[i], "skip") == 0)
1024 sscanf(v[i], "%d", &zp->s);
1025 if (strcmp(k[i], "special") == 0)
1026 sscanf(v[i], "%d", &zp->c);
1028 if (strcmp(k[i], "origin") == 0)
1030 int x = 0, y = 0, z = 0;
1032 sscanf(v[i], "%d %d %d", &x, &y, &z);
1034 zp->p[0] = +(float) (x) / SCALE;
1035 zp->p[1] = +(float) (z - 24) / SCALE;
1036 zp->p[2] = -(float) (y) / SCALE;
1041 static void make_view(struct s_file *fp,
1043 char v[][MAXSTR], int c)
1045 int i, wi = incw(fp);
1047 struct s_view *wp = fp->wv + wi;
1056 for (i = 0; i < c; i++)
1058 if (strcmp(k[i], "target") == 0)
1059 make_ref(v[i], targ_wi + wi);
1061 if (strcmp(k[i], "origin") == 0)
1063 int x = 0, y = 0, z = 0;
1065 sscanf(v[i], "%d %d %d", &x, &y, &z);
1067 wp->p[0] = +(float) x / SCALE;
1068 wp->p[1] = +(float) z / SCALE;
1069 wp->p[2] = -(float) y / SCALE;
1074 static void make_jump(struct s_file *fp,
1076 char v[][MAXSTR], int c)
1078 int i, ji = incj(fp);
1080 struct s_jump *jp = fp->jv + ji;
1090 for (i = 0; i < c; i++)
1092 if (strcmp(k[i], "radius") == 0)
1093 sscanf(v[i], "%f", &jp->r);
1095 if (strcmp(k[i], "target") == 0)
1096 make_ref(v[i], targ_ji + ji);
1098 if (strcmp(k[i], "origin") == 0)
1100 int x = 0, y = 0, z = 0;
1102 sscanf(v[i], "%d %d %d", &x, &y, &z);
1104 jp->p[0] = +(float) x / SCALE;
1105 jp->p[1] = +(float) z / SCALE;
1106 jp->p[2] = -(float) y / SCALE;
1111 static void make_swch(struct s_file *fp,
1113 char v[][MAXSTR], int c)
1115 int i, xi = incx(fp);
1117 struct s_swch *xp = fp->xv + xi;
1130 for (i = 0; i < c; i++)
1132 if (strcmp(k[i], "radius") == 0)
1133 sscanf(v[i], "%f", &xp->r);
1135 if (strcmp(k[i], "target") == 0)
1136 make_ref(v[i], &xp->pi);
1138 if (strcmp(k[i], "timer") == 0)
1139 sscanf(v[i], "%f", &xp->t0);
1141 if (strcmp(k[i], "state") == 0)
1144 if (strcmp(k[i], "invisible") == 0)
1147 if (strcmp(k[i], "origin") == 0)
1149 int x = 0, y = 0, z = 0;
1151 sscanf(v[i], "%d %d %d", &x, &y, &z);
1153 xp->p[0] = +(float) x / SCALE;
1154 xp->p[1] = +(float) z / SCALE;
1155 xp->p[2] = -(float) y / SCALE;
1160 static void make_targ(struct s_file *fp,
1162 char v[][MAXSTR], int c)
1166 targ_p[targ_n][0] = 0.f;
1167 targ_p[targ_n][1] = 0.f;
1168 targ_p[targ_n][3] = 0.f;
1170 for (i = 0; i < c; i++)
1172 if (strcmp(k[i], "targetname") == 0)
1173 make_sym(v[i], targ_n);
1175 if (strcmp(k[i], "origin") == 0)
1177 int x = 0, y = 0, z = 0;
1179 sscanf(v[i], "%d %d %d", &x, &y, &z);
1181 targ_p[targ_n][0] = +(float) x / SCALE;
1182 targ_p[targ_n][1] = +(float) z / SCALE;
1183 targ_p[targ_n][2] = -(float) y / SCALE;
1190 static void make_ball(struct s_file *fp,
1192 char v[][MAXSTR], int c)
1194 int i, ui = incu(fp);
1196 struct s_ball *up = fp->uv + ui;
1220 for (i = 0; i < c; i++)
1222 if (strcmp(k[i], "radius") == 0)
1223 sscanf(v[i], "%f", &up->r);
1225 if (strcmp(k[i], "origin") == 0)
1227 int x = 0, y = 0, z = 0;
1229 sscanf(v[i], "%d %d %d", &x, &y, &z);
1231 up->p[0] = +(float) (x) / SCALE;
1232 up->p[1] = +(float) (z - 24) / SCALE;
1233 up->p[2] = -(float) (y) / SCALE;
1237 up->p[1] += up->r + SMALL;
1240 /*---------------------------------------------------------------------------*/
1242 static void read_ent(struct s_file *fp, FILE *fin)
1244 char k[MAXKEY][MAXSTR];
1245 char v[MAXKEY][MAXSTR];
1246 int t, i = 0, c = 0;
1250 while ((t = map_token(fin, -1, k[c], v[c])))
1254 if (strcmp(k[c], "classname") == 0)
1258 if (t == T_BEG) read_lump(fp, fin);
1259 if (t == T_END) break;
1262 if (!strcmp(v[i], "light")) make_coin(fp, k, v, c);
1263 if (!strcmp(v[i], "item_health_large")) make_item(fp, k, v, c);
1264 if (!strcmp(v[i], "item_health_small")) make_item(fp, k, v, c);
1265 if (!strcmp(v[i], "info_camp")) make_swch(fp, k, v, c);
1266 if (!strcmp(v[i], "info_null")) make_bill(fp, k, v, c);
1267 if (!strcmp(v[i], "path_corner")) make_path(fp, k, v, c);
1268 if (!strcmp(v[i], "info_player_start")) make_ball(fp, k, v, c);
1269 if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1270 if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
1271 if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
1272 if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
1273 if (!strcmp(v[i], "worldspawn")) make_body(fp, k, v, c, l0);
1274 if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
1275 if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
1278 static void read_map(struct s_file *fp, FILE *fin)
1284 while ((t = map_token(fin, -1, k, v)))
1289 /*---------------------------------------------------------------------------*/
1291 /* Test the location of a point with respect to a side plane. */
1293 static int fore_side(const float p[3], const struct s_side *sp)
1295 return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1298 static int on_side(const float p[3], const struct s_side *sp)
1300 float d = v_dot(p, sp->n) - sp->d;
1302 return (-SMALL < d && d < +SMALL) ? 1 : 0;
1305 /*---------------------------------------------------------------------------*/
1307 * Confirm that the addition of a vert would not result in degenerate
1311 static int ok_vert(const struct s_file *fp,
1312 const struct s_lump *lp, const float p[3])
1317 for (i = 0; i < lp->vc; i++)
1319 float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1323 if (v_len(r) < SMALL)
1329 /*---------------------------------------------------------------------------*/
1332 * The following functions take the set of planes defining a lump and
1333 * find the verts, edges, and geoms that describe its boundaries. To
1334 * do this, they first find the verts, and then search these verts for
1335 * valid edges and geoms. It may be more efficient to compute edges
1336 * and geoms directly by clipping down infinite line segments and
1337 * planes, but this would be more complex and prone to numerical
1342 * Given 3 side planes, compute the point of intersection, if any.
1343 * Confirm that this point falls within the current lump, and that it
1344 * is unique. Add it as a vert of the solid.
1346 static void clip_vert(struct s_file *fp,
1347 struct s_lump *lp, int si, int sj, int sk)
1349 float M[16], X[16], I[16];
1353 d[0] = fp->sv[si].d;
1354 d[1] = fp->sv[sj].d;
1355 d[2] = fp->sv[sk].d;
1357 m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1364 for (i = 0; i < lp->sc; i++)
1366 int si = fp->iv[lp->s0 + i];
1368 if (fore_side(p, fp->sv + si))
1372 if (ok_vert(fp, lp, p))
1374 v_cpy(fp->vv[fp->vc].p, p);
1376 fp->iv[fp->ic] = fp->vc;
1385 * Given two side planes, find an edge along their intersection by
1386 * finding a pair of vertices that fall on both planes. Add it to the
1389 static void clip_edge(struct s_file *fp,
1390 struct s_lump *lp, int si, int sj)
1394 for (i = 1; i < lp->vc; i++)
1395 for (j = 0; j < i; j++)
1397 int vi = fp->iv[lp->v0 + i];
1398 int vj = fp->iv[lp->v0 + j];
1400 if (on_side(fp->vv[vi].p, fp->sv + si) &&
1401 on_side(fp->vv[vj].p, fp->sv + si) &&
1402 on_side(fp->vv[vi].p, fp->sv + sj) &&
1403 on_side(fp->vv[vj].p, fp->sv + sj))
1405 fp->ev[fp->ec].vi = vi;
1406 fp->ev[fp->ec].vj = vj;
1408 fp->iv[fp->ic] = fp->ec;
1418 * Find all verts that lie on the given side of the lump. Sort these
1419 * verts to have a counter-clockwise winding about the plane normal.
1420 * Create geoms to tessalate the resulting convex polygon.
1422 static void clip_geom(struct s_file *fp,
1423 struct s_lump *lp, int si)
1425 int m[256], t[256], d, i, j, n = 0;
1430 struct s_side *sp = fp->sv + si;
1434 for (i = 0; i < lp->vc; i++)
1436 int vi = fp->iv[lp->v0 + i];
1438 if (on_side(fp->vv[vi].p, sp))
1443 v_add(v, fp->vv[vi].p, plane_p[si]);
1445 fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1446 fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1454 for (i = 1; i < n; i++)
1455 for (j = i + 1; j < n; j++)
1457 v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1458 v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1461 if (v_dot(w, sp->n) < 0.f)
1475 for (i = 0; i < n - 2; i++)
1477 fp->gv[fp->gc].mi = plane_m[si];
1479 fp->gv[fp->gc].ti = t[0];
1480 fp->gv[fp->gc].tj = t[i + 1];
1481 fp->gv[fp->gc].tk = t[i + 2];
1483 fp->gv[fp->gc].si = si;
1484 fp->gv[fp->gc].sj = si;
1485 fp->gv[fp->gc].sk = si;
1487 fp->gv[fp->gc].vi = m[0];
1488 fp->gv[fp->gc].vj = m[i + 1];
1489 fp->gv[fp->gc].vk = m[i + 2];
1491 fp->iv[fp->ic] = fp->gc;
1499 * Iterate the sides of the lump, attemping to generate a new vert for
1500 * each trio of planes, a new edge for each pair of planes, and a new
1501 * set of geom for each visible plane.
1503 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1510 for (i = 2; i < lp->sc; i++)
1511 for (j = 1; j < i; j++)
1512 for (k = 0; k < j; k++)
1516 fp->iv[lp->s0 + k]);
1521 for (i = 1; i < lp->sc; i++)
1522 for (j = 0; j < i; j++)
1525 fp->iv[lp->s0 + j]);
1530 for (i = 0; i < lp->sc; i++)
1531 if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0)
1533 fp->iv[lp->s0 + i]);
1535 for (i = 0; i < lp->sc; i++)
1536 if (plane_f[fp->iv[lp->s0 + i]])
1540 static void clip_file(struct s_file *fp)
1544 for (i = 0; i < fp->lc; i++)
1545 clip_lump(fp, fp->lv + i);
1548 /*---------------------------------------------------------------------------*/
1551 * For each body element type, determine if element 'p' is equivalent
1552 * to element 'q'. This is more than a simple memory compare. It
1553 * effectively snaps mtrls and verts togather, and may reverse the
1554 * winding of an edge or a geom. This is done in order to maximize
1555 * the number of elements that can be eliminated.
1558 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1560 if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1561 if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1562 if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1563 if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1565 if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1566 if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1567 if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1568 if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1570 if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1571 if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1572 if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1573 if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1575 if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1576 if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1577 if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1578 if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1580 if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1582 if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1587 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1589 if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1590 if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1591 if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1596 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1598 if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1599 if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1604 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1606 if (fabs(sp->d - sq->d) > SMALL) return 0;
1607 if (v_dot(sp->n, sq->n) < 0.9999) return 0;
1612 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1614 if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1615 if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1620 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1622 if (gp->mi != gq->mi) return 0;
1624 if (gp->ti != gq->ti) return 0;
1625 if (gp->si != gq->si) return 0;
1626 if (gp->vi != gq->vi) return 0;
1628 if (gp->tj != gq->tj) return 0;
1629 if (gp->sj != gq->sj) return 0;
1630 if (gp->vj != gq->vj) return 0;
1632 if (gp->tk != gq->tk) return 0;
1633 if (gp->sk != gq->sk) return 0;
1634 if (gp->vk != gq->vk) return 0;
1639 /*---------------------------------------------------------------------------*/
1642 * For each file element type, replace all references to element 'i'
1643 * with a reference to element 'j'. These are used when optimizing
1644 * and sorting the file.
1647 static void swap_mtrl(struct s_file *fp, int mi, int mj)
1651 for (i = 0; i < fp->gc; i++)
1652 if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1653 for (i = 0; i < fp->rc; i++)
1654 if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1657 static void swap_vert(struct s_file *fp, int vi, int vj)
1661 for (i = 0; i < fp->ec; i++)
1663 if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1664 if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1667 for (i = 0; i < fp->gc; i++)
1669 if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1670 if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1671 if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1674 for (i = 0; i < fp->lc; i++)
1675 for (j = 0; j < fp->lv[i].vc; j++)
1676 if (fp->iv[fp->lv[i].v0 + j] == vi)
1677 fp->iv[fp->lv[i].v0 + j] = vj;
1680 static void swap_edge(struct s_file *fp, int ei, int ej)
1684 for (i = 0; i < fp->lc; i++)
1685 for (j = 0; j < fp->lv[i].ec; j++)
1686 if (fp->iv[fp->lv[i].e0 + j] == ei)
1687 fp->iv[fp->lv[i].e0 + j] = ej;
1690 static void swap_side(struct s_file *fp, int si, int sj)
1694 for (i = 0; i < fp->gc; i++)
1696 if (fp->gv[i].si == si) fp->gv[i].si = sj;
1697 if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1698 if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1700 for (i = 0; i < fp->nc; i++)
1701 if (fp->nv[i].si == si) fp->nv[i].si = sj;
1703 for (i = 0; i < fp->lc; i++)
1704 for (j = 0; j < fp->lv[i].sc; j++)
1705 if (fp->iv[fp->lv[i].s0 + j] == si)
1706 fp->iv[fp->lv[i].s0 + j] = sj;
1709 static void swap_texc(struct s_file *fp, int ti, int tj)
1713 for (i = 0; i < fp->gc; i++)
1715 if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1716 if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1717 if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1722 static void swap_geom(struct s_file *fp, int gi, int gj)
1726 for (i = 0; i < fp->lc; i++)
1727 for (j = 0; j < fp->lv[i].gc; j++)
1728 if (fp->iv[fp->lv[i].g0 + j] == gi)
1729 fp->iv[fp->lv[i].g0 + j] = gj;
1731 for (i = 0; i < fp->bc; i++)
1732 for (j = 0; j < fp->bv[i].gc; j++)
1733 if (fp->iv[fp->bv[i].g0 + j] == gi)
1734 fp->iv[fp->bv[i].g0 + j] = gj;
1737 /*---------------------------------------------------------------------------*/
1739 static void uniq_mtrl(struct s_file *fp)
1743 for (i = 0; i < fp->mc; i++)
1745 for (j = 0; j < k; j++)
1746 if (comp_mtrl(fp->mv + i, fp->mv + j))
1748 swap_mtrl(fp, i, j);
1756 fp->mv[k] = fp->mv[i];
1757 swap_mtrl(fp, i, k);
1766 static void uniq_vert(struct s_file *fp)
1770 for (i = 0; i < fp->vc; i++)
1772 for (j = 0; j < k; j++)
1773 if (comp_vert(fp->vv + i, fp->vv + j))
1775 swap_vert(fp, i, j);
1783 fp->vv[k] = fp->vv[i];
1784 swap_vert(fp, i, k);
1793 static void uniq_edge(struct s_file *fp)
1797 for (i = 0; i < fp->ec; i++)
1799 for (j = 0; j < k; j++)
1800 if (comp_edge(fp->ev + i, fp->ev + j))
1802 swap_edge(fp, i, j);
1810 fp->ev[k] = fp->ev[i];
1811 swap_edge(fp, i, k);
1820 static void uniq_geom(struct s_file *fp)
1824 for (i = 0; i < fp->gc; i++)
1826 for (j = 0; j < k; j++)
1827 if (comp_geom(fp->gv + i, fp->gv + j))
1829 swap_geom(fp, i, j);
1837 fp->gv[k] = fp->gv[i];
1838 swap_geom(fp, i, k);
1847 static void uniq_texc(struct s_file *fp)
1851 for (i = 0; i < fp->tc; i++)
1853 for (j = 0; j < k; j++)
1854 if (comp_texc(fp->tv + i, fp->tv + j))
1856 swap_texc(fp, i, j);
1864 fp->tv[k] = fp->tv[i];
1865 swap_texc(fp, i, k);
1874 static void uniq_side(struct s_file *fp)
1878 for (i = 0; i < fp->sc; i++)
1880 for (j = 0; j < k; j++)
1881 if (comp_side(fp->sv + i, fp->sv + j))
1883 swap_side(fp, i, j);
1891 fp->sv[k] = fp->sv[i];
1892 swap_side(fp, i, k);
1901 static void uniq_file(struct s_file *fp)
1911 /*---------------------------------------------------------------------------*/
1913 static void sort_file(struct s_file *fp)
1917 /* Sort billboards farthest to nearest. */
1919 for (i = 0; i < fp->rc; i++)
1920 for (j = i + 1; j < fp->rc; j++)
1921 if (fp->rv[j].d > fp->rv[i].d)
1926 fp->rv[i] = fp->rv[j];
1930 /* Ensure the first vertex is the lowest. */
1932 for (i = 0; i < fp->vc; i++)
1933 if (fp->vv[0].p[1] > fp->vv[i].p[1])
1938 fp->vv[0] = fp->vv[i];
1941 swap_vert(fp, 0, -1);
1942 swap_vert(fp, i, 0);
1943 swap_vert(fp, -1, i);
1947 /*---------------------------------------------------------------------------*/
1949 static int test_lump_side(const struct s_file *fp,
1950 const struct s_lump *lp,
1951 const struct s_side *sp)
1959 /* If the given side is part of the given lump, then the lump is behind. */
1961 for (si = 0; si < lp->sc; si++)
1962 if (fp->sv + fp->iv[lp->s0 + si] == sp)
1965 /* Check if each lump vertex is in front of, behind, on the side. */
1967 for (vi = 0; vi < lp->vc; vi++)
1969 float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
1975 /* If no verts are behind, the lump is in front, and vice versa. */
1977 if (f > 0 && b == 0) return +1;
1978 if (b > 0 && f == 0) return -1;
1980 /* Else, the lump crosses the side. */
1985 static int node_node(struct s_file *fp, int l0, int lc)
1989 /* Base case. Dump all given lumps into a leaf node. */
1991 fp->nv[fp->nc].si = -1;
1992 fp->nv[fp->nc].ni = -1;
1993 fp->nv[fp->nc].nj = -1;
1994 fp->nv[fp->nc].l0 = l0;
1995 fp->nv[fp->nc].lc = lc;
2005 int li = 0, lic = 0;
2006 int lj = 0, ljc = 0;
2007 int lk = 0, lkc = 0;
2010 /* Find the side that most evenly splits the given lumps. */
2012 for (si = 0; si < fp->sc; si++)
2018 for (li = 0; li < lc; li++)
2019 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
2026 if ((d < sjd) || (d == sjd && o < sjo))
2034 /* Flag each lump with its position WRT the side. */
2036 for (li = 0; li < lc; li++)
2037 switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
2039 case +1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10; break;
2040 case 0: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20; break;
2041 case -1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40; break;
2044 /* Sort all lumps in the range by their flag values. */
2046 for (li = 1; li < lc; li++)
2047 for (lj = 0; lj < li; lj++)
2048 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
2052 l = fp->lv[l0 + li];
2053 fp->lv[l0 + li] = fp->lv[l0 + lj];
2054 fp->lv[l0 + lj] = l;
2057 /* Establish the in-front, on, and behind lump ranges. */
2063 for (i = lc - 1; i >= 0; i--)
2064 switch (fp->lv[l0 + i].fl & 0xf0)
2066 case 0x10: li = l0 + i; lic++; break;
2067 case 0x20: lj = l0 + i; ljc++; break;
2068 case 0x40: lk = l0 + i; lkc++; break;
2071 /* Add the lumps on the side to the node. */
2076 fp->nv[i].ni = node_node(fp, li, lic);
2078 fp->nv[i].nj = node_node(fp, lk, lkc);
2086 static void node_file(struct s_file *fp)
2090 /* Sort the lumps of each body into BSP nodes. */
2092 for (bi = 0; bi < fp->bc; bi++)
2093 fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
2096 /*---------------------------------------------------------------------------*/
2098 static void dump_file(struct s_file *p, const char *name)
2103 int m = p->rc + p->cc * 128 + (p->zc * p->jc + p->xc) * 32;
2105 /* Count the number of solid lumps. */
2107 for (i = 0; i < p->lc; i++)
2108 if ((p->lv[i].fl & 1) == 0)
2111 /* Count the number of visible geoms. */
2113 for (i = 0; i < p->bc; i++)
2115 for (j = 0; j < p->bv[i].lc; j++)
2116 m += p->lv[p->bv[i].l0 + j].gc;
2120 /* Count the total value of all coins. */
2122 for (i = 0; i < p->cc; i++)
2125 printf("%s (%d/%d/$%d)\n"
2126 " mtrl vert edge side texc"
2127 " geom lump path node body\n"
2128 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
2129 " coin item goal view jump"
2130 " swch bill ball char indx\n"
2131 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
2133 p->mc, p->vc, p->ec, p->sc, p->tc,
2134 p->gc, p->lc, p->pc, p->nc, p->bc,
2135 p->cc, p->hc, p->zc, p->wc, p->jc,
2136 p->xc, p->rc, p->uc, p->ac, p->ic);
2139 /* Skip the ugly SDL main substitution since we only need sdl_image. */
2144 int main(int argc, char *argv[])
2153 if (config_data_path(argv[2], NULL))
2155 strncpy(src, argv[1], MAXSTR);
2156 strncpy(dst, argv[1], MAXSTR);
2158 if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
2159 strcpy(dst + strlen(dst) - 4, ".sol");
2161 strcat(dst, ".sol");
2163 if ((fin = fopen(src, "r")))
2185 else fprintf(stderr, "Failure to establish data directory\n");
2187 else fprintf(stderr, "Usage: %s <map> [data]\n", argv[0]);