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