Correct logic of BSP back/front tests
[neverball] / share / solid.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 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19
20 #include "glext.h"
21 #include "vec3.h"
22 #include "geom.h" /* Only for height constants! */
23 #include "base_image.h"
24 #include "solid.h"
25 #include "base_config.h"
26 #include "binary.h"
27
28 #define MAGIC       0x4c4f53af
29 #define SOL_VERSION 6
30
31 #define LARGE 1.0e+5f
32 #define SMALL 1.0e-3f
33
34 /*---------------------------------------------------------------------------*/
35
36 static float erp(float t)
37 {
38     return 3.0f * t * t - 2.0f * t * t * t;
39 }
40
41 static float derp(float t)
42 {
43     return 6.0f * t     - 6.0f * t * t;
44 }
45
46 static void sol_body_v(float v[3],
47                        const struct s_file *fp,
48                        const struct s_body *bp)
49 {
50     if (bp->pi >= 0 && fp->pv[bp->pi].f)
51     {
52         const struct s_path *pp = fp->pv + bp->pi;
53         const struct s_path *pq = fp->pv + pp->pi;
54
55         v_sub(v, pq->p, pp->p);
56         v_scl(v, v, 1.0f / pp->t);
57
58         if (pp->s)
59             v_scl(v, v, derp(bp->t / pp->t));
60     }
61     else
62     {
63         v[0] = 0.0f;
64         v[1] = 0.0f;
65         v[2] = 0.0f;
66     }
67 }
68
69 void sol_body_p(float p[3],
70                 const struct s_file *fp,
71                 const struct s_body *bp)
72 {
73     float v[3];
74
75     if (bp->pi >= 0)
76     {
77         const struct s_path *pp = fp->pv + bp->pi;
78         const struct s_path *pq = fp->pv + pp->pi;
79
80         if (pp->s)
81         {
82             v_sub(v, pq->p, pp->p);
83             v_mad(p, pp->p, v, erp(bp->t / pp->t));
84         }
85         else
86         {
87             v_sub(v, pq->p, pp->p);
88             v_mad(p, pp->p, v, bp->t / pp->t);
89         }
90     }
91     else
92     {
93         p[0] = 0.0f;
94         p[1] = 0.0f;
95         p[2] = 0.0f;
96     }
97 }
98
99 /*---------------------------------------------------------------------------*/
100
101 static void sol_load_mtrl(FILE *fin, struct s_mtrl *mp)
102 {
103     get_array(fin,  mp->d, 4);
104     get_array(fin,  mp->a, 4);
105     get_array(fin,  mp->s, 4);
106     get_array(fin,  mp->e, 4);
107     get_array(fin,  mp->h, 1);
108     get_index(fin, &mp->fl);
109
110     fread(mp->f, 1, PATHMAX, fin);
111 }
112
113 static void sol_load_vert(FILE *fin, struct s_vert *vp)
114 {
115     get_array(fin,  vp->p, 3);
116 }
117
118 static void sol_load_edge(FILE *fin, struct s_edge *ep)
119 {
120     get_index(fin, &ep->vi);
121     get_index(fin, &ep->vj);
122 }
123
124 static void sol_load_side(FILE *fin, struct s_side *sp)
125 {
126     get_array(fin,  sp->n, 3);
127     get_float(fin, &sp->d);
128 }
129
130 static void sol_load_texc(FILE *fin, struct s_texc *tp)
131 {
132     get_array(fin,  tp->u, 2);
133 }
134
135 static void sol_load_geom(FILE *fin, struct s_geom *gp)
136 {
137     get_index(fin, &gp->mi);
138     get_index(fin, &gp->ti);
139     get_index(fin, &gp->si);
140     get_index(fin, &gp->vi);
141     get_index(fin, &gp->tj);
142     get_index(fin, &gp->sj);
143     get_index(fin, &gp->vj);
144     get_index(fin, &gp->tk);
145     get_index(fin, &gp->sk);
146     get_index(fin, &gp->vk);
147 }
148
149 static void sol_load_lump(FILE *fin, struct s_lump *lp)
150 {
151     get_index(fin, &lp->fl);
152     get_index(fin, &lp->v0);
153     get_index(fin, &lp->vc);
154     get_index(fin, &lp->e0);
155     get_index(fin, &lp->ec);
156     get_index(fin, &lp->g0);
157     get_index(fin, &lp->gc);
158     get_index(fin, &lp->s0);
159     get_index(fin, &lp->sc);
160 }
161
162 static void sol_load_node(FILE *fin, struct s_node *np)
163 {
164     get_index(fin, &np->si);
165     get_index(fin, &np->ni);
166     get_index(fin, &np->nj);
167     get_index(fin, &np->l0);
168     get_index(fin, &np->lc);
169 }
170
171 static void sol_load_path(FILE *fin, struct s_path *pp)
172 {
173     get_array(fin,  pp->p, 3);
174     get_float(fin, &pp->t);
175     get_index(fin, &pp->pi);
176     get_index(fin, &pp->f);
177     get_index(fin, &pp->s);
178 }
179
180 static void sol_load_body(FILE *fin, struct s_body *bp)
181 {
182     get_index(fin, &bp->pi);
183     get_index(fin, &bp->ni);
184     get_index(fin, &bp->l0);
185     get_index(fin, &bp->lc);
186     get_index(fin, &bp->g0);
187     get_index(fin, &bp->gc);
188 }
189
190 static void sol_load_item(FILE *fin, struct s_item *hp)
191 {
192     get_array(fin,  hp->p, 3);
193     get_index(fin, &hp->t);
194     get_index(fin, &hp->n);
195 }
196
197 static void sol_load_goal(FILE *fin, struct s_goal *zp)
198 {
199     get_array(fin,  zp->p, 3);
200     get_float(fin, &zp->r);
201 }
202
203 static void sol_load_swch(FILE *fin, struct s_swch *xp)
204 {
205     get_array(fin,  xp->p, 3);
206     get_float(fin, &xp->r);
207     get_index(fin, &xp->pi);
208     get_float(fin, &xp->t0);
209     get_float(fin, &xp->t);
210     get_index(fin, &xp->f0);
211     get_index(fin, &xp->f);
212     get_index(fin, &xp->i);
213 }
214
215 static void sol_load_bill(FILE *fin, struct s_bill *rp)
216 {
217     get_index(fin, &rp->fl);
218     get_index(fin, &rp->mi);
219     get_float(fin, &rp->t);
220     get_float(fin, &rp->d);
221     get_array(fin,  rp->w,  3);
222     get_array(fin,  rp->h,  3);
223     get_array(fin,  rp->rx, 3);
224     get_array(fin,  rp->ry, 3);
225     get_array(fin,  rp->rz, 3);
226     get_array(fin,  rp->p,  3);
227 }
228
229 static void sol_load_jump(FILE *fin, struct s_jump *jp)
230 {
231     get_array(fin,  jp->p, 3);
232     get_array(fin,  jp->q, 3);
233     get_float(fin, &jp->r);
234 }
235
236 static void sol_load_ball(FILE *fin, struct s_ball *bp)
237 {
238     get_array(fin,  bp->p, 3);
239     get_float(fin, &bp->r);
240
241     bp->e[0][0] = bp->E[0][0] = 1.0f;
242     bp->e[0][1] = bp->E[0][1] = 0.0f;
243     bp->e[0][2] = bp->E[0][2] = 0.0f;
244
245     bp->e[1][0] = bp->E[1][0] = 0.0f;
246     bp->e[1][1] = bp->E[1][1] = 1.0f;
247     bp->e[1][2] = bp->E[1][2] = 0.0f;
248
249     bp->e[2][0] = bp->E[2][0] = 0.0f;
250     bp->e[2][1] = bp->E[2][1] = 0.0f;
251     bp->e[2][2] = bp->E[2][2] = 1.0f;
252 }
253
254 static void sol_load_view(FILE *fin, struct s_view *wp)
255 {
256     get_array(fin,  wp->p, 3);
257     get_array(fin,  wp->q, 3);
258 }
259
260 static void sol_load_dict(FILE *fin, struct s_dict *dp)
261 {
262     get_index(fin, &dp->ai);
263     get_index(fin, &dp->aj);
264 }
265
266 static int sol_load_file(FILE *fin, struct s_file *fp)
267 {
268     int i;
269     int magic;
270     int version;
271
272     get_index(fin, &magic);
273     get_index(fin, &version);
274
275     if (magic != MAGIC || version != SOL_VERSION)
276         return 0;
277
278     get_index(fin, &fp->ac);
279     get_index(fin, &fp->dc);
280     get_index(fin, &fp->mc);
281     get_index(fin, &fp->vc);
282     get_index(fin, &fp->ec);
283     get_index(fin, &fp->sc);
284     get_index(fin, &fp->tc);
285     get_index(fin, &fp->gc);
286     get_index(fin, &fp->lc);
287     get_index(fin, &fp->nc);
288     get_index(fin, &fp->pc);
289     get_index(fin, &fp->bc);
290     get_index(fin, &fp->hc);
291     get_index(fin, &fp->zc);
292     get_index(fin, &fp->jc);
293     get_index(fin, &fp->xc);
294     get_index(fin, &fp->rc);
295     get_index(fin, &fp->uc);
296     get_index(fin, &fp->wc);
297     get_index(fin, &fp->ic);
298
299     if (fp->ac)
300         fp->av = (char          *) calloc(fp->ac, sizeof (char));
301     if (fp->mc)
302         fp->mv = (struct s_mtrl *) calloc(fp->mc, sizeof (struct s_mtrl));
303     if (fp->vc)
304         fp->vv = (struct s_vert *) calloc(fp->vc, sizeof (struct s_vert));
305     if (fp->ec)
306         fp->ev = (struct s_edge *) calloc(fp->ec, sizeof (struct s_edge));
307     if (fp->sc)
308         fp->sv = (struct s_side *) calloc(fp->sc, sizeof (struct s_side));
309     if (fp->tc)
310         fp->tv = (struct s_texc *) calloc(fp->tc, sizeof (struct s_texc));
311     if (fp->gc)
312         fp->gv = (struct s_geom *) calloc(fp->gc, sizeof (struct s_geom));
313     if (fp->lc)
314         fp->lv = (struct s_lump *) calloc(fp->lc, sizeof (struct s_lump));
315     if (fp->nc)
316         fp->nv = (struct s_node *) calloc(fp->nc, sizeof (struct s_node));
317     if (fp->pc)
318         fp->pv = (struct s_path *) calloc(fp->pc, sizeof (struct s_path));
319     if (fp->bc)
320         fp->bv = (struct s_body *) calloc(fp->bc, sizeof (struct s_body));
321     if (fp->hc)
322         fp->hv = (struct s_item *) calloc(fp->hc, sizeof (struct s_item));
323     if (fp->zc)
324         fp->zv = (struct s_goal *) calloc(fp->zc, sizeof (struct s_goal));
325     if (fp->jc)
326         fp->jv = (struct s_jump *) calloc(fp->jc, sizeof (struct s_jump));
327     if (fp->xc)
328         fp->xv = (struct s_swch *) calloc(fp->xc, sizeof (struct s_swch));
329     if (fp->rc)
330         fp->rv = (struct s_bill *) calloc(fp->rc, sizeof (struct s_bill));
331     if (fp->uc)
332         fp->uv = (struct s_ball *) calloc(fp->uc, sizeof (struct s_ball));
333     if (fp->wc)
334         fp->wv = (struct s_view *) calloc(fp->wc, sizeof (struct s_view));
335     if (fp->dc)
336         fp->dv = (struct s_dict *) calloc(fp->dc, sizeof (struct s_dict));
337     if (fp->ic)
338         fp->iv = (int           *) calloc(fp->ic, sizeof (int));
339
340     if (fp->ac)
341         fread(fp->av, 1, fp->ac, fin);
342
343     for (i = 0; i < fp->dc; i++) sol_load_dict(fin, fp->dv + i);
344     for (i = 0; i < fp->mc; i++) sol_load_mtrl(fin, fp->mv + i);
345     for (i = 0; i < fp->vc; i++) sol_load_vert(fin, fp->vv + i);
346     for (i = 0; i < fp->ec; i++) sol_load_edge(fin, fp->ev + i);
347     for (i = 0; i < fp->sc; i++) sol_load_side(fin, fp->sv + i);
348     for (i = 0; i < fp->tc; i++) sol_load_texc(fin, fp->tv + i);
349     for (i = 0; i < fp->gc; i++) sol_load_geom(fin, fp->gv + i);
350     for (i = 0; i < fp->lc; i++) sol_load_lump(fin, fp->lv + i);
351     for (i = 0; i < fp->nc; i++) sol_load_node(fin, fp->nv + i);
352     for (i = 0; i < fp->pc; i++) sol_load_path(fin, fp->pv + i);
353     for (i = 0; i < fp->bc; i++) sol_load_body(fin, fp->bv + i);
354     for (i = 0; i < fp->hc; i++) sol_load_item(fin, fp->hv + i);
355     for (i = 0; i < fp->zc; i++) sol_load_goal(fin, fp->zv + i);
356     for (i = 0; i < fp->jc; i++) sol_load_jump(fin, fp->jv + i);
357     for (i = 0; i < fp->xc; i++) sol_load_swch(fin, fp->xv + i);
358     for (i = 0; i < fp->rc; i++) sol_load_bill(fin, fp->rv + i);
359     for (i = 0; i < fp->uc; i++) sol_load_ball(fin, fp->uv + i);
360     for (i = 0; i < fp->wc; i++) sol_load_view(fin, fp->wv + i);
361     for (i = 0; i < fp->ic; i++) get_index(fin, fp->iv + i);
362
363     return 1;
364 }
365
366 static int sol_load_head(FILE *fin, struct s_file *fp)
367 {
368     int magic;
369     int version;
370
371     get_index(fin, &magic);
372     get_index(fin, &version);
373
374     if (magic != MAGIC || version != SOL_VERSION)
375         return 0;
376
377     get_index(fin, &fp->ac);
378     get_index(fin, &fp->dc);
379
380 #if 0
381     get_index(fin, &fp->mc);
382     get_index(fin, &fp->vc);
383     get_index(fin, &fp->ec);
384     get_index(fin, &fp->sc);
385     get_index(fin, &fp->tc);
386     get_index(fin, &fp->gc);
387     get_index(fin, &fp->lc);
388     get_index(fin, &fp->nc);
389     get_index(fin, &fp->pc);
390     get_index(fin, &fp->bc);
391     get_index(fin, &fp->hc);
392     get_index(fin, &fp->zc);
393     get_index(fin, &fp->jc);
394     get_index(fin, &fp->xc);
395     get_index(fin, &fp->rc);
396     get_index(fin, &fp->uc);
397     get_index(fin, &fp->wc);
398     get_index(fin, &fp->ic);
399 #endif
400     fseek(fin, 18 * 4, SEEK_CUR);
401
402     if (fp->ac)
403     {
404         fp->av = (char *) calloc(fp->ac, sizeof (char));
405         fread(fp->av, 1, fp->ac, fin);
406     }
407
408     if (fp->dc)
409     {
410         int i;
411
412         fp->dv = (struct s_dict *) calloc(fp->dc, sizeof (struct s_dict));
413
414         for (i = 0; i < fp->dc; i++)
415             sol_load_dict(fin, fp->dv + i);
416     }
417
418     return 1;
419 }
420
421 int sol_load_only_file(struct s_file *fp, const char *filename)
422 {
423     FILE *fin;
424     int res = 0;
425
426     if ((fin = fopen(filename, FMODE_RB)))
427     {
428         res = sol_load_file(fin, fp);
429         fclose(fin);
430     }
431     return res;
432 }
433
434 int sol_load_only_head(struct s_file *fp, const char *filename)
435 {
436     FILE *fin;
437     int res = 0;
438
439     if ((fin = fopen(filename, FMODE_RB)))
440     {
441         res = sol_load_head(fin, fp);
442         fclose(fin);
443     }
444     return res;
445 }
446
447 /*---------------------------------------------------------------------------*/
448
449 static void sol_stor_mtrl(FILE *fout, struct s_mtrl *mp)
450 {
451     put_array(fout,  mp->d, 4);
452     put_array(fout,  mp->a, 4);
453     put_array(fout,  mp->s, 4);
454     put_array(fout,  mp->e, 4);
455     put_array(fout,  mp->h, 1);
456     put_index(fout, &mp->fl);
457
458     fwrite(mp->f, 1, PATHMAX, fout);
459 }
460
461 static void sol_stor_vert(FILE *fout, struct s_vert *vp)
462 {
463     put_array(fout,  vp->p, 3);
464 }
465
466 static void sol_stor_edge(FILE *fout, struct s_edge *ep)
467 {
468     put_index(fout, &ep->vi);
469     put_index(fout, &ep->vj);
470 }
471
472 static void sol_stor_side(FILE *fout, struct s_side *sp)
473 {
474     put_array(fout,  sp->n, 3);
475     put_float(fout, &sp->d);
476 }
477
478 static void sol_stor_texc(FILE *fout, struct s_texc *tp)
479 {
480     put_array(fout,  tp->u, 2);
481 }
482
483 static void sol_stor_geom(FILE *fout, struct s_geom *gp)
484 {
485     put_index(fout, &gp->mi);
486     put_index(fout, &gp->ti);
487     put_index(fout, &gp->si);
488     put_index(fout, &gp->vi);
489     put_index(fout, &gp->tj);
490     put_index(fout, &gp->sj);
491     put_index(fout, &gp->vj);
492     put_index(fout, &gp->tk);
493     put_index(fout, &gp->sk);
494     put_index(fout, &gp->vk);
495 }
496
497 static void sol_stor_lump(FILE *fout, struct s_lump *lp)
498 {
499     put_index(fout, &lp->fl);
500     put_index(fout, &lp->v0);
501     put_index(fout, &lp->vc);
502     put_index(fout, &lp->e0);
503     put_index(fout, &lp->ec);
504     put_index(fout, &lp->g0);
505     put_index(fout, &lp->gc);
506     put_index(fout, &lp->s0);
507     put_index(fout, &lp->sc);
508 }
509
510 static void sol_stor_node(FILE *fout, struct s_node *np)
511 {
512     put_index(fout, &np->si);
513     put_index(fout, &np->ni);
514     put_index(fout, &np->nj);
515     put_index(fout, &np->l0);
516     put_index(fout, &np->lc);
517 }
518
519 static void sol_stor_path(FILE *fout, struct s_path *pp)
520 {
521     put_array(fout,  pp->p, 3);
522     put_float(fout, &pp->t);
523     put_index(fout, &pp->pi);
524     put_index(fout, &pp->f);
525     put_index(fout, &pp->s);
526 }
527
528 static void sol_stor_body(FILE *fout, struct s_body *bp)
529 {
530     put_index(fout, &bp->pi);
531     put_index(fout, &bp->ni);
532     put_index(fout, &bp->l0);
533     put_index(fout, &bp->lc);
534     put_index(fout, &bp->g0);
535     put_index(fout, &bp->gc);
536 }
537
538 static void sol_stor_item(FILE *fout, struct s_item *hp)
539 {
540     put_array(fout,  hp->p, 3);
541     put_index(fout, &hp->t);
542     put_index(fout, &hp->n);
543 }
544
545 static void sol_stor_goal(FILE *fout, struct s_goal *zp)
546 {
547     put_array(fout,  zp->p, 3);
548     put_float(fout, &zp->r);
549 }
550
551 static void sol_stor_swch(FILE *fout, struct s_swch *xp)
552 {
553     put_array(fout,  xp->p, 3);
554     put_float(fout, &xp->r);
555     put_index(fout, &xp->pi);
556     put_float(fout, &xp->t0);
557     put_float(fout, &xp->t);
558     put_index(fout, &xp->f0);
559     put_index(fout, &xp->f);
560     put_index(fout, &xp->i);
561 }
562
563 static void sol_stor_bill(FILE *fout, struct s_bill *rp)
564 {
565     put_index(fout, &rp->fl);
566     put_index(fout, &rp->mi);
567     put_float(fout, &rp->t);
568     put_float(fout, &rp->d);
569     put_array(fout,  rp->w,  3);
570     put_array(fout,  rp->h,  3);
571     put_array(fout,  rp->rx, 3);
572     put_array(fout,  rp->ry, 3);
573     put_array(fout,  rp->rz, 3);
574     put_array(fout,  rp->p,  3);
575 }
576
577 static void sol_stor_jump(FILE *fout, struct s_jump *jp)
578 {
579     put_array(fout,  jp->p, 3);
580     put_array(fout,  jp->q, 3);
581     put_float(fout, &jp->r);
582 }
583
584 static void sol_stor_ball(FILE *fout, struct s_ball *bp)
585 {
586     put_array(fout,  bp->p, 3);
587     put_float(fout, &bp->r);
588 }
589
590 static void sol_stor_view(FILE *fout, struct s_view *wp)
591 {
592     put_array(fout,  wp->p, 3);
593     put_array(fout,  wp->q, 3);
594 }
595
596 static void sol_stor_dict(FILE *fout, struct s_dict *dp)
597 {
598     put_index(fout, &dp->ai);
599     put_index(fout, &dp->aj);
600 }
601
602 static void sol_stor_file(FILE *fin, struct s_file *fp)
603 {
604     int i;
605     int magic   = MAGIC;
606     int version = SOL_VERSION;
607
608     put_index(fin, &magic);
609     put_index(fin, &version);
610
611     put_index(fin, &fp->ac);
612     put_index(fin, &fp->dc);
613     put_index(fin, &fp->mc);
614     put_index(fin, &fp->vc);
615     put_index(fin, &fp->ec);
616     put_index(fin, &fp->sc);
617     put_index(fin, &fp->tc);
618     put_index(fin, &fp->gc);
619     put_index(fin, &fp->lc);
620     put_index(fin, &fp->nc);
621     put_index(fin, &fp->pc);
622     put_index(fin, &fp->bc);
623     put_index(fin, &fp->hc);
624     put_index(fin, &fp->zc);
625     put_index(fin, &fp->jc);
626     put_index(fin, &fp->xc);
627     put_index(fin, &fp->rc);
628     put_index(fin, &fp->uc);
629     put_index(fin, &fp->wc);
630     put_index(fin, &fp->ic);
631
632     fwrite(fp->av, 1, fp->ac, fin);
633
634     for (i = 0; i < fp->dc; i++) sol_stor_dict(fin, fp->dv + i);
635     for (i = 0; i < fp->mc; i++) sol_stor_mtrl(fin, fp->mv + i);
636     for (i = 0; i < fp->vc; i++) sol_stor_vert(fin, fp->vv + i);
637     for (i = 0; i < fp->ec; i++) sol_stor_edge(fin, fp->ev + i);
638     for (i = 0; i < fp->sc; i++) sol_stor_side(fin, fp->sv + i);
639     for (i = 0; i < fp->tc; i++) sol_stor_texc(fin, fp->tv + i);
640     for (i = 0; i < fp->gc; i++) sol_stor_geom(fin, fp->gv + i);
641     for (i = 0; i < fp->lc; i++) sol_stor_lump(fin, fp->lv + i);
642     for (i = 0; i < fp->nc; i++) sol_stor_node(fin, fp->nv + i);
643     for (i = 0; i < fp->pc; i++) sol_stor_path(fin, fp->pv + i);
644     for (i = 0; i < fp->bc; i++) sol_stor_body(fin, fp->bv + i);
645     for (i = 0; i < fp->hc; i++) sol_stor_item(fin, fp->hv + i);
646     for (i = 0; i < fp->zc; i++) sol_stor_goal(fin, fp->zv + i);
647     for (i = 0; i < fp->jc; i++) sol_stor_jump(fin, fp->jv + i);
648     for (i = 0; i < fp->xc; i++) sol_stor_swch(fin, fp->xv + i);
649     for (i = 0; i < fp->rc; i++) sol_stor_bill(fin, fp->rv + i);
650     for (i = 0; i < fp->uc; i++) sol_stor_ball(fin, fp->uv + i);
651     for (i = 0; i < fp->wc; i++) sol_stor_view(fin, fp->wv + i);
652     for (i = 0; i < fp->ic; i++) put_index(fin, fp->iv + i);
653 }
654
655 /*---------------------------------------------------------------------------*/
656
657 int sol_stor(struct s_file *fp, const char *filename)
658 {
659     FILE *fout;
660
661     if ((fout = fopen(filename, FMODE_WB)))
662     {
663         sol_stor_file(fout, fp);
664         fclose(fout);
665
666         return 1;
667     }
668     return 0;
669 }
670
671 void sol_free(struct s_file *fp)
672 {
673     if (fp->av) free(fp->av);
674     if (fp->mv) free(fp->mv);
675     if (fp->vv) free(fp->vv);
676     if (fp->ev) free(fp->ev);
677     if (fp->sv) free(fp->sv);
678     if (fp->tv) free(fp->tv);
679     if (fp->gv) free(fp->gv);
680     if (fp->lv) free(fp->lv);
681     if (fp->nv) free(fp->nv);
682     if (fp->pv) free(fp->pv);
683     if (fp->bv) free(fp->bv);
684     if (fp->hc) free(fp->hv);
685     if (fp->zv) free(fp->zv);
686     if (fp->jv) free(fp->jv);
687     if (fp->xv) free(fp->xv);
688     if (fp->rv) free(fp->rv);
689     if (fp->uv) free(fp->uv);
690     if (fp->wv) free(fp->wv);
691     if (fp->dv) free(fp->dv);
692     if (fp->iv) free(fp->iv);
693
694     memset(fp, 0, sizeof (struct s_file));
695 }
696
697 /*---------------------------------------------------------------------------*/
698 /* Solves (p + v * t) . (p + v * t) == r * r for smallest t.                 */
699
700 static float v_sol(const float p[3], const float v[3], float r)
701 {
702     float a = v_dot(v, v);
703     float b = v_dot(v, p) * 2.0f;
704     float c = v_dot(p, p) - r * r;
705     float d = b * b - 4.0f * a * c;
706
707 /* HACK: This seems to cause failures to detect low-velocity collision
708          Yet, the potential division by zero below seems fine.
709     if (fabsf(a) < SMALL) return LARGE;
710 */
711
712     if      (d < 0.0f) return LARGE;
713     else if (d > 0.0f)
714     {
715         float t0 = 0.5f * (-b - fsqrtf(d)) / a;
716         float t1 = 0.5f * (-b + fsqrtf(d)) / a;
717         float t  = (t0 < t1) ? t0 : t1;
718
719         return (t < 0.0f) ? LARGE : t;
720     }
721     else return -b * 0.5f / a;
722 }
723
724 /*---------------------------------------------------------------------------*/
725
726 /*
727  * Compute the  earliest time  and position of  the intersection  of a
728  * sphere and a vertex.
729  *
730  * The sphere has radius R and moves along vector V from point P.  The
731  * vertex moves  along vector  W from point  Q in a  coordinate system
732  * based at O.
733  */
734 static float v_vert(float Q[3],
735                     const float o[3],
736                     const float q[3],
737                     const float w[3],
738                     const float p[3],
739                     const float v[3], float r)
740 {
741     float O[3], P[3], V[3];
742     float t = LARGE;
743
744     v_add(O, o, q);
745     v_sub(P, p, O);
746     v_sub(V, v, w);
747
748     if (v_dot(P, V) < 0.0f)
749     {
750         t = v_sol(P, V, r);
751
752         if (t < LARGE)
753             v_mad(Q, O, w, t);
754     }
755     return t;
756 }
757
758 /*
759  * Compute the  earliest time  and position of  the intersection  of a
760  * sphere and an edge.
761  *
762  * The sphere has radius R and moves along vector V from point P.  The
763  * edge moves along vector W from point Q in a coordinate system based
764  * at O.  The edge extends along the length of vector U.
765  */
766 static float v_edge(float Q[3],
767                     const float o[3],
768                     const float q[3],
769                     const float u[3],
770                     const float w[3],
771                     const float p[3],
772                     const float v[3], float r)
773 {
774     float d[3], e[3];
775     float P[3], V[3];
776     float du, eu, uu, s, t;
777
778     v_sub(d, p, o);
779     v_sub(d, d, q);
780     v_sub(e, v, w);
781
782     du = v_dot(d, u);
783     eu = v_dot(e, u);
784     uu = v_dot(u, u);
785
786     v_mad(P, d, u, -du / uu);
787     v_mad(V, e, u, -eu / uu);
788
789     t = v_sol(P, V, r);
790     s = (du + eu * t) / uu;
791
792     if (0.0f <= t && t < LARGE && 0.0f < s && s < 1.0f)
793     {
794         v_mad(d, o, w, t);
795         v_mad(e, q, u, s);
796         v_add(Q, e, d);
797     }
798     else
799         t = LARGE;
800
801     return t;
802 }
803
804 /*
805  * Compute  the earliest  time and  position of  the intersection  of a
806  * sphere and a plane.
807  *
808  * The sphere has radius R and moves along vector V from point P.  The
809  * plane  moves  along  vector  W.   The  plane has  normal  N  and  is
810  * positioned at distance D from the origin O along that normal.
811  */
812 static float v_side(float Q[3],
813                     const float o[3],
814                     const float w[3],
815                     const float n[3], float d,
816                     const float p[3],
817                     const float v[3], float r)
818 {
819     float vn = v_dot(v, n);
820     float wn = v_dot(w, n);
821     float t  = LARGE;
822
823     if (vn - wn <= 0.0f)
824     {
825         float on = v_dot(o, n);
826         float pn = v_dot(p, n);
827
828         float u = (r + d + on - pn) / (vn - wn);
829         float a = (    d + on - pn) / (vn - wn);
830
831         if (0.0f <= u)
832         {
833             t = u;
834
835             v_mad(Q, p, v, +t);
836             v_mad(Q, Q, n, -r);
837         }
838         else if (0.0f <= a)
839         {
840             t = 0;
841
842             v_mad(Q, p, v, +t);
843             v_mad(Q, Q, n, -r);
844         }
845     }
846     return t;
847 }
848
849 /*---------------------------------------------------------------------------*/
850
851 /*
852  * Integrate the rotation of the given basis E under angular velocity W
853  * through time DT.
854  */
855 static void sol_rotate(float e[3][3], const float w[3], float dt)
856 {
857     if (v_len(w) > 0.0f)
858     {
859         float a[3], M[16], f[3][3];
860
861         /* Compute the rotation matrix. */
862
863         v_nrm(a, w);
864         m_rot(M, a, v_len(w) * dt);
865
866         /* Apply it to the basis. */
867
868         m_vxfm(f[0], M, e[0]);
869         m_vxfm(f[1], M, e[1]);
870         m_vxfm(f[2], M, e[2]);
871
872         /* Re-orthonormalize the basis. */
873
874         v_crs(e[2], f[0], f[1]);
875         v_crs(e[1], f[2], f[0]);
876         v_crs(e[0], f[1], f[2]);
877
878         v_nrm(e[0], e[0]);
879         v_nrm(e[1], e[1]);
880         v_nrm(e[2], e[2]);
881     }
882 }
883
884 /*
885  * Compute the new  linear and angular velocities of  a bouncing ball.
886  * Q  gives the  position  of the  point  of impact  and  W gives  the
887  * velocity of the object being impacted.
888  */
889 static float sol_bounce(struct s_ball *up,
890                         const float q[3],
891                         const float w[3], float dt)
892 {
893     float n[3], r[3], d[3], vn, wn;
894     float *p = up->p;
895     float *v = up->v;
896
897     /* Find the normal of the impact. */
898
899     v_sub(r, p, q);
900     v_sub(d, v, w);
901     v_nrm(n, r);
902
903     /* Find the new angular velocity. */
904
905     v_crs(up->w, d, r);
906     v_scl(up->w, up->w, -1.0f / (up->r * up->r));
907
908     /* Find the new linear velocity. */
909
910     vn = v_dot(v, n);
911     wn = v_dot(w, n);
912
913     v_mad(v, v, n, 1.7 * (wn - vn));
914
915     v_mad(p, q, n, up->r);
916
917     /* Return the "energy" of the impact, to determine the sound amplitude. */
918
919     return fabsf(v_dot(n, d));
920 }
921
922 /*
923  * Compute the new angular velocity and orientation of a ball pendulum.
924  * A gives the accelleration of the ball.  G gives the gravity vector.
925  */
926 static void sol_pendulum(struct s_ball *up,
927                          const float a[3],
928                          const float g[3], float dt)
929 {
930     float v[3], A[3], F[3], r[3], Y[3], T[3] = { 0.0f, 0.0f, 0.0f };
931
932     const float m  = 5.000f;
933     const float ka = 0.500f;
934     const float kd = 0.995f;
935
936     /* Find the total force over DT. */
937
938     v_scl(A, a,     ka);
939     v_mad(A, A, g, -dt);
940
941     /* Find the force. */
942
943     v_scl(F, A, m / dt);
944
945     /* Find the position of the pendulum. */
946
947     v_scl(r, up->E[1], -up->r);
948
949     /* Find the torque on the pendulum. */
950
951     if (fabsf(v_dot(r, F)) > 0.0f)
952         v_crs(T, F, r);
953
954     /* Apply the torque and dampen the angular velocity. */
955
956     v_mad(up->W, up->W, T, dt);
957     v_scl(up->W, up->W,    kd);
958
959     /* Apply the angular velocity to the pendulum basis. */
960
961     sol_rotate(up->E, up->W, dt);
962
963     /* Apply a torque turning the pendulum toward the ball velocity. */
964
965     v_mad(v, up->v, up->E[1], v_dot(up->v, up->E[1]));
966     v_crs(Y, v, up->E[2]);
967     v_scl(Y, up->E[1], 2 * v_dot(Y, up->E[1]));
968
969     sol_rotate(up->E, Y, dt);
970 }
971
972 /*---------------------------------------------------------------------------*/
973
974 /*
975  * Compute the states of all switches after DT seconds have passed.
976  */
977 static void sol_swch_step(struct s_file *fp, float dt)
978 {
979     int xi;
980
981     for (xi = 0; xi < fp->xc; xi++)
982     {
983         struct s_swch *xp = fp->xv + xi;
984
985         if (xp->t > 0)
986         {
987             xp->t -= dt;
988
989             if (xp->t <= 0)
990             {
991                 int pi = xp->pi;
992                 int pj = xp->pi;
993
994                 do  /* Tortoise and hare cycle traverser. */
995                 {
996                     fp->pv[pi].f = xp->f0;
997                     fp->pv[pj].f = xp->f0;
998
999                     pi = fp->pv[pi].pi;
1000                     pj = fp->pv[pj].pi;
1001                     pj = fp->pv[pj].pi;
1002                 }
1003                 while (pi != pj);
1004
1005                 xp->f = xp->f0;
1006             }
1007         }
1008     }
1009 }
1010
1011 /*
1012  * Compute the positions of all bodies after DT seconds have passed.
1013  */
1014 static void sol_body_step(struct s_file *fp, float dt)
1015 {
1016     int i;
1017
1018     for (i = 0; i < fp->bc; i++)
1019     {
1020         struct s_body *bp = fp->bv + i;
1021         struct s_path *pp = fp->pv + bp->pi;
1022
1023         if (bp->pi >= 0 && pp->f)
1024         {
1025             bp->t += dt;
1026
1027             if (bp->t >= pp->t)
1028             {
1029                 bp->t  = 0;
1030                 bp->pi = pp->pi;
1031             }
1032         }
1033     }
1034 }
1035
1036 /*
1037  * Compute the positions of all balls after DT seconds have passed.
1038  */
1039 static void sol_ball_step(struct s_file *fp, float dt)
1040 {
1041     int i;
1042
1043     for (i = 0; i < fp->uc; i++)
1044     {
1045         struct s_ball *up = fp->uv + i;
1046
1047         v_mad(up->p, up->p, up->v, dt);
1048
1049         sol_rotate(up->e, up->w, dt);
1050     }
1051 }
1052
1053 /*---------------------------------------------------------------------------*/
1054
1055 static float sol_test_vert(float dt,
1056                            float T[3],
1057                            const struct s_ball *up,
1058                            const struct s_vert *vp,
1059                            const float o[3],
1060                            const float w[3])
1061 {
1062     return v_vert(T, o, vp->p, w, up->p, up->v, up->r);
1063 }
1064
1065 static float sol_test_edge(float dt,
1066                            float T[3],
1067                            const struct s_ball *up,
1068                            const struct s_file *fp,
1069                            const struct s_edge *ep,
1070                            const float o[3],
1071                            const float w[3])
1072 {
1073     float q[3];
1074     float u[3];
1075
1076     v_cpy(q, fp->vv[ep->vi].p);
1077     v_sub(u, fp->vv[ep->vj].p,
1078           fp->vv[ep->vi].p);
1079
1080     return v_edge(T, o, q, u, w, up->p, up->v, up->r);
1081 }
1082
1083 static float sol_test_side(float dt,
1084                            float T[3],
1085                            const struct s_ball *up,
1086                            const struct s_file *fp,
1087                            const struct s_lump *lp,
1088                            const struct s_side *sp,
1089                            const float o[3],
1090                            const float w[3])
1091 {
1092     float t = v_side(T, o, w, sp->n, sp->d, up->p, up->v, up->r);
1093     int i;
1094
1095     if (t < dt)
1096         for (i = 0; i < lp->sc; i++)
1097         {
1098             const struct s_side *sq = fp->sv + fp->iv[lp->s0 + i];
1099
1100             if (sp != sq &&
1101                 v_dot(T, sq->n) -
1102                 v_dot(o, sq->n) -
1103                 v_dot(w, sq->n) * t > sq->d)
1104                 return LARGE;
1105         }
1106     return t;
1107 }
1108
1109 /*---------------------------------------------------------------------------*/
1110
1111 static int sol_test_fore(float dt,
1112                          const struct s_ball *up,
1113                          const struct s_side *sp,
1114                          const float o[3],
1115                          const float w[3])
1116 {
1117     float q[3];
1118
1119     /* If the ball is not behind the plane, the test passes. */
1120
1121     v_sub(q, up->p, o);
1122
1123     if (v_dot(q, sp->n) - sp->d + up->r >= 0)
1124         return 1;
1125
1126     /* If it's not behind the plane after DT seconds, the test passes. */
1127
1128     v_mad(q, q, up->v, dt);
1129
1130     if (v_dot(q, sp->n) - sp->d + up->r >= 0)
1131         return 1;
1132
1133     /* Else, test fails. */
1134
1135     return 0;
1136 }
1137
1138 static int sol_test_back(float dt,
1139                          const struct s_ball *up,
1140                          const struct s_side *sp,
1141                          const float o[3],
1142                          const float w[3])
1143 {
1144     float q[3];
1145
1146     /* If the ball is not in front of the plane, the test passes. */
1147
1148     v_sub(q, up->p, o);
1149
1150     if (v_dot(q, sp->n) - sp->d - up->r <= 0)
1151         return 1;
1152
1153     /* If it's not in front of the plane after DT seconds, the test passes. */
1154
1155     v_mad(q, q, up->v, dt);
1156
1157     if (v_dot(q, sp->n) - sp->d - up->r <= 0)
1158         return 1;
1159
1160     /* Else, test fails. */
1161
1162     return 0;
1163 }
1164
1165 /*---------------------------------------------------------------------------*/
1166
1167 static float sol_test_lump(float dt,
1168                            float T[3],
1169                            const struct s_ball *up,
1170                            const struct s_file *fp,
1171                            const struct s_lump *lp,
1172                            const float o[3],
1173                            const float w[3])
1174 {
1175     float U[3] = { 0.0f, 0.0f, 0.0f };
1176     float u, t = dt;
1177     int i;
1178
1179     /* Short circuit a non-solid lump. */
1180
1181     if (lp->fl & L_DETAIL) return t;
1182
1183     /* Test all verts */
1184
1185     if (up->r > 0.0f)
1186         for (i = 0; i < lp->vc; i++)
1187         {
1188             const struct s_vert *vp = fp->vv + fp->iv[lp->v0 + i];
1189
1190             if ((u = sol_test_vert(t, U, up, vp, o, w)) < t)
1191             {
1192                 v_cpy(T, U);
1193                 t = u;
1194             }
1195         }
1196
1197     /* Test all edges */
1198
1199     if (up->r > 0.0f)
1200         for (i = 0; i < lp->ec; i++)
1201         {
1202             const struct s_edge *ep = fp->ev + fp->iv[lp->e0 + i];
1203
1204             if ((u = sol_test_edge(t, U, up, fp, ep, o, w)) < t)
1205             {
1206                 v_cpy(T, U);
1207                 t = u;
1208             }
1209         }
1210
1211     /* Test all sides */
1212
1213     for (i = 0; i < lp->sc; i++)
1214     {
1215         const struct s_side *sp = fp->sv + fp->iv[lp->s0 + i];
1216
1217         if ((u = sol_test_side(t, U, up, fp, lp, sp, o, w)) < t)
1218         {
1219             v_cpy(T, U);
1220             t = u;
1221         }
1222     }
1223     return t;
1224 }
1225
1226 static float sol_test_node(float dt,
1227                            float T[3],
1228                            const struct s_ball *up,
1229                            const struct s_file *fp,
1230                            const struct s_node *np,
1231                            const float o[3],
1232                            const float w[3])
1233 {
1234     float U[3], u, t = dt;
1235     int i;
1236
1237     /* Test all lumps */
1238
1239     for (i = 0; i < np->lc; i++)
1240     {
1241         const struct s_lump *lp = fp->lv + np->l0 + i;
1242
1243         if ((u = sol_test_lump(t, U, up, fp, lp, o, w)) < t)
1244         {
1245             v_cpy(T, U);
1246             t = u;
1247         }
1248     }
1249
1250     /* Test in front of this node */
1251
1252     if (np->ni >= 0 && sol_test_fore(t, up, fp->sv + np->si, o, w))
1253     {
1254         const struct s_node *nq = fp->nv + np->ni;
1255
1256         if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1257         {
1258             v_cpy(T, U);
1259             t = u;
1260         }
1261     }
1262
1263     /* Test behind this node */
1264
1265     if (np->nj >= 0 && sol_test_back(t, up, fp->sv + np->si, o, w))
1266     {
1267         const struct s_node *nq = fp->nv + np->nj;
1268
1269         if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1270         {
1271             v_cpy(T, U);
1272             t = u;
1273         }
1274     }
1275
1276     return t;
1277 }
1278
1279 static float sol_test_body(float dt,
1280                            float T[3], float V[3],
1281                            const struct s_ball *up,
1282                            const struct s_file *fp,
1283                            const struct s_body *bp)
1284 {
1285     float U[3], O[3], W[3], u, t = dt;
1286
1287     const struct s_node *np = fp->nv + bp->ni;
1288
1289     sol_body_p(O, fp, bp);
1290     sol_body_v(W, fp, bp);
1291
1292     if ((u = sol_test_node(t, U, up, fp, np, O, W)) < t)
1293     {
1294         v_cpy(T, U);
1295         v_cpy(V, W);
1296         t = u;
1297     }
1298     return t;
1299 }
1300
1301 static float sol_test_file(float dt,
1302                            float T[3], float V[3],
1303                            const struct s_ball *up,
1304                            const struct s_file *fp)
1305 {
1306     float U[3], W[3], u, t = dt;
1307     int i;
1308
1309     for (i = 0; i < fp->bc; i++)
1310     {
1311         const struct s_body *bp = fp->bv + i;
1312
1313         if ((u = sol_test_body(t, U, W, up, fp, bp)) < t)
1314         {
1315             v_cpy(T, U);
1316             v_cpy(V, W);
1317             t = u;
1318         }
1319     }
1320     return t;
1321 }
1322
1323 /*---------------------------------------------------------------------------*/
1324
1325 /*
1326  * Step the physics forward DT  seconds under the influence of gravity
1327  * vector G.  If the ball gets pinched between two moving solids, this
1328  * loop might not terminate.  It  is better to do something physically
1329  * impossible than  to lock up the game.   So, if we make  more than C
1330  * iterations, punt it.
1331  */
1332
1333 float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
1334 {
1335     float P[3], V[3], v[3], r[3], a[3], d, e, nt, b = 0.0f, tt = dt;
1336     int c = 16;
1337
1338     if (ui < fp->uc)
1339     {
1340         struct s_ball *up = fp->uv + ui;
1341
1342         /* If the ball is in contact with a surface, apply friction. */
1343
1344         v_cpy(a, up->v);
1345         v_cpy(v, up->v);
1346         v_cpy(up->v, g);
1347
1348         if (m && sol_test_file(tt, P, V, up, fp) < 0.0005f)
1349         {
1350             v_cpy(up->v, v);
1351             v_sub(r, P, up->p);
1352
1353             if ((d = v_dot(r, g) / (v_len(r) * v_len(g))) > 0.999f)
1354             {
1355                 if ((e = (v_len(up->v) - dt)) > 0.0f)
1356                 {
1357                     /* Scale the linear velocity. */
1358
1359                     v_nrm(up->v, up->v);
1360                     v_scl(up->v, up->v, e);
1361
1362                     /* Scale the angular velocity. */
1363
1364                     v_sub(v, V, up->v);
1365                     v_crs(up->w, v, r);
1366                     v_scl(up->w, up->w, -1.0f / (up->r * up->r));
1367                 }
1368                 else
1369                 {
1370                     /* Friction has brought the ball to a stop. */
1371
1372                     up->v[0] = 0.0f;
1373                     up->v[1] = 0.0f;
1374                     up->v[2] = 0.0f;
1375
1376                     (*m)++;
1377                 }
1378             }
1379             else v_mad(up->v, v, g, tt);
1380         }
1381         else v_mad(up->v, v, g, tt);
1382
1383         /* Test for collision. */
1384
1385         while (c > 0 && tt > 0 && tt > (nt = sol_test_file(tt, P, V, up, fp)))
1386         {
1387             sol_body_step(fp, nt);
1388             sol_swch_step(fp, nt);
1389             sol_ball_step(fp, nt);
1390
1391             tt -= nt;
1392
1393             if (b < (d = sol_bounce(up, P, V, nt)))
1394                 b = d;
1395
1396             c--;
1397         }
1398
1399         sol_body_step(fp, tt);
1400         sol_swch_step(fp, tt);
1401         sol_ball_step(fp, tt);
1402
1403         /* Apply the ball's accelleration to the pendulum. */
1404
1405         v_sub(a, up->v, a);
1406
1407         sol_pendulum(up, a, g, dt);
1408     }
1409     return b;
1410 }
1411
1412 /*---------------------------------------------------------------------------*/
1413
1414 struct s_item *sol_item_test(struct s_file *fp, float *p, float item_r)
1415 {
1416     const float *ball_p = fp->uv->p;
1417     const float  ball_r = fp->uv->r;
1418
1419     int hi;
1420
1421     for (hi = 0; hi < fp->hc; hi++)
1422     {
1423         float r[3];
1424
1425         r[0] = ball_p[0] - fp->hv[hi].p[0];
1426         r[1] = ball_p[1] - fp->hv[hi].p[1];
1427         r[2] = ball_p[2] - fp->hv[hi].p[2];
1428
1429         if (fp->hv[hi].t != ITEM_NONE && v_len(r) < ball_r + item_r)
1430         {
1431             p[0] = fp->hv[hi].p[0];
1432             p[1] = fp->hv[hi].p[1];
1433             p[2] = fp->hv[hi].p[2];
1434
1435             return &fp->hv[hi];
1436         }
1437     }
1438     return NULL;
1439 }
1440
1441 struct s_goal *sol_goal_test(struct s_file *fp, float *p, int ui)
1442 {
1443     const float *ball_p = fp->uv[ui].p;
1444     const float  ball_r = fp->uv[ui].r;
1445     int zi;
1446
1447     for (zi = 0; zi < fp->zc; zi++)
1448     {
1449         float r[3];
1450
1451         r[0] = ball_p[0] - fp->zv[zi].p[0];
1452         r[1] = ball_p[2] - fp->zv[zi].p[2];
1453         r[2] = 0;
1454
1455         if (v_len(r) < fp->zv[zi].r - ball_r &&
1456             ball_p[1] > fp->zv[zi].p[1] &&
1457             ball_p[1] < fp->zv[zi].p[1] + GOAL_HEIGHT / 2)
1458         {
1459             p[0] = fp->zv[zi].p[0];
1460             p[1] = fp->zv[zi].p[1];
1461             p[2] = fp->zv[zi].p[2];
1462
1463             return &fp->zv[zi];
1464         }
1465     }
1466     return NULL;
1467 }
1468
1469 /*
1470  * Test if the  ball UI is inside a  jump. Return 1 if yes  and fill P
1471  * with the destination position, return 0 if not, and return 2 if the
1472  * ball is on the border of a jump.
1473  */
1474 int sol_jump_test(struct s_file *fp, float *p, int ui)
1475 {
1476     const float *ball_p = fp->uv[ui].p;
1477     const float  ball_r = fp->uv[ui].r;
1478     int ji;
1479     float l;
1480     int res = 0;
1481
1482     for (ji = 0; ji < fp->jc; ji++)
1483     {
1484         float r[3];
1485
1486         r[0] = ball_p[0] - fp->jv[ji].p[0];
1487         r[1] = ball_p[2] - fp->jv[ji].p[2];
1488         r[2] = 0;
1489
1490         l = v_len(r) - fp->jv[ji].r;
1491         if (l < 0 &&
1492             ball_p[1] > fp->jv[ji].p[1] &&
1493             ball_p[1] < fp->jv[ji].p[1] + JUMP_HEIGHT / 2)
1494         {
1495             if (l < - ball_r )
1496             {
1497                 p[0] = fp->jv[ji].q[0] + (ball_p[0] - fp->jv[ji].p[0]);
1498                 p[1] = fp->jv[ji].q[1] + (ball_p[1] - fp->jv[ji].p[1]);
1499                 p[2] = fp->jv[ji].q[2] + (ball_p[2] - fp->jv[ji].p[2]);
1500
1501                 return 1;
1502             }
1503             else
1504                 res = 2;
1505         }
1506     }
1507     return res;
1508 }
1509
1510 /*
1511  * Test and process the event the ball UI enters a switch. Return 1 if
1512  * a visible  switch is  activated, return 0  otherwise (no  switch is
1513  * activated or only invisible switches).
1514  */
1515 int sol_swch_test(struct s_file *fp, int ui)
1516 {
1517     const float *ball_p = fp->uv[ui].p;
1518     const float  ball_r = fp->uv[ui].r;
1519     int xi;
1520     int res = 0;
1521
1522     for (xi = 0; xi < fp->xc; xi++)
1523     {
1524         struct s_swch *xp = fp->xv + xi;
1525
1526         if (xp->t0 == 0 || xp->f == xp->f0)
1527         {
1528             float l;
1529             float r[3];
1530
1531             r[0] = ball_p[0] - xp->p[0];
1532             r[1] = ball_p[2] - xp->p[2];
1533             r[2] = 0;
1534
1535             l = v_len(r) - xp->r;
1536
1537             if (l < ball_r &&
1538                 ball_p[1] > xp->p[1] &&
1539                 ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
1540             {
1541                 if (!xp->e && l < - ball_r)
1542                 {
1543                     int pi = xp->pi;
1544                     int pj = xp->pi;
1545
1546                     /* The ball enters. */
1547
1548                     if (xp->t0 == 0)
1549                         xp->e = 1;
1550
1551                     /* Toggle the state, update the path. */
1552
1553                     xp->f = xp->f ? 0 : 1;
1554
1555                     do  /* Tortoise and hare cycle traverser. */
1556                     {
1557                         fp->pv[pi].f = xp->f;
1558                         fp->pv[pj].f = xp->f;
1559
1560                         pi = fp->pv[pi].pi;
1561                         pj = fp->pv[pj].pi;
1562                         pj = fp->pv[pj].pi;
1563                     }
1564                     while (pi != pj);
1565
1566                     /* It toggled to non-default state, start the timer. */
1567
1568                     if (xp->f != xp->f0)
1569                         xp->t  = xp->t0;
1570
1571                     /* If visible, set the result. */
1572
1573                     if (!xp->i)
1574                         res = 1;
1575                 }
1576             }
1577
1578             /* The ball exits. */
1579
1580             else if (xp->e)
1581                 xp->e = 0;
1582         }
1583     }
1584     return res;
1585 }
1586
1587 /*---------------------------------------------------------------------------*/
1588
1589 void put_file_state(FILE *fout, struct s_file *fp)
1590 {
1591     /* Write the position and orientation of the ball. */
1592
1593     put_array(fout, fp->uv[0].p,    3);
1594     put_array(fout, fp->uv[0].e[0], 3);
1595     put_array(fout, fp->uv[0].e[1], 3);
1596 }
1597
1598 void get_file_state(FILE *fin, struct s_file *fp)
1599 {
1600     /* Read the position and orientation of the ball. */
1601
1602     get_array(fin, fp->uv[0].p,    3);
1603     get_array(fin, fp->uv[0].e[0], 3);
1604     get_array(fin, fp->uv[0].e[1], 3);
1605
1606     /* Compute the 3rd vector of the ball orientation basis. */
1607
1608     v_crs(fp->uv[0].e[2], fp->uv[0].e[0], fp->uv[0].e[1]);
1609 }
1610
1611 /*---------------------------------------------------------------------------*/
1612