2 * Copyright (C) 2003 Robert Kooima
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.
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.
16 #include <SDL_rwops.h>
17 #include <SDL_image.h>
26 #include "geom.h" /* Only for height constants! */
27 #include "base_image.h"
29 #include "base_config.h"
32 #define MAGIC 0x4c4f53af
37 /*---------------------------------------------------------------------------*/
39 static float erp(float t)
41 return 3.0f * t * t - 2.0f * t * t * t;
44 static float derp(float t)
46 return 6.0f * t - 6.0f * t * t;
49 static void sol_body_v(float v[3],
50 const struct s_file *fp,
51 const struct s_body *bp)
53 if (bp->pi >= 0 && fp->pv[bp->pi].f)
55 const struct s_path *pp = fp->pv + bp->pi;
56 const struct s_path *pq = fp->pv + pp->pi;
58 v_sub(v, pq->p, pp->p);
59 v_scl(v, v, 1.0f / pp->t);
61 v_scl(v, v, derp(bp->t / pp->t));
71 void sol_body_p(float p[3],
72 const struct s_file *fp,
73 const struct s_body *bp)
79 const struct s_path *pp = fp->pv + bp->pi;
80 const struct s_path *pq = fp->pv + pp->pi;
82 v_sub(v, pq->p, pp->p);
83 v_mad(p, pp->p, v, erp(bp->t / pp->t));
93 /*---------------------------------------------------------------------------*/
95 static void sol_load_mtrl(FILE *fin, struct s_mtrl *mp)
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);
104 fread(mp->f, 1, PATHMAX, fin);
107 static void sol_load_vert(FILE *fin, struct s_vert *vp)
109 get_array(fin, vp->p, 3);
112 static void sol_load_edge(FILE *fin, struct s_edge *ep)
114 get_index(fin, &ep->vi);
115 get_index(fin, &ep->vj);
118 static void sol_load_side(FILE *fin, struct s_side *sp)
120 get_array(fin, sp->n, 3);
121 get_float(fin, &sp->d);
124 static void sol_load_texc(FILE *fin, struct s_texc *tp)
126 get_array(fin, tp->u, 2);
129 static void sol_load_geom(FILE *fin, struct s_geom *gp)
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);
143 static void sol_load_lump(FILE *fin, struct s_lump *lp)
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);
156 static void sol_load_node(FILE *fin, struct s_node *np)
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);
165 static void sol_load_path(FILE *fin, struct s_path *pp)
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);
173 static void sol_load_body(FILE *fin, struct s_body *bp)
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);
183 static void sol_load_item(FILE *fin, struct s_item *hp)
185 get_array(fin, hp->p, 3);
186 get_index(fin, &hp->t);
187 get_index(fin, &hp->n);
190 static void sol_load_goal(FILE *fin, struct s_goal *zp)
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);
198 static void sol_load_swch(FILE *fin, struct s_swch *xp)
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);
210 static void sol_load_bill(FILE *fin, struct s_bill *rp)
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);
223 static void sol_load_jump(FILE *fin, struct s_jump *jp)
225 get_array(fin, jp->p, 3);
226 get_array(fin, jp->q, 3);
227 get_float(fin, &jp->r);
230 static void sol_load_ball(FILE *fin, struct s_ball *bp)
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);
239 static void sol_load_view(FILE *fin, struct s_view *wp)
241 get_array(fin, wp->p, 3);
242 get_array(fin, wp->q, 3);
245 static int sol_load_file(FILE *fin, struct s_file *fp)
251 get_index(fin, &magic);
252 get_index(fin, &version);
254 if (magic != MAGIC || version != SOL_VERSION)
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);
278 fp->av = (char *) calloc(fp->ac, sizeof (char));
280 fp->mv = (struct s_mtrl *) calloc(fp->mc, sizeof (struct s_mtrl));
282 fp->vv = (struct s_vert *) calloc(fp->vc, sizeof (struct s_vert));
284 fp->ev = (struct s_edge *) calloc(fp->ec, sizeof (struct s_edge));
286 fp->sv = (struct s_side *) calloc(fp->sc, sizeof (struct s_side));
288 fp->tv = (struct s_texc *) calloc(fp->tc, sizeof (struct s_texc));
290 fp->gv = (struct s_geom *) calloc(fp->gc, sizeof (struct s_geom));
292 fp->lv = (struct s_lump *) calloc(fp->lc, sizeof (struct s_lump));
294 fp->nv = (struct s_node *) calloc(fp->nc, sizeof (struct s_node));
296 fp->pv = (struct s_path *) calloc(fp->pc, sizeof (struct s_path));
298 fp->bv = (struct s_body *) calloc(fp->bc, sizeof (struct s_body));
300 fp->hv = (struct s_item *) calloc(fp->hc, sizeof (struct s_item));
302 fp->zv = (struct s_goal *) calloc(fp->zc, sizeof (struct s_goal));
304 fp->jv = (struct s_jump *) calloc(fp->jc, sizeof (struct s_jump));
306 fp->xv = (struct s_swch *) calloc(fp->xc, sizeof (struct s_swch));
308 fp->rv = (struct s_bill *) calloc(fp->rc, sizeof (struct s_bill));
310 fp->uv = (struct s_ball *) calloc(fp->uc, sizeof (struct s_ball));
312 fp->wv = (struct s_view *) calloc(fp->wc, sizeof (struct s_view));
314 fp->iv = (int *) calloc(fp->ic, sizeof (int));
317 fread(fp->av, 1, fp->ac, fin);
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);
341 static int sol_load_head(FILE *fin, struct s_file *fp)
346 get_index(fin, &magic);
347 get_index(fin, &version);
349 if (magic != MAGIC || version != SOL_VERSION)
352 get_index(fin, &fp->ac);
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);
374 fseek(fin, 18 * 4, SEEK_CUR);
378 fp->av = (char *) calloc(fp->ac, sizeof (char));
379 fread(fp->av, 1, fp->ac, fin);
385 int sol_load_only_file(struct s_file *fp, const char *filename)
390 if ((fin = fopen(filename, FMODE_RB)))
392 res = sol_load_file(fin, fp);
398 int sol_load_only_head(struct s_file *fp, const char *filename)
403 if ((fin = fopen(filename, FMODE_RB)))
405 res = sol_load_head(fin, fp);
411 /*---------------------------------------------------------------------------*/
413 static void sol_stor_mtrl(FILE *fout, struct s_mtrl *mp)
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);
422 fwrite(mp->f, 1, PATHMAX, fout);
425 static void sol_stor_vert(FILE *fout, struct s_vert *vp)
427 put_array(fout, vp->p, 3);
430 static void sol_stor_edge(FILE *fout, struct s_edge *ep)
432 put_index(fout, &ep->vi);
433 put_index(fout, &ep->vj);
436 static void sol_stor_side(FILE *fout, struct s_side *sp)
438 put_array(fout, sp->n, 3);
439 put_float(fout, &sp->d);
442 static void sol_stor_texc(FILE *fout, struct s_texc *tp)
444 put_array(fout, tp->u, 2);
447 static void sol_stor_geom(FILE *fout, struct s_geom *gp)
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);
461 static void sol_stor_lump(FILE *fout, struct s_lump *lp)
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);
474 static void sol_stor_node(FILE *fout, struct s_node *np)
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);
483 static void sol_stor_path(FILE *fout, struct s_path *pp)
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);
491 static void sol_stor_body(FILE *fout, struct s_body *bp)
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);
501 static void sol_stor_item(FILE *fout, struct s_item *hp)
503 put_array(fout, hp->p, 3);
504 put_index(fout, &hp->t);
505 put_index(fout, &hp->n);
508 static void sol_stor_goal(FILE *fout, struct s_goal *zp)
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);
516 static void sol_stor_swch(FILE *fout, struct s_swch *xp)
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);
528 static void sol_stor_bill(FILE *fout, struct s_bill *rp)
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);
541 static void sol_stor_jump(FILE *fout, struct s_jump *jp)
543 put_array(fout, jp->p, 3);
544 put_array(fout, jp->q, 3);
545 put_float(fout, &jp->r);
548 static void sol_stor_ball(FILE *fout, struct s_ball *bp)
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);
557 static void sol_stor_view(FILE *fout, struct s_view *wp)
559 put_array(fout, wp->p, 3);
560 put_array(fout, wp->q, 3);
563 static void sol_stor_file(FILE *fin, struct s_file *fp)
567 int version = SOL_VERSION;
569 put_index(fin, &magic);
570 put_index(fin, &version);
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);
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);
613 /*---------------------------------------------------------------------------*/
615 int sol_stor(struct s_file *fp, const char *filename)
619 if ((fout = fopen(filename, FMODE_WB)))
621 sol_stor_file(fout, fp);
629 void sol_free(struct s_file *fp)
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);
651 memset(fp, 0, sizeof (struct s_file));
654 /*---------------------------------------------------------------------------*/
655 /* Solves (p + v * t) . (p + v * t) == r * r for smallest t. */
657 static float v_sol(const float p[3], const float v[3], float r)
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;
664 if (a == 0.0f) return LARGE;
665 if (d < 0.0f) return LARGE;
668 return -b * 0.5f / a;
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;
675 return (t < 0.0f) ? LARGE : t;
679 /*---------------------------------------------------------------------------*/
682 * Compute the earliest time and position of the intersection of a
683 * sphere and a vertex.
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
689 static float v_vert(float Q[3],
694 const float v[3], float r)
696 float O[3], P[3], V[3];
703 if (v_dot(P, V) < 0.0f)
714 * Compute the earliest time and position of the intersection of a
715 * sphere and an edge.
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.
721 static float v_edge(float Q[3],
727 const float v[3], float r)
731 float du, eu, uu, s, t;
741 v_mad(P, d, u, -du / uu);
742 v_mad(V, e, u, -eu / uu);
745 s = (du + eu * t) / uu;
747 if (0.0f < t && t < LARGE && 0.0f < s && s < 1.0f)
760 * Compute the earlist time and position of the intersection of a
761 * sphere and a plane.
763 * The sphere has radius R and moves along vector V from point P. The
764 * plane oves along vector W. The plane has normal N and is
765 * positioned at distance D from the origin O along that normal.
767 static float v_side(float Q[3],
770 const float n[3], float d,
772 const float v[3], float r)
774 float vn = v_dot(v, n);
775 float wn = v_dot(w, n);
780 float on = v_dot(o, n);
781 float pn = v_dot(p, n);
783 float u = (r + d + on - pn) / (vn - wn);
784 float a = ( d + on - pn) / (vn - wn);
804 /*---------------------------------------------------------------------------*/
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.
811 static float sol_bounce(struct s_ball *up,
813 const float w[3], float dt)
815 const float kb = 1.10f;
816 const float ke = 0.70f;
817 const float km = 0.20f;
819 float n[3], r[3], d[3], u[3], vn, wn, xn, yn;
823 /* Find the normal of the impact. */
829 /* Find the new angular velocity. */
832 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
834 /* Find the new linear velocity. */
838 xn = (vn < 0.0f) ? -vn * ke : vn;
839 yn = (wn > 0.0f) ? wn * kb : wn;
843 v_mad(v, v, u, +km * dt);
844 v_mad(v, v, n, xn + yn);
846 v_mad(p, q, n, up->r);
848 /* Return the "energy" of the impact, to determine the sound amplitude. */
850 return fabsf(v_dot(n, d));
853 /*---------------------------------------------------------------------------*/
856 * Compute the states of all switches after DT seconds have passed.
858 static void sol_swch_step(struct s_file *fp, float dt)
862 for (xi = 0; xi < fp->xc; xi++)
864 struct s_swch *xp = fp->xv + xi;
875 do /* Tortoise and hare cycle traverser. */
877 fp->pv[pi].f = xp->f0;
878 fp->pv[pj].f = xp->f0;
893 * Compute the positions of all bodies after DT seconds have passed.
895 static void sol_body_step(struct s_file *fp, float dt)
899 for (i = 0; i < fp->bc; i++)
901 struct s_body *bp = fp->bv + i;
902 struct s_path *pp = fp->pv + bp->pi;
904 if (bp->pi >= 0 && pp->f)
918 * Compute the positions of all balls after DT seconds have passed.
920 static void sol_ball_step(struct s_file *fp, float dt)
924 for (i = 0; i < fp->uc; i++)
926 struct s_ball *up = fp->uv + i;
928 v_mad(up->p, up->p, up->v, dt);
930 if (v_len(up->w) > 0.0f)
937 m_rot(M, w, v_len(up->w) * dt);
939 m_vxfm(e[0], M, up->e[0]);
940 m_vxfm(e[1], M, up->e[1]);
941 m_vxfm(e[2], M, up->e[2]);
943 v_crs(up->e[2], e[0], e[1]);
944 v_crs(up->e[1], e[2], e[0]);
945 v_crs(up->e[0], e[1], e[2]);
947 v_nrm(up->e[0], up->e[0]);
948 v_nrm(up->e[1], up->e[1]);
949 v_nrm(up->e[2], up->e[2]);
954 /*---------------------------------------------------------------------------*/
956 static float sol_test_vert(float dt,
958 const struct s_ball *up,
959 const struct s_vert *vp,
963 return v_vert(T, o, vp->p, w, up->p, up->v, up->r);
966 static float sol_test_edge(float dt,
968 const struct s_ball *up,
969 const struct s_file *fp,
970 const struct s_edge *ep,
977 v_cpy(q, fp->vv[ep->vi].p);
978 v_sub(u, fp->vv[ep->vj].p,
981 return v_edge(T, o, q, u, w, up->p, up->v, up->r);
984 static float sol_test_side(float dt,
986 const struct s_ball *up,
987 const struct s_file *fp,
988 const struct s_lump *lp,
989 const struct s_side *sp,
993 float t = v_side(T, o, w, sp->n, sp->d, up->p, up->v, up->r);
997 for (i = 0; i < lp->sc; i++)
999 const struct s_side *sq = fp->sv + fp->iv[lp->s0 + i];
1004 v_dot(w, sq->n) * t > sq->d)
1010 /*---------------------------------------------------------------------------*/
1012 static float sol_test_fore(float dt,
1013 const struct s_ball *up,
1014 const struct s_side *sp,
1020 /* If the ball is not behind the plane, the test passes. */
1024 if (v_dot(q, sp->n) - sp->d + up->r >= 0)
1027 /* if the ball is behind the plane but will hit before dt, test passes. */
1029 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1032 /* If the ball is behind but moving toward the plane, test passes. */
1034 if (v_dot(up->v, sp->n) > 0)
1038 /* Else, test fails. */
1043 static float sol_test_back(float dt,
1044 const struct s_ball *up,
1045 const struct s_side *sp,
1051 /* If the ball is not in front of the plane, the test passes. */
1055 if (v_dot(q, sp->n) - sp->d - up->r <= 0)
1058 /* if the ball is behind the plane but will hit before dt, test passes. */
1060 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1063 /* If the ball is in front but moving toward the plane, test passes. */
1065 if (v_dot(up->v, sp->n) < 0)
1069 /* Else, test fails. */
1074 /*---------------------------------------------------------------------------*/
1076 static float sol_test_lump(float dt,
1078 const struct s_ball *up,
1079 const struct s_file *fp,
1080 const struct s_lump *lp,
1084 float U[3] = {0.0f, 0.0f, 0.0f}; /* init value only to avoid gcc warnings */
1088 /* Short circuit a non-solid lump. */
1090 if (lp->fl & L_DETAIL) return t;
1092 /* Test all verts */
1095 for (i = 0; i < lp->vc; i++)
1097 const struct s_vert *vp = fp->vv + fp->iv[lp->v0 + i];
1099 if ((u = sol_test_vert(t, U, up, vp, o, w)) < t)
1106 /* Test all edges */
1109 for (i = 0; i < lp->ec; i++)
1111 const struct s_edge *ep = fp->ev + fp->iv[lp->e0 + i];
1113 if ((u = sol_test_edge(t, U, up, fp, ep, o, w)) < t)
1120 /* Test all sides */
1122 for (i = 0; i < lp->sc; i++)
1124 const struct s_side *sp = fp->sv + fp->iv[lp->s0 + i];
1126 if ((u = sol_test_side(t, U, up, fp, lp, sp, o, w)) < t)
1135 static float sol_test_node(float dt,
1137 const struct s_ball *up,
1138 const struct s_file *fp,
1139 const struct s_node *np,
1143 float U[3], u, t = dt;
1146 /* Test all lumps */
1148 for (i = 0; i < np->lc; i++)
1150 const struct s_lump *lp = fp->lv + np->l0 + i;
1152 if ((u = sol_test_lump(t, U, up, fp, lp, o, w)) < t)
1159 /* Test in front of this node */
1161 if (np->ni >= 0 && sol_test_fore(t, up, fp->sv + np->si, o, w))
1163 const struct s_node *nq = fp->nv + np->ni;
1165 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1172 /* Test behind this node */
1174 if (np->nj >= 0 && sol_test_back(t, up, fp->sv + np->si, o, w))
1176 const struct s_node *nq = fp->nv + np->nj;
1178 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1188 static float sol_test_body(float dt,
1189 float T[3], float V[3],
1190 const struct s_ball *up,
1191 const struct s_file *fp,
1192 const struct s_body *bp)
1194 float U[3], O[3], W[3], u, t = dt;
1196 const struct s_node *np = fp->nv + bp->ni;
1198 sol_body_p(O, fp, bp);
1199 sol_body_v(W, fp, bp);
1201 if ((u = sol_test_node(t, U, up, fp, np, O, W)) < t)
1210 static float sol_test_file(float dt,
1211 float T[3], float V[3],
1212 const struct s_ball *up,
1213 const struct s_file *fp)
1215 float U[3], W[3], u, t = dt;
1218 for (i = 0; i < fp->bc; i++)
1220 const struct s_body *bp = fp->bv + i;
1222 if ((u = sol_test_body(t, U, W, up, fp, bp)) < t)
1232 /*---------------------------------------------------------------------------*/
1235 * Step the physics forward DT seconds under the influence of gravity
1236 * vector G. If the ball gets pinched between two moving solids, this
1237 * loop might not terminate. It is better to do something physically
1238 * impossible than to lock up the game. So, if we make more than C
1239 * iterations, punt it.
1242 float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
1244 float P[3], V[3], v[3], r[3], d, e, nt, b = 0.0f, tt = dt;
1249 struct s_ball *up = fp->uv + ui;
1251 /* If the ball is in contact with a surface, apply friction. */
1256 if (m && sol_test_file(tt, P, V, up, fp) < 0.0005f)
1261 if ((d = v_dot(r, g) / (v_len(r) * v_len(g))) > 0.999f)
1263 if ((e = (v_len(up->v) - dt)) > 0.0f)
1265 /* Scale the linear velocity. */
1267 v_nrm(up->v, up->v);
1268 v_scl(up->v, up->v, e);
1270 /* Scale the angular velocity. */
1274 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
1278 /* Friction has brought the ball to a stop. */
1287 else v_mad(up->v, v, g, tt);
1289 else v_mad(up->v, v, g, tt);
1291 /* Test for collision. */
1293 while (c > 0 && tt > 0 && tt > (nt = sol_test_file(tt, P, V, up, fp)))
1295 sol_body_step(fp, nt);
1296 sol_swch_step(fp, nt);
1297 sol_ball_step(fp, nt);
1301 if (b < (d = sol_bounce(up, P, V, nt)))
1307 sol_body_step(fp, tt);
1308 sol_swch_step(fp, tt);
1309 sol_ball_step(fp, tt);
1314 /*---------------------------------------------------------------------------*/
1316 struct s_item *sol_item_test(struct s_file *fp, float *p, float item_r)
1318 const float *ball_p = fp->uv->p;
1319 const float ball_r = fp->uv->r;
1323 for (hi = 0; hi < fp->hc; hi++)
1327 r[0] = ball_p[0] - fp->hv[hi].p[0];
1328 r[1] = ball_p[1] - fp->hv[hi].p[1];
1329 r[2] = ball_p[2] - fp->hv[hi].p[2];
1331 if (fp->hv[hi].t != ITEM_NONE && v_len(r) < ball_r + item_r)
1333 p[0] = fp->hv[hi].p[0];
1334 p[1] = fp->hv[hi].p[1];
1335 p[2] = fp->hv[hi].p[2];
1343 struct s_goal *sol_goal_test(struct s_file *fp, float *p, int ui)
1345 const float *ball_p = fp->uv[ui].p;
1346 const float ball_r = fp->uv[ui].r;
1349 for (zi = 0; zi < fp->zc; zi++)
1353 r[0] = ball_p[0] - fp->zv[zi].p[0];
1354 r[1] = ball_p[2] - fp->zv[zi].p[2];
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)
1361 p[0] = fp->zv[zi].p[0];
1362 p[1] = fp->zv[zi].p[1];
1363 p[2] = fp->zv[zi].p[2];
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. */
1377 const float *ball_p = fp->uv[ui].p;
1378 const float ball_r = fp->uv[ui].r;
1383 for (ji = 0; ji < fp->jc; ji++)
1387 r[0] = ball_p[0] - fp->jv[ji].p[0];
1388 r[1] = ball_p[2] - fp->jv[ji].p[2];
1391 l = v_len(r) - fp->jv[ji].r;
1393 ball_p[1] > fp->jv[ji].p[1] &&
1394 ball_p[1] < fp->jv[ji].p[1] + JUMP_HEIGHT / 2)
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]);
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) */
1416 const float *ball_p = fp->uv[ui].p;
1417 const float ball_r = fp->uv[ui].r;
1420 int res = 0; /* result */
1422 for (xi = 0; xi < fp->xc; xi++)
1424 struct s_swch *xp = fp->xv + xi;
1426 if (xp->t0 == 0 || xp->f == xp->f0)
1430 r[0] = ball_p[0] - xp->p[0];
1431 r[1] = ball_p[2] - xp->p[2];
1434 l = v_len(r) - xp->r;
1436 ball_p[1] > xp->p[1] &&
1437 ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
1439 if (!xp->e && l < - ball_r)
1444 /* The ball enter */
1448 /* Toggle the state, update the path. */
1450 xp->f = xp->f ? 0 : 1;
1452 do /* Tortoise and hare cycle traverser. */
1454 fp->pv[pi].f = xp->f;
1455 fp->pv[pj].f = xp->f;
1463 /* It toggled to non-default state, start the timer. */
1465 if (xp->f != xp->f0)
1468 /* If visible, set the result */
1481 /*---------------------------------------------------------------------------*/
1483 void put_file_state(FILE *fout, struct s_file *fp)
1485 /* Write the position and orientation of the ball. */
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);
1492 void get_file_state(FILE *fin, struct s_file *fp)
1494 /* Read the position and orientation of the ball. */
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);
1500 /* Compute the 3rd vector of the ball orientatian basis. */
1502 v_crs(fp->uv[0].e[2], fp->uv[0].e[0], fp->uv[0].e[1]);
1505 /*---------------------------------------------------------------------------*/