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! */
100 static int overflow(const char *s)
102 printf("%s overflow\n", s);
107 static int incm(struct s_file *fp)
109 return (fp->mc < MAXM) ? fp->mc++ : overflow("mtrl");
112 static int incv(struct s_file *fp)
114 return (fp->vc < MAXV) ? fp->vc++ : overflow("vert");
117 static int ince(struct s_file *fp)
119 return (fp->ec < MAXE) ? fp->ec++ : overflow("edge");
122 static int incs(struct s_file *fp)
124 return (fp->sc < MAXS) ? fp->sc++ : overflow("side");
127 static int inct(struct s_file *fp)
129 return (fp->tc < MAXT) ? fp->tc++ : overflow("texc");
132 static int incg(struct s_file *fp)
134 return (fp->gc < MAXG) ? fp->gc++ : overflow("geom");
137 static int incl(struct s_file *fp)
139 return (fp->lc < MAXL) ? fp->lc++ : overflow("lump");
142 static int incn(struct s_file *fp)
144 return (fp->nc < MAXN) ? fp->nc++ : overflow("node");
147 static int incp(struct s_file *fp)
149 return (fp->pc < MAXP) ? fp->pc++ : overflow("path");
152 static int incb(struct s_file *fp)
154 return (fp->bc < MAXB) ? fp->bc++ : overflow("body");
157 static int inch(struct s_file *fp)
159 return (fp->hc < MAXH) ? fp->hc++ : overflow("item");
162 static int incz(struct s_file *fp)
164 return (fp->zc < MAXZ) ? fp->zc++ : overflow("goal");
167 static int incj(struct s_file *fp)
169 return (fp->jc < MAXJ) ? fp->jc++ : overflow("jump");
172 static int incx(struct s_file *fp)
174 return (fp->xc < MAXX) ? fp->xc++ : overflow("swch");
177 static int incr(struct s_file *fp)
179 return (fp->rc < MAXR) ? fp->rc++ : overflow("bill");
182 static int incu(struct s_file *fp)
184 return (fp->uc < MAXU) ? fp->uc++ : overflow("ball");
187 static int incw(struct s_file *fp)
189 return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
192 static int inci(struct s_file *fp)
194 return (fp->ic < MAXI) ? fp->ic++ : overflow("indx");
197 static void init_file(struct s_file *fp)
219 fp->mv = (struct s_mtrl *) calloc(MAXM, sizeof (struct s_mtrl));
220 fp->vv = (struct s_vert *) calloc(MAXV, sizeof (struct s_vert));
221 fp->ev = (struct s_edge *) calloc(MAXE, sizeof (struct s_edge));
222 fp->sv = (struct s_side *) calloc(MAXS, sizeof (struct s_side));
223 fp->tv = (struct s_texc *) calloc(MAXT, sizeof (struct s_texc));
224 fp->gv = (struct s_geom *) calloc(MAXG, sizeof (struct s_geom));
225 fp->lv = (struct s_lump *) calloc(MAXL, sizeof (struct s_lump));
226 fp->nv = (struct s_node *) calloc(MAXN, sizeof (struct s_node));
227 fp->pv = (struct s_path *) calloc(MAXP, sizeof (struct s_path));
228 fp->bv = (struct s_body *) calloc(MAXB, sizeof (struct s_body));
229 fp->hv = (struct s_item *) calloc(MAXH, sizeof (struct s_item));
230 fp->zv = (struct s_goal *) calloc(MAXZ, sizeof (struct s_goal));
231 fp->jv = (struct s_jump *) calloc(MAXJ, sizeof (struct s_jump));
232 fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
233 fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
234 fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
235 fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
236 fp->av = (char *) calloc(MAXA, sizeof (char));
237 fp->iv = (int *) calloc(MAXI, sizeof (int));
240 /*---------------------------------------------------------------------------*/
243 * The following is a small symbol table data structure. Symbols and
244 * their integer values are collected in symv and valv. References
245 * and pointers to their unsatisfied integer values are collected in
246 * refv and pntv. The resolve procedure matches references to symbols
247 * and fills waiting ints with the proper values.
252 static char symv[MAXSYM][MAXSTR];
253 static int valv[MAXSYM];
255 static char refv[MAXSYM][MAXSTR];
256 static int *pntv[MAXSYM];
261 static void make_sym(const char *s, int v)
263 strncpy(symv[strc], s, MAXSTR - 1);
268 static void make_ref(const char *r, int *p)
270 strncpy(refv[refc], r, MAXSTR - 1);
275 static void resolve(void)
279 for (i = 0; i < refc; i++)
280 for (j = 0; j < strc; j++)
281 if (strncmp(refv[i], symv[j], MAXSTR) == 0)
283 *(pntv[i]) = valv[j];
288 /*---------------------------------------------------------------------------*/
291 * The following globals are used to cache target_positions. They are
292 * targeted by various entities and must be resolved in a second pass.
295 static float targ_p [MAXW][3];
296 static int targ_wi[MAXW];
297 static int targ_ji[MAXW];
300 static void targets(struct s_file *fp)
304 for (i = 0; i < fp->wc; i++)
305 v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
307 for (i = 0; i < fp->jc; i++)
308 v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
311 /*---------------------------------------------------------------------------*/
314 * The following code caches image sizes. Textures are referenced by
315 * name, but their sizes are necessary when computing texture
316 * coordinates. This code allows each file to be accessed only once
317 * regardless of the number of surfaces referring to it.
326 static struct _imagedata *imagedata = NULL;
327 static int image_n = 0;
328 static int image_alloc = 0;
330 #define IMAGE_REALLOC 32
332 static void free_imagedata()
338 for (i = 0; i < image_n; i++)
339 free(imagedata[i].s);
343 image_n = image_alloc = 0;
346 static int size_load(const char *file, int *w, int *h)
350 if ((S = IMG_Load(file)))
362 static void size_image(const char *name, int *w, int *h)
370 for (i = 0; i < image_n; i++)
371 if (strncmp(imagedata[i].s, name, MAXSTR) == 0)
382 strcpy(jpg, name); strcat(jpg, ".jpg");
383 strcpy(tga, name); strcat(tga, ".tga");
384 strcpy(png, name); strcat(png, ".png");
386 if (size_load(config_data(png), w, h) ||
387 size_load(config_data(tga), w, h) ||
388 size_load(config_data(jpg), w, h))
391 if (image_n + 1 >= image_alloc)
393 struct _imagedata *tmp =
394 (struct _imagedata *) malloc(sizeof(struct _imagedata) * (image_alloc + IMAGE_REALLOC));
397 printf("malloc error\n");
402 (void) memcpy(tmp, imagedata, sizeof(struct _imagedata) * image_alloc);
406 image_alloc += IMAGE_REALLOC;
409 imagedata[image_n].s = (char *) calloc(strlen(name) + 1, 1);
410 imagedata[image_n].w = *w;
411 imagedata[image_n].h = *h;
412 strcpy(imagedata[image_n].s, name);
418 /*---------------------------------------------------------------------------*/
420 /* Read the given material file, adding a new material to the solid. */
422 static int read_mtrl(struct s_file *fp, const char *name)
428 for (mi = 0; mi < fp->mc; mi++)
429 if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
432 mp = fp->mv + incm(fp);
434 strncpy(mp->f, name, PATHMAX - 1);
436 mp->a[0] = mp->a[1] = mp->a[2] = mp->a[3] = 1.0f;
437 mp->d[0] = mp->d[1] = mp->d[2] = mp->d[3] = 1.0f;
438 mp->s[0] = mp->s[1] = mp->s[2] = mp->s[3] = 1.0f;
439 mp->e[0] = mp->e[1] = mp->e[2] = mp->e[3] = 1.0f;
443 if ((fin = fopen(config_data(name), "r")))
451 mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
452 mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
453 mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
454 mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
462 /*---------------------------------------------------------------------------*/
465 * All bodies with an associated path are assumed to be positioned at
466 * the beginning of that path. These bodies must be moved to the
467 * origin in order for their path transforms to behave correctly.
468 * This is how we get away with defining func_trains with no origin
472 static void move_side(struct s_side *sp, const float p[3])
474 sp->d -= v_dot(sp->n, p);
477 static void move_vert(struct s_vert *vp, const float p[3])
479 v_sub(vp->p, vp->p, p);
482 static void move_lump(struct s_file *fp,
483 struct s_lump *lp, const float p[3])
487 for (i = 0; i < lp->sc; i++)
488 move_side(fp->sv + fp->iv[lp->s0 + i], p);
489 for (i = 0; i < lp->vc; i++)
490 move_vert(fp->vv + fp->iv[lp->v0 + i], p);
493 static void move_body(struct s_file *fp,
498 for (i = 0; i < bp->lc; i++)
499 move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
502 static void move_file(struct s_file *fp)
506 for (i = 0; i < fp->bc; i++)
507 if (fp->bv[i].pi >= 0)
508 move_body(fp, fp->bv + i);
511 /*---------------------------------------------------------------------------*/
514 * This is a basic OBJ loader. It is by no means fully compliant with
515 * the OBJ specification, but it works well with the output of
516 * Wings3D. All faces must be triangles and all vertices must include
517 * normals and texture coordinates. Material names are taken to be
518 * references to Neverball materials, rather than MTL definitions.
521 static void read_vt(struct s_file *fp, const char *line)
523 struct s_texc *tp = fp->tv + inct(fp);
525 sscanf(line, "%f %f", tp->u, tp->u + 1);
528 static void read_vn(struct s_file *fp, const char *line)
530 struct s_side *sp = fp->sv + incs(fp);
532 sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
535 static void read_v(struct s_file *fp, const char *line)
537 struct s_vert *vp = fp->vv + incv(fp);
539 sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
542 static void read_f(struct s_file *fp, const char *line,
543 int v0, int t0, int s0, int mi)
545 struct s_geom *gp = fp->gv + incg(fp);
550 sscanf(line, "%d%c%d%c%d %d%c%d%c%d %d%c%d%c%d",
551 &gp->vi, &c1, &gp->ti, &c2, &gp->si,
552 &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
553 &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
568 static void read_obj(struct s_file *fp, const char *name)
579 if ((fin = fopen(config_data(name), "r")))
581 while (fgets(line, MAXSTR, fin))
583 if (strncmp(line, "usemtl", 6) == 0)
585 sscanf(line + 6, "%s", mtrl);
586 mi = read_mtrl(fp, mtrl);
589 else if (strncmp(line, "f", 1) == 0)
591 if (fp->mv[mi].d[3] > 0)
592 read_f(fp, line + 1, v0, t0, s0, mi);
595 else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
596 else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
597 else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
603 /*---------------------------------------------------------------------------*/
605 static float plane_d[MAXS];
606 static float plane_n[MAXS][3];
607 static float plane_p[MAXS][3];
608 static float plane_u[MAXS][3];
609 static float plane_v[MAXS][3];
610 static int plane_f[MAXS];
611 static int plane_m[MAXS];
613 static void make_plane(int pi, int x0, int y0, int z0,
614 int x1, int y1, int z1,
615 int x2, int y2, int z2,
616 int tu, int tv, int r,
617 float su, float sv, int fl, const char *s)
619 static const float base[6][3][3] = {
620 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
621 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
622 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
623 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
624 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
625 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
629 float p0[3], p1[3], p2[3];
630 float u[3], v[3], p[3];
635 size_image(s, &w, &h);
637 plane_f[pi] = fl ? L_DETAIL : 0;
639 p0[0] = +(float) x0 / SCALE;
640 p0[1] = +(float) z0 / SCALE;
641 p0[2] = -(float) y0 / SCALE;
643 p1[0] = +(float) x1 / SCALE;
644 p1[1] = +(float) z1 / SCALE;
645 p1[2] = -(float) y1 / SCALE;
647 p2[0] = +(float) x2 / SCALE;
648 p2[1] = +(float) z2 / SCALE;
649 p2[2] = -(float) y2 / SCALE;
654 v_crs(plane_n[pi], u, v);
655 v_nrm(plane_n[pi], plane_n[pi]);
657 plane_d[pi] = v_dot(plane_n[pi], p1);
659 for (i = 0; i < 6; i++)
660 if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
670 m_rot(R, base[n][0], V_RAD(r));
672 v_mad(p, p, base[n][1], su * tu / SCALE);
673 v_mad(p, p, base[n][2], sv * tv / SCALE);
675 m_vxfm(plane_u[pi], R, base[n][1]);
676 m_vxfm(plane_v[pi], R, base[n][2]);
677 m_vxfm(plane_p[pi], R, p);
679 v_scl(plane_u[pi], plane_u[pi], 64.f / w);
680 v_scl(plane_v[pi], plane_v[pi], 64.f / h);
682 v_scl(plane_u[pi], plane_u[pi], 1.f / su);
683 v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
686 /*---------------------------------------------------------------------------*/
695 static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
699 if (fgets(buf, MAXSTR, fin))
709 /* Scan the beginning or end of a block. */
711 if (buf[0] == '{') return T_BEG;
712 if (buf[0] == '}') return T_END;
714 /* Scan a key-value pair. */
718 strcpy(key, strtok(buf, "\""));
719 (void) strtok(NULL, "\"");
720 strcpy(val, strtok(NULL, "\""));
731 "%s %d %d %d %f %f %d",
732 &c, &x0, &y0, &z0, &c,
733 &c, &x1, &y1, &z1, &c,
734 &c, &x2, &y2, &z2, &c,
735 key, &tu, &tv, &r, &su, &sv, &fl) == 22)
737 make_plane(pi, x0, y0, z0,
740 tu, tv, r, su, sv, fl, key);
744 /* If it's not recognized, it must be uninteresting. */
751 /*---------------------------------------------------------------------------*/
753 /* Parse a lump from the given file and add it to the solid. */
755 static void read_lump(struct s_file *fp, FILE *fin)
761 struct s_lump *lp = fp->lv + incl(fp);
765 while ((t = map_token(fin, fp->sc, k, v)))
769 fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
770 fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
771 fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
772 fp->sv[fp->sc].d = plane_d[fp->sc];
774 plane_m[fp->sc] = read_mtrl(fp, k);
776 fp->iv[fp->ic] = fp->sc;
786 /*---------------------------------------------------------------------------*/
788 static void make_path(struct s_file *fp,
790 char v[][MAXSTR], int c)
792 int i, pi = incp(fp);
794 struct s_path *pp = fp->pv + pi;
803 for (i = 0; i < c; i++)
805 if (strcmp(k[i], "targetname") == 0)
808 if (strcmp(k[i], "target") == 0)
809 make_ref(v[i], &pp->pi);
811 if (strcmp(k[i], "state") == 0)
814 if (strcmp(k[i], "speed") == 0)
815 sscanf(v[i], "%f", &pp->t);
817 if (strcmp(k[i], "origin") == 0)
819 int x = 0, y = 0, z = 0;
821 sscanf(v[i], "%d %d %d", &x, &y, &z);
823 pp->p[0] = +(float) x / SCALE;
824 pp->p[1] = +(float) z / SCALE;
825 pp->p[2] = -(float) y / SCALE;
830 static void make_body(struct s_file *fp,
832 char v[][MAXSTR], int c, int l0)
834 int i, bi = incb(fp);
845 struct s_body *bp = fp->bv + bi;
851 for (i = 0; i < c; i++)
853 if (strcmp(k[i], "targetname") == 0)
856 else if (strcmp(k[i], "target") == 0)
857 make_ref(v[i], &bp->pi);
859 else if (strcmp(k[i], "model") == 0)
862 else if (strcmp(k[i], "origin") == 0)
863 sscanf(v[i], "%d %d %d", &x, &y, &z);
865 else if (strcmp(k[i], "classname") != 0)
867 /* Considers other strings as metadata */
868 strcat(fp->av, k[i]);
870 strcat(fp->av, v[i]);
871 strcat(fp->av, "\n");
872 fp->ac += (int) (strlen(v[i]) + (strlen(k[i])) + 2);
877 bp->lc = fp->lc - l0;
879 bp->gc = fp->gc - g0;
881 for (i = 0; i < bp->gc; i++)
882 fp->iv[inci(fp)] = g0++;
884 p[0] = +(float) x / SCALE;
885 p[1] = +(float) z / SCALE;
886 p[2] = -(float) y / SCALE;
888 for (i = v0; i < fp->vc; i++)
889 v_add(fp->vv[i].p, fp->vv[i].p, p);
892 static void make_item(struct s_file *fp,
894 char v[][MAXSTR], int c)
896 int i, hi = inch(fp);
898 struct s_item *hp = fp->hv + hi;
907 for (i = 0; i < c; i++)
909 if (strcmp(k[i], "classname") == 0)
911 if (strcmp(v[i], "light") == 0)
913 else if (strcmp(v[i], "item_health_large") == 0)
915 else if (strcmp(v[i], "item_health_small") == 0)
919 if (strcmp(k[i], "light") == 0)
920 sscanf(v[i], "%d", &hp->n);
922 if (strcmp(k[i], "origin") == 0)
924 int x = 0, y = 0, z = 0;
926 sscanf(v[i], "%d %d %d", &x, &y, &z);
928 hp->p[0] = +(float) x / SCALE;
929 hp->p[1] = +(float) z / SCALE;
930 hp->p[2] = -(float) y / SCALE;
935 static void make_bill(struct s_file *fp,
937 char v[][MAXSTR], int c)
939 int i, ri = incr(fp);
941 struct s_bill *rp = fp->rv + ri;
943 memset(rp, 0, sizeof (struct s_bill));
946 for (i = 0; i < c; i++)
948 if (strcmp(k[i], "width") == 0)
949 sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
950 if (strcmp(k[i], "height") == 0)
951 sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
953 if (strcmp(k[i], "xrot") == 0)
954 sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
955 if (strcmp(k[i], "yrot") == 0)
956 sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
957 if (strcmp(k[i], "zrot") == 0)
958 sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
960 if (strcmp(k[i], "time") == 0)
961 sscanf(v[i], "%f", &rp->t);
962 if (strcmp(k[i], "dist") == 0)
963 sscanf(v[i], "%f", &rp->d);
964 if (strcmp(k[i], "flag") == 0)
965 sscanf(v[i], "%d", &rp->fl);
967 if (strcmp(k[i], "image") == 0)
969 rp->mi = read_mtrl(fp, v[i]);
970 fp->mv[rp->mi].fl |= M_CLAMPED;
973 if (strcmp(k[i], "origin") == 0)
975 int x = 0, y = 0, z = 0;
978 sscanf(v[i], "%d %d %d", &x, &y, &z);
980 p[0] = +(float) x / SCALE;
981 p[1] = +(float) z / SCALE;
982 p[2] = -(float) y / SCALE;
985 rp->rx[0] = V_DEG(fatan2f(+p[1], rp->d));
986 rp->ry[0] = V_DEG(fatan2f(+p[0], -p[2]));
990 if (rp->fl & B_ADDITIVE)
991 fp->mv[rp->mi].fl |= M_ADDITIVE;
994 static void make_goal(struct s_file *fp,
996 char v[][MAXSTR], int c)
998 int i, zi = incz(fp);
1000 struct s_goal *zp = fp->zv + zi;
1009 for (i = 0; i < c; i++)
1011 if (strcmp(k[i], "radius") == 0)
1012 sscanf(v[i], "%f", &zp->r);
1013 if (strcmp(k[i], "skip") == 0)
1014 sscanf(v[i], "%d", &zp->s);
1015 if (strcmp(k[i], "special") == 0)
1016 sscanf(v[i], "%d", &zp->c);
1018 if (strcmp(k[i], "origin") == 0)
1020 int x = 0, y = 0, z = 0;
1022 sscanf(v[i], "%d %d %d", &x, &y, &z);
1024 zp->p[0] = +(float) (x) / SCALE;
1025 zp->p[1] = +(float) (z - 24) / SCALE;
1026 zp->p[2] = -(float) (y) / SCALE;
1031 static void make_view(struct s_file *fp,
1033 char v[][MAXSTR], int c)
1035 int i, wi = incw(fp);
1037 struct s_view *wp = fp->wv + wi;
1046 for (i = 0; i < c; i++)
1048 if (strcmp(k[i], "target") == 0)
1049 make_ref(v[i], targ_wi + wi);
1051 if (strcmp(k[i], "origin") == 0)
1053 int x = 0, y = 0, z = 0;
1055 sscanf(v[i], "%d %d %d", &x, &y, &z);
1057 wp->p[0] = +(float) x / SCALE;
1058 wp->p[1] = +(float) z / SCALE;
1059 wp->p[2] = -(float) y / SCALE;
1064 static void make_jump(struct s_file *fp,
1066 char v[][MAXSTR], int c)
1068 int i, ji = incj(fp);
1070 struct s_jump *jp = fp->jv + ji;
1080 for (i = 0; i < c; i++)
1082 if (strcmp(k[i], "radius") == 0)
1083 sscanf(v[i], "%f", &jp->r);
1085 if (strcmp(k[i], "target") == 0)
1086 make_ref(v[i], targ_ji + ji);
1088 if (strcmp(k[i], "origin") == 0)
1090 int x = 0, y = 0, z = 0;
1092 sscanf(v[i], "%d %d %d", &x, &y, &z);
1094 jp->p[0] = +(float) x / SCALE;
1095 jp->p[1] = +(float) z / SCALE;
1096 jp->p[2] = -(float) y / SCALE;
1101 static void make_swch(struct s_file *fp,
1103 char v[][MAXSTR], int c)
1105 int i, xi = incx(fp);
1107 struct s_swch *xp = fp->xv + xi;
1120 for (i = 0; i < c; i++)
1122 if (strcmp(k[i], "radius") == 0)
1123 sscanf(v[i], "%f", &xp->r);
1125 if (strcmp(k[i], "target") == 0)
1126 make_ref(v[i], &xp->pi);
1128 if (strcmp(k[i], "timer") == 0)
1129 sscanf(v[i], "%f", &xp->t0);
1131 if (strcmp(k[i], "state") == 0)
1134 if (strcmp(k[i], "invisible") == 0)
1137 if (strcmp(k[i], "origin") == 0)
1139 int x = 0, y = 0, z = 0;
1141 sscanf(v[i], "%d %d %d", &x, &y, &z);
1143 xp->p[0] = +(float) x / SCALE;
1144 xp->p[1] = +(float) z / SCALE;
1145 xp->p[2] = -(float) y / SCALE;
1150 static void make_targ(struct s_file *fp,
1152 char v[][MAXSTR], int c)
1156 targ_p[targ_n][0] = 0.f;
1157 targ_p[targ_n][1] = 0.f;
1158 targ_p[targ_n][3] = 0.f;
1160 for (i = 0; i < c; i++)
1162 if (strcmp(k[i], "targetname") == 0)
1163 make_sym(v[i], targ_n);
1165 if (strcmp(k[i], "origin") == 0)
1167 int x = 0, y = 0, z = 0;
1169 sscanf(v[i], "%d %d %d", &x, &y, &z);
1171 targ_p[targ_n][0] = +(float) x / SCALE;
1172 targ_p[targ_n][1] = +(float) z / SCALE;
1173 targ_p[targ_n][2] = -(float) y / SCALE;
1180 static void make_ball(struct s_file *fp,
1182 char v[][MAXSTR], int c)
1184 int i, ui = incu(fp);
1186 struct s_ball *up = fp->uv + ui;
1210 for (i = 0; i < c; i++)
1212 if (strcmp(k[i], "radius") == 0)
1213 sscanf(v[i], "%f", &up->r);
1215 if (strcmp(k[i], "origin") == 0)
1217 int x = 0, y = 0, z = 0;
1219 sscanf(v[i], "%d %d %d", &x, &y, &z);
1221 up->p[0] = +(float) (x) / SCALE;
1222 up->p[1] = +(float) (z - 24) / SCALE;
1223 up->p[2] = -(float) (y) / SCALE;
1227 up->p[1] += up->r + SMALL;
1230 /*---------------------------------------------------------------------------*/
1232 static void read_ent(struct s_file *fp, FILE *fin)
1234 char k[MAXKEY][MAXSTR];
1235 char v[MAXKEY][MAXSTR];
1236 int t, i = 0, c = 0;
1240 while ((t = map_token(fin, -1, k[c], v[c])))
1244 if (strcmp(k[c], "classname") == 0)
1248 if (t == T_BEG) read_lump(fp, fin);
1249 if (t == T_END) break;
1252 if (!strcmp(v[i], "light")) make_item(fp, k, v, c);
1253 if (!strcmp(v[i], "item_health_large")) make_item(fp, k, v, c);
1254 if (!strcmp(v[i], "item_health_small")) make_item(fp, k, v, c);
1255 if (!strcmp(v[i], "info_camp")) make_swch(fp, k, v, c);
1256 if (!strcmp(v[i], "info_null")) make_bill(fp, k, v, c);
1257 if (!strcmp(v[i], "path_corner")) make_path(fp, k, v, c);
1258 if (!strcmp(v[i], "info_player_start")) make_ball(fp, k, v, c);
1259 if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1260 if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
1261 if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
1262 if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
1263 if (!strcmp(v[i], "worldspawn")) make_body(fp, k, v, c, l0);
1264 if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
1265 if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
1268 static void read_map(struct s_file *fp, FILE *fin)
1274 while ((t = map_token(fin, -1, k, v)))
1279 /*---------------------------------------------------------------------------*/
1281 /* Test the location of a point with respect to a side plane. */
1283 static int fore_side(const float p[3], const struct s_side *sp)
1285 return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1288 static int on_side(const float p[3], const struct s_side *sp)
1290 float d = v_dot(p, sp->n) - sp->d;
1292 return (-SMALL < d && d < +SMALL) ? 1 : 0;
1295 /*---------------------------------------------------------------------------*/
1297 * Confirm that the addition of a vert would not result in degenerate
1301 static int ok_vert(const struct s_file *fp,
1302 const struct s_lump *lp, const float p[3])
1307 for (i = 0; i < lp->vc; i++)
1309 float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1313 if (v_len(r) < SMALL)
1319 /*---------------------------------------------------------------------------*/
1322 * The following functions take the set of planes defining a lump and
1323 * find the verts, edges, and geoms that describe its boundaries. To
1324 * do this, they first find the verts, and then search these verts for
1325 * valid edges and geoms. It may be more efficient to compute edges
1326 * and geoms directly by clipping down infinite line segments and
1327 * planes, but this would be more complex and prone to numerical
1332 * Given 3 side planes, compute the point of intersection, if any.
1333 * Confirm that this point falls within the current lump, and that it
1334 * is unique. Add it as a vert of the solid.
1336 static void clip_vert(struct s_file *fp,
1337 struct s_lump *lp, int si, int sj, int sk)
1339 float M[16], X[16], I[16];
1343 d[0] = fp->sv[si].d;
1344 d[1] = fp->sv[sj].d;
1345 d[2] = fp->sv[sk].d;
1347 m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1354 for (i = 0; i < lp->sc; i++)
1356 int si = fp->iv[lp->s0 + i];
1358 if (fore_side(p, fp->sv + si))
1362 if (ok_vert(fp, lp, p))
1364 v_cpy(fp->vv[fp->vc].p, p);
1366 fp->iv[fp->ic] = fp->vc;
1375 * Given two side planes, find an edge along their intersection by
1376 * finding a pair of vertices that fall on both planes. Add it to the
1379 static void clip_edge(struct s_file *fp,
1380 struct s_lump *lp, int si, int sj)
1384 for (i = 1; i < lp->vc; i++)
1385 for (j = 0; j < i; j++)
1387 int vi = fp->iv[lp->v0 + i];
1388 int vj = fp->iv[lp->v0 + j];
1390 if (on_side(fp->vv[vi].p, fp->sv + si) &&
1391 on_side(fp->vv[vj].p, fp->sv + si) &&
1392 on_side(fp->vv[vi].p, fp->sv + sj) &&
1393 on_side(fp->vv[vj].p, fp->sv + sj))
1395 fp->ev[fp->ec].vi = vi;
1396 fp->ev[fp->ec].vj = vj;
1398 fp->iv[fp->ic] = fp->ec;
1408 * Find all verts that lie on the given side of the lump. Sort these
1409 * verts to have a counter-clockwise winding about the plane normal.
1410 * Create geoms to tessellate the resulting convex polygon.
1412 static void clip_geom(struct s_file *fp,
1413 struct s_lump *lp, int si)
1415 int m[256], t[256], d, i, j, n = 0;
1420 struct s_side *sp = fp->sv + si;
1424 for (i = 0; i < lp->vc; i++)
1426 int vi = fp->iv[lp->v0 + i];
1428 if (on_side(fp->vv[vi].p, sp))
1433 v_add(v, fp->vv[vi].p, plane_p[si]);
1435 fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1436 fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1444 for (i = 1; i < n; i++)
1445 for (j = i + 1; j < n; j++)
1447 v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1448 v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1451 if (v_dot(w, sp->n) < 0.f)
1465 for (i = 0; i < n - 2; i++)
1467 fp->gv[fp->gc].mi = plane_m[si];
1469 fp->gv[fp->gc].ti = t[0];
1470 fp->gv[fp->gc].tj = t[i + 1];
1471 fp->gv[fp->gc].tk = t[i + 2];
1473 fp->gv[fp->gc].si = si;
1474 fp->gv[fp->gc].sj = si;
1475 fp->gv[fp->gc].sk = si;
1477 fp->gv[fp->gc].vi = m[0];
1478 fp->gv[fp->gc].vj = m[i + 1];
1479 fp->gv[fp->gc].vk = m[i + 2];
1481 fp->iv[fp->ic] = fp->gc;
1489 * Iterate the sides of the lump, attempting to generate a new vert for
1490 * each trio of planes, a new edge for each pair of planes, and a new
1491 * set of geom for each visible plane.
1493 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1500 for (i = 2; i < lp->sc; i++)
1501 for (j = 1; j < i; j++)
1502 for (k = 0; k < j; k++)
1506 fp->iv[lp->s0 + k]);
1511 for (i = 1; i < lp->sc; i++)
1512 for (j = 0; j < i; j++)
1515 fp->iv[lp->s0 + j]);
1520 for (i = 0; i < lp->sc; i++)
1521 if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0)
1523 fp->iv[lp->s0 + i]);
1525 for (i = 0; i < lp->sc; i++)
1526 if (plane_f[fp->iv[lp->s0 + i]])
1530 static void clip_file(struct s_file *fp)
1534 for (i = 0; i < fp->lc; i++)
1535 clip_lump(fp, fp->lv + i);
1538 /*---------------------------------------------------------------------------*/
1541 * For each body element type, determine if element 'p' is equivalent
1542 * to element 'q'. This is more than a simple memory compare. It
1543 * effectively snaps mtrls and verts together, and may reverse the
1544 * winding of an edge or a geom. This is done in order to maximize
1545 * the number of elements that can be eliminated.
1548 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1550 if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1551 if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1552 if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1553 if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1555 if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1556 if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1557 if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1558 if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1560 if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1561 if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1562 if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1563 if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1565 if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1566 if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1567 if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1568 if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1570 if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1572 if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1577 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1579 if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1580 if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1581 if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1586 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1588 if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1589 if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1594 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1596 if (fabs(sp->d - sq->d) > SMALL) return 0;
1597 if (v_dot(sp->n, sq->n) < 0.9999) return 0;
1602 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1604 if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1605 if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1610 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1612 if (gp->mi != gq->mi) return 0;
1614 if (gp->ti != gq->ti) return 0;
1615 if (gp->si != gq->si) return 0;
1616 if (gp->vi != gq->vi) return 0;
1618 if (gp->tj != gq->tj) return 0;
1619 if (gp->sj != gq->sj) return 0;
1620 if (gp->vj != gq->vj) return 0;
1622 if (gp->tk != gq->tk) return 0;
1623 if (gp->sk != gq->sk) return 0;
1624 if (gp->vk != gq->vk) return 0;
1629 /*---------------------------------------------------------------------------*/
1632 * For each file element type, replace all references to element 'i'
1633 * with a reference to element 'j'. These are used when optimizing
1634 * and sorting the file.
1637 static void swap_mtrl(struct s_file *fp, int mi, int mj)
1641 for (i = 0; i < fp->gc; i++)
1642 if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1643 for (i = 0; i < fp->rc; i++)
1644 if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1647 static void swap_vert(struct s_file *fp, int vi, int vj)
1651 for (i = 0; i < fp->ec; i++)
1653 if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1654 if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1657 for (i = 0; i < fp->gc; i++)
1659 if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1660 if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1661 if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1664 for (i = 0; i < fp->lc; i++)
1665 for (j = 0; j < fp->lv[i].vc; j++)
1666 if (fp->iv[fp->lv[i].v0 + j] == vi)
1667 fp->iv[fp->lv[i].v0 + j] = vj;
1670 static void swap_edge(struct s_file *fp, int ei, int ej)
1674 for (i = 0; i < fp->lc; i++)
1675 for (j = 0; j < fp->lv[i].ec; j++)
1676 if (fp->iv[fp->lv[i].e0 + j] == ei)
1677 fp->iv[fp->lv[i].e0 + j] = ej;
1680 static void swap_side(struct s_file *fp, int si, int sj)
1684 for (i = 0; i < fp->gc; i++)
1686 if (fp->gv[i].si == si) fp->gv[i].si = sj;
1687 if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1688 if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1690 for (i = 0; i < fp->nc; i++)
1691 if (fp->nv[i].si == si) fp->nv[i].si = sj;
1693 for (i = 0; i < fp->lc; i++)
1694 for (j = 0; j < fp->lv[i].sc; j++)
1695 if (fp->iv[fp->lv[i].s0 + j] == si)
1696 fp->iv[fp->lv[i].s0 + j] = sj;
1699 static void swap_texc(struct s_file *fp, int ti, int tj)
1703 for (i = 0; i < fp->gc; i++)
1705 if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1706 if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1707 if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1712 static void swap_geom(struct s_file *fp, int gi, int gj)
1716 for (i = 0; i < fp->lc; i++)
1717 for (j = 0; j < fp->lv[i].gc; j++)
1718 if (fp->iv[fp->lv[i].g0 + j] == gi)
1719 fp->iv[fp->lv[i].g0 + j] = gj;
1721 for (i = 0; i < fp->bc; i++)
1722 for (j = 0; j < fp->bv[i].gc; j++)
1723 if (fp->iv[fp->bv[i].g0 + j] == gi)
1724 fp->iv[fp->bv[i].g0 + j] = gj;
1727 /*---------------------------------------------------------------------------*/
1729 static void uniq_mtrl(struct s_file *fp)
1733 for (i = 0; i < fp->mc; i++)
1735 for (j = 0; j < k; j++)
1736 if (comp_mtrl(fp->mv + i, fp->mv + j))
1738 swap_mtrl(fp, i, j);
1746 fp->mv[k] = fp->mv[i];
1747 swap_mtrl(fp, i, k);
1756 static void uniq_vert(struct s_file *fp)
1760 for (i = 0; i < fp->vc; i++)
1762 for (j = 0; j < k; j++)
1763 if (comp_vert(fp->vv + i, fp->vv + j))
1765 swap_vert(fp, i, j);
1773 fp->vv[k] = fp->vv[i];
1774 swap_vert(fp, i, k);
1783 static void uniq_edge(struct s_file *fp)
1787 for (i = 0; i < fp->ec; i++)
1789 for (j = 0; j < k; j++)
1790 if (comp_edge(fp->ev + i, fp->ev + j))
1792 swap_edge(fp, i, j);
1800 fp->ev[k] = fp->ev[i];
1801 swap_edge(fp, i, k);
1810 static void uniq_geom(struct s_file *fp)
1814 for (i = 0; i < fp->gc; i++)
1816 for (j = 0; j < k; j++)
1817 if (comp_geom(fp->gv + i, fp->gv + j))
1819 swap_geom(fp, i, j);
1827 fp->gv[k] = fp->gv[i];
1828 swap_geom(fp, i, k);
1837 static void uniq_texc(struct s_file *fp)
1841 for (i = 0; i < fp->tc; i++)
1843 for (j = 0; j < k; j++)
1844 if (comp_texc(fp->tv + i, fp->tv + j))
1846 swap_texc(fp, i, j);
1854 fp->tv[k] = fp->tv[i];
1855 swap_texc(fp, i, k);
1864 static void uniq_side(struct s_file *fp)
1868 for (i = 0; i < fp->sc; i++)
1870 for (j = 0; j < k; j++)
1871 if (comp_side(fp->sv + i, fp->sv + j))
1873 swap_side(fp, i, j);
1881 fp->sv[k] = fp->sv[i];
1882 swap_side(fp, i, k);
1891 static void uniq_file(struct s_file *fp)
1901 /*---------------------------------------------------------------------------*/
1903 static void sort_file(struct s_file *fp)
1907 /* Sort billboards farthest to nearest. */
1909 for (i = 0; i < fp->rc; i++)
1910 for (j = i + 1; j < fp->rc; j++)
1911 if (fp->rv[j].d > fp->rv[i].d)
1916 fp->rv[i] = fp->rv[j];
1920 /* Ensure the first vertex is the lowest. */
1922 for (i = 0; i < fp->vc; i++)
1923 if (fp->vv[0].p[1] > fp->vv[i].p[1])
1928 fp->vv[0] = fp->vv[i];
1931 swap_vert(fp, 0, -1);
1932 swap_vert(fp, i, 0);
1933 swap_vert(fp, -1, i);
1937 /*---------------------------------------------------------------------------*/
1939 static int test_lump_side(const struct s_file *fp,
1940 const struct s_lump *lp,
1941 const struct s_side *sp)
1949 /* If the given side is part of the given lump, then the lump is behind. */
1951 for (si = 0; si < lp->sc; si++)
1952 if (fp->sv + fp->iv[lp->s0 + si] == sp)
1955 /* Check if each lump vertex is in front of, behind, on the side. */
1957 for (vi = 0; vi < lp->vc; vi++)
1959 float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
1965 /* If no verts are behind, the lump is in front, and vice versa. */
1967 if (f > 0 && b == 0) return +1;
1968 if (b > 0 && f == 0) return -1;
1970 /* Else, the lump crosses the side. */
1975 static int node_node(struct s_file *fp, int l0, int lc)
1979 /* Base case. Dump all given lumps into a leaf node. */
1981 fp->nv[fp->nc].si = -1;
1982 fp->nv[fp->nc].ni = -1;
1983 fp->nv[fp->nc].nj = -1;
1984 fp->nv[fp->nc].l0 = l0;
1985 fp->nv[fp->nc].lc = lc;
1995 int li = 0, lic = 0;
1996 int lj = 0, ljc = 0;
1997 int lk = 0, lkc = 0;
2000 /* Find the side that most evenly splits the given lumps. */
2002 for (si = 0; si < fp->sc; si++)
2008 for (li = 0; li < lc; li++)
2009 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
2016 if ((d < sjd) || (d == sjd && o < sjo))
2024 /* Flag each lump with its position WRT the side. */
2026 for (li = 0; li < lc; li++)
2027 switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
2029 case +1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10; break;
2030 case 0: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20; break;
2031 case -1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40; break;
2034 /* Sort all lumps in the range by their flag values. */
2036 for (li = 1; li < lc; li++)
2037 for (lj = 0; lj < li; lj++)
2038 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
2042 l = fp->lv[l0 + li];
2043 fp->lv[l0 + li] = fp->lv[l0 + lj];
2044 fp->lv[l0 + lj] = l;
2047 /* Establish the in-front, on, and behind lump ranges. */
2053 for (i = lc - 1; i >= 0; i--)
2054 switch (fp->lv[l0 + i].fl & 0xf0)
2056 case 0x10: li = l0 + i; lic++; break;
2057 case 0x20: lj = l0 + i; ljc++; break;
2058 case 0x40: lk = l0 + i; lkc++; break;
2061 /* Add the lumps on the side to the node. */
2066 fp->nv[i].ni = node_node(fp, li, lic);
2068 fp->nv[i].nj = node_node(fp, lk, lkc);
2076 static void node_file(struct s_file *fp)
2080 /* Sort the lumps of each body into BSP nodes. */
2082 for (bi = 0; bi < fp->bc; bi++)
2083 fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
2086 /*---------------------------------------------------------------------------*/
2088 static void dump_file(struct s_file *p, const char *name)
2090 /* FIXME: Count visible geoms.
2092 * I'm afraid items break this (not sure though) so leaving it out.
2102 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)
2112 /* Count the number of visible geoms. */
2114 for (i = 0; i < p->bc; i++)
2116 for (j = 0; j < p->bv[i].lc; j++)
2117 m += p->lv[p->bv[i].l0 + j].gc;
2122 /* Count the total value of all coins. */
2124 for (i = 0; i < p->hc; i++)
2125 if (p->hv[i].t == ITEM_COIN)
2129 printf("%s (%d/%d/$%d)\n"
2131 printf("%s (%d/$%d)\n"
2132 " mtrl vert edge side texc"
2133 " geom lump path node body\n"
2134 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
2135 " item goal view jump swch"
2136 " bill ball char indx\n"
2137 "%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
2142 p->mc, p->vc, p->ec, p->sc, p->tc,
2143 p->gc, p->lc, p->pc, p->nc, p->bc,
2144 p->hc, p->zc, p->wc, p->jc, p->xc,
2145 p->rc, p->uc, p->ac, p->ic);
2148 /* Skip the ugly SDL main substitution since we only need sdl_image. */
2153 int main(int argc, char *argv[])
2162 if (config_data_path(argv[2], NULL))
2164 strncpy(src, argv[1], MAXSTR);
2165 strncpy(dst, argv[1], MAXSTR);
2167 if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
2168 strcpy(dst + strlen(dst) - 4, ".sol");
2170 strcat(dst, ".sol");
2172 if ((fin = fopen(src, "r")))
2194 else fprintf(stderr, "Failure to establish data directory\n");
2196 else fprintf(stderr, "Usage: %s <map> [data]\n", argv[0]);