Almost completely separate coins and items in share/geom.c. Items still
[neverball] / share / mapc.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
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.
8  *
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.
13  */
14
15 /*---------------------------------------------------------------------------*/
16
17 #ifdef WIN32
18 #pragma comment(lib, "SDL_ttf.lib")
19 #pragma comment(lib, "SDL_image.lib")
20 #pragma comment(lib, "SDL_mixer.lib")
21 #pragma comment(lib, "SDL.lib")
22 #pragma comment(lib, "SDLmain.lib")
23 #pragma comment(lib, "opengl32.lib")
24 #endif
25
26 /*---------------------------------------------------------------------------*/
27
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>
34
35 #include "vec3.h"
36 #include "solid.h"
37 #include "base_config.h"
38
39 #define MAXSTR 256
40 #define MAXKEY 16
41 #define SCALE  64.f
42 #define SMALL  0.0005f
43
44 /*
45  * The overall design  of this map converter is  very stupid, but very
46  * simple. It  begins by assuming  that every mtrl, vert,  edge, side,
47  * and texc  in the map is  unique.  It then makes  an optimizing pass
48  * that discards redundant information.  The result is optimal, though
49  * the process is terribly inefficient.
50  */
51
52 /*---------------------------------------------------------------------------*/
53
54 /* Ohhhh... arbitrary! */
55
56 #define MAXM    256
57 #define MAXV    32767
58 #define MAXE    32767
59 #define MAXS    32767
60 #define MAXT    32767
61 #define MAXG    32767
62 #define MAXL    1024
63 #define MAXN    1024
64 #define MAXP    512
65 #define MAXB    512
66 #define MAXC    1024
67 #define MAXH    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 MAXD    128
75 #define MAXA    8192
76 #define MAXI    32767
77
78 static int overflow(const char *s)
79 {
80     printf("%s overflow\n", s);
81     exit(1);
82     return 0;
83 }
84
85 static int incm(struct s_file *fp)
86 {
87     return (fp->mc < MAXM) ? fp->mc++ : overflow("mtrl");
88 }
89
90 static int incv(struct s_file *fp)
91 {
92     return (fp->vc < MAXV) ? fp->vc++ : overflow("vert");
93 }
94
95 static int ince(struct s_file *fp)
96 {
97     return (fp->ec < MAXE) ? fp->ec++ : overflow("edge");
98 }
99
100 static int incs(struct s_file *fp)
101 {
102     return (fp->sc < MAXS) ? fp->sc++ : overflow("side");
103 }
104
105 static int inct(struct s_file *fp)
106 {
107     return (fp->tc < MAXT) ? fp->tc++ : overflow("texc");
108 }
109
110 static int incg(struct s_file *fp)
111 {
112     return (fp->gc < MAXG) ? fp->gc++ : overflow("geom");
113 }
114
115 static int incl(struct s_file *fp)
116 {
117     return (fp->lc < MAXL) ? fp->lc++ : overflow("lump");
118 }
119
120 static int incn(struct s_file *fp)
121 {
122     return (fp->nc < MAXN) ? fp->nc++ : overflow("node");
123 }
124
125 static int incp(struct s_file *fp)
126 {
127     return (fp->pc < MAXP) ? fp->pc++ : overflow("path");
128 }
129
130 static int incb(struct s_file *fp)
131 {
132     return (fp->bc < MAXB) ? fp->bc++ : overflow("body");
133 }
134
135 static int incc(struct s_file *fp)
136 {
137     return (fp->cc < MAXC) ? fp->cc++ : overflow("coin");
138 }
139
140 static int inch(struct s_file *fp)
141 {
142     return (fp->hc < MAXH) ? fp->hc++ : overflow("item");
143 }
144
145 static int incz(struct s_file *fp)
146 {
147     return (fp->zc < MAXZ) ? fp->zc++ : overflow("geol");
148 }
149
150 static int incj(struct s_file *fp)
151 {
152     return (fp->jc < MAXJ) ? fp->jc++ : overflow("jump");
153 }
154
155 static int incx(struct s_file *fp)
156 {
157     return (fp->xc < MAXX) ? fp->xc++ : overflow("swch");
158 }
159
160 static int incr(struct s_file *fp)
161 {
162     return (fp->rc < MAXR) ? fp->rc++ : overflow("bill");
163 }
164
165 static int incu(struct s_file *fp)
166 {
167     return (fp->uc < MAXU) ? fp->uc++ : overflow("ball");
168 }
169
170 static int incw(struct s_file *fp)
171 {
172     return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
173 }
174
175 static int inci(struct s_file *fp)
176 {
177     return (fp->ic < MAXI) ? fp->ic++ : overflow("indx");
178 }
179
180 static void init_file(struct s_file *fp)
181 {
182     fp->mc = 0;
183     fp->vc = 0;
184     fp->ec = 0;
185     fp->sc = 0;
186     fp->tc = 0;
187     fp->gc = 0;
188     fp->lc = 0;
189     fp->nc = 0;
190     fp->pc = 0;
191     fp->bc = 0;
192     fp->cc = 0;
193     fp->hc = 0;
194     fp->zc = 0;
195     fp->jc = 0;
196     fp->xc = 0;
197     fp->rc = 0;
198     fp->uc = 0;
199     fp->wc = 0;
200     fp->ac = 0;
201     fp->ic = 0;
202
203     fp->mv = (struct s_mtrl *) calloc(MAXM, sizeof (struct s_mtrl));
204     fp->vv = (struct s_vert *) calloc(MAXV, sizeof (struct s_vert));
205     fp->ev = (struct s_edge *) calloc(MAXE, sizeof (struct s_edge));
206     fp->sv = (struct s_side *) calloc(MAXS, sizeof (struct s_side));
207     fp->tv = (struct s_texc *) calloc(MAXT, sizeof (struct s_texc));
208     fp->gv = (struct s_geom *) calloc(MAXG, sizeof (struct s_geom));
209     fp->lv = (struct s_lump *) calloc(MAXL, sizeof (struct s_lump));
210     fp->nv = (struct s_node *) calloc(MAXN, sizeof (struct s_node));
211     fp->pv = (struct s_path *) calloc(MAXP, sizeof (struct s_path));
212     fp->bv = (struct s_body *) calloc(MAXB, sizeof (struct s_body));
213     fp->cv = (struct s_coin *) calloc(MAXC, sizeof (struct s_coin));
214     fp->hv = (struct s_item *) calloc(MAXH, sizeof (struct s_item));
215     fp->zv = (struct s_goal *) calloc(MAXZ, sizeof (struct s_goal));
216     fp->jv = (struct s_jump *) calloc(MAXJ, sizeof (struct s_jump));
217     fp->xv = (struct s_swch *) calloc(MAXX, sizeof (struct s_swch));
218     fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
219     fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
220     fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
221     fp->av = (char          *) calloc(MAXA, sizeof (char));
222     fp->iv = (int           *) calloc(MAXI, sizeof (int));
223 }
224
225 /*---------------------------------------------------------------------------*/
226
227 /*
228  * The following is a small  symbol table data structure.  Symbols and
229  * their integer  values are collected  in symv and  valv.  References
230  * and pointers  to their unsatisfied integer values  are collected in
231  * refv and pntv.  The resolve procedure matches references to symbols
232  * and fills waiting ints with the proper values.
233  */
234
235 #define MAXSYM 1024
236
237 static char symv[MAXSYM][MAXSTR];
238 static int  valv[MAXSYM];
239
240 static char refv[MAXSYM][MAXSTR];
241 static int *pntv[MAXSYM];
242
243 static int  strc;
244 static int  refc;
245
246 static void make_sym(const char *s, int  v)
247 {
248     strncpy(symv[strc], s, MAXSTR - 1);
249     valv[strc] = v;
250     strc++;
251 }
252
253 static void make_ref(const char *r, int *p)
254 {
255     strncpy(refv[refc], r, MAXSTR - 1);
256     pntv[refc] = p;
257     refc++;
258 }
259
260 static void resolve(void)
261 {
262     int i, j;
263
264     for (i = 0; i < refc; i++)
265         for (j = 0; j < strc; j++)
266             if (strncmp(refv[i], symv[j], MAXSTR) == 0)
267             {
268                 *(pntv[i]) = valv[j];
269                 break;
270             }
271 }
272
273 /*---------------------------------------------------------------------------*/
274
275 /*
276  * The following globals are used to cache target_positions.  They are
277  * targeted by various entities and must be resolved in a second pass.
278  */
279
280 static float targ_p [MAXW][3];
281 static int   targ_wi[MAXW];
282 static int   targ_ji[MAXW];
283 static int   targ_n;
284
285 static void targets(struct s_file *fp)
286 {
287     int i;
288
289     for (i = 0; i < fp->wc; i++)
290         v_cpy(fp->wv[i].q, targ_p[targ_wi[i]]);
291
292     for (i = 0; i < fp->jc; i++)
293         v_cpy(fp->jv[i].q, targ_p[targ_ji[i]]);
294 }
295
296 /*---------------------------------------------------------------------------*/
297
298 /*
299  * The following code caches  image sizes.  Textures are referenced by
300  * name,  but  their  sizes   are  necessary  when  computing  texture
301  * coordinates.  This code  allows each file to be  accessed only once
302  * regardless of the number of surfaces refering to it.
303  */
304
305 struct _imagedata
306 {
307     char *s;
308     int w, h;
309 };
310
311 static struct _imagedata *imagedata = NULL;
312 static int image_n = 0;
313 static int image_alloc = 0;
314
315 #define IMAGE_REALLOC 32
316
317 static void free_imagedata()
318 {
319     int i;
320
321     if (imagedata)
322     {
323         for (i = 0; i < image_n; i++)
324             free(imagedata[i].s);
325         free(imagedata);
326     }
327
328     image_n = image_alloc = 0;
329 }
330
331 static int size_load(const char *file, int *w, int *h)
332 {
333     SDL_Surface *S;
334
335     if ((S = IMG_Load(file)))
336     {
337         *w = S->w;
338         *h = S->h;
339
340         SDL_FreeSurface(S);
341
342         return 1;
343     }
344     return 0;
345 }
346
347 static void size_image(const char *name, int *w, int *h)
348 {
349     char jpg[MAXSTR];
350     char tga[MAXSTR];
351     char png[MAXSTR];
352     int i;
353
354     if (imagedata)
355         for (i = 0; i < image_n; i++)
356             if (strncmp(imagedata[i].s, name, MAXSTR) == 0)
357             {
358                 *w = imagedata[i].w;
359                 *h = imagedata[i].h;
360
361                 return;
362             }
363
364     *w = 0;
365     *h = 0;
366
367     strcpy(jpg, name); strcat(jpg, ".jpg");
368     strcpy(tga, name); strcat(tga, ".tga");
369     strcpy(png, name); strcat(png, ".png");
370
371     if (size_load(config_data(png), w, h) ||
372         size_load(config_data(tga), w, h) ||
373         size_load(config_data(jpg), w, h))
374     {
375
376         if (image_n + 1 >= image_alloc)
377         {
378             struct _imagedata *tmp =
379                 (struct _imagedata *) malloc(sizeof(struct _imagedata) * (image_alloc + IMAGE_REALLOC));
380             if (!tmp)
381             {
382                 printf("malloc error\n");
383                 exit(1);
384             }
385             if (imagedata)
386             {
387                 (void) memcpy(tmp, imagedata, sizeof(struct _imagedata) * image_alloc);
388                 free(imagedata);
389             }
390             imagedata = tmp;
391             image_alloc += IMAGE_REALLOC;
392         }
393
394         imagedata[image_n].s = (char *) calloc(strlen(name) + 1, 1);
395         imagedata[image_n].w = *w;
396         imagedata[image_n].h = *h;
397         strcpy(imagedata[image_n].s, name);
398
399         image_n++;
400     }
401 }
402
403 /*---------------------------------------------------------------------------*/
404
405 /* Read the given material file, adding a new material to the solid.  */
406
407 static int read_mtrl(struct s_file *fp, const char *name)
408 {
409     struct s_mtrl *mp;
410     FILE *fin;
411     int mi;
412
413     for (mi = 0; mi < fp->mc; mi++)
414         if (strncmp(name, fp->mv[mi].f, MAXSTR) == 0)
415             return mi;
416
417     mp = fp->mv + incm(fp);
418
419     strncpy(mp->f, name, PATHMAX - 1);
420
421     mp->a[0] = mp->a[1] = mp->a[2] = mp->a[3] = 1.0f;
422     mp->d[0] = mp->d[1] = mp->d[2] = mp->d[3] = 1.0f;
423     mp->s[0] = mp->s[1] = mp->s[2] = mp->s[3] = 1.0f;
424     mp->e[0] = mp->e[1] = mp->e[2] = mp->e[3] = 1.0f;
425     mp->h[0] = 0.0f;
426     mp->fl   = 0;
427
428     if ((fin = fopen(config_data(name), "r")))
429     {
430         fscanf(fin,
431                "%f %f %f %f "
432                "%f %f %f %f "
433                "%f %f %f %f "
434                "%f %f %f %f "
435                "%f %d ",
436                mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
437                mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
438                mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
439                mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
440                mp->h, &mp->fl);
441         fclose(fin);
442     }
443
444     return mi;
445 }
446
447 /*---------------------------------------------------------------------------*/
448
449 /*
450  * All bodies with an associated  path are assumed to be positioned at
451  * the  beginning of that  path.  These  bodies must  be moved  to the
452  * origin  in order  for their  path transforms  to  behave correctly.
453  * This is  how we get away  with defining func_trains  with no origin
454  * specification.
455  */
456
457 static void move_side(struct s_side *sp, const float p[3])
458 {
459     sp->d -= v_dot(sp->n, p);
460 }
461
462 static void move_vert(struct s_vert *vp, const float p[3])
463 {
464     v_sub(vp->p, vp->p, p);
465 }
466
467 static void move_lump(struct s_file *fp,
468                       struct s_lump *lp, const float p[3])
469 {
470     int i;
471
472     for (i = 0; i < lp->sc; i++)
473         move_side(fp->sv + fp->iv[lp->s0 + i], p);
474     for (i = 0; i < lp->vc; i++)
475         move_vert(fp->vv + fp->iv[lp->v0 + i], p);
476 }
477
478 static void move_body(struct s_file *fp,
479                       struct s_body *bp)
480 {
481     int i;
482
483     for (i = 0; i < bp->lc; i++)
484         move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
485 }
486
487 static void move_file(struct s_file *fp)
488 {
489     int i;
490
491     for (i = 0; i < fp->bc; i++)
492         if (fp->bv[i].pi >= 0)
493             move_body(fp, fp->bv + i);
494 }
495
496 /*---------------------------------------------------------------------------*/
497
498 /*
499  * This is a basic OBJ loader.  It is by no means fully compliant with
500  * the  OBJ  specification, but  it  works  well  with the  output  of
501  * Wings3D.  All faces must be triangles and all vertices must include
502  * normals and  texture coordinates.  Material  names are taken  to be
503  * references to Neverball materials, rather than MTL definitions.
504  */
505
506 static void read_vt(struct s_file *fp, const char *line)
507 {
508     struct s_texc *tp = fp->tv + inct(fp);
509
510     sscanf(line, "%f %f", tp->u, tp->u + 1);
511 }
512
513 static void read_vn(struct s_file *fp, const char *line)
514 {
515     struct s_side *sp = fp->sv + incs(fp);
516
517     sscanf(line, "%f %f %f", sp->n, sp->n + 1, sp->n + 2);
518 }
519
520 static void read_v(struct s_file *fp, const char *line)
521 {
522     struct s_vert *vp = fp->vv + incv(fp);
523
524     sscanf(line, "%f %f %f", vp->p, vp->p + 1, vp->p + 2);
525 }
526
527 static void read_f(struct s_file *fp, const char *line,
528                    int v0, int t0, int s0, int mi)
529 {
530     struct s_geom *gp = fp->gv + incg(fp);
531
532     char c1;
533     char c2;
534
535     sscanf(line, "%d%c%d%c%d %d%c%d%c%d %d%c%d%c%d",
536            &gp->vi, &c1, &gp->ti, &c2, &gp->si,
537            &gp->vj, &c1, &gp->tj, &c2, &gp->sj,
538            &gp->vk, &c1, &gp->tk, &c2, &gp->sk);
539
540     gp->vi += (v0 - 1);
541     gp->vj += (v0 - 1);
542     gp->vk += (v0 - 1);
543     gp->ti += (t0 - 1);
544     gp->tj += (t0 - 1);
545     gp->tk += (t0 - 1);
546     gp->si += (s0 - 1);
547     gp->sj += (s0 - 1);
548     gp->sk += (s0 - 1);
549
550     gp->mi  = mi;
551 }
552
553 static void read_obj(struct s_file *fp, const char *name)
554 {
555     char line[MAXSTR];
556     char mtrl[MAXSTR];
557     FILE *fin;
558
559     int v0 = fp->vc;
560     int t0 = fp->tc;
561     int s0 = fp->sc;
562     int mi = 0;
563
564     if ((fin = fopen(config_data(name), "r")))
565     {
566         while (fgets(line, MAXSTR, fin))
567         {
568             if (strncmp(line, "usemtl", 6) == 0)
569             {
570                 sscanf(line + 6, "%s", mtrl);
571                 mi = read_mtrl(fp, mtrl);
572             }
573
574             else if (strncmp(line, "f", 1) == 0)
575             {
576                 if (fp->mv[mi].d[3] > 0)
577                     read_f(fp, line + 1, v0, t0, s0, mi);
578             }
579
580             else if (strncmp(line, "vt", 2) == 0) read_vt(fp, line + 2);
581             else if (strncmp(line, "vn", 2) == 0) read_vn(fp, line + 2);
582             else if (strncmp(line, "v",  1) == 0) read_v (fp, line + 1);
583         }
584         fclose(fin);
585     }
586 }
587
588 /*---------------------------------------------------------------------------*/
589
590 static float plane_d[MAXS];
591 static float plane_n[MAXS][3];
592 static float plane_p[MAXS][3];
593 static float plane_u[MAXS][3];
594 static float plane_v[MAXS][3];
595 static int   plane_f[MAXS];
596 static int   plane_m[MAXS];
597
598 static void make_plane(int pi, int x0, int y0, int z0,
599                        int x1, int y1, int z1,
600                        int x2, int y2, int z2,
601                        int tu, int tv, int r,
602                        float su, float sv, int fl, const char *s)
603 {
604     static const float base[6][3][3] = {
605         {{  0,  0,  1 }, {  1,  0,  0 }, {  0, -1,  0 }},
606         {{  0,  0, -1 }, {  1,  0,  0 }, {  0, -1,  0 }},
607         {{  1,  0,  0 }, {  0,  0, -1 }, {  0, -1,  0 }},
608         {{ -1,  0,  0 }, {  0,  0, -1 }, {  0, -1,  0 }},
609         {{  0,  1,  0 }, {  1,  0,  0 }, {  0,  0,  1 }},
610         {{  0, -1,  0 }, {  1,  0,  0 }, {  0,  0,  1 }},
611     };
612
613     float R[16];
614     float p0[3], p1[3], p2[3];
615     float u[3],  v[3],  p[3];
616     float k, d = 0.0f;
617     int   i, n = 0;
618     int   w, h;
619
620     size_image(s, &w, &h);
621
622     plane_f[pi] = fl ? L_DETAIL : 0;
623
624     p0[0] = +(float) x0 / SCALE;
625     p0[1] = +(float) z0 / SCALE;
626     p0[2] = -(float) y0 / SCALE;
627
628     p1[0] = +(float) x1 / SCALE;
629     p1[1] = +(float) z1 / SCALE;
630     p1[2] = -(float) y1 / SCALE;
631
632     p2[0] = +(float) x2 / SCALE;
633     p2[1] = +(float) z2 / SCALE;
634     p2[2] = -(float) y2 / SCALE;
635
636     v_sub(u, p0, p1);
637     v_sub(v, p2, p1);
638
639     v_crs(plane_n[pi], u, v);
640     v_nrm(plane_n[pi], plane_n[pi]);
641
642     plane_d[pi] = v_dot(plane_n[pi], p1);
643
644     for (i = 0; i < 6; i++)
645         if ((k = v_dot(plane_n[pi], base[i][0])) >= d)
646         {
647             d = k;
648             n = i;
649         }
650
651     p[0] = 0.f;
652     p[1] = 0.f;
653     p[2] = 0.f;
654
655     m_rot(R, base[n][0], V_RAD(r));
656
657     v_mad(p, p, base[n][1], su * tu / SCALE);
658     v_mad(p, p, base[n][2], sv * tv / SCALE);
659
660     m_vxfm(plane_u[pi], R, base[n][1]);
661     m_vxfm(plane_v[pi], R, base[n][2]);
662     m_vxfm(plane_p[pi], R, p);
663
664     v_scl(plane_u[pi], plane_u[pi], 64.f / w);
665     v_scl(plane_v[pi], plane_v[pi], 64.f / h);
666
667     v_scl(plane_u[pi], plane_u[pi], 1.f / su);
668     v_scl(plane_v[pi], plane_v[pi], 1.f / sv);
669 }
670
671 /*---------------------------------------------------------------------------*/
672
673 #define T_EOF 0
674 #define T_BEG 1
675 #define T_CLP 2
676 #define T_KEY 3
677 #define T_END 4
678 #define T_NOP 5
679
680 static int map_token(FILE *fin, int pi, char key[MAXSTR], char val[MAXSTR])
681 {
682     char buf[MAXSTR];
683
684     if (fgets(buf, MAXSTR, fin))
685     {
686         char c;
687         int x0, y0, z0;
688         int x1, y1, z1;
689         int x2, y2, z2;
690         int tu, tv, r;
691         float su, sv;
692         int fl;
693
694         /* Scan the beginning or end of a block. */
695
696         if (buf[0] == '{') return T_BEG;
697         if (buf[0] == '}') return T_END;
698
699         /* Scan a key-value pair. */
700
701         if (buf[0] == '"')
702         {
703             strcpy(key, strtok(buf,  "\""));
704             (void)      strtok(NULL, "\"");
705             strcpy(val, strtok(NULL, "\""));
706
707             return T_KEY;
708         }
709
710         /* Scan a plane. */
711
712         if (sscanf(buf,
713                    "%c %d %d %d %c "
714                    "%c %d %d %d %c "
715                    "%c %d %d %d %c "
716                    "%s %d %d %d %f %f %d",
717                    &c, &x0, &y0, &z0, &c,
718                    &c, &x1, &y1, &z1, &c,
719                    &c, &x2, &y2, &z2, &c,
720                    key, &tu, &tv, &r, &su, &sv, &fl) == 22)
721         {
722             make_plane(pi, x0, y0, z0,
723                        x1, y1, z1,
724                        x2, y2, z2,
725                        tu, tv, r, su, sv, fl, key);
726             return T_CLP;
727         }
728
729         /* If it's not recognized, it must be uninteresting. */
730
731         return T_NOP;
732     }
733     return T_EOF;
734 }
735
736 /*---------------------------------------------------------------------------*/
737
738 /* Parse a lump from the given file and add it to the solid. */
739
740 static void read_lump(struct s_file *fp, FILE *fin)
741 {
742     char k[MAXSTR];
743     char v[MAXSTR];
744     int t;
745
746     struct s_lump *lp = fp->lv + incl(fp);
747
748     lp->s0 = fp->ic;
749
750     while ((t = map_token(fin, fp->sc, k, v)))
751     {
752         if (t == T_CLP)
753         {
754             fp->sv[fp->sc].n[0] = plane_n[fp->sc][0];
755             fp->sv[fp->sc].n[1] = plane_n[fp->sc][1];
756             fp->sv[fp->sc].n[2] = plane_n[fp->sc][2];
757             fp->sv[fp->sc].d    = plane_d[fp->sc];
758
759             plane_m[fp->sc] = read_mtrl(fp, k);
760
761             fp->iv[fp->ic] = fp->sc;
762             inci(fp);
763             incs(fp);
764             lp->sc++;
765         }
766         if (t == T_END)
767             break;
768     }
769 }
770
771 /*---------------------------------------------------------------------------*/
772
773 static void make_path(struct s_file *fp,
774                       char k[][MAXSTR],
775                       char v[][MAXSTR], int c)
776 {
777     int i, pi = incp(fp);
778
779     struct s_path *pp = fp->pv + pi;
780
781     pp->p[0] = 0.f;
782     pp->p[1] = 0.f;
783     pp->p[2] = 0.f;
784     pp->t    = 1.f;
785     pp->pi   = pi;
786     pp->f    = 1;
787
788     for (i = 0; i < c; i++)
789     {
790         if (strcmp(k[i], "targetname") == 0)
791             make_sym(v[i], pi);
792
793         if (strcmp(k[i], "target") == 0)
794             make_ref(v[i], &pp->pi);
795
796         if (strcmp(k[i], "state") == 0)
797             pp->f = atoi(v[i]);
798
799         if (strcmp(k[i], "speed") == 0)
800             sscanf(v[i], "%f", &pp->t);
801
802         if (strcmp(k[i], "origin") == 0)
803         {
804             int x = 0, y = 0, z = 0;
805
806             sscanf(v[i], "%d %d %d", &x, &y, &z);
807
808             pp->p[0] = +(float) x / SCALE;
809             pp->p[1] = +(float) z / SCALE;
810             pp->p[2] = -(float) y / SCALE;
811         }
812     }
813 }
814
815 static void make_body(struct s_file *fp,
816                       char k[][MAXSTR],
817                       char v[][MAXSTR], int c, int l0)
818 {
819     int i, bi = incb(fp);
820
821     int g0 = fp->gc;
822     int v0 = fp->vc;
823
824     float p[3];
825
826     int x = 0;
827     int y = 0;
828     int z = 0;
829
830     struct s_body *bp = fp->bv + bi;
831
832     bp->t  = 0.f;
833     bp->pi = -1;
834     bp->ni = -1;
835
836     for (i = 0; i < c; i++)
837     {
838         if (strcmp(k[i], "targetname") == 0)
839             make_sym(v[i], bi);
840
841         else if (strcmp(k[i], "target") == 0)
842             make_ref(v[i], &bp->pi);
843
844         else if (strcmp(k[i], "model") == 0)
845             read_obj(fp, v[i]);
846
847         else if (strcmp(k[i], "origin") == 0)
848             sscanf(v[i], "%d %d %d", &x, &y, &z);
849
850         else if (strcmp(k[i], "classname") != 0)
851         {
852             /* Considers other strings as metadata */
853             strcat(fp->av, k[i]);
854             strcat(fp->av, "=");
855             strcat(fp->av, v[i]);
856             strcat(fp->av, "\n");
857             fp->ac += (int) (strlen(v[i]) + (strlen(k[i])) + 2);
858         }
859     }
860
861     bp->l0 = l0;
862     bp->lc = fp->lc - l0;
863     bp->g0 = fp->ic;
864     bp->gc = fp->gc - g0;
865
866     for (i = 0; i < bp->gc; i++)
867         fp->iv[inci(fp)] = g0++;
868
869     p[0] = +(float) x / SCALE;
870     p[1] = +(float) z / SCALE;
871     p[2] = -(float) y / SCALE;
872
873     for (i = v0; i < fp->vc; i++)
874         v_add(fp->vv[i].p, fp->vv[i].p, p);
875 }
876
877 static void make_coin(struct s_file *fp,
878                       char k[][MAXSTR],
879                       char v[][MAXSTR], int c)
880 {
881     int i, ci = incc(fp);
882
883     struct s_coin *cp = fp->cv + ci;
884
885     cp->p[0] = 0.f;
886     cp->p[1] = 0.f;
887     cp->p[2] = 0.f;
888     cp->n    = 1;
889
890     for (i = 0; i < c; i++)
891     {
892         if (strcmp(k[i], "light") == 0)
893             sscanf(v[i], "%d", &cp->n);
894
895         if (strcmp(k[i], "origin") == 0)
896         {
897             int x = 0, y = 0, z = 0;
898
899             sscanf(v[i], "%d %d %d", &x, &y, &z);
900
901             cp->p[0] = +(float) x / SCALE;
902             cp->p[1] = +(float) z / SCALE;
903             cp->p[2] = -(float) y / SCALE;
904         }
905     }
906 }
907
908 static void make_item(struct s_file *fp,
909                       char k[][MAXSTR],
910                       char v[][MAXSTR], int c)
911 {
912     int i, hi = inch(fp);
913
914     struct s_item *hp = fp->hv + hi;
915
916     hp->p[0] = 0.f;
917     hp->p[1] = 0.f;
918     hp->p[2] = 0.f;
919
920     hp->t = ITEM_NONE;
921
922     for (i = 0; i < c; i++)
923     {
924         if (strcmp(k[i], "classname") == 0)
925         {
926             if (strcmp(v[i], "item_health_large") == 0)
927                 hp->t = ITEM_GROW;
928             else if (strcmp(v[i], "item_health_small") == 0)
929                 hp->t = ITEM_SHRINK;
930         }
931
932         if (strcmp(k[i], "origin") == 0)
933         {
934             int x = 0, y = 0, z = 0;
935
936             sscanf(v[i], "%d %d %d", &x, &y, &z);
937
938             hp->p[0] = +(float) x / SCALE;
939             hp->p[1] = +(float) z / SCALE;
940             hp->p[2] = -(float) y / SCALE;
941         }
942     }
943 }
944
945 static void make_bill(struct s_file *fp,
946                       char k[][MAXSTR],
947                       char v[][MAXSTR], int c)
948 {
949     int i, ri = incr(fp);
950
951     struct s_bill *rp = fp->rv + ri;
952
953     memset(rp, 0, sizeof (struct s_bill));
954     rp->t = 1.0f;
955
956     for (i = 0; i < c; i++)
957     {
958         if (strcmp(k[i], "width") == 0)
959             sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
960         if (strcmp(k[i], "height") == 0)
961             sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
962
963         if (strcmp(k[i], "xrot") == 0)
964             sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
965         if (strcmp(k[i], "yrot") == 0)
966             sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
967         if (strcmp(k[i], "zrot") == 0)
968             sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
969
970         if (strcmp(k[i], "time") == 0)
971             sscanf(v[i], "%f", &rp->t);
972         if (strcmp(k[i], "dist") == 0)
973             sscanf(v[i], "%f", &rp->d);
974         if (strcmp(k[i], "flag") == 0)
975             sscanf(v[i], "%d", &rp->fl);
976
977         if (strcmp(k[i], "image") == 0)
978         {
979             rp->mi = read_mtrl(fp, v[i]);
980             fp->mv[rp->mi].fl |= M_CLAMPED;
981         }
982
983         if (strcmp(k[i], "origin") == 0)
984         {
985             int x = 0, y = 0, z = 0;
986             float p[3];
987
988             sscanf(v[i], "%d %d %d", &x, &y, &z);
989
990             p[0] = +(float) x / SCALE;
991             p[1] = +(float) z / SCALE;
992             p[2] = -(float) y / SCALE;
993
994             rp->d     = v_len(p);
995             rp->rx[0] = V_DEG(fatan2f(+p[1], rp->d));
996             rp->ry[0] = V_DEG(fatan2f(+p[0], -p[2]));
997         }
998     }
999
1000     if (rp->fl & B_ADDITIVE)
1001         fp->mv[rp->mi].fl |= M_ADDITIVE;
1002 }
1003
1004 static void make_goal(struct s_file *fp,
1005                       char k[][MAXSTR],
1006                       char v[][MAXSTR], int c)
1007 {
1008     int i, zi = incz(fp);
1009
1010     struct s_goal *zp = fp->zv + zi;
1011
1012     zp->p[0] = 0.f;
1013     zp->p[1] = 0.f;
1014     zp->p[2] = 0.f;
1015     zp->r    = 0.75;
1016     zp->s    = 0;
1017     zp->c    = 0;
1018
1019     for (i = 0; i < c; i++)
1020     {
1021         if (strcmp(k[i], "radius") == 0)
1022             sscanf(v[i], "%f", &zp->r);
1023         if (strcmp(k[i], "skip") == 0)
1024             sscanf(v[i], "%d", &zp->s);
1025         if (strcmp(k[i], "special") == 0)
1026             sscanf(v[i], "%d", &zp->c);
1027
1028         if (strcmp(k[i], "origin") == 0)
1029         {
1030             int x = 0, y = 0, z = 0;
1031
1032             sscanf(v[i], "%d %d %d", &x, &y, &z);
1033
1034             zp->p[0] = +(float) (x)      / SCALE;
1035             zp->p[1] = +(float) (z - 24) / SCALE;
1036             zp->p[2] = -(float) (y)      / SCALE;
1037         }
1038     }
1039 }
1040
1041 static void make_view(struct s_file *fp,
1042                       char k[][MAXSTR],
1043                       char v[][MAXSTR], int c)
1044 {
1045     int i, wi = incw(fp);
1046
1047     struct s_view *wp = fp->wv + wi;
1048
1049     wp->p[0] = 0.f;
1050     wp->p[1] = 0.f;
1051     wp->p[2] = 0.f;
1052     wp->q[0] = 0.f;
1053     wp->q[1] = 0.f;
1054     wp->q[2] = 0.f;
1055
1056     for (i = 0; i < c; i++)
1057     {
1058         if (strcmp(k[i], "target") == 0)
1059             make_ref(v[i], targ_wi + wi);
1060
1061         if (strcmp(k[i], "origin") == 0)
1062         {
1063             int x = 0, y = 0, z = 0;
1064
1065             sscanf(v[i], "%d %d %d", &x, &y, &z);
1066
1067             wp->p[0] = +(float) x / SCALE;
1068             wp->p[1] = +(float) z / SCALE;
1069             wp->p[2] = -(float) y / SCALE;
1070         }
1071     }
1072 }
1073
1074 static void make_jump(struct s_file *fp,
1075                       char k[][MAXSTR],
1076                       char v[][MAXSTR], int c)
1077 {
1078     int i, ji = incj(fp);
1079
1080     struct s_jump *jp = fp->jv + ji;
1081
1082     jp->p[0] = 0.f;
1083     jp->p[1] = 0.f;
1084     jp->p[2] = 0.f;
1085     jp->q[0] = 0.f;
1086     jp->q[1] = 0.f;
1087     jp->q[2] = 0.f;
1088     jp->r    = 0.5;
1089
1090     for (i = 0; i < c; i++)
1091     {
1092         if (strcmp(k[i], "radius") == 0)
1093             sscanf(v[i], "%f", &jp->r);
1094
1095         if (strcmp(k[i], "target") == 0)
1096             make_ref(v[i], targ_ji + ji);
1097
1098         if (strcmp(k[i], "origin") == 0)
1099         {
1100             int x = 0, y = 0, z = 0;
1101
1102             sscanf(v[i], "%d %d %d", &x, &y, &z);
1103
1104             jp->p[0] = +(float) x / SCALE;
1105             jp->p[1] = +(float) z / SCALE;
1106             jp->p[2] = -(float) y / SCALE;
1107         }
1108     }
1109 }
1110
1111 static void make_swch(struct s_file *fp,
1112                       char k[][MAXSTR],
1113                       char v[][MAXSTR], int c)
1114 {
1115     int i, xi = incx(fp);
1116
1117     struct s_swch *xp = fp->xv + xi;
1118
1119     xp->p[0] = 0.f;
1120     xp->p[1] = 0.f;
1121     xp->p[2] = 0.f;
1122     xp->r    = 0.5;
1123     xp->pi   = 0;
1124     xp->t0   = 0;
1125     xp->t    = 0;
1126     xp->f0   = 0;
1127     xp->f    = 0;
1128     xp->i    = 0;
1129
1130     for (i = 0; i < c; i++)
1131     {
1132         if (strcmp(k[i], "radius") == 0)
1133             sscanf(v[i], "%f", &xp->r);
1134
1135         if (strcmp(k[i], "target") == 0)
1136             make_ref(v[i], &xp->pi);
1137
1138         if (strcmp(k[i], "timer") == 0)
1139             sscanf(v[i], "%f", &xp->t0);
1140
1141         if (strcmp(k[i], "state") == 0)
1142             xp->f = atoi(v[i]);
1143
1144         if (strcmp(k[i], "invisible") == 0)
1145             xp->i = atoi(v[i]);
1146
1147         if (strcmp(k[i], "origin") == 0)
1148         {
1149             int x = 0, y = 0, z = 0;
1150
1151             sscanf(v[i], "%d %d %d", &x, &y, &z);
1152
1153             xp->p[0] = +(float) x / SCALE;
1154             xp->p[1] = +(float) z / SCALE;
1155             xp->p[2] = -(float) y / SCALE;
1156         }
1157     }
1158 }
1159
1160 static void make_targ(struct s_file *fp,
1161                       char k[][MAXSTR],
1162                       char v[][MAXSTR], int c)
1163 {
1164     int i;
1165
1166     targ_p[targ_n][0] = 0.f;
1167     targ_p[targ_n][1] = 0.f;
1168     targ_p[targ_n][3] = 0.f;
1169
1170     for (i = 0; i < c; i++)
1171     {
1172         if (strcmp(k[i], "targetname") == 0)
1173             make_sym(v[i], targ_n);
1174
1175         if (strcmp(k[i], "origin") == 0)
1176         {
1177             int x = 0, y = 0, z = 0;
1178
1179             sscanf(v[i], "%d %d %d", &x, &y, &z);
1180
1181             targ_p[targ_n][0] = +(float) x / SCALE;
1182             targ_p[targ_n][1] = +(float) z / SCALE;
1183             targ_p[targ_n][2] = -(float) y / SCALE;
1184         }
1185     }
1186
1187     targ_n++;
1188 }
1189
1190 static void make_ball(struct s_file *fp,
1191                       char k[][MAXSTR],
1192                       char v[][MAXSTR], int c)
1193 {
1194     int i, ui = incu(fp);
1195
1196     struct s_ball *up = fp->uv + ui;
1197
1198     up->p[0] = 0.f;
1199     up->p[1] = 0.f;
1200     up->p[2] = 0.f;
1201     up->r    = 0.25;
1202
1203     up->e[0][0] = 1.f;
1204     up->e[0][1] = 0.f;
1205     up->e[0][2] = 0.f;
1206     up->e[1][0] = 0.f;
1207     up->e[1][1] = 1.f;
1208     up->e[1][2] = 0.f;
1209     up->e[2][0] = 0.f;
1210     up->e[2][1] = 0.f;
1211     up->e[2][2] = 1.f;
1212
1213     up->v[0] = 0.f;
1214     up->v[1] = 0.f;
1215     up->v[2] = 0.f;
1216     up->w[0] = 0.f;
1217     up->w[1] = 0.f;
1218     up->w[2] = 0.f;
1219
1220     for (i = 0; i < c; i++)
1221     {
1222         if (strcmp(k[i], "radius") == 0)
1223             sscanf(v[i], "%f", &up->r);
1224
1225         if (strcmp(k[i], "origin") == 0)
1226         {
1227             int x = 0, y = 0, z = 0;
1228
1229             sscanf(v[i], "%d %d %d", &x, &y, &z);
1230
1231             up->p[0] = +(float) (x)      / SCALE;
1232             up->p[1] = +(float) (z - 24) / SCALE;
1233             up->p[2] = -(float) (y)      / SCALE;
1234         }
1235     }
1236
1237     up->p[1] += up->r + SMALL;
1238 }
1239
1240 /*---------------------------------------------------------------------------*/
1241
1242 static void read_ent(struct s_file *fp, FILE *fin)
1243 {
1244     char k[MAXKEY][MAXSTR];
1245     char v[MAXKEY][MAXSTR];
1246     int t, i = 0, c = 0;
1247
1248     int l0 = fp->lc;
1249
1250     while ((t = map_token(fin, -1, k[c], v[c])))
1251     {
1252         if (t == T_KEY)
1253         {
1254             if (strcmp(k[c], "classname") == 0)
1255                 i = c;
1256             c++;
1257         }
1258         if (t == T_BEG) read_lump(fp, fin);
1259         if (t == T_END) break;
1260     }
1261
1262     if (!strcmp(v[i], "light"))                    make_coin(fp, k, v, c);
1263     if (!strcmp(v[i], "item_health_large"))        make_item(fp, k, v, c);
1264     if (!strcmp(v[i], "item_health_small"))        make_item(fp, k, v, c);
1265     if (!strcmp(v[i], "info_camp"))                make_swch(fp, k, v, c);
1266     if (!strcmp(v[i], "info_null"))                make_bill(fp, k, v, c);
1267     if (!strcmp(v[i], "path_corner"))              make_path(fp, k, v, c);
1268     if (!strcmp(v[i], "info_player_start"))        make_ball(fp, k, v, c);
1269     if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1270     if (!strcmp(v[i], "info_player_deathmatch"))   make_goal(fp, k, v, c);
1271     if (!strcmp(v[i], "target_teleporter"))        make_jump(fp, k, v, c);
1272     if (!strcmp(v[i], "target_position"))          make_targ(fp, k, v, c);
1273     if (!strcmp(v[i], "worldspawn"))               make_body(fp, k, v, c, l0);
1274     if (!strcmp(v[i], "func_train"))               make_body(fp, k, v, c, l0);
1275     if (!strcmp(v[i], "misc_model"))               make_body(fp, k, v, c, l0);
1276 }
1277
1278 static void read_map(struct s_file *fp, FILE *fin)
1279 {
1280     char k[MAXSTR];
1281     char v[MAXSTR];
1282     int t;
1283
1284     while ((t = map_token(fin, -1, k, v)))
1285         if (t == T_BEG)
1286             read_ent(fp, fin);
1287 }
1288
1289 /*---------------------------------------------------------------------------*/
1290
1291 /* Test the location of a point with respect to a side plane. */
1292
1293 static int fore_side(const float p[3], const struct s_side *sp)
1294 {
1295     return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1296 }
1297
1298 static int on_side(const float p[3], const struct s_side *sp)
1299 {
1300     float d = v_dot(p, sp->n) - sp->d;
1301
1302     return (-SMALL < d && d < +SMALL) ? 1 : 0;
1303 }
1304
1305 /*---------------------------------------------------------------------------*/
1306 /*
1307  * Confirm  that  the addition  of  a vert  would  not  result in  degenerate
1308  * geometry.
1309  */
1310
1311 static int ok_vert(const struct s_file *fp,
1312                    const struct s_lump *lp, const float p[3])
1313 {
1314     float r[3];
1315     int i;
1316
1317     for (i = 0; i < lp->vc; i++)
1318     {
1319         float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1320
1321         v_sub(r, p, q);
1322
1323         if (v_len(r) < SMALL)
1324             return 0;
1325     }
1326     return 1;
1327 }
1328
1329 /*---------------------------------------------------------------------------*/
1330
1331 /*
1332  * The following functions take the  set of planes defining a lump and
1333  * find the verts, edges, and  geoms that describe its boundaries.  To
1334  * do this, they first find the verts, and then search these verts for
1335  * valid edges and  geoms.  It may be more  efficient to compute edges
1336  * and  geoms directly  by clipping  down infinite  line  segments and
1337  * planes,  but this  would be  more  complex and  prone to  numerical
1338  * error.
1339  */
1340
1341 /*
1342  * Given 3  side planes,  compute the point  of intersection,  if any.
1343  * Confirm that this point falls  within the current lump, and that it
1344  * is unique.  Add it as a vert of the solid.
1345  */
1346 static void clip_vert(struct s_file *fp,
1347                       struct s_lump *lp, int si, int sj, int sk)
1348 {
1349     float M[16], X[16], I[16];
1350     float d[3],  p[3];
1351     int i;
1352
1353     d[0] = fp->sv[si].d;
1354     d[1] = fp->sv[sj].d;
1355     d[2] = fp->sv[sk].d;
1356
1357     m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1358     m_xps(X, M);
1359
1360     if (m_inv(I, X))
1361     {
1362         m_vxfm(p, I, d);
1363
1364         for (i = 0; i < lp->sc; i++)
1365         {
1366             int si = fp->iv[lp->s0 + i];
1367
1368             if (fore_side(p, fp->sv + si))
1369                 return;
1370         }
1371
1372         if (ok_vert(fp, lp, p))
1373         {
1374             v_cpy(fp->vv[fp->vc].p, p);
1375
1376             fp->iv[fp->ic] = fp->vc;
1377             inci(fp);
1378             incv(fp);
1379             lp->vc++;
1380         }
1381     }
1382 }
1383
1384 /*
1385  * Given two  side planes,  find an edge  along their  intersection by
1386  * finding a pair of vertices that fall on both planes.  Add it to the
1387  * solid.
1388  */
1389 static void clip_edge(struct s_file *fp,
1390                       struct s_lump *lp, int si, int sj)
1391 {
1392     int i, j;
1393
1394     for (i = 1; i < lp->vc; i++)
1395         for (j = 0; j < i; j++)
1396         {
1397             int vi = fp->iv[lp->v0 + i];
1398             int vj = fp->iv[lp->v0 + j];
1399
1400             if (on_side(fp->vv[vi].p, fp->sv + si) &&
1401                 on_side(fp->vv[vj].p, fp->sv + si) &&
1402                 on_side(fp->vv[vi].p, fp->sv + sj) &&
1403                 on_side(fp->vv[vj].p, fp->sv + sj))
1404             {
1405                 fp->ev[fp->ec].vi = vi;
1406                 fp->ev[fp->ec].vj = vj;
1407
1408                 fp->iv[fp->ic] = fp->ec;
1409
1410                 inci(fp);
1411                 ince(fp);
1412                 lp->ec++;
1413             }
1414         }
1415 }
1416
1417 /*
1418  * Find all verts that lie on  the given side of the lump.  Sort these
1419  * verts to  have a counter-clockwise winding about  the plane normal.
1420  * Create geoms to tessalate the resulting convex polygon.
1421  */
1422 static void clip_geom(struct s_file *fp,
1423                       struct s_lump *lp, int si)
1424 {
1425     int   m[256], t[256], d, i, j, n = 0;
1426     float u[3];
1427     float v[3];
1428     float w[3];
1429
1430     struct s_side *sp = fp->sv + si;
1431
1432     /* Find em. */
1433
1434     for (i = 0; i < lp->vc; i++)
1435     {
1436         int vi = fp->iv[lp->v0 + i];
1437
1438         if (on_side(fp->vv[vi].p, sp))
1439         {
1440             m[n] = vi;
1441             t[n] = inct(fp);
1442
1443             v_add(v, fp->vv[vi].p, plane_p[si]);
1444
1445             fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1446             fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1447
1448             n++;
1449         }
1450     }
1451
1452     /* Sort em. */
1453
1454     for (i = 1; i < n; i++)
1455         for (j = i + 1; j < n; j++)
1456         {
1457             v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1458             v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1459             v_crs(w, u, v);
1460
1461             if (v_dot(w, sp->n) < 0.f)
1462             {
1463                 d     = m[i];
1464                 m[i]  = m[j];
1465                 m[j]  =    d;
1466
1467                 d     = t[i];
1468                 t[i]  = t[j];
1469                 t[j]  =    d;
1470             }
1471         }
1472
1473     /* Index em. */
1474
1475     for (i = 0; i < n - 2; i++)
1476     {
1477         fp->gv[fp->gc].mi = plane_m[si];
1478
1479         fp->gv[fp->gc].ti = t[0];
1480         fp->gv[fp->gc].tj = t[i + 1];
1481         fp->gv[fp->gc].tk = t[i + 2];
1482
1483         fp->gv[fp->gc].si = si;
1484         fp->gv[fp->gc].sj = si;
1485         fp->gv[fp->gc].sk = si;
1486
1487         fp->gv[fp->gc].vi = m[0];
1488         fp->gv[fp->gc].vj = m[i + 1];
1489         fp->gv[fp->gc].vk = m[i + 2];
1490
1491         fp->iv[fp->ic] = fp->gc;
1492         inci(fp);
1493         incg(fp);
1494         lp->gc++;
1495     }
1496 }
1497
1498 /*
1499  * Iterate the sides of the lump, attemping to generate a new vert for
1500  * each trio of planes, a new edge  for each pair of planes, and a new
1501  * set of geom for each visible plane.
1502  */
1503 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1504 {
1505     int i, j, k;
1506
1507     lp->v0 = fp->ic;
1508     lp->vc = 0;
1509
1510     for (i = 2; i < lp->sc; i++)
1511         for (j = 1; j < i; j++)
1512             for (k = 0; k < j; k++)
1513                 clip_vert(fp, lp,
1514                           fp->iv[lp->s0 + i],
1515                           fp->iv[lp->s0 + j],
1516                           fp->iv[lp->s0 + k]);
1517
1518     lp->e0 = fp->ic;
1519     lp->ec = 0;
1520
1521     for (i = 1; i < lp->sc; i++)
1522         for (j = 0; j < i; j++)
1523             clip_edge(fp, lp,
1524                       fp->iv[lp->s0 + i],
1525                       fp->iv[lp->s0 + j]);
1526
1527     lp->g0 = fp->ic;
1528     lp->gc = 0;
1529
1530     for (i = 0; i < lp->sc; i++)
1531         if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0)
1532             clip_geom(fp, lp,
1533                       fp->iv[lp->s0 + i]);
1534
1535     for (i = 0; i < lp->sc; i++)
1536         if (plane_f[fp->iv[lp->s0 + i]])
1537             lp->fl |= L_DETAIL;
1538 }
1539
1540 static void clip_file(struct s_file *fp)
1541 {
1542     int i;
1543
1544     for (i = 0; i < fp->lc; i++)
1545         clip_lump(fp, fp->lv + i);
1546 }
1547
1548 /*---------------------------------------------------------------------------*/
1549
1550 /*
1551  * For each body element type,  determine if element 'p' is equivalent
1552  * to element  'q'.  This  is more than  a simple memory  compare.  It
1553  * effectively  snaps mtrls and  verts togather,  and may  reverse the
1554  * winding of  an edge or a geom.   This is done in  order to maximize
1555  * the number of elements that can be eliminated.
1556  */
1557
1558 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1559 {
1560     if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1561     if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1562     if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1563     if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1564
1565     if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1566     if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1567     if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1568     if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1569
1570     if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1571     if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1572     if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1573     if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1574
1575     if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1576     if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1577     if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1578     if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1579
1580     if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1581
1582     if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1583
1584     return 1;
1585 }
1586
1587 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1588 {
1589     if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1590     if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1591     if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1592
1593     return 1;
1594 }
1595
1596 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1597 {
1598     if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1599     if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1600
1601     return 1;
1602 }
1603
1604 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1605 {
1606     if  (fabs(sp->d - sq->d) > SMALL)  return 0;
1607     if (v_dot(sp->n,  sq->n) < 0.9999) return 0;
1608
1609     return 1;
1610 }
1611
1612 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1613 {
1614     if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1615     if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1616
1617     return 1;
1618 }
1619
1620 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1621 {
1622     if (gp->mi != gq->mi) return 0;
1623
1624     if (gp->ti != gq->ti) return 0;
1625     if (gp->si != gq->si) return 0;
1626     if (gp->vi != gq->vi) return 0;
1627
1628     if (gp->tj != gq->tj) return 0;
1629     if (gp->sj != gq->sj) return 0;
1630     if (gp->vj != gq->vj) return 0;
1631
1632     if (gp->tk != gq->tk) return 0;
1633     if (gp->sk != gq->sk) return 0;
1634     if (gp->vk != gq->vk) return 0;
1635
1636     return 1;
1637 }
1638
1639 /*---------------------------------------------------------------------------*/
1640
1641 /*
1642  * For each file  element type, replace all references  to element 'i'
1643  * with a  reference to element  'j'.  These are used  when optimizing
1644  * and sorting the file.
1645  */
1646
1647 static void swap_mtrl(struct s_file *fp, int mi, int mj)
1648 {
1649     int i;
1650
1651     for (i = 0; i < fp->gc; i++)
1652         if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1653     for (i = 0; i < fp->rc; i++)
1654         if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1655 }
1656
1657 static void swap_vert(struct s_file *fp, int vi, int vj)
1658 {
1659     int i, j;
1660
1661     for (i = 0; i < fp->ec; i++)
1662     {
1663         if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1664         if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1665     }
1666
1667     for (i = 0; i < fp->gc; i++)
1668     {
1669         if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1670         if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1671         if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1672     }
1673
1674     for (i = 0; i < fp->lc; i++)
1675         for (j = 0; j < fp->lv[i].vc; j++)
1676             if (fp->iv[fp->lv[i].v0 + j] == vi)
1677                 fp->iv[fp->lv[i].v0 + j]  = vj;
1678 }
1679
1680 static void swap_edge(struct s_file *fp, int ei, int ej)
1681 {
1682     int i, j;
1683
1684     for (i = 0; i < fp->lc; i++)
1685         for (j = 0; j < fp->lv[i].ec; j++)
1686             if (fp->iv[fp->lv[i].e0 + j] == ei)
1687                 fp->iv[fp->lv[i].e0 + j]  = ej;
1688 }
1689
1690 static void swap_side(struct s_file *fp, int si, int sj)
1691 {
1692     int i, j;
1693
1694     for (i = 0; i < fp->gc; i++)
1695     {
1696         if (fp->gv[i].si == si) fp->gv[i].si = sj;
1697         if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1698         if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1699     }
1700     for (i = 0; i < fp->nc; i++)
1701         if (fp->nv[i].si == si) fp->nv[i].si = sj;
1702
1703     for (i = 0; i < fp->lc; i++)
1704         for (j = 0; j < fp->lv[i].sc; j++)
1705             if (fp->iv[fp->lv[i].s0 + j] == si)
1706                 fp->iv[fp->lv[i].s0 + j]  = sj;
1707 }
1708
1709 static void swap_texc(struct s_file *fp, int ti, int tj)
1710 {
1711     int i;
1712
1713     for (i = 0; i < fp->gc; i++)
1714     {
1715         if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1716         if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1717         if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1718     }
1719 }
1720
1721
1722 static void swap_geom(struct s_file *fp, int gi, int gj)
1723 {
1724     int i, j;
1725
1726     for (i = 0; i < fp->lc; i++)
1727         for (j = 0; j < fp->lv[i].gc; j++)
1728             if (fp->iv[fp->lv[i].g0 + j] == gi)
1729                 fp->iv[fp->lv[i].g0 + j]  = gj;
1730
1731     for (i = 0; i < fp->bc; i++)
1732         for (j = 0; j < fp->bv[i].gc; j++)
1733             if (fp->iv[fp->bv[i].g0 + j] == gi)
1734                 fp->iv[fp->bv[i].g0 + j]  = gj;
1735 }
1736
1737 /*---------------------------------------------------------------------------*/
1738
1739 static void uniq_mtrl(struct s_file *fp)
1740 {
1741     int i, j, k = 0;
1742
1743     for (i = 0; i < fp->mc; i++)
1744     {
1745         for (j = 0; j < k; j++)
1746             if (comp_mtrl(fp->mv + i, fp->mv + j))
1747             {
1748                 swap_mtrl(fp, i, j);
1749                 break;
1750             }
1751
1752         if (j == k)
1753         {
1754             if (i != k)
1755             {
1756                 fp->mv[k] = fp->mv[i];
1757                 swap_mtrl(fp, i, k);
1758             }
1759             k++;
1760         }
1761     }
1762
1763     fp->mc = k;
1764 }
1765
1766 static void uniq_vert(struct s_file *fp)
1767 {
1768     int i, j, k = 0;
1769
1770     for (i = 0; i < fp->vc; i++)
1771     {
1772         for (j = 0; j < k; j++)
1773             if (comp_vert(fp->vv + i, fp->vv + j))
1774             {
1775                 swap_vert(fp, i, j);
1776                 break;
1777             }
1778
1779         if (j == k)
1780         {
1781             if (i != k)
1782             {
1783                 fp->vv[k] = fp->vv[i];
1784                 swap_vert(fp, i, k);
1785             }
1786             k++;
1787         }
1788     }
1789
1790     fp->vc = k;
1791 }
1792
1793 static void uniq_edge(struct s_file *fp)
1794 {
1795     int i, j, k = 0;
1796
1797     for (i = 0; i < fp->ec; i++)
1798     {
1799         for (j = 0; j < k; j++)
1800             if (comp_edge(fp->ev + i, fp->ev + j))
1801             {
1802                 swap_edge(fp, i, j);
1803                 break;
1804             }
1805
1806         if (j == k)
1807         {
1808             if (i != k)
1809             {
1810                 fp->ev[k] = fp->ev[i];
1811                 swap_edge(fp, i, k);
1812             }
1813             k++;
1814         }
1815     }
1816
1817     fp->ec = k;
1818 }
1819
1820 static void uniq_geom(struct s_file *fp)
1821 {
1822     int i, j, k = 0;
1823
1824     for (i = 0; i < fp->gc; i++)
1825     {
1826         for (j = 0; j < k; j++)
1827             if (comp_geom(fp->gv + i, fp->gv + j))
1828             {
1829                 swap_geom(fp, i, j);
1830                 break;
1831             }
1832
1833         if (j == k)
1834         {
1835             if (i != k)
1836             {
1837                 fp->gv[k] = fp->gv[i];
1838                 swap_geom(fp, i, k);
1839             }
1840             k++;
1841         }
1842     }
1843
1844     fp->gc = k;
1845 }
1846
1847 static void uniq_texc(struct s_file *fp)
1848 {
1849     int i, j, k = 0;
1850
1851     for (i = 0; i < fp->tc; i++)
1852     {
1853         for (j = 0; j < k; j++)
1854             if (comp_texc(fp->tv + i, fp->tv + j))
1855             {
1856                 swap_texc(fp, i, j);
1857                 break;
1858             }
1859
1860         if (j == k)
1861         {
1862             if (i != k)
1863             {
1864                 fp->tv[k] = fp->tv[i];
1865                 swap_texc(fp, i, k);
1866             }
1867             k++;
1868         }
1869     }
1870
1871     fp->tc = k;
1872 }
1873
1874 static void uniq_side(struct s_file *fp)
1875 {
1876     int i, j, k = 0;
1877
1878     for (i = 0; i < fp->sc; i++)
1879     {
1880         for (j = 0; j < k; j++)
1881             if (comp_side(fp->sv + i, fp->sv + j))
1882             {
1883                 swap_side(fp, i, j);
1884                 break;
1885             }
1886
1887         if (j == k)
1888         {
1889             if (i != k)
1890             {
1891                 fp->sv[k] = fp->sv[i];
1892                 swap_side(fp, i, k);
1893             }
1894             k++;
1895         }
1896     }
1897
1898     fp->sc = k;
1899 }
1900
1901 static void uniq_file(struct s_file *fp)
1902 {
1903     uniq_mtrl(fp);
1904     uniq_vert(fp);
1905     uniq_edge(fp);
1906     uniq_side(fp);
1907     uniq_texc(fp);
1908     uniq_geom(fp);
1909 }
1910
1911 /*---------------------------------------------------------------------------*/
1912
1913 static void sort_file(struct s_file *fp)
1914 {
1915     int i, j;
1916
1917     /* Sort billboards farthest to nearest. */
1918
1919     for (i = 0; i < fp->rc; i++)
1920         for (j = i + 1; j < fp->rc; j++)
1921             if (fp->rv[j].d > fp->rv[i].d)
1922             {
1923                 struct s_bill t;
1924
1925                 t         = fp->rv[i];
1926                 fp->rv[i] = fp->rv[j];
1927                 fp->rv[j] =         t;
1928             }
1929
1930     /* Ensure the first vertex is the lowest. */
1931
1932     for (i = 0; i < fp->vc; i++)
1933         if (fp->vv[0].p[1] > fp->vv[i].p[1])
1934         {
1935             struct s_vert t;
1936
1937             t         = fp->vv[0];
1938             fp->vv[0] = fp->vv[i];
1939             fp->vv[i] =         t;
1940
1941             swap_vert(fp,  0, -1);
1942             swap_vert(fp,  i,  0);
1943             swap_vert(fp, -1,  i);
1944         }
1945 }
1946
1947 /*---------------------------------------------------------------------------*/
1948
1949 static int test_lump_side(const struct s_file *fp,
1950                           const struct s_lump *lp,
1951                           const struct s_side *sp)
1952 {
1953     int si;
1954     int vi;
1955
1956     int f = 0;
1957     int b = 0;
1958
1959     /* If the given side is part of the given lump, then the lump is behind. */
1960
1961     for (si = 0; si < lp->sc; si++)
1962         if (fp->sv + fp->iv[lp->s0 + si] == sp)
1963             return -1;
1964
1965     /* Check if each lump vertex is in front of, behind, on the side. */
1966
1967     for (vi = 0; vi < lp->vc; vi++)
1968     {
1969         float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
1970
1971         if (d > 0) f++;
1972         if (d < 0) b++;
1973     }
1974
1975     /* If no verts are behind, the lump is in front, and vice versa. */
1976
1977     if (f > 0 && b == 0) return +1;
1978     if (b > 0 && f == 0) return -1;
1979
1980     /* Else, the lump crosses the side. */
1981
1982     return 0;
1983 }
1984
1985 static int node_node(struct s_file *fp, int l0, int lc)
1986 {
1987     if (lc < 8)
1988     {
1989         /* Base case.  Dump all given lumps into a leaf node. */
1990
1991         fp->nv[fp->nc].si = -1;
1992         fp->nv[fp->nc].ni = -1;
1993         fp->nv[fp->nc].nj = -1;
1994         fp->nv[fp->nc].l0 = l0;
1995         fp->nv[fp->nc].lc = lc;
1996
1997         return incn(fp);
1998     }
1999     else
2000     {
2001         int sj  = 0;
2002         int sjd = lc;
2003         int sjo = lc;
2004         int si;
2005         int li = 0, lic = 0;
2006         int lj = 0, ljc = 0;
2007         int lk = 0, lkc = 0;
2008         int i;
2009
2010         /* Find the side that most evenly splits the given lumps. */
2011
2012         for (si = 0; si < fp->sc; si++)
2013         {
2014             int o = 0;
2015             int d = 0;
2016             int k = 0;
2017
2018             for (li = 0; li < lc; li++)
2019                 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
2020                     d += k;
2021                 else
2022                     o++;
2023
2024             d = abs(d);
2025
2026             if ((d < sjd) || (d == sjd && o < sjo))
2027             {
2028                 sj  = si;
2029                 sjd = d;
2030                 sjo = o;
2031             }
2032         }
2033
2034         /* Flag each lump with its position WRT the side. */
2035
2036         for (li = 0; li < lc; li++)
2037             switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
2038             {
2039             case +1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10; break;
2040             case  0: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20; break;
2041             case -1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40; break;
2042             }
2043
2044         /* Sort all lumps in the range by their flag values. */
2045
2046         for (li = 1; li < lc; li++)
2047             for (lj = 0; lj < li; lj++)
2048                 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
2049                 {
2050                     struct s_lump l;
2051
2052                     l               = fp->lv[l0 + li];
2053                     fp->lv[l0 + li] = fp->lv[l0 + lj];
2054                     fp->lv[l0 + lj] =               l;
2055                 }
2056
2057         /* Establish the in-front, on, and behind lump ranges. */
2058
2059         li = lic = 0;
2060         lj = ljc = 0;
2061         lk = lkc = 0;
2062
2063         for (i = lc - 1; i >= 0; i--)
2064             switch (fp->lv[l0 + i].fl & 0xf0)
2065             {
2066             case 0x10: li = l0 + i; lic++; break;
2067             case 0x20: lj = l0 + i; ljc++; break;
2068             case 0x40: lk = l0 + i; lkc++; break;
2069             }
2070
2071         /* Add the lumps on the side to the node. */
2072
2073         i = incn(fp);
2074
2075         fp->nv[i].si = sj;
2076         fp->nv[i].ni = node_node(fp, li, lic);
2077
2078         fp->nv[i].nj = node_node(fp, lk, lkc);
2079         fp->nv[i].l0 = lj;
2080         fp->nv[i].lc = ljc;
2081
2082         return i;
2083     }
2084 }
2085
2086 static void node_file(struct s_file *fp)
2087 {
2088     int bi;
2089
2090     /* Sort the lumps of each body into BSP nodes. */
2091
2092     for (bi = 0; bi < fp->bc; bi++)
2093         fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
2094 }
2095
2096 /*---------------------------------------------------------------------------*/
2097
2098 static void dump_file(struct s_file *p, const char *name)
2099 {
2100     int i, j;
2101     int c = 0;
2102     int n = 0;
2103     int m = p->rc + p->cc * 128 + (p->zc * p->jc + p->xc) * 32;
2104
2105     /* Count the number of solid lumps. */
2106
2107     for (i = 0; i < p->lc; i++)
2108         if ((p->lv[i].fl & 1) == 0)
2109             n++;
2110
2111     /* Count the number of visible geoms. */
2112
2113     for (i = 0; i < p->bc; i++)
2114     {
2115         for (j = 0; j < p->bv[i].lc; j++)
2116             m += p->lv[p->bv[i].l0 + j].gc;
2117         m += p->bv[i].gc;
2118     }
2119
2120     /* Count the total value of all coins. */
2121
2122     for (i = 0; i < p->cc; i++)
2123         c += p->cv[i].n;
2124
2125     printf("%s (%d/%d/$%d)\n"
2126            "  mtrl  vert  edge  side  texc"
2127            "  geom  lump  path  node  body\n"
2128            "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
2129            "  coin  item  goal  view  jump"
2130            "  swch  bill  ball  char  indx\n"
2131            "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
2132            name, n, m, c,
2133            p->mc, p->vc, p->ec, p->sc, p->tc,
2134            p->gc, p->lc, p->pc, p->nc, p->bc,
2135            p->cc, p->hc, p->zc, p->wc, p->jc,
2136            p->xc, p->rc, p->uc, p->ac, p->ic);
2137 }
2138
2139 /* Skip the ugly SDL main substitution since we only need sdl_image. */
2140 #ifdef main
2141 #    undef main
2142 #endif
2143
2144 int main(int argc, char *argv[])
2145 {
2146     char src[MAXSTR];
2147     char dst[MAXSTR];
2148     struct s_file f;
2149     FILE *fin;
2150
2151     if (argc > 2)
2152     {
2153         if (config_data_path(argv[2], NULL))
2154         {
2155             strncpy(src,  argv[1], MAXSTR);
2156             strncpy(dst,  argv[1], MAXSTR);
2157
2158             if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
2159                 strcpy(dst + strlen(dst) - 4, ".sol");
2160             else
2161                 strcat(dst, ".sol");
2162
2163             if ((fin = fopen(src, "r")))
2164             {
2165                 init_file(&f);
2166                 read_map(&f, fin);
2167
2168                 resolve();
2169                 targets(&f);
2170
2171                 clip_file(&f);
2172                 move_file(&f);
2173                 uniq_file(&f);
2174                 sort_file(&f);
2175                 node_file(&f);
2176                 dump_file(&f, dst);
2177
2178                 sol_stor(&f, dst);
2179
2180                 fclose(fin);
2181
2182                 free_imagedata();
2183             }
2184         }
2185         else fprintf(stderr, "Failure to establish data directory\n");
2186     }
2187     else fprintf(stderr, "Usage: %s <map> [data]\n", argv[0]);
2188
2189     return 0;
2190 }
2191