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 short sol_enum_mtrl(const struct s_file
*fp
,
93 const struct s_body
*bp
, short mi
)
97 /* Count all lump geoms with this material. */
99 for (li
= 0; li
< bp
->lc
; li
++)
101 short g0
= fp
->lv
[bp
->l0
+ li
].g0
;
102 short 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 short sol_enum_body(const struct s_file
*fp
,
119 const struct s_body
*bp
, short 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 * The following code renders a body in a ludicrously inefficient
135 * manner. It iterates the materials and scans the data structure for
136 * geometry using each. This has the effect of absolutely minimizing
137 * material changes, texture bindings, and Begin/End pairs, but
138 * maximizing trips through the data.
140 * However, this is only done once for each level. The results are
141 * stored in display lists. Thus, it is well worth it.
144 static void sol_draw_mtrl(const struct s_file
*fp
, short i
)
146 const struct s_mtrl
*mp
= fp
->mv
+ i
;
148 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT
, mp
->a
);
149 glMaterialfv(GL_FRONT_AND_BACK
, GL_DIFFUSE
, mp
->d
);
150 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, mp
->s
);
151 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, mp
->e
);
152 glMaterialfv(GL_FRONT_AND_BACK
, GL_SHININESS
, mp
->h
);
154 if (mp
->fl
& M_ENVIRONMENT
)
156 glEnable(GL_TEXTURE_GEN_S
);
157 glEnable(GL_TEXTURE_GEN_T
);
159 glBindTexture(GL_TEXTURE_2D
, mp
->o
);
161 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
162 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
166 glDisable(GL_TEXTURE_GEN_S
);
167 glDisable(GL_TEXTURE_GEN_T
);
169 glBindTexture(GL_TEXTURE_2D
, mp
->o
);
172 if (mp
->fl
& M_ADDITIVE
)
173 glBlendFunc(GL_ONE
, GL_ONE
);
175 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
179 static void sol_draw_geom(const struct s_file
*fp
,
180 const struct s_geom
*gp
, short mi
, int s
)
184 const float *ui
= fp
->tv
[gp
->ti
].u
;
185 const float *uj
= fp
->tv
[gp
->tj
].u
;
186 const float *uk
= fp
->tv
[gp
->tk
].u
;
188 const float *ni
= fp
->sv
[gp
->si
].n
;
189 const float *nj
= fp
->sv
[gp
->sj
].n
;
190 const float *nk
= fp
->sv
[gp
->sk
].n
;
192 const float *vi
= fp
->vv
[gp
->vi
].p
;
193 const float *vj
= fp
->vv
[gp
->vj
].p
;
194 const float *vk
= fp
->vv
[gp
->vk
].p
;
198 glMultiTexCoord2f(GL_TEXTURE0
, ui
[0], ui
[1]);
199 glMultiTexCoord2f(GL_TEXTURE1
, vi
[0], vi
[2]);
203 glMultiTexCoord2f(GL_TEXTURE0
, uj
[0], uj
[1]);
204 glMultiTexCoord2f(GL_TEXTURE1
, vj
[0], vj
[2]);
208 glMultiTexCoord2f(GL_TEXTURE0
, uk
[0], uk
[1]);
209 glMultiTexCoord2f(GL_TEXTURE1
, vk
[0], vk
[2]);
230 static void sol_draw_lump(const struct s_file
*fp
,
231 const struct s_lump
*lp
, short mi
, int s
)
235 for (i
= 0; i
< lp
->gc
; i
++)
237 short gi
= fp
->iv
[lp
->g0
+ i
];
239 sol_draw_geom(fp
, fp
->gv
+ gi
, mi
, s
);
243 static void sol_draw_body(const struct s_file
*fp
,
244 const struct s_body
*bp
, short fl
, int s
)
248 /* Iterate all materials of the correct opacity. */
250 for (mi
= 0; mi
< fp
->mc
; mi
++)
251 if (fp
->mv
[mi
].fl
& fl
)
253 if (sol_enum_mtrl(fp
, bp
, mi
))
255 /* Set the material state. */
257 sol_draw_mtrl(fp
, mi
);
259 /* Render all geometry of that material. */
261 glBegin(GL_TRIANGLES
);
263 for (li
= 0; li
< bp
->lc
; li
++)
264 sol_draw_lump(fp
, fp
->lv
+ bp
->l0
+ li
, mi
, s
);
265 for (gi
= 0; gi
< bp
->gc
; gi
++)
266 sol_draw_geom(fp
, fp
->gv
+ fp
->iv
[bp
->g0
+ gi
], mi
, s
);
273 static void sol_draw_bill(const struct s_file
*fp
,
274 const struct s_bill
*rp
, float t
)
276 float T
= fmodf(t
, rp
->t
) - rp
->t
/ 2;
278 float w
= rp
->w
[0] + rp
->w
[1] * T
+ rp
->w
[2] * T
* T
;
279 float h
= rp
->h
[0] + rp
->h
[1] * T
+ rp
->h
[2] * T
* T
;
283 float rx
= rp
->rx
[0] + rp
->rx
[1] * T
+ rp
->rx
[2] * T
* T
;
284 float ry
= rp
->ry
[0] + rp
->ry
[1] * T
+ rp
->ry
[2] * T
* T
;
285 float rz
= rp
->rz
[0] + rp
->rz
[1] * T
+ rp
->rz
[2] * T
* T
;
289 float y0
= (rp
->fl
& B_EDGE
) ? 0 : -h
/ 2;
290 float y1
= (rp
->fl
& B_EDGE
) ? h
: +h
/ 2;
292 glRotatef(ry
, 0.0f
, 1.0f
, 0.0f
);
293 glRotatef(rx
, 1.0f
, 0.0f
, 0.0f
);
294 glTranslatef(0.0f
, 0.0f
, -rp
->d
);
298 glRotatef(-rx
- 90.0f
, 1.0f
, 0.0f
, 0.0f
);
299 glRotatef(-ry
, 0.0f
, 0.0f
, 1.0f
);
302 glRotatef(-rx
, 1.0f
, 0.0f
, 0.0f
);
304 glRotatef(rz
, 0.0f
, 0.0f
, 1.0f
);
306 sol_draw_mtrl(fp
, rp
->mi
);
310 glTexCoord2f(0.0f
, 1.0f
); glVertex2f(-w
/ 2, y0
);
311 glTexCoord2f(1.0f
, 1.0f
); glVertex2f(+w
/ 2, y0
);
312 glTexCoord2f(1.0f
, 0.0f
); glVertex2f(+w
/ 2, y1
);
313 glTexCoord2f(0.0f
, 0.0f
); glVertex2f(-w
/ 2, y1
);
321 static void sol_draw_list(const struct s_file
*fp
,
322 const struct s_body
*bp
, GLuint list
, int s
)
326 sol_body_p(p
, fp
, bp
);
330 /* Translate a moving body. */
332 glTranslatef(p
[0], p
[1], p
[2]);
334 /* Translate the shadow on a moving body. */
338 glActiveTexture(GL_TEXTURE1
);
339 glMatrixMode(GL_TEXTURE
);
342 glTranslatef(p
[0], p
[2], 0.0f
);
344 glMatrixMode(GL_MODELVIEW
);
345 glActiveTexture(GL_TEXTURE0
);
352 /* Pop the shadow translation. */
356 glActiveTexture(GL_TEXTURE1
);
357 glMatrixMode(GL_TEXTURE
);
361 glMatrixMode(GL_MODELVIEW
);
362 glActiveTexture(GL_TEXTURE0
);
368 /*---------------------------------------------------------------------------*/
370 void sol_back(const struct s_file
*fp
, float n
, float f
, float t
)
374 glPushAttrib(GL_LIGHTING_BIT
| GL_DEPTH_BUFFER_BIT
);
376 /* Render all billboards in the given range. */
378 glDisable(GL_LIGHTING
);
379 glDepthMask(GL_FALSE
);
381 for (ri
= 0; ri
< fp
->rc
; ri
++)
382 if (n
<= fp
->rv
[ri
].d
&& fp
->rv
[ri
].d
< f
)
383 sol_draw_bill(fp
, fp
->rv
+ ri
, t
);
388 void sol_refl(const struct s_file
*fp
, int s
)
392 glPushAttrib(GL_LIGHTING_BIT
);
394 /* Render all reflective geometry into the color and depth buffers. */
397 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
399 for (bi
= 0; bi
< fp
->bc
; bi
++)
401 sol_draw_list(fp
, fp
->bv
+ bi
, fp
->bv
[bi
].rl
, s
);
406 void sol_draw(const struct s_file
*fp
, int s
)
410 glPushAttrib(GL_TEXTURE_BIT
|
412 GL_COLOR_BUFFER_BIT
|
413 GL_DEPTH_BUFFER_BIT
);
415 /* Render all obaque geometry into the color and depth buffers. */
417 for (i
= 0; i
< fp
->bc
; i
++)
419 sol_draw_list(fp
, fp
->bv
+ i
, fp
->bv
[i
].ol
, s
);
421 /* Render all translucent geometry into only the color buffer. */
423 glDepthMask(GL_FALSE
);
426 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
428 for (i
= 0; i
< fp
->bc
; i
++)
430 sol_draw_list(fp
, fp
->bv
+ i
, fp
->bv
[i
].tl
, s
);
435 /*---------------------------------------------------------------------------*/
437 static void sol_load_objects(struct s_file
*fp
, int s
)
441 for (i
= 0; i
< fp
->bc
; i
++)
443 struct s_body
*bp
= fp
->bv
+ i
;
445 /* Draw all opaque geometry. */
447 if (sol_enum_body(fp
, bp
, M_OPAQUE
| M_ENVIRONMENT
))
449 fp
->bv
[i
].ol
= glGenLists(1);
451 glNewList(fp
->bv
[i
].ol
, GL_COMPILE
);
453 sol_draw_body(fp
, fp
->bv
+ i
, M_OPAQUE
| M_ENVIRONMENT
, s
);
457 else fp
->bv
[i
].ol
= 0;
459 /* Draw all translucent geometry. */
461 if (sol_enum_body(fp
, bp
, M_TRANSPARENT
))
463 fp
->bv
[i
].tl
= glGenLists(1);
465 glNewList(fp
->bv
[i
].tl
, GL_COMPILE
);
467 sol_draw_body(fp
, fp
->bv
+ i
, M_TRANSPARENT
, s
);
471 else fp
->bv
[i
].tl
= 0;
473 /* Draw all reflective geometry. */
475 if (sol_enum_body(fp
, bp
, M_REFLECTIVE
))
477 fp
->bv
[i
].rl
= glGenLists(1);
479 glNewList(fp
->bv
[i
].rl
, GL_COMPILE
);
481 sol_draw_body(fp
, fp
->bv
+ i
, M_REFLECTIVE
, s
);
485 else fp
->bv
[i
].rl
= 0;
489 static SDL_Surface
*sol_find_texture(const char *name
, GLenum
*f0
, GLenum
*f1
)
496 strncpy(png
, name
, PATHMAX
); strcat(png
, ".png");
497 strncpy(tga
, name
, PATHMAX
); strcat(tga
, ".tga");
498 strncpy(jpg
, name
, PATHMAX
); strcat(jpg
, ".jpg");
500 /* Prefer a lossless copy of the texture over a lossy compression. */
502 if ((s
= IMG_Load(config_data(png
))))
504 *f0
= (s
->format
->BitsPerPixel
== 32) ? GL_RGBA
: GL_RGB
;
505 *f1
= (s
->format
->BitsPerPixel
== 32) ? GL_RGBA
: GL_RGB
;
508 if ((s
= IMG_Load(config_data(tga
))))
510 *f0
= (s
->format
->BitsPerPixel
== 32) ? GL_RGBA
: GL_RGB
;
511 *f1
= (s
->format
->BitsPerPixel
== 32) ? GL_BGRA
: GL_RGB
; /* swab */
514 if ((s
= IMG_Load(config_data(jpg
))))
516 *f0
= (s
->format
->BitsPerPixel
== 32) ? GL_RGBA
: GL_RGB
;
517 *f1
= (s
->format
->BitsPerPixel
== 32) ? GL_RGBA
: GL_RGB
;
524 static void sol_load_textures(struct s_file
*fp
, int k
)
533 for (i
= 0; i
< fp
->mc
; i
++)
534 if ((s
= sol_find_texture(fp
->mv
[i
].f
, &f0
, &f1
)))
536 glGenTextures(1, &fp
->mv
[i
].o
);
537 glBindTexture(GL_TEXTURE_2D
, fp
->mv
[i
].o
);
541 /* Create a new buffer and copy the scaled image to it. */
543 d
= SDL_CreateRGBSurface(SDL_SWSURFACE
, s
->w
/ k
, s
->h
/ k
,
544 s
->format
->BitsPerPixel
,
545 RMASK
, GMASK
, BMASK
, AMASK
);
552 s
->w
, s
->h
, GL_UNSIGNED_BYTE
, s
->pixels
,
553 d
->w
, d
->h
, GL_UNSIGNED_BYTE
, d
->pixels
);
555 SDL_UnlockSurface(d
);
556 SDL_UnlockSurface(s
);
558 /* Load the scaled image. */
560 gluBuild2DMipmaps(GL_TEXTURE_2D
, f0
, d
->w
, d
->h
, f1
,
561 GL_UNSIGNED_BYTE
, d
->pixels
);
567 gluBuild2DMipmaps(GL_TEXTURE_2D
, f0
, s
->w
, s
->h
, f1
,
568 GL_UNSIGNED_BYTE
, s
->pixels
);
570 glTexParameteri(GL_TEXTURE_2D
,
571 GL_TEXTURE_MIN_FILTER
, GL_LINEAR_MIPMAP_LINEAR
);
572 glTexParameteri(GL_TEXTURE_2D
,
573 GL_TEXTURE_MAG_FILTER
, GL_LINEAR_MIPMAP_LINEAR
);
575 if (fp
->mv
[i
].fl
& M_CLAMPED
)
577 glTexParameteri(GL_TEXTURE_2D
,
578 GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
579 glTexParameteri(GL_TEXTURE_2D
,
580 GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
584 glTexParameteri(GL_TEXTURE_2D
,
585 GL_TEXTURE_WRAP_S
, GL_REPEAT
);
586 glTexParameteri(GL_TEXTURE_2D
,
587 GL_TEXTURE_WRAP_T
, GL_REPEAT
);
594 /*---------------------------------------------------------------------------*/
596 static void sol_load_mtrl(FILE *fin
, struct s_mtrl
*mp
)
598 get_array(fin
, mp
->a
, 4);
599 get_array(fin
, mp
->d
, 4);
600 get_array(fin
, mp
->s
, 4);
601 get_array(fin
, mp
->e
, 4);
602 get_array(fin
, mp
->h
, 1);
603 get_short(fin
, &mp
->fl
);
605 fread(mp
->f
, 1, PATHMAX
, fin
);
608 static void sol_load_vert(FILE *fin
, struct s_vert
*vp
)
610 get_array(fin
, vp
->p
, 3);
613 static void sol_load_edge(FILE *fin
, struct s_edge
*ep
)
615 get_short(fin
, &ep
->vi
);
616 get_short(fin
, &ep
->vj
);
619 static void sol_load_side(FILE *fin
, struct s_side
*sp
)
621 get_array(fin
, sp
->n
, 3);
622 get_float(fin
, &sp
->d
);
625 static void sol_load_texc(FILE *fin
, struct s_texc
*tp
)
627 get_array(fin
, tp
->u
, 2);
630 static void sol_load_geom(FILE *fin
, struct s_geom
*gp
)
632 get_short(fin
, &gp
->mi
);
633 get_short(fin
, &gp
->ti
);
634 get_short(fin
, &gp
->si
);
635 get_short(fin
, &gp
->vi
);
636 get_short(fin
, &gp
->tj
);
637 get_short(fin
, &gp
->sj
);
638 get_short(fin
, &gp
->vj
);
639 get_short(fin
, &gp
->tk
);
640 get_short(fin
, &gp
->sk
);
641 get_short(fin
, &gp
->vk
);
644 static void sol_load_lump(FILE *fin
, struct s_lump
*lp
)
646 get_short(fin
, &lp
->fl
);
647 get_short(fin
, &lp
->v0
);
648 get_short(fin
, &lp
->vc
);
649 get_short(fin
, &lp
->e0
);
650 get_short(fin
, &lp
->ec
);
651 get_short(fin
, &lp
->g0
);
652 get_short(fin
, &lp
->gc
);
653 get_short(fin
, &lp
->s0
);
654 get_short(fin
, &lp
->sc
);
657 static void sol_load_node(FILE *fin
, struct s_node
*np
)
659 get_short(fin
, &np
->si
);
660 get_short(fin
, &np
->ni
);
661 get_short(fin
, &np
->nj
);
662 get_short(fin
, &np
->l0
);
663 get_short(fin
, &np
->lc
);
666 static void sol_load_path(FILE *fin
, struct s_path
*pp
)
668 get_array(fin
, pp
->p
, 3);
669 get_float(fin
, &pp
->t
);
670 get_short(fin
, &pp
->pi
);
671 get_short(fin
, &pp
->f
);
674 static void sol_load_body(FILE *fin
, struct s_body
*bp
)
676 get_short(fin
, &bp
->pi
);
677 get_short(fin
, &bp
->ni
);
678 get_short(fin
, &bp
->l0
);
679 get_short(fin
, &bp
->lc
);
680 get_short(fin
, &bp
->g0
);
681 get_short(fin
, &bp
->gc
);
684 static void sol_load_coin(FILE *fin
, struct s_coin
*cp
)
686 get_array(fin
, cp
->p
, 3);
687 get_short(fin
, &cp
->n
);
690 static void sol_load_goal(FILE *fin
, struct s_goal
*zp
)
692 get_array(fin
, zp
->p
, 3);
693 get_float(fin
, &zp
->r
);
696 static void sol_load_swch(FILE *fin
, struct s_swch
*xp
)
698 get_array(fin
, xp
->p
, 3);
699 get_float(fin
, &xp
->r
);
700 get_short(fin
, &xp
->pi
);
701 get_float(fin
, &xp
->t0
);
702 get_float(fin
, &xp
->t
);
703 get_short(fin
, &xp
->f0
);
704 get_short(fin
, &xp
->f
);
707 static void sol_load_bill(FILE *fin
, struct s_bill
*rp
)
709 get_short(fin
, &rp
->fl
);
710 get_short(fin
, &rp
->mi
);
711 get_float(fin
, &rp
->t
);
712 get_float(fin
, &rp
->d
);
713 get_array(fin
, rp
->w
, 3);
714 get_array(fin
, rp
->h
, 3);
715 get_array(fin
, rp
->rx
, 3);
716 get_array(fin
, rp
->ry
, 3);
717 get_array(fin
, rp
->rz
, 3);
720 static void sol_load_jump(FILE *fin
, struct s_jump
*jp
)
722 get_array(fin
, jp
->p
, 3);
723 get_array(fin
, jp
->q
, 3);
724 get_float(fin
, &jp
->r
);
727 static void sol_load_ball(FILE *fin
, struct s_ball
*bp
)
729 get_array(fin
, bp
->e
[0], 3);
730 get_array(fin
, bp
->e
[1], 3);
731 get_array(fin
, bp
->e
[2], 3);
732 get_array(fin
, bp
->p
, 3);
733 get_float(fin
, &bp
->r
);
736 static void sol_load_view(FILE *fin
, struct s_view
*wp
)
738 get_array(fin
, wp
->p
, 3);
739 get_array(fin
, wp
->q
, 3);
742 static void sol_load_file(FILE *fin
, struct s_file
*fp
)
746 get_short(fin
, &fp
->mc
);
747 get_short(fin
, &fp
->vc
);
748 get_short(fin
, &fp
->ec
);
749 get_short(fin
, &fp
->sc
);
750 get_short(fin
, &fp
->tc
);
751 get_short(fin
, &fp
->gc
);
752 get_short(fin
, &fp
->lc
);
753 get_short(fin
, &fp
->nc
);
754 get_short(fin
, &fp
->pc
);
755 get_short(fin
, &fp
->bc
);
756 get_short(fin
, &fp
->cc
);
757 get_short(fin
, &fp
->zc
);
758 get_short(fin
, &fp
->jc
);
759 get_short(fin
, &fp
->xc
);
760 get_short(fin
, &fp
->rc
);
761 get_short(fin
, &fp
->uc
);
762 get_short(fin
, &fp
->wc
);
763 get_short(fin
, &fp
->ic
);
764 get_short(fin
, &fp
->ac
);
766 fp
->mv
= (struct s_mtrl
*) calloc(fp
->mc
, sizeof (struct s_mtrl
));
767 fp
->vv
= (struct s_vert
*) calloc(fp
->vc
, sizeof (struct s_vert
));
768 fp
->ev
= (struct s_edge
*) calloc(fp
->ec
, sizeof (struct s_edge
));
769 fp
->sv
= (struct s_side
*) calloc(fp
->sc
, sizeof (struct s_side
));
770 fp
->tv
= (struct s_texc
*) calloc(fp
->tc
, sizeof (struct s_texc
));
771 fp
->gv
= (struct s_geom
*) calloc(fp
->gc
, sizeof (struct s_geom
));
772 fp
->lv
= (struct s_lump
*) calloc(fp
->lc
, sizeof (struct s_lump
));
773 fp
->nv
= (struct s_node
*) calloc(fp
->nc
, sizeof (struct s_node
));
774 fp
->pv
= (struct s_path
*) calloc(fp
->pc
, sizeof (struct s_path
));
775 fp
->bv
= (struct s_body
*) calloc(fp
->bc
, sizeof (struct s_body
));
776 fp
->cv
= (struct s_coin
*) calloc(fp
->cc
, sizeof (struct s_coin
));
777 fp
->zv
= (struct s_goal
*) calloc(fp
->zc
, sizeof (struct s_goal
));
778 fp
->jv
= (struct s_jump
*) calloc(fp
->jc
, sizeof (struct s_jump
));
779 fp
->xv
= (struct s_swch
*) calloc(fp
->xc
, sizeof (struct s_swch
));
780 fp
->rv
= (struct s_bill
*) calloc(fp
->rc
, sizeof (struct s_bill
));
781 fp
->uv
= (struct s_ball
*) calloc(fp
->uc
, sizeof (struct s_ball
));
782 fp
->wv
= (struct s_view
*) calloc(fp
->wc
, sizeof (struct s_view
));
783 fp
->iv
= (short *) calloc(fp
->ic
, sizeof (short));
784 fp
->av
= (char *) calloc(fp
->ac
, sizeof (char));
786 for (i
= 0; i
< fp
->mc
; i
++) sol_load_mtrl(fin
, fp
->mv
+ i
);
787 for (i
= 0; i
< fp
->vc
; i
++) sol_load_vert(fin
, fp
->vv
+ i
);
788 for (i
= 0; i
< fp
->ec
; i
++) sol_load_edge(fin
, fp
->ev
+ i
);
789 for (i
= 0; i
< fp
->sc
; i
++) sol_load_side(fin
, fp
->sv
+ i
);
790 for (i
= 0; i
< fp
->tc
; i
++) sol_load_texc(fin
, fp
->tv
+ i
);
791 for (i
= 0; i
< fp
->gc
; i
++) sol_load_geom(fin
, fp
->gv
+ i
);
792 for (i
= 0; i
< fp
->lc
; i
++) sol_load_lump(fin
, fp
->lv
+ i
);
793 for (i
= 0; i
< fp
->nc
; i
++) sol_load_node(fin
, fp
->nv
+ i
);
794 for (i
= 0; i
< fp
->pc
; i
++) sol_load_path(fin
, fp
->pv
+ i
);
795 for (i
= 0; i
< fp
->bc
; i
++) sol_load_body(fin
, fp
->bv
+ i
);
796 for (i
= 0; i
< fp
->cc
; i
++) sol_load_coin(fin
, fp
->cv
+ i
);
797 for (i
= 0; i
< fp
->zc
; i
++) sol_load_goal(fin
, fp
->zv
+ i
);
798 for (i
= 0; i
< fp
->jc
; i
++) sol_load_jump(fin
, fp
->jv
+ i
);
799 for (i
= 0; i
< fp
->xc
; i
++) sol_load_swch(fin
, fp
->xv
+ i
);
800 for (i
= 0; i
< fp
->rc
; i
++) sol_load_bill(fin
, fp
->rv
+ i
);
801 for (i
= 0; i
< fp
->uc
; i
++) sol_load_ball(fin
, fp
->uv
+ i
);
802 for (i
= 0; i
< fp
->wc
; i
++) sol_load_view(fin
, fp
->wv
+ i
);
803 for (i
= 0; i
< fp
->ic
; i
++) get_short(fin
, fp
->iv
+ i
);
805 fread(fp
->av
, 1, fp
->ac
, fin
);
808 int sol_load(struct s_file
*fp
, const char *filename
, int k
, int s
)
812 if ((fin
= fopen(filename
, FMODE_RB
)))
814 sol_load_file(fin
, fp
);
815 sol_load_textures(fp
, k
);
816 sol_load_objects (fp
, s
);
825 /*---------------------------------------------------------------------------*/
827 static void sol_stor_mtrl(FILE *fout
, struct s_mtrl
*mp
)
829 put_array(fout
, mp
->a
, 4);
830 put_array(fout
, mp
->d
, 4);
831 put_array(fout
, mp
->s
, 4);
832 put_array(fout
, mp
->e
, 4);
833 put_array(fout
, mp
->h
, 1);
834 put_short(fout
, &mp
->fl
);
836 fwrite(mp
->f
, 1, PATHMAX
, fout
);
839 static void sol_stor_vert(FILE *fout
, struct s_vert
*vp
)
841 put_array(fout
, vp
->p
, 3);
844 static void sol_stor_edge(FILE *fout
, struct s_edge
*ep
)
846 put_short(fout
, &ep
->vi
);
847 put_short(fout
, &ep
->vj
);
850 static void sol_stor_side(FILE *fout
, struct s_side
*sp
)
852 put_array(fout
, sp
->n
, 3);
853 put_float(fout
, &sp
->d
);
856 static void sol_stor_texc(FILE *fout
, struct s_texc
*tp
)
858 put_array(fout
, tp
->u
, 2);
861 static void sol_stor_geom(FILE *fout
, struct s_geom
*gp
)
863 put_short(fout
, &gp
->mi
);
864 put_short(fout
, &gp
->ti
);
865 put_short(fout
, &gp
->si
);
866 put_short(fout
, &gp
->vi
);
867 put_short(fout
, &gp
->tj
);
868 put_short(fout
, &gp
->sj
);
869 put_short(fout
, &gp
->vj
);
870 put_short(fout
, &gp
->tk
);
871 put_short(fout
, &gp
->sk
);
872 put_short(fout
, &gp
->vk
);
875 static void sol_stor_lump(FILE *fout
, struct s_lump
*lp
)
877 put_short(fout
, &lp
->fl
);
878 put_short(fout
, &lp
->v0
);
879 put_short(fout
, &lp
->vc
);
880 put_short(fout
, &lp
->e0
);
881 put_short(fout
, &lp
->ec
);
882 put_short(fout
, &lp
->g0
);
883 put_short(fout
, &lp
->gc
);
884 put_short(fout
, &lp
->s0
);
885 put_short(fout
, &lp
->sc
);
888 static void sol_stor_node(FILE *fout
, struct s_node
*np
)
890 put_short(fout
, &np
->si
);
891 put_short(fout
, &np
->ni
);
892 put_short(fout
, &np
->nj
);
893 put_short(fout
, &np
->l0
);
894 put_short(fout
, &np
->lc
);
897 static void sol_stor_path(FILE *fout
, struct s_path
*pp
)
899 put_array(fout
, pp
->p
, 3);
900 put_float(fout
, &pp
->t
);
901 put_short(fout
, &pp
->pi
);
902 put_short(fout
, &pp
->f
);
905 static void sol_stor_body(FILE *fout
, struct s_body
*bp
)
907 put_short(fout
, &bp
->pi
);
908 put_short(fout
, &bp
->ni
);
909 put_short(fout
, &bp
->l0
);
910 put_short(fout
, &bp
->lc
);
911 put_short(fout
, &bp
->g0
);
912 put_short(fout
, &bp
->gc
);
915 static void sol_stor_coin(FILE *fout
, struct s_coin
*cp
)
917 put_array(fout
, cp
->p
, 3);
918 put_short(fout
, &cp
->n
);
921 static void sol_stor_goal(FILE *fout
, struct s_goal
*zp
)
923 put_array(fout
, zp
->p
, 3);
924 put_float(fout
, &zp
->r
);
927 static void sol_stor_swch(FILE *fout
, struct s_swch
*xp
)
929 put_array(fout
, xp
->p
, 3);
930 put_float(fout
, &xp
->r
);
931 put_short(fout
, &xp
->pi
);
932 put_float(fout
, &xp
->t0
);
933 put_float(fout
, &xp
->t
);
934 put_short(fout
, &xp
->f0
);
935 put_short(fout
, &xp
->f
);
938 static void sol_stor_bill(FILE *fout
, struct s_bill
*rp
)
940 put_short(fout
, &rp
->fl
);
941 put_short(fout
, &rp
->mi
);
942 put_float(fout
, &rp
->t
);
943 put_float(fout
, &rp
->d
);
944 put_array(fout
, rp
->w
, 3);
945 put_array(fout
, rp
->h
, 3);
946 put_array(fout
, rp
->rx
, 3);
947 put_array(fout
, rp
->ry
, 3);
948 put_array(fout
, rp
->rz
, 3);
951 static void sol_stor_jump(FILE *fout
, struct s_jump
*jp
)
953 put_array(fout
, jp
->p
, 3);
954 put_array(fout
, jp
->q
, 3);
955 put_float(fout
, &jp
->r
);
958 static void sol_stor_ball(FILE *fout
, struct s_ball
*bp
)
960 put_array(fout
, bp
->e
[0], 3);
961 put_array(fout
, bp
->e
[1], 3);
962 put_array(fout
, bp
->e
[2], 3);
963 put_array(fout
, bp
->p
, 3);
964 put_float(fout
, &bp
->r
);
967 static void sol_stor_view(FILE *fout
, struct s_view
*wp
)
969 put_array(fout
, wp
->p
, 3);
970 put_array(fout
, wp
->q
, 3);
973 static void sol_stor_file(FILE *fin
, struct s_file
*fp
)
977 put_short(fin
, &fp
->mc
);
978 put_short(fin
, &fp
->vc
);
979 put_short(fin
, &fp
->ec
);
980 put_short(fin
, &fp
->sc
);
981 put_short(fin
, &fp
->tc
);
982 put_short(fin
, &fp
->gc
);
983 put_short(fin
, &fp
->lc
);
984 put_short(fin
, &fp
->nc
);
985 put_short(fin
, &fp
->pc
);
986 put_short(fin
, &fp
->bc
);
987 put_short(fin
, &fp
->cc
);
988 put_short(fin
, &fp
->zc
);
989 put_short(fin
, &fp
->jc
);
990 put_short(fin
, &fp
->xc
);
991 put_short(fin
, &fp
->rc
);
992 put_short(fin
, &fp
->uc
);
993 put_short(fin
, &fp
->wc
);
994 put_short(fin
, &fp
->ic
);
995 put_short(fin
, &fp
->ac
);
997 for (i
= 0; i
< fp
->mc
; i
++) sol_stor_mtrl(fin
, fp
->mv
+ i
);
998 for (i
= 0; i
< fp
->vc
; i
++) sol_stor_vert(fin
, fp
->vv
+ i
);
999 for (i
= 0; i
< fp
->ec
; i
++) sol_stor_edge(fin
, fp
->ev
+ i
);
1000 for (i
= 0; i
< fp
->sc
; i
++) sol_stor_side(fin
, fp
->sv
+ i
);
1001 for (i
= 0; i
< fp
->tc
; i
++) sol_stor_texc(fin
, fp
->tv
+ i
);
1002 for (i
= 0; i
< fp
->gc
; i
++) sol_stor_geom(fin
, fp
->gv
+ i
);
1003 for (i
= 0; i
< fp
->lc
; i
++) sol_stor_lump(fin
, fp
->lv
+ i
);
1004 for (i
= 0; i
< fp
->nc
; i
++) sol_stor_node(fin
, fp
->nv
+ i
);
1005 for (i
= 0; i
< fp
->pc
; i
++) sol_stor_path(fin
, fp
->pv
+ i
);
1006 for (i
= 0; i
< fp
->bc
; i
++) sol_stor_body(fin
, fp
->bv
+ i
);
1007 for (i
= 0; i
< fp
->cc
; i
++) sol_stor_coin(fin
, fp
->cv
+ i
);
1008 for (i
= 0; i
< fp
->zc
; i
++) sol_stor_goal(fin
, fp
->zv
+ i
);
1009 for (i
= 0; i
< fp
->jc
; i
++) sol_stor_jump(fin
, fp
->jv
+ i
);
1010 for (i
= 0; i
< fp
->xc
; i
++) sol_stor_swch(fin
, fp
->xv
+ i
);
1011 for (i
= 0; i
< fp
->rc
; i
++) sol_stor_bill(fin
, fp
->rv
+ i
);
1012 for (i
= 0; i
< fp
->uc
; i
++) sol_stor_ball(fin
, fp
->uv
+ i
);
1013 for (i
= 0; i
< fp
->wc
; i
++) sol_stor_view(fin
, fp
->wv
+ i
);
1014 for (i
= 0; i
< fp
->ic
; i
++) put_short(fin
, fp
->iv
+ i
);
1016 fwrite(fp
->av
, 1, fp
->ac
, fin
);
1019 /*---------------------------------------------------------------------------*/
1021 int sol_stor(struct s_file
*fp
, const char *filename
)
1025 if ((fout
= fopen(filename
, FMODE_WB
)))
1027 sol_stor_file(fout
, fp
);
1035 void sol_free(struct s_file
*fp
)
1039 for (i
= 0; i
< fp
->mc
; i
++)
1041 if (glIsTexture(fp
->mv
[i
].o
))
1042 glDeleteTextures(1, &fp
->mv
[i
].o
);
1045 for (i
= 0; i
< fp
->bc
; i
++)
1047 if (glIsList(fp
->bv
[i
].ol
))
1048 glDeleteLists(fp
->bv
[i
].ol
, 1);
1049 if (glIsList(fp
->bv
[i
].tl
))
1050 glDeleteLists(fp
->bv
[i
].tl
, 1);
1051 if (glIsList(fp
->bv
[i
].rl
))
1052 glDeleteLists(fp
->bv
[i
].rl
, 1);
1055 if (fp
->mv
) free(fp
->mv
);
1056 if (fp
->vv
) free(fp
->vv
);
1057 if (fp
->ev
) free(fp
->ev
);
1058 if (fp
->sv
) free(fp
->sv
);
1059 if (fp
->tv
) free(fp
->tv
);
1060 if (fp
->gv
) free(fp
->gv
);
1061 if (fp
->lv
) free(fp
->lv
);
1062 if (fp
->nv
) free(fp
->nv
);
1063 if (fp
->pv
) free(fp
->pv
);
1064 if (fp
->bv
) free(fp
->bv
);
1065 if (fp
->cv
) free(fp
->cv
);
1066 if (fp
->zv
) free(fp
->zv
);
1067 if (fp
->jv
) free(fp
->jv
);
1068 if (fp
->xv
) free(fp
->xv
);
1069 if (fp
->rv
) free(fp
->rv
);
1070 if (fp
->uv
) free(fp
->uv
);
1071 if (fp
->wv
) free(fp
->wv
);
1072 if (fp
->av
) free(fp
->av
);
1073 if (fp
->iv
) free(fp
->iv
);
1075 memset(fp
, 0, sizeof (struct s_file
));
1078 /*---------------------------------------------------------------------------*/
1079 /* Solves (p + v * t) . (p + v * t) == r * r for smallest t. */
1081 static float v_sol(const float p
[3], const float v
[3], float r
)
1083 float a
= v_dot(v
, v
);
1084 float b
= v_dot(v
, p
) * 2.0f
;
1085 float c
= v_dot(p
, p
) - r
* r
;
1086 float d
= b
* b
- 4.0f
* a
* c
;
1088 if (a
== 0.0f
) return LARGE
;
1089 if (d
< 0.0f
) return LARGE
;
1092 return -b
* 0.5f
/ a
;
1095 float t0
= 0.5f
* (-b
- fsqrtf(d
)) / a
;
1096 float t1
= 0.5f
* (-b
+ fsqrtf(d
)) / a
;
1097 float t
= (t0
< t1
) ? t0
: t1
;
1099 return (t
< 0.0f
) ? LARGE
: t
;
1103 /*---------------------------------------------------------------------------*/
1106 * Compute the earliest time and position of the intersection of a
1107 * sphere and a vertex.
1109 * The sphere has radius R and moves along vector V from point P. The
1110 * vertex moves along vector W from point Q in a coordinate system
1113 static float v_vert(float Q
[3],
1118 const float v
[3], float r
)
1120 float O
[3], P
[3], V
[3];
1127 if (v_dot(P
, V
) < 0.0f
)
1138 * Compute the earliest time and position of the intersection of a
1139 * sphere and an edge.
1141 * The sphere has radius R and moves along vector V from point P. The
1142 * edge moves along vector W from point Q in a coordinate system based
1143 * at O. The edge extends along the length of vector U.
1145 static float v_edge(float Q
[3],
1151 const float v
[3], float r
)
1155 float du
, eu
, uu
, s
, t
;
1165 v_mad(P
, d
, u
, -du
/ uu
);
1166 v_mad(V
, e
, u
, -eu
/ uu
);
1169 s
= (du
+ eu
* t
) / uu
;
1171 if (0.0f
< t
&& t
< LARGE
&& 0.0f
< s
&& s
< 1.0f
)
1184 * Compute the earlist time and position of the intersection of a
1185 * sphere and a plane.
1187 * The sphere has radius R and moves along vector V from point P. The
1188 * plane oves along vector W. The plane has normal N and is
1189 * positioned at distance D from the origin O along that normal.
1191 static float v_side(float Q
[3],
1194 const float n
[3], float d
,
1196 const float v
[3], float r
)
1198 float vn
= v_dot(v
, n
);
1199 float wn
= v_dot(w
, n
);
1202 if (vn
- wn
<= 0.0f
)
1204 float on
= v_dot(o
, n
);
1205 float pn
= v_dot(p
, n
);
1207 float u
= (r
+ d
+ on
- pn
) / (vn
- wn
);
1208 float a
= ( d
+ on
- pn
) / (vn
- wn
);
1228 /*---------------------------------------------------------------------------*/
1231 * Compute the new linear and angular velocities of a bouncing ball.
1232 * Q gives the position of the point of impact and W gives the
1233 * velocity of the object being impacted.
1235 static float sol_bounce(struct s_ball
*up
,
1237 const float w
[3], float dt
)
1239 const float kb
= 1.10f
;
1240 const float ke
= 0.70f
;
1241 const float km
= 0.20f
;
1243 float n
[3], r
[3], d
[3], u
[3], vn
, wn
, xn
, yn
;
1247 /* Find the normal of the impact. */
1253 /* Find the new angular velocity. */
1256 v_scl(up
->w
, up
->w
, -1.0f
/ (up
->r
* up
->r
));
1258 /* Find the new linear velocity. */
1262 xn
= (vn
< 0.0f
) ? -vn
* ke
: vn
;
1263 yn
= (wn
> 0.0f
) ? wn
* kb
: wn
;
1265 v_mad(u
, w
, n
, -wn
);
1266 v_mad(v
, v
, n
, -vn
);
1267 v_mad(v
, v
, u
, +km
* dt
);
1268 v_mad(v
, v
, n
, xn
+ yn
);
1270 v_mad(p
, q
, n
, up
->r
);
1272 /* Return the "energy" of the impact, to determine the sound amplitude. */
1274 return fabsf(v_dot(n
, d
));
1277 /*---------------------------------------------------------------------------*/
1280 * Compute the states of all switches after DT seconds have passed.
1282 static void sol_swch_step(struct s_file
*fp
, float dt
)
1286 for (xi
= 0; xi
< fp
->xc
; xi
++)
1288 struct s_swch
*xp
= fp
->xv
+ xi
;
1299 do /* Tortoise and hare cycle traverser. */
1301 fp
->pv
[pi
].f
= xp
->f0
;
1302 fp
->pv
[pj
].f
= xp
->f0
;
1317 * Compute the positions of all bodies after DT seconds have passed.
1319 static void sol_body_step(struct s_file
*fp
, float dt
)
1323 for (i
= 0; i
< fp
->bc
; i
++)
1325 struct s_body
*bp
= fp
->bv
+ i
;
1326 struct s_path
*pp
= fp
->pv
+ bp
->pi
;
1328 if (bp
->pi
>= 0 && pp
->f
)
1342 * Compute the positions of all balls after DT seconds have passed.
1344 static void sol_ball_step(struct s_file
*fp
, float dt
)
1348 for (i
= 0; i
< fp
->uc
; i
++)
1350 struct s_ball
*up
= fp
->uv
+ i
;
1352 v_mad(up
->p
, up
->p
, up
->v
, dt
);
1354 if (v_len(up
->w
) > 0.0f
)
1361 m_rot(M
, w
, v_len(up
->w
) * dt
);
1363 m_vxfm(e
[0], M
, up
->e
[0]);
1364 m_vxfm(e
[1], M
, up
->e
[1]);
1365 m_vxfm(e
[2], M
, up
->e
[2]);
1367 v_crs(up
->e
[2], e
[0], e
[1]);
1368 v_crs(up
->e
[1], e
[2], e
[0]);
1369 v_crs(up
->e
[0], e
[1], e
[2]);
1371 v_nrm(up
->e
[0], up
->e
[0]);
1372 v_nrm(up
->e
[1], up
->e
[1]);
1373 v_nrm(up
->e
[2], up
->e
[2]);
1378 /*---------------------------------------------------------------------------*/
1380 static float sol_test_vert(float dt
,
1382 const struct s_ball
*up
,
1383 const struct s_vert
*vp
,
1387 return v_vert(T
, o
, vp
->p
, w
, up
->p
, up
->v
, up
->r
);
1390 static float sol_test_edge(float dt
,
1392 const struct s_ball
*up
,
1393 const struct s_file
*fp
,
1394 const struct s_edge
*ep
,
1401 v_cpy(q
, fp
->vv
[ep
->vi
].p
);
1402 v_sub(u
, fp
->vv
[ep
->vj
].p
,
1405 return v_edge(T
, o
, q
, u
, w
, up
->p
, up
->v
, up
->r
);
1408 static float sol_test_side(float dt
,
1410 const struct s_ball
*up
,
1411 const struct s_file
*fp
,
1412 const struct s_lump
*lp
,
1413 const struct s_side
*sp
,
1417 float t
= v_side(T
, o
, w
, sp
->n
, sp
->d
, up
->p
, up
->v
, up
->r
);
1421 for (i
= 0; i
< lp
->sc
; i
++)
1423 const struct s_side
*sq
= fp
->sv
+ fp
->iv
[lp
->s0
+ i
];
1428 v_dot(w
, sq
->n
) * t
> sq
->d
)
1434 /*---------------------------------------------------------------------------*/
1436 static float sol_test_fore(float dt
,
1437 const struct s_ball
*up
,
1438 const struct s_side
*sp
,
1444 /* If the ball is not behind the plane, the test passes. */
1448 if (v_dot(q
, sp
->n
) - sp
->d
+ up
->r
>= 0)
1451 /* if the ball is behind the plane but will hit before dt, test passes. */
1453 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1456 /* If the ball is behind but moving toward the plane, test passes. */
1458 if (v_dot(up
->v
, sp
->n
) > 0)
1462 /* Else, test fails. */
1467 static float sol_test_back(float dt
,
1468 const struct s_ball
*up
,
1469 const struct s_side
*sp
,
1475 /* If the ball is not in front of the plane, the test passes. */
1479 if (v_dot(q
, sp
->n
) - sp
->d
- up
->r
<= 0)
1482 /* if the ball is behind the plane but will hit before dt, test passes. */
1484 if (v_side(q, o, w, sp->n, sp->d, up->p, up->v, up->r) < dt)
1487 /* If the ball is in front but moving toward the plane, test passes. */
1489 if (v_dot(up
->v
, sp
->n
) < 0)
1493 /* Else, test fails. */
1498 /*---------------------------------------------------------------------------*/
1500 static float sol_test_lump(float dt
,
1502 const struct s_ball
*up
,
1503 const struct s_file
*fp
,
1504 const struct s_lump
*lp
,
1508 float U
[3], u
, t
= dt
;
1511 /* Short circuit a non-solid lump. */
1513 if (lp
->fl
& L_DETAIL
) return t
;
1515 /* Test all verts */
1518 for (i
= 0; i
< lp
->vc
; i
++)
1520 const struct s_vert
*vp
= fp
->vv
+ fp
->iv
[lp
->v0
+ i
];
1522 if ((u
= sol_test_vert(t
, U
, up
, vp
, o
, w
)) < t
)
1529 /* Test all edges */
1532 for (i
= 0; i
< lp
->ec
; i
++)
1534 const struct s_edge
*ep
= fp
->ev
+ fp
->iv
[lp
->e0
+ i
];
1536 if ((u
= sol_test_edge(t
, U
, up
, fp
, ep
, o
, w
)) < t
)
1543 /* Test all sides */
1545 for (i
= 0; i
< lp
->sc
; i
++)
1547 const struct s_side
*sp
= fp
->sv
+ fp
->iv
[lp
->s0
+ i
];
1549 if ((u
= sol_test_side(t
, U
, up
, fp
, lp
, sp
, o
, w
)) < t
)
1558 static float sol_test_node(float dt
,
1560 const struct s_ball
*up
,
1561 const struct s_file
*fp
,
1562 const struct s_node
*np
,
1566 float U
[3], u
, t
= dt
;
1569 /* Test all lumps */
1571 for (i
= 0; i
< np
->lc
; i
++)
1573 const struct s_lump
*lp
= fp
->lv
+ np
->l0
+ i
;
1575 if ((u
= sol_test_lump(t
, U
, up
, fp
, lp
, o
, w
)) < t
)
1582 /* Test in front of this node */
1584 if (np
->ni
>= 0 && sol_test_fore(t
, up
, fp
->sv
+ np
->si
, o
, w
))
1586 const struct s_node
*nq
= fp
->nv
+ np
->ni
;
1588 if ((u
= sol_test_node(t
, U
, up
, fp
, nq
, o
, w
)) < t
)
1595 /* Test behind this node */
1597 if (np
->nj
>= 0 && sol_test_back(t
, up
, fp
->sv
+ np
->si
, o
, w
))
1599 const struct s_node
*nq
= fp
->nv
+ np
->nj
;
1601 if ((u
= sol_test_node(t
, U
, up
, fp
, nq
, o
, w
)) < t
)
1611 static float sol_test_body(float dt
,
1612 float T
[3], float V
[3],
1613 const struct s_ball
*up
,
1614 const struct s_file
*fp
,
1615 const struct s_body
*bp
)
1617 float U
[3], O
[3], W
[3], u
, t
= dt
;
1619 const struct s_node
*np
= fp
->nv
+ bp
->ni
;
1621 sol_body_p(O
, fp
, bp
);
1622 sol_body_v(W
, fp
, bp
);
1624 if ((u
= sol_test_node(t
, U
, up
, fp
, np
, O
, W
)) < t
)
1633 static float sol_test_file(float dt
,
1634 float T
[3], float V
[3],
1635 const struct s_ball
*up
,
1636 const struct s_file
*fp
)
1638 float U
[3], W
[3], u
, t
= dt
;
1641 for (i
= 0; i
< fp
->bc
; i
++)
1643 const struct s_body
*bp
= fp
->bv
+ i
;
1645 if ((u
= sol_test_body(t
, U
, W
, up
, fp
, bp
)) < t
)
1655 /*---------------------------------------------------------------------------*/
1658 * Step the physics forward DT seconds under the influence of gravity
1659 * vector G. If the ball gets pinched between two moving solids, this
1660 * loop might not terminate. It is better to do something physically
1661 * impossible than to lock up the game. So, if we make more than C
1662 * iterations, punt it.
1665 float sol_step(struct s_file
*fp
, const float *g
, float dt
, short ui
, int *m
)
1667 float P
[3], V
[3], v
[3], r
[3], d
, e
, nt
, b
= 0.0f
, tt
= dt
;
1672 struct s_ball
*up
= fp
->uv
+ ui
;
1674 /* If the ball is in contact with a surface, apply friction. */
1679 if (m
&& sol_test_file(tt
, P
, V
, up
, fp
) < 0.0005f
)
1684 if ((d
= v_dot(r
, g
) / (v_len(r
) * v_len(g
))) > 0.999f
)
1686 if ((e
= (v_len(up
->v
) - dt
)) > 0.0f
)
1688 /* Scale the linear velocity. */
1690 v_nrm(up
->v
, up
->v
);
1691 v_scl(up
->v
, up
->v
, e
);
1693 /* Scale the angular velocity. */
1697 v_scl(up
->w
, up
->w
, -1.0f
/ (up
->r
* up
->r
));
1701 /* Friction has brought the ball to a stop. */
1710 else v_mad(up
->v
, v
, g
, tt
);
1712 else v_mad(up
->v
, v
, g
, tt
);
1714 /* Test for collision. */
1716 while (c
> 0 && tt
> 0 && tt
> (nt
= sol_test_file(tt
, P
, V
, up
, fp
)))
1718 sol_body_step(fp
, nt
);
1719 sol_swch_step(fp
, nt
);
1720 sol_ball_step(fp
, nt
);
1724 if (b
< (d
= sol_bounce(up
, P
, V
, nt
)))
1730 sol_body_step(fp
, tt
);
1731 sol_swch_step(fp
, tt
);
1732 sol_ball_step(fp
, tt
);
1737 /*---------------------------------------------------------------------------*/
1739 int sol_coin_test(struct s_file
*fp
, float *p
, float coin_r
)
1741 const float *ball_p
= fp
->uv
->p
;
1742 const float ball_r
= fp
->uv
->r
;
1745 for (ci
= 0; ci
< fp
->cc
; ci
++)
1749 r
[0] = ball_p
[0] - fp
->cv
[ci
].p
[0];
1750 r
[1] = ball_p
[1] - fp
->cv
[ci
].p
[1];
1751 r
[2] = ball_p
[2] - fp
->cv
[ci
].p
[2];
1753 if (fp
->cv
[ci
].n
> 0 && v_len(r
) < ball_r
+ coin_r
)
1755 p
[0] = fp
->cv
[ci
].p
[0];
1756 p
[1] = fp
->cv
[ci
].p
[1];
1757 p
[2] = fp
->cv
[ci
].p
[2];
1768 int sol_goal_test(struct s_file
*fp
, float *p
, short ui
)
1770 const float *ball_p
= fp
->uv
[ui
].p
;
1771 const float ball_r
= fp
->uv
[ui
].r
;
1774 for (zi
= 0; zi
< fp
->zc
; zi
++)
1778 r
[0] = ball_p
[0] - fp
->zv
[zi
].p
[0];
1779 r
[1] = ball_p
[2] - fp
->zv
[zi
].p
[2];
1782 if (v_len(r
) < fp
->zv
[zi
].r
* 1.1 - ball_r
&&
1783 ball_p
[1] > fp
->zv
[zi
].p
[1] &&
1784 ball_p
[1] < fp
->zv
[zi
].p
[1] + GOAL_HEIGHT
/ 2)
1786 p
[0] = fp
->zv
[zi
].p
[0];
1787 p
[1] = fp
->zv
[zi
].p
[1];
1788 p
[2] = fp
->zv
[zi
].p
[2];
1796 int sol_jump_test(struct s_file
*fp
, float *p
, short ui
)
1798 const float *ball_p
= fp
->uv
[ui
].p
;
1799 const float ball_r
= fp
->uv
[ui
].r
;
1802 for (ji
= 0; ji
< fp
->jc
; ji
++)
1806 r
[0] = ball_p
[0] - fp
->jv
[ji
].p
[0];
1807 r
[1] = ball_p
[2] - fp
->jv
[ji
].p
[2];
1810 if (v_len(r
) < fp
->jv
[ji
].r
- ball_r
&&
1811 ball_p
[1] > fp
->jv
[ji
].p
[1] &&
1812 ball_p
[1] < fp
->jv
[ji
].p
[1] + JUMP_HEIGHT
/ 2)
1814 p
[0] = fp
->jv
[ji
].q
[0] + (ball_p
[0] - fp
->jv
[ji
].p
[0]);
1815 p
[1] = fp
->jv
[ji
].q
[1] + (ball_p
[1] - fp
->jv
[ji
].p
[1]);
1816 p
[2] = fp
->jv
[ji
].q
[2] + (ball_p
[2] - fp
->jv
[ji
].p
[2]);
1824 int sol_swch_test(struct s_file
*fp
, int flag
, short ui
)
1826 const float *ball_p
= fp
->uv
[ui
].p
;
1827 const float ball_r
= fp
->uv
[ui
].r
;
1831 for (xi
= 0; xi
< fp
->xc
; xi
++)
1833 struct s_swch
*xp
= fp
->xv
+ xi
;
1835 if (xp
->t0
== 0 || xp
->f
== xp
->f0
)
1839 r
[0] = ball_p
[0] - xp
->p
[0];
1840 r
[1] = ball_p
[2] - xp
->p
[2];
1843 if (v_len(r
) < xp
->r
- ball_r
&&
1844 ball_p
[1] > xp
->p
[1] &&
1845 ball_p
[1] < xp
->p
[1] + SWCH_HEIGHT
/ 2)
1852 /* Toggle the state, update the path. */
1854 xp
->f
= xp
->f
? 0 : 1;
1856 do /* Tortoise and hare cycle traverser. */
1858 fp
->pv
[pi
].f
= xp
->f
;
1859 fp
->pv
[pj
].f
= xp
->f
;
1867 /* It toggled to non-default state, start the timer. */
1869 if (xp
->f
!= xp
->f0
)
1879 /*---------------------------------------------------------------------------*/
1881 void put_file_state(FILE *fout
, struct s_file
*fp
)
1883 /* Write the position and orientation of the ball. */
1885 put_array(fout
, fp
->uv
[0].p
, 3);
1886 put_array(fout
, fp
->uv
[0].e
[0], 3);
1887 put_array(fout
, fp
->uv
[0].e
[1], 3);
1890 void get_file_state(FILE *fin
, struct s_file
*fp
)
1892 /* Read the position and orientation of the ball. */
1894 get_array(fin
, fp
->uv
[0].p
, 3);
1895 get_array(fin
, fp
->uv
[0].e
[0], 3);
1896 get_array(fin
, fp
->uv
[0].e
[1], 3);
1898 /* Compute the 3rd vector of the ball orientatian basis. */
1900 v_crs(fp
->uv
[0].e
[2], fp
->uv
[0].e
[0], fp
->uv
[0].e
[1]);
1903 /*---------------------------------------------------------------------------*/