Clear "paused" flag on delete/keep at Replay Paused screen.
[neverball] / ball / game.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
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.
8  *
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.
13  */
14
15 #include <SDL.h>
16 #include <math.h>
17
18 #include "glext.h"
19 #include "game.h"
20 #include "vec3.h"
21 #include "geom.h"
22 #include "back.h"
23 #include "part.h"
24 #include "image.h"
25 #include "audio.h"
26 #include "solid_gl.h"
27 #include "config.h"
28 #include "binary.h"
29 #include "level.h"
30
31 /*---------------------------------------------------------------------------*/
32
33 static int game_state = 0;
34
35 static struct s_file file;
36 static struct s_file back;
37
38 static float clock      = 0.f;          /* Clock time                        */
39 static int   clock_down = 1;            /* Clock go up or down?              */
40
41 static float game_ix;                   /* Input rotation about X axis       */
42 static float game_iz;                   /* Input rotation about Z axis       */
43 static float game_rx;                   /* Floor rotation about X axis       */
44 static float game_rz;                   /* Floor rotation about Z axis       */
45
46 static float view_a;                    /* Ideal view rotation about Y axis  */
47 static float view_ry;                   /* Angular velocity about Y axis     */
48 static float view_dc;                   /* Ideal view distance above ball    */
49 static float view_dp;                   /* Ideal view distance above ball    */
50 static float view_dz;                   /* Ideal view distance behind ball   */
51 static float view_fov;                  /* Field of view                     */
52
53 static float view_c[3];                 /* Current view center               */
54 static float view_v[3];                 /* Current view vector               */
55 static float view_p[3];                 /* Current view position             */
56 static float view_e[3][3];              /* Current view orientation          */
57 static float view_k;
58
59 static int   coins  = 0;                /* Collected coins                   */
60 static int   goal_c = 0;                /* Goal coins remaining (0 = open)   */
61 static float goal_k = 0;                /* Goal animation                    */
62 static int   jump_e = 1;                /* Jumping enabled flag              */
63 static int   jump_b = 0;                /* Jump-in-progress flag             */
64 static float jump_dt;                   /* Jump duration                     */
65 static float jump_p[3];                 /* Jump destination                  */
66 static float fade_k = 0.0;              /* Fade in/out level                 */
67 static float fade_d = 0.0;              /* Fade in/out direction             */
68
69 static int   grow = 0;                  /* Should the ball be changing size? */
70 static float grow_orig = 0;             /* the original ball size            */
71 static float grow_goal = 0;             /* how big or small to get!          */
72 static float grow_t = 0.0;              /* timer for the ball to grow...     */
73 static float grow_strt = 0;             /* starting value for growth         */
74 static int   got_orig = 0;              /* Do we know original ball size?    */
75
76 #define GROW_TIME  0.5f                 /* sec for the ball to get to size.  */
77 #define GROW_BIG   1.5f                 /* large factor                      */
78 #define GROW_SMALL 0.5f                 /* small factor                      */
79
80 /*---------------------------------------------------------------------------*/
81
82 static void grow_set(const struct s_file *fp, int type)
83 {
84     if (!got_orig)
85     {
86         grow_orig = fp->uv->r;
87         grow_goal = grow_orig;
88         grow_strt = grow_orig;
89         got_orig  = 1;
90     }
91
92     switch (type)
93     {
94     case ITEM_SHRINK:
95         audio_play(AUD_SHRINK, 1.f);
96
97         if (grow_goal == grow_orig * GROW_SMALL)
98             return;
99         else if (grow_goal == grow_orig * GROW_BIG)
100         {
101             grow_goal = grow_orig;
102             grow = 1;
103         }
104         else
105         {
106             grow_goal = grow_orig * GROW_SMALL;
107             grow = 1;
108         }
109
110         break;
111
112     case ITEM_GROW:
113         audio_play(AUD_GROW, 1.f);
114
115         if (grow_goal == grow_orig * GROW_BIG)
116             return;
117         else if (grow_goal == grow_orig * GROW_SMALL)
118         {
119             grow = 1;
120             grow_goal = grow_orig;
121         }
122         else
123         {
124             grow_goal = grow_orig * GROW_BIG;
125             grow = 1;
126         }
127
128         break;
129
130     default:
131         break;
132     }
133
134     if (grow)
135     {
136         grow_t = 0.0;
137         grow_strt = fp->uv->r;
138     }
139 }
140
141 static void grow_ball(const struct s_file *fp, float dt)
142 {
143     float dr;
144
145     /* Calculate new size based on how long since you touched the coin... */
146
147     grow_t += dt;
148
149     if (grow_t >= GROW_TIME)
150     {
151         grow = 0;
152         grow_t = GROW_TIME;
153     }
154
155     dr = grow_strt + ((grow_goal-grow_strt) * (1.0f / (GROW_TIME / grow_t)));
156
157     /* No sinking through the floor! Keeps ball's bottom constant. */
158     fp->uv->p[1] += (dr - fp->uv->r); 
159     fp->uv->r = dr;
160 }
161
162 static void view_init(void)
163 {
164     view_a  = 0.f;
165     view_ry = 0.f;
166
167     view_fov = (float) config_get_d(CONFIG_VIEW_FOV);
168     view_dp  = (float) config_get_d(CONFIG_VIEW_DP) / 100.0f;
169     view_dc  = (float) config_get_d(CONFIG_VIEW_DC) / 100.0f;
170     view_dz  = (float) config_get_d(CONFIG_VIEW_DZ) / 100.0f;
171     view_k   = 1.0f;
172
173     view_c[0] = 0.f;
174     view_c[1] = view_dc;
175     view_c[2] = 0.f;
176
177     view_p[0] =     0.f;
178     view_p[1] = view_dp;
179     view_p[2] = view_dz;
180
181     view_e[0][0] = 1.f;
182     view_e[0][1] = 0.f;
183     view_e[0][2] = 0.f;
184     view_e[1][0] = 0.f;
185     view_e[1][1] = 1.f;
186     view_e[1][2] = 0.f;
187     view_e[2][0] = 0.f;
188     view_e[2][1] = 0.f;
189     view_e[2][2] = 1.f;
190 }
191
192 int game_init(const struct level *level, int t, int g)
193 {
194     clock      = (float) t / 100.f;
195     clock_down = (t > 0);
196     coins      = 0;
197
198     if (game_state)
199         game_free();
200
201     if (!sol_load_gl(&file, config_data(level->file),
202                      config_get_d(CONFIG_TEXTURES),
203                      config_get_d(CONFIG_SHADOW)))
204         return (game_state = 0);
205
206     game_state = 1;
207
208     game_ix = 0.f;
209     game_iz = 0.f;
210     game_rx = 0.f;
211     game_rz = 0.f;
212
213     /* Initialize jump and goal states. */
214
215     jump_e = 1;
216     jump_b = 0;
217
218     goal_c = g;
219     goal_k = (g == 0) ? 1.0f : 0.0f;
220
221     /* Initialise the level, background, particles, fade, and view. */
222
223     fade_k =  1.0f;
224     fade_d = -2.0f;
225
226     part_reset(GOAL_HEIGHT);
227     view_init();
228     back_init(level->grad, config_get_d(CONFIG_GEOMETRY));
229
230     sol_load_gl(&back, config_data(level->back),
231                 config_get_d(CONFIG_TEXTURES), 0);
232
233     /* Initialize ball size tracking... */
234
235     got_orig = 0;
236     grow = 0;
237
238     return game_state;
239 }
240
241 void game_free(void)
242 {
243     if (game_state)
244     {
245         sol_free_gl(&file);
246         sol_free_gl(&back);
247         back_free();
248     }
249     game_state = 0;
250 }
251
252 /*---------------------------------------------------------------------------*/
253
254 int curr_clock(void)
255 {
256     return (int) (clock * 100.f);
257 }
258
259 int curr_coins(void)
260 {
261     return coins;
262 }
263
264 int curr_goal(void)
265 {
266     return goal_c;
267 }
268
269 /*---------------------------------------------------------------------------*/
270
271 static void game_draw_balls(const struct s_file *fp)
272 {
273     float c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
274     float M[16];
275
276     m_basis(M, fp->uv[0].e[0], fp->uv[0].e[1], fp->uv[0].e[2]);
277
278     glPushMatrix();
279     {
280         glTranslatef(fp->uv[0].p[0],
281                      fp->uv[0].p[1] + BALL_FUDGE,
282                      fp->uv[0].p[2]);
283         glMultMatrixf(M);
284         glScalef(fp->uv[0].r,
285                  fp->uv[0].r,
286                  fp->uv[0].r);
287
288         glColor4fv(c);
289         ball_draw();
290     }
291     glPopMatrix();
292 }
293
294 static void game_draw_items(const struct s_file *fp)
295 {
296     float r = 360.f * SDL_GetTicks() / 1000.f;
297     int hi;
298
299     /* FIXME:  Draw items of different types in one pass? */
300
301     item_push(ITEM_COIN);
302     {
303         for (hi = 0; hi < fp->hc; hi++)
304
305             if (fp->hv[hi].t == ITEM_COIN && fp->hv[hi].n > 0)
306             {
307                 glPushMatrix();
308                 {
309                     glTranslatef(fp->hv[hi].p[0],
310                                  fp->hv[hi].p[1],
311                                  fp->hv[hi].p[2]);
312                     glRotatef(r, 0.0f, 1.0f, 0.0f);
313                     item_draw(&fp->hv[hi], r);
314                 }
315                 glPopMatrix();
316             }
317     }
318     item_pull();
319
320     item_push(ITEM_SHRINK);
321     {
322         for (hi = 0; hi < fp->hc; hi++)
323
324             if (fp->hv[hi].t == ITEM_SHRINK)
325             {
326                 glPushMatrix();
327                 {
328                     glTranslatef(fp->hv[hi].p[0],
329                                  fp->hv[hi].p[1],
330                                  fp->hv[hi].p[2]);
331                     glRotatef(r, 0.0f, 1.0f, 0.0f);
332                     item_draw(&fp->hv[hi], r);
333                 }
334                 glPopMatrix();
335             }
336     }
337     item_pull();
338
339     item_push(ITEM_GROW);
340     {
341         for (hi = 0; hi < fp->hc; hi++)
342
343             if (fp->hv[hi].t == ITEM_GROW)
344             {
345                 glPushMatrix();
346                 {
347                     glTranslatef(fp->hv[hi].p[0],
348                                  fp->hv[hi].p[1],
349                                  fp->hv[hi].p[2]);
350                     glRotatef(r, 0.0f, 1.0f, 0.0f);
351                     item_draw(&fp->hv[hi], r);
352                 }
353                 glPopMatrix();
354             }
355     }
356     item_pull();
357 }
358
359 static void game_draw_goals(const struct s_file *fp, float rx, float ry)
360 {
361     int zi;
362
363     if (goal_c == 0)
364         for (zi = 0; zi < fp->zc; zi++)
365         {
366             glPushMatrix();
367             {
368                 glTranslatef(fp->zv[zi].p[0],
369                              fp->zv[zi].p[1],
370                              fp->zv[zi].p[2]);
371
372                 part_draw_goal(rx, ry, fp->zv[zi].r, goal_k);
373
374                 glScalef(fp->zv[zi].r, goal_k, fp->zv[zi].r);
375                 goal_draw();
376             }
377             glPopMatrix();
378         }
379 }
380
381 static void game_draw_jumps(const struct s_file *fp)
382 {
383     int ji;
384
385     for (ji = 0; ji < fp->jc; ji++)
386     {
387         glPushMatrix();
388         {
389             glTranslatef(fp->jv[ji].p[0],
390                          fp->jv[ji].p[1],
391                          fp->jv[ji].p[2]);
392
393             glScalef(fp->jv[ji].r, 1.f, fp->jv[ji].r);
394             jump_draw(!jump_e);
395         }
396         glPopMatrix();
397     }
398 }
399
400 static void game_draw_swchs(const struct s_file *fp)
401 {
402     int xi;
403
404     for (xi = 0; xi < fp->xc; xi++)
405     {
406         if (fp->xv[xi].i)
407             continue;
408
409         glPushMatrix();
410         {
411             glTranslatef(fp->xv[xi].p[0],
412                          fp->xv[xi].p[1],
413                          fp->xv[xi].p[2]);
414
415             glScalef(fp->xv[xi].r, 1.f, fp->xv[xi].r);
416             swch_draw(fp->xv[xi].f, fp->xv[xi].e);
417         }
418         glPopMatrix();
419     }
420 }
421
422 /*---------------------------------------------------------------------------*/
423
424 static void game_refl_all(int s)
425 {
426     const float *ball_p = file.uv->p;
427
428     glPushMatrix();
429     {
430         /* Rotate the environment about the position of the ball. */
431
432         glTranslatef(+ball_p[0], +ball_p[1], +ball_p[2]);
433         glRotatef(-game_rz, view_e[2][0], view_e[2][1], view_e[2][2]);
434         glRotatef(-game_rx, view_e[0][0], view_e[0][1], view_e[0][2]);
435         glTranslatef(-ball_p[0], -ball_p[1], -ball_p[2]);
436
437         /* Draw the floor. */
438
439         sol_refl(&file);
440     }
441     glPopMatrix();
442 }
443
444 /*---------------------------------------------------------------------------*/
445
446 static void game_draw_light(void)
447 {
448     const float light_p[2][4] = {
449         { -8.0f, +32.0f, -8.0f, 0.0f },
450         { +8.0f, +32.0f, +8.0f, 0.0f },
451     };
452     const float light_c[2][4] = {
453         { 1.0f, 0.8f, 0.8f, 1.0f },
454         { 0.8f, 1.0f, 0.8f, 1.0f },
455     };
456
457     /* Configure the lighting. */
458
459     glEnable(GL_LIGHT0);
460     glLightfv(GL_LIGHT0, GL_POSITION, light_p[0]);
461     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_c[0]);
462     glLightfv(GL_LIGHT0, GL_SPECULAR, light_c[0]);
463
464     glEnable(GL_LIGHT1);
465     glLightfv(GL_LIGHT1, GL_POSITION, light_p[1]);
466     glLightfv(GL_LIGHT1, GL_DIFFUSE,  light_c[1]);
467     glLightfv(GL_LIGHT1, GL_SPECULAR, light_c[1]);
468 }
469
470 static void game_draw_back(int pose, int d, const float p[3])
471 {
472     float c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
473     float t = SDL_GetTicks() / 1000.f + 120.0f;
474
475     glPushMatrix();
476     {
477         if (d < 0)
478         {
479             glRotatef(game_rz * 2, view_e[2][0], view_e[2][1], view_e[2][2]);
480             glRotatef(game_rx * 2, view_e[0][0], view_e[0][1], view_e[0][2]);
481         }
482
483         glTranslatef(p[0], p[1], p[2]);
484         glColor4fv(c);
485
486         if (config_get_d(CONFIG_BACKGROUND))
487         {
488             /* Draw all background layers back to front. */
489
490             sol_back(&back, BACK_DIST, FAR_DIST, t);
491             back_draw(0);
492             sol_back(&back, 0, BACK_DIST, t);
493
494             /* Draw all foreground geometry in the background file. */
495
496             sol_draw(&back);
497         }
498         else back_draw(0);
499     }
500     glPopMatrix();
501 }
502
503 static void game_draw_fore(int pose, float rx, float ry, int d, const float p[3])
504 {
505     const float *ball_p = file.uv->p;
506     const float  ball_r = file.uv->r;
507
508     glPushAttrib(GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT);
509     {
510         glPushMatrix();
511         {
512             /* Rotate the environment about the position of the ball. */
513
514             glTranslatef(+ball_p[0], +ball_p[1] * d, +ball_p[2]);
515             glRotatef(-game_rz * d, view_e[2][0], view_e[2][1], view_e[2][2]);
516             glRotatef(-game_rx * d, view_e[0][0], view_e[0][1], view_e[0][2]);
517             glTranslatef(-ball_p[0], -ball_p[1] * d, -ball_p[2]);
518
519             if (d < 0)
520             {
521                 GLdouble e[4];
522
523                 e[0] = +0;
524                 e[1] = +1;
525                 e[2] = +0;
526                 e[3] = -0.00001;
527
528                 glEnable(GL_CLIP_PLANE0);
529                 glClipPlane(GL_CLIP_PLANE0, e);
530             }
531
532             /* Draw the floor. */
533
534             sol_draw(&file);
535
536             if (config_get_d(CONFIG_SHADOW))
537             {
538                 shad_draw_set(ball_p, ball_r);
539                 sol_shad(&file);
540                 shad_draw_clr();
541             }
542
543             /* Draw the game elements. */
544
545             glEnable(GL_BLEND);
546             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
547
548             if (pose == 0)
549             {
550                 part_draw_coin(-rx * d, -ry);
551                 game_draw_items(&file);
552                 game_draw_balls(&file);
553             }
554             game_draw_goals(&file, -rx * d, -ry);
555             game_draw_jumps(&file);
556             game_draw_swchs(&file);
557
558             glDisable(GL_CLIP_PLANE0);
559         }
560         glPopMatrix();
561     }
562     glPopAttrib();
563 }
564
565 void game_draw(int pose, float st)
566 {
567     float fov = view_fov;
568
569     if (jump_b) fov *= 2.f * fabsf(jump_dt - 0.5);
570
571     if (game_state)
572     {
573         config_push_persp(fov, 0.1f, FAR_DIST);
574         glPushMatrix();
575         {
576             float v[3], rx, ry;
577             float pup[3];
578             float pdn[3];
579
580             v_cpy(pup, view_p);
581             v_cpy(pdn, view_p);
582             pdn[1] = -pdn[1];
583
584             /* Compute and apply the view. */
585
586             v_sub(v, view_c, view_p);
587
588             rx = V_DEG(fatan2f(-v[1], fsqrtf(v[0] * v[0] + v[2] * v[2])));
589             ry = V_DEG(fatan2f(+v[0], -v[2])) + st;
590
591             glTranslatef(0.f, 0.f, -v_len(v));
592             glRotatef(rx, 1.f, 0.f, 0.f);
593             glRotatef(ry, 0.f, 1.f, 0.f);
594             glTranslatef(-view_c[0], -view_c[1], -view_c[2]);
595
596             if (config_get_d(CONFIG_REFLECTION))
597             {
598                 /* Draw the mirror only into the stencil buffer. */
599
600                 glDisable(GL_DEPTH_TEST);
601                 glEnable(GL_STENCIL_TEST);
602                 glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
603                 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
604                 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
605
606                 game_refl_all(0);
607
608                 /* Draw the scene reflected into color and depth buffers. */
609
610                 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
611                 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
612                 glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
613                 glEnable(GL_DEPTH_TEST);
614
615                 glFrontFace(GL_CW);
616                 glPushMatrix();
617                 {
618                     glScalef(+1.f, -1.f, +1.f);
619
620                     game_draw_light();
621                     game_draw_back(pose,         -1, pdn);
622                     game_draw_fore(pose, rx, ry, -1, pdn);
623                 }
624                 glPopMatrix();
625                 glFrontFace(GL_CCW);
626
627                 glDisable(GL_STENCIL_TEST);
628             }
629
630             /* Draw the scene normally. */
631
632             game_draw_light();
633             game_refl_all(pose ? 0 : config_get_d(CONFIG_SHADOW));
634             game_draw_back(pose,         +1, pup);
635             game_draw_fore(pose, rx, ry, +1, pup);
636         }
637         glPopMatrix();
638         config_pop_matrix();
639
640         /* Draw the fade overlay. */
641
642         fade_draw(fade_k);
643     }
644 }
645
646 /*---------------------------------------------------------------------------*/
647
648 static void game_update_grav(float h[3], const float g[3])
649 {
650     struct s_file *fp = &file;
651
652     float x[3];
653     float y[3] = { 0.f, 1.f, 0.f };
654     float z[3];
655     float X[16];
656     float Z[16];
657     float M[16];
658
659     /* Compute the gravity vector from the given world rotations. */
660
661     v_sub(z, view_p, fp->uv->p);
662     v_crs(x, y, z);
663     v_crs(z, x, y);
664     v_nrm(x, x);
665     v_nrm(z, z);
666
667     m_rot (Z, z, V_RAD(game_rz));
668     m_rot (X, x, V_RAD(game_rx));
669     m_mult(M, Z, X);
670     m_vxfm(h, M, g);
671 }
672
673 static void game_update_view(float dt)
674 {
675     float dc = view_dc * (jump_b ? 2.0f * fabsf(jump_dt - 0.5f) : 1.0f);
676     float dx = view_ry * dt * 5.0f;
677     float k;
678
679     view_a += view_ry * dt * 90.f;
680
681     /* Center the view about the ball. */
682
683     v_cpy(view_c, file.uv->p);
684     v_inv(view_v, file.uv->v);
685
686     switch (config_get_d(CONFIG_CAMERA))
687     {
688     case 1: /* Camera 1:  Viewpoint chases the ball position. */
689
690         v_sub(view_e[2], view_p, view_c);
691         break;
692
693     case 2: /* Camera 2: View vector is given by view angle. */
694
695         view_e[2][0] = fsinf(V_RAD(view_a));
696         view_e[2][1] = 0.f;
697         view_e[2][2] = fcosf(V_RAD(view_a));
698
699         dx = 0.0f;
700
701         break;
702
703     default: /* Default: View vector approaches the ball velocity vector. */
704
705         k = v_dot(view_v, view_v);
706
707         v_sub(view_e[2], view_p, view_c);
708         v_mad(view_e[2], view_e[2], view_v, k * dt / 4);
709
710         break;
711     }
712
713     /* Orthonormalize the basis of the view in its new position. */
714
715     v_crs(view_e[0], view_e[1], view_e[2]);
716     v_crs(view_e[2], view_e[0], view_e[1]);
717     v_nrm(view_e[0], view_e[0]);
718     v_nrm(view_e[2], view_e[2]);
719
720     /* Compute the new view position. */
721
722     k = 1.0f + v_dot(view_e[2], view_v) / 10.0f;
723
724     view_k = view_k + (k - view_k) * dt;
725
726     if (view_k < 0.5) view_k = 0.5;
727
728     v_cpy(view_p, file.uv->p);
729     v_mad(view_p, view_p, view_e[0], dx      * view_k);
730     v_mad(view_p, view_p, view_e[1], view_dp * view_k);
731     v_mad(view_p, view_p, view_e[2], view_dz * view_k);
732
733     /* Compute the new view center. */
734
735     v_cpy(view_c, file.uv->p);
736     v_mad(view_c, view_c, view_e[1], dc);
737
738     /* Note the current view angle. */
739
740     view_a = V_DEG(fatan2f(view_e[2][0], view_e[2][2]));
741 }
742
743 static void game_update_time(float dt, int b)
744 {
745     if (goal_c == 0 && goal_k < 1.0f)
746         goal_k += dt;
747
748    /* The ticking clock. */
749
750     if (b && clock_down)
751     {
752         if (clock < 600.f)
753             clock -= dt;
754         if (clock < 0.f)
755             clock = 0.f;
756     }
757     else if (b)
758     {
759         clock += dt;
760     }
761 }
762
763 static int game_update_state(int bt)
764 {
765     struct s_file *fp = &file;
766     struct s_goal *zp;
767     struct s_item *hp;
768
769     float p[3];
770     float c[3];
771
772     /* Test for an item. */
773     if (bt && (hp = sol_item_test(fp, p, COIN_RADIUS)))
774     {
775         int sound = AUD_COIN;
776
777         item_color(hp, c);
778         part_burst(p, c);
779
780         grow_set(fp, hp->t);
781
782         if (hp->t == ITEM_COIN)
783         {
784             coins += hp->n;
785
786             /* Check for goal open. */
787             if (goal_c > 0)
788             {
789                 goal_c -= hp->n;
790                 if (goal_c <= 0)
791                 {
792                     sound = AUD_SWITCH;
793                     goal_c = 0;
794                 }
795             }
796         }
797         audio_play(sound, 1.f);
798
799         /* Reset item type. */
800         hp->t = ITEM_NONE;
801     }
802
803     /* Test for a switch. */
804     if (sol_swch_test(fp, 0))
805         audio_play(AUD_SWITCH, 1.f);
806
807     /* Test for a jump. */
808
809     if (jump_e == 1 && jump_b == 0 && sol_jump_test(fp, jump_p, 0) == 1)
810     {
811         jump_b  = 1;
812         jump_e  = 0;
813         jump_dt = 0.f;
814
815         audio_play(AUD_JUMP, 1.f);
816     }
817     if (jump_e == 0 && jump_b == 0 && sol_jump_test(fp, jump_p, 0) == 0)
818         jump_e = 1;
819
820     /* Test for a goal. */
821
822     if (bt && goal_c == 0 && (zp = sol_goal_test(fp, p, 0)))
823     {
824         audio_play(AUD_GOAL, 1.0f);
825         return GAME_GOAL;
826     }
827
828     /* Test for time-out. */
829
830     if (bt && clock_down && clock <= 0.f)
831     {
832         audio_play(AUD_TIME, 1.0f);
833         return GAME_TIME;
834     }
835
836     /* Test for fall-out. */
837
838     if (bt && fp->uv[0].p[1] < fp->vv[0].p[1])
839     {
840         audio_play(AUD_FALL, 1.0f);
841         return GAME_FALL;
842     }
843
844     return GAME_NONE;
845 }
846
847 /*
848  * On  most  hardware, rendering  requires  much  more  computing power  than
849  * physics.  Since  physics takes less time  than graphics, it  make sense to
850  * detach  the physics update  time step  from the  graphics frame  rate.  By
851  * performing multiple physics updates for  each graphics update, we get away
852  * with higher quality physics with little impact on overall performance.
853  *
854  * Toward this  end, we establish a  baseline maximum physics  time step.  If
855  * the measured  frame time  exceeds this  maximum, we cut  the time  step in
856  * half, and  do two updates.  If THIS  time step exceeds the  maximum, we do
857  * four updates.  And  so on.  In this way, the physics  system is allowed to
858  * seek an optimal update rate independent of, yet in integral sync with, the
859  * graphics frame rate.
860  */
861
862 int game_step(const float g[3], float dt, int bt)
863 {
864     struct s_file *fp = &file;
865
866     float h[3];
867     float d = 0.f;
868     float b = 0.f;
869     float t;
870     int i, n = 1;
871
872     if (game_state)
873     {
874         t = dt;
875
876         /* Smooth jittery or discontinuous input. */
877
878         if (t < RESPONSE)
879         {
880             game_rx += (game_ix - game_rx) * t / RESPONSE;
881             game_rz += (game_iz - game_rz) * t / RESPONSE;
882         }
883         else
884         {
885             game_rx = game_ix;
886             game_rz = game_iz;
887         }
888
889         if (grow)
890             grow_ball(fp, dt);
891
892         game_update_grav(h, g);
893         part_step(h, t);
894
895         if (jump_b)
896         {
897             jump_dt += t;
898
899             /* Handle a jump. */
900
901             if (0.5 < jump_dt)
902             {
903                 fp->uv[0].p[0] = jump_p[0];
904                 fp->uv[0].p[1] = jump_p[1];
905                 fp->uv[0].p[2] = jump_p[2];
906             }
907             if (1.f < jump_dt)
908                 jump_b = 0;
909         }
910         else
911         {
912             /* Run the sim. */
913
914             while (t > MAX_DT && n < MAX_DN)
915             {
916                 t /= 2;
917                 n *= 2;
918             }
919
920             for (i = 0; i < n; i++)
921                 if (b < (d = sol_step(fp, h, t, 0, NULL)))
922                     b = d;
923
924             /* Mix the sound of a ball bounce. */
925
926             if (b > 0.5)
927             {
928                 float k = (b - 0.5f) * 2.0f;
929                 
930                 if (got_orig)
931                 {
932                     if      (fp->uv->r > grow_orig) audio_play(AUD_BUMPL, k);
933                     else if (fp->uv->r < grow_orig) audio_play(AUD_BUMPS, k);
934                     else                            audio_play(AUD_BUMPM, k);
935                 }
936                 else audio_play(AUD_BUMPM, k);
937             }
938         }
939
940         game_step_fade(dt);
941         game_update_view(dt);
942         game_update_time(dt, bt);
943
944         return game_update_state(bt);
945     }
946     return GAME_NONE;
947 }
948
949 /*---------------------------------------------------------------------------*/
950
951 void game_no_aa(void)
952 {
953     float max = game_ix * game_ix + game_iz * game_iz;
954     if (max > ANGLE_BOUND * ANGLE_BOUND)
955     {
956         max = ANGLE_BOUND / sqrt(max);
957         game_ix *= max;
958         game_iz *= max;
959     }
960 }
961
962 void game_set_x(int k)
963 {
964     game_ix = -(ANGLE_BOUND) * k / JOY_MAX;
965 #if NO_AA
966     game_no_aa();
967 #endif
968 }
969
970 void game_set_z(int k)
971 {
972     game_iz = +ANGLE_BOUND * k / JOY_MAX;
973 #if NO_AA
974     game_no_aa();
975 #endif
976 }
977
978 void game_set_pos(int x, int y)
979 {
980     game_ix += 40.f * y / config_get_d(CONFIG_MOUSE_SENSE);
981     game_iz += 40.f * x / config_get_d(CONFIG_MOUSE_SENSE);
982
983 #if NO_AA
984     game_no_aa();
985 #else
986     if (game_ix > +ANGLE_BOUND) game_ix = +ANGLE_BOUND;
987     if (game_ix < -ANGLE_BOUND) game_ix = -ANGLE_BOUND;
988     if (game_iz > +ANGLE_BOUND) game_iz = +ANGLE_BOUND;
989     if (game_iz < -ANGLE_BOUND) game_iz = -ANGLE_BOUND;
990 #endif
991 }
992
993 void game_set_rot(float r)
994 {
995     view_ry = r;
996 }
997
998 /*---------------------------------------------------------------------------*/
999
1000 void game_set_fly(float k)
1001 {
1002     struct s_file *fp = &file;
1003
1004     float  x[3] = { 1.f, 0.f, 0.f };
1005     float  y[3] = { 0.f, 1.f, 0.f };
1006     float  z[3] = { 0.f, 0.f, 1.f };
1007     float c0[3] = { 0.f, 0.f, 0.f };
1008     float p0[3] = { 0.f, 0.f, 0.f };
1009     float c1[3] = { 0.f, 0.f, 0.f };
1010     float p1[3] = { 0.f, 0.f, 0.f };
1011     float  v[3];
1012
1013     z[0] = fsinf(V_RAD(view_a));
1014     z[2] = fcosf(V_RAD(view_a));
1015
1016     v_cpy(view_e[0], x);
1017     v_cpy(view_e[1], y);
1018     v_cpy(view_e[2], z);
1019
1020     /* k = 0.0 view is at the ball. */
1021
1022     if (fp->uc > 0)
1023     {
1024         v_cpy(c0, fp->uv[0].p);
1025         v_cpy(p0, fp->uv[0].p);
1026     }
1027
1028     v_mad(p0, p0, y, view_dp);
1029     v_mad(p0, p0, z, view_dz);
1030     v_mad(c0, c0, y, view_dc);
1031
1032     /* k = +1.0 view is s_view 0 */
1033
1034     if (k >= 0 && fp->wc > 0)
1035     {
1036         v_cpy(p1, fp->wv[0].p);
1037         v_cpy(c1, fp->wv[0].q);
1038     }
1039
1040     /* k = -1.0 view is s_view 1 */
1041
1042     if (k <= 0 && fp->wc > 1)
1043     {
1044         v_cpy(p1, fp->wv[1].p);
1045         v_cpy(c1, fp->wv[1].q);
1046     }
1047
1048     /* Interpolate the views. */
1049
1050     v_sub(v, p1, p0);
1051     v_mad(view_p, p0, v, k * k);
1052
1053     v_sub(v, c1, c0);
1054     v_mad(view_c, c0, v, k * k);
1055
1056     /* Orthonormalize the view basis. */
1057
1058     v_sub(view_e[2], view_p, view_c);
1059     v_crs(view_e[0], view_e[1], view_e[2]);
1060     v_crs(view_e[2], view_e[0], view_e[1]);
1061     v_nrm(view_e[0], view_e[0]);
1062     v_nrm(view_e[2], view_e[2]);
1063 }
1064
1065 void game_look(float phi, float theta)
1066 {
1067     view_c[0] = view_p[0] + fsinf(V_RAD(theta)) * fcosf(V_RAD(phi));
1068     view_c[1] = view_p[1] +                       fsinf(V_RAD(phi));
1069     view_c[2] = view_p[2] - fcosf(V_RAD(theta)) * fcosf(V_RAD(phi));
1070 }
1071
1072 /*---------------------------------------------------------------------------*/
1073
1074 void game_kill_fade(void)
1075 {
1076     fade_k = 0.0f;
1077     fade_d = 0.0f;
1078 }
1079
1080 void game_step_fade(float dt)
1081 {
1082     if ((fade_k < 1.0f && fade_d > 0.0f) ||
1083         (fade_k > 0.0f && fade_d < 0.0f))
1084         fade_k += fade_d * dt;
1085
1086     if (fade_k < 0.0f)
1087     {
1088         fade_k = 0.0f;
1089         fade_d = 0.0f;
1090     }
1091     if (fade_k > 1.0f)
1092     {
1093         fade_k = 1.0f;
1094         fade_d = 0.0f;
1095     }
1096 }
1097
1098 void game_fade(float d)
1099 {
1100     fade_d = d;
1101 }
1102
1103 /*---------------------------------------------------------------------------*/
1104
1105 int put_game_state(FILE *fout)
1106 {
1107     if (game_state)
1108     {
1109         /* Write the view and tilt state. */
1110
1111         put_float(fout, &game_rx);
1112         put_float(fout, &game_rz);
1113         put_array(fout,  view_c, 3);
1114         put_array(fout,  view_p, 3);
1115
1116         /* Write the game simulation state. */
1117
1118         put_file_state(fout, &file);
1119
1120         return 1;
1121     }
1122     return 0;
1123 }
1124
1125 int get_game_state(FILE *fin)
1126 {
1127     if (game_state)
1128     {
1129         /* Read the view and tilt state. */
1130
1131         get_float(fin, &game_rx);
1132         get_float(fin, &game_rz);
1133         get_array(fin,  view_c, 3);
1134         get_array(fin,  view_p, 3);
1135
1136         /* Read the game simulation state. */
1137
1138         get_file_state(fin, &file);
1139
1140         return (feof(fin) ? 0 : 1);
1141     }
1142     return 0;
1143 }
1144
1145 /*---------------------------------------------------------------------------*/