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>
29 #include "base_config.h"
32 #define MAGIC 0x4F425251 /* Neverball sol file magic number (should not change) */
33 #define SOL_VERSION 4 /* Neverball sol file format version (can change) */
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 static 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 int sol_enum_mtrl(const struct s_file *fp,
96 const struct s_body *bp, int mi)
100 /* Count all lump geoms with this material. */
102 for (li = 0; li < bp->lc; li++)
104 int g0 = fp->lv[bp->l0 + li].g0;
105 int gc = fp->lv[bp->l0 + li].gc;
107 for (gi = 0; gi < gc; gi++)
108 if (fp->gv[fp->iv[g0 + gi]].mi == mi)
112 /* Count all body geoms with this material. */
114 for (gi = 0; gi < bp->gc; gi++)
115 if (fp->gv[fp->iv[bp->g0 + gi]].mi == mi)
121 static int sol_enum_body(const struct s_file *fp,
122 const struct s_body *bp, int fl)
126 /* Count all geoms with this flag. */
128 for (mi = 0; mi < fp->mc; mi++)
129 if (fp->mv[mi].fl & fl)
130 c = c + sol_enum_mtrl(fp, bp, mi);
135 /*---------------------------------------------------------------------------*/
137 static void sol_draw_mtrl(const struct s_file *fp, int i)
139 const struct s_mtrl *mp = fp->mv + i;
141 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mp->a);
142 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->d);
143 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mp->s);
144 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mp->e);
145 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mp->h);
147 if (mp->fl & M_ENVIRONMENT)
149 glEnable(GL_TEXTURE_GEN_S);
150 glEnable(GL_TEXTURE_GEN_T);
152 glBindTexture(GL_TEXTURE_2D, mp->o);
154 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
155 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
159 glDisable(GL_TEXTURE_GEN_S);
160 glDisable(GL_TEXTURE_GEN_T);
162 glBindTexture(GL_TEXTURE_2D, mp->o);
165 if (mp->fl & M_ADDITIVE)
166 glBlendFunc(GL_ONE, GL_ONE);
168 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
172 static void sol_draw_bill(const struct s_file *fp,
173 const struct s_bill *rp, float t)
175 float T = fmodf(t, rp->t) - rp->t / 2;
177 float w = rp->w[0] + rp->w[1] * T + rp->w[2] * T * T;
178 float h = rp->h[0] + rp->h[1] * T + rp->h[2] * T * T;
182 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * T * T;
183 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * T * T;
184 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * T * T;
188 float y0 = (rp->fl & B_EDGE) ? 0 : -h / 2;
189 float y1 = (rp->fl & B_EDGE) ? h : +h / 2;
191 glRotatef(ry, 0.0f, 1.0f, 0.0f);
192 glRotatef(rx, 1.0f, 0.0f, 0.0f);
193 glTranslatef(0.0f, 0.0f, -rp->d);
197 glRotatef(-rx - 90.0f, 1.0f, 0.0f, 0.0f);
198 glRotatef(-ry, 0.0f, 0.0f, 1.0f);
201 glRotatef(-rx, 1.0f, 0.0f, 0.0f);
203 glRotatef(rz, 0.0f, 0.0f, 1.0f);
205 sol_draw_mtrl(fp, rp->mi);
209 glTexCoord2f(0.0f, 1.0f); glVertex2f(-w / 2, y0);
210 glTexCoord2f(1.0f, 1.0f); glVertex2f(+w / 2, y0);
211 glTexCoord2f(1.0f, 0.0f); glVertex2f(+w / 2, y1);
212 glTexCoord2f(0.0f, 0.0f); glVertex2f(-w / 2, y1);
220 void sol_back(const struct s_file *fp, float n, float f, float t)
224 glPushAttrib(GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
226 /* Render all billboards in the given range. */
228 glDisable(GL_LIGHTING);
229 glDepthMask(GL_FALSE);
231 for (ri = 0; ri < fp->rc; ri++)
232 if (n <= fp->rv[ri].d && fp->rv[ri].d < f)
233 sol_draw_bill(fp, fp->rv + ri, t);
238 /*---------------------------------------------------------------------------*/
240 * The following code renders a body in a ludicrously inefficient
241 * manner. It iterates the materials and scans the data structure for
242 * geometry using each. This has the effect of absolutely minimizing
243 * material changes, texture bindings, and Begin/End pairs, but
244 * maximizing trips through the data.
246 * However, this is only done once for each level. The results are
247 * stored in display lists. Thus, it is well worth it.
250 static void sol_draw_geom(const struct s_file *fp,
251 const struct s_geom *gp, int mi)
255 const float *ui = fp->tv[gp->ti].u;
256 const float *uj = fp->tv[gp->tj].u;
257 const float *uk = fp->tv[gp->tk].u;
259 const float *ni = fp->sv[gp->si].n;
260 const float *nj = fp->sv[gp->sj].n;
261 const float *nk = fp->sv[gp->sk].n;
263 const float *vi = fp->vv[gp->vi].p;
264 const float *vj = fp->vv[gp->vj].p;
265 const float *vk = fp->vv[gp->vk].p;
281 static void sol_draw_lump(const struct s_file *fp,
282 const struct s_lump *lp, int mi)
286 for (i = 0; i < lp->gc; i++)
287 sol_draw_geom(fp, fp->gv + fp->iv[lp->g0 + i], mi);
290 static void sol_draw_body(const struct s_file *fp,
291 const struct s_body *bp, int fl)
295 /* Iterate all materials of the correct opacity. */
297 for (mi = 0; mi < fp->mc; mi++)
298 if (fp->mv[mi].fl & fl)
300 if (sol_enum_mtrl(fp, bp, mi))
302 /* Set the material state. */
304 sol_draw_mtrl(fp, mi);
306 /* Render all geometry of that material. */
308 glBegin(GL_TRIANGLES);
310 for (li = 0; li < bp->lc; li++)
311 sol_draw_lump(fp, fp->lv + bp->l0 + li, mi);
312 for (gi = 0; gi < bp->gc; gi++)
313 sol_draw_geom(fp, fp->gv + fp->iv[bp->g0 + gi], mi);
320 static void sol_draw_list(const struct s_file *fp,
321 const struct s_body *bp, GLuint list)
325 sol_body_p(p, fp, bp);
329 /* Translate a moving body. */
331 glTranslatef(p[0], p[1], p[2]);
340 void sol_draw(const struct s_file *fp)
344 glPushAttrib(GL_TEXTURE_BIT |
346 GL_COLOR_BUFFER_BIT |
347 GL_DEPTH_BUFFER_BIT);
349 /* Render all obaque geometry into the color and depth buffers. */
351 for (bi = 0; bi < fp->bc; bi++)
353 sol_draw_list(fp, fp->bv + bi, fp->bv[bi].ol);
355 /* Render all translucent geometry into only the color buffer. */
357 glDepthMask(GL_FALSE);
360 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
362 for (bi = 0; bi < fp->bc; bi++)
364 sol_draw_list(fp, fp->bv + bi, fp->bv[bi].tl);
369 void sol_refl(const struct s_file *fp)
373 glPushAttrib(GL_LIGHTING_BIT);
375 /* Render all reflective geometry into the color and depth buffers. */
378 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
380 for (bi = 0; bi < fp->bc; bi++)
382 sol_draw_list(fp, fp->bv + bi, fp->bv[bi].rl);
387 /*---------------------------------------------------------------------------*/
389 static void sol_shad_geom(const struct s_file *fp,
390 const struct s_geom *gp, int mi)
394 const float *vi = fp->vv[gp->vi].p;
395 const float *vj = fp->vv[gp->vj].p;
396 const float *vk = fp->vv[gp->vk].p;
398 glTexCoord2f(vi[0], vi[2]);
401 glTexCoord2f(vj[0], vj[2]);
404 glTexCoord2f(vk[0], vk[2]);
409 static void sol_shad_lump(const struct s_file *fp,
410 const struct s_lump *lp, int mi)
414 for (i = 0; i < lp->gc; i++)
415 sol_shad_geom(fp, fp->gv + fp->iv[lp->g0 + i], mi);
418 static void sol_shad_body(const struct s_file *fp,
419 const struct s_body *bp, int fl)
423 glBegin(GL_TRIANGLES);
425 for (mi = 0; mi < fp->mc; mi++)
426 if (fp->mv[mi].fl & fl)
428 for (li = 0; li < bp->lc; li++)
429 sol_shad_lump(fp, fp->lv + bp->l0 + li, mi);
430 for (gi = 0; gi < bp->gc; gi++)
431 sol_shad_geom(fp, fp->gv + fp->iv[bp->g0 + gi], mi);
437 static void sol_shad_list(const struct s_file *fp,
438 const struct s_body *bp, GLuint list)
442 sol_body_p(p, fp, bp);
446 /* Translate a moving body. */
448 glTranslatef(p[0], p[1], p[2]);
450 /* Translate the shadow on a moving body. */
452 glMatrixMode(GL_TEXTURE);
455 glTranslatef(p[0], p[2], 0.0f);
457 glMatrixMode(GL_MODELVIEW);
463 /* Pop the shadow translation. */
465 glMatrixMode(GL_TEXTURE);
469 glMatrixMode(GL_MODELVIEW);
474 void sol_shad(const struct s_file *fp)
478 glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT);
480 /* Render all shadowed geometry. */
483 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
485 glDepthFunc(GL_LEQUAL);
486 glDepthMask(GL_FALSE);
488 for (bi = 0; bi < fp->bc; bi++)
490 sol_shad_list(fp, fp->bv + bi, fp->bv[bi].sl);
495 /*---------------------------------------------------------------------------*/
497 static void sol_load_objects(struct s_file *fp, int s)
501 for (i = 0; i < fp->bc; i++)
503 struct s_body *bp = fp->bv + i;
505 /* Draw all opaque geometry. */
507 if (sol_enum_body(fp, bp, M_OPAQUE | M_ENVIRONMENT))
509 fp->bv[i].ol = glGenLists(1);
511 glNewList(fp->bv[i].ol, GL_COMPILE);
513 sol_draw_body(fp, fp->bv + i, M_OPAQUE | M_ENVIRONMENT);
517 else fp->bv[i].ol = 0;
519 /* Draw all translucent geometry. */
521 if (sol_enum_body(fp, bp, M_TRANSPARENT))
523 fp->bv[i].tl = glGenLists(1);
525 glNewList(fp->bv[i].tl, GL_COMPILE);
527 sol_draw_body(fp, fp->bv + i, M_TRANSPARENT);
531 else fp->bv[i].tl = 0;
533 /* Draw all reflective geometry. */
535 if (sol_enum_body(fp, bp, M_REFLECTIVE))
537 fp->bv[i].rl = glGenLists(1);
539 glNewList(fp->bv[i].rl, GL_COMPILE);
541 sol_draw_body(fp, fp->bv + i, M_REFLECTIVE);
545 else fp->bv[i].rl = 0;
547 /* Draw all shadowed geometry. */
549 if (s && sol_enum_body(fp, bp, M_SHADOWED))
551 fp->bv[i].sl = glGenLists(1);
553 glNewList(fp->bv[i].sl, GL_COMPILE);
555 sol_shad_body(fp, fp->bv + i, M_SHADOWED);
559 else fp->bv[i].sl = 0;
563 static SDL_Surface *sol_find_texture(const char *name)
570 /* Prefer a lossless copy of the texture over a lossy compression. */
572 strncpy(png, name, PATHMAX); strcat(png, ".png");
573 strncpy(tga, name, PATHMAX); strcat(tga, ".tga");
574 strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
576 /* Check for a PNG. */
578 if ((s = IMG_Load(config_data(png))))
581 /* Check for a TGA, swapping channels if found. */
583 if ((s = IMG_Load(config_data(tga))))
589 /* Check for a JPG. */
591 if ((s = IMG_Load(config_data(jpg))))
597 static void sol_load_textures(struct s_file *fp, int k)
604 for (i = 0; i < fp->mc; i++)
605 if ((s = sol_find_texture(fp->mv[i].f)))
607 GLenum f = (s->format->BitsPerPixel == 32) ? GL_RGBA : GL_RGB;
609 glGenTextures(1, &fp->mv[i].o);
610 glBindTexture(GL_TEXTURE_2D, fp->mv[i].o);
614 /* Create a new buffer and copy the scaled image to it. */
616 if ((d = image_scale(s, k)))
618 glTexImage2D(GL_TEXTURE_2D, 0, f, d->w, d->h, 0, f,
619 GL_UNSIGNED_BYTE, d->pixels);
624 glTexImage2D(GL_TEXTURE_2D, 0, f, s->w, s->h, 0, f,
625 GL_UNSIGNED_BYTE, s->pixels);
627 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
628 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
630 /* Set the texture to clamp or repeat based on material type. */
632 if (fp->mv[i].fl & M_CLAMPED)
634 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
635 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
639 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
640 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
647 /*---------------------------------------------------------------------------*/
649 static void sol_load_mtrl(FILE *fin, struct s_mtrl *mp)
651 get_array(fin, mp->a, 4);
652 get_array(fin, mp->d, 4);
653 get_array(fin, mp->s, 4);
654 get_array(fin, mp->e, 4);
655 get_array(fin, mp->h, 1);
656 get_index(fin, &mp->fl);
658 fread(mp->f, 1, PATHMAX, fin);
661 static void sol_load_vert(FILE *fin, struct s_vert *vp)
663 get_array(fin, vp->p, 3);
666 static void sol_load_edge(FILE *fin, struct s_edge *ep)
668 get_index(fin, &ep->vi);
669 get_index(fin, &ep->vj);
672 static void sol_load_side(FILE *fin, struct s_side *sp)
674 get_array(fin, sp->n, 3);
675 get_float(fin, &sp->d);
678 static void sol_load_texc(FILE *fin, struct s_texc *tp)
680 get_array(fin, tp->u, 2);
683 static void sol_load_geom(FILE *fin, struct s_geom *gp)
685 get_index(fin, &gp->mi);
686 get_index(fin, &gp->ti);
687 get_index(fin, &gp->si);
688 get_index(fin, &gp->vi);
689 get_index(fin, &gp->tj);
690 get_index(fin, &gp->sj);
691 get_index(fin, &gp->vj);
692 get_index(fin, &gp->tk);
693 get_index(fin, &gp->sk);
694 get_index(fin, &gp->vk);
697 static void sol_load_lump(FILE *fin, struct s_lump *lp)
699 get_index(fin, &lp->fl);
700 get_index(fin, &lp->v0);
701 get_index(fin, &lp->vc);
702 get_index(fin, &lp->e0);
703 get_index(fin, &lp->ec);
704 get_index(fin, &lp->g0);
705 get_index(fin, &lp->gc);
706 get_index(fin, &lp->s0);
707 get_index(fin, &lp->sc);
710 static void sol_load_node(FILE *fin, struct s_node *np)
712 get_index(fin, &np->si);
713 get_index(fin, &np->ni);
714 get_index(fin, &np->nj);
715 get_index(fin, &np->l0);
716 get_index(fin, &np->lc);
719 static void sol_load_path(FILE *fin, struct s_path *pp)
721 get_array(fin, pp->p, 3);
722 get_float(fin, &pp->t);
723 get_index(fin, &pp->pi);
724 get_index(fin, &pp->f);
727 static void sol_load_body(FILE *fin, struct s_body *bp)
729 get_index(fin, &bp->pi);
730 get_index(fin, &bp->ni);
731 get_index(fin, &bp->l0);
732 get_index(fin, &bp->lc);
733 get_index(fin, &bp->g0);
734 get_index(fin, &bp->gc);
737 static void sol_load_coin(FILE *fin, struct s_coin *cp)
739 get_array(fin, cp->p, 3);
740 get_index(fin, &cp->n);
743 static void sol_load_goal(FILE *fin, struct s_goal *zp)
745 get_array(fin, zp->p, 3);
746 get_float(fin, &zp->r);
747 get_index(fin, &zp->s);
748 get_index(fin, &zp->c);
751 static void sol_load_swch(FILE *fin, struct s_swch *xp)
753 get_array(fin, xp->p, 3);
754 get_float(fin, &xp->r);
755 get_index(fin, &xp->pi);
756 get_float(fin, &xp->t0);
757 get_float(fin, &xp->t);
758 get_index(fin, &xp->f0);
759 get_index(fin, &xp->f);
760 get_index(fin, &xp->i);
763 static void sol_load_bill(FILE *fin, struct s_bill *rp)
765 get_index(fin, &rp->fl);
766 get_index(fin, &rp->mi);
767 get_float(fin, &rp->t);
768 get_float(fin, &rp->d);
769 get_array(fin, rp->w, 3);
770 get_array(fin, rp->h, 3);
771 get_array(fin, rp->rx, 3);
772 get_array(fin, rp->ry, 3);
773 get_array(fin, rp->rz, 3);
776 static void sol_load_jump(FILE *fin, struct s_jump *jp)
778 get_array(fin, jp->p, 3);
779 get_array(fin, jp->q, 3);
780 get_float(fin, &jp->r);
783 static void sol_load_ball(FILE *fin, struct s_ball *bp)
785 get_array(fin, bp->e[0], 3);
786 get_array(fin, bp->e[1], 3);
787 get_array(fin, bp->e[2], 3);
788 get_array(fin, bp->p, 3);
789 get_float(fin, &bp->r);
792 static void sol_load_view(FILE *fin, struct s_view *wp)
794 get_array(fin, wp->p, 3);
795 get_array(fin, wp->q, 3);
798 static int sol_load_file(FILE *fin, struct s_file *fp)
804 get_index(fin, &magic);
805 get_index(fin, &version);
806 if (magic != MAGIC || version != SOL_VERSION)
809 get_index(fin, &fp->mc);
810 get_index(fin, &fp->vc);
811 get_index(fin, &fp->ec);
812 get_index(fin, &fp->sc);
813 get_index(fin, &fp->tc);
814 get_index(fin, &fp->gc);
815 get_index(fin, &fp->lc);
816 get_index(fin, &fp->nc);
817 get_index(fin, &fp->pc);
818 get_index(fin, &fp->bc);
819 get_index(fin, &fp->cc);
820 get_index(fin, &fp->zc);
821 get_index(fin, &fp->jc);
822 get_index(fin, &fp->xc);
823 get_index(fin, &fp->rc);
824 get_index(fin, &fp->uc);
825 get_index(fin, &fp->wc);
826 get_index(fin, &fp->ic);
827 get_index(fin, &fp->ac);
830 fp->mv = (struct s_mtrl *) calloc(fp->mc, sizeof (struct s_mtrl));
832 fp->vv = (struct s_vert *) calloc(fp->vc, sizeof (struct s_vert));
834 fp->ev = (struct s_edge *) calloc(fp->ec, sizeof (struct s_edge));
836 fp->sv = (struct s_side *) calloc(fp->sc, sizeof (struct s_side));
838 fp->tv = (struct s_texc *) calloc(fp->tc, sizeof (struct s_texc));
840 fp->gv = (struct s_geom *) calloc(fp->gc, sizeof (struct s_geom));
842 fp->lv = (struct s_lump *) calloc(fp->lc, sizeof (struct s_lump));
844 fp->nv = (struct s_node *) calloc(fp->nc, sizeof (struct s_node));
846 fp->pv = (struct s_path *) calloc(fp->pc, sizeof (struct s_path));
848 fp->bv = (struct s_body *) calloc(fp->bc, sizeof (struct s_body));
850 fp->cv = (struct s_coin *) calloc(fp->cc, sizeof (struct s_coin));
852 fp->zv = (struct s_goal *) calloc(fp->zc, sizeof (struct s_goal));
854 fp->jv = (struct s_jump *) calloc(fp->jc, sizeof (struct s_jump));
856 fp->xv = (struct s_swch *) calloc(fp->xc, sizeof (struct s_swch));
858 fp->rv = (struct s_bill *) calloc(fp->rc, sizeof (struct s_bill));
860 fp->uv = (struct s_ball *) calloc(fp->uc, sizeof (struct s_ball));
862 fp->wv = (struct s_view *) calloc(fp->wc, sizeof (struct s_view));
864 fp->iv = (int *) calloc(fp->ic, sizeof (int));
866 fp->av = (char *) calloc(fp->ac, sizeof (char));
868 for (i = 0; i < fp->mc; i++) sol_load_mtrl(fin, fp->mv + i);
869 for (i = 0; i < fp->vc; i++) sol_load_vert(fin, fp->vv + i);
870 for (i = 0; i < fp->ec; i++) sol_load_edge(fin, fp->ev + i);
871 for (i = 0; i < fp->sc; i++) sol_load_side(fin, fp->sv + i);
872 for (i = 0; i < fp->tc; i++) sol_load_texc(fin, fp->tv + i);
873 for (i = 0; i < fp->gc; i++) sol_load_geom(fin, fp->gv + i);
874 for (i = 0; i < fp->lc; i++) sol_load_lump(fin, fp->lv + i);
875 for (i = 0; i < fp->nc; i++) sol_load_node(fin, fp->nv + i);
876 for (i = 0; i < fp->pc; i++) sol_load_path(fin, fp->pv + i);
877 for (i = 0; i < fp->bc; i++) sol_load_body(fin, fp->bv + i);
878 for (i = 0; i < fp->cc; i++) sol_load_coin(fin, fp->cv + i);
879 for (i = 0; i < fp->zc; i++) sol_load_goal(fin, fp->zv + i);
880 for (i = 0; i < fp->jc; i++) sol_load_jump(fin, fp->jv + i);
881 for (i = 0; i < fp->xc; i++) sol_load_swch(fin, fp->xv + i);
882 for (i = 0; i < fp->rc; i++) sol_load_bill(fin, fp->rv + i);
883 for (i = 0; i < fp->uc; i++) sol_load_ball(fin, fp->uv + i);
884 for (i = 0; i < fp->wc; i++) sol_load_view(fin, fp->wv + i);
885 for (i = 0; i < fp->ic; i++) get_index(fin, fp->iv + i);
887 if (fp->ac) fread(fp->av, 1, fp->ac, fin);
892 int sol_load_only_file(struct s_file *fp, const char *filename)
897 if ((fin = fopen(filename, FMODE_RB)))
899 res = sol_load_file(fin, fp);
905 int sol_load(struct s_file *fp, const char *filename, int k, int s)
910 if ((fin = fopen(filename, FMODE_RB)))
912 if (sol_load_file(fin, fp))
915 sol_load_textures(fp, k);
916 sol_load_objects (fp, s);
924 /*---------------------------------------------------------------------------*/
926 static void sol_stor_mtrl(FILE *fout, struct s_mtrl *mp)
928 put_array(fout, mp->a, 4);
929 put_array(fout, mp->d, 4);
930 put_array(fout, mp->s, 4);
931 put_array(fout, mp->e, 4);
932 put_array(fout, mp->h, 1);
933 put_index(fout, &mp->fl);
935 fwrite(mp->f, 1, PATHMAX, fout);
938 static void sol_stor_vert(FILE *fout, struct s_vert *vp)
940 put_array(fout, vp->p, 3);
943 static void sol_stor_edge(FILE *fout, struct s_edge *ep)
945 put_index(fout, &ep->vi);
946 put_index(fout, &ep->vj);
949 static void sol_stor_side(FILE *fout, struct s_side *sp)
951 put_array(fout, sp->n, 3);
952 put_float(fout, &sp->d);
955 static void sol_stor_texc(FILE *fout, struct s_texc *tp)
957 put_array(fout, tp->u, 2);
960 static void sol_stor_geom(FILE *fout, struct s_geom *gp)
962 put_index(fout, &gp->mi);
963 put_index(fout, &gp->ti);
964 put_index(fout, &gp->si);
965 put_index(fout, &gp->vi);
966 put_index(fout, &gp->tj);
967 put_index(fout, &gp->sj);
968 put_index(fout, &gp->vj);
969 put_index(fout, &gp->tk);
970 put_index(fout, &gp->sk);
971 put_index(fout, &gp->vk);
974 static void sol_stor_lump(FILE *fout, struct s_lump *lp)
976 put_index(fout, &lp->fl);
977 put_index(fout, &lp->v0);
978 put_index(fout, &lp->vc);
979 put_index(fout, &lp->e0);
980 put_index(fout, &lp->ec);
981 put_index(fout, &lp->g0);
982 put_index(fout, &lp->gc);
983 put_index(fout, &lp->s0);
984 put_index(fout, &lp->sc);
987 static void sol_stor_node(FILE *fout, struct s_node *np)
989 put_index(fout, &np->si);
990 put_index(fout, &np->ni);
991 put_index(fout, &np->nj);
992 put_index(fout, &np->l0);
993 put_index(fout, &np->lc);
996 static void sol_stor_path(FILE *fout, struct s_path *pp)
998 put_array(fout, pp->p, 3);
999 put_float(fout, &pp->t);
1000 put_index(fout, &pp->pi);
1001 put_index(fout, &pp->f);
1004 static void sol_stor_body(FILE *fout, struct s_body *bp)
1006 put_index(fout, &bp->pi);
1007 put_index(fout, &bp->ni);
1008 put_index(fout, &bp->l0);
1009 put_index(fout, &bp->lc);
1010 put_index(fout, &bp->g0);
1011 put_index(fout, &bp->gc);
1014 static void sol_stor_coin(FILE *fout, struct s_coin *cp)
1016 put_array(fout, cp->p, 3);
1017 put_index(fout, &cp->n);
1020 static void sol_stor_goal(FILE *fout, struct s_goal *zp)
1022 put_array(fout, zp->p, 3);
1023 put_float(fout, &zp->r);
1024 put_index(fout, &zp->s);
1025 put_index(fout, &zp->c);
1028 static void sol_stor_swch(FILE *fout, struct s_swch *xp)
1030 put_array(fout, xp->p, 3);
1031 put_float(fout, &xp->r);
1032 put_index(fout, &xp->pi);
1033 put_float(fout, &xp->t0);
1034 put_float(fout, &xp->t);
1035 put_index(fout, &xp->f0);
1036 put_index(fout, &xp->f);
1037 put_index(fout, &xp->i);
1040 static void sol_stor_bill(FILE *fout, struct s_bill *rp)
1042 put_index(fout, &rp->fl);
1043 put_index(fout, &rp->mi);
1044 put_float(fout, &rp->t);
1045 put_float(fout, &rp->d);
1046 put_array(fout, rp->w, 3);
1047 put_array(fout, rp->h, 3);
1048 put_array(fout, rp->rx, 3);
1049 put_array(fout, rp->ry, 3);
1050 put_array(fout, rp->rz, 3);
1053 static void sol_stor_jump(FILE *fout, struct s_jump *jp)
1055 put_array(fout, jp->p, 3);
1056 put_array(fout, jp->q, 3);
1057 put_float(fout, &jp->r);
1060 static void sol_stor_ball(FILE *fout, struct s_ball *bp)
1062 put_array(fout, bp->e[0], 3);
1063 put_array(fout, bp->e[1], 3);
1064 put_array(fout, bp->e[2], 3);
1065 put_array(fout, bp->p, 3);
1066 put_float(fout, &bp->r);
1069 static void sol_stor_view(FILE *fout, struct s_view *wp)
1071 put_array(fout, wp->p, 3);
1072 put_array(fout, wp->q, 3);
1075 static void sol_stor_file(FILE *fin, struct s_file *fp)
1079 int version = SOL_VERSION;
1081 put_index(fin, &magic);
1082 put_index(fin, &version);
1084 put_index(fin, &fp->mc);
1085 put_index(fin, &fp->vc);
1086 put_index(fin, &fp->ec);
1087 put_index(fin, &fp->sc);
1088 put_index(fin, &fp->tc);
1089 put_index(fin, &fp->gc);
1090 put_index(fin, &fp->lc);
1091 put_index(fin, &fp->nc);
1092 put_index(fin, &fp->pc);
1093 put_index(fin, &fp->bc);
1094 put_index(fin, &fp->cc);
1095 put_index(fin, &fp->zc);
1096 put_index(fin, &fp->jc);
1097 put_index(fin, &fp->xc);
1098 put_index(fin, &fp->rc);
1099 put_index(fin, &fp->uc);
1100 put_index(fin, &fp->wc);
1101 put_index(fin, &fp->ic);
1102 put_index(fin, &fp->ac);
1104 for (i = 0; i < fp->mc; i++) sol_stor_mtrl(fin, fp->mv + i);
1105 for (i = 0; i < fp->vc; i++) sol_stor_vert(fin, fp->vv + i);
1106 for (i = 0; i < fp->ec; i++) sol_stor_edge(fin, fp->ev + i);
1107 for (i = 0; i < fp->sc; i++) sol_stor_side(fin, fp->sv + i);
1108 for (i = 0; i < fp->tc; i++) sol_stor_texc(fin, fp->tv + i);
1109 for (i = 0; i < fp->gc; i++) sol_stor_geom(fin, fp->gv + i);
1110 for (i = 0; i < fp->lc; i++) sol_stor_lump(fin, fp->lv + i);
1111 for (i = 0; i < fp->nc; i++) sol_stor_node(fin, fp->nv + i);
1112 for (i = 0; i < fp->pc; i++) sol_stor_path(fin, fp->pv + i);
1113 for (i = 0; i < fp->bc; i++) sol_stor_body(fin, fp->bv + i);
1114 for (i = 0; i < fp->cc; i++) sol_stor_coin(fin, fp->cv + i);
1115 for (i = 0; i < fp->zc; i++) sol_stor_goal(fin, fp->zv + i);
1116 for (i = 0; i < fp->jc; i++) sol_stor_jump(fin, fp->jv + i);
1117 for (i = 0; i < fp->xc; i++) sol_stor_swch(fin, fp->xv + i);
1118 for (i = 0; i < fp->rc; i++) sol_stor_bill(fin, fp->rv + i);
1119 for (i = 0; i < fp->uc; i++) sol_stor_ball(fin, fp->uv + i);
1120 for (i = 0; i < fp->wc; i++) sol_stor_view(fin, fp->wv + i);
1121 for (i = 0; i < fp->ic; i++) put_index(fin, fp->iv + i);
1123 fwrite(fp->av, 1, fp->ac, fin);
1126 /*---------------------------------------------------------------------------*/
1128 int sol_stor(struct s_file *fp, const char *filename)
1132 if ((fout = fopen(filename, FMODE_WB)))
1134 sol_stor_file(fout, fp);
1142 void sol_free(struct s_file *fp)
1146 for (i = 0; i < fp->mc; i++)
1148 if (glIsTexture(fp->mv[i].o))
1149 glDeleteTextures(1, &fp->mv[i].o);
1152 for (i = 0; i < fp->bc; i++)
1154 if (glIsList(fp->bv[i].ol))
1155 glDeleteLists(fp->bv[i].ol, 1);
1156 if (glIsList(fp->bv[i].tl))
1157 glDeleteLists(fp->bv[i].tl, 1);
1158 if (glIsList(fp->bv[i].rl))
1159 glDeleteLists(fp->bv[i].rl, 1);
1162 if (fp->mv) free(fp->mv);
1163 if (fp->vv) free(fp->vv);
1164 if (fp->ev) free(fp->ev);
1165 if (fp->sv) free(fp->sv);
1166 if (fp->tv) free(fp->tv);
1167 if (fp->gv) free(fp->gv);
1168 if (fp->lv) free(fp->lv);
1169 if (fp->nv) free(fp->nv);
1170 if (fp->pv) free(fp->pv);
1171 if (fp->bv) free(fp->bv);
1172 if (fp->cv) free(fp->cv);
1173 if (fp->zv) free(fp->zv);
1174 if (fp->jv) free(fp->jv);
1175 if (fp->xv) free(fp->xv);
1176 if (fp->rv) free(fp->rv);
1177 if (fp->uv) free(fp->uv);
1178 if (fp->wv) free(fp->wv);
1179 if (fp->av) free(fp->av);
1180 if (fp->iv) free(fp->iv);
1182 memset(fp, 0, sizeof (struct s_file));
1185 /*---------------------------------------------------------------------------*/
1186 /* Solves (p + v * t) . (p + v * t) == r * r for smallest t. */
1188 static float v_sol(const float p[3], const float v[3], float r)
1190 float a = v_dot(v, v);
1191 float b = v_dot(v, p) * 2.0f;
1192 float c = v_dot(p, p) - r * r;
1193 float d = b * b - 4.0f * a * c;
1195 if (a == 0.0f) return LARGE;
1196 if (d < 0.0f) return LARGE;
1199 return -b * 0.5f / a;
1202 float t0 = 0.5f * (-b - fsqrtf(d)) / a;
1203 float t1 = 0.5f * (-b + fsqrtf(d)) / a;
1204 float t = (t0 < t1) ? t0 : t1;
1206 return (t < 0.0f) ? LARGE : t;
1210 /*---------------------------------------------------------------------------*/
1213 * Compute the earliest time and position of the intersection of a
1214 * sphere and a vertex.
1216 * The sphere has radius R and moves along vector V from point P. The
1217 * vertex moves along vector W from point Q in a coordinate system
1220 static float v_vert(float Q[3],
1225 const float v[3], float r)
1227 float O[3], P[3], V[3];
1234 if (v_dot(P, V) < 0.0f)
1245 * Compute the earliest time and position of the intersection of a
1246 * sphere and an edge.
1248 * The sphere has radius R and moves along vector V from point P. The
1249 * edge moves along vector W from point Q in a coordinate system based
1250 * at O. The edge extends along the length of vector U.
1252 static float v_edge(float Q[3],
1258 const float v[3], float r)
1262 float du, eu, uu, s, t;
1272 v_mad(P, d, u, -du / uu);
1273 v_mad(V, e, u, -eu / uu);
1276 s = (du + eu * t) / uu;
1278 if (0.0f < t && t < LARGE && 0.0f < s && s < 1.0f)
1291 * Compute the earlist time and position of the intersection of a
1292 * sphere and a plane.
1294 * The sphere has radius R and moves along vector V from point P. The
1295 * plane oves along vector W. The plane has normal N and is
1296 * positioned at distance D from the origin O along that normal.
1298 static float v_side(float Q[3],
1301 const float n[3], float d,
1303 const float v[3], float r)
1305 float vn = v_dot(v, n);
1306 float wn = v_dot(w, n);
1309 if (vn - wn <= 0.0f)
1311 float on = v_dot(o, n);
1312 float pn = v_dot(p, n);
1314 float u = (r + d + on - pn) / (vn - wn);
1315 float a = ( d + on - pn) / (vn - wn);
1335 /*---------------------------------------------------------------------------*/
1338 * Compute the new linear and angular velocities of a bouncing ball.
1339 * Q gives the position of the point of impact and W gives the
1340 * velocity of the object being impacted.
1342 static float sol_bounce(struct s_ball *up,
1344 const float w[3], float dt)
1346 const float kb = 1.10f;
1347 const float ke = 0.70f;
1348 const float km = 0.20f;
1350 float n[3], r[3], d[3], u[3], vn, wn, xn, yn;
1354 /* Find the normal of the impact. */
1360 /* Find the new angular velocity. */
1363 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
1365 /* Find the new linear velocity. */
1369 xn = (vn < 0.0f) ? -vn * ke : vn;
1370 yn = (wn > 0.0f) ? wn * kb : wn;
1372 v_mad(u, w, n, -wn);
1373 v_mad(v, v, n, -vn);
1374 v_mad(v, v, u, +km * dt);
1375 v_mad(v, v, n, xn + yn);
1377 v_mad(p, q, n, up->r);
1379 /* Return the "energy" of the impact, to determine the sound amplitude. */
1381 return fabsf(v_dot(n, d));
1384 /*---------------------------------------------------------------------------*/
1387 * Compute the states of all switches after DT seconds have passed.
1389 static void sol_swch_step(struct s_file *fp, float dt)
1393 for (xi = 0; xi < fp->xc; xi++)
1395 struct s_swch *xp = fp->xv + xi;
1406 do /* Tortoise and hare cycle traverser. */
1408 fp->pv[pi].f = xp->f0;
1409 fp->pv[pj].f = xp->f0;
1424 * Compute the positions of all bodies after DT seconds have passed.
1426 static void sol_body_step(struct s_file *fp, float dt)
1430 for (i = 0; i < fp->bc; i++)
1432 struct s_body *bp = fp->bv + i;
1433 struct s_path *pp = fp->pv + bp->pi;
1435 if (bp->pi >= 0 && pp->f)
1449 * Compute the positions of all balls after DT seconds have passed.
1451 static void sol_ball_step(struct s_file *fp, float dt)
1455 for (i = 0; i < fp->uc; i++)
1457 struct s_ball *up = fp->uv + i;
1459 v_mad(up->p, up->p, up->v, dt);
1461 if (v_len(up->w) > 0.0f)
1468 m_rot(M, w, v_len(up->w) * dt);
1470 m_vxfm(e[0], M, up->e[0]);
1471 m_vxfm(e[1], M, up->e[1]);
1472 m_vxfm(e[2], M, up->e[2]);
1474 v_crs(up->e[2], e[0], e[1]);
1475 v_crs(up->e[1], e[2], e[0]);
1476 v_crs(up->e[0], e[1], e[2]);
1478 v_nrm(up->e[0], up->e[0]);
1479 v_nrm(up->e[1], up->e[1]);
1480 v_nrm(up->e[2], up->e[2]);
1485 /*---------------------------------------------------------------------------*/
1487 static float sol_test_vert(float dt,
1489 const struct s_ball *up,
1490 const struct s_vert *vp,
1494 return v_vert(T, o, vp->p, w, up->p, up->v, up->r);
1497 static float sol_test_edge(float dt,
1499 const struct s_ball *up,
1500 const struct s_file *fp,
1501 const struct s_edge *ep,
1508 v_cpy(q, fp->vv[ep->vi].p);
1509 v_sub(u, fp->vv[ep->vj].p,
1512 return v_edge(T, o, q, u, w, up->p, up->v, up->r);
1515 static float sol_test_side(float dt,
1517 const struct s_ball *up,
1518 const struct s_file *fp,
1519 const struct s_lump *lp,
1520 const struct s_side *sp,
1524 float t = v_side(T, o, w, sp->n, sp->d, up->p, up->v, up->r);
1528 for (i = 0; i < lp->sc; i++)
1530 const struct s_side *sq = fp->sv + fp->iv[lp->s0 + i];
1535 v_dot(w, sq->n) * t > sq->d)
1541 /*---------------------------------------------------------------------------*/
1543 static float sol_test_fore(float dt,
1544 const struct s_ball *up,
1545 const struct s_side *sp,
1551 /* If the ball is not behind the plane, the test passes. */
1555 if (v_dot(q, sp->n) - sp->d + up->r >= 0)
1558 /* if the ball is behind the plane but will hit before dt, test passes. */
1560 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1563 /* If the ball is behind but moving toward the plane, test passes. */
1565 if (v_dot(up->v, sp->n) > 0)
1569 /* Else, test fails. */
1574 static float sol_test_back(float dt,
1575 const struct s_ball *up,
1576 const struct s_side *sp,
1582 /* If the ball is not in front of the plane, the test passes. */
1586 if (v_dot(q, sp->n) - sp->d - up->r <= 0)
1589 /* if the ball is behind the plane but will hit before dt, test passes. */
1591 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1594 /* If the ball is in front but moving toward the plane, test passes. */
1596 if (v_dot(up->v, sp->n) < 0)
1600 /* Else, test fails. */
1605 /*---------------------------------------------------------------------------*/
1607 static float sol_test_lump(float dt,
1609 const struct s_ball *up,
1610 const struct s_file *fp,
1611 const struct s_lump *lp,
1615 float U[3], u, t = dt;
1618 /* Short circuit a non-solid lump. */
1620 if (lp->fl & L_DETAIL) return t;
1622 /* Test all verts */
1625 for (i = 0; i < lp->vc; i++)
1627 const struct s_vert *vp = fp->vv + fp->iv[lp->v0 + i];
1629 if ((u = sol_test_vert(t, U, up, vp, o, w)) < t)
1636 /* Test all edges */
1639 for (i = 0; i < lp->ec; i++)
1641 const struct s_edge *ep = fp->ev + fp->iv[lp->e0 + i];
1643 if ((u = sol_test_edge(t, U, up, fp, ep, o, w)) < t)
1650 /* Test all sides */
1652 for (i = 0; i < lp->sc; i++)
1654 const struct s_side *sp = fp->sv + fp->iv[lp->s0 + i];
1656 if ((u = sol_test_side(t, U, up, fp, lp, sp, o, w)) < t)
1665 static float sol_test_node(float dt,
1667 const struct s_ball *up,
1668 const struct s_file *fp,
1669 const struct s_node *np,
1673 float U[3], u, t = dt;
1676 /* Test all lumps */
1678 for (i = 0; i < np->lc; i++)
1680 const struct s_lump *lp = fp->lv + np->l0 + i;
1682 if ((u = sol_test_lump(t, U, up, fp, lp, o, w)) < t)
1689 /* Test in front of this node */
1691 if (np->ni >= 0 && sol_test_fore(t, up, fp->sv + np->si, o, w))
1693 const struct s_node *nq = fp->nv + np->ni;
1695 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1702 /* Test behind this node */
1704 if (np->nj >= 0 && sol_test_back(t, up, fp->sv + np->si, o, w))
1706 const struct s_node *nq = fp->nv + np->nj;
1708 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1718 static float sol_test_body(float dt,
1719 float T[3], float V[3],
1720 const struct s_ball *up,
1721 const struct s_file *fp,
1722 const struct s_body *bp)
1724 float U[3], O[3], W[3], u, t = dt;
1726 const struct s_node *np = fp->nv + bp->ni;
1728 sol_body_p(O, fp, bp);
1729 sol_body_v(W, fp, bp);
1731 if ((u = sol_test_node(t, U, up, fp, np, O, W)) < t)
1740 static float sol_test_file(float dt,
1741 float T[3], float V[3],
1742 const struct s_ball *up,
1743 const struct s_file *fp)
1745 float U[3], W[3], u, t = dt;
1748 for (i = 0; i < fp->bc; i++)
1750 const struct s_body *bp = fp->bv + i;
1752 if ((u = sol_test_body(t, U, W, up, fp, bp)) < t)
1762 /*---------------------------------------------------------------------------*/
1765 * Step the physics forward DT seconds under the influence of gravity
1766 * vector G. If the ball gets pinched between two moving solids, this
1767 * loop might not terminate. It is better to do something physically
1768 * impossible than to lock up the game. So, if we make more than C
1769 * iterations, punt it.
1772 float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
1774 float P[3], V[3], v[3], r[3], d, e, nt, b = 0.0f, tt = dt;
1779 struct s_ball *up = fp->uv + ui;
1781 /* If the ball is in contact with a surface, apply friction. */
1786 if (m && sol_test_file(tt, P, V, up, fp) < 0.0005f)
1791 if ((d = v_dot(r, g) / (v_len(r) * v_len(g))) > 0.999f)
1793 if ((e = (v_len(up->v) - dt)) > 0.0f)
1795 /* Scale the linear velocity. */
1797 v_nrm(up->v, up->v);
1798 v_scl(up->v, up->v, e);
1800 /* Scale the angular velocity. */
1804 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
1808 /* Friction has brought the ball to a stop. */
1817 else v_mad(up->v, v, g, tt);
1819 else v_mad(up->v, v, g, tt);
1821 /* Test for collision. */
1823 while (c > 0 && tt > 0 && tt > (nt = sol_test_file(tt, P, V, up, fp)))
1825 sol_body_step(fp, nt);
1826 sol_swch_step(fp, nt);
1827 sol_ball_step(fp, nt);
1831 if (b < (d = sol_bounce(up, P, V, nt)))
1837 sol_body_step(fp, tt);
1838 sol_swch_step(fp, tt);
1839 sol_ball_step(fp, tt);
1844 /*---------------------------------------------------------------------------*/
1846 int sol_coin_test(struct s_file *fp, float *p, float coin_r)
1848 const float *ball_p = fp->uv->p;
1849 const float ball_r = fp->uv->r;
1852 for (ci = 0; ci < fp->cc; ci++)
1856 r[0] = ball_p[0] - fp->cv[ci].p[0];
1857 r[1] = ball_p[1] - fp->cv[ci].p[1];
1858 r[2] = ball_p[2] - fp->cv[ci].p[2];
1860 if (fp->cv[ci].n > 0 && v_len(r) < ball_r + coin_r)
1862 p[0] = fp->cv[ci].p[0];
1863 p[1] = fp->cv[ci].p[1];
1864 p[2] = fp->cv[ci].p[2];
1875 int sol_goal_test(struct s_file *fp, float *p, int ui)
1877 const float *ball_p = fp->uv[ui].p;
1878 const float ball_r = fp->uv[ui].r;
1881 for (zi = 0; zi < fp->zc; zi++)
1885 r[0] = ball_p[0] - fp->zv[zi].p[0];
1886 r[1] = ball_p[2] - fp->zv[zi].p[2];
1889 if (v_len(r) < fp->zv[zi].r * 1.1 - ball_r &&
1890 ball_p[1] > fp->zv[zi].p[1] &&
1891 ball_p[1] < fp->zv[zi].p[1] + GOAL_HEIGHT / 2)
1893 p[0] = fp->zv[zi].p[0];
1894 p[1] = fp->zv[zi].p[1];
1895 p[2] = fp->zv[zi].p[2];
1897 return 1 + fp->zv[zi].s;
1903 int sol_jump_test(struct s_file *fp, float *p, int ui)
1904 /* Test if the ball ui in inside a jump */
1905 /* Return 1 if yes and fill p with the destination position */
1906 /* Return 0 if no */
1907 /* Return 2 if the ball is on the border of a jump */
1909 const float *ball_p = fp->uv[ui].p;
1910 const float ball_r = fp->uv[ui].r;
1915 for (ji = 0; ji < fp->jc; ji++)
1919 r[0] = ball_p[0] - fp->jv[ji].p[0];
1920 r[1] = ball_p[2] - fp->jv[ji].p[2];
1923 l = v_len(r) - fp->jv[ji].r;
1925 ball_p[1] > fp->jv[ji].p[1] &&
1926 ball_p[1] < fp->jv[ji].p[1] + JUMP_HEIGHT / 2)
1930 p[0] = fp->jv[ji].q[0] + (ball_p[0] - fp->jv[ji].p[0]);
1931 p[1] = fp->jv[ji].q[1] + (ball_p[1] - fp->jv[ji].p[1]);
1932 p[2] = fp->jv[ji].q[2] + (ball_p[2] - fp->jv[ji].p[2]);
1943 int sol_swch_test(struct s_file *fp, int ui)
1944 /* In the sol fp, test and process the event the ball ui enters a switch
1945 * return 1 if a visibla switch is activated
1946 * return 0 else (no switch is activated or only invisible switchs) */
1948 const float *ball_p = fp->uv[ui].p;
1949 const float ball_r = fp->uv[ui].r;
1952 int res = 0; /* result */
1954 for (xi = 0; xi < fp->xc; xi++)
1956 struct s_swch *xp = fp->xv + xi;
1958 if (xp->t0 == 0 || xp->f == xp->f0)
1962 r[0] = ball_p[0] - xp->p[0];
1963 r[1] = ball_p[2] - xp->p[2];
1966 l = v_len(r) - xp->r;
1968 ball_p[1] > xp->p[1] &&
1969 ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
1971 if (!xp->e && l < - ball_r)
1976 /* The ball enter */
1980 /* Toggle the state, update the path. */
1982 xp->f = xp->f ? 0 : 1;
1984 do /* Tortoise and hare cycle traverser. */
1986 fp->pv[pi].f = xp->f;
1987 fp->pv[pj].f = xp->f;
1995 /* It toggled to non-default state, start the timer. */
1997 if (xp->f != xp->f0)
2000 /* If visible, set the result */
2013 /*---------------------------------------------------------------------------*/
2015 void put_file_state(FILE *fout, struct s_file *fp)
2017 /* Write the position and orientation of the ball. */
2019 put_array(fout, fp->uv[0].p, 3);
2020 put_array(fout, fp->uv[0].e[0], 3);
2021 put_array(fout, fp->uv[0].e[1], 3);
2024 void get_file_state(FILE *fin, struct s_file *fp)
2026 /* Read the position and orientation of the ball. */
2028 get_array(fin, fp->uv[0].p, 3);
2029 get_array(fin, fp->uv[0].e[0], 3);
2030 get_array(fin, fp->uv[0].e[1], 3);
2032 /* Compute the 3rd vector of the ball orientatian basis. */
2034 v_crs(fp->uv[0].e[2], fp->uv[0].e[0], fp->uv[0].e[1]);
2037 /*---------------------------------------------------------------------------*/