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