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