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.
22 #include "geom.h" /* Only for height constants! */
23 #include "base_image.h"
25 #include "base_config.h"
28 #define MAGIC 0x4c4f53af
34 /*---------------------------------------------------------------------------*/
36 static float erp(float t)
38 return 3.0f * t * t - 2.0f * t * t * t;
41 static float derp(float t)
43 return 6.0f * t - 6.0f * t * t;
46 static void sol_body_v(float v[3],
47 const struct s_file *fp,
48 const struct s_body *bp)
50 if (bp->pi >= 0 && fp->pv[bp->pi].f)
52 const struct s_path *pp = fp->pv + bp->pi;
53 const struct s_path *pq = fp->pv + pp->pi;
55 v_sub(v, pq->p, pp->p);
56 v_scl(v, v, 1.0f / pp->t);
59 v_scl(v, v, derp(bp->t / pp->t));
69 void sol_body_p(float p[3],
70 const struct s_file *fp,
71 const struct s_body *bp)
77 const struct s_path *pp = fp->pv + bp->pi;
78 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));
87 v_sub(v, pq->p, pp->p);
88 v_mad(p, pp->p, v, bp->t / pp->t);
99 /*---------------------------------------------------------------------------*/
101 static void sol_load_mtrl(FILE *fin, struct s_mtrl *mp)
103 get_array(fin, mp->d, 4);
104 get_array(fin, mp->a, 4);
105 get_array(fin, mp->s, 4);
106 get_array(fin, mp->e, 4);
107 get_array(fin, mp->h, 1);
108 get_index(fin, &mp->fl);
110 fread(mp->f, 1, PATHMAX, fin);
113 static void sol_load_vert(FILE *fin, struct s_vert *vp)
115 get_array(fin, vp->p, 3);
118 static void sol_load_edge(FILE *fin, struct s_edge *ep)
120 get_index(fin, &ep->vi);
121 get_index(fin, &ep->vj);
124 static void sol_load_side(FILE *fin, struct s_side *sp)
126 get_array(fin, sp->n, 3);
127 get_float(fin, &sp->d);
130 static void sol_load_texc(FILE *fin, struct s_texc *tp)
132 get_array(fin, tp->u, 2);
135 static void sol_load_geom(FILE *fin, struct s_geom *gp)
137 get_index(fin, &gp->mi);
138 get_index(fin, &gp->ti);
139 get_index(fin, &gp->si);
140 get_index(fin, &gp->vi);
141 get_index(fin, &gp->tj);
142 get_index(fin, &gp->sj);
143 get_index(fin, &gp->vj);
144 get_index(fin, &gp->tk);
145 get_index(fin, &gp->sk);
146 get_index(fin, &gp->vk);
149 static void sol_load_lump(FILE *fin, struct s_lump *lp)
151 get_index(fin, &lp->fl);
152 get_index(fin, &lp->v0);
153 get_index(fin, &lp->vc);
154 get_index(fin, &lp->e0);
155 get_index(fin, &lp->ec);
156 get_index(fin, &lp->g0);
157 get_index(fin, &lp->gc);
158 get_index(fin, &lp->s0);
159 get_index(fin, &lp->sc);
162 static void sol_load_node(FILE *fin, struct s_node *np)
164 get_index(fin, &np->si);
165 get_index(fin, &np->ni);
166 get_index(fin, &np->nj);
167 get_index(fin, &np->l0);
168 get_index(fin, &np->lc);
171 static void sol_load_path(FILE *fin, struct s_path *pp)
173 get_array(fin, pp->p, 3);
174 get_float(fin, &pp->t);
175 get_index(fin, &pp->pi);
176 get_index(fin, &pp->f);
177 get_index(fin, &pp->s);
180 static void sol_load_body(FILE *fin, struct s_body *bp)
182 get_index(fin, &bp->pi);
183 get_index(fin, &bp->ni);
184 get_index(fin, &bp->l0);
185 get_index(fin, &bp->lc);
186 get_index(fin, &bp->g0);
187 get_index(fin, &bp->gc);
190 static void sol_load_item(FILE *fin, struct s_item *hp)
192 get_array(fin, hp->p, 3);
193 get_index(fin, &hp->t);
194 get_index(fin, &hp->n);
197 static void sol_load_goal(FILE *fin, struct s_goal *zp)
199 get_array(fin, zp->p, 3);
200 get_float(fin, &zp->r);
203 static void sol_load_swch(FILE *fin, struct s_swch *xp)
205 get_array(fin, xp->p, 3);
206 get_float(fin, &xp->r);
207 get_index(fin, &xp->pi);
208 get_float(fin, &xp->t0);
209 get_float(fin, &xp->t);
210 get_index(fin, &xp->f0);
211 get_index(fin, &xp->f);
212 get_index(fin, &xp->i);
215 static void sol_load_bill(FILE *fin, struct s_bill *rp)
217 get_index(fin, &rp->fl);
218 get_index(fin, &rp->mi);
219 get_float(fin, &rp->t);
220 get_float(fin, &rp->d);
221 get_array(fin, rp->w, 3);
222 get_array(fin, rp->h, 3);
223 get_array(fin, rp->rx, 3);
224 get_array(fin, rp->ry, 3);
225 get_array(fin, rp->rz, 3);
226 get_array(fin, rp->p, 3);
229 static void sol_load_jump(FILE *fin, struct s_jump *jp)
231 get_array(fin, jp->p, 3);
232 get_array(fin, jp->q, 3);
233 get_float(fin, &jp->r);
236 static void sol_load_ball(FILE *fin, struct s_ball *bp)
238 get_array(fin, bp->p, 3);
239 get_float(fin, &bp->r);
241 bp->e[0][0] = bp->E[0][0] = 1.0f;
242 bp->e[0][1] = bp->E[0][1] = 0.0f;
243 bp->e[0][2] = bp->E[0][2] = 0.0f;
245 bp->e[1][0] = bp->E[1][0] = 0.0f;
246 bp->e[1][1] = bp->E[1][1] = 1.0f;
247 bp->e[1][2] = bp->E[1][2] = 0.0f;
249 bp->e[2][0] = bp->E[2][0] = 0.0f;
250 bp->e[2][1] = bp->E[2][1] = 0.0f;
251 bp->e[2][2] = bp->E[2][2] = 1.0f;
254 static void sol_load_view(FILE *fin, struct s_view *wp)
256 get_array(fin, wp->p, 3);
257 get_array(fin, wp->q, 3);
260 static void sol_load_dict(FILE *fin, struct s_dict *dp)
262 get_index(fin, &dp->ai);
263 get_index(fin, &dp->aj);
266 static int sol_load_file(FILE *fin, struct s_file *fp)
272 get_index(fin, &magic);
273 get_index(fin, &version);
275 if (magic != MAGIC || version != SOL_VERSION)
278 get_index(fin, &fp->ac);
279 get_index(fin, &fp->dc);
280 get_index(fin, &fp->mc);
281 get_index(fin, &fp->vc);
282 get_index(fin, &fp->ec);
283 get_index(fin, &fp->sc);
284 get_index(fin, &fp->tc);
285 get_index(fin, &fp->gc);
286 get_index(fin, &fp->lc);
287 get_index(fin, &fp->nc);
288 get_index(fin, &fp->pc);
289 get_index(fin, &fp->bc);
290 get_index(fin, &fp->hc);
291 get_index(fin, &fp->zc);
292 get_index(fin, &fp->jc);
293 get_index(fin, &fp->xc);
294 get_index(fin, &fp->rc);
295 get_index(fin, &fp->uc);
296 get_index(fin, &fp->wc);
297 get_index(fin, &fp->ic);
300 fp->av = (char *) calloc(fp->ac, sizeof (char));
302 fp->mv = (struct s_mtrl *) calloc(fp->mc, sizeof (struct s_mtrl));
304 fp->vv = (struct s_vert *) calloc(fp->vc, sizeof (struct s_vert));
306 fp->ev = (struct s_edge *) calloc(fp->ec, sizeof (struct s_edge));
308 fp->sv = (struct s_side *) calloc(fp->sc, sizeof (struct s_side));
310 fp->tv = (struct s_texc *) calloc(fp->tc, sizeof (struct s_texc));
312 fp->gv = (struct s_geom *) calloc(fp->gc, sizeof (struct s_geom));
314 fp->lv = (struct s_lump *) calloc(fp->lc, sizeof (struct s_lump));
316 fp->nv = (struct s_node *) calloc(fp->nc, sizeof (struct s_node));
318 fp->pv = (struct s_path *) calloc(fp->pc, sizeof (struct s_path));
320 fp->bv = (struct s_body *) calloc(fp->bc, sizeof (struct s_body));
322 fp->hv = (struct s_item *) calloc(fp->hc, sizeof (struct s_item));
324 fp->zv = (struct s_goal *) calloc(fp->zc, sizeof (struct s_goal));
326 fp->jv = (struct s_jump *) calloc(fp->jc, sizeof (struct s_jump));
328 fp->xv = (struct s_swch *) calloc(fp->xc, sizeof (struct s_swch));
330 fp->rv = (struct s_bill *) calloc(fp->rc, sizeof (struct s_bill));
332 fp->uv = (struct s_ball *) calloc(fp->uc, sizeof (struct s_ball));
334 fp->wv = (struct s_view *) calloc(fp->wc, sizeof (struct s_view));
336 fp->dv = (struct s_dict *) calloc(fp->dc, sizeof (struct s_dict));
338 fp->iv = (int *) calloc(fp->ic, sizeof (int));
341 fread(fp->av, 1, fp->ac, fin);
343 for (i = 0; i < fp->dc; i++) sol_load_dict(fin, fp->dv + i);
344 for (i = 0; i < fp->mc; i++) sol_load_mtrl(fin, fp->mv + i);
345 for (i = 0; i < fp->vc; i++) sol_load_vert(fin, fp->vv + i);
346 for (i = 0; i < fp->ec; i++) sol_load_edge(fin, fp->ev + i);
347 for (i = 0; i < fp->sc; i++) sol_load_side(fin, fp->sv + i);
348 for (i = 0; i < fp->tc; i++) sol_load_texc(fin, fp->tv + i);
349 for (i = 0; i < fp->gc; i++) sol_load_geom(fin, fp->gv + i);
350 for (i = 0; i < fp->lc; i++) sol_load_lump(fin, fp->lv + i);
351 for (i = 0; i < fp->nc; i++) sol_load_node(fin, fp->nv + i);
352 for (i = 0; i < fp->pc; i++) sol_load_path(fin, fp->pv + i);
353 for (i = 0; i < fp->bc; i++) sol_load_body(fin, fp->bv + i);
354 for (i = 0; i < fp->hc; i++) sol_load_item(fin, fp->hv + i);
355 for (i = 0; i < fp->zc; i++) sol_load_goal(fin, fp->zv + i);
356 for (i = 0; i < fp->jc; i++) sol_load_jump(fin, fp->jv + i);
357 for (i = 0; i < fp->xc; i++) sol_load_swch(fin, fp->xv + i);
358 for (i = 0; i < fp->rc; i++) sol_load_bill(fin, fp->rv + i);
359 for (i = 0; i < fp->uc; i++) sol_load_ball(fin, fp->uv + i);
360 for (i = 0; i < fp->wc; i++) sol_load_view(fin, fp->wv + i);
361 for (i = 0; i < fp->ic; i++) get_index(fin, fp->iv + i);
366 static int sol_load_head(FILE *fin, struct s_file *fp)
371 get_index(fin, &magic);
372 get_index(fin, &version);
374 if (magic != MAGIC || version != SOL_VERSION)
377 get_index(fin, &fp->ac);
378 get_index(fin, &fp->dc);
381 get_index(fin, &fp->mc);
382 get_index(fin, &fp->vc);
383 get_index(fin, &fp->ec);
384 get_index(fin, &fp->sc);
385 get_index(fin, &fp->tc);
386 get_index(fin, &fp->gc);
387 get_index(fin, &fp->lc);
388 get_index(fin, &fp->nc);
389 get_index(fin, &fp->pc);
390 get_index(fin, &fp->bc);
391 get_index(fin, &fp->hc);
392 get_index(fin, &fp->zc);
393 get_index(fin, &fp->jc);
394 get_index(fin, &fp->xc);
395 get_index(fin, &fp->rc);
396 get_index(fin, &fp->uc);
397 get_index(fin, &fp->wc);
398 get_index(fin, &fp->ic);
400 fseek(fin, 18 * 4, SEEK_CUR);
404 fp->av = (char *) calloc(fp->ac, sizeof (char));
405 fread(fp->av, 1, fp->ac, fin);
412 fp->dv = (struct s_dict *) calloc(fp->dc, sizeof (struct s_dict));
414 for (i = 0; i < fp->dc; i++)
415 sol_load_dict(fin, fp->dv + i);
421 int sol_load_only_file(struct s_file *fp, const char *filename)
426 if ((fin = fopen(filename, FMODE_RB)))
428 res = sol_load_file(fin, fp);
434 int sol_load_only_head(struct s_file *fp, const char *filename)
439 if ((fin = fopen(filename, FMODE_RB)))
441 res = sol_load_head(fin, fp);
447 /*---------------------------------------------------------------------------*/
449 static void sol_stor_mtrl(FILE *fout, struct s_mtrl *mp)
451 put_array(fout, mp->d, 4);
452 put_array(fout, mp->a, 4);
453 put_array(fout, mp->s, 4);
454 put_array(fout, mp->e, 4);
455 put_array(fout, mp->h, 1);
456 put_index(fout, &mp->fl);
458 fwrite(mp->f, 1, PATHMAX, fout);
461 static void sol_stor_vert(FILE *fout, struct s_vert *vp)
463 put_array(fout, vp->p, 3);
466 static void sol_stor_edge(FILE *fout, struct s_edge *ep)
468 put_index(fout, &ep->vi);
469 put_index(fout, &ep->vj);
472 static void sol_stor_side(FILE *fout, struct s_side *sp)
474 put_array(fout, sp->n, 3);
475 put_float(fout, &sp->d);
478 static void sol_stor_texc(FILE *fout, struct s_texc *tp)
480 put_array(fout, tp->u, 2);
483 static void sol_stor_geom(FILE *fout, struct s_geom *gp)
485 put_index(fout, &gp->mi);
486 put_index(fout, &gp->ti);
487 put_index(fout, &gp->si);
488 put_index(fout, &gp->vi);
489 put_index(fout, &gp->tj);
490 put_index(fout, &gp->sj);
491 put_index(fout, &gp->vj);
492 put_index(fout, &gp->tk);
493 put_index(fout, &gp->sk);
494 put_index(fout, &gp->vk);
497 static void sol_stor_lump(FILE *fout, struct s_lump *lp)
499 put_index(fout, &lp->fl);
500 put_index(fout, &lp->v0);
501 put_index(fout, &lp->vc);
502 put_index(fout, &lp->e0);
503 put_index(fout, &lp->ec);
504 put_index(fout, &lp->g0);
505 put_index(fout, &lp->gc);
506 put_index(fout, &lp->s0);
507 put_index(fout, &lp->sc);
510 static void sol_stor_node(FILE *fout, struct s_node *np)
512 put_index(fout, &np->si);
513 put_index(fout, &np->ni);
514 put_index(fout, &np->nj);
515 put_index(fout, &np->l0);
516 put_index(fout, &np->lc);
519 static void sol_stor_path(FILE *fout, struct s_path *pp)
521 put_array(fout, pp->p, 3);
522 put_float(fout, &pp->t);
523 put_index(fout, &pp->pi);
524 put_index(fout, &pp->f);
525 put_index(fout, &pp->s);
528 static void sol_stor_body(FILE *fout, struct s_body *bp)
530 put_index(fout, &bp->pi);
531 put_index(fout, &bp->ni);
532 put_index(fout, &bp->l0);
533 put_index(fout, &bp->lc);
534 put_index(fout, &bp->g0);
535 put_index(fout, &bp->gc);
538 static void sol_stor_item(FILE *fout, struct s_item *hp)
540 put_array(fout, hp->p, 3);
541 put_index(fout, &hp->t);
542 put_index(fout, &hp->n);
545 static void sol_stor_goal(FILE *fout, struct s_goal *zp)
547 put_array(fout, zp->p, 3);
548 put_float(fout, &zp->r);
551 static void sol_stor_swch(FILE *fout, struct s_swch *xp)
553 put_array(fout, xp->p, 3);
554 put_float(fout, &xp->r);
555 put_index(fout, &xp->pi);
556 put_float(fout, &xp->t0);
557 put_float(fout, &xp->t);
558 put_index(fout, &xp->f0);
559 put_index(fout, &xp->f);
560 put_index(fout, &xp->i);
563 static void sol_stor_bill(FILE *fout, struct s_bill *rp)
565 put_index(fout, &rp->fl);
566 put_index(fout, &rp->mi);
567 put_float(fout, &rp->t);
568 put_float(fout, &rp->d);
569 put_array(fout, rp->w, 3);
570 put_array(fout, rp->h, 3);
571 put_array(fout, rp->rx, 3);
572 put_array(fout, rp->ry, 3);
573 put_array(fout, rp->rz, 3);
574 put_array(fout, rp->p, 3);
577 static void sol_stor_jump(FILE *fout, struct s_jump *jp)
579 put_array(fout, jp->p, 3);
580 put_array(fout, jp->q, 3);
581 put_float(fout, &jp->r);
584 static void sol_stor_ball(FILE *fout, struct s_ball *bp)
586 put_array(fout, bp->p, 3);
587 put_float(fout, &bp->r);
590 static void sol_stor_view(FILE *fout, struct s_view *wp)
592 put_array(fout, wp->p, 3);
593 put_array(fout, wp->q, 3);
596 static void sol_stor_dict(FILE *fout, struct s_dict *dp)
598 put_index(fout, &dp->ai);
599 put_index(fout, &dp->aj);
602 static void sol_stor_file(FILE *fin, struct s_file *fp)
606 int version = SOL_VERSION;
608 put_index(fin, &magic);
609 put_index(fin, &version);
611 put_index(fin, &fp->ac);
612 put_index(fin, &fp->dc);
613 put_index(fin, &fp->mc);
614 put_index(fin, &fp->vc);
615 put_index(fin, &fp->ec);
616 put_index(fin, &fp->sc);
617 put_index(fin, &fp->tc);
618 put_index(fin, &fp->gc);
619 put_index(fin, &fp->lc);
620 put_index(fin, &fp->nc);
621 put_index(fin, &fp->pc);
622 put_index(fin, &fp->bc);
623 put_index(fin, &fp->hc);
624 put_index(fin, &fp->zc);
625 put_index(fin, &fp->jc);
626 put_index(fin, &fp->xc);
627 put_index(fin, &fp->rc);
628 put_index(fin, &fp->uc);
629 put_index(fin, &fp->wc);
630 put_index(fin, &fp->ic);
632 fwrite(fp->av, 1, fp->ac, fin);
634 for (i = 0; i < fp->dc; i++) sol_stor_dict(fin, fp->dv + i);
635 for (i = 0; i < fp->mc; i++) sol_stor_mtrl(fin, fp->mv + i);
636 for (i = 0; i < fp->vc; i++) sol_stor_vert(fin, fp->vv + i);
637 for (i = 0; i < fp->ec; i++) sol_stor_edge(fin, fp->ev + i);
638 for (i = 0; i < fp->sc; i++) sol_stor_side(fin, fp->sv + i);
639 for (i = 0; i < fp->tc; i++) sol_stor_texc(fin, fp->tv + i);
640 for (i = 0; i < fp->gc; i++) sol_stor_geom(fin, fp->gv + i);
641 for (i = 0; i < fp->lc; i++) sol_stor_lump(fin, fp->lv + i);
642 for (i = 0; i < fp->nc; i++) sol_stor_node(fin, fp->nv + i);
643 for (i = 0; i < fp->pc; i++) sol_stor_path(fin, fp->pv + i);
644 for (i = 0; i < fp->bc; i++) sol_stor_body(fin, fp->bv + i);
645 for (i = 0; i < fp->hc; i++) sol_stor_item(fin, fp->hv + i);
646 for (i = 0; i < fp->zc; i++) sol_stor_goal(fin, fp->zv + i);
647 for (i = 0; i < fp->jc; i++) sol_stor_jump(fin, fp->jv + i);
648 for (i = 0; i < fp->xc; i++) sol_stor_swch(fin, fp->xv + i);
649 for (i = 0; i < fp->rc; i++) sol_stor_bill(fin, fp->rv + i);
650 for (i = 0; i < fp->uc; i++) sol_stor_ball(fin, fp->uv + i);
651 for (i = 0; i < fp->wc; i++) sol_stor_view(fin, fp->wv + i);
652 for (i = 0; i < fp->ic; i++) put_index(fin, fp->iv + i);
655 /*---------------------------------------------------------------------------*/
657 int sol_stor(struct s_file *fp, const char *filename)
661 if ((fout = fopen(filename, FMODE_WB)))
663 sol_stor_file(fout, fp);
671 void sol_free(struct s_file *fp)
673 if (fp->av) free(fp->av);
674 if (fp->mv) free(fp->mv);
675 if (fp->vv) free(fp->vv);
676 if (fp->ev) free(fp->ev);
677 if (fp->sv) free(fp->sv);
678 if (fp->tv) free(fp->tv);
679 if (fp->gv) free(fp->gv);
680 if (fp->lv) free(fp->lv);
681 if (fp->nv) free(fp->nv);
682 if (fp->pv) free(fp->pv);
683 if (fp->bv) free(fp->bv);
684 if (fp->hc) free(fp->hv);
685 if (fp->zv) free(fp->zv);
686 if (fp->jv) free(fp->jv);
687 if (fp->xv) free(fp->xv);
688 if (fp->rv) free(fp->rv);
689 if (fp->uv) free(fp->uv);
690 if (fp->wv) free(fp->wv);
691 if (fp->dv) free(fp->dv);
692 if (fp->iv) free(fp->iv);
694 memset(fp, 0, sizeof (struct s_file));
697 /*---------------------------------------------------------------------------*/
698 /* Solves (p + v * t) . (p + v * t) == r * r for smallest t. */
700 static float v_sol(const float p[3], const float v[3], float r)
702 float a = v_dot(v, v);
703 float b = v_dot(v, p) * 2.0f;
704 float c = v_dot(p, p) - r * r;
705 float d = b * b - 4.0f * a * c;
707 /* HACK: This seems to cause failures to detect low-velocity collision
708 Yet, the potential division by zero below seems fine.
709 if (fabsf(a) < SMALL) return LARGE;
712 if (d < 0.0f) return LARGE;
715 float t0 = 0.5f * (-b - fsqrtf(d)) / a;
716 float t1 = 0.5f * (-b + fsqrtf(d)) / a;
717 float t = (t0 < t1) ? t0 : t1;
719 return (t < 0.0f) ? LARGE : t;
721 else return -b * 0.5f / a;
724 /*---------------------------------------------------------------------------*/
727 * Compute the earliest time and position of the intersection of a
728 * sphere and a vertex.
730 * The sphere has radius R and moves along vector V from point P. The
731 * vertex moves along vector W from point Q in a coordinate system
734 static float v_vert(float Q[3],
739 const float v[3], float r)
741 float O[3], P[3], V[3];
748 if (v_dot(P, V) < 0.0f)
759 * Compute the earliest time and position of the intersection of a
760 * sphere and an edge.
762 * The sphere has radius R and moves along vector V from point P. The
763 * edge moves along vector W from point Q in a coordinate system based
764 * at O. The edge extends along the length of vector U.
766 static float v_edge(float Q[3],
772 const float v[3], float r)
776 float du, eu, uu, s, t;
786 v_mad(P, d, u, -du / uu);
787 v_mad(V, e, u, -eu / uu);
790 s = (du + eu * t) / uu;
792 if (0.0f <= t && t < LARGE && 0.0f < s && s < 1.0f)
805 * Compute the earliest time and position of the intersection of a
806 * sphere and a plane.
808 * The sphere has radius R and moves along vector V from point P. The
809 * plane moves along vector W. The plane has normal N and is
810 * positioned at distance D from the origin O along that normal.
812 static float v_side(float Q[3],
815 const float n[3], float d,
817 const float v[3], float r)
819 float vn = v_dot(v, n);
820 float wn = v_dot(w, n);
825 float on = v_dot(o, n);
826 float pn = v_dot(p, n);
828 float u = (r + d + on - pn) / (vn - wn);
829 float a = ( d + on - pn) / (vn - wn);
849 /*---------------------------------------------------------------------------*/
852 * Integrate the rotation of the given basis E under angular velocity W
855 static void sol_rotate(float e[3][3], const float w[3], float dt)
859 float a[3], M[16], f[3][3];
861 /* Compute the rotation matrix. */
864 m_rot(M, a, v_len(w) * dt);
866 /* Apply it to the basis. */
868 m_vxfm(f[0], M, e[0]);
869 m_vxfm(f[1], M, e[1]);
870 m_vxfm(f[2], M, e[2]);
872 /* Re-orthonormalize the basis. */
874 v_crs(e[2], f[0], f[1]);
875 v_crs(e[1], f[2], f[0]);
876 v_crs(e[0], f[1], f[2]);
885 * Compute the new linear and angular velocities of a bouncing ball.
886 * Q gives the position of the point of impact and W gives the
887 * velocity of the object being impacted.
889 static float sol_bounce(struct s_ball *up,
891 const float w[3], float dt)
893 float n[3], r[3], d[3], vn, wn;
897 /* Find the normal of the impact. */
903 /* Find the new angular velocity. */
906 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
908 /* Find the new linear velocity. */
913 v_mad(v, v, n, 1.7 * (wn - vn));
915 v_mad(p, q, n, up->r);
917 /* Return the "energy" of the impact, to determine the sound amplitude. */
919 return fabsf(v_dot(n, d));
923 * Compute the new angular velocity and orientation of a ball pendulum.
924 * A gives the accelleration of the ball. G gives the gravity vector.
926 static void sol_pendulum(struct s_ball *up,
928 const float g[3], float dt)
930 float v[3], A[3], F[3], r[3], Y[3], T[3] = { 0.0f, 0.0f, 0.0f };
932 const float m = 5.000f;
933 const float ka = 0.500f;
934 const float kd = 0.995f;
936 /* Find the total force over DT. */
941 /* Find the force. */
945 /* Find the position of the pendulum. */
947 v_scl(r, up->E[1], -up->r);
949 /* Find the torque on the pendulum. */
951 if (fabsf(v_dot(r, F)) > 0.0f)
954 /* Apply the torque and dampen the angular velocity. */
956 v_mad(up->W, up->W, T, dt);
957 v_scl(up->W, up->W, kd);
959 /* Apply the angular velocity to the pendulum basis. */
961 sol_rotate(up->E, up->W, dt);
963 /* Apply a torque turning the pendulum toward the ball velocity. */
965 v_mad(v, up->v, up->E[1], v_dot(up->v, up->E[1]));
966 v_crs(Y, v, up->E[2]);
967 v_scl(Y, up->E[1], 2 * v_dot(Y, up->E[1]));
969 sol_rotate(up->E, Y, dt);
972 /*---------------------------------------------------------------------------*/
975 * Compute the states of all switches after DT seconds have passed.
977 static void sol_swch_step(struct s_file *fp, float dt)
981 for (xi = 0; xi < fp->xc; xi++)
983 struct s_swch *xp = fp->xv + xi;
994 do /* Tortoise and hare cycle traverser. */
996 fp->pv[pi].f = xp->f0;
997 fp->pv[pj].f = xp->f0;
1012 * Compute the positions of all bodies after DT seconds have passed.
1014 static void sol_body_step(struct s_file *fp, float dt)
1018 for (i = 0; i < fp->bc; i++)
1020 struct s_body *bp = fp->bv + i;
1021 struct s_path *pp = fp->pv + bp->pi;
1023 if (bp->pi >= 0 && pp->f)
1037 * Compute the positions of all balls after DT seconds have passed.
1039 static void sol_ball_step(struct s_file *fp, float dt)
1043 for (i = 0; i < fp->uc; i++)
1045 struct s_ball *up = fp->uv + i;
1047 v_mad(up->p, up->p, up->v, dt);
1049 sol_rotate(up->e, up->w, dt);
1053 /*---------------------------------------------------------------------------*/
1055 static float sol_test_vert(float dt,
1057 const struct s_ball *up,
1058 const struct s_vert *vp,
1062 return v_vert(T, o, vp->p, w, up->p, up->v, up->r);
1065 static float sol_test_edge(float dt,
1067 const struct s_ball *up,
1068 const struct s_file *fp,
1069 const struct s_edge *ep,
1076 v_cpy(q, fp->vv[ep->vi].p);
1077 v_sub(u, fp->vv[ep->vj].p,
1080 return v_edge(T, o, q, u, w, up->p, up->v, up->r);
1083 static float sol_test_side(float dt,
1085 const struct s_ball *up,
1086 const struct s_file *fp,
1087 const struct s_lump *lp,
1088 const struct s_side *sp,
1092 float t = v_side(T, o, w, sp->n, sp->d, up->p, up->v, up->r);
1096 for (i = 0; i < lp->sc; i++)
1098 const struct s_side *sq = fp->sv + fp->iv[lp->s0 + i];
1103 v_dot(w, sq->n) * t > sq->d)
1109 /*---------------------------------------------------------------------------*/
1111 static int sol_test_fore(float dt,
1112 const struct s_ball *up,
1113 const struct s_side *sp,
1119 /* If the ball is not behind the plane, the test passes. */
1123 if (v_dot(q, sp->n) - sp->d + up->r >= 0)
1126 /* If it's not behind the plane after DT seconds, the test passes. */
1128 v_mad(q, q, up->v, dt);
1130 if (v_dot(q, sp->n) - sp->d + up->r >= 0)
1133 /* Else, test fails. */
1138 static int sol_test_back(float dt,
1139 const struct s_ball *up,
1140 const struct s_side *sp,
1146 /* If the ball is not in front of the plane, the test passes. */
1150 if (v_dot(q, sp->n) - sp->d - up->r <= 0)
1153 /* If it's not in front of the plane after DT seconds, the test passes. */
1155 v_mad(q, q, up->v, dt);
1157 if (v_dot(q, sp->n) - sp->d - up->r <= 0)
1160 /* Else, test fails. */
1165 /*---------------------------------------------------------------------------*/
1167 static float sol_test_lump(float dt,
1169 const struct s_ball *up,
1170 const struct s_file *fp,
1171 const struct s_lump *lp,
1175 float U[3] = { 0.0f, 0.0f, 0.0f };
1179 /* Short circuit a non-solid lump. */
1181 if (lp->fl & L_DETAIL) return t;
1183 /* Test all verts */
1186 for (i = 0; i < lp->vc; i++)
1188 const struct s_vert *vp = fp->vv + fp->iv[lp->v0 + i];
1190 if ((u = sol_test_vert(t, U, up, vp, o, w)) < t)
1197 /* Test all edges */
1200 for (i = 0; i < lp->ec; i++)
1202 const struct s_edge *ep = fp->ev + fp->iv[lp->e0 + i];
1204 if ((u = sol_test_edge(t, U, up, fp, ep, o, w)) < t)
1211 /* Test all sides */
1213 for (i = 0; i < lp->sc; i++)
1215 const struct s_side *sp = fp->sv + fp->iv[lp->s0 + i];
1217 if ((u = sol_test_side(t, U, up, fp, lp, sp, o, w)) < t)
1226 static float sol_test_node(float dt,
1228 const struct s_ball *up,
1229 const struct s_file *fp,
1230 const struct s_node *np,
1234 float U[3], u, t = dt;
1237 /* Test all lumps */
1239 for (i = 0; i < np->lc; i++)
1241 const struct s_lump *lp = fp->lv + np->l0 + i;
1243 if ((u = sol_test_lump(t, U, up, fp, lp, o, w)) < t)
1250 /* Test in front of this node */
1252 if (np->ni >= 0 && sol_test_fore(t, up, fp->sv + np->si, o, w))
1254 const struct s_node *nq = fp->nv + np->ni;
1256 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1263 /* Test behind this node */
1265 if (np->nj >= 0 && sol_test_back(t, up, fp->sv + np->si, o, w))
1267 const struct s_node *nq = fp->nv + np->nj;
1269 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1279 static float sol_test_body(float dt,
1280 float T[3], float V[3],
1281 const struct s_ball *up,
1282 const struct s_file *fp,
1283 const struct s_body *bp)
1285 float U[3], O[3], W[3], u, t = dt;
1287 const struct s_node *np = fp->nv + bp->ni;
1289 sol_body_p(O, fp, bp);
1290 sol_body_v(W, fp, bp);
1292 if ((u = sol_test_node(t, U, up, fp, np, O, W)) < t)
1301 static float sol_test_file(float dt,
1302 float T[3], float V[3],
1303 const struct s_ball *up,
1304 const struct s_file *fp)
1306 float U[3], W[3], u, t = dt;
1309 for (i = 0; i < fp->bc; i++)
1311 const struct s_body *bp = fp->bv + i;
1313 if ((u = sol_test_body(t, U, W, up, fp, bp)) < t)
1323 /*---------------------------------------------------------------------------*/
1326 * Step the physics forward DT seconds under the influence of gravity
1327 * vector G. If the ball gets pinched between two moving solids, this
1328 * loop might not terminate. It is better to do something physically
1329 * impossible than to lock up the game. So, if we make more than C
1330 * iterations, punt it.
1333 float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
1335 float P[3], V[3], v[3], r[3], a[3], d, e, nt, b = 0.0f, tt = dt;
1340 struct s_ball *up = fp->uv + ui;
1342 /* If the ball is in contact with a surface, apply friction. */
1348 if (m && sol_test_file(tt, P, V, up, fp) < 0.0005f)
1353 if ((d = v_dot(r, g) / (v_len(r) * v_len(g))) > 0.999f)
1355 if ((e = (v_len(up->v) - dt)) > 0.0f)
1357 /* Scale the linear velocity. */
1359 v_nrm(up->v, up->v);
1360 v_scl(up->v, up->v, e);
1362 /* Scale the angular velocity. */
1366 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
1370 /* Friction has brought the ball to a stop. */
1379 else v_mad(up->v, v, g, tt);
1381 else v_mad(up->v, v, g, tt);
1383 /* Test for collision. */
1385 while (c > 0 && tt > 0 && tt > (nt = sol_test_file(tt, P, V, up, fp)))
1387 sol_body_step(fp, nt);
1388 sol_swch_step(fp, nt);
1389 sol_ball_step(fp, nt);
1393 if (b < (d = sol_bounce(up, P, V, nt)))
1399 sol_body_step(fp, tt);
1400 sol_swch_step(fp, tt);
1401 sol_ball_step(fp, tt);
1403 /* Apply the ball's accelleration to the pendulum. */
1407 sol_pendulum(up, a, g, dt);
1412 /*---------------------------------------------------------------------------*/
1414 struct s_item *sol_item_test(struct s_file *fp, float *p, float item_r)
1416 const float *ball_p = fp->uv->p;
1417 const float ball_r = fp->uv->r;
1421 for (hi = 0; hi < fp->hc; hi++)
1425 r[0] = ball_p[0] - fp->hv[hi].p[0];
1426 r[1] = ball_p[1] - fp->hv[hi].p[1];
1427 r[2] = ball_p[2] - fp->hv[hi].p[2];
1429 if (fp->hv[hi].t != ITEM_NONE && v_len(r) < ball_r + item_r)
1431 p[0] = fp->hv[hi].p[0];
1432 p[1] = fp->hv[hi].p[1];
1433 p[2] = fp->hv[hi].p[2];
1441 struct s_goal *sol_goal_test(struct s_file *fp, float *p, int ui)
1443 const float *ball_p = fp->uv[ui].p;
1444 const float ball_r = fp->uv[ui].r;
1447 for (zi = 0; zi < fp->zc; zi++)
1451 r[0] = ball_p[0] - fp->zv[zi].p[0];
1452 r[1] = ball_p[2] - fp->zv[zi].p[2];
1455 if (v_len(r) < fp->zv[zi].r - ball_r &&
1456 ball_p[1] > fp->zv[zi].p[1] &&
1457 ball_p[1] < fp->zv[zi].p[1] + GOAL_HEIGHT / 2)
1459 p[0] = fp->zv[zi].p[0];
1460 p[1] = fp->zv[zi].p[1];
1461 p[2] = fp->zv[zi].p[2];
1470 * Test if the ball UI is inside a jump. Return 1 if yes and fill P
1471 * with the destination position, return 0 if not, and return 2 if the
1472 * ball is on the border of a jump.
1474 int sol_jump_test(struct s_file *fp, float *p, int ui)
1476 const float *ball_p = fp->uv[ui].p;
1477 const float ball_r = fp->uv[ui].r;
1482 for (ji = 0; ji < fp->jc; ji++)
1486 r[0] = ball_p[0] - fp->jv[ji].p[0];
1487 r[1] = ball_p[2] - fp->jv[ji].p[2];
1490 l = v_len(r) - fp->jv[ji].r;
1492 ball_p[1] > fp->jv[ji].p[1] &&
1493 ball_p[1] < fp->jv[ji].p[1] + JUMP_HEIGHT / 2)
1497 p[0] = fp->jv[ji].q[0] + (ball_p[0] - fp->jv[ji].p[0]);
1498 p[1] = fp->jv[ji].q[1] + (ball_p[1] - fp->jv[ji].p[1]);
1499 p[2] = fp->jv[ji].q[2] + (ball_p[2] - fp->jv[ji].p[2]);
1511 * Test and process the event the ball UI enters a switch. Return 1 if
1512 * a visible switch is activated, return 0 otherwise (no switch is
1513 * activated or only invisible switches).
1515 int sol_swch_test(struct s_file *fp, int ui)
1517 const float *ball_p = fp->uv[ui].p;
1518 const float ball_r = fp->uv[ui].r;
1522 for (xi = 0; xi < fp->xc; xi++)
1524 struct s_swch *xp = fp->xv + xi;
1526 if (xp->t0 == 0 || xp->f == xp->f0)
1531 r[0] = ball_p[0] - xp->p[0];
1532 r[1] = ball_p[2] - xp->p[2];
1535 l = v_len(r) - xp->r;
1538 ball_p[1] > xp->p[1] &&
1539 ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
1541 if (!xp->e && l < - ball_r)
1546 /* The ball enters. */
1551 /* Toggle the state, update the path. */
1553 xp->f = xp->f ? 0 : 1;
1555 do /* Tortoise and hare cycle traverser. */
1557 fp->pv[pi].f = xp->f;
1558 fp->pv[pj].f = xp->f;
1566 /* It toggled to non-default state, start the timer. */
1568 if (xp->f != xp->f0)
1571 /* If visible, set the result. */
1578 /* The ball exits. */
1587 /*---------------------------------------------------------------------------*/
1589 void put_file_state(FILE *fout, struct s_file *fp)
1591 /* Write the position and orientation of the ball. */
1593 put_array(fout, fp->uv[0].p, 3);
1594 put_array(fout, fp->uv[0].e[0], 3);
1595 put_array(fout, fp->uv[0].e[1], 3);
1598 void get_file_state(FILE *fin, struct s_file *fp)
1600 /* Read the position and orientation of the ball. */
1602 get_array(fin, fp->uv[0].p, 3);
1603 get_array(fin, fp->uv[0].e[0], 3);
1604 get_array(fin, fp->uv[0].e[1], 3);
1606 /* Compute the 3rd vector of the ball orientation basis. */
1608 v_crs(fp->uv[0].e[2], fp->uv[0].e[0], fp->uv[0].e[1]);
1611 /*---------------------------------------------------------------------------*/