2 * Copyright (C) 2003 Robert Kooima
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
15 /*---------------------------------------------------------------------------*/
24 #include "base_image.h"
25 #include "base_config.h"
33 * The overall design of this map converter is very stupid, but very
34 * simple. It begins by assuming that every mtrl, vert, edge, side,
35 * and texc in the map is unique. It then makes an optimizing pass
36 * that discards redundant information. The result is optimal, though
37 * the process is terribly inefficient.
40 /*---------------------------------------------------------------------------*/
42 static int debug_output = 0;
44 /*---------------------------------------------------------------------------*/
46 /* Ohhhh... arbitrary! */
69 static int overflow(const char *s)
71 printf("%s overflow\n", s);
76 static int incm(struct s_file *fp)
78 return (fp->mc < MAXM) ? fp->mc++ : overflow("mtrl");
81 static int incv(struct s_file *fp)
83 return (fp->vc < MAXV) ? fp->vc++ : overflow("vert");
86 static int ince(struct s_file *fp)
88 return (fp->ec < MAXE) ? fp->ec++ : overflow("edge");
91 static int incs(struct s_file *fp)
93 return (fp->sc < MAXS) ? fp->sc++ : overflow("side");
96 static int inct(struct s_file *fp)
98 return (fp->tc < MAXT) ? fp->tc++ : overflow("texc");
101 static int incg(struct s_file *fp)
103 return (fp->gc < MAXG) ? fp->gc++ : overflow("geom");
106 static int incl(struct s_file *fp)
108 return (fp->lc < MAXL) ? fp->lc++ : overflow("lump");
111 static int incn(struct s_file *fp)
113 return (fp->nc < MAXN) ? fp->nc++ : overflow("node");
116 static int incp(struct s_file *fp)
118 return (fp->pc < MAXP) ? fp->pc++ : overflow("path");
121 static int incb(struct s_file *fp)
123 return (fp->bc < MAXB) ? fp->bc++ : overflow("body");
126 static int inch(struct s_file *fp)
128 return (fp->hc < MAXH) ? fp->hc++ : overflow("item");
131 static int incz(struct s_file *fp)
133 return (fp->zc < MAXZ) ? fp->zc++ : overflow("goal");
136 static int incj(struct s_file *fp)
138 return (fp->jc < MAXJ) ? fp->jc++ : overflow("jump");
141 static int incx(struct s_file *fp)
143 return (fp->xc < MAXX) ? fp->xc++ : overflow("swch");
146 static int incr(struct s_file *fp)
148 return (fp->rc < MAXR) ? fp->rc++ : overflow("bill");
151 static int incu(struct s_file *fp)
153 return (fp->uc < MAXU) ? fp->uc++ : overflow("ball");
156 static int incw(struct s_file *fp)
158 return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
161 static int incd(struct s_file *fp)
163 return (fp->dc < MAXD) ? fp->dc++ : overflow("dict");
166 static int inci(struct s_file *fp)
168 return (fp->ic < MAXI) ? fp->ic++ : overflow("indx");
171 static void init_file(struct s_file *fp)
194 fp->mv = (struct s_mtrl *) calloc(MAXM, sizeof (struct s_mtrl));
195 fp->vv = (struct s_vert *) calloc(MAXV, sizeof (struct s_vert));
196 fp->ev = (struct s_edge *) calloc(MAXE, sizeof (struct s_edge));
197 fp->sv = (struct s_side *) calloc(MAXS, sizeof (struct s_side));
198 fp->tv = (struct s_texc *) calloc(MAXT, sizeof (struct s_texc));
199 fp->gv = (struct s_geom *) calloc(MAXG, sizeof (struct s_geom));
200 fp->lv = (struct s_lump *) calloc(MAXL, sizeof (struct s_lump));
201 fp->nv = (struct s_node *) calloc(MAXN, sizeof (struct s_node));
202 fp->pv = (struct s_path *) calloc(MAXP, sizeof (struct s_path));
203 fp->bv = (struct s_body *) calloc(MAXB, sizeof (struct s_body));
204 fp->hv = (struct s_item *) calloc(MAXH, sizeof (struct s_item));
205 fp->zv = (struct s_goal *) calloc(MAXZ, sizeof (struct s_goal));
206 fp->jv = (struct s_jump *) calloc(MAXJ, sizeof (struct s_jump));
207 fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
208 fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
209 fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
210 fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
211 fp->dv = (struct s_dict *) calloc(MAXD, sizeof (struct s_dict));
212 fp->av = (char *) calloc(MAXA, sizeof (char));
213 fp->iv = (int *) calloc(MAXI, sizeof (int));
216 /*---------------------------------------------------------------------------*/
219 * The following is a small symbol table data structure. Symbols and
220 * their integer values are collected in symv and valv. References
221 * and pointers to their unsatisfied integer values are collected in
222 * refv and pntv. The resolve procedure matches references to symbols
223 * and fills waiting ints with the proper values.
228 static char symv[MAXSYM][MAXSTR];
229 static int valv[MAXSYM];
231 static char refv[MAXSYM][MAXSTR];
232 static int *pntv[MAXSYM];
237 static void make_sym(const char *s, int v)
239 strncpy(symv[strc], s, MAXSTR - 1);
244 static void make_ref(const char *r, int *p)
246 strncpy(refv[refc], r, MAXSTR - 1);
251 static void resolve(void)
255 for (i = 0; i < refc; i++)
256 for (j = 0; j < strc; j++)
257 if (strncmp(refv[i], symv[j], MAXSTR) == 0)
259 *(pntv[i]) = valv[j];
264 /*---------------------------------------------------------------------------*/
267 * The following globals are used to cache target_positions. They are
268 * targeted by various entities and must be resolved in a second pass.
271 static float targ_p [MAXW][3];
272 static int targ_wi[MAXW];
273 static int targ_ji[MAXW];
276 static void targets(struct s_file *fp)
280 for (i = 0; i < fp->wc; i++)
281 v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
283 for (i = 0; i < fp->jc; i++)
284 v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
287 /*---------------------------------------------------------------------------*/
290 * The following code caches image sizes. Textures are referenced by
291 * name, but their sizes are necessary when computing texture
292 * coordinates. This code allows each file to be accessed only once
293 * regardless of the number of surfaces referring to it.
302 static struct _imagedata *imagedata = NULL;
303 static int image_n = 0;
304 static int image_alloc = 0;
306 #define IMAGE_REALLOC 32
308 static void free_imagedata()
314 for (i = 0; i < image_n; i++)
315 free(imagedata[i].s);
319 image_n = image_alloc = 0;
322 static int size_load(const char *file, int *w, int *h)
326 if ((p = image_load(file, w, h, NULL)))
334 static void size_image(const char *name, int *w, int *h)
341 for (i = 0; i < image_n; i++)
342 if (strncmp(imagedata[i].s, name, MAXSTR) == 0)
353 strcpy(jpg, name); strcat(jpg, ".jpg");
354 strcpy(png, name); strcat(png, ".png");
356 if (size_load(config_data(png), w, h) ||
357 size_load(config_data(jpg), w, h))
360 if (image_n + 1 >= image_alloc)
362 struct _imagedata *tmp =
363 (struct _imagedata *) malloc(sizeof(struct _imagedata) * (image_alloc + IMAGE_REALLOC));
366 printf("malloc error\n");
371 (void) memcpy(tmp, imagedata, sizeof(struct _imagedata) * image_alloc);
375 image_alloc += IMAGE_REALLOC;
378 imagedata[image_n].s = (char *) calloc(strlen(name) + 1, 1);
379 imagedata[image_n].w = *w;
380 imagedata[image_n].h = *h;
381 strcpy(imagedata[image_n].s, name);
387 /*---------------------------------------------------------------------------*/
389 /* Read the given material file, adding a new material to the solid. */
391 static int read_mtrl(struct s_file *fp, const char *name)
397 for (mi = 0; mi < fp->mc; mi++)
398 if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
401 mp = fp->mv + incm(fp);
403 strncpy(mp->f, name, PATHMAX - 1);
405 mp->a[0] = mp->a[1] = mp->a[2] = 0.2f;
406 mp->d[0] = mp->d[1] = mp->d[2] = 0.8f;
407 mp->s[0] = mp->s[1] = mp->s[2] = 0.0f;
408 mp->e[0] = mp->e[1] = mp->e[2] = 0.0f;
409 mp->a[3] = mp->d[3] = mp->s[3] = mp->e[3] = 1.0f;
414 if ((fin = fopen(config_data(name), "r")))
422 mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
423 mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
424 mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
425 mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
426 mp->h, &mp->fl, &mp->angle);
433 /*---------------------------------------------------------------------------*/
436 * All bodies with an associated path are assumed to be positioned at
437 * the beginning of that path. These bodies must be moved to the
438 * origin in order for their path transforms to behave correctly.
439 * This is how we get away with defining func_trains with no origin
443 static void move_side(struct s_side *sp, const float p[3])
445 sp->d -= v_dot(sp->n, p);
448 static void move_vert(struct s_vert *vp, const float p[3])
450 v_sub(vp->p, vp->p, p);
453 static void move_lump(struct s_file *fp,
454 struct s_lump *lp, const float p[3])
458 for (i = 0; i < lp->sc; i++)
459 move_side(fp->sv + fp->iv[lp->s0 + i], p);
460 for (i = 0; i < lp->vc; i++)
461 move_vert(fp->vv + fp->iv[lp->v0 + i], p);
464 static void move_body(struct s_file *fp,
469 /* Move the lumps. */
471 for (i = 0; i < bp->lc; i++)
472 move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
474 /* Create an array to mark any verts referenced by moved geoms. */
476 if (bp->gc > 0 && (b = (int *) calloc(fp->vc, sizeof (int))))
478 /* Mark the verts. */
480 for (i = 0; i < bp->gc; i++)
482 b[fp->gv[fp->iv[bp->g0 + i]].vi] = 1;
483 b[fp->gv[fp->iv[bp->g0 + i]].vj] = 1;
484 b[fp->gv[fp->iv[bp->g0 + i]].vk] = 1;
487 /* Apply the motion to the marked vertices. */
489 for (i = 0; i < fp->vc; ++i)
491 move_vert(fp->vv + i, fp->pv[bp->pi].p);
497 static void move_file(struct s_file *fp)
501 for (i = 0; i < fp->bc; i++)
502 if (fp->bv[i].pi >= 0)
503 move_body(fp, fp->bv + i);
506 /*---------------------------------------------------------------------------*/
509 * This is a basic OBJ loader. It is by no means fully compliant with
510 * the OBJ specification, but it works well with the output of
511 * Wings3D. All faces must be triangles and all vertices must include
512 * normals and texture coordinates. Material names are taken to be
513 * references to Neverball materials, rather than MTL definitions.
516 static void read_vt(struct s_file *fp, const char *line)
518 struct s_texc *tp = fp->tv + inct(fp);
520 sscanf(line, "%f %f", tp->u, tp->u + 1);
523 static void read_vn(struct s_file *fp, const char *line)
525 struct s_side *sp = fp->sv + incs(fp);
527 sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
530 static void read_v(struct s_file *fp, const char *line)
532 struct s_vert *vp = fp->vv + incv(fp);
534 sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
537 static void read_f(struct s_file *fp, const char *line,
538 int v0, int t0, int s0, int mi)
540 struct s_geom *gp = fp->gv + incg(fp);
545 sscanf(line, "%d%c%d%c%d %d%c%d%c%d %d%c%d%c%d",
546 &gp->vi, &c1, &gp->ti, &c2, &gp->si,
547 &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
548 &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
563 static void read_obj(struct s_file *fp, const char *name, int mi)
573 if ((fin = fopen(config_data(name), "r")))
575 while (fgets(line, MAXSTR, fin))
577 if (strncmp(line, "usemtl", 6) == 0)
579 sscanf(line + 6, "%s", mtrl);
580 mi = read_mtrl(fp, mtrl);
583 else if (strncmp(line, "f", 1) == 0)
585 if (fp->mv[mi].d[3] > 0.0f)
586 read_f(fp, line + 1, v0, t0, s0, mi);
589 else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
590 else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
591 else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
597 /*---------------------------------------------------------------------------*/
599 static float plane_d[MAXS];
600 static float plane_n[MAXS][3];
601 static float plane_p[MAXS][3];
602 static float plane_u[MAXS][3];
603 static float plane_v[MAXS][3];
604 static int plane_f[MAXS];
605 static int plane_m[MAXS];
607 static void make_plane(int pi, float x0, float y0, float z0,
608 float x1, float y1, float z1,
609 float x2, float y2, float z2,
610 float tu, float tv, float r,
611 float su, float sv, int fl, const char *s)
613 static const float base[6][3][3] = {
614 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
615 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
616 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
617 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
618 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
619 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
623 float p0[3], p1[3], p2[3];
624 float u[3], v[3], p[3];
629 size_image(s, &w, &h);
631 plane_f[pi] = fl ? L_DETAIL : 0;
648 v_crs(plane_n[pi], u, v);
649 v_nrm(plane_n[pi], plane_n[pi]);
651 plane_d[pi] = v_dot(plane_n[pi], p1);
653 for (i = 0; i < 6; i++)
654 if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
664 m_rot(R, base[n][0], V_RAD(r));
666 v_mad(p, p, base[n][1], su * tu / SCALE);
667 v_mad(p, p, base[n][2], sv * tv / SCALE);
669 m_vxfm(plane_u[pi], R, base[n][1]);
670 m_vxfm(plane_v[pi], R, base[n][2]);
671 m_vxfm(plane_p[pi], R, p);
673 v_scl(plane_u[pi], plane_u[pi], 64.f / w);
674 v_scl(plane_v[pi], plane_v[pi], 64.f / h);
676 v_scl(plane_u[pi], plane_u[pi], 1.f / su);
677 v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
680 /*---------------------------------------------------------------------------*/
689 static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
693 if (fgets(buf, MAXSTR, fin))
703 /* Scan the beginning or end of a block. */
705 if (buf[0] == '{') return T_BEG;
706 if (buf[0] == '}') return T_END;
708 /* Scan a key-value pair. */
712 strcpy(key, strtok(buf, "\""));
713 (void) strtok(NULL, "\"");
714 strcpy(val, strtok(NULL, "\""));
725 "%s %f %f %f %f %f %d",
726 &c, &x0, &y0, &z0, &c,
727 &c, &x1, &y1, &z1, &c,
728 &c, &x2, &y2, &z2, &c,
729 key, &tu, &tv, &r, &su, &sv, &fl) == 22)
731 make_plane(pi, x0, y0, z0,
734 tu, tv, r, su, sv, fl, key);
738 /* If it's not recognized, it must be uninteresting. */
745 /*---------------------------------------------------------------------------*/
747 /* Parse a lump from the given file and add it to the solid. */
749 static void read_lump(struct s_file *fp, FILE *fin)
755 struct s_lump *lp = fp->lv + incl(fp);
759 while ((t = map_token(fin, fp->sc, k, v)))
763 fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
764 fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
765 fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
766 fp->sv[fp->sc].d = plane_d[fp->sc];
768 plane_m[fp->sc] = read_mtrl(fp, k);
770 fp->iv[fp->ic] = fp->sc;
780 /*---------------------------------------------------------------------------*/
782 static void make_path(struct s_file *fp,
784 char v[][MAXSTR], int c)
786 int i, pi = incp(fp);
788 struct s_path *pp = fp->pv + pi;
798 for (i = 0; i < c; i++)
800 if (strcmp(k[i], "targetname") == 0)
803 if (strcmp(k[i], "target") == 0)
804 make_ref(v[i], &pp->pi);
806 if (strcmp(k[i], "state") == 0)
809 if (strcmp(k[i], "speed") == 0)
810 sscanf(v[i], "%f", &pp->t);
812 if (strcmp(k[i], "smooth") == 0)
815 if (strcmp(k[i], "origin") == 0)
817 float x = 0.f, y = 0.f, z = 0.f;
819 sscanf(v[i], "%f %f %f", &x, &y, &z);
821 pp->p[0] = +x / SCALE;
822 pp->p[1] = +z / SCALE;
823 pp->p[2] = -y / SCALE;
828 static void make_dict(struct s_file *fp,
832 int space_left, space_needed, di = incd(fp);
834 struct s_dict *dp = fp->dv + di;
836 space_left = MAXA - fp->ac;
837 space_needed = strlen(k) + 1 + strlen(v) + 1;
839 if (space_needed > space_left)
846 dp->aj = dp->ai + strlen(k) + 1;
847 fp->ac = dp->aj + strlen(v) + 1;
849 strncpy(fp->av + dp->ai, k, space_left);
850 strncpy(fp->av + dp->aj, v, space_left - strlen(k) - 1);
853 static int read_dict_entries = 0;
855 static void make_body(struct s_file *fp,
857 char v[][MAXSTR], int c, int l0)
859 int i, mi = 0, bi = incb(fp);
870 struct s_body *bp = fp->bv + bi;
876 for (i = 0; i < c; i++)
878 if (strcmp(k[i], "targetname") == 0)
881 else if (strcmp(k[i], "target") == 0)
882 make_ref(v[i], &bp->pi);
884 else if (strcmp(k[i], "material") == 0)
885 mi = read_mtrl(fp, v[i]);
887 else if (strcmp(k[i], "model") == 0)
888 read_obj(fp, v[i], mi);
890 else if (strcmp(k[i], "origin") == 0)
891 sscanf(v[i], "%f %f %f", &x, &y, &z);
893 else if (read_dict_entries && strcmp(k[i], "classname") != 0)
894 make_dict(fp, k[i], v[i]);
898 bp->lc = fp->lc - l0;
900 bp->gc = fp->gc - g0;
902 for (i = 0; i < bp->gc; i++)
903 fp->iv[inci(fp)] = g0++;
909 for (i = v0; i < fp->vc; i++)
910 v_add(fp->vv[i].p, fp->vv[i].p, p);
912 read_dict_entries = 0;
915 static void make_item(struct s_file *fp,
917 char v[][MAXSTR], int c)
919 int i, hi = inch(fp);
921 struct s_item *hp = fp->hv + hi;
930 for (i = 0; i < c; i++)
932 if (strcmp(k[i], "classname") == 0)
934 if (strcmp(v[i], "light") == 0)
936 else if (strcmp(v[i], "item_health_large") == 0)
938 else if (strcmp(v[i], "item_health_small") == 0)
942 if (strcmp(k[i], "light") == 0)
943 sscanf(v[i], "%d", &hp->n);
945 if (strcmp(k[i], "origin") == 0)
947 float x = 0.f, y = 0.f, z = 0.f;
949 sscanf(v[i], "%f %f %f", &x, &y, &z);
951 hp->p[0] = +x / SCALE;
952 hp->p[1] = +z / SCALE;
953 hp->p[2] = -y / SCALE;
958 static void make_bill(struct s_file *fp,
960 char v[][MAXSTR], int c)
962 int i, ri = incr(fp);
964 struct s_bill *rp = fp->rv + ri;
966 memset(rp, 0, sizeof (struct s_bill));
969 for (i = 0; i < c; i++)
971 if (strcmp(k[i], "width") == 0)
972 sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
973 if (strcmp(k[i], "height") == 0)
974 sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
976 if (strcmp(k[i], "xrot") == 0)
977 sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
978 if (strcmp(k[i], "yrot") == 0)
979 sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
980 if (strcmp(k[i], "zrot") == 0)
981 sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
983 if (strcmp(k[i], "time") == 0)
984 sscanf(v[i], "%f", &rp->t);
985 if (strcmp(k[i], "dist") == 0)
986 sscanf(v[i], "%f", &rp->d);
987 if (strcmp(k[i], "flag") == 0)
988 sscanf(v[i], "%d", &rp->fl);
990 if (strcmp(k[i], "image") == 0)
992 rp->mi = read_mtrl(fp, v[i]);
993 fp->mv[rp->mi].fl |= M_CLAMPED;
996 if (strcmp(k[i], "origin") == 0)
998 float x = 0.f, y = 0.f, z = 0.f;
1000 sscanf(v[i], "%f %f %f", &x, &y, &z);
1002 rp->p[0] = +x / SCALE;
1003 rp->p[1] = +z / SCALE;
1004 rp->p[2] = -y / SCALE;
1008 if (rp->fl & B_ADDITIVE)
1009 fp->mv[rp->mi].fl |= M_ADDITIVE;
1012 static void make_goal(struct s_file *fp,
1014 char v[][MAXSTR], int c)
1016 int i, zi = incz(fp);
1018 struct s_goal *zp = fp->zv + zi;
1025 for (i = 0; i < c; i++)
1027 if (strcmp(k[i], "radius") == 0)
1028 sscanf(v[i], "%f", &zp->r);
1030 if (strcmp(k[i], "origin") == 0)
1032 float x = 0.f, y = 0.f, z = 0.f;
1034 sscanf(v[i], "%f %f %f", &x, &y, &z);
1036 zp->p[0] = +(x) / SCALE;
1037 zp->p[1] = +(z - 24) / SCALE;
1038 zp->p[2] = -(y) / SCALE;
1043 static void make_view(struct s_file *fp,
1045 char v[][MAXSTR], int c)
1047 int i, wi = incw(fp);
1049 struct s_view *wp = fp->wv + wi;
1058 for (i = 0; i < c; i++)
1060 if (strcmp(k[i], "target") == 0)
1061 make_ref(v[i], targ_wi + wi);
1063 if (strcmp(k[i], "origin") == 0)
1065 float x = 0.f, y = 0.f, z = 0.f;
1067 sscanf(v[i], "%f %f %f", &x, &y, &z);
1069 wp->p[0] = +x / SCALE;
1070 wp->p[1] = +z / SCALE;
1071 wp->p[2] = -y / SCALE;
1076 static void make_jump(struct s_file *fp,
1078 char v[][MAXSTR], int c)
1080 int i, ji = incj(fp);
1082 struct s_jump *jp = fp->jv + ji;
1092 for (i = 0; i < c; i++)
1094 if (strcmp(k[i], "radius") == 0)
1095 sscanf(v[i], "%f", &jp->r);
1097 if (strcmp(k[i], "target") == 0)
1098 make_ref(v[i], targ_ji + ji);
1100 if (strcmp(k[i], "origin") == 0)
1102 float x = 0.f, y = 0.f, z = 0.f;
1104 sscanf(v[i], "%f %f %f", &x, &y, &z);
1106 jp->p[0] = +x / SCALE;
1107 jp->p[1] = +z / SCALE;
1108 jp->p[2] = -y / SCALE;
1113 static void make_swch(struct s_file *fp,
1115 char v[][MAXSTR], int c)
1117 int i, xi = incx(fp);
1119 struct s_swch *xp = fp->xv + xi;
1132 for (i = 0; i < c; i++)
1134 if (strcmp(k[i], "radius") == 0)
1135 sscanf(v[i], "%f", &xp->r);
1137 if (strcmp(k[i], "target") == 0)
1138 make_ref(v[i], &xp->pi);
1140 if (strcmp(k[i], "timer") == 0)
1141 sscanf(v[i], "%f", &xp->t0);
1143 if (strcmp(k[i], "state") == 0)
1146 xp->f0 = atoi(v[i]);
1149 if (strcmp(k[i], "invisible") == 0)
1152 if (strcmp(k[i], "origin") == 0)
1154 float x = 0.f, y = 0.f, z = 0.f;
1156 sscanf(v[i], "%f %f %f", &x, &y, &z);
1158 xp->p[0] = +x / SCALE;
1159 xp->p[1] = +z / SCALE;
1160 xp->p[2] = -y / SCALE;
1165 static void make_targ(struct s_file *fp,
1167 char v[][MAXSTR], int c)
1171 targ_p[targ_n][0] = 0.f;
1172 targ_p[targ_n][1] = 0.f;
1173 targ_p[targ_n][2] = 0.f;
1175 for (i = 0; i < c; i++)
1177 if (strcmp(k[i], "targetname") == 0)
1178 make_sym(v[i], targ_n);
1180 if (strcmp(k[i], "origin") == 0)
1182 float x = 0.f, y = 0.f, z = 0.f;
1184 sscanf(v[i], "%f %f %f", &x, &y, &z);
1186 targ_p[targ_n][0] = +x / SCALE;
1187 targ_p[targ_n][1] = +z / SCALE;
1188 targ_p[targ_n][2] = -y / SCALE;
1195 static void make_ball(struct s_file *fp,
1197 char v[][MAXSTR], int c)
1199 int i, ui = incu(fp);
1201 struct s_ball *up = fp->uv + ui;
1208 for (i = 0; i < c; i++)
1210 if (strcmp(k[i], "radius") == 0)
1211 sscanf(v[i], "%f", &up->r);
1213 if (strcmp(k[i], "origin") == 0)
1215 float x = 0.f, y = 0.f, z = 0.f;
1217 sscanf(v[i], "%f %f %f", &x, &y, &z);
1219 up->p[0] = +(x) / SCALE;
1220 up->p[1] = +(z - 24) / SCALE;
1221 up->p[2] = -(y) / SCALE;
1225 up->p[1] += up->r + SMALL;
1228 /*---------------------------------------------------------------------------*/
1230 static void read_ent(struct s_file *fp, FILE *fin)
1232 char k[MAXKEY][MAXSTR];
1233 char v[MAXKEY][MAXSTR];
1234 int t, i = 0, c = 0;
1238 while ((t = map_token(fin, -1, k[c], v[c])))
1242 if (strcmp(k[c], "classname") == 0)
1246 if (t == T_BEG) read_lump(fp, fin);
1247 if (t == T_END) break;
1250 if (!strcmp(v[i], "light")) make_item(fp, k, v, c);
1251 if (!strcmp(v[i], "item_health_large")) make_item(fp, k, v, c);
1252 if (!strcmp(v[i], "item_health_small")) make_item(fp, k, v, c);
1253 if (!strcmp(v[i], "info_camp")) make_swch(fp, k, v, c);
1254 if (!strcmp(v[i], "info_null")) make_bill(fp, k, v, c);
1255 if (!strcmp(v[i], "path_corner")) make_path(fp, k, v, c);
1256 if (!strcmp(v[i], "info_player_start")) make_ball(fp, k, v, c);
1257 if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1258 if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
1259 if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
1260 if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
1261 if (!strcmp(v[i], "worldspawn"))
1263 read_dict_entries = 1;
1264 make_body(fp, k, v, c, l0);
1266 if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
1267 if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
1270 static void read_map(struct s_file *fp, FILE *fin)
1276 while ((t = map_token(fin, -1, k, v)))
1281 /*---------------------------------------------------------------------------*/
1283 /* Test the location of a point with respect to a side plane. */
1285 static int fore_side(const float p[3], const struct s_side *sp)
1287 return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1290 static int on_side(const float p[3], const struct s_side *sp)
1292 float d = v_dot(p, sp->n) - sp->d;
1294 return (-SMALL < d && d < +SMALL) ? 1 : 0;
1297 /*---------------------------------------------------------------------------*/
1299 * Confirm that the addition of a vert would not result in degenerate
1303 static int ok_vert(const struct s_file *fp,
1304 const struct s_lump *lp, const float p[3])
1309 for (i = 0; i < lp->vc; i++)
1311 float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1315 if (v_len(r) < SMALL)
1321 /*---------------------------------------------------------------------------*/
1324 * The following functions take the set of planes defining a lump and
1325 * find the verts, edges, and geoms that describe its boundaries. To
1326 * do this, they first find the verts, and then search these verts for
1327 * valid edges and geoms. It may be more efficient to compute edges
1328 * and geoms directly by clipping down infinite line segments and
1329 * planes, but this would be more complex and prone to numerical
1334 * Given 3 side planes, compute the point of intersection, if any.
1335 * Confirm that this point falls within the current lump, and that it
1336 * is unique. Add it as a vert of the solid.
1338 static void clip_vert(struct s_file *fp,
1339 struct s_lump *lp, int si, int sj, int sk)
1341 float M[16], X[16], I[16];
1345 d[0] = fp->sv[si].d;
1346 d[1] = fp->sv[sj].d;
1347 d[2] = fp->sv[sk].d;
1349 m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1356 for (i = 0; i < lp->sc; i++)
1358 int si = fp->iv[lp->s0 + i];
1360 if (fore_side(p, fp->sv + si))
1364 if (ok_vert(fp, lp, p))
1366 v_cpy(fp->vv[fp->vc].p, p);
1368 fp->iv[fp->ic] = fp->vc;
1377 * Given two side planes, find an edge along their intersection by
1378 * finding a pair of vertices that fall on both planes. Add it to the
1381 static void clip_edge(struct s_file *fp,
1382 struct s_lump *lp, int si, int sj)
1386 for (i = 1; i < lp->vc; i++)
1387 for (j = 0; j < i; j++)
1389 int vi = fp->iv[lp->v0 + i];
1390 int vj = fp->iv[lp->v0 + j];
1392 if (on_side(fp->vv[vi].p, fp->sv + si) &&
1393 on_side(fp->vv[vj].p, fp->sv + si) &&
1394 on_side(fp->vv[vi].p, fp->sv + sj) &&
1395 on_side(fp->vv[vj].p, fp->sv + sj))
1397 fp->ev[fp->ec].vi = vi;
1398 fp->ev[fp->ec].vj = vj;
1400 fp->iv[fp->ic] = fp->ec;
1410 * Find all verts that lie on the given side of the lump. Sort these
1411 * verts to have a counter-clockwise winding about the plane normal.
1412 * Create geoms to tessellate the resulting convex polygon.
1414 static void clip_geom(struct s_file *fp,
1415 struct s_lump *lp, int si)
1417 int m[256], t[256], d, i, j, n = 0;
1422 struct s_side *sp = fp->sv + si;
1426 for (i = 0; i < lp->vc; i++)
1428 int vi = fp->iv[lp->v0 + i];
1430 if (on_side(fp->vv[vi].p, sp))
1435 v_add(v, fp->vv[vi].p, plane_p[si]);
1437 fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1438 fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1446 for (i = 1; i < n; i++)
1447 for (j = i + 1; j < n; j++)
1449 v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1450 v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1453 if (v_dot(w, sp->n) < 0.f)
1467 for (i = 0; i < n - 2; i++)
1469 fp->gv[fp->gc].mi = plane_m[si];
1471 fp->gv[fp->gc].ti = t[0];
1472 fp->gv[fp->gc].tj = t[i + 1];
1473 fp->gv[fp->gc].tk = t[i + 2];
1475 fp->gv[fp->gc].si = si;
1476 fp->gv[fp->gc].sj = si;
1477 fp->gv[fp->gc].sk = si;
1479 fp->gv[fp->gc].vi = m[0];
1480 fp->gv[fp->gc].vj = m[i + 1];
1481 fp->gv[fp->gc].vk = m[i + 2];
1483 fp->iv[fp->ic] = fp->gc;
1491 * Iterate the sides of the lump, attempting to generate a new vert for
1492 * each trio of planes, a new edge for each pair of planes, and a new
1493 * set of geom for each visible plane.
1495 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1502 for (i = 2; i < lp->sc; i++)
1503 for (j = 1; j < i; j++)
1504 for (k = 0; k < j; k++)
1508 fp->iv[lp->s0 + k]);
1513 for (i = 1; i < lp->sc; i++)
1514 for (j = 0; j < i; j++)
1517 fp->iv[lp->s0 + j]);
1522 for (i = 0; i < lp->sc; i++)
1523 if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0.0f)
1525 fp->iv[lp->s0 + i]);
1527 for (i = 0; i < lp->sc; i++)
1528 if (plane_f[fp->iv[lp->s0 + i]])
1532 static void clip_file(struct s_file *fp)
1536 for (i = 0; i < fp->lc; i++)
1537 clip_lump(fp, fp->lv + i);
1540 /*---------------------------------------------------------------------------*/
1543 * For each body element type, determine if element 'p' is equivalent
1544 * to element 'q'. This is more than a simple memory compare. It
1545 * effectively snaps mtrls and verts together, and may reverse the
1546 * winding of an edge or a geom. This is done in order to maximize
1547 * the number of elements that can be eliminated.
1550 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1552 if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1553 if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1554 if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1555 if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1557 if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1558 if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1559 if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1560 if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1562 if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1563 if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1564 if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1565 if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1567 if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1568 if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1569 if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1570 if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1572 if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1574 if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1579 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1581 if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1582 if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1583 if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1588 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1590 if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1591 if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1596 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1598 if (fabs(sp->d - sq->d) > SMALL) return 0;
1599 if (v_dot(sp->n, sq->n) < 0.9999) return 0;
1604 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1606 if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1607 if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1612 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1614 if (gp->mi != gq->mi) return 0;
1616 if (gp->ti != gq->ti) return 0;
1617 if (gp->si != gq->si) return 0;
1618 if (gp->vi != gq->vi) return 0;
1620 if (gp->tj != gq->tj) return 0;
1621 if (gp->sj != gq->sj) return 0;
1622 if (gp->vj != gq->vj) return 0;
1624 if (gp->tk != gq->tk) return 0;
1625 if (gp->sk != gq->sk) return 0;
1626 if (gp->vk != gq->vk) return 0;
1631 /*---------------------------------------------------------------------------*/
1634 * For each file element type, replace all references to element 'i'
1635 * with a reference to element 'j'. These are used when optimizing
1636 * and sorting the file.
1639 static void swap_mtrl(struct s_file *fp, int mi, int mj)
1643 for (i = 0; i < fp->gc; i++)
1644 if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1645 for (i = 0; i < fp->rc; i++)
1646 if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1649 static void swap_vert(struct s_file *fp, int vi, int vj)
1653 for (i = 0; i < fp->ec; i++)
1655 if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1656 if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1659 for (i = 0; i < fp->gc; i++)
1661 if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1662 if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1663 if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1666 for (i = 0; i < fp->lc; i++)
1667 for (j = 0; j < fp->lv[i].vc; j++)
1668 if (fp->iv[fp->lv[i].v0 + j] == vi)
1669 fp->iv[fp->lv[i].v0 + j] = vj;
1672 static void swap_edge(struct s_file *fp, int ei, int ej)
1676 for (i = 0; i < fp->lc; i++)
1677 for (j = 0; j < fp->lv[i].ec; j++)
1678 if (fp->iv[fp->lv[i].e0 + j] == ei)
1679 fp->iv[fp->lv[i].e0 + j] = ej;
1682 static void swap_side(struct s_file *fp, int si, int sj)
1686 for (i = 0; i < fp->gc; i++)
1688 if (fp->gv[i].si == si) fp->gv[i].si = sj;
1689 if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1690 if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1692 for (i = 0; i < fp->nc; i++)
1693 if (fp->nv[i].si == si) fp->nv[i].si = sj;
1695 for (i = 0; i < fp->lc; i++)
1696 for (j = 0; j < fp->lv[i].sc; j++)
1697 if (fp->iv[fp->lv[i].s0 + j] == si)
1698 fp->iv[fp->lv[i].s0 + j] = sj;
1701 static void swap_texc(struct s_file *fp, int ti, int tj)
1705 for (i = 0; i < fp->gc; i++)
1707 if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1708 if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1709 if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1714 static void swap_geom(struct s_file *fp, int gi, int gj)
1718 for (i = 0; i < fp->lc; i++)
1719 for (j = 0; j < fp->lv[i].gc; j++)
1720 if (fp->iv[fp->lv[i].g0 + j] == gi)
1721 fp->iv[fp->lv[i].g0 + j] = gj;
1723 for (i = 0; i < fp->bc; i++)
1724 for (j = 0; j < fp->bv[i].gc; j++)
1725 if (fp->iv[fp->bv[i].g0 + j] == gi)
1726 fp->iv[fp->bv[i].g0 + j] = gj;
1729 /*---------------------------------------------------------------------------*/
1731 static void uniq_mtrl(struct s_file *fp)
1735 for (i = 0; i < fp->mc; i++)
1737 for (j = 0; j < k; j++)
1738 if (comp_mtrl(fp->mv + i, fp->mv + j))
1740 swap_mtrl(fp, i, j);
1748 fp->mv[k] = fp->mv[i];
1749 swap_mtrl(fp, i, k);
1758 static void uniq_vert(struct s_file *fp)
1762 for (i = 0; i < fp->vc; i++)
1764 for (j = 0; j < k; j++)
1765 if (comp_vert(fp->vv + i, fp->vv + j))
1767 swap_vert(fp, i, j);
1775 fp->vv[k] = fp->vv[i];
1776 swap_vert(fp, i, k);
1785 static void uniq_edge(struct s_file *fp)
1789 for (i = 0; i < fp->ec; i++)
1791 for (j = 0; j < k; j++)
1792 if (comp_edge(fp->ev + i, fp->ev + j))
1794 swap_edge(fp, i, j);
1802 fp->ev[k] = fp->ev[i];
1803 swap_edge(fp, i, k);
1812 static void uniq_geom(struct s_file *fp)
1816 for (i = 0; i < fp->gc; i++)
1818 for (j = 0; j < k; j++)
1819 if (comp_geom(fp->gv + i, fp->gv + j))
1821 swap_geom(fp, i, j);
1829 fp->gv[k] = fp->gv[i];
1830 swap_geom(fp, i, k);
1839 static void uniq_texc(struct s_file *fp)
1843 for (i = 0; i < fp->tc; i++)
1845 for (j = 0; j < k; j++)
1846 if (comp_texc(fp->tv + i, fp->tv + j))
1848 swap_texc(fp, i, j);
1856 fp->tv[k] = fp->tv[i];
1857 swap_texc(fp, i, k);
1866 static void uniq_side(struct s_file *fp)
1870 for (i = 0; i < fp->sc; i++)
1872 for (j = 0; j < k; j++)
1873 if (comp_side(fp->sv + i, fp->sv + j))
1875 swap_side(fp, i, j);
1883 fp->sv[k] = fp->sv[i];
1884 swap_side(fp, i, k);
1893 static void uniq_file(struct s_file *fp)
1895 /* Debug mode skips optimization, producing oversized output files. */
1897 if (debug_output == 0)
1908 /*---------------------------------------------------------------------------*/
1918 static int comp_trip(const void *p, const void *q)
1920 const struct s_trip *tp = (const struct s_trip *) p;
1921 const struct s_trip *tq = (const struct s_trip *) q;
1923 if (tp->vi < tq->vi) return -1;
1924 if (tp->vi > tq->vi) return +1;
1925 if (tp->mi < tq->mi) return -1;
1926 if (tp->mi > tq->mi) return +1;
1931 static void smth_file(struct s_file *fp)
1933 struct s_trip temp, *T;
1935 if (debug_output == 0)
1937 if ((T = (struct s_trip *) malloc(fp->gc * 3 * sizeof (struct s_trip))))
1939 int gi, i, j, k, l, c = 0;
1941 /* Create a list of all non-faceted vertex triplets. */
1943 for (gi = 0; gi < fp->gc; ++gi)
1945 struct s_geom *gp = fp->gv + gi;
1966 /* Sort all triplets by vertex index and material. */
1968 qsort(T, c, sizeof (struct s_trip), comp_trip);
1970 /* For each set of triplets sharing vertex index and material... */
1972 for (i = 0; i < c; i = l)
1976 float N[3], angle = fp->mv[T[i].mi].angle;
1977 const float *Ni = fp->sv[T[i].si].n;
1979 /* Sort the set by side similarity to the first. */
1981 for (j = i + 1; j < c && (T[j].vi == T[i].vi &&
1982 T[j].mi == T[i].mi); ++j)
1984 for (k = j + 1; k < c && (T[k].vi == T[i].vi &&
1985 T[k].mi == T[i].mi); ++k)
1987 const float *Nj = fp->sv[T[j].si].n;
1988 const float *Nk = fp->sv[T[k].si].n;
1990 if (T[j].si != T[k].si && v_dot(Nk, Ni) > v_dot(Nj, Ni))
1999 /* Accumulate all similar side normals. */
2005 for (l = i + 1; l < c && (T[l].vi == T[i].vi &&
2006 T[l].mi == T[i].mi); ++l)
2007 if (T[l].si != T[i].si)
2009 const float *Nl = fp->sv[T[l].si].n;
2011 if (V_DEG(facosf(v_dot(Ni, Nl))) > angle)
2021 /* If at least two normals have been accumulated... */
2025 /* Store the accumulated normal as a new side. */
2029 v_nrm(fp->sv[ss].n, N);
2030 fp->sv[ss].d = 0.0f;
2032 /* Assign the new normal to the merged triplets. */
2034 for (j = i; j < l; ++j)
2039 /* Assign the remapped normals to the original geoms. */
2041 for (i = 0; i < c; ++i)
2043 struct s_geom *gp = fp->gv + T[i].gi;
2045 if (gp->vi == T[i].vi) gp->si = T[i].si;
2046 if (gp->vj == T[i].vi) gp->sj = T[i].si;
2047 if (gp->vk == T[i].vi) gp->sk = T[i].si;
2058 /*---------------------------------------------------------------------------*/
2060 static void sort_file(struct s_file *fp)
2064 /* Sort billboards by material within distance. */
2066 for (i = 0; i < fp->rc; i++)
2067 for (j = i + 1; j < fp->rc; j++)
2068 if ((fp->rv[j].d > fp->rv[i].d) ||
2069 (fp->rv[j].d == fp->rv[i].d &&
2070 fp->rv[j].mi > fp->rv[i].mi))
2075 fp->rv[i] = fp->rv[j];
2079 /* Ensure the first vertex is the lowest. */
2081 for (i = 0; i < fp->vc; i++)
2082 if (fp->vv[0].p[1] > fp->vv[i].p[1])
2087 fp->vv[0] = fp->vv[i];
2090 swap_vert(fp, 0, -1);
2091 swap_vert(fp, i, 0);
2092 swap_vert(fp, -1, i);
2096 /*---------------------------------------------------------------------------*/
2098 static int test_lump_side(const struct s_file *fp,
2099 const struct s_lump *lp,
2100 const struct s_side *sp)
2108 /* If the given side is part of the given lump, then the lump is behind. */
2110 for (si = 0; si < lp->sc; si++)
2111 if (fp->sv + fp->iv[lp->s0 + si] == sp)
2114 /* Check if each lump vertex is in front of, behind, on the side. */
2116 for (vi = 0; vi < lp->vc; vi++)
2118 float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
2124 /* If no verts are behind, the lump is in front, and vice versa. */
2126 if (f > 0 && b == 0) return +1;
2127 if (b > 0 && f == 0) return -1;
2129 /* Else, the lump crosses the side. */
2134 static int node_node(struct s_file *fp, int l0, int lc)
2138 /* Base case. Dump all given lumps into a leaf node. */
2140 fp->nv[fp->nc].si = -1;
2141 fp->nv[fp->nc].ni = -1;
2142 fp->nv[fp->nc].nj = -1;
2143 fp->nv[fp->nc].l0 = l0;
2144 fp->nv[fp->nc].lc = lc;
2154 int li = 0, lic = 0;
2155 int lj = 0, ljc = 0;
2156 int lk = 0, lkc = 0;
2159 /* Find the side that most evenly splits the given lumps. */
2161 for (si = 0; si < fp->sc; si++)
2167 for (li = 0; li < lc; li++)
2168 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
2175 if ((d < sjd) || (d == sjd && o < sjo))
2183 /* Flag each lump with its position WRT the side. */
2185 for (li = 0; li < lc; li++)
2188 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2192 switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
2195 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10;
2199 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2203 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40;
2208 /* Sort all lumps in the range by their flag values. */
2210 for (li = 1; li < lc; li++)
2211 for (lj = 0; lj < li; lj++)
2212 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
2216 l = fp->lv[l0 + li];
2217 fp->lv[l0 + li] = fp->lv[l0 + lj];
2218 fp->lv[l0 + lj] = l;
2221 /* Establish the in-front, on, and behind lump ranges. */
2227 for (i = lc - 1; i >= 0; i--)
2228 switch (fp->lv[l0 + i].fl & 0xf0)
2230 case 0x10: li = l0 + i; lic++; break;
2231 case 0x20: lj = l0 + i; ljc++; break;
2232 case 0x40: lk = l0 + i; lkc++; break;
2235 /* Add the lumps on the side to the node. */
2240 fp->nv[i].ni = node_node(fp, li, lic);
2242 fp->nv[i].nj = node_node(fp, lk, lkc);
2250 static void node_file(struct s_file *fp)
2254 /* Sort the lumps of each body into BSP nodes. */
2256 for (bi = 0; bi < fp->bc; bi++)
2257 fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
2260 /*---------------------------------------------------------------------------*/
2262 static void dump_file(struct s_file *p, const char *name)
2264 /* FIXME: Count visible geoms.
2266 * I'm afraid items break this (not sure though) so leaving it out.
2276 int m = p->rc + p->cc * 128 + (p->zc * p->jc + p->xc) * 32;
2279 /* Count the number of solid lumps. */
2281 for (i = 0; i < p->lc; i++)
2282 if ((p->lv[i].fl & 1) == 0)
2286 /* Count the number of visible geoms. */
2288 for (i = 0; i < p->bc; i++)
2290 for (j = 0; j < p->bv[i].lc; j++)
2291 m += p->lv[p->bv[i].l0 + j].gc;
2296 /* Count the total value of all coins. */
2298 for (i = 0; i < p->hc; i++)
2299 if (p->hv[i].t == ITEM_COIN)
2303 printf("%s (%d/%d/$%d)\n"
2305 printf("%s (%d/$%d)\n"
2306 " mtrl vert edge side texc"
2307 " geom lump path node body\n"
2308 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
2309 " item goal view jump swch"
2310 " bill ball char dict indx\n"
2311 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
2316 p->mc, p->vc, p->ec, p->sc, p->tc,
2317 p->gc, p->lc, p->pc, p->nc, p->bc,
2318 p->hc, p->zc, p->wc, p->jc, p->xc,
2319 p->rc, p->uc, p->ac, p->dc, p->ic);
2322 int main(int argc, char *argv[])
2331 if (argc > 3 && strcmp(argv[3], "--debug") == 0)
2334 if (config_data_path(argv[2], NULL))
2336 strncpy(src, argv[1], MAXSTR);
2337 strncpy(dst, argv[1], MAXSTR);
2339 if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
2340 strcpy(dst + strlen(dst) - 4, ".sol");
2342 strcat(dst, ".sol");
2344 if ((fin = fopen(src, "r")))
2367 else fprintf(stderr, "Failure to establish data directory\n");
2369 else fprintf(stderr, "Usage: %s <map> <data> [--debug]\n", argv[0]);