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