Import from neverball-1.3.1.tar.gz
[neverball-archive.git] / share / mapc.c
blobce03aede637f6be7170b82eab1cb64af72d38f0b
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_mixer.lib")
20 #pragma comment(lib, "SDL.lib")
21 #pragma comment(lib, "SDLmain.lib")
22 #pragma comment(lib, "glu32.lib")
23 #pragma comment(lib, "opengl32.lib")
24 #endif
26 /*---------------------------------------------------------------------------*/
28 #include <SDL.h>
29 #include <SDL_image.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
35 #include "vec3.h"
36 #include "glext.h"
37 #include "solid.h"
38 #include "config.h"
40 #define MAXSTR 256
41 #define MAXKEY 16
42 #define SCALE 64.f
43 #define SMALL 0.0005f
46 * The overall design of this map converter is very stupid, but very
47 * simple. It begins by assuming that every mtrl, vert, edge, side,
48 * and texc in the map is unique. It then makes an optimizing pass
49 * that discards redundant information. The result is optimal, though
50 * the process is terribly inefficient.
53 /*---------------------------------------------------------------------------*/
55 /* Ohhhh... arbitrary! */
57 #define MAXM 256
58 #define MAXV 32768
59 #define MAXE 32768
60 #define MAXS 32768
61 #define MAXT 32768
62 #define MAXG 32768
63 #define MAXL 1024
64 #define MAXN 1024
65 #define MAXP 512
66 #define MAXB 512
67 #define MAXC 1024
68 #define MAXZ 16
69 #define MAXJ 32
70 #define MAXX 16
71 #define MAXR 1024
72 #define MAXU 16
73 #define MAXW 32
74 #define MAXA 512
75 #define MAXI 32768
77 static void init_file(struct s_file *fp)
79 fp->mc = 0;
80 fp->vc = 0;
81 fp->ec = 0;
82 fp->sc = 0;
83 fp->tc = 0;
84 fp->gc = 0;
85 fp->lc = 0;
86 fp->nc = 0;
87 fp->pc = 0;
88 fp->bc = 0;
89 fp->cc = 0;
90 fp->zc = 0;
91 fp->jc = 0;
92 fp->xc = 0;
93 fp->rc = 0;
94 fp->uc = 0;
95 fp->wc = 0;
96 fp->ac = 0;
97 fp->ic = 0;
99 fp->mv = (struct s_mtrl *) calloc(MAXM, sizeof (struct s_mtrl));
100 fp->vv = (struct s_vert *) calloc(MAXV, sizeof (struct s_vert));
101 fp->ev = (struct s_edge *) calloc(MAXE, sizeof (struct s_edge));
102 fp->sv = (struct s_side *) calloc(MAXS, sizeof (struct s_side));
103 fp->tv = (struct s_texc *) calloc(MAXT, sizeof (struct s_texc));
104 fp->gv = (struct s_geom *) calloc(MAXG, sizeof (struct s_geom));
105 fp->lv = (struct s_lump *) calloc(MAXL, sizeof (struct s_lump));
106 fp->nv = (struct s_node *) calloc(MAXN, sizeof (struct s_node));
107 fp->pv = (struct s_path *) calloc(MAXP, sizeof (struct s_path));
108 fp->bv = (struct s_body *) calloc(MAXB, sizeof (struct s_body));
109 fp->cv = (struct s_coin *) calloc(MAXC, sizeof (struct s_coin));
110 fp->zv = (struct s_goal *) calloc(MAXZ, sizeof (struct s_goal));
111 fp->jv = (struct s_jump *) calloc(MAXJ, sizeof (struct s_jump));
112 fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
113 fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
114 fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
115 fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
116 fp->av = (char *) calloc(MAXA, sizeof (char));
117 fp->iv = (short *) calloc(MAXI, sizeof (short));
120 /*---------------------------------------------------------------------------*/
123 * The following is a small symbol table data structure. Symbols and
124 * their integer values are collected in symv and valv. References
125 * and pointers to their unsatisfied integer values are collected in
126 * refv and pntv. The resolve procedure matches references to symbols
127 * and fills waiting ints with the proper values.
130 #define MAXSYM 1024
132 static char symv[MAXSYM][MAXSTR];
133 static short valv[MAXSYM];
135 static char refv[MAXSYM][MAXSTR];
136 static short *pntv[MAXSYM];
138 static int strc;
139 static int refc;
141 static void make_sym(const char *s, short v)
143 strncpy(symv[strc], s, MAXSTR - 1);
144 valv[strc] = v;
145 strc++;
148 static void make_ref(const char *r, short *p)
150 strncpy(refv[refc], r, MAXSTR - 1);
151 pntv[refc] = p;
152 refc++;
155 static void resolve(void)
157 int i, j;
159 for (i = 0; i < refc; i++)
160 for (j = 0; j < strc; j++)
161 if (strncmp(refv[i], symv[j], MAXSTR) == 0)
163 *(pntv[i]) = valv[j];
164 break;
168 /*---------------------------------------------------------------------------*/
171 * The following globals are used to cache target_positions. They are
172 * targeted by various entities and must be resolved in a second pass.
175 static float targ_p [MAXW][3];
176 static short targ_wi[MAXW];
177 static short targ_ji[MAXW];
178 static short targ_n;
180 static void targets(struct s_file *fp)
182 short i;
184 for (i = 0; i < fp->wc; i++)
185 v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
187 for (i = 0; i < fp->jc; i++)
188 v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
191 /*---------------------------------------------------------------------------*/
194 * The following code caches image sizes. Textures are referenced by
195 * name, but their sizes are necessary when computing texture
196 * coordinates. This code allows each file to be accessed only once
197 * regardless of the number of surfaces refering to it.
200 static char *image_s[MAXM];
201 static int image_w[MAXM];
202 static int image_h[MAXM];
203 static int image_n;
205 static int size_load(const char *file, int *w, int *h)
207 SDL_Surface *S;
209 if ((S = IMG_Load(file)))
211 *w = S->w;
212 *h = S->h;
214 SDL_FreeSurface(S);
216 return 1;
218 return 0;
221 static void size_image(const char *name, int *w, int *h)
223 char jpg[MAXSTR];
224 char tga[MAXSTR];
225 char png[MAXSTR];
226 int i;
228 for (i = 0; i < image_n; i++)
229 if (strncmp(image_s[i], name, MAXSTR) == 0)
231 *w = image_w[i];
232 *h = image_h[i];
234 return;
237 *w = 0;
238 *h = 0;
240 strcpy(jpg, name); strcat(jpg, ".jpg");
241 strcpy(tga, name); strcat(tga, ".tga");
242 strcpy(png, name); strcat(png, ".png");
244 if (size_load(config_data(png), w, h) ||
245 size_load(config_data(tga), w, h) ||
246 size_load(config_data(jpg), w, h))
248 image_s[image_n] = (char *) calloc(strlen(name) + 1, 1);
249 image_w[image_n] = *w;
250 image_h[image_n] = *h;
252 strcpy(image_s[image_n], name);
253 image_n++;
257 /*---------------------------------------------------------------------------*/
259 /* Read the given material file, adding a new material to the solid. */
261 static int read_mtrl(struct s_file *fp, const char *name)
263 struct s_mtrl *mp;
264 FILE *fin;
265 short mi;
267 for (mi = 0; mi < fp->mc; mi++)
268 if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
269 return mi;
271 mp = fp->mv + fp->mc++;
273 strncpy(mp->f, name, PATHMAX - 1);
275 mp->a[0] = mp->a[1] = mp->a[2] = mp->a[3] = 1.0f;
276 mp->d[0] = mp->d[1] = mp->d[2] = mp->d[3] = 1.0f;
277 mp->s[0] = mp->s[1] = mp->s[2] = mp->s[3] = 1.0f;
278 mp->e[0] = mp->e[1] = mp->e[2] = mp->e[3] = 1.0f;
279 mp->h[0] = 0.0f;
280 mp->fl = 0;
282 if ((fin = fopen(config_data(name), "r")))
284 fscanf(fin,
285 "%f %f %f %f "
286 "%f %f %f %f "
287 "%f %f %f %f "
288 "%f %f %f %f "
289 "%f %hd ",
290 mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
291 mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
292 mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
293 mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
294 mp->h, &mp->fl);
295 fclose(fin);
298 return mi;
301 /*---------------------------------------------------------------------------*/
304 * All bodies with an associated path are assumed to be positioned at
305 * the beginning of that path. These bodies must be moved to the
306 * origin in order for their path transforms to behave correctly.
307 * This is how we get away with defining func_trains with no origin
308 * specification.
311 static void move_side(struct s_side *sp, const float p[3])
313 sp->d -= v_dot(sp->n, p);
316 static void move_vert(struct s_vert *vp, const float p[3])
318 v_sub(vp->p, vp->p, p);
321 static void move_lump(struct s_file *fp,
322 struct s_lump *lp, const float p[3])
324 short i;
326 for (i = 0; i < lp->sc; i++)
327 move_side(fp->sv + fp->iv[lp->s0 + i], p);
328 for (i = 0; i < lp->vc; i++)
329 move_vert(fp->vv + fp->iv[lp->v0 + i], p);
332 static void move_body(struct s_file *fp,
333 struct s_body *bp)
335 short i;
337 for (i = 0; i < bp->lc; i++)
338 move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
341 static void move_file(struct s_file *fp)
343 short i;
345 for (i = 0; i < fp->bc; i++)
346 if (fp->bv[i].pi >= 0)
347 move_body(fp, fp->bv + i);
350 /*---------------------------------------------------------------------------*/
352 static void read_vt(struct s_file *fp, const char *line)
354 struct s_texc *tp = fp->tv + fp->tc++;
356 sscanf(line, "%f %f", tp->u, tp->u + 1);
359 static void read_vn(struct s_file *fp, const char *line)
361 struct s_side *sp = fp->sv + fp->sc++;
363 sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
366 static void read_v(struct s_file *fp, const char *line)
368 struct s_vert *vp = fp->vv + fp->vc++;
370 sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
373 static void read_f(struct s_file *fp, const char *line,
374 short v0, short t0, short s0, short mi)
376 struct s_geom *gp = fp->gv + fp->gc++;
378 char c1;
379 char c2;
382 * FIXME: All faces must be triangles and must include a normal
383 * and texture coordinate.
386 sscanf(line, "%hd%c%hd%c%hd %hd%c%hd%c%hd %hd%c%hd%c%hd",
387 &gp->vi, &c1, &gp->ti, &c2, &gp->si,
388 &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
389 &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
391 gp->vi += (v0 - 1);
392 gp->vj += (v0 - 1);
393 gp->vk += (v0 - 1);
394 gp->ti += (t0 - 1);
395 gp->tj += (t0 - 1);
396 gp->tk += (t0 - 1);
397 gp->si += (s0 - 1);
398 gp->sj += (s0 - 1);
399 gp->sk += (s0 - 1);
401 gp->mi = mi;
404 static void read_obj(struct s_file *fp, const char *name)
406 char line[MAXSTR];
407 char mtrl[MAXSTR];
408 FILE *fin;
410 short v0 = fp->vc;
411 short t0 = fp->tc;
412 short s0 = fp->sc;
413 short mi = 0;
415 if ((fin = fopen(config_data(name), "r")))
417 while (fgets(line, MAXSTR, fin))
419 if (strncmp(line, "usemtl", 6) == 0)
421 sscanf(line + 6, "%s", mtrl);
422 mi = read_mtrl(fp, mtrl);
425 else if (strncmp(line, "f", 1) == 0)
427 if (fp->mv[mi].d[3] > 0)
428 read_f(fp, line + 1, v0, t0, s0, mi);
431 else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
432 else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
433 else if (strncmp(line, "v", 1) == 0) read_v (fp, line + 1);
435 fclose(fin);
439 /*---------------------------------------------------------------------------*/
441 static float plane_d[MAXS];
442 static float plane_n[MAXS][3];
443 static float plane_p[MAXS][3];
444 static float plane_u[MAXS][3];
445 static float plane_v[MAXS][3];
446 static short plane_f[MAXS];
447 static short plane_m[MAXS];
449 static void make_plane(short pi, short x0, short y0, short z0,
450 short x1, short y1, short z1,
451 short x2, short y2, short z2,
452 short tu, short tv, short r,
453 float su, float sv, int fl, const char *s)
455 static const float base[6][3][3] = {
456 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
457 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
458 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
459 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
460 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
461 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
464 float R[16];
465 float p0[3], p1[3], p2[3];
466 float u[3], v[3], p[3];
467 float k, d = 0.f;
468 short i, n = 0;
469 int w, h;
471 size_image(s, &w, &h);
473 plane_f[pi] = fl ? L_DETAIL : 0;
475 p0[0] = +(float) x0 / SCALE;
476 p0[1] = +(float) z0 / SCALE;
477 p0[2] = -(float) y0 / SCALE;
479 p1[0] = +(float) x1 / SCALE;
480 p1[1] = +(float) z1 / SCALE;
481 p1[2] = -(float) y1 / SCALE;
483 p2[0] = +(float) x2 / SCALE;
484 p2[1] = +(float) z2 / SCALE;
485 p2[2] = -(float) y2 / SCALE;
487 v_sub(u, p0, p1);
488 v_sub(v, p2, p1);
490 v_crs(plane_n[pi], u, v);
491 v_nrm(plane_n[pi], plane_n[pi]);
493 plane_d[pi] = v_dot(plane_n[pi], p1);
495 for (i = 0; i < 6; i++)
496 if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
498 d = k;
499 n = i;
502 p[0] = 0.f;
503 p[1] = 0.f;
504 p[2] = 0.f;
506 m_rot(R, base[n][0], V_RAD(r));
508 v_mad(p, p, base[n][1], su * tu / SCALE);
509 v_mad(p, p, base[n][2], sv * tv / SCALE);
511 m_vxfm(plane_u[pi], R, base[n][1]);
512 m_vxfm(plane_v[pi], R, base[n][2]);
513 m_vxfm(plane_p[pi], R, p);
515 v_scl(plane_u[pi], plane_u[pi], 64.f / w);
516 v_scl(plane_v[pi], plane_v[pi], 64.f / h);
518 v_scl(plane_u[pi], plane_u[pi], 1.f / su);
519 v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
522 /*---------------------------------------------------------------------------*/
524 #define T_EOF 0
525 #define T_BEG 1
526 #define T_CLP 2
527 #define T_KEY 3
528 #define T_END 4
529 #define T_NOP 5
531 static int map_token(FILE *fin, short pi, char key[MAXSTR], char val[MAXSTR])
533 char buf[MAXSTR];
535 if (fgets(buf, MAXSTR, fin))
537 char c;
538 short x0, y0, z0;
539 short x1, y1, z1;
540 short x2, y2, z2;
541 short tu, tv, r;
542 float su, sv;
543 int fl;
545 /* Scan the beginning or end of a block. */
547 if (buf[0] == '{') return T_BEG;
548 if (buf[0] == '}') return T_END;
550 /* Scan a key-value pair. */
552 if (buf[0] == '"')
554 strcpy(key, strtok(buf, "\""));
555 (void) strtok(NULL, "\"");
556 strcpy(val, strtok(NULL, "\""));
558 return T_KEY;
561 /* Scan a plane. */
563 if (sscanf(buf,
564 "%c %hd %hd %hd %c "
565 "%c %hd %hd %hd %c "
566 "%c %hd %hd %hd %c "
567 "%s %hd %hd %hd %f %f %d",
568 &c, &x0, &y0, &z0, &c,
569 &c, &x1, &y1, &z1, &c,
570 &c, &x2, &y2, &z2, &c,
571 key, &tu, &tv, &r, &su, &sv, &fl) == 22)
573 make_plane(pi, x0, y0, z0,
574 x1, y1, z1,
575 x2, y2, z2,
576 tu, tv, r, su, sv, fl, key);
577 return T_CLP;
580 /* If it's not recognized, it must be uninteresting. */
582 return T_NOP;
584 return T_EOF;
587 /*---------------------------------------------------------------------------*/
589 /* Parse a lump from the given file and add it to the solid. */
591 static void read_lump(struct s_file *fp, FILE *fin)
593 char k[MAXSTR];
594 char v[MAXSTR];
595 int t;
597 struct s_lump *lp = fp->lv + fp->lc++;
599 lp->s0 = fp->ic;
601 while ((t = map_token(fin, fp->sc, k, v)))
603 if (t == T_CLP)
605 fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
606 fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
607 fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
608 fp->sv[fp->sc].d = plane_d[fp->sc];
610 plane_m[fp->sc] = read_mtrl(fp, k);
612 fp->iv[fp->ic] = fp->sc;
613 fp->ic++;
614 fp->sc++;
615 lp->sc++;
617 if (t == T_END)
618 break;
622 /*---------------------------------------------------------------------------*/
624 static void make_path(struct s_file *fp,
625 char k[][MAXSTR],
626 char v[][MAXSTR], short c)
628 short i, pi = fp->pc++;
630 struct s_path *pp = fp->pv + pi;
632 pp->p[0] = 0.f;
633 pp->p[1] = 0.f;
634 pp->p[2] = 0.f;
635 pp->t = 1.f;
636 pp->pi = pi;
637 pp->f = 1;
639 for (i = 0; i < c; i++)
641 if (strcmp(k[i], "targetname") == 0)
642 make_sym(v[i], pi);
644 if (strcmp(k[i], "target") == 0)
645 make_ref(v[i], &pp->pi);
647 if (strcmp(k[i], "state") == 0)
648 pp->f = atoi(v[i]);
650 if (strcmp(k[i], "speed") == 0)
651 sscanf(v[i], "%f", &pp->t);
653 if (strcmp(k[i], "origin") == 0)
655 short x = 0, y = 0, z = 0;
657 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
659 pp->p[0] = +(float) x / SCALE;
660 pp->p[1] = +(float) z / SCALE;
661 pp->p[2] = -(float) y / SCALE;
666 static void make_body(struct s_file *fp,
667 char k[][MAXSTR],
668 char v[][MAXSTR], short c, short l0)
670 short i, bi = fp->bc++;
672 short g0 = fp->gc;
673 short v0 = fp->vc;
675 float p[3];
677 short x = 0;
678 short y = 0;
679 short z = 0;
681 struct s_body *bp = fp->bv + bi;
683 bp->t = 0.f;
684 bp->pi = -1;
685 bp->ni = -1;
687 for (i = 0; i < c; i++)
689 if (strcmp(k[i], "targetname") == 0)
690 make_sym(v[i], bi);
692 if (strcmp(k[i], "target") == 0)
693 make_ref(v[i], &bp->pi);
695 if (strcmp(k[i], "model") == 0)
696 read_obj(fp, v[i]);
698 if (strcmp(k[i], "origin") == 0)
699 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
701 if (strcmp(k[i], "message") == 0)
703 strcpy(fp->av, v[i]);
704 fp->ac = (short) (strlen(v[i]) + 1);
708 bp->l0 = l0;
709 bp->lc = fp->lc - l0;
710 bp->g0 = fp->ic;
711 bp->gc = fp->gc - g0;
713 for (i = 0; i < bp->gc; i++)
714 fp->iv[fp->ic++] = g0++;
716 p[0] = +(float) x / SCALE;
717 p[1] = +(float) z / SCALE;
718 p[2] = -(float) y / SCALE;
720 for (i = v0; i < fp->vc; i++)
721 v_add(fp->vv[i].p, fp->vv[i].p, p);
724 static void make_coin(struct s_file *fp,
725 char k[][MAXSTR],
726 char v[][MAXSTR], short c)
728 short i, ci = fp->cc++;
730 struct s_coin *cp = fp->cv + ci;
732 cp->p[0] = 0.f;
733 cp->p[1] = 0.f;
734 cp->p[2] = 0.f;
735 cp->n = 1;
737 for (i = 0; i < c; i++)
739 if (strcmp(k[i], "light") == 0)
740 sscanf(v[i], "%hd", &cp->n);
742 if (strcmp(k[i], "origin") == 0)
744 short x = 0, y = 0, z = 0;
746 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
748 cp->p[0] = +(float) x / SCALE;
749 cp->p[1] = +(float) z / SCALE;
750 cp->p[2] = -(float) y / SCALE;
755 static void make_bill(struct s_file *fp,
756 char k[][MAXSTR],
757 char v[][MAXSTR], short c)
759 short i, ri = fp->rc++;
761 struct s_bill *rp = fp->rv + ri;
763 memset(rp, 0, sizeof (struct s_bill));
764 rp->t = 1.0f;
766 for (i = 0; i < c; i++)
768 if (strcmp(k[i], "width") == 0)
769 sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
770 if (strcmp(k[i], "height") == 0)
771 sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
773 if (strcmp(k[i], "xrot") == 0)
774 sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
775 if (strcmp(k[i], "yrot") == 0)
776 sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
777 if (strcmp(k[i], "zrot") == 0)
778 sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
780 if (strcmp(k[i], "time") == 0)
781 sscanf(v[i], "%f", &rp->t);
782 if (strcmp(k[i], "dist") == 0)
783 sscanf(v[i], "%f", &rp->d);
784 if (strcmp(k[i], "flag") == 0)
785 sscanf(v[i], "%hd", &rp->fl);
787 if (strcmp(k[i], "image") == 0)
789 rp->mi = read_mtrl(fp, v[i]);
790 fp->mv[rp->mi].fl |= M_CLAMPED;
793 if (strcmp(k[i], "origin") == 0)
795 short x = 0, y = 0, z = 0;
796 float p[3];
798 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
800 p[0] = +(float) x / SCALE;
801 p[1] = +(float) z / SCALE;
802 p[2] = -(float) y / SCALE;
804 rp->d = v_len(p);
805 rp->rx[0] = V_DEG(fatan2f(+p[1], rp->d));
806 rp->ry[0] = V_DEG(fatan2f(+p[0], -p[2]));
810 if (rp->fl & B_ADDITIVE)
811 fp->mv[rp->mi].fl |= M_ADDITIVE;
814 static void make_goal(struct s_file *fp,
815 char k[][MAXSTR],
816 char v[][MAXSTR], short c)
818 short i, zi = fp->zc++;
820 struct s_goal *zp = fp->zv + zi;
822 zp->p[0] = 0.f;
823 zp->p[1] = 0.f;
824 zp->p[2] = 0.f;
825 zp->r = 0.75;
827 for (i = 0; i < c; i++)
829 if (strcmp(k[i], "radius") == 0)
830 sscanf(v[i], "%f", &zp->r);
832 if (strcmp(k[i], "origin") == 0)
834 short x = 0, y = 0, z = 0;
836 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
838 zp->p[0] = +(float) (x) / SCALE;
839 zp->p[1] = +(float) (z - 24) / SCALE;
840 zp->p[2] = -(float) (y) / SCALE;
845 static void make_view(struct s_file *fp,
846 char k[][MAXSTR],
847 char v[][MAXSTR], short c)
849 short i, wi = fp->wc++;
851 struct s_view *wp = fp->wv + wi;
853 wp->p[0] = 0.f;
854 wp->p[1] = 0.f;
855 wp->p[2] = 0.f;
856 wp->q[0] = 0.f;
857 wp->q[1] = 0.f;
858 wp->q[2] = 0.f;
860 for (i = 0; i < c; i++)
862 if (strcmp(k[i], "target") == 0)
863 make_ref(v[i], targ_wi + wi);
865 if (strcmp(k[i], "origin") == 0)
867 short x = 0, y = 0, z = 0;
869 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
871 wp->p[0] = +(float) x / SCALE;
872 wp->p[1] = +(float) z / SCALE;
873 wp->p[2] = -(float) y / SCALE;
878 static void make_jump(struct s_file *fp,
879 char k[][MAXSTR],
880 char v[][MAXSTR], short c)
882 short i, ji = fp->jc++;
884 struct s_jump *jp = fp->jv + ji;
886 jp->p[0] = 0.f;
887 jp->p[1] = 0.f;
888 jp->p[2] = 0.f;
889 jp->q[0] = 0.f;
890 jp->q[1] = 0.f;
891 jp->q[2] = 0.f;
892 jp->r = 0.5;
894 for (i = 0; i < c; i++)
896 if (strcmp(k[i], "radius") == 0)
897 sscanf(v[i], "%f", &jp->r);
899 if (strcmp(k[i], "target") == 0)
900 make_ref(v[i], targ_ji + ji);
902 if (strcmp(k[i], "origin") == 0)
904 short x = 0, y = 0, z = 0;
906 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
908 jp->p[0] = +(float) x / SCALE;
909 jp->p[1] = +(float) z / SCALE;
910 jp->p[2] = -(float) y / SCALE;
915 static void make_swch(struct s_file *fp,
916 char k[][MAXSTR],
917 char v[][MAXSTR], short c)
919 short i, xi = fp->xc++;
921 struct s_swch *xp = fp->xv + xi;
923 xp->p[0] = 0.f;
924 xp->p[1] = 0.f;
925 xp->p[2] = 0.f;
926 xp->r = 0.5;
927 xp->pi = 0;
928 xp->t0 = 0;
929 xp->t = 0;
930 xp->f0 = 0;
931 xp->f = 0;
933 for (i = 0; i < c; i++)
935 if (strcmp(k[i], "radius") == 0)
936 sscanf(v[i], "%f", &xp->r);
938 if (strcmp(k[i], "target") == 0)
939 make_ref(v[i], &xp->pi);
941 if (strcmp(k[i], "timer") == 0)
942 sscanf(v[i], "%f", &xp->t0);
944 if (strcmp(k[i], "state") == 0)
945 xp->f = atoi(v[i]);
947 if (strcmp(k[i], "origin") == 0)
949 short x = 0, y = 0, z = 0;
951 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
953 xp->p[0] = +(float) x / SCALE;
954 xp->p[1] = +(float) z / SCALE;
955 xp->p[2] = -(float) y / SCALE;
960 static void make_targ(struct s_file *fp,
961 char k[][MAXSTR],
962 char v[][MAXSTR], short c)
964 short i;
966 targ_p[targ_n][0] = 0.f;
967 targ_p[targ_n][1] = 0.f;
968 targ_p[targ_n][3] = 0.f;
970 for (i = 0; i < c; i++)
972 if (strcmp(k[i], "targetname") == 0)
973 make_sym(v[i], targ_n);
975 if (strcmp(k[i], "origin") == 0)
977 short x = 0, y = 0, z = 0;
979 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
981 targ_p[targ_n][0] = +(float) x / SCALE;
982 targ_p[targ_n][1] = +(float) z / SCALE;
983 targ_p[targ_n][2] = -(float) y / SCALE;
987 targ_n++;
990 static void make_ball(struct s_file *fp,
991 char k[][MAXSTR],
992 char v[][MAXSTR], short c)
994 short i, ui = fp->uc++;
996 struct s_ball *up = fp->uv + ui;
998 up->p[0] = 0.f;
999 up->p[1] = 0.f;
1000 up->p[2] = 0.f;
1001 up->r = 0.25;
1003 up->e[0][0] = 1.f;
1004 up->e[0][1] = 0.f;
1005 up->e[0][2] = 0.f;
1006 up->e[1][0] = 0.f;
1007 up->e[1][1] = 1.f;
1008 up->e[1][2] = 0.f;
1009 up->e[2][0] = 0.f;
1010 up->e[2][1] = 0.f;
1011 up->e[2][2] = 1.f;
1013 up->v[0] = 0.f;
1014 up->v[1] = 0.f;
1015 up->v[2] = 0.f;
1016 up->w[0] = 0.f;
1017 up->w[1] = 0.f;
1018 up->w[2] = 0.f;
1020 for (i = 0; i < c; i++)
1022 if (strcmp(k[i], "radius") == 0)
1023 sscanf(v[i], "%f", &up->r);
1025 if (strcmp(k[i], "origin") == 0)
1027 short x = 0, y = 0, z = 0;
1029 sscanf(v[i], "%hd %hd %hd", &x, &y, &z);
1031 up->p[0] = +(float) (x) / SCALE;
1032 up->p[1] = +(float) (z - 24) / SCALE;
1033 up->p[2] = -(float) (y) / SCALE;
1037 up->p[1] += up->r + SMALL;
1040 /*---------------------------------------------------------------------------*/
1042 static void read_ent(struct s_file *fp, FILE *fin)
1044 char k[MAXKEY][MAXSTR];
1045 char v[MAXKEY][MAXSTR];
1046 short t, i = 0, c = 0;
1048 short l0 = fp->lc;
1050 while ((t = map_token(fin, -1, k[c], v[c])))
1052 if (t == T_KEY)
1054 if (strcmp(k[c], "classname") == 0)
1055 i = c;
1056 c++;
1058 if (t == T_BEG) read_lump(fp, fin);
1059 if (t == T_END) break;
1062 if (!strcmp(v[i], "light")) make_coin(fp, k, v, c);
1063 if (!strcmp(v[i], "info_camp")) make_swch(fp, k, v, c);
1064 if (!strcmp(v[i], "info_null")) make_bill(fp, k, v, c);
1065 if (!strcmp(v[i], "path_corner")) make_path(fp, k, v, c);
1066 if (!strcmp(v[i], "info_player_start")) make_ball(fp, k, v, c);
1067 if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1068 if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
1069 if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
1070 if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
1071 if (!strcmp(v[i], "worldspawn")) make_body(fp, k, v, c, l0);
1072 if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
1073 if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
1076 static void read_map(struct s_file *fp, FILE *fin)
1078 char k[MAXSTR];
1079 char v[MAXSTR];
1080 int t;
1082 while ((t = map_token(fin, -1, k, v)))
1083 if (t == T_BEG)
1084 read_ent(fp, fin);
1087 /*---------------------------------------------------------------------------*/
1089 /* Test the location of a point with respect to a side plane. */
1091 static int fore_side(const float p[3], const struct s_side *sp)
1093 return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1096 static int on_side(const float p[3], const struct s_side *sp)
1098 float d = v_dot(p, sp->n) - sp->d;
1100 return (-SMALL < d && d < +SMALL) ? 1 : 0;
1103 /*---------------------------------------------------------------------------*/
1105 * Confirm that the addition of a vert would not result in degenerate
1106 * geometry.
1109 static int ok_vert(const struct s_file *fp,
1110 const struct s_lump *lp, const float p[3])
1112 float r[3];
1113 short i;
1115 for (i = 0; i < lp->vc; i++)
1117 float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1119 v_sub(r, p, q);
1121 if (v_len(r) < SMALL)
1122 return 0;
1124 return 1;
1127 /*---------------------------------------------------------------------------*/
1130 * The following functions take the set of planes defining a lump and
1131 * find the verts, edges, and geoms that describe its boundaries. To
1132 * do this, they first find the verts, and then search these verts for
1133 * valid edges and geoms. It may be more efficient to compute edges
1134 * and geoms directly by clipping down infinite line segments and
1135 * planes, but this would be more complex and prone to numerical
1136 * error.
1140 * Given 3 side planes, compute the point of intersection, if any.
1141 * Confirm that this point falls within the current lump, and that it
1142 * is unique. Add it as a vert of the solid.
1144 static void clip_vert(struct s_file *fp,
1145 struct s_lump *lp, short si, short sj, short sk)
1147 float M[16], X[16], I[16];
1148 float d[3], p[3];
1149 short i;
1151 d[0] = fp->sv[si].d;
1152 d[1] = fp->sv[sj].d;
1153 d[2] = fp->sv[sk].d;
1155 m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1156 m_xps(X, M);
1158 if (m_inv(I, X))
1160 m_vxfm(p, I, d);
1162 for (i = 0; i < lp->sc; i++)
1164 short si = fp->iv[lp->s0 + i];
1166 if (fore_side(p, fp->sv + si))
1167 return;
1170 if (ok_vert(fp, lp, p))
1172 v_cpy(fp->vv[fp->vc].p, p);
1174 fp->iv[fp->ic] = fp->vc;
1175 fp->ic++;
1176 fp->vc++;
1177 lp->vc++;
1183 * Given two side planes, find an edge along their intersection by
1184 * finding a pair of vertices that fall on both planes. Add it to the
1185 * solid.
1187 static void clip_edge(struct s_file *fp,
1188 struct s_lump *lp, short si, short sj)
1190 short i, j;
1192 for (i = 1; i < lp->vc; i++)
1193 for (j = 0; j < i; j++)
1195 short vi = fp->iv[lp->v0 + i];
1196 short vj = fp->iv[lp->v0 + j];
1198 if (on_side(fp->vv[vi].p, fp->sv + si) &&
1199 on_side(fp->vv[vj].p, fp->sv + si) &&
1200 on_side(fp->vv[vi].p, fp->sv + sj) &&
1201 on_side(fp->vv[vj].p, fp->sv + sj))
1203 fp->ev[fp->ec].vi = vi;
1204 fp->ev[fp->ec].vj = vj;
1206 fp->iv[fp->ic] = fp->ec;
1208 fp->ic++;
1209 fp->ec++;
1210 lp->ec++;
1216 * Find all verts that lie on the given side of the lump. Sort these
1217 * verts to have a counter-clockwise winding about the plane normal.
1218 * Create geoms to tessalate the resulting convex polygon.
1220 static void clip_geom(struct s_file *fp,
1221 struct s_lump *lp, short si)
1223 short m[256], t[256], d, i, j, n = 0;
1224 float u[3];
1225 float v[3];
1226 float w[3];
1228 struct s_side *sp = fp->sv + si;
1230 /* Find em. */
1232 for (i = 0; i < lp->vc; i++)
1234 short vi = fp->iv[lp->v0 + i];
1236 if (on_side(fp->vv[vi].p, sp))
1238 m[n] = vi;
1239 t[n] = fp->tc++;
1241 v_add(v, fp->vv[vi].p, plane_p[si]);
1243 fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1244 fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1246 n++;
1250 /* Sort em. */
1252 for (i = 1; i < n; i++)
1253 for (j = i + 1; j < n; j++)
1255 v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1256 v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1257 v_crs(w, u, v);
1259 if (v_dot(w, sp->n) < 0.f)
1261 d = m[i];
1262 m[i] = m[j];
1263 m[j] = d;
1265 d = t[i];
1266 t[i] = t[j];
1267 t[j] = d;
1271 /* Index em. */
1273 for (i = 0; i < n - 2; i++)
1275 fp->gv[fp->gc].mi = plane_m[si];
1277 fp->gv[fp->gc].ti = t[0];
1278 fp->gv[fp->gc].tj = t[i + 1];
1279 fp->gv[fp->gc].tk = t[i + 2];
1281 fp->gv[fp->gc].si = si;
1282 fp->gv[fp->gc].sj = si;
1283 fp->gv[fp->gc].sk = si;
1285 fp->gv[fp->gc].vi = m[0];
1286 fp->gv[fp->gc].vj = m[i + 1];
1287 fp->gv[fp->gc].vk = m[i + 2];
1289 fp->iv[fp->ic] = fp->gc;
1290 fp->ic++;
1291 fp->gc++;
1292 lp->gc++;
1297 * Iterate the sides of the lump, attemping to generate a new vert for
1298 * each trio of planes, a new edge for each pair of planes, and a new
1299 * set of geom for each visible plane.
1301 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1303 short i, j, k;
1305 lp->v0 = fp->ic;
1306 lp->vc = 0;
1308 for (i = 2; i < lp->sc; i++)
1309 for (j = 1; j < i; j++)
1310 for (k = 0; k < j; k++)
1311 clip_vert(fp, lp,
1312 fp->iv[lp->s0 + i],
1313 fp->iv[lp->s0 + j],
1314 fp->iv[lp->s0 + k]);
1316 lp->e0 = fp->ic;
1317 lp->ec = 0;
1319 for (i = 1; i < lp->sc; i++)
1320 for (j = 0; j < i; j++)
1321 clip_edge(fp, lp,
1322 fp->iv[lp->s0 + i],
1323 fp->iv[lp->s0 + j]);
1325 lp->g0 = fp->ic;
1326 lp->gc = 0;
1328 for (i = 0; i < lp->sc; i++)
1329 if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0)
1330 clip_geom(fp, lp,
1331 fp->iv[lp->s0 + i]);
1333 for (i = 0; i < lp->sc; i++)
1334 if (plane_f[fp->iv[lp->s0 + i]])
1335 lp->fl |= L_DETAIL;
1338 static void clip_file(struct s_file *fp)
1340 short i;
1342 for (i = 0; i < fp->lc; i++)
1343 clip_lump(fp, fp->lv + i);
1346 /*---------------------------------------------------------------------------*/
1349 * For each body element type, determine if element 'p' is equivalent
1350 * to element 'q'. This is more than a simple memory compare. It
1351 * effectively snaps mtrls and verts togather, and may reverse the
1352 * winding of an edge or a geom. This is done in order to maximize
1353 * the number of elements that can be eliminated.
1356 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1358 if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1359 if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1360 if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1361 if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1363 if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1364 if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1365 if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1366 if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1368 if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1369 if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1370 if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1371 if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1373 if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1374 if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1375 if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1376 if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1378 if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1380 if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1382 return 1;
1385 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1387 if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1388 if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1389 if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1391 return 1;
1394 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1396 if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1397 if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1399 return 1;
1402 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1404 if (fabs(sp->d - sq->d) > SMALL) return 0;
1405 if (v_dot(sp->n, sq->n) < 0.99999) return 0;
1407 return 1;
1410 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1412 if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1413 if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1415 return 1;
1418 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1420 if (gp->mi != gq->mi) return 0;
1422 if (gp->ti != gq->ti) return 0;
1423 if (gp->si != gq->si) return 0;
1424 if (gp->vi != gq->vi) return 0;
1426 if (gp->tj != gq->tj) return 0;
1427 if (gp->sj != gq->sj) return 0;
1428 if (gp->vj != gq->vj) return 0;
1430 if (gp->tk != gq->tk) return 0;
1431 if (gp->sk != gq->sk) return 0;
1432 if (gp->vk != gq->vk) return 0;
1434 return 1;
1437 /*---------------------------------------------------------------------------*/
1440 * For each file element type, replace all references to element 'i'
1441 * with a reference to element 'j'. These are used when optimizing
1442 * and sorting the file.
1445 static void swap_mtrl(struct s_file *fp, short mi, short mj)
1447 short i;
1449 for (i = 0; i < fp->gc; i++)
1450 if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1451 for (i = 0; i < fp->rc; i++)
1452 if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1455 static void swap_vert(struct s_file *fp, short vi, short vj)
1457 short i, j;
1459 for (i = 0; i < fp->ec; i++)
1461 if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1462 if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1465 for (i = 0; i < fp->gc; i++)
1467 if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1468 if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1469 if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1472 for (i = 0; i < fp->lc; i++)
1473 for (j = 0; j < fp->lv[i].vc; j++)
1474 if (fp->iv[fp->lv[i].v0 + j] == vi)
1475 fp->iv[fp->lv[i].v0 + j] = vj;
1478 static void swap_edge(struct s_file *fp, short ei, short ej)
1480 short i, j;
1482 for (i = 0; i < fp->lc; i++)
1483 for (j = 0; j < fp->lv[i].ec; j++)
1484 if (fp->iv[fp->lv[i].e0 + j] == ei)
1485 fp->iv[fp->lv[i].e0 + j] = ej;
1488 static void swap_side(struct s_file *fp, short si, short sj)
1490 short i, j;
1492 for (i = 0; i < fp->gc; i++)
1494 if (fp->gv[i].si == si) fp->gv[i].si = sj;
1495 if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1496 if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1498 for (i = 0; i < fp->nc; i++)
1499 if (fp->nv[i].si == si) fp->nv[i].si = sj;
1501 for (i = 0; i < fp->lc; i++)
1502 for (j = 0; j < fp->lv[i].sc; j++)
1503 if (fp->iv[fp->lv[i].s0 + j] == si)
1504 fp->iv[fp->lv[i].s0 + j] = sj;
1507 static void swap_texc(struct s_file *fp, short ti, short tj)
1509 short i;
1511 for (i = 0; i < fp->gc; i++)
1513 if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1514 if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1515 if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1520 static void swap_geom(struct s_file *fp, short gi, short gj)
1522 short i, j;
1524 for (i = 0; i < fp->lc; i++)
1525 for (j = 0; j < fp->lv[i].gc; j++)
1526 if (fp->iv[fp->lv[i].g0 + j] == gi)
1527 fp->iv[fp->lv[i].g0 + j] = gj;
1529 for (i = 0; i < fp->bc; i++)
1530 for (j = 0; j < fp->bv[i].gc; j++)
1531 if (fp->iv[fp->bv[i].g0 + j] == gi)
1532 fp->iv[fp->bv[i].g0 + j] = gj;
1535 /*---------------------------------------------------------------------------*/
1537 static void uniq_mtrl(struct s_file *fp)
1539 short i, j, k = 0;
1541 for (i = 0; i < fp->mc; i++)
1543 for (j = 0; j < i; j++)
1544 if (comp_mtrl(fp->mv + i, fp->mv + j))
1546 swap_mtrl(fp, i, j);
1547 break;
1550 if (i == j)
1552 if (i != k)
1554 fp->mv[k] = fp->mv[i];
1555 swap_mtrl(fp, i, k);
1557 k++;
1561 fp->mc = k;
1564 static void uniq_vert(struct s_file *fp)
1566 short i, j, k = 0;
1568 for (i = 0; i < fp->vc; i++)
1570 for (j = 0; j < i; j++)
1571 if (comp_vert(fp->vv + i, fp->vv + j))
1573 swap_vert(fp, i, j);
1574 break;
1577 if (i == j)
1579 if (i != k)
1581 fp->vv[k] = fp->vv[i];
1582 swap_vert(fp, i, k);
1584 k++;
1588 fp->vc = k;
1591 static void uniq_edge(struct s_file *fp)
1593 short i, j, k = 0;
1595 for (i = 0; i < fp->ec; i++)
1597 for (j = 0; j < i; j++)
1598 if (comp_edge(fp->ev + i, fp->ev + j))
1600 swap_edge(fp, i, j);
1601 break;
1604 if (i == j)
1606 if (i != k)
1608 fp->ev[k] = fp->ev[i];
1609 swap_edge(fp, i, k);
1611 k++;
1615 fp->ec = k;
1618 static void uniq_geom(struct s_file *fp)
1620 short i, j, k = 0;
1622 for (i = 0; i < fp->gc; i++)
1624 for (j = 0; j < i; j++)
1625 if (comp_geom(fp->gv + i, fp->gv + j))
1627 swap_geom(fp, i, j);
1628 break;
1631 if (i == j)
1633 if (i != k)
1635 fp->gv[k] = fp->gv[i];
1636 swap_geom(fp, i, k);
1638 k++;
1642 fp->gc = k;
1645 static void uniq_texc(struct s_file *fp)
1647 short i, j, k = 0;
1649 for (i = 0; i < fp->tc; i++)
1651 for (j = 0; j < i; j++)
1652 if (comp_texc(fp->tv + i, fp->tv + j))
1654 swap_texc(fp, i, j);
1655 break;
1658 if (i == j)
1660 if (i != k)
1662 fp->tv[k] = fp->tv[i];
1663 swap_texc(fp, i, k);
1665 k++;
1669 fp->tc = k;
1672 static void uniq_side(struct s_file *fp)
1674 short i, j, k = 0;
1676 for (i = 0; i < fp->sc; i++)
1678 for (j = 0; j < i; j++)
1679 if (comp_side(fp->sv + i, fp->sv + j))
1681 swap_side(fp, i, j);
1682 break;
1685 if (i == j)
1687 if (i != k)
1689 fp->sv[k] = fp->sv[i];
1690 swap_side(fp, i, k);
1692 k++;
1696 fp->sc = k;
1699 static void uniq_file(struct s_file *fp)
1701 uniq_mtrl(fp);
1702 uniq_vert(fp);
1703 uniq_edge(fp);
1704 uniq_side(fp);
1705 uniq_texc(fp);
1706 uniq_geom(fp);
1709 /*---------------------------------------------------------------------------*/
1711 static void sort_file(struct s_file *fp)
1713 int i, j;
1715 /* Sort billboards farthest to nearest. */
1717 for (i = 0; i < fp->rc; i++)
1718 for (j = i + 1; j < fp->rc; j++)
1719 if (fp->rv[j].d > fp->rv[i].d)
1721 struct s_bill t;
1723 t = fp->rv[i];
1724 fp->rv[i] = fp->rv[j];
1725 fp->rv[j] = t;
1728 /* Ensure the first vertex is the lowest. */
1730 for (i = 0; i < fp->vc; i++)
1731 if (fp->vv[0].p[1] > fp->vv[i].p[1])
1733 struct s_vert t;
1735 t = fp->vv[0];
1736 fp->vv[0] = fp->vv[i];
1737 fp->vv[i] = t;
1739 swap_vert(fp, 0, -1);
1740 swap_vert(fp, i, 0);
1741 swap_vert(fp, -1, i);
1745 /*---------------------------------------------------------------------------*/
1747 static int test_lump_side(const struct s_file *fp,
1748 const struct s_lump *lp,
1749 const struct s_side *sp)
1751 short si;
1752 short vi;
1754 short f = 0;
1755 short b = 0;
1757 /* If the given side is part of the given lump, then the lump is behind. */
1759 for (si = 0; si < lp->sc; si++)
1760 if (fp->sv + fp->iv[lp->s0 + si] == sp)
1761 return -1;
1763 /* Check if each lump vertex is in front of, behind, on the side. */
1765 for (vi = 0; vi < lp->vc; vi++)
1767 float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
1769 if (d > 0) f++;
1770 if (d < 0) b++;
1773 /* If no verts are behind, the lump is in front, and vice versa. */
1775 if (f > 0 && b == 0) return +1;
1776 if (b > 0 && f == 0) return -1;
1778 /* Else, the lump crosses the side. */
1780 return 0;
1783 static int node_node(struct s_file *fp, short l0, short lc)
1785 if (lc < 8)
1787 /* Base case. Dump all given lumps into a leaf node. */
1789 fp->nv[fp->nc].si = -1;
1790 fp->nv[fp->nc].ni = -1;
1791 fp->nv[fp->nc].nj = -1;
1792 fp->nv[fp->nc].l0 = l0;
1793 fp->nv[fp->nc].lc = lc;
1795 return fp->nc++;
1797 else
1799 short sj = 0;
1800 short sjd = lc;
1801 short sjo = lc;
1802 short si;
1803 short li = 0, lic = 0;
1804 short lj = 0, ljc = 0;
1805 short lk = 0, lkc = 0;
1806 short i;
1808 /* Find the side that most evenly splits the given lumps. */
1810 for (si = 0; si < fp->sc; si++)
1812 short o = 0;
1813 short d = 0;
1814 short k = 0;
1816 for (li = 0; li < lc; li++)
1817 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
1818 d += k;
1819 else
1820 o++;
1822 d = abs(d);
1824 if ((d < sjd) || (d == sjd && o < sjo))
1826 sj = si;
1827 sjd = d;
1828 sjo = o;
1832 /* Flag each lump with its position WRT the side. */
1834 for (li = 0; li < lc; li++)
1835 switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
1837 case +1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10; break;
1838 case 0: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20; break;
1839 case -1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40; break;
1842 /* Sort all lumps in the range by their flag values. */
1844 for (li = 1; li < lc; li++)
1845 for (lj = 0; lj < li; lj++)
1846 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
1848 struct s_lump l;
1850 l = fp->lv[l0 + li];
1851 fp->lv[l0 + li] = fp->lv[l0 + lj];
1852 fp->lv[l0 + lj] = l;
1855 /* Establish the in-front, on, and behind lump ranges. */
1857 li = lic = 0;
1858 lj = ljc = 0;
1859 lk = lkc = 0;
1861 for (i = lc - 1; i >= 0; i--)
1862 switch (fp->lv[l0 + i].fl & 0xf0)
1864 case 0x10: li = l0 + i; lic++; break;
1865 case 0x20: lj = l0 + i; ljc++; break;
1866 case 0x40: lk = l0 + i; lkc++; break;
1869 /* Add the lumps on the side to the node. */
1871 i = fp->nc++;
1873 fp->nv[i].si = sj;
1874 fp->nv[i].ni = node_node(fp, li, lic);
1876 fp->nv[i].nj = node_node(fp, lk, lkc);
1877 fp->nv[i].l0 = lj;
1878 fp->nv[i].lc = ljc;
1880 return i;
1884 static void node_file(struct s_file *fp)
1886 short bi;
1888 /* Sort the lumps of each body into BSP nodes. */
1890 for (bi = 0; bi < fp->bc; bi++)
1891 fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
1894 /*---------------------------------------------------------------------------*/
1896 static void dump_file(struct s_file *p, const char *name)
1898 short i, j;
1899 int c = 0;
1900 int n = 0;
1901 int m = p->rc + p->cc * 128 + (p->zc * p->jc + p->xc) * 32;
1903 /* Count the number of solid lumps. */
1905 for (i = 0; i < p->lc; i++)
1906 if ((p->lv[i].fl & 1) == 0)
1907 n++;
1909 /* Count the number of visible geoms. */
1911 for (i = 0; i < p->bc; i++)
1913 for (j = 0; j < p->bv[i].lc; j++)
1914 m += p->lv[p->bv[i].l0 + j].gc;
1915 m += p->bv[i].gc;
1918 /* Count the total value of all coins. */
1920 for (i = 0; i < p->cc; i++)
1921 c += p->cv[i].n;
1923 printf("%s (%d/%d/$%d)\n"
1924 " mtrl vert edge side texc"
1925 " geom lump path node body\n"
1926 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
1927 " coin goal view jump swch"
1928 " bill ball char indx\n"
1929 "%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
1930 name, n, m, c,
1931 p->mc, p->vc, p->ec, p->sc, p->tc,
1932 p->gc, p->lc, p->pc, p->nc, p->bc,
1933 p->cc, p->zc, p->wc, p->jc, p->xc,
1934 p->rc, p->uc, p->ac, p->ic);
1937 int main(int argc, char *argv[])
1939 char src[MAXSTR];
1940 char dst[MAXSTR];
1941 struct s_file f;
1942 FILE *fin;
1944 if (argc > 2)
1946 if (config_data_path(argv[2], NULL))
1948 strncpy(src, argv[1], MAXSTR);
1949 strncpy(dst, argv[1], MAXSTR);
1951 if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
1952 strcpy(dst + strlen(dst) - 4, ".sol");
1953 else
1954 strcat(dst, ".sol");
1956 if ((fin = fopen(src, "r")))
1958 init_file(&f);
1959 read_map(&f, fin);
1961 resolve();
1962 targets(&f);
1964 clip_file(&f);
1965 move_file(&f);
1966 uniq_file(&f);
1967 sort_file(&f);
1968 node_file(&f);
1969 dump_file(&f, dst);
1971 sol_stor(&f, dst);
1973 fclose(fin);
1976 else fprintf(stderr, "Failure to establish data directory\n");
1978 else fprintf(stderr, "Usage: %s <map> [data]\n", argv[0]);
1980 return 0;