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