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