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