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 1 /* 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);
749 static void sol_load_swch(FILE *fin, struct s_swch *xp)
751 get_array(fin, xp->p, 3);
752 get_float(fin, &xp->r);
753 get_index(fin, &xp->pi);
754 get_float(fin, &xp->t0);
755 get_float(fin, &xp->t);
756 get_index(fin, &xp->f0);
757 get_index(fin, &xp->f);
760 static void sol_load_bill(FILE *fin, struct s_bill *rp)
762 get_index(fin, &rp->fl);
763 get_index(fin, &rp->mi);
764 get_float(fin, &rp->t);
765 get_float(fin, &rp->d);
766 get_array(fin, rp->w, 3);
767 get_array(fin, rp->h, 3);
768 get_array(fin, rp->rx, 3);
769 get_array(fin, rp->ry, 3);
770 get_array(fin, rp->rz, 3);
773 static void sol_load_jump(FILE *fin, struct s_jump *jp)
775 get_array(fin, jp->p, 3);
776 get_array(fin, jp->q, 3);
777 get_float(fin, &jp->r);
780 static void sol_load_ball(FILE *fin, struct s_ball *bp)
782 get_array(fin, bp->e[0], 3);
783 get_array(fin, bp->e[1], 3);
784 get_array(fin, bp->e[2], 3);
785 get_array(fin, bp->p, 3);
786 get_float(fin, &bp->r);
789 static void sol_load_view(FILE *fin, struct s_view *wp)
791 get_array(fin, wp->p, 3);
792 get_array(fin, wp->q, 3);
795 static int sol_load_file(FILE *fin, struct s_file *fp)
801 get_index(fin, &magic);
802 get_index(fin, &version);
803 if (magic != MAGIC || version != SOL_VERSION)
806 get_index(fin, &fp->mc);
807 get_index(fin, &fp->vc);
808 get_index(fin, &fp->ec);
809 get_index(fin, &fp->sc);
810 get_index(fin, &fp->tc);
811 get_index(fin, &fp->gc);
812 get_index(fin, &fp->lc);
813 get_index(fin, &fp->nc);
814 get_index(fin, &fp->pc);
815 get_index(fin, &fp->bc);
816 get_index(fin, &fp->cc);
817 get_index(fin, &fp->zc);
818 get_index(fin, &fp->jc);
819 get_index(fin, &fp->xc);
820 get_index(fin, &fp->rc);
821 get_index(fin, &fp->uc);
822 get_index(fin, &fp->wc);
823 get_index(fin, &fp->ic);
824 get_index(fin, &fp->ac);
827 fp->mv = (struct s_mtrl *) calloc(fp->mc, sizeof (struct s_mtrl));
829 fp->vv = (struct s_vert *) calloc(fp->vc, sizeof (struct s_vert));
831 fp->ev = (struct s_edge *) calloc(fp->ec, sizeof (struct s_edge));
833 fp->sv = (struct s_side *) calloc(fp->sc, sizeof (struct s_side));
835 fp->tv = (struct s_texc *) calloc(fp->tc, sizeof (struct s_texc));
837 fp->gv = (struct s_geom *) calloc(fp->gc, sizeof (struct s_geom));
839 fp->lv = (struct s_lump *) calloc(fp->lc, sizeof (struct s_lump));
841 fp->nv = (struct s_node *) calloc(fp->nc, sizeof (struct s_node));
843 fp->pv = (struct s_path *) calloc(fp->pc, sizeof (struct s_path));
845 fp->bv = (struct s_body *) calloc(fp->bc, sizeof (struct s_body));
847 fp->cv = (struct s_coin *) calloc(fp->cc, sizeof (struct s_coin));
849 fp->zv = (struct s_goal *) calloc(fp->zc, sizeof (struct s_goal));
851 fp->jv = (struct s_jump *) calloc(fp->jc, sizeof (struct s_jump));
853 fp->xv = (struct s_swch *) calloc(fp->xc, sizeof (struct s_swch));
855 fp->rv = (struct s_bill *) calloc(fp->rc, sizeof (struct s_bill));
857 fp->uv = (struct s_ball *) calloc(fp->uc, sizeof (struct s_ball));
859 fp->wv = (struct s_view *) calloc(fp->wc, sizeof (struct s_view));
861 fp->iv = (int *) calloc(fp->ic, sizeof (int));
863 fp->av = (char *) calloc(fp->ac, sizeof (char));
865 for (i = 0; i < fp->mc; i++) sol_load_mtrl(fin, fp->mv + i);
866 for (i = 0; i < fp->vc; i++) sol_load_vert(fin, fp->vv + i);
867 for (i = 0; i < fp->ec; i++) sol_load_edge(fin, fp->ev + i);
868 for (i = 0; i < fp->sc; i++) sol_load_side(fin, fp->sv + i);
869 for (i = 0; i < fp->tc; i++) sol_load_texc(fin, fp->tv + i);
870 for (i = 0; i < fp->gc; i++) sol_load_geom(fin, fp->gv + i);
871 for (i = 0; i < fp->lc; i++) sol_load_lump(fin, fp->lv + i);
872 for (i = 0; i < fp->nc; i++) sol_load_node(fin, fp->nv + i);
873 for (i = 0; i < fp->pc; i++) sol_load_path(fin, fp->pv + i);
874 for (i = 0; i < fp->bc; i++) sol_load_body(fin, fp->bv + i);
875 for (i = 0; i < fp->cc; i++) sol_load_coin(fin, fp->cv + i);
876 for (i = 0; i < fp->zc; i++) sol_load_goal(fin, fp->zv + i);
877 for (i = 0; i < fp->jc; i++) sol_load_jump(fin, fp->jv + i);
878 for (i = 0; i < fp->xc; i++) sol_load_swch(fin, fp->xv + i);
879 for (i = 0; i < fp->rc; i++) sol_load_bill(fin, fp->rv + i);
880 for (i = 0; i < fp->uc; i++) sol_load_ball(fin, fp->uv + i);
881 for (i = 0; i < fp->wc; i++) sol_load_view(fin, fp->wv + i);
882 for (i = 0; i < fp->ic; i++) get_index(fin, fp->iv + i);
884 if (fp->ac) fread(fp->av, 1, fp->ac, fin);
889 int sol_load_only_file(struct s_file *fp, const char *filename)
894 if ((fin = fopen(filename, FMODE_RB)))
896 res = sol_load_file(fin, fp);
902 int sol_load(struct s_file *fp, const char *filename, int k, int s)
907 if ((fin = fopen(filename, FMODE_RB)))
909 if (sol_load_file(fin, fp))
912 sol_load_textures(fp, k);
913 sol_load_objects (fp, s);
921 /*---------------------------------------------------------------------------*/
923 static void sol_stor_mtrl(FILE *fout, struct s_mtrl *mp)
925 put_array(fout, mp->a, 4);
926 put_array(fout, mp->d, 4);
927 put_array(fout, mp->s, 4);
928 put_array(fout, mp->e, 4);
929 put_array(fout, mp->h, 1);
930 put_index(fout, &mp->fl);
932 fwrite(mp->f, 1, PATHMAX, fout);
935 static void sol_stor_vert(FILE *fout, struct s_vert *vp)
937 put_array(fout, vp->p, 3);
940 static void sol_stor_edge(FILE *fout, struct s_edge *ep)
942 put_index(fout, &ep->vi);
943 put_index(fout, &ep->vj);
946 static void sol_stor_side(FILE *fout, struct s_side *sp)
948 put_array(fout, sp->n, 3);
949 put_float(fout, &sp->d);
952 static void sol_stor_texc(FILE *fout, struct s_texc *tp)
954 put_array(fout, tp->u, 2);
957 static void sol_stor_geom(FILE *fout, struct s_geom *gp)
959 put_index(fout, &gp->mi);
960 put_index(fout, &gp->ti);
961 put_index(fout, &gp->si);
962 put_index(fout, &gp->vi);
963 put_index(fout, &gp->tj);
964 put_index(fout, &gp->sj);
965 put_index(fout, &gp->vj);
966 put_index(fout, &gp->tk);
967 put_index(fout, &gp->sk);
968 put_index(fout, &gp->vk);
971 static void sol_stor_lump(FILE *fout, struct s_lump *lp)
973 put_index(fout, &lp->fl);
974 put_index(fout, &lp->v0);
975 put_index(fout, &lp->vc);
976 put_index(fout, &lp->e0);
977 put_index(fout, &lp->ec);
978 put_index(fout, &lp->g0);
979 put_index(fout, &lp->gc);
980 put_index(fout, &lp->s0);
981 put_index(fout, &lp->sc);
984 static void sol_stor_node(FILE *fout, struct s_node *np)
986 put_index(fout, &np->si);
987 put_index(fout, &np->ni);
988 put_index(fout, &np->nj);
989 put_index(fout, &np->l0);
990 put_index(fout, &np->lc);
993 static void sol_stor_path(FILE *fout, struct s_path *pp)
995 put_array(fout, pp->p, 3);
996 put_float(fout, &pp->t);
997 put_index(fout, &pp->pi);
998 put_index(fout, &pp->f);
1001 static void sol_stor_body(FILE *fout, struct s_body *bp)
1003 put_index(fout, &bp->pi);
1004 put_index(fout, &bp->ni);
1005 put_index(fout, &bp->l0);
1006 put_index(fout, &bp->lc);
1007 put_index(fout, &bp->g0);
1008 put_index(fout, &bp->gc);
1011 static void sol_stor_coin(FILE *fout, struct s_coin *cp)
1013 put_array(fout, cp->p, 3);
1014 put_index(fout, &cp->n);
1017 static void sol_stor_goal(FILE *fout, struct s_goal *zp)
1019 put_array(fout, zp->p, 3);
1020 put_float(fout, &zp->r);
1023 static void sol_stor_swch(FILE *fout, struct s_swch *xp)
1025 put_array(fout, xp->p, 3);
1026 put_float(fout, &xp->r);
1027 put_index(fout, &xp->pi);
1028 put_float(fout, &xp->t0);
1029 put_float(fout, &xp->t);
1030 put_index(fout, &xp->f0);
1031 put_index(fout, &xp->f);
1034 static void sol_stor_bill(FILE *fout, struct s_bill *rp)
1036 put_index(fout, &rp->fl);
1037 put_index(fout, &rp->mi);
1038 put_float(fout, &rp->t);
1039 put_float(fout, &rp->d);
1040 put_array(fout, rp->w, 3);
1041 put_array(fout, rp->h, 3);
1042 put_array(fout, rp->rx, 3);
1043 put_array(fout, rp->ry, 3);
1044 put_array(fout, rp->rz, 3);
1047 static void sol_stor_jump(FILE *fout, struct s_jump *jp)
1049 put_array(fout, jp->p, 3);
1050 put_array(fout, jp->q, 3);
1051 put_float(fout, &jp->r);
1054 static void sol_stor_ball(FILE *fout, struct s_ball *bp)
1056 put_array(fout, bp->e[0], 3);
1057 put_array(fout, bp->e[1], 3);
1058 put_array(fout, bp->e[2], 3);
1059 put_array(fout, bp->p, 3);
1060 put_float(fout, &bp->r);
1063 static void sol_stor_view(FILE *fout, struct s_view *wp)
1065 put_array(fout, wp->p, 3);
1066 put_array(fout, wp->q, 3);
1069 static void sol_stor_file(FILE *fin, struct s_file *fp)
1073 int version = SOL_VERSION;
1075 put_index(fin, &magic);
1076 put_index(fin, &version);
1078 put_index(fin, &fp->mc);
1079 put_index(fin, &fp->vc);
1080 put_index(fin, &fp->ec);
1081 put_index(fin, &fp->sc);
1082 put_index(fin, &fp->tc);
1083 put_index(fin, &fp->gc);
1084 put_index(fin, &fp->lc);
1085 put_index(fin, &fp->nc);
1086 put_index(fin, &fp->pc);
1087 put_index(fin, &fp->bc);
1088 put_index(fin, &fp->cc);
1089 put_index(fin, &fp->zc);
1090 put_index(fin, &fp->jc);
1091 put_index(fin, &fp->xc);
1092 put_index(fin, &fp->rc);
1093 put_index(fin, &fp->uc);
1094 put_index(fin, &fp->wc);
1095 put_index(fin, &fp->ic);
1096 put_index(fin, &fp->ac);
1098 for (i = 0; i < fp->mc; i++) sol_stor_mtrl(fin, fp->mv + i);
1099 for (i = 0; i < fp->vc; i++) sol_stor_vert(fin, fp->vv + i);
1100 for (i = 0; i < fp->ec; i++) sol_stor_edge(fin, fp->ev + i);
1101 for (i = 0; i < fp->sc; i++) sol_stor_side(fin, fp->sv + i);
1102 for (i = 0; i < fp->tc; i++) sol_stor_texc(fin, fp->tv + i);
1103 for (i = 0; i < fp->gc; i++) sol_stor_geom(fin, fp->gv + i);
1104 for (i = 0; i < fp->lc; i++) sol_stor_lump(fin, fp->lv + i);
1105 for (i = 0; i < fp->nc; i++) sol_stor_node(fin, fp->nv + i);
1106 for (i = 0; i < fp->pc; i++) sol_stor_path(fin, fp->pv + i);
1107 for (i = 0; i < fp->bc; i++) sol_stor_body(fin, fp->bv + i);
1108 for (i = 0; i < fp->cc; i++) sol_stor_coin(fin, fp->cv + i);
1109 for (i = 0; i < fp->zc; i++) sol_stor_goal(fin, fp->zv + i);
1110 for (i = 0; i < fp->jc; i++) sol_stor_jump(fin, fp->jv + i);
1111 for (i = 0; i < fp->xc; i++) sol_stor_swch(fin, fp->xv + i);
1112 for (i = 0; i < fp->rc; i++) sol_stor_bill(fin, fp->rv + i);
1113 for (i = 0; i < fp->uc; i++) sol_stor_ball(fin, fp->uv + i);
1114 for (i = 0; i < fp->wc; i++) sol_stor_view(fin, fp->wv + i);
1115 for (i = 0; i < fp->ic; i++) put_index(fin, fp->iv + i);
1117 fwrite(fp->av, 1, fp->ac, fin);
1120 /*---------------------------------------------------------------------------*/
1122 int sol_stor(struct s_file *fp, const char *filename)
1126 if ((fout = fopen(filename, FMODE_WB)))
1128 sol_stor_file(fout, fp);
1136 void sol_free(struct s_file *fp)
1140 for (i = 0; i < fp->mc; i++)
1142 if (glIsTexture(fp->mv[i].o))
1143 glDeleteTextures(1, &fp->mv[i].o);
1146 for (i = 0; i < fp->bc; i++)
1148 if (glIsList(fp->bv[i].ol))
1149 glDeleteLists(fp->bv[i].ol, 1);
1150 if (glIsList(fp->bv[i].tl))
1151 glDeleteLists(fp->bv[i].tl, 1);
1152 if (glIsList(fp->bv[i].rl))
1153 glDeleteLists(fp->bv[i].rl, 1);
1156 if (fp->mv) free(fp->mv);
1157 if (fp->vv) free(fp->vv);
1158 if (fp->ev) free(fp->ev);
1159 if (fp->sv) free(fp->sv);
1160 if (fp->tv) free(fp->tv);
1161 if (fp->gv) free(fp->gv);
1162 if (fp->lv) free(fp->lv);
1163 if (fp->nv) free(fp->nv);
1164 if (fp->pv) free(fp->pv);
1165 if (fp->bv) free(fp->bv);
1166 if (fp->cv) free(fp->cv);
1167 if (fp->zv) free(fp->zv);
1168 if (fp->jv) free(fp->jv);
1169 if (fp->xv) free(fp->xv);
1170 if (fp->rv) free(fp->rv);
1171 if (fp->uv) free(fp->uv);
1172 if (fp->wv) free(fp->wv);
1173 if (fp->av) free(fp->av);
1174 if (fp->iv) free(fp->iv);
1176 memset(fp, 0, sizeof (struct s_file));
1179 /*---------------------------------------------------------------------------*/
1180 /* Solves (p + v * t) . (p + v * t) == r * r for smallest t. */
1182 static float v_sol(const float p[3], const float v[3], float r)
1184 float a = v_dot(v, v);
1185 float b = v_dot(v, p) * 2.0f;
1186 float c = v_dot(p, p) - r * r;
1187 float d = b * b - 4.0f * a * c;
1189 if (a == 0.0f) return LARGE;
1190 if (d < 0.0f) return LARGE;
1193 return -b * 0.5f / a;
1196 float t0 = 0.5f * (-b - fsqrtf(d)) / a;
1197 float t1 = 0.5f * (-b + fsqrtf(d)) / a;
1198 float t = (t0 < t1) ? t0 : t1;
1200 return (t < 0.0f) ? LARGE : t;
1204 /*---------------------------------------------------------------------------*/
1207 * Compute the earliest time and position of the intersection of a
1208 * sphere and a vertex.
1210 * The sphere has radius R and moves along vector V from point P. The
1211 * vertex moves along vector W from point Q in a coordinate system
1214 static float v_vert(float Q[3],
1219 const float v[3], float r)
1221 float O[3], P[3], V[3];
1228 if (v_dot(P, V) < 0.0f)
1239 * Compute the earliest time and position of the intersection of a
1240 * sphere and an edge.
1242 * The sphere has radius R and moves along vector V from point P. The
1243 * edge moves along vector W from point Q in a coordinate system based
1244 * at O. The edge extends along the length of vector U.
1246 static float v_edge(float Q[3],
1252 const float v[3], float r)
1256 float du, eu, uu, s, t;
1266 v_mad(P, d, u, -du / uu);
1267 v_mad(V, e, u, -eu / uu);
1270 s = (du + eu * t) / uu;
1272 if (0.0f < t && t < LARGE && 0.0f < s && s < 1.0f)
1285 * Compute the earlist time and position of the intersection of a
1286 * sphere and a plane.
1288 * The sphere has radius R and moves along vector V from point P. The
1289 * plane oves along vector W. The plane has normal N and is
1290 * positioned at distance D from the origin O along that normal.
1292 static float v_side(float Q[3],
1295 const float n[3], float d,
1297 const float v[3], float r)
1299 float vn = v_dot(v, n);
1300 float wn = v_dot(w, n);
1303 if (vn - wn <= 0.0f)
1305 float on = v_dot(o, n);
1306 float pn = v_dot(p, n);
1308 float u = (r + d + on - pn) / (vn - wn);
1309 float a = ( d + on - pn) / (vn - wn);
1329 /*---------------------------------------------------------------------------*/
1332 * Compute the new linear and angular velocities of a bouncing ball.
1333 * Q gives the position of the point of impact and W gives the
1334 * velocity of the object being impacted.
1336 static float sol_bounce(struct s_ball *up,
1338 const float w[3], float dt)
1340 const float kb = 1.10f;
1341 const float ke = 0.70f;
1342 const float km = 0.20f;
1344 float n[3], r[3], d[3], u[3], vn, wn, xn, yn;
1348 /* Find the normal of the impact. */
1354 /* Find the new angular velocity. */
1357 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
1359 /* Find the new linear velocity. */
1363 xn = (vn < 0.0f) ? -vn * ke : vn;
1364 yn = (wn > 0.0f) ? wn * kb : wn;
1366 v_mad(u, w, n, -wn);
1367 v_mad(v, v, n, -vn);
1368 v_mad(v, v, u, +km * dt);
1369 v_mad(v, v, n, xn + yn);
1371 v_mad(p, q, n, up->r);
1373 /* Return the "energy" of the impact, to determine the sound amplitude. */
1375 return fabsf(v_dot(n, d));
1378 /*---------------------------------------------------------------------------*/
1381 * Compute the states of all switches after DT seconds have passed.
1383 static void sol_swch_step(struct s_file *fp, float dt)
1387 for (xi = 0; xi < fp->xc; xi++)
1389 struct s_swch *xp = fp->xv + xi;
1400 do /* Tortoise and hare cycle traverser. */
1402 fp->pv[pi].f = xp->f0;
1403 fp->pv[pj].f = xp->f0;
1418 * Compute the positions of all bodies after DT seconds have passed.
1420 static void sol_body_step(struct s_file *fp, float dt)
1424 for (i = 0; i < fp->bc; i++)
1426 struct s_body *bp = fp->bv + i;
1427 struct s_path *pp = fp->pv + bp->pi;
1429 if (bp->pi >= 0 && pp->f)
1443 * Compute the positions of all balls after DT seconds have passed.
1445 static void sol_ball_step(struct s_file *fp, float dt)
1449 for (i = 0; i < fp->uc; i++)
1451 struct s_ball *up = fp->uv + i;
1453 v_mad(up->p, up->p, up->v, dt);
1455 if (v_len(up->w) > 0.0f)
1462 m_rot(M, w, v_len(up->w) * dt);
1464 m_vxfm(e[0], M, up->e[0]);
1465 m_vxfm(e[1], M, up->e[1]);
1466 m_vxfm(e[2], M, up->e[2]);
1468 v_crs(up->e[2], e[0], e[1]);
1469 v_crs(up->e[1], e[2], e[0]);
1470 v_crs(up->e[0], e[1], e[2]);
1472 v_nrm(up->e[0], up->e[0]);
1473 v_nrm(up->e[1], up->e[1]);
1474 v_nrm(up->e[2], up->e[2]);
1479 /*---------------------------------------------------------------------------*/
1481 static float sol_test_vert(float dt,
1483 const struct s_ball *up,
1484 const struct s_vert *vp,
1488 return v_vert(T, o, vp->p, w, up->p, up->v, up->r);
1491 static float sol_test_edge(float dt,
1493 const struct s_ball *up,
1494 const struct s_file *fp,
1495 const struct s_edge *ep,
1502 v_cpy(q, fp->vv[ep->vi].p);
1503 v_sub(u, fp->vv[ep->vj].p,
1506 return v_edge(T, o, q, u, w, up->p, up->v, up->r);
1509 static float sol_test_side(float dt,
1511 const struct s_ball *up,
1512 const struct s_file *fp,
1513 const struct s_lump *lp,
1514 const struct s_side *sp,
1518 float t = v_side(T, o, w, sp->n, sp->d, up->p, up->v, up->r);
1522 for (i = 0; i < lp->sc; i++)
1524 const struct s_side *sq = fp->sv + fp->iv[lp->s0 + i];
1529 v_dot(w, sq->n) * t > sq->d)
1535 /*---------------------------------------------------------------------------*/
1537 static float sol_test_fore(float dt,
1538 const struct s_ball *up,
1539 const struct s_side *sp,
1545 /* If the ball is not behind the plane, the test passes. */
1549 if (v_dot(q, sp->n) - sp->d + up->r >= 0)
1552 /* if the ball is behind the plane but will hit before dt, test passes. */
1554 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1557 /* If the ball is behind but moving toward the plane, test passes. */
1559 if (v_dot(up->v, sp->n) > 0)
1563 /* Else, test fails. */
1568 static float sol_test_back(float dt,
1569 const struct s_ball *up,
1570 const struct s_side *sp,
1576 /* If the ball is not in front of the plane, the test passes. */
1580 if (v_dot(q, sp->n) - sp->d - up->r <= 0)
1583 /* if the ball is behind the plane but will hit before dt, test passes. */
1585 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1588 /* If the ball is in front but moving toward the plane, test passes. */
1590 if (v_dot(up->v, sp->n) < 0)
1594 /* Else, test fails. */
1599 /*---------------------------------------------------------------------------*/
1601 static float sol_test_lump(float dt,
1603 const struct s_ball *up,
1604 const struct s_file *fp,
1605 const struct s_lump *lp,
1609 float U[3], u, t = dt;
1612 /* Short circuit a non-solid lump. */
1614 if (lp->fl & L_DETAIL) return t;
1616 /* Test all verts */
1619 for (i = 0; i < lp->vc; i++)
1621 const struct s_vert *vp = fp->vv + fp->iv[lp->v0 + i];
1623 if ((u = sol_test_vert(t, U, up, vp, o, w)) < t)
1630 /* Test all edges */
1633 for (i = 0; i < lp->ec; i++)
1635 const struct s_edge *ep = fp->ev + fp->iv[lp->e0 + i];
1637 if ((u = sol_test_edge(t, U, up, fp, ep, o, w)) < t)
1644 /* Test all sides */
1646 for (i = 0; i < lp->sc; i++)
1648 const struct s_side *sp = fp->sv + fp->iv[lp->s0 + i];
1650 if ((u = sol_test_side(t, U, up, fp, lp, sp, o, w)) < t)
1659 static float sol_test_node(float dt,
1661 const struct s_ball *up,
1662 const struct s_file *fp,
1663 const struct s_node *np,
1667 float U[3], u, t = dt;
1670 /* Test all lumps */
1672 for (i = 0; i < np->lc; i++)
1674 const struct s_lump *lp = fp->lv + np->l0 + i;
1676 if ((u = sol_test_lump(t, U, up, fp, lp, o, w)) < t)
1683 /* Test in front of this node */
1685 if (np->ni >= 0 && sol_test_fore(t, up, fp->sv + np->si, o, w))
1687 const struct s_node *nq = fp->nv + np->ni;
1689 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1696 /* Test behind this node */
1698 if (np->nj >= 0 && sol_test_back(t, up, fp->sv + np->si, o, w))
1700 const struct s_node *nq = fp->nv + np->nj;
1702 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1712 static float sol_test_body(float dt,
1713 float T[3], float V[3],
1714 const struct s_ball *up,
1715 const struct s_file *fp,
1716 const struct s_body *bp)
1718 float U[3], O[3], W[3], u, t = dt;
1720 const struct s_node *np = fp->nv + bp->ni;
1722 sol_body_p(O, fp, bp);
1723 sol_body_v(W, fp, bp);
1725 if ((u = sol_test_node(t, U, up, fp, np, O, W)) < t)
1734 static float sol_test_file(float dt,
1735 float T[3], float V[3],
1736 const struct s_ball *up,
1737 const struct s_file *fp)
1739 float U[3], W[3], u, t = dt;
1742 for (i = 0; i < fp->bc; i++)
1744 const struct s_body *bp = fp->bv + i;
1746 if ((u = sol_test_body(t, U, W, up, fp, bp)) < t)
1756 /*---------------------------------------------------------------------------*/
1759 * Step the physics forward DT seconds under the influence of gravity
1760 * vector G. If the ball gets pinched between two moving solids, this
1761 * loop might not terminate. It is better to do something physically
1762 * impossible than to lock up the game. So, if we make more than C
1763 * iterations, punt it.
1766 float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
1768 float P[3], V[3], v[3], r[3], d, e, nt, b = 0.0f, tt = dt;
1773 struct s_ball *up = fp->uv + ui;
1775 /* If the ball is in contact with a surface, apply friction. */
1780 if (m && sol_test_file(tt, P, V, up, fp) < 0.0005f)
1785 if ((d = v_dot(r, g) / (v_len(r) * v_len(g))) > 0.999f)
1787 if ((e = (v_len(up->v) - dt)) > 0.0f)
1789 /* Scale the linear velocity. */
1791 v_nrm(up->v, up->v);
1792 v_scl(up->v, up->v, e);
1794 /* Scale the angular velocity. */
1798 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
1802 /* Friction has brought the ball to a stop. */
1811 else v_mad(up->v, v, g, tt);
1813 else v_mad(up->v, v, g, tt);
1815 /* Test for collision. */
1817 while (c > 0 && tt > 0 && tt > (nt = sol_test_file(tt, P, V, up, fp)))
1819 sol_body_step(fp, nt);
1820 sol_swch_step(fp, nt);
1821 sol_ball_step(fp, nt);
1825 if (b < (d = sol_bounce(up, P, V, nt)))
1831 sol_body_step(fp, tt);
1832 sol_swch_step(fp, tt);
1833 sol_ball_step(fp, tt);
1838 /*---------------------------------------------------------------------------*/
1840 int sol_coin_test(struct s_file *fp, float *p, float coin_r)
1842 const float *ball_p = fp->uv->p;
1843 const float ball_r = fp->uv->r;
1846 for (ci = 0; ci < fp->cc; ci++)
1850 r[0] = ball_p[0] - fp->cv[ci].p[0];
1851 r[1] = ball_p[1] - fp->cv[ci].p[1];
1852 r[2] = ball_p[2] - fp->cv[ci].p[2];
1854 if (fp->cv[ci].n > 0 && v_len(r) < ball_r + coin_r)
1856 p[0] = fp->cv[ci].p[0];
1857 p[1] = fp->cv[ci].p[1];
1858 p[2] = fp->cv[ci].p[2];
1869 int sol_goal_test(struct s_file *fp, float *p, int ui)
1871 const float *ball_p = fp->uv[ui].p;
1872 const float ball_r = fp->uv[ui].r;
1875 for (zi = 0; zi < fp->zc; zi++)
1879 r[0] = ball_p[0] - fp->zv[zi].p[0];
1880 r[1] = ball_p[2] - fp->zv[zi].p[2];
1883 if (v_len(r) < fp->zv[zi].r * 1.1 - ball_r &&
1884 ball_p[1] > fp->zv[zi].p[1] &&
1885 ball_p[1] < fp->zv[zi].p[1] + GOAL_HEIGHT / 2)
1887 p[0] = fp->zv[zi].p[0];
1888 p[1] = fp->zv[zi].p[1];
1889 p[2] = fp->zv[zi].p[2];
1897 int sol_jump_test(struct s_file *fp, float *p, int ui)
1899 const float *ball_p = fp->uv[ui].p;
1900 const float ball_r = fp->uv[ui].r;
1903 for (ji = 0; ji < fp->jc; ji++)
1907 r[0] = ball_p[0] - fp->jv[ji].p[0];
1908 r[1] = ball_p[2] - fp->jv[ji].p[2];
1911 if (v_len(r) < fp->jv[ji].r - ball_r &&
1912 ball_p[1] > fp->jv[ji].p[1] &&
1913 ball_p[1] < fp->jv[ji].p[1] + JUMP_HEIGHT / 2)
1915 p[0] = fp->jv[ji].q[0] + (ball_p[0] - fp->jv[ji].p[0]);
1916 p[1] = fp->jv[ji].q[1] + (ball_p[1] - fp->jv[ji].p[1]);
1917 p[2] = fp->jv[ji].q[2] + (ball_p[2] - fp->jv[ji].p[2]);
1925 int sol_swch_test(struct s_file *fp, int flag, int ui)
1927 const float *ball_p = fp->uv[ui].p;
1928 const float ball_r = fp->uv[ui].r;
1932 for (xi = 0; xi < fp->xc; xi++)
1934 struct s_swch *xp = fp->xv + xi;
1936 if (xp->t0 == 0 || xp->f == xp->f0)
1940 r[0] = ball_p[0] - xp->p[0];
1941 r[1] = ball_p[2] - xp->p[2];
1944 if (v_len(r) < xp->r - ball_r &&
1945 ball_p[1] > xp->p[1] &&
1946 ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
1953 /* Toggle the state, update the path. */
1955 xp->f = xp->f ? 0 : 1;
1957 do /* Tortoise and hare cycle traverser. */
1959 fp->pv[pi].f = xp->f;
1960 fp->pv[pj].f = xp->f;
1968 /* It toggled to non-default state, start the timer. */
1970 if (xp->f != xp->f0)
1980 /*---------------------------------------------------------------------------*/
1982 void put_file_state(FILE *fout, struct s_file *fp)
1984 /* Write the position and orientation of the ball. */
1986 put_array(fout, fp->uv[0].p, 3);
1987 put_array(fout, fp->uv[0].e[0], 3);
1988 put_array(fout, fp->uv[0].e[1], 3);
1991 void get_file_state(FILE *fin, struct s_file *fp)
1993 /* Read the position and orientation of the ball. */
1995 get_array(fin, fp->uv[0].p, 3);
1996 get_array(fin, fp->uv[0].e[0], 3);
1997 get_array(fin, fp->uv[0].e[1], 3);
1999 /* Compute the 3rd vector of the ball orientatian basis. */
2001 v_crs(fp->uv[0].e[2], fp->uv[0].e[0], fp->uv[0].e[1]);
2004 /*---------------------------------------------------------------------------*/