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