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