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>
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);
58 v_scl(v, v, derp(bp->t / pp->t));
68 static void sol_body_p(float p[3],
69 const struct s_file *fp,
70 const struct s_body *bp)
76 const struct s_path *pp = fp->pv + bp->pi;
77 const struct s_path *pq = fp->pv + pp->pi;
79 v_sub(v, pq->p, pp->p);
80 v_mad(p, pp->p, v, erp(bp->t / pp->t));
90 /*---------------------------------------------------------------------------*/
92 static int sol_enum_mtrl(const struct s_file *fp,
93 const struct s_body *bp, int mi)
97 /* Count all lump geoms with this material. */
99 for (li = 0; li < bp->lc; li++)
101 int g0 = fp->lv[bp->l0 + li].g0;
102 int gc = fp->lv[bp->l0 + li].gc;
104 for (gi = 0; gi < gc; gi++)
105 if (fp->gv[fp->iv[g0 + gi]].mi == mi)
109 /* Count all body geoms with this material. */
111 for (gi = 0; gi < bp->gc; gi++)
112 if (fp->gv[fp->iv[bp->g0 + gi]].mi == mi)
118 static int sol_enum_body(const struct s_file *fp,
119 const struct s_body *bp, int fl)
123 /* Count all geoms with this flag. */
125 for (mi = 0; mi < fp->mc; mi++)
126 if (fp->mv[mi].fl & fl)
127 c = c + sol_enum_mtrl(fp, bp, mi);
132 /*---------------------------------------------------------------------------*/
134 static void sol_draw_mtrl(const struct s_file *fp, int i)
136 const struct s_mtrl *mp = fp->mv + i;
138 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mp->a);
139 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->d);
140 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mp->s);
141 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mp->e);
142 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mp->h);
144 if (mp->fl & M_ENVIRONMENT)
146 glEnable(GL_TEXTURE_GEN_S);
147 glEnable(GL_TEXTURE_GEN_T);
149 glBindTexture(GL_TEXTURE_2D, mp->o);
151 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
152 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
156 glDisable(GL_TEXTURE_GEN_S);
157 glDisable(GL_TEXTURE_GEN_T);
159 glBindTexture(GL_TEXTURE_2D, mp->o);
162 if (mp->fl & M_ADDITIVE)
163 glBlendFunc(GL_ONE, GL_ONE);
165 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
169 static void sol_draw_bill(const struct s_file *fp,
170 const struct s_bill *rp, float t)
172 float T = fmodf(t, rp->t) - rp->t / 2;
174 float w = rp->w[0] + rp->w[1] * T + rp->w[2] * T * T;
175 float h = rp->h[0] + rp->h[1] * T + rp->h[2] * T * T;
179 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * T * T;
180 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * T * T;
181 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * T * T;
185 float y0 = (rp->fl & B_EDGE) ? 0 : -h / 2;
186 float y1 = (rp->fl & B_EDGE) ? h : +h / 2;
188 glRotatef(ry, 0.0f, 1.0f, 0.0f);
189 glRotatef(rx, 1.0f, 0.0f, 0.0f);
190 glTranslatef(0.0f, 0.0f, -rp->d);
194 glRotatef(-rx - 90.0f, 1.0f, 0.0f, 0.0f);
195 glRotatef(-ry, 0.0f, 0.0f, 1.0f);
198 glRotatef(-rx, 1.0f, 0.0f, 0.0f);
200 glRotatef(rz, 0.0f, 0.0f, 1.0f);
202 sol_draw_mtrl(fp, rp->mi);
206 glTexCoord2f(0.0f, 1.0f); glVertex2f(-w / 2, y0);
207 glTexCoord2f(1.0f, 1.0f); glVertex2f(+w / 2, y0);
208 glTexCoord2f(1.0f, 0.0f); glVertex2f(+w / 2, y1);
209 glTexCoord2f(0.0f, 0.0f); glVertex2f(-w / 2, y1);
217 void sol_back(const struct s_file *fp, float n, float f, float t)
221 glPushAttrib(GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
223 /* Render all billboards in the given range. */
225 glDisable(GL_LIGHTING);
226 glDepthMask(GL_FALSE);
228 for (ri = 0; ri < fp->rc; ri++)
229 if (n <= fp->rv[ri].d && fp->rv[ri].d < f)
230 sol_draw_bill(fp, fp->rv + ri, t);
235 /*---------------------------------------------------------------------------*/
237 * The following code renders a body in a ludicrously inefficient
238 * manner. It iterates the materials and scans the data structure for
239 * geometry using each. This has the effect of absolutely minimizing
240 * material changes, texture bindings, and Begin/End pairs, but
241 * maximizing trips through the data.
243 * However, this is only done once for each level. The results are
244 * stored in display lists. Thus, it is well worth it.
247 static void sol_draw_geom(const struct s_file *fp,
248 const struct s_geom *gp, int mi)
252 const float *ui = fp->tv[gp->ti].u;
253 const float *uj = fp->tv[gp->tj].u;
254 const float *uk = fp->tv[gp->tk].u;
256 const float *ni = fp->sv[gp->si].n;
257 const float *nj = fp->sv[gp->sj].n;
258 const float *nk = fp->sv[gp->sk].n;
260 const float *vi = fp->vv[gp->vi].p;
261 const float *vj = fp->vv[gp->vj].p;
262 const float *vk = fp->vv[gp->vk].p;
278 static void sol_draw_lump(const struct s_file *fp,
279 const struct s_lump *lp, int mi)
283 for (i = 0; i < lp->gc; i++)
284 sol_draw_geom(fp, fp->gv + fp->iv[lp->g0 + i], mi);
287 static void sol_draw_body(const struct s_file *fp,
288 const struct s_body *bp, int fl)
292 /* Iterate all materials of the correct opacity. */
294 for (mi = 0; mi < fp->mc; mi++)
295 if (fp->mv[mi].fl & fl)
297 if (sol_enum_mtrl(fp, bp, mi))
299 /* Set the material state. */
301 sol_draw_mtrl(fp, mi);
303 /* Render all geometry of that material. */
305 glBegin(GL_TRIANGLES);
307 for (li = 0; li < bp->lc; li++)
308 sol_draw_lump(fp, fp->lv + bp->l0 + li, mi);
309 for (gi = 0; gi < bp->gc; gi++)
310 sol_draw_geom(fp, fp->gv + fp->iv[bp->g0 + gi], mi);
317 static void sol_draw_list(const struct s_file *fp,
318 const struct s_body *bp, GLuint list)
322 sol_body_p(p, fp, bp);
326 /* Translate a moving body. */
328 glTranslatef(p[0], p[1], p[2]);
337 void sol_draw(const struct s_file *fp)
341 glPushAttrib(GL_TEXTURE_BIT |
343 GL_COLOR_BUFFER_BIT |
344 GL_DEPTH_BUFFER_BIT);
346 /* Render all obaque geometry into the color and depth buffers. */
348 for (bi = 0; bi < fp->bc; bi++)
350 sol_draw_list(fp, fp->bv + bi, fp->bv[bi].ol);
352 /* Render all translucent geometry into only the color buffer. */
354 glDepthMask(GL_FALSE);
357 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
359 for (bi = 0; bi < fp->bc; bi++)
361 sol_draw_list(fp, fp->bv + bi, fp->bv[bi].tl);
366 void sol_refl(const struct s_file *fp)
370 glPushAttrib(GL_LIGHTING_BIT);
372 /* Render all reflective geometry into the color and depth buffers. */
375 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
377 for (bi = 0; bi < fp->bc; bi++)
379 sol_draw_list(fp, fp->bv + bi, fp->bv[bi].rl);
384 /*---------------------------------------------------------------------------*/
386 static void sol_shad_geom(const struct s_file *fp,
387 const struct s_geom *gp, int mi)
391 const float *vi = fp->vv[gp->vi].p;
392 const float *vj = fp->vv[gp->vj].p;
393 const float *vk = fp->vv[gp->vk].p;
395 glTexCoord2f(vi[0], vi[2]);
398 glTexCoord2f(vj[0], vj[2]);
401 glTexCoord2f(vk[0], vk[2]);
406 static void sol_shad_lump(const struct s_file *fp,
407 const struct s_lump *lp, int mi)
411 for (i = 0; i < lp->gc; i++)
412 sol_shad_geom(fp, fp->gv + fp->iv[lp->g0 + i], mi);
415 static void sol_shad_body(const struct s_file *fp,
416 const struct s_body *bp, int fl)
420 glBegin(GL_TRIANGLES);
422 for (mi = 0; mi < fp->mc; mi++)
423 if (fp->mv[mi].fl & fl)
425 for (li = 0; li < bp->lc; li++)
426 sol_shad_lump(fp, fp->lv + bp->l0 + li, mi);
427 for (gi = 0; gi < bp->gc; gi++)
428 sol_shad_geom(fp, fp->gv + fp->iv[bp->g0 + gi], mi);
434 static void sol_shad_list(const struct s_file *fp,
435 const struct s_body *bp, GLuint list)
439 sol_body_p(p, fp, bp);
443 /* Translate a moving body. */
445 glTranslatef(p[0], p[1], p[2]);
447 /* Translate the shadow on a moving body. */
449 glMatrixMode(GL_TEXTURE);
452 glTranslatef(p[0], p[2], 0.0f);
454 glMatrixMode(GL_MODELVIEW);
460 /* Pop the shadow translation. */
462 glMatrixMode(GL_TEXTURE);
466 glMatrixMode(GL_MODELVIEW);
471 void sol_shad(const struct s_file *fp)
475 glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT);
477 /* Render all shadowed geometry. */
480 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
482 glDepthFunc(GL_LEQUAL);
483 glDepthMask(GL_FALSE);
485 for (bi = 0; bi < fp->bc; bi++)
487 sol_shad_list(fp, fp->bv + bi, fp->bv[bi].sl);
492 /*---------------------------------------------------------------------------*/
494 static void sol_load_objects(struct s_file *fp, int s)
498 for (i = 0; i < fp->bc; i++)
500 struct s_body *bp = fp->bv + i;
502 /* Draw all opaque geometry. */
504 if (sol_enum_body(fp, bp, M_OPAQUE | M_ENVIRONMENT))
506 fp->bv[i].ol = glGenLists(1);
508 glNewList(fp->bv[i].ol, GL_COMPILE);
510 sol_draw_body(fp, fp->bv + i, M_OPAQUE | M_ENVIRONMENT);
514 else fp->bv[i].ol = 0;
516 /* Draw all translucent geometry. */
518 if (sol_enum_body(fp, bp, M_TRANSPARENT))
520 fp->bv[i].tl = glGenLists(1);
522 glNewList(fp->bv[i].tl, GL_COMPILE);
524 sol_draw_body(fp, fp->bv + i, M_TRANSPARENT);
528 else fp->bv[i].tl = 0;
530 /* Draw all reflective geometry. */
532 if (sol_enum_body(fp, bp, M_REFLECTIVE))
534 fp->bv[i].rl = glGenLists(1);
536 glNewList(fp->bv[i].rl, GL_COMPILE);
538 sol_draw_body(fp, fp->bv + i, M_REFLECTIVE);
542 else fp->bv[i].rl = 0;
544 /* Draw all shadowed geometry. */
546 if (s && sol_enum_body(fp, bp, M_SHADOWED))
548 fp->bv[i].sl = glGenLists(1);
550 glNewList(fp->bv[i].sl, GL_COMPILE);
552 sol_shad_body(fp, fp->bv + i, M_SHADOWED);
556 else fp->bv[i].sl = 0;
560 static SDL_Surface *sol_find_texture(const char *name)
567 /* Prefer a lossless copy of the texture over a lossy compression. */
569 strncpy(png, name, PATHMAX); strcat(png, ".png");
570 strncpy(tga, name, PATHMAX); strcat(tga, ".tga");
571 strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
573 /* Check for a PNG. */
575 if ((s = IMG_Load(config_data(png))))
578 /* Check for a TGA, swapping channels if found. */
580 if ((s = IMG_Load(config_data(tga))))
586 /* Check for a JPG. */
588 if ((s = IMG_Load(config_data(jpg))))
594 static void sol_load_textures(struct s_file *fp, int k)
601 for (i = 0; i < fp->mc; i++)
602 if ((s = sol_find_texture(fp->mv[i].f)))
604 GLenum f = (s->format->BitsPerPixel == 32) ? GL_RGBA : GL_RGB;
606 glGenTextures(1, &fp->mv[i].o);
607 glBindTexture(GL_TEXTURE_2D, fp->mv[i].o);
611 /* Create a new buffer and copy the scaled image to it. */
613 if ((d = image_scale(s, k)))
615 glTexImage2D(GL_TEXTURE_2D, 0, f, d->w, d->h, 0, f,
616 GL_UNSIGNED_BYTE, d->pixels);
621 glTexImage2D(GL_TEXTURE_2D, 0, f, s->w, s->h, 0, f,
622 GL_UNSIGNED_BYTE, s->pixels);
624 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
625 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
627 /* Set the texture to clamp or repeat based on material type. */
629 if (fp->mv[i].fl & M_CLAMPED)
631 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
632 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
636 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
637 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
644 /*---------------------------------------------------------------------------*/
646 static void sol_load_mtrl(FILE *fin, struct s_mtrl *mp)
648 get_array(fin, mp->a, 4);
649 get_array(fin, mp->d, 4);
650 get_array(fin, mp->s, 4);
651 get_array(fin, mp->e, 4);
652 get_array(fin, mp->h, 1);
653 get_index(fin, &mp->fl);
655 fread(mp->f, 1, PATHMAX, fin);
658 static void sol_load_vert(FILE *fin, struct s_vert *vp)
660 get_array(fin, vp->p, 3);
663 static void sol_load_edge(FILE *fin, struct s_edge *ep)
665 get_index(fin, &ep->vi);
666 get_index(fin, &ep->vj);
669 static void sol_load_side(FILE *fin, struct s_side *sp)
671 get_array(fin, sp->n, 3);
672 get_float(fin, &sp->d);
675 static void sol_load_texc(FILE *fin, struct s_texc *tp)
677 get_array(fin, tp->u, 2);
680 static void sol_load_geom(FILE *fin, struct s_geom *gp)
682 get_index(fin, &gp->mi);
683 get_index(fin, &gp->ti);
684 get_index(fin, &gp->si);
685 get_index(fin, &gp->vi);
686 get_index(fin, &gp->tj);
687 get_index(fin, &gp->sj);
688 get_index(fin, &gp->vj);
689 get_index(fin, &gp->tk);
690 get_index(fin, &gp->sk);
691 get_index(fin, &gp->vk);
694 static void sol_load_lump(FILE *fin, struct s_lump *lp)
696 get_index(fin, &lp->fl);
697 get_index(fin, &lp->v0);
698 get_index(fin, &lp->vc);
699 get_index(fin, &lp->e0);
700 get_index(fin, &lp->ec);
701 get_index(fin, &lp->g0);
702 get_index(fin, &lp->gc);
703 get_index(fin, &lp->s0);
704 get_index(fin, &lp->sc);
707 static void sol_load_node(FILE *fin, struct s_node *np)
709 get_index(fin, &np->si);
710 get_index(fin, &np->ni);
711 get_index(fin, &np->nj);
712 get_index(fin, &np->l0);
713 get_index(fin, &np->lc);
716 static void sol_load_path(FILE *fin, struct s_path *pp)
718 get_array(fin, pp->p, 3);
719 get_float(fin, &pp->t);
720 get_index(fin, &pp->pi);
721 get_index(fin, &pp->f);
724 static void sol_load_body(FILE *fin, struct s_body *bp)
726 get_index(fin, &bp->pi);
727 get_index(fin, &bp->ni);
728 get_index(fin, &bp->l0);
729 get_index(fin, &bp->lc);
730 get_index(fin, &bp->g0);
731 get_index(fin, &bp->gc);
734 static void sol_load_coin(FILE *fin, struct s_coin *cp)
736 get_array(fin, cp->p, 3);
737 get_index(fin, &cp->n);
740 static void sol_load_goal(FILE *fin, struct s_goal *zp)
742 get_array(fin, zp->p, 3);
743 get_float(fin, &zp->r);
746 static void sol_load_swch(FILE *fin, struct s_swch *xp)
748 get_array(fin, xp->p, 3);
749 get_float(fin, &xp->r);
750 get_index(fin, &xp->pi);
751 get_float(fin, &xp->t0);
752 get_float(fin, &xp->t);
753 get_index(fin, &xp->f0);
754 get_index(fin, &xp->f);
757 static void sol_load_bill(FILE *fin, struct s_bill *rp)
759 get_index(fin, &rp->fl);
760 get_index(fin, &rp->mi);
761 get_float(fin, &rp->t);
762 get_float(fin, &rp->d);
763 get_array(fin, rp->w, 3);
764 get_array(fin, rp->h, 3);
765 get_array(fin, rp->rx, 3);
766 get_array(fin, rp->ry, 3);
767 get_array(fin, rp->rz, 3);
770 static void sol_load_jump(FILE *fin, struct s_jump *jp)
772 get_array(fin, jp->p, 3);
773 get_array(fin, jp->q, 3);
774 get_float(fin, &jp->r);
777 static void sol_load_ball(FILE *fin, struct s_ball *bp)
779 get_array(fin, bp->e[0], 3);
780 get_array(fin, bp->e[1], 3);
781 get_array(fin, bp->e[2], 3);
782 get_array(fin, bp->p, 3);
783 get_float(fin, &bp->r);
786 static void sol_load_view(FILE *fin, struct s_view *wp)
788 get_array(fin, wp->p, 3);
789 get_array(fin, wp->q, 3);
792 static void sol_load_file(FILE *fin, struct s_file *fp)
796 get_index(fin, &fp->mc);
797 get_index(fin, &fp->vc);
798 get_index(fin, &fp->ec);
799 get_index(fin, &fp->sc);
800 get_index(fin, &fp->tc);
801 get_index(fin, &fp->gc);
802 get_index(fin, &fp->lc);
803 get_index(fin, &fp->nc);
804 get_index(fin, &fp->pc);
805 get_index(fin, &fp->bc);
806 get_index(fin, &fp->cc);
807 get_index(fin, &fp->zc);
808 get_index(fin, &fp->jc);
809 get_index(fin, &fp->xc);
810 get_index(fin, &fp->rc);
811 get_index(fin, &fp->uc);
812 get_index(fin, &fp->wc);
813 get_index(fin, &fp->ic);
814 get_index(fin, &fp->ac);
817 fp->mv = (struct s_mtrl *) calloc(fp->mc, sizeof (struct s_mtrl));
819 fp->vv = (struct s_vert *) calloc(fp->vc, sizeof (struct s_vert));
821 fp->ev = (struct s_edge *) calloc(fp->ec, sizeof (struct s_edge));
823 fp->sv = (struct s_side *) calloc(fp->sc, sizeof (struct s_side));
825 fp->tv = (struct s_texc *) calloc(fp->tc, sizeof (struct s_texc));
827 fp->gv = (struct s_geom *) calloc(fp->gc, sizeof (struct s_geom));
829 fp->lv = (struct s_lump *) calloc(fp->lc, sizeof (struct s_lump));
831 fp->nv = (struct s_node *) calloc(fp->nc, sizeof (struct s_node));
833 fp->pv = (struct s_path *) calloc(fp->pc, sizeof (struct s_path));
835 fp->bv = (struct s_body *) calloc(fp->bc, sizeof (struct s_body));
837 fp->cv = (struct s_coin *) calloc(fp->cc, sizeof (struct s_coin));
839 fp->zv = (struct s_goal *) calloc(fp->zc, sizeof (struct s_goal));
841 fp->jv = (struct s_jump *) calloc(fp->jc, sizeof (struct s_jump));
843 fp->xv = (struct s_swch *) calloc(fp->xc, sizeof (struct s_swch));
845 fp->rv = (struct s_bill *) calloc(fp->rc, sizeof (struct s_bill));
847 fp->uv = (struct s_ball *) calloc(fp->uc, sizeof (struct s_ball));
849 fp->wv = (struct s_view *) calloc(fp->wc, sizeof (struct s_view));
851 fp->iv = (int *) calloc(fp->ic, sizeof (int));
853 fp->av = (char *) calloc(fp->ac, sizeof (char));
855 for (i = 0; i < fp->mc; i++) sol_load_mtrl(fin, fp->mv + i);
856 for (i = 0; i < fp->vc; i++) sol_load_vert(fin, fp->vv + i);
857 for (i = 0; i < fp->ec; i++) sol_load_edge(fin, fp->ev + i);
858 for (i = 0; i < fp->sc; i++) sol_load_side(fin, fp->sv + i);
859 for (i = 0; i < fp->tc; i++) sol_load_texc(fin, fp->tv + i);
860 for (i = 0; i < fp->gc; i++) sol_load_geom(fin, fp->gv + i);
861 for (i = 0; i < fp->lc; i++) sol_load_lump(fin, fp->lv + i);
862 for (i = 0; i < fp->nc; i++) sol_load_node(fin, fp->nv + i);
863 for (i = 0; i < fp->pc; i++) sol_load_path(fin, fp->pv + i);
864 for (i = 0; i < fp->bc; i++) sol_load_body(fin, fp->bv + i);
865 for (i = 0; i < fp->cc; i++) sol_load_coin(fin, fp->cv + i);
866 for (i = 0; i < fp->zc; i++) sol_load_goal(fin, fp->zv + i);
867 for (i = 0; i < fp->jc; i++) sol_load_jump(fin, fp->jv + i);
868 for (i = 0; i < fp->xc; i++) sol_load_swch(fin, fp->xv + i);
869 for (i = 0; i < fp->rc; i++) sol_load_bill(fin, fp->rv + i);
870 for (i = 0; i < fp->uc; i++) sol_load_ball(fin, fp->uv + i);
871 for (i = 0; i < fp->wc; i++) sol_load_view(fin, fp->wv + i);
872 for (i = 0; i < fp->ic; i++) get_index(fin, fp->iv + i);
874 if (fp->ac) fread(fp->av, 1, fp->ac, fin);
877 int sol_load(struct s_file *fp, const char *filename, int k, int s)
881 if ((fin = fopen(filename, FMODE_RB)))
883 sol_load_file(fin, fp);
884 sol_load_textures(fp, k);
885 sol_load_objects (fp, s);
894 /*---------------------------------------------------------------------------*/
896 static void sol_stor_mtrl(FILE *fout, struct s_mtrl *mp)
898 put_array(fout, mp->a, 4);
899 put_array(fout, mp->d, 4);
900 put_array(fout, mp->s, 4);
901 put_array(fout, mp->e, 4);
902 put_array(fout, mp->h, 1);
903 put_index(fout, &mp->fl);
905 fwrite(mp->f, 1, PATHMAX, fout);
908 static void sol_stor_vert(FILE *fout, struct s_vert *vp)
910 put_array(fout, vp->p, 3);
913 static void sol_stor_edge(FILE *fout, struct s_edge *ep)
915 put_index(fout, &ep->vi);
916 put_index(fout, &ep->vj);
919 static void sol_stor_side(FILE *fout, struct s_side *sp)
921 put_array(fout, sp->n, 3);
922 put_float(fout, &sp->d);
925 static void sol_stor_texc(FILE *fout, struct s_texc *tp)
927 put_array(fout, tp->u, 2);
930 static void sol_stor_geom(FILE *fout, struct s_geom *gp)
932 put_index(fout, &gp->mi);
933 put_index(fout, &gp->ti);
934 put_index(fout, &gp->si);
935 put_index(fout, &gp->vi);
936 put_index(fout, &gp->tj);
937 put_index(fout, &gp->sj);
938 put_index(fout, &gp->vj);
939 put_index(fout, &gp->tk);
940 put_index(fout, &gp->sk);
941 put_index(fout, &gp->vk);
944 static void sol_stor_lump(FILE *fout, struct s_lump *lp)
946 put_index(fout, &lp->fl);
947 put_index(fout, &lp->v0);
948 put_index(fout, &lp->vc);
949 put_index(fout, &lp->e0);
950 put_index(fout, &lp->ec);
951 put_index(fout, &lp->g0);
952 put_index(fout, &lp->gc);
953 put_index(fout, &lp->s0);
954 put_index(fout, &lp->sc);
957 static void sol_stor_node(FILE *fout, struct s_node *np)
959 put_index(fout, &np->si);
960 put_index(fout, &np->ni);
961 put_index(fout, &np->nj);
962 put_index(fout, &np->l0);
963 put_index(fout, &np->lc);
966 static void sol_stor_path(FILE *fout, struct s_path *pp)
968 put_array(fout, pp->p, 3);
969 put_float(fout, &pp->t);
970 put_index(fout, &pp->pi);
971 put_index(fout, &pp->f);
974 static void sol_stor_body(FILE *fout, struct s_body *bp)
976 put_index(fout, &bp->pi);
977 put_index(fout, &bp->ni);
978 put_index(fout, &bp->l0);
979 put_index(fout, &bp->lc);
980 put_index(fout, &bp->g0);
981 put_index(fout, &bp->gc);
984 static void sol_stor_coin(FILE *fout, struct s_coin *cp)
986 put_array(fout, cp->p, 3);
987 put_index(fout, &cp->n);
990 static void sol_stor_goal(FILE *fout, struct s_goal *zp)
992 put_array(fout, zp->p, 3);
993 put_float(fout, &zp->r);
996 static void sol_stor_swch(FILE *fout, struct s_swch *xp)
998 put_array(fout, xp->p, 3);
999 put_float(fout, &xp->r);
1000 put_index(fout, &xp->pi);
1001 put_float(fout, &xp->t0);
1002 put_float(fout, &xp->t);
1003 put_index(fout, &xp->f0);
1004 put_index(fout, &xp->f);
1007 static void sol_stor_bill(FILE *fout, struct s_bill *rp)
1009 put_index(fout, &rp->fl);
1010 put_index(fout, &rp->mi);
1011 put_float(fout, &rp->t);
1012 put_float(fout, &rp->d);
1013 put_array(fout, rp->w, 3);
1014 put_array(fout, rp->h, 3);
1015 put_array(fout, rp->rx, 3);
1016 put_array(fout, rp->ry, 3);
1017 put_array(fout, rp->rz, 3);
1020 static void sol_stor_jump(FILE *fout, struct s_jump *jp)
1022 put_array(fout, jp->p, 3);
1023 put_array(fout, jp->q, 3);
1024 put_float(fout, &jp->r);
1027 static void sol_stor_ball(FILE *fout, struct s_ball *bp)
1029 put_array(fout, bp->e[0], 3);
1030 put_array(fout, bp->e[1], 3);
1031 put_array(fout, bp->e[2], 3);
1032 put_array(fout, bp->p, 3);
1033 put_float(fout, &bp->r);
1036 static void sol_stor_view(FILE *fout, struct s_view *wp)
1038 put_array(fout, wp->p, 3);
1039 put_array(fout, wp->q, 3);
1042 static void sol_stor_file(FILE *fin, struct s_file *fp)
1046 put_index(fin, &fp->mc);
1047 put_index(fin, &fp->vc);
1048 put_index(fin, &fp->ec);
1049 put_index(fin, &fp->sc);
1050 put_index(fin, &fp->tc);
1051 put_index(fin, &fp->gc);
1052 put_index(fin, &fp->lc);
1053 put_index(fin, &fp->nc);
1054 put_index(fin, &fp->pc);
1055 put_index(fin, &fp->bc);
1056 put_index(fin, &fp->cc);
1057 put_index(fin, &fp->zc);
1058 put_index(fin, &fp->jc);
1059 put_index(fin, &fp->xc);
1060 put_index(fin, &fp->rc);
1061 put_index(fin, &fp->uc);
1062 put_index(fin, &fp->wc);
1063 put_index(fin, &fp->ic);
1064 put_index(fin, &fp->ac);
1066 for (i = 0; i < fp->mc; i++) sol_stor_mtrl(fin, fp->mv + i);
1067 for (i = 0; i < fp->vc; i++) sol_stor_vert(fin, fp->vv + i);
1068 for (i = 0; i < fp->ec; i++) sol_stor_edge(fin, fp->ev + i);
1069 for (i = 0; i < fp->sc; i++) sol_stor_side(fin, fp->sv + i);
1070 for (i = 0; i < fp->tc; i++) sol_stor_texc(fin, fp->tv + i);
1071 for (i = 0; i < fp->gc; i++) sol_stor_geom(fin, fp->gv + i);
1072 for (i = 0; i < fp->lc; i++) sol_stor_lump(fin, fp->lv + i);
1073 for (i = 0; i < fp->nc; i++) sol_stor_node(fin, fp->nv + i);
1074 for (i = 0; i < fp->pc; i++) sol_stor_path(fin, fp->pv + i);
1075 for (i = 0; i < fp->bc; i++) sol_stor_body(fin, fp->bv + i);
1076 for (i = 0; i < fp->cc; i++) sol_stor_coin(fin, fp->cv + i);
1077 for (i = 0; i < fp->zc; i++) sol_stor_goal(fin, fp->zv + i);
1078 for (i = 0; i < fp->jc; i++) sol_stor_jump(fin, fp->jv + i);
1079 for (i = 0; i < fp->xc; i++) sol_stor_swch(fin, fp->xv + i);
1080 for (i = 0; i < fp->rc; i++) sol_stor_bill(fin, fp->rv + i);
1081 for (i = 0; i < fp->uc; i++) sol_stor_ball(fin, fp->uv + i);
1082 for (i = 0; i < fp->wc; i++) sol_stor_view(fin, fp->wv + i);
1083 for (i = 0; i < fp->ic; i++) put_index(fin, fp->iv + i);
1085 fwrite(fp->av, 1, fp->ac, fin);
1088 /*---------------------------------------------------------------------------*/
1090 int sol_stor(struct s_file *fp, const char *filename)
1094 if ((fout = fopen(filename, FMODE_WB)))
1096 sol_stor_file(fout, fp);
1104 void sol_free(struct s_file *fp)
1108 for (i = 0; i < fp->mc; i++)
1110 if (glIsTexture(fp->mv[i].o))
1111 glDeleteTextures(1, &fp->mv[i].o);
1114 for (i = 0; i < fp->bc; i++)
1116 if (glIsList(fp->bv[i].ol))
1117 glDeleteLists(fp->bv[i].ol, 1);
1118 if (glIsList(fp->bv[i].tl))
1119 glDeleteLists(fp->bv[i].tl, 1);
1120 if (glIsList(fp->bv[i].rl))
1121 glDeleteLists(fp->bv[i].rl, 1);
1124 if (fp->mv) free(fp->mv);
1125 if (fp->vv) free(fp->vv);
1126 if (fp->ev) free(fp->ev);
1127 if (fp->sv) free(fp->sv);
1128 if (fp->tv) free(fp->tv);
1129 if (fp->gv) free(fp->gv);
1130 if (fp->lv) free(fp->lv);
1131 if (fp->nv) free(fp->nv);
1132 if (fp->pv) free(fp->pv);
1133 if (fp->bv) free(fp->bv);
1134 if (fp->cv) free(fp->cv);
1135 if (fp->zv) free(fp->zv);
1136 if (fp->jv) free(fp->jv);
1137 if (fp->xv) free(fp->xv);
1138 if (fp->rv) free(fp->rv);
1139 if (fp->uv) free(fp->uv);
1140 if (fp->wv) free(fp->wv);
1141 if (fp->av) free(fp->av);
1142 if (fp->iv) free(fp->iv);
1144 memset(fp, 0, sizeof (struct s_file));
1147 /*---------------------------------------------------------------------------*/
1148 /* Solves (p + v * t) . (p + v * t) == r * r for smallest t. */
1150 static float v_sol(const float p[3], const float v[3], float r)
1152 float a = v_dot(v, v);
1153 float b = v_dot(v, p) * 2.0f;
1154 float c = v_dot(p, p) - r * r;
1155 float d = b * b - 4.0f * a * c;
1157 if (a == 0.0f) return LARGE;
1158 if (d < 0.0f) return LARGE;
1161 return -b * 0.5f / a;
1164 float t0 = 0.5f * (-b - fsqrtf(d)) / a;
1165 float t1 = 0.5f * (-b + fsqrtf(d)) / a;
1166 float t = (t0 < t1) ? t0 : t1;
1168 return (t < 0.0f) ? LARGE : t;
1172 /*---------------------------------------------------------------------------*/
1175 * Compute the earliest time and position of the intersection of a
1176 * sphere and a vertex.
1178 * The sphere has radius R and moves along vector V from point P. The
1179 * vertex moves along vector W from point Q in a coordinate system
1182 static float v_vert(float Q[3],
1187 const float v[3], float r)
1189 float O[3], P[3], V[3];
1196 if (v_dot(P, V) < 0.0f)
1207 * Compute the earliest time and position of the intersection of a
1208 * sphere and an edge.
1210 * The sphere has radius R and moves along vector V from point P. The
1211 * edge moves along vector W from point Q in a coordinate system based
1212 * at O. The edge extends along the length of vector U.
1214 static float v_edge(float Q[3],
1220 const float v[3], float r)
1224 float du, eu, uu, s, t;
1234 v_mad(P, d, u, -du / uu);
1235 v_mad(V, e, u, -eu / uu);
1238 s = (du + eu * t) / uu;
1240 if (0.0f < t && t < LARGE && 0.0f < s && s < 1.0f)
1253 * Compute the earlist time and position of the intersection of a
1254 * sphere and a plane.
1256 * The sphere has radius R and moves along vector V from point P. The
1257 * plane oves along vector W. The plane has normal N and is
1258 * positioned at distance D from the origin O along that normal.
1260 static float v_side(float Q[3],
1263 const float n[3], float d,
1265 const float v[3], float r)
1267 float vn = v_dot(v, n);
1268 float wn = v_dot(w, n);
1271 if (vn - wn <= 0.0f)
1273 float on = v_dot(o, n);
1274 float pn = v_dot(p, n);
1276 float u = (r + d + on - pn) / (vn - wn);
1277 float a = ( d + on - pn) / (vn - wn);
1297 /*---------------------------------------------------------------------------*/
1300 * Compute the new linear and angular velocities of a bouncing ball.
1301 * Q gives the position of the point of impact and W gives the
1302 * velocity of the object being impacted.
1304 static float sol_bounce(struct s_ball *up,
1306 const float w[3], float dt)
1308 const float kb = 1.10f;
1309 const float ke = 0.70f;
1310 const float km = 0.20f;
1312 float n[3], r[3], d[3], u[3], vn, wn, xn, yn;
1316 /* Find the normal of the impact. */
1322 /* Find the new angular velocity. */
1325 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
1327 /* Find the new linear velocity. */
1331 xn = (vn < 0.0f) ? -vn * ke : vn;
1332 yn = (wn > 0.0f) ? wn * kb : wn;
1334 v_mad(u, w, n, -wn);
1335 v_mad(v, v, n, -vn);
1336 v_mad(v, v, u, +km * dt);
1337 v_mad(v, v, n, xn + yn);
1339 v_mad(p, q, n, up->r);
1341 /* Return the "energy" of the impact, to determine the sound amplitude. */
1343 return fabsf(v_dot(n, d));
1346 /*---------------------------------------------------------------------------*/
1349 * Compute the states of all switches after DT seconds have passed.
1351 static void sol_swch_step(struct s_file *fp, float dt)
1355 for (xi = 0; xi < fp->xc; xi++)
1357 struct s_swch *xp = fp->xv + xi;
1368 do /* Tortoise and hare cycle traverser. */
1370 fp->pv[pi].f = xp->f0;
1371 fp->pv[pj].f = xp->f0;
1386 * Compute the positions of all bodies after DT seconds have passed.
1388 static void sol_body_step(struct s_file *fp, float dt)
1392 for (i = 0; i < fp->bc; i++)
1394 struct s_body *bp = fp->bv + i;
1395 struct s_path *pp = fp->pv + bp->pi;
1397 if (bp->pi >= 0 && pp->f)
1411 * Compute the positions of all balls after DT seconds have passed.
1413 static void sol_ball_step(struct s_file *fp, float dt)
1417 for (i = 0; i < fp->uc; i++)
1419 struct s_ball *up = fp->uv + i;
1421 v_mad(up->p, up->p, up->v, dt);
1423 if (v_len(up->w) > 0.0f)
1430 m_rot(M, w, v_len(up->w) * dt);
1432 m_vxfm(e[0], M, up->e[0]);
1433 m_vxfm(e[1], M, up->e[1]);
1434 m_vxfm(e[2], M, up->e[2]);
1436 v_crs(up->e[2], e[0], e[1]);
1437 v_crs(up->e[1], e[2], e[0]);
1438 v_crs(up->e[0], e[1], e[2]);
1440 v_nrm(up->e[0], up->e[0]);
1441 v_nrm(up->e[1], up->e[1]);
1442 v_nrm(up->e[2], up->e[2]);
1447 /*---------------------------------------------------------------------------*/
1449 static float sol_test_vert(float dt,
1451 const struct s_ball *up,
1452 const struct s_vert *vp,
1456 return v_vert(T, o, vp->p, w, up->p, up->v, up->r);
1459 static float sol_test_edge(float dt,
1461 const struct s_ball *up,
1462 const struct s_file *fp,
1463 const struct s_edge *ep,
1470 v_cpy(q, fp->vv[ep->vi].p);
1471 v_sub(u, fp->vv[ep->vj].p,
1474 return v_edge(T, o, q, u, w, up->p, up->v, up->r);
1477 static float sol_test_side(float dt,
1479 const struct s_ball *up,
1480 const struct s_file *fp,
1481 const struct s_lump *lp,
1482 const struct s_side *sp,
1486 float t = v_side(T, o, w, sp->n, sp->d, up->p, up->v, up->r);
1490 for (i = 0; i < lp->sc; i++)
1492 const struct s_side *sq = fp->sv + fp->iv[lp->s0 + i];
1497 v_dot(w, sq->n) * t > sq->d)
1503 /*---------------------------------------------------------------------------*/
1505 static float sol_test_fore(float dt,
1506 const struct s_ball *up,
1507 const struct s_side *sp,
1513 /* If the ball is not behind the plane, the test passes. */
1517 if (v_dot(q, sp->n) - sp->d + up->r >= 0)
1520 /* if the ball is behind the plane but will hit before dt, test passes. */
1522 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1525 /* If the ball is behind but moving toward the plane, test passes. */
1527 if (v_dot(up->v, sp->n) > 0)
1531 /* Else, test fails. */
1536 static float sol_test_back(float dt,
1537 const struct s_ball *up,
1538 const struct s_side *sp,
1544 /* If the ball is not in front of the plane, the test passes. */
1548 if (v_dot(q, sp->n) - sp->d - up->r <= 0)
1551 /* if the ball is behind the plane but will hit before dt, test passes. */
1553 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1556 /* If the ball is in front but moving toward the plane, test passes. */
1558 if (v_dot(up->v, sp->n) < 0)
1562 /* Else, test fails. */
1567 /*---------------------------------------------------------------------------*/
1569 static float sol_test_lump(float dt,
1571 const struct s_ball *up,
1572 const struct s_file *fp,
1573 const struct s_lump *lp,
1577 float U[3], u, t = dt;
1580 /* Short circuit a non-solid lump. */
1582 if (lp->fl & L_DETAIL) return t;
1584 /* Test all verts */
1587 for (i = 0; i < lp->vc; i++)
1589 const struct s_vert *vp = fp->vv + fp->iv[lp->v0 + i];
1591 if ((u = sol_test_vert(t, U, up, vp, o, w)) < t)
1598 /* Test all edges */
1601 for (i = 0; i < lp->ec; i++)
1603 const struct s_edge *ep = fp->ev + fp->iv[lp->e0 + i];
1605 if ((u = sol_test_edge(t, U, up, fp, ep, o, w)) < t)
1612 /* Test all sides */
1614 for (i = 0; i < lp->sc; i++)
1616 const struct s_side *sp = fp->sv + fp->iv[lp->s0 + i];
1618 if ((u = sol_test_side(t, U, up, fp, lp, sp, o, w)) < t)
1627 static float sol_test_node(float dt,
1629 const struct s_ball *up,
1630 const struct s_file *fp,
1631 const struct s_node *np,
1635 float U[3], u, t = dt;
1638 /* Test all lumps */
1640 for (i = 0; i < np->lc; i++)
1642 const struct s_lump *lp = fp->lv + np->l0 + i;
1644 if ((u = sol_test_lump(t, U, up, fp, lp, o, w)) < t)
1651 /* Test in front of this node */
1653 if (np->ni >= 0 && sol_test_fore(t, up, fp->sv + np->si, o, w))
1655 const struct s_node *nq = fp->nv + np->ni;
1657 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1664 /* Test behind this node */
1666 if (np->nj >= 0 && sol_test_back(t, up, fp->sv + np->si, o, w))
1668 const struct s_node *nq = fp->nv + np->nj;
1670 if ((u = sol_test_node(t, U, up, fp, nq, o, w)) < t)
1680 static float sol_test_body(float dt,
1681 float T[3], float V[3],
1682 const struct s_ball *up,
1683 const struct s_file *fp,
1684 const struct s_body *bp)
1686 float U[3], O[3], W[3], u, t = dt;
1688 const struct s_node *np = fp->nv + bp->ni;
1690 sol_body_p(O, fp, bp);
1691 sol_body_v(W, fp, bp);
1693 if ((u = sol_test_node(t, U, up, fp, np, O, W)) < t)
1702 static float sol_test_file(float dt,
1703 float T[3], float V[3],
1704 const struct s_ball *up,
1705 const struct s_file *fp)
1707 float U[3], W[3], u, t = dt;
1710 for (i = 0; i < fp->bc; i++)
1712 const struct s_body *bp = fp->bv + i;
1714 if ((u = sol_test_body(t, U, W, up, fp, bp)) < t)
1724 /*---------------------------------------------------------------------------*/
1727 * Step the physics forward DT seconds under the influence of gravity
1728 * vector G. If the ball gets pinched between two moving solids, this
1729 * loop might not terminate. It is better to do something physically
1730 * impossible than to lock up the game. So, if we make more than C
1731 * iterations, punt it.
1734 float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
1736 float P[3], V[3], v[3], r[3], d, e, nt, b = 0.0f, tt = dt;
1741 struct s_ball *up = fp->uv + ui;
1743 /* If the ball is in contact with a surface, apply friction. */
1748 if (m && sol_test_file(tt, P, V, up, fp) < 0.0005f)
1753 if ((d = v_dot(r, g) / (v_len(r) * v_len(g))) > 0.999f)
1755 if ((e = (v_len(up->v) - dt)) > 0.0f)
1757 /* Scale the linear velocity. */
1759 v_nrm(up->v, up->v);
1760 v_scl(up->v, up->v, e);
1762 /* Scale the angular velocity. */
1766 v_scl(up->w, up->w, -1.0f / (up->r * up->r));
1770 /* Friction has brought the ball to a stop. */
1779 else v_mad(up->v, v, g, tt);
1781 else v_mad(up->v, v, g, tt);
1783 /* Test for collision. */
1785 while (c > 0 && tt > 0 && tt > (nt = sol_test_file(tt, P, V, up, fp)))
1787 sol_body_step(fp, nt);
1788 sol_swch_step(fp, nt);
1789 sol_ball_step(fp, nt);
1793 if (b < (d = sol_bounce(up, P, V, nt)))
1799 sol_body_step(fp, tt);
1800 sol_swch_step(fp, tt);
1801 sol_ball_step(fp, tt);
1806 /*---------------------------------------------------------------------------*/
1808 int sol_coin_test(struct s_file *fp, float *p, float coin_r)
1810 const float *ball_p = fp->uv->p;
1811 const float ball_r = fp->uv->r;
1814 for (ci = 0; ci < fp->cc; ci++)
1818 r[0] = ball_p[0] - fp->cv[ci].p[0];
1819 r[1] = ball_p[1] - fp->cv[ci].p[1];
1820 r[2] = ball_p[2] - fp->cv[ci].p[2];
1822 if (fp->cv[ci].n > 0 && v_len(r) < ball_r + coin_r)
1824 p[0] = fp->cv[ci].p[0];
1825 p[1] = fp->cv[ci].p[1];
1826 p[2] = fp->cv[ci].p[2];
1837 int sol_goal_test(struct s_file *fp, float *p, int ui)
1839 const float *ball_p = fp->uv[ui].p;
1840 const float ball_r = fp->uv[ui].r;
1843 for (zi = 0; zi < fp->zc; zi++)
1847 r[0] = ball_p[0] - fp->zv[zi].p[0];
1848 r[1] = ball_p[2] - fp->zv[zi].p[2];
1851 if (v_len(r) < fp->zv[zi].r * 1.1 - ball_r &&
1852 ball_p[1] > fp->zv[zi].p[1] &&
1853 ball_p[1] < fp->zv[zi].p[1] + GOAL_HEIGHT / 2)
1855 p[0] = fp->zv[zi].p[0];
1856 p[1] = fp->zv[zi].p[1];
1857 p[2] = fp->zv[zi].p[2];
1865 int sol_jump_test(struct s_file *fp, float *p, int ui)
1867 const float *ball_p = fp->uv[ui].p;
1868 const float ball_r = fp->uv[ui].r;
1871 for (ji = 0; ji < fp->jc; ji++)
1875 r[0] = ball_p[0] - fp->jv[ji].p[0];
1876 r[1] = ball_p[2] - fp->jv[ji].p[2];
1879 if (v_len(r) < fp->jv[ji].r - ball_r &&
1880 ball_p[1] > fp->jv[ji].p[1] &&
1881 ball_p[1] < fp->jv[ji].p[1] + JUMP_HEIGHT / 2)
1883 p[0] = fp->jv[ji].q[0] + (ball_p[0] - fp->jv[ji].p[0]);
1884 p[1] = fp->jv[ji].q[1] + (ball_p[1] - fp->jv[ji].p[1]);
1885 p[2] = fp->jv[ji].q[2] + (ball_p[2] - fp->jv[ji].p[2]);
1893 int sol_swch_test(struct s_file *fp, int flag, int ui)
1895 const float *ball_p = fp->uv[ui].p;
1896 const float ball_r = fp->uv[ui].r;
1900 for (xi = 0; xi < fp->xc; xi++)
1902 struct s_swch *xp = fp->xv + xi;
1904 if (xp->t0 == 0 || xp->f == xp->f0)
1908 r[0] = ball_p[0] - xp->p[0];
1909 r[1] = ball_p[2] - xp->p[2];
1912 if (v_len(r) < xp->r - ball_r &&
1913 ball_p[1] > xp->p[1] &&
1914 ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
1921 /* Toggle the state, update the path. */
1923 xp->f = xp->f ? 0 : 1;
1925 do /* Tortoise and hare cycle traverser. */
1927 fp->pv[pi].f = xp->f;
1928 fp->pv[pj].f = xp->f;
1936 /* It toggled to non-default state, start the timer. */
1938 if (xp->f != xp->f0)
1948 /*---------------------------------------------------------------------------*/
1950 void put_file_state(FILE *fout, struct s_file *fp)
1952 /* Write the position and orientation of the ball. */
1954 put_array(fout, fp->uv[0].p, 3);
1955 put_array(fout, fp->uv[0].e[0], 3);
1956 put_array(fout, fp->uv[0].e[1], 3);
1959 void get_file_state(FILE *fin, struct s_file *fp)
1961 /* Read the position and orientation of the ball. */
1963 get_array(fin, fp->uv[0].p, 3);
1964 get_array(fin, fp->uv[0].e[0], 3);
1965 get_array(fin, fp->uv[0].e[1], 3);
1967 /* Compute the 3rd vector of the ball orientatian basis. */
1969 v_crs(fp->uv[0].e[2], fp->uv[0].e[0], fp->uv[0].e[1]);
1972 /*---------------------------------------------------------------------------*/