Import from neverball-1.2.6-9.tar.gz
[neverball-archive.git] / share / mapc.c
blob8c836a73428a6f973a4c167a341fd52b12b2b320
1 /*
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 /*---------------------------------------------------------------------------*/
17 #ifdef WIN32
18 #pragma comment(lib, "SDL_image.lib")
19 #pragma comment(lib, "SDL.lib")
20 #pragma comment(lib, "SDLmain.lib")
21 #pragma comment(lib, "glu32.lib")
22 #pragma comment(lib, "opengl32.lib")
23 #endif
25 /*---------------------------------------------------------------------------*/
27 #include <SDL.h>
28 #include <SDL_image.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
34 #include "glext.h"
35 #include "vec3.h"
36 #include "solid.h"
38 #define MAXSTR 256
39 #define MAXKEY 16
40 #define SCALE 64.f
41 #define SMALL 0.0005f
43 static char path[MAXSTR];
44 static char src[MAXSTR];
45 static char dst[MAXSTR];
48 * The overall design of this map converter is very stupid, but very
49 * simple. It begins by assuming that every mtrl, vert, edge, side,
50 * and texc in the map is unique. It then makes an optimizing pass
51 * that discards redundant information. The result is optimal, though
52 * the process is terribly inefficient.
55 /*---------------------------------------------------------------------------*/
57 /* Ohhhh... arbitrary! */
59 #define MAXM 256
60 #define MAXV 32768
61 #define MAXE 32768
62 #define MAXS 32768
63 #define MAXT 32768
64 #define MAXG 32768
65 #define MAXL 1024
66 #define MAXN 1024
67 #define MAXP 512
68 #define MAXB 512
69 #define MAXC 1024
70 #define MAXZ 16
71 #define MAXJ 32
72 #define MAXX 16
73 #define MAXR 256
74 #define MAXU 16
75 #define MAXW 32
76 #define MAXA 512
77 #define MAXI 32768
79 static void init_file(struct s_file *fp)
81 fp->mc = 0;
82 fp->vc = 0;
83 fp->ec = 0;
84 fp->sc = 0;
85 fp->tc = 0;
86 fp->gc = 0;
87 fp->lc = 0;
88 fp->nc = 0;
89 fp->pc = 0;
90 fp->bc = 0;
91 fp->cc = 0;
92 fp->zc = 0;
93 fp->jc = 0;
94 fp->xc = 0;
95 fp->rc = 0;
96 fp->uc = 0;
97 fp->wc = 0;
98 fp->ac = 0;
99 fp->ic = 0;
101 fp->mv = (struct s_mtrl *) calloc(MAXM, sizeof (struct s_mtrl));
102 fp->vv = (struct s_vert *) calloc(MAXV, sizeof (struct s_vert));
103 fp->ev = (struct s_edge *) calloc(MAXE, sizeof (struct s_edge));
104 fp->sv = (struct s_side *) calloc(MAXS, sizeof (struct s_side));
105 fp->tv = (struct s_texc *) calloc(MAXT, sizeof (struct s_texc));
106 fp->gv = (struct s_geom *) calloc(MAXG, sizeof (struct s_geom));
107 fp->lv = (struct s_lump *) calloc(MAXL, sizeof (struct s_lump));
108 fp->nv = (struct s_node *) calloc(MAXN, sizeof (struct s_node));
109 fp->pv = (struct s_path *) calloc(MAXP, sizeof (struct s_path));
110 fp->bv = (struct s_body *) calloc(MAXB, sizeof (struct s_body));
111 fp->cv = (struct s_coin *) calloc(MAXC, sizeof (struct s_coin));
112 fp->zv = (struct s_goal *) calloc(MAXZ, sizeof (struct s_goal));
113 fp->jv = (struct s_jump *) calloc(MAXJ, sizeof (struct s_jump));
114 fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
115 fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
116 fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
117 fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
118 fp->av = (char *) calloc(MAXA, sizeof (char));
119 fp->iv = (short *) calloc(MAXI, sizeof (short));
122 /*---------------------------------------------------------------------------*/
124 static void strapp(char *dest,
125 const char *path,
126 const char *root,
127 const char *extn, size_t n)
129 size_t p = strlen(path);
130 size_t r = strlen(path);
132 strncpy(dest, path, n - 1);
133 strncat(dest, "/", n - p - 1);
134 strncat(dest, root, n - p - 2);
135 strncat(dest, extn, n - p - r - 2);
138 /*---------------------------------------------------------------------------*/
141 * The following is a small symbol table data structure. Symbols and
142 * their integer values are collected in symv and valv. References
143 * and pointers to their unsatisfied integer values are collected in
144 * refv and pntv. The resolve procedure matches references to symbols
145 * and fills waiting ints with the proper values.
148 #define MAXSYM 1024
150 static char symv[MAXSYM][MAXSTR];
151 static short valv[MAXSYM];
153 static char refv[MAXSYM][MAXSTR];
154 static short *pntv[MAXSYM];
156 static int strc;
157 static int refc;
159 static void make_sym(const char *s, short v)
161 strncpy(symv[strc], s, MAXSTR - 1);
162 valv[strc] = v;
163 strc++;
166 static void make_ref(const char *r, short *p)
168 strncpy(refv[refc], r, MAXSTR - 1);
169 pntv[refc] = p;
170 refc++;
173 static void resolve(void)
175 int i, j;
177 for (i = 0; i < refc; i++)
178 for (j = 0; j < strc; j++)
179 if (strncmp(refv[i], symv[j], MAXSTR) == 0)
181 *(pntv[i]) = valv[j];
182 break;
186 /*---------------------------------------------------------------------------*/
189 * The following globals are used to cache target_positions. They are
190 * targeted by various entities and must be resolved in a second pass.
193 static float targ_p [MAXW][3];
194 static short targ_wi[MAXW];
195 static short targ_ji[MAXW];
196 static short targ_n;
198 static void targets(struct s_file *fp)
200 short i;
202 for (i = 0; i < fp->wc; i++)
203 v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
205 for (i = 0; i < fp->jc; i++)
206 v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
209 /*---------------------------------------------------------------------------*/
212 * The following code caches image sizes. Textures are referenced by
213 * name, but their sizes are necessary when computing texture
214 * coordinates. This code allows each file to be accessed only once
215 * regardless of the number of surfaces refering to it.
218 static char *image_s[MAXM];
219 static int image_w[MAXM];
220 static int image_h[MAXM];
221 static int image_n;
223 static int size_load(const char *file, int *w, int *h)
225 SDL_Surface *S;
227 if ((S = IMG_Load(file)))
229 *w = S->w;
230 *h = S->h;
232 SDL_FreeSurface(S);
234 return 1;
236 return 0;
239 static void size_image(const char *name, int *w, int *h)
241 char jpg[MAXSTR];
242 char tga[MAXSTR];
243 char png[MAXSTR];
244 int i;
246 for (i = 0; i < image_n; i++)
247 if (strncmp(image_s[i], name, MAXSTR) == 0)
249 *w = image_w[i];
250 *h = image_h[i];
252 return;
255 *w = 0;
256 *h = 0;
258 strapp(jpg, path, name, ".jpg", MAXSTR);
259 strapp(tga, path, name, ".tga", MAXSTR);
260 strapp(png, path, name, ".png", MAXSTR);
262 if (size_load(png, w, h) || size_load(tga, w, h) || size_load(jpg, w, h))
264 image_s[image_n] = (char *) calloc(strlen(name) + 1, 1);
265 image_w[image_n] = *w;
266 image_h[image_n] = *h;
268 strcpy(image_s[image_n], name);
269 image_n++;
273 /*---------------------------------------------------------------------------*/
275 /* Read the given material file, adding a new material to the solid. */
277 static int read_mtrl(struct s_file *fp, const char *name)
279 struct s_mtrl *mp;
280 FILE *fin;
281 char file[MAXSTR];
282 short mi;
284 strapp(file, path, name, "", MAXSTR);
286 for (mi = 0; mi < fp->mc; mi++)
287 if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
288 return mi;
290 mp = fp->mv + fp->mc++;
292 if ((fin = fopen(file, "r")))
294 fscanf(fin,
295 "%f %f %f %f "
296 "%f %f %f %f "
297 "%f %f %f %f "
298 "%f %f %f %f "
299 "%f %hd ",
300 mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
301 mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
302 mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
303 mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
304 mp->h, &mp->fl);
305 fclose(fin);
307 strncpy(mp->f, name, PATHMAX - 1);
310 return mi;
313 /*---------------------------------------------------------------------------*/
316 * All bodies with an associated path are assumed to be positioned at
317 * the beginning of that path. These bodies must be moved to the
318 * origin in order for their path transforms to behave correctly.
319 * This is how we get away with defining func_trains with no origin
320 * specification.
323 static void move_side(struct s_side *sp, const float p[3])
325 sp->d -= v_dot(sp->n, p);
328 static void move_vert(struct s_vert *vp, const float p[3])
330 v_sub(vp->p, vp->p, p);
333 static void move_lump(struct s_file *fp,
334 struct s_lump *lp, const float p[3])
336 short i;
338 for (i = 0; i < lp->sc; i++)
339 move_side(fp->sv + fp->iv[lp->s0 + i], p);
340 for (i = 0; i < lp->vc; i++)
341 move_vert(fp->vv + fp->iv[lp->v0 + i], p);
344 static void move_body(struct s_file *fp,
345 struct s_body *bp)
347 short i;
349 for (i = 0; i < bp->lc; i++)
350 move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
353 static void move_file(struct s_file *fp)
355 short i;
357 for (i = 0; i < fp->bc; i++)
358 if (fp->bv[i].pi >= 0)
359 move_body(fp, fp->bv + i);
362 /*---------------------------------------------------------------------------*/
364 static void read_vt(struct s_file *fp, const char *line)
366 struct s_texc *tp = fp->tv + fp->tc++;
368 sscanf(line, "%f %f", tp->u, tp->u + 1);
371 static void read_vn(struct s_file *fp, const char *line)
373 struct s_side *sp = fp->sv + fp->sc++;
375 sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
378 static void read_v(struct s_file *fp, const char *line)
380 struct s_vert *vp = fp->vv + fp->vc++;
382 sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
385 static void read_f(struct s_file *fp, const char *line,
386 short v0, short t0, short s0, short mi)
388 struct s_geom *gp = fp->gv + fp->gc++;
390 char c1;
391 char c2;
394 * FIXME: All faces must be triangles and must include a normal
395 * and texture coordinate.
398 sscanf(line, "%hd%c%hd%c%hd %hd%c%hd%c%hd %hd%c%hd%c%hd",
399 &gp->vi, &c1, &gp->ti, &c2, &gp->si,
400 &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
401 &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
403 gp->vi += (v0 - 1);
404 gp->vj += (v0 - 1);
405 gp->vk += (v0 - 1);
406 gp->ti += (t0 - 1);
407 gp->tj += (t0 - 1);
408 gp->tk += (t0 - 1);
409 gp->si += (s0 - 1);
410 gp->sj += (s0 - 1);
411 gp->sk += (s0 - 1);
413 gp->mi = mi;
416 static void read_obj(struct s_file *fp, const char *name)
418 char file[MAXSTR];
419 char line[MAXSTR];
420 char mtrl[MAXSTR];
421 FILE *fin;
423 short v0 = fp->vc;
424 short t0 = fp->tc;
425 short s0 = fp->sc;
426 short mi = 0;
428 strapp(file, path, name, "", MAXSTR);
430 if ((fin = fopen(file, "r")))
432 while (fgets(line, MAXSTR, fin))
434 if (strncmp(line, "usemtl", 6) == 0)
436 sscanf(line + 6, "%s", mtrl);
437 mi = read_mtrl(fp, mtrl);
440 else if (strncmp(line, "f", 1) == 0)
442 if (fp->mv[mi].d[3] > 0)
443 read_f(fp, line + 1, v0, t0, s0, mi);
446 else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
447 else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
448 else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
450 fclose(fin);
454 /*---------------------------------------------------------------------------*/
456 static float plane_d[MAXS];
457 static float plane_n[MAXS][3];
458 static float plane_p[MAXS][3];
459 static float plane_u[MAXS][3];
460 static float plane_v[MAXS][3];
461 static short plane_f[MAXS];
462 static short plane_m[MAXS];
464 static void make_plane(short pi, short x0, short y0, short z0,
465 short x1, short y1, short z1,
466 short x2, short y2, short z2,
467 short tu, short tv, short r,
468 float su, float sv, int fl, const char *s)
470 static const float base[6][3][3] = {
471 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
472 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
473 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
474 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
475 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
476 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
479 float R[16];
480 float p0[3], p1[3], p2[3];
481 float u[3], v[3], p[3];
482 float k, d = 0.f;
483 short i, n = 0;
484 int w, h;
486 size_image(s, &w, &h);
488 plane_f[pi] = fl ? L_DETAIL : 0;
490 p0[0] = +(float) x0 / SCALE;
491 p0[1] = +(float) z0 / SCALE;
492 p0[2] = -(float) y0 / SCALE;
494 p1[0] = +(float) x1 / SCALE;
495 p1[1] = +(float) z1 / SCALE;
496 p1[2] = -(float) y1 / SCALE;
498 p2[0] = +(float) x2 / SCALE;
499 p2[1] = +(float) z2 / SCALE;
500 p2[2] = -(float) y2 / SCALE;
502 v_sub(u, p0, p1);
503 v_sub(v, p2, p1);
505 v_crs(plane_n[pi], u, v);
506 v_nrm(plane_n[pi], plane_n[pi]);
508 plane_d[pi] = v_dot(plane_n[pi], p1);
510 for (i = 0; i < 6; i++)
511 if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
513 d = k;
514 n = i;
517 p[0] = 0.f;
518 p[1] = 0.f;
519 p[2] = 0.f;
521 m_rot(R, base[n][0], V_RAD(r));
523 v_mad(p, p, base[n][1], su * tu / SCALE);
524 v_mad(p, p, base[n][2], sv * tv / SCALE);
526 m_vxfm(plane_u[pi], R, base[n][1]);
527 m_vxfm(plane_v[pi], R, base[n][2]);
528 m_vxfm(plane_p[pi], R, p);
530 v_scl(plane_u[pi], plane_u[pi], 64.f / w);
531 v_scl(plane_v[pi], plane_v[pi], 64.f / h);
533 v_scl(plane_u[pi], plane_u[pi], 1.f / su);
534 v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
537 /*---------------------------------------------------------------------------*/
539 #define T_EOF 0
540 #define T_BEG 1
541 #define T_CLP 2
542 #define T_KEY 3
543 #define T_END 4
544 #define T_NOP 5
546 static int map_token(FILE *fin, short pi, char key[MAXSTR], char val[MAXSTR])
548 char buf[MAXSTR];
550 if (fgets(buf, MAXSTR, fin))
552 char c;
553 short x0, y0, z0;
554 short x1, y1, z1;
555 short x2, y2, z2;
556 short tu, tv, r;
557 float su, sv;
558 int fl;
560 /* Scan the beginning or end of a block. */
562 if (buf[0] == '{') return T_BEG;
563 if (buf[0] == '}') return T_END;
565 /* Scan a key-value pair. */
567 if (buf[0] == '"')
569 strcpy(key, strtok(buf, "\""));
570 (void) strtok(NULL, "\"");
571 strcpy(val, strtok(NULL, "\""));
573 return T_KEY;
576 /* Scan a plane. */
578 if (sscanf(buf,
579 "%c %hd %hd %hd %c "
580 "%c %hd %hd %hd %c "
581 "%c %hd %hd %hd %c "
582 "%s %hd %hd %hd %f %f %d",
583 &c, &x0, &y0, &z0, &c,
584 &c, &x1, &y1, &z1, &c,
585 &c, &x2, &y2, &z2, &c,
586 key, &tu, &tv, &r, &su, &sv, &fl) == 22)
588 make_plane(pi, x0, y0, z0,
589 x1, y1, z1,
590 x2, y2, z2,
591 tu, tv, r, su, sv, fl, key);
592 return T_CLP;
595 /* If it's not recognized, it must be uninteresting. */
597 return T_NOP;
599 return T_EOF;
602 /*---------------------------------------------------------------------------*/
604 /* Parse a lump from the given file and add it to the solid. */
606 static void read_lump(struct s_file *fp, FILE *fin)
608 char k[MAXSTR];
609 char v[MAXSTR];
610 int t;
612 struct s_lump *lp = fp->lv + fp->lc++;
614 lp->s0 = fp->ic;
616 while ((t = map_token(fin, fp->sc, k, v)))
618 if (t == T_CLP)
620 fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
621 fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
622 fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
623 fp->sv[fp->sc].d = plane_d[fp->sc];
625 plane_m[fp->sc] = read_mtrl(fp, k);
627 fp->iv[fp->ic] = fp->sc;
628 fp->ic++;
629 fp->sc++;
630 lp->sc++;
632 if (t == T_END)
633 break;
637 /*---------------------------------------------------------------------------*/
639 static void make_path(struct s_file *fp,
640 char k[][MAXSTR],
641 char v[][MAXSTR], short c)
643 short i, pi = fp->pc++;
645 struct s_path *pp = fp->pv + pi;
647 pp->p[0] = 0.f;
648 pp->p[1] = 0.f;
649 pp->p[2] = 0.f;
650 pp->t = 1.f;
651 pp->pi = pi;
652 pp->f = 1;
654 for (i = 0; i < c; i++)
656 if (strcmp(k[i], "targetname") == 0)
657 make_sym(v[i], pi);
659 if (strcmp(k[i], "target") == 0)
660 make_ref(v[i], &pp->pi);
662 if (strcmp(k[i], "state") == 0)
663 pp->f = atoi(v[i]);
665 if (strcmp(k[i], "speed") == 0)
666 sscanf(v[i], "%f", &pp->t);
668 if (strcmp(k[i], "origin") == 0)
670 short x = 0, y = 0, z = 0;
672 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
674 pp->p[0] = +(float) x / SCALE;
675 pp->p[1] = +(float) z / SCALE;
676 pp->p[2] = -(float) y / SCALE;
681 static void make_body(struct s_file *fp,
682 char k[][MAXSTR],
683 char v[][MAXSTR], short c, short l0)
685 short i, bi = fp->bc++;
687 short g0 = fp->gc;
688 short v0 = fp->vc;
690 float p[3];
692 short x = 0;
693 short y = 0;
694 short z = 0;
696 struct s_body *bp = fp->bv + bi;
698 bp->t = 0.f;
699 bp->pi = -1;
700 bp->ni = -1;
702 for (i = 0; i < c; i++)
704 if (strcmp(k[i], "targetname") == 0)
705 make_sym(v[i], bi);
707 if (strcmp(k[i], "target") == 0)
708 make_ref(v[i], &bp->pi);
710 if (strcmp(k[i], "model") == 0)
711 read_obj(fp, v[i]);
713 if (strcmp(k[i], "origin") == 0)
714 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
716 if (strcmp(k[i], "message") == 0)
718 strcpy(fp->av, v[i]);
719 fp->ac = (short) (strlen(v[i]) + 1);
723 bp->l0 = l0;
724 bp->lc = fp->lc - l0;
725 bp->g0 = fp->ic;
726 bp->gc = fp->gc - g0;
728 for (i = 0; i < bp->gc; i++)
729 fp->iv[fp->ic++] = g0++;
731 p[0] = +(float) x / SCALE;
732 p[1] = +(float) z / SCALE;
733 p[2] = -(float) y / SCALE;
735 for (i = v0; i < fp->vc; i++)
736 v_add(fp->vv[i].p, fp->vv[i].p, p);
739 static void make_coin(struct s_file *fp,
740 char k[][MAXSTR],
741 char v[][MAXSTR], short c)
743 short i, ci = fp->cc++;
745 struct s_coin *cp = fp->cv + ci;
747 cp->p[0] = 0.f;
748 cp->p[1] = 0.f;
749 cp->p[2] = 0.f;
750 cp->n = 1;
752 for (i = 0; i < c; i++)
754 if (strcmp(k[i], "light") == 0)
755 sscanf(v[i], "%hd", &cp->n);
757 if (strcmp(k[i], "origin") == 0)
759 short x = 0, y = 0, z = 0;
761 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
763 cp->p[0] = +(float) x / SCALE;
764 cp->p[1] = +(float) z / SCALE;
765 cp->p[2] = -(float) y / SCALE;
770 static void make_bill(struct s_file *fp,
771 char k[][MAXSTR],
772 char v[][MAXSTR], short c)
774 short i, ri = fp->rc++;
776 struct s_bill *rp = fp->rv + ri;
778 rp->p[0] = 0.f;
779 rp->p[1] = 0.f;
780 rp->p[2] = 0.f;
781 rp->w = 1.f;
782 rp->h = 1.f;
783 rp->z = 0.f;
785 for (i = 0; i < c; i++)
787 if (strcmp(k[i], "angle") == 0)
788 sscanf(v[i], "%f", &rp->z);
790 if (strcmp(k[i], "radius") == 0)
792 sscanf(v[i], "%f", &rp->w);
793 sscanf(v[i], "%f", &rp->h);
796 if (strcmp(k[i], "width") == 0)
797 sscanf(v[i], "%f", &rp->w);
799 if (strcmp(k[i], "height") == 0)
800 sscanf(v[i], "%f", &rp->h);
802 if (strcmp(k[i], "image") == 0)
803 rp->mi = read_mtrl(fp, v[i]);
805 if (strcmp(k[i], "origin") == 0)
807 short x = 0, y = 0, z = 0;
809 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
811 rp->p[0] = +(float) x / SCALE;
812 rp->p[1] = +(float) z / SCALE;
813 rp->p[2] = -(float) y / SCALE;
818 static void make_goal(struct s_file *fp,
819 char k[][MAXSTR],
820 char v[][MAXSTR], short c)
822 short i, zi = fp->zc++;
824 struct s_goal *zp = fp->zv + zi;
826 zp->p[0] = 0.f;
827 zp->p[1] = 0.f;
828 zp->p[2] = 0.f;
829 zp->r = 0.75;
831 for (i = 0; i < c; i++)
833 if (strcmp(k[i], "radius") == 0)
834 sscanf(v[i], "%f", &zp->r);
836 if (strcmp(k[i], "origin") == 0)
838 short x = 0, y = 0, z = 0;
840 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
842 zp->p[0] = +(float) (x) / SCALE;
843 zp->p[1] = +(float) (z - 24) / SCALE;
844 zp->p[2] = -(float) (y) / SCALE;
849 static void make_view(struct s_file *fp,
850 char k[][MAXSTR],
851 char v[][MAXSTR], short c)
853 short i, wi = fp->wc++;
855 struct s_view *wp = fp->wv + wi;
857 wp->p[0] = 0.f;
858 wp->p[1] = 0.f;
859 wp->p[2] = 0.f;
860 wp->q[0] = 0.f;
861 wp->q[1] = 0.f;
862 wp->q[2] = 0.f;
864 for (i = 0; i < c; i++)
866 if (strcmp(k[i], "target") == 0)
867 make_ref(v[i], targ_wi + wi);
869 if (strcmp(k[i], "origin") == 0)
871 short x = 0, y = 0, z = 0;
873 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
875 wp->p[0] = +(float) x / SCALE;
876 wp->p[1] = +(float) z / SCALE;
877 wp->p[2] = -(float) y / SCALE;
882 static void make_jump(struct s_file *fp,
883 char k[][MAXSTR],
884 char v[][MAXSTR], short c)
886 short i, ji = fp->jc++;
888 struct s_jump *jp = fp->jv + ji;
890 jp->p[0] = 0.f;
891 jp->p[1] = 0.f;
892 jp->p[2] = 0.f;
893 jp->q[0] = 0.f;
894 jp->q[1] = 0.f;
895 jp->q[2] = 0.f;
896 jp->r = 0.5;
898 for (i = 0; i < c; i++)
900 if (strcmp(k[i], "radius") == 0)
901 sscanf(v[i], "%f", &jp->r);
903 if (strcmp(k[i], "target") == 0)
904 make_ref(v[i], targ_ji + ji);
906 if (strcmp(k[i], "origin") == 0)
908 short x = 0, y = 0, z = 0;
910 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
912 jp->p[0] = +(float) x / SCALE;
913 jp->p[1] = +(float) z / SCALE;
914 jp->p[2] = -(float) y / SCALE;
919 static void make_swch(struct s_file *fp,
920 char k[][MAXSTR],
921 char v[][MAXSTR], short c)
923 short i, xi = fp->xc++;
925 struct s_swch *xp = fp->xv + xi;
927 xp->p[0] = 0.f;
928 xp->p[1] = 0.f;
929 xp->p[2] = 0.f;
930 xp->r = 0.5;
931 xp->pi = 0;
932 xp->t0 = 0;
933 xp->t = 0;
934 xp->f0 = 0;
935 xp->f = 0;
937 for (i = 0; i < c; i++)
939 if (strcmp(k[i], "radius") == 0)
940 sscanf(v[i], "%f", &xp->r);
942 if (strcmp(k[i], "target") == 0)
943 make_ref(v[i], &xp->pi);
945 if (strcmp(k[i], "timer") == 0)
946 sscanf(v[i], "%f", &xp->t0);
948 if (strcmp(k[i], "state") == 0)
949 xp->f = atoi(v[i]);
951 if (strcmp(k[i], "origin") == 0)
953 short x = 0, y = 0, z = 0;
955 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
957 xp->p[0] = +(float) x / SCALE;
958 xp->p[1] = +(float) z / SCALE;
959 xp->p[2] = -(float) y / SCALE;
964 static void make_targ(struct s_file *fp,
965 char k[][MAXSTR],
966 char v[][MAXSTR], short c)
968 short i;
970 targ_p[targ_n][0] = 0.f;
971 targ_p[targ_n][1] = 0.f;
972 targ_p[targ_n][3] = 0.f;
974 for (i = 0; i < c; i++)
976 if (strcmp(k[i], "targetname") == 0)
977 make_sym(v[i], targ_n);
979 if (strcmp(k[i], "origin") == 0)
981 short x = 0, y = 0, z = 0;
983 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
985 targ_p[targ_n][0] = +(float) x / SCALE;
986 targ_p[targ_n][1] = +(float) z / SCALE;
987 targ_p[targ_n][2] = -(float) y / SCALE;
991 targ_n++;
994 static void make_ball(struct s_file *fp,
995 char k[][MAXSTR],
996 char v[][MAXSTR], short c)
998 short i, ui = fp->uc++;
1000 struct s_ball *up = fp->uv + ui;
1002 up->p[0] = 0.f;
1003 up->p[1] = 0.f;
1004 up->p[2] = 0.f;
1005 up->r = 0.25;
1007 up->e[0][0] = 1.f;
1008 up->e[0][1] = 0.f;
1009 up->e[0][2] = 0.f;
1010 up->e[1][0] = 0.f;
1011 up->e[1][1] = 1.f;
1012 up->e[1][2] = 0.f;
1013 up->e[2][0] = 0.f;
1014 up->e[2][1] = 0.f;
1015 up->e[2][2] = 1.f;
1017 up->v[0] = 0.f;
1018 up->v[1] = 0.f;
1019 up->v[2] = 0.f;
1020 up->w[0] = 0.f;
1021 up->w[1] = 0.f;
1022 up->w[2] = 0.f;
1024 for (i = 0; i < c; i++)
1026 if (strcmp(k[i], "radius") == 0)
1027 sscanf(v[i], "%f", &up->r);
1029 if (strcmp(k[i], "origin") == 0)
1031 short x = 0, y = 0, z = 0;
1033 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
1035 up->p[0] = +(float) (x) / SCALE;
1036 up->p[1] = +(float) (z - 24) / SCALE;
1037 up->p[2] = -(float) (y) / SCALE;
1041 up->p[1] += up->r + SMALL;
1044 /*---------------------------------------------------------------------------*/
1046 static void read_ent(struct s_file *fp, FILE *fin)
1048 char k[MAXKEY][MAXSTR];
1049 char v[MAXKEY][MAXSTR];
1050 short t, i = 0, c = 0;
1052 short l0 = fp->lc;
1054 while ((t = map_token(fin, -1, k[c], v[c])))
1056 if (t == T_KEY)
1058 if (strcmp(k[c], "classname") == 0)
1059 i = c;
1060 c++;
1062 if (t == T_BEG) read_lump(fp, fin);
1063 if (t == T_END) break;
1066 if (!strcmp(v[i], "light")) make_coin(fp, k, v, c);
1067 if (!strcmp(v[i], "info_camp")) make_swch(fp, k, v, c);
1068 if (!strcmp(v[i], "info_null")) make_bill(fp, k, v, c);
1069 if (!strcmp(v[i], "path_corner")) make_path(fp, k, v, c);
1070 if (!strcmp(v[i], "info_player_start")) make_ball(fp, k, v, c);
1071 if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1072 if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
1073 if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
1074 if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
1075 if (!strcmp(v[i], "worldspawn")) make_body(fp, k, v, c, l0);
1076 if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
1077 if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
1080 static void read_map(struct s_file *fp, FILE *fin)
1082 char k[MAXSTR];
1083 char v[MAXSTR];
1084 int t;
1086 while ((t = map_token(fin, -1, k, v)))
1087 if (t == T_BEG)
1088 read_ent(fp, fin);
1091 /*---------------------------------------------------------------------------*/
1093 /* Test the location of a point with respect to a side plane. */
1095 static int fore_side(const float p[3], const struct s_side *sp)
1097 return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1100 static int on_side(const float p[3], const struct s_side *sp)
1102 float d = v_dot(p, sp->n) - sp->d;
1104 return (-SMALL < d && d < +SMALL) ? 1 : 0;
1107 /*---------------------------------------------------------------------------*/
1109 * Confirm that the addition of a vert would not result in degenerate
1110 * geometry.
1113 static int ok_vert(const struct s_file *fp,
1114 const struct s_lump *lp, const float p[3])
1116 float r[3];
1117 short i;
1119 for (i = 0; i < lp->vc; i++)
1121 float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1123 v_sub(r, p, q);
1125 if (v_len(r) < SMALL)
1126 return 0;
1128 return 1;
1131 /*---------------------------------------------------------------------------*/
1134 * The following functions take the set of planes defining a lump and
1135 * find the verts, edges, and geoms that describe its boundaries. To
1136 * do this, they first find the verts, and then search these verts for
1137 * valid edges and geoms. It may be more efficient to compute edges
1138 * and geoms directly by clipping down infinite line segments and
1139 * planes, but this would be more complex and prone to numerical
1140 * error.
1144 * Given 3 side planes, compute the point of intersection, if any.
1145 * Confirm that this point falls within the current lump, and that it
1146 * is unique. Add it as a vert of the solid.
1148 static void clip_vert(struct s_file *fp,
1149 struct s_lump *lp, short si, short sj, short sk)
1151 float M[16], X[16], I[16];
1152 float d[3], p[3];
1153 short i;
1155 d[0] = fp->sv[si].d;
1156 d[1] = fp->sv[sj].d;
1157 d[2] = fp->sv[sk].d;
1159 m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1160 m_xps(X, M);
1162 if (m_inv(I, X))
1164 m_vxfm(p, I, d);
1166 for (i = 0; i < lp->sc; i++)
1168 short si = fp->iv[lp->s0 + i];
1170 if (fore_side(p, fp->sv + si))
1171 return;
1174 if (ok_vert(fp, lp, p))
1176 v_cpy(fp->vv[fp->vc].p, p);
1178 fp->iv[fp->ic] = fp->vc;
1179 fp->ic++;
1180 fp->vc++;
1181 lp->vc++;
1187 * Given two side planes, find an edge along their intersection by
1188 * finding a pair of vertices that fall on both planes. Add it to the
1189 * solid.
1191 static void clip_edge(struct s_file *fp,
1192 struct s_lump *lp, short si, short sj)
1194 short i, j;
1196 for (i = 1; i < lp->vc; i++)
1197 for (j = 0; j < i; j++)
1199 short vi = fp->iv[lp->v0 + i];
1200 short vj = fp->iv[lp->v0 + j];
1202 if (on_side(fp->vv[vi].p, fp->sv + si) &&
1203 on_side(fp->vv[vj].p, fp->sv + si) &&
1204 on_side(fp->vv[vi].p, fp->sv + sj) &&
1205 on_side(fp->vv[vj].p, fp->sv + sj))
1207 fp->ev[fp->ec].vi = vi;
1208 fp->ev[fp->ec].vj = vj;
1210 fp->iv[fp->ic] = fp->ec;
1212 fp->ic++;
1213 fp->ec++;
1214 lp->ec++;
1220 * Find all verts that lie on the given side of the lump. Sort these
1221 * verts to have a counter-clockwise winding about the plane normal.
1222 * Create geoms to tessalate the resulting convex polygon.
1224 static void clip_geom(struct s_file *fp,
1225 struct s_lump *lp, short si)
1227 short m[256], t[256], d, i, j, n = 0;
1228 float u[3];
1229 float v[3];
1230 float w[3];
1232 struct s_side *sp = fp->sv + si;
1234 /* Find em. */
1236 for (i = 0; i < lp->vc; i++)
1238 short vi = fp->iv[lp->v0 + i];
1240 if (on_side(fp->vv[vi].p, sp))
1242 m[n] = vi;
1243 t[n] = fp->tc++;
1245 v_add(v, fp->vv[vi].p, plane_p[si]);
1247 fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1248 fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1250 n++;
1254 /* Sort em. */
1256 for (i = 1; i < n; i++)
1257 for (j = i + 1; j < n; j++)
1259 v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1260 v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1261 v_crs(w, u, v);
1263 if (v_dot(w, sp->n) < 0.f)
1265 d = m[i];
1266 m[i] = m[j];
1267 m[j] = d;
1269 d = t[i];
1270 t[i] = t[j];
1271 t[j] = d;
1275 /* Index em. */
1277 for (i = 0; i < n - 2; i++)
1279 fp->gv[fp->gc].mi = plane_m[si];
1281 fp->gv[fp->gc].ti = t[0];
1282 fp->gv[fp->gc].tj = t[i + 1];
1283 fp->gv[fp->gc].tk = t[i + 2];
1285 fp->gv[fp->gc].si = si;
1286 fp->gv[fp->gc].sj = si;
1287 fp->gv[fp->gc].sk = si;
1289 fp->gv[fp->gc].vi = m[0];
1290 fp->gv[fp->gc].vj = m[i + 1];
1291 fp->gv[fp->gc].vk = m[i + 2];
1293 fp->iv[fp->ic] = fp->gc;
1294 fp->ic++;
1295 fp->gc++;
1296 lp->gc++;
1301 * Iterate the sides of the lump, attemping to generate a new vert for
1302 * each trio of planes, a new edge for each pair of planes, and a new
1303 * set of geom for each visible plane.
1305 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1307 short i, j, k;
1309 lp->v0 = fp->ic;
1310 lp->vc = 0;
1312 for (i = 2; i < lp->sc; i++)
1313 for (j = 1; j < i; j++)
1314 for (k = 0; k < j; k++)
1315 clip_vert(fp, lp,
1316 fp->iv[lp->s0 + i],
1317 fp->iv[lp->s0 + j],
1318 fp->iv[lp->s0 + k]);
1320 lp->e0 = fp->ic;
1321 lp->ec = 0;
1323 for (i = 1; i < lp->sc; i++)
1324 for (j = 0; j < i; j++)
1325 clip_edge(fp, lp,
1326 fp->iv[lp->s0 + i],
1327 fp->iv[lp->s0 + j]);
1329 lp->g0 = fp->ic;
1330 lp->gc = 0;
1332 for (i = 0; i < lp->sc; i++)
1333 if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0)
1334 clip_geom(fp, lp,
1335 fp->iv[lp->s0 + i]);
1337 for (i = 0; i < lp->sc; i++)
1338 if (plane_f[fp->iv[lp->s0 + i]])
1339 lp->fl |= L_DETAIL;
1342 static void clip_file(struct s_file *fp)
1344 short i;
1346 for (i = 0; i < fp->lc; i++)
1347 clip_lump(fp, fp->lv + i);
1350 /*---------------------------------------------------------------------------*/
1353 * For each body element type, determine if element 'p' is equivalent
1354 * to element 'q'. This is more than a simple memory compare. It
1355 * effectively snaps mtrls and verts togather, and may reverse the
1356 * winding of an edge or a geom. This is done in order to maximize
1357 * the number of elements that can be eliminated.
1360 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1362 if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1363 if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1364 if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1365 if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1367 if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1368 if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1369 if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1370 if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1372 if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1373 if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1374 if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1375 if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1377 if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1378 if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1379 if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1380 if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1382 if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1384 if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1386 return 1;
1389 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1391 if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1392 if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1393 if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1395 return 1;
1398 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1400 if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1401 if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1403 return 1;
1406 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1408 if (fabs(sp->d - sq->d) > SMALL) return 0;
1409 if (v_dot(sp->n, sq->n) < 0.99999) return 0;
1411 return 1;
1414 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1416 if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1417 if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1419 return 1;
1422 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1424 if (gp->mi != gq->mi) return 0;
1426 if (gp->ti != gq->ti) return 0;
1427 if (gp->si != gq->si) return 0;
1428 if (gp->vi != gq->vi) return 0;
1430 if (gp->tj != gq->tj) return 0;
1431 if (gp->sj != gq->sj) return 0;
1432 if (gp->vj != gq->vj) return 0;
1434 if (gp->tk != gq->tk) return 0;
1435 if (gp->sk != gq->sk) return 0;
1436 if (gp->vk != gq->vk) return 0;
1438 return 1;
1441 /*---------------------------------------------------------------------------*/
1444 * For each file element type, replace all references to element 'i'
1445 * with a reference to element 'j'. These are used when optimizing
1446 * and sorting the file.
1449 static void swap_mtrl(struct s_file *fp, short mi, short mj)
1451 short i;
1453 for (i = 0; i < fp->gc; i++)
1454 if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1455 for (i = 0; i < fp->rc; i++)
1456 if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1459 static void swap_vert(struct s_file *fp, short vi, short vj)
1461 short i, j;
1463 for (i = 0; i < fp->ec; i++)
1465 if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1466 if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1469 for (i = 0; i < fp->gc; i++)
1471 if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1472 if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1473 if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1476 for (i = 0; i < fp->lc; i++)
1477 for (j = 0; j < fp->lv[i].vc; j++)
1478 if (fp->iv[fp->lv[i].v0 + j] == vi)
1479 fp->iv[fp->lv[i].v0 + j] = vj;
1482 static void swap_edge(struct s_file *fp, short ei, short ej)
1484 short i, j;
1486 for (i = 0; i < fp->lc; i++)
1487 for (j = 0; j < fp->lv[i].ec; j++)
1488 if (fp->iv[fp->lv[i].e0 + j] == ei)
1489 fp->iv[fp->lv[i].e0 + j] = ej;
1492 static void swap_side(struct s_file *fp, short si, short sj)
1494 short i, j;
1496 for (i = 0; i < fp->gc; i++)
1498 if (fp->gv[i].si == si) fp->gv[i].si = sj;
1499 if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1500 if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1502 for (i = 0; i < fp->nc; i++)
1503 if (fp->nv[i].si == si) fp->nv[i].si = sj;
1505 for (i = 0; i < fp->lc; i++)
1506 for (j = 0; j < fp->lv[i].sc; j++)
1507 if (fp->iv[fp->lv[i].s0 + j] == si)
1508 fp->iv[fp->lv[i].s0 + j] = sj;
1511 static void swap_texc(struct s_file *fp, short ti, short tj)
1513 short i;
1515 for (i = 0; i < fp->gc; i++)
1517 if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1518 if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1519 if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1524 static void swap_geom(struct s_file *fp, short gi, short gj)
1526 short i, j;
1528 for (i = 0; i < fp->lc; i++)
1529 for (j = 0; j < fp->lv[i].gc; j++)
1530 if (fp->iv[fp->lv[i].g0 + j] == gi)
1531 fp->iv[fp->lv[i].g0 + j] = gj;
1533 for (i = 0; i < fp->bc; i++)
1534 for (j = 0; j < fp->bv[i].gc; j++)
1535 if (fp->iv[fp->bv[i].g0 + j] == gi)
1536 fp->iv[fp->bv[i].g0 + j] = gj;
1539 /*---------------------------------------------------------------------------*/
1541 static void uniq_mtrl(struct s_file *fp)
1543 short i, j, k = 0;
1545 for (i = 0; i < fp->mc; i++)
1547 for (j = 0; j < i; j++)
1548 if (comp_mtrl(fp->mv + i, fp->mv + j))
1550 swap_mtrl(fp, i, j);
1551 break;
1554 if (i == j)
1556 fp->mv[k] = fp->mv[i];
1557 swap_mtrl(fp, i, k);
1558 k++;
1562 fp->mc = k;
1565 static void uniq_vert(struct s_file *fp)
1567 short i, j, k = 0;
1569 for (i = 0; i < fp->vc; i++)
1571 for (j = 0; j < i; j++)
1572 if (comp_vert(fp->vv + i, fp->vv + j))
1574 swap_vert(fp, i, j);
1575 break;
1578 if (i == j)
1580 fp->vv[k] = fp->vv[i];
1581 swap_vert(fp, i, k);
1582 k++;
1586 fp->vc = k;
1589 static void uniq_edge(struct s_file *fp)
1591 short i, j, k = 0;
1593 for (i = 0; i < fp->ec; i++)
1595 for (j = 0; j < i; j++)
1596 if (comp_edge(fp->ev + i, fp->ev + j))
1598 swap_edge(fp, i, j);
1599 break;
1602 if (i == j)
1604 fp->ev[k] = fp->ev[i];
1605 swap_edge(fp, i, k);
1606 k++;
1610 fp->ec = k;
1613 static void uniq_geom(struct s_file *fp)
1615 short i, j, k = 0;
1617 for (i = 0; i < fp->gc; i++)
1619 for (j = 0; j < i; j++)
1620 if (comp_geom(fp->gv + i, fp->gv + j))
1622 swap_geom(fp, i, j);
1623 break;
1626 if (i == j)
1628 fp->gv[k] = fp->gv[i];
1629 swap_geom(fp, i, k);
1630 k++;
1634 fp->gc = k;
1637 static void uniq_texc(struct s_file *fp)
1639 short i, j, k = 0;
1641 for (i = 0; i < fp->tc; i++)
1643 for (j = 0; j < i; j++)
1644 if (comp_texc(fp->tv + i, fp->tv + j))
1646 swap_texc(fp, i, j);
1647 break;
1649 if (i == j)
1651 fp->tv[k] = fp->tv[i];
1652 swap_texc(fp, i, k);
1653 k++;
1657 fp->tc = k;
1660 static void uniq_side(struct s_file *fp)
1662 short i, j, k = 0;
1664 for (i = 0; i < fp->sc; i++)
1666 for (j = 0; j < i; j++)
1667 if (comp_side(fp->sv + i, fp->sv + j))
1669 swap_side(fp, i, j);
1670 break;
1672 if (i == j)
1674 fp->sv[k] = fp->sv[i];
1675 swap_side(fp, i, k);
1676 k++;
1680 fp->sc = k;
1683 static void uniq_file(struct s_file *fp)
1685 uniq_mtrl(fp);
1686 uniq_vert(fp);
1687 uniq_edge(fp);
1688 uniq_side(fp);
1689 uniq_texc(fp);
1690 uniq_geom(fp);
1693 /*---------------------------------------------------------------------------*/
1695 static int test_lump_side(const struct s_file *fp,
1696 const struct s_lump *lp,
1697 const struct s_side *sp)
1699 short si;
1700 short vi;
1702 short f = 0;
1703 short b = 0;
1705 /* If the given side is part of the given lump, then the lump is behind. */
1707 for (si = 0; si < lp->sc; si++)
1708 if (fp->sv + fp->iv[lp->s0 + si] == sp)
1709 return -1;
1711 /* Check if each lump vertex is in front of, behind, on the side. */
1713 for (vi = 0; vi < lp->vc; vi++)
1715 float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
1717 if (d > 0) f++;
1718 if (d < 0) b++;
1721 /* If no verts are behind, the lump is in front, and vice versa. */
1723 if (f > 0 && b == 0) return +1;
1724 if (b > 0 && f == 0) return -1;
1726 /* Else, the lump crosses the side. */
1728 return 0;
1731 static int node_node(struct s_file *fp, short l0, short lc)
1733 if (lc < 8)
1735 /* Base case. Dump all given lumps into a leaf node. */
1737 fp->nv[fp->nc].si = -1;
1738 fp->nv[fp->nc].ni = -1;
1739 fp->nv[fp->nc].nj = -1;
1740 fp->nv[fp->nc].l0 = l0;
1741 fp->nv[fp->nc].lc = lc;
1743 return fp->nc++;
1745 else
1747 short sj = 0;
1748 short sjd = lc;
1749 short sjo = lc;
1750 short si;
1751 short li = 0, lic = 0;
1752 short lj = 0, ljc = 0;
1753 short lk = 0, lkc = 0;
1754 short i;
1756 /* Find the side that most evenly splits the given lumps. */
1758 for (si = 0; si < fp->sc; si++)
1760 short o = 0;
1761 short d = 0;
1762 short k = 0;
1764 for (li = 0; li < lc; li++)
1765 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
1766 d += k;
1767 else
1768 o++;
1770 d = abs(d);
1772 if ((d < sjd) || (d == sjd && o < sjo))
1774 sj = si;
1775 sjd = d;
1776 sjo = o;
1780 /* Flag each lump with its position WRT the side. */
1782 for (li = 0; li < lc; li++)
1783 switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
1785 case +1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10; break;
1786 case 0: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20; break;
1787 case -1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40; break;
1790 /* Sort all lumps in the range by their flag values. */
1792 for (li = 1; li < lc; li++)
1793 for (lj = 0; lj < li; lj++)
1794 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
1796 struct s_lump l;
1798 l = fp->lv[l0 + li];
1799 fp->lv[l0 + li] = fp->lv[l0 + lj];
1800 fp->lv[l0 + lj] = l;
1803 /* Establish the in-front, on, and behind lump ranges. */
1805 li = lic = 0;
1806 lj = ljc = 0;
1807 lk = lkc = 0;
1809 for (i = lc - 1; i >= 0; i--)
1810 switch (fp->lv[l0 + i].fl & 0xf0)
1812 case 0x10: li = l0 + i; lic++; break;
1813 case 0x20: lj = l0 + i; ljc++; break;
1814 case 0x40: lk = l0 + i; lkc++; break;
1817 /* Add the lumps on the side to the node. */
1819 i = fp->nc++;
1821 fp->nv[i].si = sj;
1822 fp->nv[i].ni = node_node(fp, li, lic);
1824 fp->nv[i].nj = node_node(fp, lk, lkc);
1825 fp->nv[i].l0 = lj;
1826 fp->nv[i].lc = ljc;
1828 return i;
1832 static void node_file(struct s_file *fp)
1834 short bi;
1836 /* Sort the lumps of each body into BSP nodes. */
1838 for (bi = 0; bi < fp->bc; bi++)
1839 fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
1842 /*---------------------------------------------------------------------------*/
1844 static void dump_file(struct s_file *p, const char *name)
1846 short i, j;
1847 int c = 0;
1848 int n = 0;
1849 int m = p->rc + p->cc * 128 + (p->zc * p->jc + p->xc) * 32;
1851 /* Count the number of solid lumps. */
1853 for (i = 0; i < p->lc; i++)
1854 if ((p->lv[i].fl & 1) == 0)
1855 n++;
1857 /* Count the number of visible geoms. */
1859 for (i = 0; i < p->bc; i++)
1861 for (j = 0; j < p->bv[i].lc; j++)
1862 m += p->lv[p->bv[i].l0 + j].gc;
1863 m += p->bv[i].gc;
1866 /* Count the total value of all coins. */
1868 for (i = 0; i < p->cc; i++)
1869 c += p->cv[i].n;
1871 printf("%s (%d/%d/$%d)\n"
1872 " mtrl vert edge side texc"
1873 " geom lump path node body\n"
1874 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
1875 " coin goal view jump swch"
1876 " bill ball char indx\n"
1877 "%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
1878 name, n, m, c,
1879 p->mc, p->vc, p->ec, p->sc, p->tc,
1880 p->gc, p->lc, p->pc, p->nc, p->bc,
1881 p->cc, p->zc, p->wc, p->jc, p->xc,
1882 p->rc, p->uc, p->ac, p->ic);
1885 int main(int argc, char *argv[])
1887 struct s_file f;
1888 FILE *fin;
1890 if (argc > 2)
1892 strncpy(src, argv[1], MAXSTR);
1893 strncpy(dst, argv[1], MAXSTR);
1894 strncpy(path, argv[2], MAXSTR);
1896 if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
1897 strcpy(dst + strlen(dst) - 4, ".sol");
1898 else
1899 strcat(dst, ".sol");
1901 if ((fin = fopen(src, "r")))
1903 init_file(&f);
1904 read_map(&f, fin);
1906 resolve();
1907 targets(&f);
1909 clip_file(&f);
1910 move_file(&f);
1911 uniq_file(&f);
1912 node_file(&f);
1913 dump_file(&f, dst);
1915 sol_stor(&f, dst);
1917 fclose(fin);
1920 else
1921 fprintf(stderr, "Usage: %s <map> <data>\n", argv[0]);
1923 return 0;