Add Spanish translation and try not to mess anything up while doing
[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 MAXZ    16
68 #define MAXJ    32
69 #define MAXX    16
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 incc(struct s_file *fp)
135 {
136     return (fp->cc < MAXC) ? fp->cc++ : overflow("coin");
137 }
138
139 static int incz(struct s_file *fp)
140 {
141     return (fp->zc < MAXZ) ? fp->zc++ : overflow("geol");
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->cc = 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->cv = (struct s_coin *) calloc(MAXC, sizeof (struct s_coin));
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 refering 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_coin(struct s_file *fp,
870                       char k[][MAXSTR],
871                       char v[][MAXSTR], int c)
872 {
873     int i, ci = incc(fp);
874
875     struct s_coin *cp = fp->cv + ci;
876
877     cp->p[0] = 0.f;
878     cp->p[1] = 0.f;
879     cp->p[2] = 0.f;
880     cp->n    = 1;
881
882     for (i = 0; i < c; i++)
883     {
884         if (strcmp(k[i], "light") == 0)
885             sscanf(v[i], "%d", &cp->n);
886
887         if (strcmp(k[i], "origin") == 0)
888         {
889             int x = 0, y = 0, z = 0;
890
891             sscanf(v[i], "%d %d %d", &x, &y, &z);
892
893             cp->p[0] = +(float) x / SCALE;
894             cp->p[1] = +(float) z / SCALE;
895             cp->p[2] = -(float) y / SCALE;
896         }
897     }
898 }
899
900 static void make_bill(struct s_file *fp,
901                       char k[][MAXSTR],
902                       char v[][MAXSTR], int c)
903 {
904     int i, ri = incr(fp);
905
906     struct s_bill *rp = fp->rv + ri;
907
908     memset(rp, 0, sizeof (struct s_bill));
909     rp->t = 1.0f;
910
911     for (i = 0; i < c; i++)
912     {
913         if (strcmp(k[i], "width") == 0)
914             sscanf(v[i], "%f %f %f", rp->w, rp->w + 1, rp->w + 2);
915         if (strcmp(k[i], "height") == 0)
916             sscanf(v[i], "%f %f %f", rp->h, rp->h + 1, rp->h + 2);
917
918         if (strcmp(k[i], "xrot") == 0)
919             sscanf(v[i], "%f %f %f", rp->rx, rp->rx + 1, rp->rx + 2);
920         if (strcmp(k[i], "yrot") == 0)
921             sscanf(v[i], "%f %f %f", rp->ry, rp->ry + 1, rp->ry + 2);
922         if (strcmp(k[i], "zrot") == 0)
923             sscanf(v[i], "%f %f %f", rp->rz, rp->rz + 1, rp->rz + 2);
924
925         if (strcmp(k[i], "time") == 0)
926             sscanf(v[i], "%f", &rp->t);
927         if (strcmp(k[i], "dist") == 0)
928             sscanf(v[i], "%f", &rp->d);
929         if (strcmp(k[i], "flag") == 0)
930             sscanf(v[i], "%d", &rp->fl);
931
932         if (strcmp(k[i], "image") == 0)
933         {
934             rp->mi = read_mtrl(fp, v[i]);
935             fp->mv[rp->mi].fl |= M_CLAMPED;
936         }
937
938         if (strcmp(k[i], "origin") == 0)
939         {
940             int x = 0, y = 0, z = 0;
941             float p[3];
942
943             sscanf(v[i], "%d %d %d", &x, &y, &z);
944
945             p[0] = +(float) x / SCALE;
946             p[1] = +(float) z / SCALE;
947             p[2] = -(float) y / SCALE;
948
949             rp->d     = v_len(p);
950             rp->rx[0] = V_DEG(fatan2f(+p[1], rp->d));
951             rp->ry[0] = V_DEG(fatan2f(+p[0], -p[2]));
952         }
953     }
954
955     if (rp->fl & B_ADDITIVE)
956         fp->mv[rp->mi].fl |= M_ADDITIVE;
957 }
958
959 static void make_goal(struct s_file *fp,
960                       char k[][MAXSTR],
961                       char v[][MAXSTR], int c)
962 {
963     int i, zi = incz(fp);
964
965     struct s_goal *zp = fp->zv + zi;
966
967     zp->p[0] = 0.f;
968     zp->p[1] = 0.f;
969     zp->p[2] = 0.f;
970     zp->r    = 0.75;
971     zp->s    = 0;
972     zp->c    = 0;
973
974     for (i = 0; i < c; i++)
975     {
976         if (strcmp(k[i], "radius") == 0)
977             sscanf(v[i], "%f", &zp->r);
978         if (strcmp(k[i], "skip") == 0)
979             sscanf(v[i], "%d", &zp->s);
980         if (strcmp(k[i], "special") == 0)
981             sscanf(v[i], "%d", &zp->c);
982
983         if (strcmp(k[i], "origin") == 0)
984         {
985             int x = 0, y = 0, z = 0;
986
987             sscanf(v[i], "%d %d %d", &x, &y, &z);
988
989             zp->p[0] = +(float) (x)      / SCALE;
990             zp->p[1] = +(float) (z - 24) / SCALE;
991             zp->p[2] = -(float) (y)      / SCALE;
992         }
993     }
994 }
995
996 static void make_view(struct s_file *fp,
997                       char k[][MAXSTR],
998                       char v[][MAXSTR], int c)
999 {
1000     int i, wi = incw(fp);
1001
1002     struct s_view *wp = fp->wv + wi;
1003
1004     wp->p[0] = 0.f;
1005     wp->p[1] = 0.f;
1006     wp->p[2] = 0.f;
1007     wp->q[0] = 0.f;
1008     wp->q[1] = 0.f;
1009     wp->q[2] = 0.f;
1010
1011     for (i = 0; i < c; i++)
1012     {
1013         if (strcmp(k[i], "target") == 0)
1014             make_ref(v[i], targ_wi + wi);
1015
1016         if (strcmp(k[i], "origin") == 0)
1017         {
1018             int x = 0, y = 0, z = 0;
1019
1020             sscanf(v[i], "%d %d %d", &x, &y, &z);
1021
1022             wp->p[0] = +(float) x / SCALE;
1023             wp->p[1] = +(float) z / SCALE;
1024             wp->p[2] = -(float) y / SCALE;
1025         }
1026     }
1027 }
1028
1029 static void make_jump(struct s_file *fp,
1030                       char k[][MAXSTR],
1031                       char v[][MAXSTR], int c)
1032 {
1033     int i, ji = incj(fp);
1034
1035     struct s_jump *jp = fp->jv + ji;
1036
1037     jp->p[0] = 0.f;
1038     jp->p[1] = 0.f;
1039     jp->p[2] = 0.f;
1040     jp->q[0] = 0.f;
1041     jp->q[1] = 0.f;
1042     jp->q[2] = 0.f;
1043     jp->r    = 0.5;
1044
1045     for (i = 0; i < c; i++)
1046     {
1047         if (strcmp(k[i], "radius") == 0)
1048             sscanf(v[i], "%f", &jp->r);
1049
1050         if (strcmp(k[i], "target") == 0)
1051             make_ref(v[i], targ_ji + ji);
1052
1053         if (strcmp(k[i], "origin") == 0)
1054         {
1055             int x = 0, y = 0, z = 0;
1056
1057             sscanf(v[i], "%d %d %d", &x, &y, &z);
1058
1059             jp->p[0] = +(float) x / SCALE;
1060             jp->p[1] = +(float) z / SCALE;
1061             jp->p[2] = -(float) y / SCALE;
1062         }
1063     }
1064 }
1065
1066 static void make_swch(struct s_file *fp,
1067                       char k[][MAXSTR],
1068                       char v[][MAXSTR], int c)
1069 {
1070     int i, xi = incx(fp);
1071
1072     struct s_swch *xp = fp->xv + xi;
1073
1074     xp->p[0] = 0.f;
1075     xp->p[1] = 0.f;
1076     xp->p[2] = 0.f;
1077     xp->r    = 0.5;
1078     xp->pi   = 0;
1079     xp->t0   = 0;
1080     xp->t    = 0;
1081     xp->f0   = 0;
1082     xp->f    = 0;
1083     xp->i    = 0;
1084
1085     for (i = 0; i < c; i++)
1086     {
1087         if (strcmp(k[i], "radius") == 0)
1088             sscanf(v[i], "%f", &xp->r);
1089
1090         if (strcmp(k[i], "target") == 0)
1091             make_ref(v[i], &xp->pi);
1092
1093         if (strcmp(k[i], "timer") == 0)
1094             sscanf(v[i], "%f", &xp->t0);
1095
1096         if (strcmp(k[i], "state") == 0)
1097             xp->f = atoi(v[i]);
1098
1099         if (strcmp(k[i], "invisible") == 0)
1100             xp->i = atoi(v[i]);
1101
1102         if (strcmp(k[i], "origin") == 0)
1103         {
1104             int x = 0, y = 0, z = 0;
1105
1106             sscanf(v[i], "%d %d %d", &x, &y, &z);
1107
1108             xp->p[0] = +(float) x / SCALE;
1109             xp->p[1] = +(float) z / SCALE;
1110             xp->p[2] = -(float) y / SCALE;
1111         }
1112     }
1113 }
1114
1115 static void make_targ(struct s_file *fp,
1116                       char k[][MAXSTR],
1117                       char v[][MAXSTR], int c)
1118 {
1119     int i;
1120
1121     targ_p[targ_n][0] = 0.f;
1122     targ_p[targ_n][1] = 0.f;
1123     targ_p[targ_n][3] = 0.f;
1124
1125     for (i = 0; i < c; i++)
1126     {
1127         if (strcmp(k[i], "targetname") == 0)
1128             make_sym(v[i], targ_n);
1129
1130         if (strcmp(k[i], "origin") == 0)
1131         {
1132             int x = 0, y = 0, z = 0;
1133
1134             sscanf(v[i], "%d %d %d", &x, &y, &z);
1135
1136             targ_p[targ_n][0] = +(float) x / SCALE;
1137             targ_p[targ_n][1] = +(float) z / SCALE;
1138             targ_p[targ_n][2] = -(float) y / SCALE;
1139         }
1140     }
1141
1142     targ_n++;
1143 }
1144
1145 static void make_ball(struct s_file *fp,
1146                       char k[][MAXSTR],
1147                       char v[][MAXSTR], int c)
1148 {
1149     int i, ui = incu(fp);
1150
1151     struct s_ball *up = fp->uv + ui;
1152
1153     up->p[0] = 0.f;
1154     up->p[1] = 0.f;
1155     up->p[2] = 0.f;
1156     up->r    = 0.25;
1157
1158     up->e[0][0] = 1.f;
1159     up->e[0][1] = 0.f;
1160     up->e[0][2] = 0.f;
1161     up->e[1][0] = 0.f;
1162     up->e[1][1] = 1.f;
1163     up->e[1][2] = 0.f;
1164     up->e[2][0] = 0.f;
1165     up->e[2][1] = 0.f;
1166     up->e[2][2] = 1.f;
1167
1168     up->v[0] = 0.f;
1169     up->v[1] = 0.f;
1170     up->v[2] = 0.f;
1171     up->w[0] = 0.f;
1172     up->w[1] = 0.f;
1173     up->w[2] = 0.f;
1174
1175     for (i = 0; i < c; i++)
1176     {
1177         if (strcmp(k[i], "radius") == 0)
1178             sscanf(v[i], "%f", &up->r);
1179
1180         if (strcmp(k[i], "origin") == 0)
1181         {
1182             int x = 0, y = 0, z = 0;
1183
1184             sscanf(v[i], "%d %d %d", &x, &y, &z);
1185
1186             up->p[0] = +(float) (x)      / SCALE;
1187             up->p[1] = +(float) (z - 24) / SCALE;
1188             up->p[2] = -(float) (y)      / SCALE;
1189         }
1190     }
1191
1192     up->p[1] += up->r + SMALL;
1193 }
1194
1195 /*---------------------------------------------------------------------------*/
1196
1197 static void read_ent(struct s_file *fp, FILE *fin)
1198 {
1199     char k[MAXKEY][MAXSTR];
1200     char v[MAXKEY][MAXSTR];
1201     int t, i = 0, c = 0;
1202
1203     int l0 = fp->lc;
1204
1205     while ((t = map_token(fin, -1, k[c], v[c])))
1206     {
1207         if (t == T_KEY)
1208         {
1209             if (strcmp(k[c], "classname") == 0)
1210                 i = c;
1211             c++;
1212         }
1213         if (t == T_BEG) read_lump(fp, fin);
1214         if (t == T_END) break;
1215     }
1216
1217     if (!strcmp(v[i], "light"))                    make_coin(fp, k, v, c);
1218     if (!strcmp(v[i], "info_camp"))                make_swch(fp, k, v, c);
1219     if (!strcmp(v[i], "info_null"))                make_bill(fp, k, v, c);
1220     if (!strcmp(v[i], "path_corner"))              make_path(fp, k, v, c);
1221     if (!strcmp(v[i], "info_player_start"))        make_ball(fp, k, v, c);
1222     if (!strcmp(v[i], "info_player_intermission")) make_view(fp, k, v, c);
1223     if (!strcmp(v[i], "info_player_deathmatch"))   make_goal(fp, k, v, c);
1224     if (!strcmp(v[i], "target_teleporter"))        make_jump(fp, k, v, c);
1225     if (!strcmp(v[i], "target_position"))          make_targ(fp, k, v, c);
1226     if (!strcmp(v[i], "worldspawn"))               make_body(fp, k, v, c, l0);
1227     if (!strcmp(v[i], "func_train"))               make_body(fp, k, v, c, l0);
1228     if (!strcmp(v[i], "misc_model"))               make_body(fp, k, v, c, l0);
1229 }
1230
1231 static void read_map(struct s_file *fp, FILE *fin)
1232 {
1233     char k[MAXSTR];
1234     char v[MAXSTR];
1235     int t;
1236
1237     while ((t = map_token(fin, -1, k, v)))
1238         if (t == T_BEG)
1239             read_ent(fp, fin);
1240 }
1241
1242 /*---------------------------------------------------------------------------*/
1243
1244 /* Test the location of a point with respect to a side plane. */
1245
1246 static int fore_side(const float p[3], const struct s_side *sp)
1247 {
1248     return (v_dot(p, sp->n) - sp->d > +SMALL) ? 1 : 0;
1249 }
1250
1251 static int on_side(const float p[3], const struct s_side *sp)
1252 {
1253     float d = v_dot(p, sp->n) - sp->d;
1254
1255     return (-SMALL < d && d < +SMALL) ? 1 : 0;
1256 }
1257
1258 /*---------------------------------------------------------------------------*/
1259 /*
1260  * Confirm  that  the addition  of  a vert  would  not  result in  degenerate
1261  * geometry.
1262  */
1263
1264 static int ok_vert(const struct s_file *fp,
1265                    const struct s_lump *lp, const float p[3])
1266 {
1267     float r[3];
1268     int i;
1269
1270     for (i = 0; i < lp->vc; i++)
1271     {
1272         float *q = fp->vv[fp->iv[lp->v0 + i]].p;
1273
1274         v_sub(r, p, q);
1275
1276         if (v_len(r) < SMALL)
1277             return 0;
1278     }
1279     return 1;
1280 }
1281
1282 /*---------------------------------------------------------------------------*/
1283
1284 /*
1285  * The following functions take the  set of planes defining a lump and
1286  * find the verts, edges, and  geoms that describe its boundaries.  To
1287  * do this, they first find the verts, and then search these verts for
1288  * valid edges and  geoms.  It may be more  efficient to compute edges
1289  * and  geoms directly  by clipping  down infinite  line  segments and
1290  * planes,  but this  would be  more  complex and  prone to  numerical
1291  * error.
1292  */
1293
1294 /*
1295  * Given 3  side planes,  compute the point  of intersection,  if any.
1296  * Confirm that this point falls  within the current lump, and that it
1297  * is unique.  Add it as a vert of the solid.
1298  */
1299 static void clip_vert(struct s_file *fp,
1300                       struct s_lump *lp, int si, int sj, int sk)
1301 {
1302     float M[16], X[16], I[16];
1303     float d[3],  p[3];
1304     int i;
1305
1306     d[0] = fp->sv[si].d;
1307     d[1] = fp->sv[sj].d;
1308     d[2] = fp->sv[sk].d;
1309
1310     m_basis(M, fp->sv[si].n, fp->sv[sj].n, fp->sv[sk].n);
1311     m_xps(X, M);
1312
1313     if (m_inv(I, X))
1314     {
1315         m_vxfm(p, I, d);
1316
1317         for (i = 0; i < lp->sc; i++)
1318         {
1319             int si = fp->iv[lp->s0 + i];
1320
1321             if (fore_side(p, fp->sv + si))
1322                 return;
1323         }
1324
1325         if (ok_vert(fp, lp, p))
1326         {
1327             v_cpy(fp->vv[fp->vc].p, p);
1328
1329             fp->iv[fp->ic] = fp->vc;
1330             inci(fp);
1331             incv(fp);
1332             lp->vc++;
1333         }
1334     }
1335 }
1336
1337 /*
1338  * Given two  side planes,  find an edge  along their  intersection by
1339  * finding a pair of vertices that fall on both planes.  Add it to the
1340  * solid.
1341  */
1342 static void clip_edge(struct s_file *fp,
1343                       struct s_lump *lp, int si, int sj)
1344 {
1345     int i, j;
1346
1347     for (i = 1; i < lp->vc; i++)
1348         for (j = 0; j < i; j++)
1349         {
1350             int vi = fp->iv[lp->v0 + i];
1351             int vj = fp->iv[lp->v0 + j];
1352
1353             if (on_side(fp->vv[vi].p, fp->sv + si) &&
1354                 on_side(fp->vv[vj].p, fp->sv + si) &&
1355                 on_side(fp->vv[vi].p, fp->sv + sj) &&
1356                 on_side(fp->vv[vj].p, fp->sv + sj))
1357             {
1358                 fp->ev[fp->ec].vi = vi;
1359                 fp->ev[fp->ec].vj = vj;
1360
1361                 fp->iv[fp->ic] = fp->ec;
1362
1363                 inci(fp);
1364                 ince(fp);
1365                 lp->ec++;
1366             }
1367         }
1368 }
1369
1370 /*
1371  * Find all verts that lie on  the given side of the lump.  Sort these
1372  * verts to  have a counter-clockwise winding about  the plane normal.
1373  * Create geoms to tessalate the resulting convex polygon.
1374  */
1375 static void clip_geom(struct s_file *fp,
1376                       struct s_lump *lp, int si)
1377 {
1378     int   m[256], t[256], d, i, j, n = 0;
1379     float u[3];
1380     float v[3];
1381     float w[3];
1382
1383     struct s_side *sp = fp->sv + si;
1384
1385     /* Find em. */
1386
1387     for (i = 0; i < lp->vc; i++)
1388     {
1389         int vi = fp->iv[lp->v0 + i];
1390
1391         if (on_side(fp->vv[vi].p, sp))
1392         {
1393             m[n] = vi;
1394             t[n] = inct(fp);
1395
1396             v_add(v, fp->vv[vi].p, plane_p[si]);
1397
1398             fp->tv[t[n]].u[0] = v_dot(v, plane_u[si]);
1399             fp->tv[t[n]].u[1] = v_dot(v, plane_v[si]);
1400
1401             n++;
1402         }
1403     }
1404
1405     /* Sort em. */
1406
1407     for (i = 1; i < n; i++)
1408         for (j = i + 1; j < n; j++)
1409         {
1410             v_sub(u, fp->vv[m[i]].p, fp->vv[m[0]].p);
1411             v_sub(v, fp->vv[m[j]].p, fp->vv[m[0]].p);
1412             v_crs(w, u, v);
1413
1414             if (v_dot(w, sp->n) < 0.f)
1415             {
1416                 d     = m[i];
1417                 m[i]  = m[j];
1418                 m[j]  =    d;
1419
1420                 d     = t[i];
1421                 t[i]  = t[j];
1422                 t[j]  =    d;
1423             }
1424         }
1425
1426     /* Index em. */
1427
1428     for (i = 0; i < n - 2; i++)
1429     {
1430         fp->gv[fp->gc].mi = plane_m[si];
1431
1432         fp->gv[fp->gc].ti = t[0];
1433         fp->gv[fp->gc].tj = t[i + 1];
1434         fp->gv[fp->gc].tk = t[i + 2];
1435
1436         fp->gv[fp->gc].si = si;
1437         fp->gv[fp->gc].sj = si;
1438         fp->gv[fp->gc].sk = si;
1439
1440         fp->gv[fp->gc].vi = m[0];
1441         fp->gv[fp->gc].vj = m[i + 1];
1442         fp->gv[fp->gc].vk = m[i + 2];
1443
1444         fp->iv[fp->ic] = fp->gc;
1445         inci(fp);
1446         incg(fp);
1447         lp->gc++;
1448     }
1449 }
1450
1451 /*
1452  * Iterate the sides of the lump, attemping to generate a new vert for
1453  * each trio of planes, a new edge  for each pair of planes, and a new
1454  * set of geom for each visible plane.
1455  */
1456 static void clip_lump(struct s_file *fp, struct s_lump *lp)
1457 {
1458     int i, j, k;
1459
1460     lp->v0 = fp->ic;
1461     lp->vc = 0;
1462
1463     for (i = 2; i < lp->sc; i++)
1464         for (j = 1; j < i; j++)
1465             for (k = 0; k < j; k++)
1466                 clip_vert(fp, lp,
1467                           fp->iv[lp->s0 + i],
1468                           fp->iv[lp->s0 + j],
1469                           fp->iv[lp->s0 + k]);
1470
1471     lp->e0 = fp->ic;
1472     lp->ec = 0;
1473
1474     for (i = 1; i < lp->sc; i++)
1475         for (j = 0; j < i; j++)
1476             clip_edge(fp, lp,
1477                       fp->iv[lp->s0 + i],
1478                       fp->iv[lp->s0 + j]);
1479
1480     lp->g0 = fp->ic;
1481     lp->gc = 0;
1482
1483     for (i = 0; i < lp->sc; i++)
1484         if (fp->mv[plane_m[fp->iv[lp->s0 + i]]].d[3] > 0)
1485             clip_geom(fp, lp,
1486                       fp->iv[lp->s0 + i]);
1487
1488     for (i = 0; i < lp->sc; i++)
1489         if (plane_f[fp->iv[lp->s0 + i]])
1490             lp->fl |= L_DETAIL;
1491 }
1492
1493 static void clip_file(struct s_file *fp)
1494 {
1495     int i;
1496
1497     for (i = 0; i < fp->lc; i++)
1498         clip_lump(fp, fp->lv + i);
1499 }
1500
1501 /*---------------------------------------------------------------------------*/
1502
1503 /*
1504  * For each body element type,  determine if element 'p' is equivalent
1505  * to element  'q'.  This  is more than  a simple memory  compare.  It
1506  * effectively  snaps mtrls and  verts togather,  and may  reverse the
1507  * winding of  an edge or a geom.   This is done in  order to maximize
1508  * the number of elements that can be eliminated.
1509  */
1510
1511 static int comp_mtrl(const struct s_mtrl *mp, const struct s_mtrl *mq)
1512 {
1513     if (fabs(mp->d[0] - mq->d[0]) > SMALL) return 0;
1514     if (fabs(mp->d[1] - mq->d[1]) > SMALL) return 0;
1515     if (fabs(mp->d[2] - mq->d[2]) > SMALL) return 0;
1516     if (fabs(mp->d[3] - mq->d[3]) > SMALL) return 0;
1517
1518     if (fabs(mp->a[0] - mq->a[0]) > SMALL) return 0;
1519     if (fabs(mp->a[1] - mq->a[1]) > SMALL) return 0;
1520     if (fabs(mp->a[2] - mq->a[2]) > SMALL) return 0;
1521     if (fabs(mp->a[3] - mq->a[3]) > SMALL) return 0;
1522
1523     if (fabs(mp->s[0] - mq->s[0]) > SMALL) return 0;
1524     if (fabs(mp->s[1] - mq->s[1]) > SMALL) return 0;
1525     if (fabs(mp->s[2] - mq->s[2]) > SMALL) return 0;
1526     if (fabs(mp->s[3] - mq->s[3]) > SMALL) return 0;
1527
1528     if (fabs(mp->e[0] - mq->e[0]) > SMALL) return 0;
1529     if (fabs(mp->e[1] - mq->e[1]) > SMALL) return 0;
1530     if (fabs(mp->e[2] - mq->e[2]) > SMALL) return 0;
1531     if (fabs(mp->e[3] - mq->e[3]) > SMALL) return 0;
1532
1533     if (fabs(mp->h[0] - mq->h[0]) > SMALL) return 0;
1534
1535     if (strncmp(mp->f, mq->f, PATHMAX)) return 0;
1536
1537     return 1;
1538 }
1539
1540 static int comp_vert(const struct s_vert *vp, const struct s_vert *vq)
1541 {
1542     if (fabs(vp->p[0] - vq->p[0]) > SMALL) return 0;
1543     if (fabs(vp->p[1] - vq->p[1]) > SMALL) return 0;
1544     if (fabs(vp->p[2] - vq->p[2]) > SMALL) return 0;
1545
1546     return 1;
1547 }
1548
1549 static int comp_edge(const struct s_edge *ep, const struct s_edge *eq)
1550 {
1551     if (ep->vi != eq->vi && ep->vi != eq->vj) return 0;
1552     if (ep->vj != eq->vi && ep->vj != eq->vj) return 0;
1553
1554     return 1;
1555 }
1556
1557 static int comp_side(const struct s_side *sp, const struct s_side *sq)
1558 {
1559     if  (fabs(sp->d - sq->d) > SMALL)  return 0;
1560     if (v_dot(sp->n,  sq->n) < 0.9999) return 0;
1561
1562     return 1;
1563 }
1564
1565 static int comp_texc(const struct s_texc *tp, const struct s_texc *tq)
1566 {
1567     if (fabs(tp->u[0] - tq->u[0]) > SMALL) return 0;
1568     if (fabs(tp->u[1] - tq->u[1]) > SMALL) return 0;
1569
1570     return 1;
1571 }
1572
1573 static int comp_geom(const struct s_geom *gp, const struct s_geom *gq)
1574 {
1575     if (gp->mi != gq->mi) return 0;
1576
1577     if (gp->ti != gq->ti) return 0;
1578     if (gp->si != gq->si) return 0;
1579     if (gp->vi != gq->vi) return 0;
1580
1581     if (gp->tj != gq->tj) return 0;
1582     if (gp->sj != gq->sj) return 0;
1583     if (gp->vj != gq->vj) return 0;
1584
1585     if (gp->tk != gq->tk) return 0;
1586     if (gp->sk != gq->sk) return 0;
1587     if (gp->vk != gq->vk) return 0;
1588
1589     return 1;
1590 }
1591
1592 /*---------------------------------------------------------------------------*/
1593
1594 /*
1595  * For each file  element type, replace all references  to element 'i'
1596  * with a  reference to element  'j'.  These are used  when optimizing
1597  * and sorting the file.
1598  */
1599
1600 static void swap_mtrl(struct s_file *fp, int mi, int mj)
1601 {
1602     int i;
1603
1604     for (i = 0; i < fp->gc; i++)
1605         if (fp->gv[i].mi == mi) fp->gv[i].mi = mj;
1606     for (i = 0; i < fp->rc; i++)
1607         if (fp->rv[i].mi == mi) fp->rv[i].mi = mj;
1608 }
1609
1610 static void swap_vert(struct s_file *fp, int vi, int vj)
1611 {
1612     int i, j;
1613
1614     for (i = 0; i < fp->ec; i++)
1615     {
1616         if (fp->ev[i].vi == vi) fp->ev[i].vi = vj;
1617         if (fp->ev[i].vj == vi) fp->ev[i].vj = vj;
1618     }
1619
1620     for (i = 0; i < fp->gc; i++)
1621     {
1622         if (fp->gv[i].vi == vi) fp->gv[i].vi = vj;
1623         if (fp->gv[i].vj == vi) fp->gv[i].vj = vj;
1624         if (fp->gv[i].vk == vi) fp->gv[i].vk = vj;
1625     }
1626
1627     for (i = 0; i < fp->lc; i++)
1628         for (j = 0; j < fp->lv[i].vc; j++)
1629             if (fp->iv[fp->lv[i].v0 + j] == vi)
1630                 fp->iv[fp->lv[i].v0 + j]  = vj;
1631 }
1632
1633 static void swap_edge(struct s_file *fp, int ei, int ej)
1634 {
1635     int i, j;
1636
1637     for (i = 0; i < fp->lc; i++)
1638         for (j = 0; j < fp->lv[i].ec; j++)
1639             if (fp->iv[fp->lv[i].e0 + j] == ei)
1640                 fp->iv[fp->lv[i].e0 + j]  = ej;
1641 }
1642
1643 static void swap_side(struct s_file *fp, int si, int sj)
1644 {
1645     int i, j;
1646
1647     for (i = 0; i < fp->gc; i++)
1648     {
1649         if (fp->gv[i].si == si) fp->gv[i].si = sj;
1650         if (fp->gv[i].sj == si) fp->gv[i].sj = sj;
1651         if (fp->gv[i].sk == si) fp->gv[i].sk = sj;
1652     }
1653     for (i = 0; i < fp->nc; i++)
1654         if (fp->nv[i].si == si) fp->nv[i].si = sj;
1655
1656     for (i = 0; i < fp->lc; i++)
1657         for (j = 0; j < fp->lv[i].sc; j++)
1658             if (fp->iv[fp->lv[i].s0 + j] == si)
1659                 fp->iv[fp->lv[i].s0 + j]  = sj;
1660 }
1661
1662 static void swap_texc(struct s_file *fp, int ti, int tj)
1663 {
1664     int i;
1665
1666     for (i = 0; i < fp->gc; i++)
1667     {
1668         if (fp->gv[i].ti == ti) fp->gv[i].ti = tj;
1669         if (fp->gv[i].tj == ti) fp->gv[i].tj = tj;
1670         if (fp->gv[i].tk == ti) fp->gv[i].tk = tj;
1671     }
1672 }
1673
1674
1675 static void swap_geom(struct s_file *fp, int gi, int gj)
1676 {
1677     int i, j;
1678
1679     for (i = 0; i < fp->lc; i++)
1680         for (j = 0; j < fp->lv[i].gc; j++)
1681             if (fp->iv[fp->lv[i].g0 + j] == gi)
1682                 fp->iv[fp->lv[i].g0 + j]  = gj;
1683
1684     for (i = 0; i < fp->bc; i++)
1685         for (j = 0; j < fp->bv[i].gc; j++)
1686             if (fp->iv[fp->bv[i].g0 + j] == gi)
1687                 fp->iv[fp->bv[i].g0 + j]  = gj;
1688 }
1689
1690 /*---------------------------------------------------------------------------*/
1691
1692 static void uniq_mtrl(struct s_file *fp)
1693 {
1694     int i, j, k = 0;
1695
1696     for (i = 0; i < fp->mc; i++)
1697     {
1698         for (j = 0; j < k; j++)
1699             if (comp_mtrl(fp->mv + i, fp->mv + j))
1700             {
1701                 swap_mtrl(fp, i, j);
1702                 break;
1703             }
1704
1705         if (j == k)
1706         {
1707             if (i != k)
1708             {
1709                 fp->mv[k] = fp->mv[i];
1710                 swap_mtrl(fp, i, k);
1711             }
1712             k++;
1713         }
1714     }
1715
1716     fp->mc = k;
1717 }
1718
1719 static void uniq_vert(struct s_file *fp)
1720 {
1721     int i, j, k = 0;
1722
1723     for (i = 0; i < fp->vc; i++)
1724     {
1725         for (j = 0; j < k; j++)
1726             if (comp_vert(fp->vv + i, fp->vv + j))
1727             {
1728                 swap_vert(fp, i, j);
1729                 break;
1730             }
1731
1732         if (j == k)
1733         {
1734             if (i != k)
1735             {
1736                 fp->vv[k] = fp->vv[i];
1737                 swap_vert(fp, i, k);
1738             }
1739             k++;
1740         }
1741     }
1742
1743     fp->vc = k;
1744 }
1745
1746 static void uniq_edge(struct s_file *fp)
1747 {
1748     int i, j, k = 0;
1749
1750     for (i = 0; i < fp->ec; i++)
1751     {
1752         for (j = 0; j < k; j++)
1753             if (comp_edge(fp->ev + i, fp->ev + j))
1754             {
1755                 swap_edge(fp, i, j);
1756                 break;
1757             }
1758
1759         if (j == k)
1760         {
1761             if (i != k)
1762             {
1763                 fp->ev[k] = fp->ev[i];
1764                 swap_edge(fp, i, k);
1765             }
1766             k++;
1767         }
1768     }
1769
1770     fp->ec = k;
1771 }
1772
1773 static void uniq_geom(struct s_file *fp)
1774 {
1775     int i, j, k = 0;
1776
1777     for (i = 0; i < fp->gc; i++)
1778     {
1779         for (j = 0; j < k; j++)
1780             if (comp_geom(fp->gv + i, fp->gv + j))
1781             {
1782                 swap_geom(fp, i, j);
1783                 break;
1784             }
1785
1786         if (j == k)
1787         {
1788             if (i != k)
1789             {
1790                 fp->gv[k] = fp->gv[i];
1791                 swap_geom(fp, i, k);
1792             }
1793             k++;
1794         }
1795     }
1796
1797     fp->gc = k;
1798 }
1799
1800 static void uniq_texc(struct s_file *fp)
1801 {
1802     int i, j, k = 0;
1803
1804     for (i = 0; i < fp->tc; i++)
1805     {
1806         for (j = 0; j < k; j++)
1807             if (comp_texc(fp->tv + i, fp->tv + j))
1808             {
1809                 swap_texc(fp, i, j);
1810                 break;
1811             }
1812
1813         if (j == k)
1814         {
1815             if (i != k)
1816             {
1817                 fp->tv[k] = fp->tv[i];
1818                 swap_texc(fp, i, k);
1819             }
1820             k++;
1821         }
1822     }
1823
1824     fp->tc = k;
1825 }
1826
1827 static void uniq_side(struct s_file *fp)
1828 {
1829     int i, j, k = 0;
1830
1831     for (i = 0; i < fp->sc; i++)
1832     {
1833         for (j = 0; j < k; j++)
1834             if (comp_side(fp->sv + i, fp->sv + j))
1835             {
1836                 swap_side(fp, i, j);
1837                 break;
1838             }
1839
1840         if (j == k)
1841         {
1842             if (i != k)
1843             {
1844                 fp->sv[k] = fp->sv[i];
1845                 swap_side(fp, i, k);
1846             }
1847             k++;
1848         }
1849     }
1850
1851     fp->sc = k;
1852 }
1853
1854 static void uniq_file(struct s_file *fp)
1855 {
1856     uniq_mtrl(fp);
1857     uniq_vert(fp);
1858     uniq_edge(fp);
1859     uniq_side(fp);
1860     uniq_texc(fp);
1861     uniq_geom(fp);
1862 }
1863
1864 /*---------------------------------------------------------------------------*/
1865
1866 static void sort_file(struct s_file *fp)
1867 {
1868     int i, j;
1869
1870     /* Sort billboards farthest to nearest. */
1871
1872     for (i = 0; i < fp->rc; i++)
1873         for (j = i + 1; j < fp->rc; j++)
1874             if (fp->rv[j].d > fp->rv[i].d)
1875             {
1876                 struct s_bill t;
1877
1878                 t         = fp->rv[i];
1879                 fp->rv[i] = fp->rv[j];
1880                 fp->rv[j] =         t;
1881             }
1882
1883     /* Ensure the first vertex is the lowest. */
1884
1885     for (i = 0; i < fp->vc; i++)
1886         if (fp->vv[0].p[1] > fp->vv[i].p[1])
1887         {
1888             struct s_vert t;
1889
1890             t         = fp->vv[0];
1891             fp->vv[0] = fp->vv[i];
1892             fp->vv[i] =         t;
1893
1894             swap_vert(fp,  0, -1);
1895             swap_vert(fp,  i,  0);
1896             swap_vert(fp, -1,  i);
1897         }
1898 }
1899
1900 /*---------------------------------------------------------------------------*/
1901
1902 static int test_lump_side(const struct s_file *fp,
1903                           const struct s_lump *lp,
1904                           const struct s_side *sp)
1905 {
1906     int si;
1907     int vi;
1908
1909     int f = 0;
1910     int b = 0;
1911
1912     /* If the given side is part of the given lump, then the lump is behind. */
1913
1914     for (si = 0; si < lp->sc; si++)
1915         if (fp->sv + fp->iv[lp->s0 + si] == sp)
1916             return -1;
1917
1918     /* Check if each lump vertex is in front of, behind, on the side. */
1919
1920     for (vi = 0; vi < lp->vc; vi++)
1921     {
1922         float d = v_dot(fp->vv[fp->iv[lp->v0 + vi]].p, sp->n) - sp->d;
1923
1924         if (d > 0) f++;
1925         if (d < 0) b++;
1926     }
1927
1928     /* If no verts are behind, the lump is in front, and vice versa. */
1929
1930     if (f > 0 && b == 0) return +1;
1931     if (b > 0 && f == 0) return -1;
1932
1933     /* Else, the lump crosses the side. */
1934
1935     return 0;
1936 }
1937
1938 static int node_node(struct s_file *fp, int l0, int lc)
1939 {
1940     if (lc < 8)
1941     {
1942         /* Base case.  Dump all given lumps into a leaf node. */
1943
1944         fp->nv[fp->nc].si = -1;
1945         fp->nv[fp->nc].ni = -1;
1946         fp->nv[fp->nc].nj = -1;
1947         fp->nv[fp->nc].l0 = l0;
1948         fp->nv[fp->nc].lc = lc;
1949
1950         return incn(fp);
1951     }
1952     else
1953     {
1954         int sj  = 0;
1955         int sjd = lc;
1956         int sjo = lc;
1957         int si;
1958         int li = 0, lic = 0;
1959         int lj = 0, ljc = 0;
1960         int lk = 0, lkc = 0;
1961         int i;
1962
1963         /* Find the side that most evenly splits the given lumps. */
1964
1965         for (si = 0; si < fp->sc; si++)
1966         {
1967             int o = 0;
1968             int d = 0;
1969             int k = 0;
1970
1971             for (li = 0; li < lc; li++)
1972                 if ((k = test_lump_side(fp, fp->lv + l0 + li, fp->sv + si)))
1973                     d += k;
1974                 else
1975                     o++;
1976
1977             d = abs(d);
1978
1979             if ((d < sjd) || (d == sjd && o < sjo))
1980             {
1981                 sj  = si;
1982                 sjd = d;
1983                 sjo = o;
1984             }
1985         }
1986
1987         /* Flag each lump with its position WRT the side. */
1988
1989         for (li = 0; li < lc; li++)
1990             switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
1991             {
1992             case +1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10; break;
1993             case  0: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20; break;
1994             case -1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40; break;
1995             }
1996
1997         /* Sort all lumps in the range by their flag values. */
1998
1999         for (li = 1; li < lc; li++)
2000             for (lj = 0; lj < li; lj++)
2001                 if (fp->lv[l0 + li].fl < fp->lv[l0 + lj].fl)
2002                 {
2003                     struct s_lump l;
2004
2005                     l               = fp->lv[l0 + li];
2006                     fp->lv[l0 + li] = fp->lv[l0 + lj];
2007                     fp->lv[l0 + lj] =               l;
2008                 }
2009
2010         /* Establish the in-front, on, and behind lump ranges. */
2011
2012         li = lic = 0;
2013         lj = ljc = 0;
2014         lk = lkc = 0;
2015
2016         for (i = lc - 1; i >= 0; i--)
2017             switch (fp->lv[l0 + i].fl & 0xf0)
2018             {
2019             case 0x10: li = l0 + i; lic++; break;
2020             case 0x20: lj = l0 + i; ljc++; break;
2021             case 0x40: lk = l0 + i; lkc++; break;
2022             }
2023
2024         /* Add the lumps on the side to the node. */
2025
2026         i = incn(fp);
2027
2028         fp->nv[i].si = sj;
2029         fp->nv[i].ni = node_node(fp, li, lic);
2030
2031         fp->nv[i].nj = node_node(fp, lk, lkc);
2032         fp->nv[i].l0 = lj;
2033         fp->nv[i].lc = ljc;
2034
2035         return i;
2036     }
2037 }
2038
2039 static void node_file(struct s_file *fp)
2040 {
2041     int bi;
2042
2043     /* Sort the lumps of each body into BSP nodes. */
2044
2045     for (bi = 0; bi < fp->bc; bi++)
2046         fp->bv[bi].ni = node_node(fp, fp->bv[bi].l0, fp->bv[bi].lc);
2047 }
2048
2049 /*---------------------------------------------------------------------------*/
2050
2051 static void dump_file(struct s_file *p, const char *name)
2052 {
2053     int i, j;
2054     int c = 0;
2055     int n = 0;
2056     int m = p->rc + p->cc * 128 + (p->zc * p->jc + p->xc) * 32;
2057
2058     /* Count the number of solid lumps. */
2059
2060     for (i = 0; i < p->lc; i++)
2061         if ((p->lv[i].fl & 1) == 0)
2062             n++;
2063
2064     /* Count the number of visible geoms. */
2065
2066     for (i = 0; i < p->bc; i++)
2067     {
2068         for (j = 0; j < p->bv[i].lc; j++)
2069             m += p->lv[p->bv[i].l0 + j].gc;
2070         m += p->bv[i].gc;
2071     }
2072
2073     /* Count the total value of all coins. */
2074
2075     for (i = 0; i < p->cc; i++)
2076         c += p->cv[i].n;
2077
2078     printf("%s (%d/%d/$%d)\n"
2079            "  mtrl  vert  edge  side  texc"
2080            "  geom  lump  path  node  body\n"
2081            "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
2082            "  coin  goal  view  jump  swch"
2083            "  bill  ball  char  indx\n"
2084            "%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
2085            name, n, m, c,
2086            p->mc, p->vc, p->ec, p->sc, p->tc,
2087            p->gc, p->lc, p->pc, p->nc, p->bc,
2088            p->cc, p->zc, p->wc, p->jc, p->xc,
2089            p->rc, p->uc, p->ac, p->ic);
2090 }
2091
2092 /* Skip the ugly SDL main substitution since we only need sdl_image. */
2093 #ifdef main
2094 #    undef main
2095 #endif
2096
2097 int main(int argc, char *argv[])
2098 {
2099     char src[MAXSTR];
2100     char dst[MAXSTR];
2101     struct s_file f;
2102     FILE *fin;
2103
2104     if (argc > 2)
2105     {
2106         if (config_data_path(argv[2], NULL))
2107         {
2108             strncpy(src,  argv[1], MAXSTR);
2109             strncpy(dst,  argv[1], MAXSTR);
2110
2111             if (strcmp(dst + strlen(dst) - 4, ".map") == 0)
2112                 strcpy(dst + strlen(dst) - 4, ".sol");
2113             else
2114                 strcat(dst, ".sol");
2115
2116             if ((fin = fopen(src, "r")))
2117             {
2118                 init_file(&f);
2119                 read_map(&f, fin);
2120
2121                 resolve();
2122                 targets(&f);
2123
2124                 clip_file(&f);
2125                 move_file(&f);
2126                 uniq_file(&f);
2127                 sort_file(&f);
2128                 node_file(&f);
2129                 dump_file(&f, dst);
2130
2131                 sol_stor(&f, dst);
2132
2133                 fclose(fin);
2134
2135                 free_imagedata();
2136             }
2137         }
2138         else fprintf(stderr, "Failure to establish data directory\n");
2139     }
2140     else fprintf(stderr, "Usage: %s <map> [data]\n", argv[0]);
2141
2142     return 0;
2143 }
2144