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