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 /*---------------------------------------------------------------------------*/
22 #include "solid_base.h"
25 #include "base_image.h"
26 #include "base_config.h"
36 * The overall design of this map converter is very stupid, but very
37 * simple. It begins by assuming that every mtrl, vert, edge, side,
38 * and texc in the map is unique. It then makes an optimizing pass
39 * that discards redundant information. The result is optimal, though
40 * the process is terribly inefficient.
43 /*---------------------------------------------------------------------------*/
45 static const char *input_file;
46 static int debug_output;
49 /*---------------------------------------------------------------------------*/
51 /* Ohhhh... arbitrary! */
74 static int overflow(const char *s)
76 printf("%s overflow\n", s);
81 static int incm(struct s_base *fp)
83 return (fp->mc < MAXM) ? fp->mc++ : overflow("mtrl");
86 static int incv(struct s_base *fp)
88 return (fp->vc < MAXV) ? fp->vc++ : overflow("vert");
91 static int ince(struct s_base *fp)
93 return (fp->ec < MAXE) ? fp->ec++ : overflow("edge");
96 static int incs(struct s_base *fp)
98 return (fp->sc < MAXS) ? fp->sc++ : overflow("side");
101 static int inct(struct s_base *fp)
103 return (fp->tc < MAXT) ? fp->tc++ : overflow("texc");
106 static int incg(struct s_base *fp)
108 return (fp->gc < MAXG) ? fp->gc++ : overflow("geom");
111 static int incl(struct s_base *fp)
113 return (fp->lc < MAXL) ? fp->lc++ : overflow("lump");
116 static int incn(struct s_base *fp)
118 return (fp->nc < MAXN) ? fp->nc++ : overflow("node");
121 static int incp(struct s_base *fp)
123 return (fp->pc < MAXP) ? fp->pc++ : overflow("path");
126 static int incb(struct s_base *fp)
128 return (fp->bc < MAXB) ? fp->bc++ : overflow("body");
131 static int inch(struct s_base *fp)
133 return (fp->hc < MAXH) ? fp->hc++ : overflow("item");
136 static int incz(struct s_base *fp)
138 return (fp->zc < MAXZ) ? fp->zc++ : overflow("goal");
141 static int incj(struct s_base *fp)
143 return (fp->jc < MAXJ) ? fp->jc++ : overflow("jump");
146 static int incx(struct s_base *fp)
148 return (fp->xc < MAXX) ? fp->xc++ : overflow("swch");
151 static int incr(struct s_base *fp)
153 return (fp->rc < MAXR) ? fp->rc++ : overflow("bill");
156 static int incu(struct s_base *fp)
158 return (fp->uc < MAXU) ? fp->uc++ : overflow("ball");
161 static int incw(struct s_base *fp)
163 return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
166 static int incd(struct s_base *fp)
168 return (fp->dc < MAXD) ? fp->dc++ : overflow("dict");
171 static int inci(struct s_base *fp)
173 return (fp->ic < MAXI) ? fp->ic++ : overflow("indx");
176 static void init_file(struct s_base *fp)
199 fp->mv = (struct b_mtrl *) calloc(MAXM, sizeof (*fp->mv));
200 fp->vv = (struct b_vert *) calloc(MAXV, sizeof (*fp->vv));
201 fp->ev = (struct b_edge *) calloc(MAXE, sizeof (*fp->ev));
202 fp->sv = (struct b_side *) calloc(MAXS, sizeof (*fp->sv));
203 fp->tv = (struct b_texc *) calloc(MAXT, sizeof (*fp->tv));
204 fp->gv = (struct b_geom *) calloc(MAXG, sizeof (*fp->gv));
205 fp->lv = (struct b_lump *) calloc(MAXL, sizeof (*fp->lv));
206 fp->nv = (struct b_node *) calloc(MAXN, sizeof (*fp->nv));
207 fp->pv = (struct b_path *) calloc(MAXP, sizeof (*fp->pv));
208 fp->bv = (struct b_body *) calloc(MAXB, sizeof (*fp->bv));
209 fp->hv = (struct b_item *) calloc(MAXH, sizeof (*fp->hv));
210 fp->zv = (struct b_goal *) calloc(MAXZ, sizeof (*fp->zv));
211 fp->jv = (struct b_jump *) calloc(MAXJ, sizeof (*fp->jv));
212 fp->xv = (struct b_swch *) calloc(MAXX, sizeof (*fp->xv));
213 fp->rv = (struct b_bill *) calloc(MAXR, sizeof (*fp->rv));
214 fp->uv = (struct b_ball *) calloc(MAXU, sizeof (*fp->uv));
215 fp->wv = (struct b_view *) calloc(MAXW, sizeof (*fp->wv));
216 fp->dv = (struct b_dict *) calloc(MAXD, sizeof (*fp->dv));
217 fp->av = (char *) calloc(MAXA, sizeof (*fp->av));
218 fp->iv = (int *) calloc(MAXI, sizeof (*fp->iv));
221 /*---------------------------------------------------------------------------*/
224 * The following is a small symbol table data structure. Symbols and
225 * their integer values are collected in symv and valv. References
226 * and pointers to their unsatisfied integer values are collected in
227 * refv and pntv. The resolve procedure matches references to symbols
228 * and fills waiting ints with the proper values.
233 static char symv[MAXSYM][MAXSTR];
234 static int valv[MAXSYM];
236 static char refv[MAXSYM][MAXSTR];
237 static int *pntv[MAXSYM];
242 static void make_sym(const char *s, int v)
244 strncpy(symv[strc], s, MAXSTR - 1);
249 static void make_ref(const char *r, int *p)
251 strncpy(refv[refc], r, MAXSTR - 1);
256 static void resolve(void)
260 for (i = 0; i < refc; i++)
261 for (j = 0; j < strc; j++)
262 if (strncmp(refv[i], symv[j], MAXSTR) == 0)
264 *(pntv[i]) = valv[j];
269 /*---------------------------------------------------------------------------*/
272 * The following globals are used to cache target_positions. They are
273 * targeted by various entities and must be resolved in a second pass.
276 static float targ_p [MAXW][3];
277 static int targ_wi[MAXW];
278 static int targ_ji[MAXW];
281 static void targets(struct s_base *fp)
285 for (i = 0; i < fp->wc; i++)
286 v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
288 for (i = 0; i < fp->jc; i++)
289 v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
292 /*---------------------------------------------------------------------------*/
295 * The following code caches image sizes. Textures are referenced by
296 * name, but their sizes are necessary when computing texture
297 * coordinates. This code allows each file to be accessed only once
298 * regardless of the number of surfaces referring to it.
307 static struct _imagedata *imagedata = NULL;
308 static int image_n = 0;
309 static int image_alloc = 0;
311 #define IMAGE_REALLOC 32
313 static void free_imagedata()
319 for (i = 0; i < image_n; i++)
320 free(imagedata[i].s);
324 image_n = image_alloc = 0;
327 static int size_load(const char *file, int *w, int *h)
331 if ((p = image_load(file, w, h, NULL)))
339 static void size_image(const char *name, int *w, int *h)
346 for (i = 0; i < image_n; i++)
347 if (strncmp(imagedata[i].s, name, MAXSTR) == 0)
358 strcpy(jpg, name); strcat(jpg, ".jpg");
359 strcpy(png, name); strcat(png, ".png");
361 if (size_load(png, w, h) ||
362 size_load(jpg, w, h))
365 if (image_n + 1 >= image_alloc)
367 struct _imagedata *tmp =
368 (struct _imagedata *) malloc(sizeof(struct _imagedata) * (image_alloc + IMAGE_REALLOC));
371 printf("malloc error\n");
376 (void) memcpy(tmp, imagedata, sizeof(struct _imagedata) * image_alloc);
380 image_alloc += IMAGE_REALLOC;
383 imagedata[image_n].s = (char *) calloc(strlen(name) + 1, 1);
384 imagedata[image_n].w = *w;
385 imagedata[image_n].h = *h;
386 strcpy(imagedata[image_n].s, name);
392 /*---------------------------------------------------------------------------*/
394 /* Read the given material file, adding a new material to the solid. */
396 #define scan_vec4(f, s, v) \
397 if (fs_gets((s), sizeof (s), (f))) \
398 sscanf((s), "%f %f %f %f", (v), (v) + 1, (v) + 2, (v) + 3)
400 static int read_mtrl(struct s_base *fp, const char *name)
402 static char line[MAXSTR];
407 for (mi = 0; mi < fp->mc; mi++)
408 if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
411 mp = fp->mv + incm(fp);
413 strncpy(mp->f, name, PATHMAX - 1);
415 mp->a[0] = mp->a[1] = mp->a[2] = 0.2f;
416 mp->d[0] = mp->d[1] = mp->d[2] = 0.8f;
417 mp->s[0] = mp->s[1] = mp->s[2] = 0.0f;
418 mp->e[0] = mp->e[1] = mp->e[2] = 0.0f;
419 mp->a[3] = mp->d[3] = mp->s[3] = mp->e[3] = 1.0f;
424 if ((fin = fs_open(name, "r")))
426 scan_vec4(fin, line, mp->d);
427 scan_vec4(fin, line, mp->a);
428 scan_vec4(fin, line, mp->s);
429 scan_vec4(fin, line, mp->e);
431 if (fs_gets(line, sizeof (line), fin))
432 mp->h[0] = strtod(line, NULL);
434 if (fs_gets(line, sizeof (line), fin))
435 mp->fl = strtol(line, NULL, 10);
437 if (fs_gets(line, sizeof (line), fin))
438 mp->angle = strtod(line, NULL);
443 fprintf(stderr, "%s: unknown material \"%s\"\n", input_file, name);
450 /*---------------------------------------------------------------------------*/
453 * All bodies with an associated path are assumed to be positioned at
454 * the beginning of that path. These bodies must be moved to the
455 * origin in order for their path transforms to behave correctly.
456 * This is how we get away with defining func_trains with no origin
460 static void move_side(struct b_side *sp, const float p[3])
462 sp->d -= v_dot(sp->n, p);
465 static void move_vert(struct b_vert *vp, const float p[3])
467 v_sub(vp->p, vp->p, p);
470 static void move_lump(struct s_base *fp,
471 struct b_lump *lp, const float p[3])
475 for (i = 0; i < lp->sc; i++)
476 move_side(fp->sv + fp->iv[lp->s0 + i], p);
477 for (i = 0; i < lp->vc; i++)
478 move_vert(fp->vv + fp->iv[lp->v0 + i], p);
481 static void move_body(struct s_base *fp,
486 /* Move the lumps. */
488 for (i = 0; i < bp->lc; i++)
489 move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
491 /* Create an array to mark any verts referenced by moved geoms. */
493 if (bp->gc > 0 && (b = (int *) calloc(fp->vc, sizeof (int))))
495 /* Mark the verts. */
497 for (i = 0; i < bp->gc; i++)
499 b[fp->gv[fp->iv[bp->g0 + i]].vi] = 1;
500 b[fp->gv[fp->iv[bp->g0 + i]].vj] = 1;
501 b[fp->gv[fp->iv[bp->g0 + i]].vk] = 1;
504 /* Apply the motion to the marked vertices. */
506 for (i = 0; i < fp->vc; ++i)
508 move_vert(fp->vv + i, fp->pv[bp->pi].p);
514 static void move_file(struct s_base *fp)
518 for (i = 0; i < fp->bc; i++)
519 if (fp->bv[i].pi >= 0)
520 move_body(fp, fp->bv + i);
523 /*---------------------------------------------------------------------------*/
526 * This is a basic OBJ loader. It is by no means fully compliant with
527 * the OBJ specification, but it works well with the output of
528 * Wings3D. All faces must be triangles and all vertices must include
529 * normals and texture coordinates. Material names are taken to be
530 * references to Neverball materials, rather than MTL definitions.
533 static void read_vt(struct s_base *fp, const char *line)
535 struct b_texc *tp = fp->tv + inct(fp);
537 sscanf(line, "%f %f", tp->u, tp->u + 1);
540 static void read_vn(struct s_base *fp, const char *line)
542 struct b_side *sp = fp->sv + incs(fp);
544 sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
547 static void read_v(struct s_base *fp, const char *line)
549 struct b_vert *vp = fp->vv + incv(fp);
551 sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
554 static void read_f(struct s_base *fp, const char *line,
555 int v0, int t0, int s0, int mi)
557 struct b_geom *gp = fp->gv + incg(fp);
562 sscanf(line, "%d%c%d%c%d %d%c%d%c%d %d%c%d%c%d",
563 &gp->vi, &c1, &gp->ti, &c2, &gp->si,
564 &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
565 &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
580 static void read_obj(struct s_base *fp, const char *name, int mi)
590 if ((fin = fs_open(name, "r")))
592 while (fs_gets(line, MAXSTR, fin))
594 if (strncmp(line, "usemtl", 6) == 0)
596 sscanf(line + 6, "%s", mtrl);
597 mi = read_mtrl(fp, mtrl);
600 else if (strncmp(line, "f", 1) == 0)
602 if (fp->mv[mi].d[3] > 0.0f)
603 read_f(fp, line + 1, v0, t0, s0, mi);
606 else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
607 else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
608 else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
614 /*---------------------------------------------------------------------------*/
616 static float plane_d[MAXS];
617 static float plane_n[MAXS][3];
618 static float plane_p[MAXS][3];
619 static float plane_u[MAXS][3];
620 static float plane_v[MAXS][3];
621 static int plane_f[MAXS];
622 static int plane_m[MAXS];
624 static void make_plane(int pi, float x0, float y0, float z0,
625 float x1, float y1, float z1,
626 float x2, float y2, float z2,
627 float tu, float tv, float r,
628 float su, float sv, int fl, const char *s)
630 static const float base[6][3][3] = {
631 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, 1, 0 }},
632 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, 1, 0 }},
633 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, 1, 0 }},
634 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, 1, 0 }},
635 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, -1 }},
636 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, -1 }},
640 float p0[3], p1[3], p2[3];
641 float u[3], v[3], p[3];
646 size_image(s, &w, &h);
648 plane_f[pi] = fl ? L_DETAIL : 0;
665 v_crs(plane_n[pi], u, v);
666 v_nrm(plane_n[pi], plane_n[pi]);
668 plane_d[pi] = v_dot(plane_n[pi], p1);
670 for (i = 0; i < 6; i++)
671 if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
681 /* Always rotate around the positive axis */
683 m_rot(R, base[n - (n % 2)][0], V_RAD(r));
685 v_mad(p, p, base[n][1], +su * tu / SCALE);
686 v_mad(p, p, base[n][2], -sv * tv / SCALE);
688 m_vxfm(plane_u[pi], R, base[n][1]);
689 m_vxfm(plane_v[pi], R, base[n][2]);
690 m_vxfm(plane_p[pi], R, p);
692 v_scl(plane_u[pi], plane_u[pi], 64.f / w);
693 v_scl(plane_v[pi], plane_v[pi], 64.f / h);
695 v_scl(plane_u[pi], plane_u[pi], 1.f / su);
696 v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
699 /*---------------------------------------------------------------------------*/
708 static int map_token(fs_file fin, int pi, char key[MAXSTR], char val[MAXSTR])
712 if (fs_gets(buf, MAXSTR, fin))
722 /* Scan the beginning or end of a block. */
724 if (buf[0] == '{') return T_BEG;
725 if (buf[0] == '}') return T_END;
727 /* Scan a key-value pair. */
731 strcpy(key, strtok(buf, "\""));
732 (void) strtok(NULL, "\"");
733 strcpy(val, strtok(NULL, "\""));
744 "%s %f %f %f %f %f %d",
745 &c, &x0, &y0, &z0, &c,
746 &c, &x1, &y1, &z1, &c,
747 &c, &x2, &y2, &z2, &c,
748 key, &tu, &tv, &r, &su, &sv, &fl) == 22)
750 make_plane(pi, x0, y0, z0,
753 tu, tv, r, su, sv, fl, key);
757 /* If it's not recognized, it must be uninteresting. */
764 /*---------------------------------------------------------------------------*/
766 /* Parse a lump from the given file and add it to the solid. */
768 static void read_lump(struct s_base *fp, fs_file fin)
774 struct b_lump *lp = fp->lv + incl(fp);
778 while ((t = map_token(fin, fp->sc, k, v)))
782 fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
783 fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
784 fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
785 fp->sv[fp->sc].d = plane_d[fp->sc];
787 plane_m[fp->sc] = read_mtrl(fp, k);
789 fp->iv[fp->ic] = fp->sc;
799 /*---------------------------------------------------------------------------*/
801 static void make_path(struct s_base *fp,
803 char v[][MAXSTR], int c)
805 int i, pi = incp(fp);
807 struct b_path *pp = fp->pv + pi;
817 for (i = 0; i < c; i++)
819 if (strcmp(k[i], "targetname") == 0)
822 if (strcmp(k[i], "target") == 0)
823 make_ref(v[i], &pp->pi);
825 if (strcmp(k[i], "state") == 0)
828 if (strcmp(k[i], "speed") == 0)
829 sscanf(v[i], "%f", &pp->t);
831 if (strcmp(k[i], "smooth") == 0)
834 if (strcmp(k[i], "origin") == 0)
836 float x = 0.f, y = 0.f, z = 0.f;
838 sscanf(v[i], "%f %f %f", &x, &y, &z);
840 pp->p[0] = +x / SCALE;
841 pp->p[1] = +z / SCALE;
842 pp->p[2] = -y / SCALE;
846 * Radiant sets "angle" for yaw-only rotations, "angles"
847 * otherwise. Angles takes priority, so check for angle
851 if (strcmp(k[i], "angle") == 0)
853 static const float Y[3] = { 0.0f, 1.0f, 0.0f };
859 sscanf(v[i], "%f", &y);
860 q_by_axisangle(pp->e, Y, V_RAD(+y));
861 pp->fl |= P_ORIENTED;
864 if (strcmp(k[i], "angles") == 0)
866 static const float X[3] = { 1.0f, 0.0f, 0.0f };
867 static const float Y[3] = { 0.0f, 1.0f, 0.0f };
868 static const float Z[3] = { 0.0f, 0.0f, 1.0f };
870 float x = 0.0f, y = 0.0f, z = 0.0f;
873 /* Pitch, yaw and roll. */
875 sscanf(v[i], "%f %f %f", &x, &y, &z);
877 q_by_axisangle(pp->e, Y, V_RAD(+y));
879 q_by_axisangle(d, Z, V_RAD(-x));
883 q_by_axisangle(d, X, V_RAD(+z));
887 pp->fl |= P_ORIENTED;
892 static void make_dict(struct s_base *fp,
896 int space_left, space_needed, di = incd(fp);
898 struct b_dict *dp = fp->dv + di;
900 space_left = MAXA - fp->ac;
901 space_needed = strlen(k) + 1 + strlen(v) + 1;
903 if (space_needed > space_left)
910 dp->aj = dp->ai + strlen(k) + 1;
911 fp->ac = dp->aj + strlen(v) + 1;
913 strncpy(fp->av + dp->ai, k, space_left);
914 strncpy(fp->av + dp->aj, v, space_left - strlen(k) - 1);
917 static int read_dict_entries = 0;
919 static void make_body(struct s_base *fp,
921 char v[][MAXSTR], int c, int l0)
923 int i, mi = 0, bi = incb(fp);
934 struct b_body *bp = fp->bv + bi;
939 for (i = 0; i < c; i++)
941 if (strcmp(k[i], "targetname") == 0)
944 else if (strcmp(k[i], "target") == 0)
945 make_ref(v[i], &bp->pi);
947 else if (strcmp(k[i], "material") == 0)
948 mi = read_mtrl(fp, v[i]);
950 else if (strcmp(k[i], "model") == 0)
951 read_obj(fp, v[i], mi);
953 else if (strcmp(k[i], "origin") == 0)
954 sscanf(v[i], "%f %f %f", &x, &y, &z);
956 else if (read_dict_entries && strcmp(k[i], "classname") != 0)
957 make_dict(fp, k[i], v[i]);
961 bp->lc = fp->lc - l0;
963 bp->gc = fp->gc - g0;
965 for (i = 0; i < bp->gc; i++)
966 fp->iv[inci(fp)] = g0++;
972 for (i = v0; i < fp->vc; i++)
973 v_add(fp->vv[i].p, fp->vv[i].p, p);
975 read_dict_entries = 0;
978 static void make_item(struct s_base *fp,
980 char v[][MAXSTR], int c)
982 int i, hi = inch(fp);
984 struct b_item *hp = fp->hv + hi;
993 for (i = 0; i < c; i++)
995 if (strcmp(k[i], "classname") == 0)
997 if (strcmp(v[i], "light") == 0)
999 else if (strcmp(v[i], "item_health_large") == 0)
1001 else if (strcmp(v[i], "item_health_small") == 0)
1002 hp->t = ITEM_SHRINK;
1005 if (strcmp(k[i], "light") == 0)
1006 sscanf(v[i], "%d", &hp->n);
1008 if (strcmp(k[i], "origin") == 0)
1010 float x = 0.f, y = 0.f, z = 0.f;
1012 sscanf(v[i], "%f %f %f", &x, &y, &z);
1014 hp->p[0] = +x / SCALE;
1015 hp->p[1] = +z / SCALE;
1016 hp->p[2] = -y / SCALE;
1021 static void make_bill(struct s_base *fp,
1023 char v[][MAXSTR], int c)
1025 int i, ri = incr(fp);
1027 struct b_bill *rp = fp->rv + ri;
1029 memset(rp, 0, sizeof (struct b_bill));
1032 for (i = 0; i < c; i++)
1034 if (strcmp(k[i], "width") == 0)
1035 sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
1036 if (strcmp(k[i], "height") == 0)
1037 sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
1039 if (strcmp(k[i], "xrot") == 0)
1040 sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
1041 if (strcmp(k[i], "yrot") == 0)
1042 sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
1043 if (strcmp(k[i], "zrot") == 0)
1044 sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
1046 if (strcmp(k[i], "time") == 0)
1047 sscanf(v[i], "%f", &rp->t);
1048 if (strcmp(k[i], "dist") == 0)
1049 sscanf(v[i], "%f", &rp->d);
1050 if (strcmp(k[i], "flag") == 0)
1051 sscanf(v[i], "%d", &rp->fl);
1053 if (strcmp(k[i], "image") == 0)
1055 rp->mi = read_mtrl(fp, v[i]);
1056 fp->mv[rp->mi].fl |= M_CLAMPED;
1059 if (strcmp(k[i], "origin") == 0)
1061 float x = 0.f, y = 0.f, z = 0.f;
1063 sscanf(v[i], "%f %f %f", &x, &y, &z);
1065 rp->p[0] = +x / SCALE;
1066 rp->p[1] = +z / SCALE;
1067 rp->p[2] = -y / SCALE;
1071 if (rp->fl & B_ADDITIVE)
1072 fp->mv[rp->mi].fl |= M_ADDITIVE;
1075 static void make_goal(struct s_base *fp,
1077 char v[][MAXSTR], int c)
1079 int i, zi = incz(fp);
1081 struct b_goal *zp = fp->zv + zi;
1088 for (i = 0; i < c; i++)
1090 if (strcmp(k[i], "radius") == 0)
1091 sscanf(v[i], "%f", &zp->r);
1093 if (strcmp(k[i], "origin") == 0)
1095 float x = 0.f, y = 0.f, z = 0.f;
1097 sscanf(v[i], "%f %f %f", &x, &y, &z);
1099 zp->p[0] = +(x) / SCALE;
1100 zp->p[1] = +(z - 24) / SCALE;
1101 zp->p[2] = -(y) / SCALE;
1106 static void make_view(struct s_base *fp,
1108 char v[][MAXSTR], int c)
1110 int i, wi = incw(fp);
1112 struct b_view *wp = fp->wv + wi;
1121 for (i = 0; i < c; i++)
1123 if (strcmp(k[i], "target") == 0)
1124 make_ref(v[i], targ_wi + wi);
1126 if (strcmp(k[i], "origin") == 0)
1128 float x = 0.f, y = 0.f, z = 0.f;
1130 sscanf(v[i], "%f %f %f", &x, &y, &z);
1132 wp->p[0] = +x / SCALE;
1133 wp->p[1] = +z / SCALE;
1134 wp->p[2] = -y / SCALE;
1139 static void make_jump(struct s_base *fp,
1141 char v[][MAXSTR], int c)
1143 int i, ji = incj(fp);
1145 struct b_jump *jp = fp->jv + ji;
1155 for (i = 0; i < c; i++)
1157 if (strcmp(k[i], "radius") == 0)
1158 sscanf(v[i], "%f", &jp->r);
1160 if (strcmp(k[i], "target") == 0)
1161 make_ref(v[i], targ_ji + ji);
1163 if (strcmp(k[i], "origin") == 0)
1165 float x = 0.f, y = 0.f, z = 0.f;
1167 sscanf(v[i], "%f %f %f", &x, &y, &z);
1169 jp->p[0] = +x / SCALE;
1170 jp->p[1] = +z / SCALE;
1171 jp->p[2] = -y / SCALE;
1176 static void make_swch(struct s_base *fp,
1178 char v[][MAXSTR], int c)
1180 int i, xi = incx(fp);
1182 struct b_swch *xp = fp->xv + xi;
1193 for (i = 0; i < c; i++)
1195 if (strcmp(k[i], "radius") == 0)
1196 sscanf(v[i], "%f", &xp->r);
1198 if (strcmp(k[i], "target") == 0)
1199 make_ref(v[i], &xp->pi);
1201 if (strcmp(k[i], "timer") == 0)
1202 sscanf(v[i], "%f", &xp->t);
1204 if (strcmp(k[i], "state") == 0)
1207 if (strcmp(k[i], "invisible") == 0)
1210 if (strcmp(k[i], "origin") == 0)
1212 float x = 0.f, y = 0.f, z = 0.f;
1214 sscanf(v[i], "%f %f %f", &x, &y, &z);
1216 xp->p[0] = +x / SCALE;
1217 xp->p[1] = +z / SCALE;
1218 xp->p[2] = -y / SCALE;
1223 static void make_targ(struct s_base *fp,
1225 char v[][MAXSTR], int c)
1229 targ_p[targ_n][0] = 0.f;
1230 targ_p[targ_n][1] = 0.f;
1231 targ_p[targ_n][2] = 0.f;
1233 for (i = 0; i < c; i++)
1235 if (strcmp(k[i], "targetname") == 0)
1236 make_sym(v[i], targ_n);
1238 if (strcmp(k[i], "origin") == 0)
1240 float x = 0.f, y = 0.f, z = 0.f;
1242 sscanf(v[i], "%f %f %f", &x, &y, &z);
1244 targ_p[targ_n][0] = +x / SCALE;
1245 targ_p[targ_n][1] = +z / SCALE;
1246 targ_p[targ_n][2] = -y / SCALE;
1253 static void make_ball(struct s_base *fp,
1255 char v[][MAXSTR], int c)
1257 int i, ui = incu(fp);
1259 struct b_ball *up = fp->uv + ui;
1266 for (i = 0; i < c; i++)
1268 if (strcmp(k[i], "radius") == 0)
1269 sscanf(v[i], "%f", &up->r);
1271 if (strcmp(k[i], "origin") == 0)
1273 float x = 0.f, y = 0.f, z = 0.f;
1275 sscanf(v[i], "%f %f %f", &x, &y, &z);
1277 up->p[0] = +(x) / SCALE;
1278 up->p[1] = +(z - 24) / SCALE;
1279 up->p[2] = -(y) / SCALE;
1283 up->p[1] += up->r + SMALL;
1286 /*---------------------------------------------------------------------------*/
1288 static void read_ent(struct s_base *fp, fs_file fin)
1290 char k[MAXKEY][MAXSTR];
1291 char v[MAXKEY][MAXSTR];
1292 int t, i = 0, c = 0;
1296 while ((t = map_token(fin, -1, k[c], v[c])))
1300 if (strcmp(k[c], "classname") == 0)
1304 if (t == T_BEG) read_lump(fp, fin);
1305 if (t == T_END) break;
1308 if (!strcmp(v[i], "light")) make_item(fp, k, v, c);
1309 if (!strcmp(v[i], "item_health_large")) make_item(fp, k, v, c);
1310 if (!strcmp(v[i], "item_health_small")) make_item(fp, k, v, c);
1311 if (!strcmp(v[i], "info_camp")) make_swch(fp, k, v, c);
1312 if (!strcmp(v[i], "info_null")) make_bill(fp, k, v, c);
1313 if (!strcmp(v[i], "path_corner")) make_path(fp, k, v, c);
1314 if (!strcmp(v[i], "info_player_start")) make_ball(fp, k, v, c);
1315 if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1316 if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
1317 if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
1318 if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
1319 if (!strcmp(v[i], "worldspawn"))
1321 read_dict_entries = 1;
1322 make_body(fp, k, v, c, l0);
1324 if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
1325 if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
1328 static void read_map(struct s_base *fp, fs_file fin)
1334 while ((t = map_token(fin, -1, k, v)))
1339 /*---------------------------------------------------------------------------*/
1341 /* Test the location of a point with respect to a side plane. */
1343 static int fore_side(const float p[3], const struct b_side *sp)
1345 return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1348 static int on_side(const float p[3], const struct b_side *sp)
1350 float d = v_dot(p, sp->n) - sp->d;
1352 return (-SMALL < d && d < +SMALL) ? 1 : 0;
1355 /*---------------------------------------------------------------------------*/
1357 * Confirm that the addition of a vert would not result in degenerate
1361 static int ok_vert(const struct s_base *fp,
1362 const struct b_lump *lp, const float p[3])
1367 for (i = 0; i < lp->vc; i++)
1369 float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1373 if (v_len(r) < SMALL)
1379 /*---------------------------------------------------------------------------*/
1382 * The following functions take the set of planes defining a lump and
1383 * find the verts, edges, and geoms that describe its boundaries. To
1384 * do this, they first find the verts, and then search these verts for
1385 * valid edges and geoms. It may be more efficient to compute edges
1386 * and geoms directly by clipping down infinite line segments and
1387 * planes, but this would be more complex and prone to numerical
1392 * Given 3 side planes, compute the point of intersection, if any.
1393 * Confirm that this point falls within the current lump, and that it
1394 * is unique. Add it as a vert of the solid.
1396 static void clip_vert(struct s_base *fp,
1397 struct b_lump *lp, int si, int sj, int sk)
1399 float M[16], X[16], I[16];
1403 d[0] = fp->sv[si].d;
1404 d[1] = fp->sv[sj].d;
1405 d[2] = fp->sv[sk].d;
1407 m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1414 for (i = 0; i < lp->sc; i++)
1416 int si = fp->iv[lp->s0 + i];
1418 if (fore_side(p, fp->sv + si))
1422 if (ok_vert(fp, lp, p))
1424 v_cpy(fp->vv[fp->vc].p, p);
1426 fp->iv[fp->ic] = fp->vc;
1435 * Given two side planes, find an edge along their intersection by
1436 * finding a pair of vertices that fall on both planes. Add it to the
1439 static void clip_edge(struct s_base *fp,
1440 struct b_lump *lp, int si, int sj)
1444 for (i = 1; i < lp->vc; i++)
1446 int vi = fp->iv[lp->v0 + i];
1448 if (!on_side(fp->vv[vi].p, fp->sv + si) ||
1449 !on_side(fp->vv[vi].p, fp->sv + sj))
1452 for (j = 0; j < i; j++)
1454 int vj = fp->iv[lp->v0 + j];
1456 if (on_side(fp->vv[vj].p, fp->sv + si) &&
1457 on_side(fp->vv[vj].p, fp->sv + sj))
1459 fp->ev[fp->ec].vi = vi;
1460 fp->ev[fp->ec].vj = vj;
1462 fp->iv[fp->ic] = fp->ec;
1473 * Find all verts that lie on the given side of the lump. Sort these
1474 * verts to have a counter-clockwise winding about the plane normal.
1475 * Create geoms to tessellate the resulting convex polygon.
1477 static void clip_geom(struct s_base *fp,
1478 struct b_lump *lp, int si)
1480 int m[256], t[256], d, i, j, n = 0;
1485 struct b_side *sp = fp->sv + si;
1489 for (i = 0; i < lp->vc; i++)
1491 int vi = fp->iv[lp->v0 + i];
1493 if (on_side(fp->vv[vi].p, sp))
1498 v_add(v, fp->vv[vi].p, plane_p[si]);
1500 fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1501 fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1509 for (i = 1; i < n; i++)
1510 for (j = i + 1; j < n; j++)
1512 v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1513 v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1516 if (v_dot(w, sp->n) < 0.f)
1530 for (i = 0; i < n - 2; i++)
1532 fp->gv[fp->gc].mi = plane_m[si];
1534 fp->gv[fp->gc].ti = t[0];
1535 fp->gv[fp->gc].tj = t[i + 1];
1536 fp->gv[fp->gc].tk = t[i + 2];
1538 fp->gv[fp->gc].si = si;
1539 fp->gv[fp->gc].sj = si;
1540 fp->gv[fp->gc].sk = si;
1542 fp->gv[fp->gc].vi = m[0];
1543 fp->gv[fp->gc].vj = m[i + 1];
1544 fp->gv[fp->gc].vk = m[i + 2];
1546 fp->iv[fp->ic] = fp->gc;
1554 * Iterate the sides of the lump, attempting to generate a new vert for
1555 * each trio of planes, a new edge for each pair of planes, and a new
1556 * set of geom for each visible plane.
1558 static void clip_lump(struct s_base *fp, struct b_lump *lp)
1565 for (i = 2; i < lp->sc; i++)
1566 for (j = 1; j < i; j++)
1567 for (k = 0; k < j; k++)
1571 fp->iv[lp->s0 + k]);
1576 for (i = 1; i < lp->sc; i++)
1577 for (j = 0; j < i; j++)
1580 fp->iv[lp->s0 + j]);
1585 for (i = 0; i < lp->sc; i++)
1586 if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0.0f)
1588 fp->iv[lp->s0 + i]);
1590 for (i = 0; i < lp->sc; i++)
1591 if (plane_f[fp->iv[lp->s0 + i]])
1595 static void clip_file(struct s_base *fp)
1599 for (i = 0; i < fp->lc; i++)
1600 clip_lump(fp, fp->lv + i);
1603 /*---------------------------------------------------------------------------*/
1606 * For each body element type, determine if element 'p' is equivalent
1607 * to element 'q'. This is more than a simple memory compare. It
1608 * effectively snaps mtrls and verts together, and may reverse the
1609 * winding of an edge or a geom. This is done in order to maximize
1610 * the number of elements that can be eliminated.
1613 static int comp_mtrl(const struct b_mtrl *mp, const struct b_mtrl *mq)
1615 if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1616 if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1617 if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1618 if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1620 if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1621 if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1622 if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1623 if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1625 if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1626 if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1627 if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1628 if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1630 if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1631 if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1632 if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1633 if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1635 if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1637 if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1642 static int comp_vert(const struct b_vert *vp, const struct b_vert *vq)
1644 if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1645 if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1646 if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1651 static int comp_edge(const struct b_edge *ep, const struct b_edge *eq)
1653 if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1654 if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1659 static int comp_side(const struct b_side *sp, const struct b_side *sq)
1661 if (fabs(sp->d - sq->d) > SMALL) return 0;
1662 if (v_dot(sp->n, sq->n) < 0.9999) return 0;
1667 static int comp_texc(const struct b_texc *tp, const struct b_texc *tq)
1669 if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1670 if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1675 static int comp_geom(const struct b_geom *gp, const struct b_geom *gq)
1677 if (gp->mi != gq->mi) return 0;
1679 if (gp->ti != gq->ti) return 0;
1680 if (gp->si != gq->si) return 0;
1681 if (gp->vi != gq->vi) return 0;
1683 if (gp->tj != gq->tj) return 0;
1684 if (gp->sj != gq->sj) return 0;
1685 if (gp->vj != gq->vj) return 0;
1687 if (gp->tk != gq->tk) return 0;
1688 if (gp->sk != gq->sk) return 0;
1689 if (gp->vk != gq->vk) return 0;
1694 /*---------------------------------------------------------------------------*/
1697 * For each file element type, replace all references to element 'i'
1698 * with a reference to element 'j'. These are used when optimizing
1699 * and sorting the file.
1702 static void swap_mtrl(struct s_base *fp, int mi, int mj)
1706 for (i = 0; i < fp->gc; i++)
1707 if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1708 for (i = 0; i < fp->rc; i++)
1709 if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1712 static int vert_swaps[MAXV];
1714 static void apply_vert_swaps(struct s_base *fp)
1718 for (i = 0; i < fp->ec; i++)
1720 fp->ev[i].vi = vert_swaps[fp->ev[i].vi];
1721 fp->ev[i].vj = vert_swaps[fp->ev[i].vj];
1724 for (i = 0; i < fp->gc; i++)
1726 fp->gv[i].vi = vert_swaps[fp->gv[i].vi];
1727 fp->gv[i].vj = vert_swaps[fp->gv[i].vj];
1728 fp->gv[i].vk = vert_swaps[fp->gv[i].vk];
1731 for (i = 0; i < fp->lc; i++)
1732 for (j = 0; j < fp->lv[i].vc; j++)
1733 fp->iv[fp->lv[i].v0 + j] = vert_swaps[fp->iv[fp->lv[i].v0 + j]];
1736 static void swap_vert(struct s_base *fp, int vi, int vj)
1740 for (i = 0; i < fp->ec; i++)
1742 if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1743 if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1746 for (i = 0; i < fp->gc; i++)
1748 if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1749 if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1750 if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1753 for (i = 0; i < fp->lc; i++)
1754 for (j = 0; j < fp->lv[i].vc; j++)
1755 if (fp->iv[fp->lv[i].v0 + j] == vi)
1756 fp->iv[fp->lv[i].v0 + j] = vj;
1759 static int edge_swaps[MAXE];
1761 static void apply_edge_swaps(struct s_base *fp)
1765 for (i = 0; i < fp->lc; i++)
1766 for (j = 0; j < fp->lv[i].ec; j++)
1767 fp->iv[fp->lv[i].e0 + j] = edge_swaps[fp->iv[fp->lv[i].e0 + j]];
1770 static int side_swaps[MAXS];
1772 static void apply_side_swaps(struct s_base *fp)
1776 for (i = 0; i < fp->gc; i++)
1778 fp->gv[i].si = side_swaps[fp->gv[i].si];
1779 fp->gv[i].sj = side_swaps[fp->gv[i].sj];
1780 fp->gv[i].sk = side_swaps[fp->gv[i].sk];
1782 for (i = 0; i < fp->nc; i++)
1783 fp->nv[i].si = side_swaps[fp->nv[i].si];
1785 for (i = 0; i < fp->lc; i++)
1786 for (j = 0; j < fp->lv[i].sc; j++)
1787 fp->iv[fp->lv[i].s0 + j] = side_swaps[fp->iv[fp->lv[i].s0 + j]];
1790 static int texc_swaps[MAXT];
1792 static void apply_texc_swaps(struct s_base *fp)
1796 for (i = 0; i < fp->gc; i++)
1798 fp->gv[i].ti = texc_swaps[fp->gv[i].ti];
1799 fp->gv[i].tj = texc_swaps[fp->gv[i].tj];
1800 fp->gv[i].tk = texc_swaps[fp->gv[i].tk];
1804 static int geom_swaps[MAXG];
1806 static void apply_geom_swaps(struct s_base *fp)
1810 for (i = 0; i < fp->lc; i++)
1811 for (j = 0; j < fp->lv[i].gc; j++)
1812 fp->iv[fp->lv[i].g0 + j] = geom_swaps[fp->iv[fp->lv[i].g0 + j]];
1814 for (i = 0; i < fp->bc; i++)
1815 for (j = 0; j < fp->bv[i].gc; j++)
1816 fp->iv[fp->bv[i].g0 + j] = geom_swaps[fp->iv[fp->bv[i].g0 + j]];
1819 /*---------------------------------------------------------------------------*/
1821 static void uniq_mtrl(struct s_base *fp)
1825 for (i = 0; i < fp->mc; i++)
1827 for (j = 0; j < k; j++)
1828 if (comp_mtrl(fp->mv + i, fp->mv + j))
1830 swap_mtrl(fp, i, j);
1838 fp->mv[k] = fp->mv[i];
1839 swap_mtrl(fp, i, k);
1848 static void uniq_vert(struct s_base *fp)
1852 for (i = 0; i < fp->vc; i++)
1854 for (j = 0; j < k; j++)
1855 if (comp_vert(fp->vv + i, fp->vv + j))
1863 fp->vv[k] = fp->vv[i];
1868 apply_vert_swaps(fp);
1873 static void uniq_edge(struct s_base *fp)
1877 for (i = 0; i < fp->ec; i++)
1879 for (j = 0; j < k; j++)
1880 if (comp_edge(fp->ev + i, fp->ev + j))
1888 fp->ev[k] = fp->ev[i];
1893 apply_edge_swaps(fp);
1898 static int geomlist[MAXV];
1899 static int nextgeom[MAXG];
1901 static void uniq_geom(struct s_base *fp)
1905 for (i = 0; i < MAXV; i++)
1908 for (i = 0; i < fp->gc; i++)
1910 int key = fp->gv[i].vj;
1912 for (j = geomlist[key]; j != -1; j = nextgeom[j])
1913 if (comp_geom(fp->gv + i, fp->gv + j))
1916 fp->gv[k] = fp->gv[i];
1918 nextgeom[k] = geomlist[key];
1928 apply_geom_swaps(fp);
1933 static void uniq_texc(struct s_base *fp)
1937 for (i = 0; i < fp->tc; i++)
1939 for (j = 0; j < k; j++)
1940 if (comp_texc(fp->tv + i, fp->tv + j))
1948 fp->tv[k] = fp->tv[i];
1953 apply_texc_swaps(fp);
1958 static void uniq_side(struct s_base *fp)
1962 for (i = 0; i < fp->sc; i++)
1964 for (j = 0; j < k; j++)
1965 if (comp_side(fp->sv + i, fp->sv + j))
1973 fp->sv[k] = fp->sv[i];
1978 apply_side_swaps(fp);
1983 static void uniq_file(struct s_base *fp)
1985 /* Debug mode skips optimization, producing oversized output files. */
1987 if (debug_output == 0)
1998 /*---------------------------------------------------------------------------*/
2008 static int comp_trip(const void *p, const void *q)
2010 const struct b_trip *tp = (const struct b_trip *) p;
2011 const struct b_trip *tq = (const struct b_trip *) q;
2013 if (tp->vi < tq->vi) return -1;
2014 if (tp->vi > tq->vi) return +1;
2015 if (tp->mi < tq->mi) return -1;
2016 if (tp->mi > tq->mi) return +1;
2021 static void smth_file(struct s_base *fp)
2023 struct b_trip temp, *T;
2025 if (debug_output == 0)
2027 if ((T = (struct b_trip *) malloc(fp->gc * 3 * sizeof (struct b_trip))))
2029 int gi, i, j, k, l, c = 0;
2031 /* Create a list of all non-faceted vertex triplets. */
2033 for (gi = 0; gi < fp->gc; ++gi)
2035 struct b_geom *gp = fp->gv + gi;
2056 /* Sort all triplets by vertex index and material. */
2058 qsort(T, c, sizeof (struct b_trip), comp_trip);
2060 /* For each set of triplets sharing vertex index and material... */
2062 for (i = 0; i < c; i = l)
2066 float N[3], angle = fp->mv[T[i].mi].angle;
2067 const float *Ni = fp->sv[T[i].si].n;
2069 /* Sort the set by side similarity to the first. */
2071 for (j = i + 1; j < c && (T[j].vi == T[i].vi &&
2072 T[j].mi == T[i].mi); ++j)
2074 for (k = j + 1; k < c && (T[k].vi == T[i].vi &&
2075 T[k].mi == T[i].mi); ++k)
2077 const float *Nj = fp->sv[T[j].si].n;
2078 const float *Nk = fp->sv[T[k].si].n;
2080 if (T[j].si != T[k].si && v_dot(Nk, Ni) > v_dot(Nj, Ni))
2089 /* Accumulate all similar side normals. */
2095 for (l = i + 1; l < c && (T[l].vi == T[i].vi &&
2096 T[l].mi == T[i].mi); ++l)
2097 if (T[l].si != T[i].si)
2099 const float *Nl = fp->sv[T[l].si].n;
2101 if (V_DEG(facosf(v_dot(Ni, Nl))) > angle)
2111 /* If at least two normals have been accumulated... */
2115 /* Store the accumulated normal as a new side. */
2119 v_nrm(fp->sv[ss].n, N);
2120 fp->sv[ss].d = 0.0f;
2122 /* Assign the new normal to the merged triplets. */
2124 for (j = i; j < l; ++j)
2129 /* Assign the remapped normals to the original geoms. */
2131 for (i = 0; i < c; ++i)
2133 struct b_geom *gp = fp->gv + T[i].gi;
2135 if (gp->vi == T[i].vi) gp->si = T[i].si;
2136 if (gp->vj == T[i].vi) gp->sj = T[i].si;
2137 if (gp->vk == T[i].vi) gp->sk = T[i].si;
2148 /*---------------------------------------------------------------------------*/
2150 static void sort_file(struct s_base *fp)
2154 /* Sort billboards by material within distance. */
2156 for (i = 0; i < fp->rc; i++)
2157 for (j = i + 1; j < fp->rc; j++)
2158 if ((fp->rv[j].d > fp->rv[i].d) ||
2159 (fp->rv[j].d == fp->rv[i].d &&
2160 fp->rv[j].mi > fp->rv[i].mi))
2165 fp->rv[i] = fp->rv[j];
2169 /* Ensure the first vertex is the lowest. */
2171 for (i = 0; i < fp->vc; i++)
2172 if (fp->vv[0].p[1] > fp->vv[i].p[1])
2177 fp->vv[0] = fp->vv[i];
2180 swap_vert(fp, 0, -1);
2181 swap_vert(fp, i, 0);
2182 swap_vert(fp, -1, i);
2186 /*---------------------------------------------------------------------------*/
2188 static int test_lump_side(const struct s_base *fp,
2189 const struct b_lump *lp,
2190 const struct b_side *sp,
2204 /* Check if the bounding sphere of the lump is completely on one side. */
2206 d = v_dot(bsphere, sp->n) - sp->d;
2208 if (fabs(d) > bsphere[3])
2209 return d > 0 ? 1 : -1;
2211 /* If the given side is part of the given lump, then the lump is behind. */
2213 for (si = 0; si < lp->sc; si++)
2214 if (fp->sv + fp->iv[lp->s0 + si] == sp)
2217 /* Check if each lump vertex is in front of, behind, on the side. */
2219 for (vi = 0; vi < lp->vc; vi++)
2221 float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
2227 /* If no verts are behind, the lump is in front, and vice versa. */
2229 if (f > 0 && b == 0) return +1;
2230 if (b > 0 && f == 0) return -1;
2232 /* Else, the lump crosses the side. */
2237 static int node_node(struct s_base *fp, int l0, int lc, float bsphere[][4])
2241 /* Base case. Dump all given lumps into a leaf node. */
2243 fp->nv[fp->nc].si = -1;
2244 fp->nv[fp->nc].ni = -1;
2245 fp->nv[fp->nc].nj = -1;
2246 fp->nv[fp->nc].l0 = l0;
2247 fp->nv[fp->nc].lc = lc;
2257 int li = 0, lic = 0;
2258 int lj = 0, ljc = 0;
2259 int lk = 0, lkc = 0;
2262 /* Find the side that most evenly splits the given lumps. */
2264 for (si = 0; si < fp->sc; si++)
2270 for (li = 0; li < lc; li++)
2271 if ((k = test_lump_side(fp,
2281 if ((d < sjd) || (d == sjd && o < sjo))
2289 /* Flag each lump with its position WRT the side. */
2291 for (li = 0; li < lc; li++)
2294 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2298 switch (test_lump_side(fp,
2304 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10;
2308 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
2312 fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40;
2317 /* Sort all lumps in the range by their flag values. */
2319 for (li = 1; li < lc; li++)
2320 for (lj = 0; lj < li; lj++)
2321 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
2327 for (i = 0; i < 4; i++)
2329 f = bsphere[l0 + li][i];
2330 bsphere[l0 + li][i] = bsphere[l0 + lj][i];
2331 bsphere[l0 + lj][i] = f;
2334 l = fp->lv[l0 + li];
2335 fp->lv[l0 + li] = fp->lv[l0 + lj];
2336 fp->lv[l0 + lj] = l;
2339 /* Establish the in-front, on, and behind lump ranges. */
2345 for (i = lc - 1; i >= 0; i--)
2346 switch (fp->lv[l0 + i].fl & 0xf0)
2348 case 0x10: li = l0 + i; lic++; break;
2349 case 0x20: lj = l0 + i; ljc++; break;
2350 case 0x40: lk = l0 + i; lkc++; break;
2353 /* Add the lumps on the side to the node. */
2358 fp->nv[i].ni = node_node(fp, li, lic, bsphere);
2360 fp->nv[i].nj = node_node(fp, lk, lkc, bsphere);
2369 * Compute a bounding sphere for a lump (not optimal)
2371 static void lump_bounding_sphere(struct s_base *fp,
2382 bbox[0] = bbox[3] = fp->vv[fp->iv[lp->v0]].p[0];
2383 bbox[1] = bbox[4] = fp->vv[fp->iv[lp->v0]].p[1];
2384 bbox[2] = bbox[5] = fp->vv[fp->iv[lp->v0]].p[2];
2386 for (i = 1; i < lp->vc; i++)
2388 struct b_vert *vp = fp->vv + fp->iv[lp->v0 + i];
2391 for (j = 0; j < 3; j++)
2392 if (vp->p[j] < bbox[j])
2395 for (j = 0; j < 3; j++)
2396 if (vp->p[j] > bbox[j + 3])
2397 bbox[j + 3] = vp->p[j];
2402 for (i = 0; i < 3; i++)
2404 bsphere[i] = (bbox[i] + bbox[i + 3]) / 2;
2405 r += (bsphere[i] - bbox[i]) * (bsphere[i] - bbox[i]);
2408 bsphere[3] = fsqrtf(r);
2411 static void node_file(struct s_base *fp)
2413 float bsphere[MAXL][4];
2416 /* Compute a bounding sphere for each lump. */
2418 for (i = 0; i < fp->lc; i++)
2419 lump_bounding_sphere(fp, fp->lv + i, bsphere[i]);
2421 /* Sort the lumps of each body into BSP nodes. */
2423 for (i = 0; i < fp->bc; i++)
2424 fp->bv[i].ni = node_node(fp, fp->bv[i].l0, fp->bv[i].lc, bsphere);
2427 /*---------------------------------------------------------------------------*/
2429 static void dump_file(struct s_base *p, const char *name)
2436 /* Count the number of solid lumps. */
2438 for (i = 0; i < p->lc; i++)
2439 if ((p->lv[i].fl & 1) == 0)
2442 /* Count the number of visible geoms. */
2444 m = p->rc + (p->zc + p->jc + p->xc) * 32;
2446 for (i = 0; i < p->hc; i++)
2447 if (p->hv[i].t == ITEM_COIN)
2452 for (i = 0; i < p->bc; i++)
2454 for (j = 0; j < p->bv[i].lc; j++)
2455 m += p->lv[p->bv[i].l0 + j].gc;
2459 /* Count the total value of all coins. */
2461 for (i = 0; i < p->hc; i++)
2462 if (p->hv[i].t == ITEM_COIN)
2465 printf("%s (%d/%d/$%d)\n"
2466 " mtrl vert edge side texc"
2467 " geom lump path node body\n"
2468 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
2469 " item goal view jump swch"
2470 " bill ball char dict indx\n"
2471 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
2473 p->mc, p->vc, p->ec, p->sc, p->tc,
2474 p->gc, p->lc, p->pc, p->nc, p->bc,
2475 p->hc, p->zc, p->wc, p->jc, p->xc,
2476 p->rc, p->uc, p->ac, p->dc, p->ic);
2479 int main(int argc, char *argv[])
2481 char src[MAXSTR] = "";
2482 char dst[MAXSTR] = "";
2486 if (!fs_init(argv[0]))
2488 fprintf(stderr, "Failure to initialize virtual file system: %s\n",
2493 verbose = !!getenv("MAPC_VERBOSE");
2497 input_file = argv[1];
2499 if (argc > 3 && strcmp(argv[3], "--debug") == 0)
2502 strncpy(src, argv[1], MAXSTR - 1);
2503 strncpy(dst, argv[1], MAXSTR - 1);
2505 if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
2506 strcpy(dst + strlen(dst) - 4, ".sol");
2508 strcat(dst, ".sol");
2510 fs_add_path (dir_name(src));
2511 fs_set_write_dir(dir_name(dst));
2513 if ((fin = fs_open(base_name(src), "r")))
2515 if (!fs_add_path_with_archives(argv[2]))
2517 fprintf(stderr, "Failure to establish data directory\n");
2537 sol_stor_base(&f, base_name(dst));
2544 else fprintf(stderr, "Usage: %s <map> <data> [--debug]\n", argv[0]);