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.
32 /*---------------------------------------------------------------------------*/
34 static int game_state = 0;
36 static struct s_file file;
37 static struct s_file back;
39 static int reflective; /* Reflective geometry used? */
41 static float timer = 0.f; /* Clock time */
42 static int timer_down = 1; /* Timer go up or down? */
44 static float game_rx; /* Floor rotation about X axis */
45 static float game_rz; /* Floor rotation about Z axis */
47 static float view_a; /* Ideal view rotation 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 */
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 reference frame */
59 static int coins = 0; /* Collected coins */
60 static int goal_e = 0; /* Goal enabled flag */
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 */
69 /*---------------------------------------------------------------------------*/
72 * This is an abstraction of the game's input state. All input is
73 * encapsulated here, and all references to the input by the game are made
74 * here. This has the effect of homogenizing input for use in replay
75 * recording and playback.
78 * -32767 = -ANGLE_BOUND
79 * +32767 = +ANGLE_BOUND
82 * -32767 = -VIEWR_BOUND
83 * +32767 = +VIEWR_BOUND
95 static struct input input_current;
97 static void input_init(void)
105 static void input_set_x(float x)
107 if (x < -ANGLE_BOUND) x = -ANGLE_BOUND;
108 if (x > ANGLE_BOUND) x = ANGLE_BOUND;
110 input_current.x = (short) (32767.0f * x / ANGLE_BOUND);
113 static void input_set_z(float z)
115 if (z < -ANGLE_BOUND) z = -ANGLE_BOUND;
116 if (z > ANGLE_BOUND) z = ANGLE_BOUND;
118 input_current.z = (short) (32767.0f * z / ANGLE_BOUND);
121 static void input_set_r(float r)
123 if (r < -VIEWR_BOUND) r = -VIEWR_BOUND;
124 if (r > VIEWR_BOUND) r = VIEWR_BOUND;
126 input_current.r = (short) (32767.0f * r / VIEWR_BOUND);
129 static void input_set_c(int c)
131 input_current.c = (short) c;
134 static float input_get_x(void)
136 return ANGLE_BOUND * (float) input_current.x / 32767.0f;
139 static float input_get_z(void)
141 return ANGLE_BOUND * (float) input_current.z / 32767.0f;
144 static float input_get_r(void)
146 return VIEWR_BOUND * (float) input_current.r / 32767.0f;
149 static int input_get_c(void)
151 return (int) input_current.c;
154 int input_put(FILE *fout)
158 put_short(fout, &input_current.x);
159 put_short(fout, &input_current.z);
160 put_short(fout, &input_current.r);
161 put_short(fout, &input_current.c);
168 int input_get(FILE *fin)
172 get_short(fin, &input_current.x);
173 get_short(fin, &input_current.z);
174 get_short(fin, &input_current.r);
175 get_short(fin, &input_current.c);
177 return (feof(fin) ? 0 : 1);
182 /*---------------------------------------------------------------------------*/
184 static int grow = 0; /* Should the ball be changing size? */
185 static float grow_orig = 0; /* the original ball size */
186 static float grow_goal = 0; /* how big or small to get! */
187 static float grow_t = 0.0; /* timer for the ball to grow... */
188 static float grow_strt = 0; /* starting value for growth */
189 static int got_orig = 0; /* Do we know original ball size? */
191 #define GROW_TIME 0.5f /* sec for the ball to get to size. */
192 #define GROW_BIG 1.5f /* large factor */
193 #define GROW_SMALL 0.5f /* small factor */
195 static int grow_state = 0; /* Current state (values -1, 0, +1) */
197 static void grow_init(const struct s_file *fp, int type)
201 grow_orig = fp->uv->r;
202 grow_goal = grow_orig;
203 grow_strt = grow_orig;
210 if (type == ITEM_SHRINK)
218 audio_play(AUD_SHRINK, 1.f);
219 grow_goal = grow_orig * GROW_SMALL;
225 audio_play(AUD_SHRINK, 1.f);
226 grow_goal = grow_orig;
232 else if (type == ITEM_GROW)
237 audio_play(AUD_GROW, 1.f);
238 grow_goal = grow_orig;
244 audio_play(AUD_GROW, 1.f);
245 grow_goal = grow_orig * GROW_BIG;
258 grow_strt = fp->uv->r;
262 static void grow_step(const struct s_file *fp, float dt)
269 /* Calculate new size based on how long since you touched the coin... */
273 if (grow_t >= GROW_TIME)
279 dr = grow_strt + ((grow_goal-grow_strt) * (1.0f / (GROW_TIME / grow_t)));
281 /* No sinking through the floor! Keeps ball's bottom constant. */
283 fp->uv->p[1] += (dr - fp->uv->r);
287 /*---------------------------------------------------------------------------*/
289 static void view_init(void)
291 view_fov = (float) config_get_d(CONFIG_VIEW_FOV);
292 view_dp = (float) config_get_d(CONFIG_VIEW_DP) / 100.0f;
293 view_dc = (float) config_get_d(CONFIG_VIEW_DC) / 100.0f;
294 view_dz = (float) config_get_d(CONFIG_VIEW_DZ) / 100.0f;
317 int game_init(const char *file_name, int t, int e)
319 char *back_name = NULL, *grad_name = NULL;
323 timer = (float) t / 100.f;
324 timer_down = (t > 0);
330 if (!sol_load_gl(&file, config_data(file_name),
331 config_get_d(CONFIG_TEXTURES),
332 config_get_d(CONFIG_SHADOW)))
333 return (game_state = 0);
335 reflective = sol_reflective(&file);
344 /* Initialize jump and goal states. */
350 goal_k = e ? 1.0f : 0.0f;
352 /* Initialise the level, background, particles, fade, and view. */
357 for (i = 0; i < file.dc; i++)
359 char *k = file.av + file.dv[i].ai;
360 char *v = file.av + file.dv[i].aj;
362 if (strcmp(k, "back") == 0) back_name = v;
363 if (strcmp(k, "grad") == 0) grad_name = v;
366 part_reset(GOAL_HEIGHT);
368 back_init(grad_name, config_get_d(CONFIG_GEOMETRY));
370 sol_load_gl(&back, config_data(back_name),
371 config_get_d(CONFIG_TEXTURES), 0);
373 /* Initialize ball size tracking... */
392 /*---------------------------------------------------------------------------*/
396 return (int) (timer * 100.f);
404 /*---------------------------------------------------------------------------*/
406 static void game_draw_balls(const struct s_file *fp,
407 const float *bill_M, float t)
409 float c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
414 m_basis(ball_M, fp->uv[0].e[0], fp->uv[0].e[1], fp->uv[0].e[2]);
415 m_basis(pend_M, fp->uv[0].E[0], fp->uv[0].E[1], fp->uv[0].E[2]);
417 glPushAttrib(GL_LIGHTING_BIT);
420 glTranslatef(fp->uv[0].p[0],
421 fp->uv[0].p[1] + BALL_FUDGE,
423 glScalef(fp->uv[0].r,
428 ball_draw(ball_M, pend_M, bill_M, t);
434 static void game_draw_items(const struct s_file *fp, float t)
439 glPushAttrib(GL_LIGHTING_BIT);
441 item_push(ITEM_COIN);
443 for (hi = 0; hi < fp->hc; hi++)
445 if (fp->hv[hi].t == ITEM_COIN && fp->hv[hi].n > 0)
449 glTranslatef(fp->hv[hi].p[0],
452 glRotatef(r, 0.0f, 1.0f, 0.0f);
453 item_draw(&fp->hv[hi], r);
460 item_push(ITEM_SHRINK);
462 for (hi = 0; hi < fp->hc; hi++)
464 if (fp->hv[hi].t == ITEM_SHRINK)
468 glTranslatef(fp->hv[hi].p[0],
471 glRotatef(r, 0.0f, 1.0f, 0.0f);
472 item_draw(&fp->hv[hi], r);
479 item_push(ITEM_GROW);
481 for (hi = 0; hi < fp->hc; hi++)
483 if (fp->hv[hi].t == ITEM_GROW)
487 glTranslatef(fp->hv[hi].p[0],
490 glRotatef(r, 0.0f, 1.0f, 0.0f);
491 item_draw(&fp->hv[hi], r);
501 static void game_draw_goals(const struct s_file *fp, const float *M, float t)
507 /* Draw the goal particles. */
509 glEnable(GL_TEXTURE_2D);
511 for (zi = 0; zi < fp->zc; zi++)
515 glTranslatef(fp->zv[zi].p[0],
519 part_draw_goal(M, fp->zv[zi].r, goal_k, t);
524 glDisable(GL_TEXTURE_2D);
526 /* Draw the goal column. */
528 for (zi = 0; zi < fp->zc; zi++)
532 glTranslatef(fp->zv[zi].p[0],
536 glScalef(fp->zv[zi].r,
547 static void game_draw_jumps(const struct s_file *fp)
551 for (ji = 0; ji < fp->jc; ji++)
555 glTranslatef(fp->jv[ji].p[0],
558 glScalef(fp->jv[ji].r,
568 static void game_draw_swchs(const struct s_file *fp)
572 for (xi = 0; xi < fp->xc; xi++)
579 glTranslatef(fp->xv[xi].p[0],
582 glScalef(fp->xv[xi].r,
586 swch_draw(fp->xv[xi].f, fp->xv[xi].e);
592 /*---------------------------------------------------------------------------*/
594 static void game_draw_tilt(int d)
596 const float *ball_p = file.uv->p;
598 /* Rotate the environment about the position of the ball. */
600 glTranslatef(+ball_p[0], +ball_p[1] * d, +ball_p[2]);
601 glRotatef(-game_rz * d, view_e[2][0], view_e[2][1], view_e[2][2]);
602 glRotatef(-game_rx * d, view_e[0][0], view_e[0][1], view_e[0][2]);
603 glTranslatef(-ball_p[0], -ball_p[1] * d, -ball_p[2]);
606 static void game_refl_all(void)
612 /* Draw the floor. */
619 /*---------------------------------------------------------------------------*/
621 static void game_draw_light(void)
623 const float light_p[2][4] = {
624 { -8.0f, +32.0f, -8.0f, 0.0f },
625 { +8.0f, +32.0f, +8.0f, 0.0f },
627 const float light_c[2][4] = {
628 { 1.0f, 0.8f, 0.8f, 1.0f },
629 { 0.8f, 1.0f, 0.8f, 1.0f },
632 /* Configure the lighting. */
635 glLightfv(GL_LIGHT0, GL_POSITION, light_p[0]);
636 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_c[0]);
637 glLightfv(GL_LIGHT0, GL_SPECULAR, light_c[0]);
640 glLightfv(GL_LIGHT1, GL_POSITION, light_p[1]);
641 glLightfv(GL_LIGHT1, GL_DIFFUSE, light_c[1]);
642 glLightfv(GL_LIGHT1, GL_SPECULAR, light_c[1]);
645 static void game_draw_back(int pose, int d, float t)
651 glRotatef(game_rz * 2, view_e[2][0], view_e[2][1], view_e[2][2]);
652 glRotatef(game_rx * 2, view_e[0][0], view_e[0][1], view_e[0][2]);
655 glTranslatef(view_p[0], view_p[1] * d, view_p[2]);
657 if (config_get_d(CONFIG_BACKGROUND))
659 /* Draw all background layers back to front. */
661 sol_back(&back, BACK_DIST, FAR_DIST, t);
663 sol_back(&back, 0, BACK_DIST, t);
670 static void game_clip_refl(int d)
672 /* Fudge to eliminate the floor from reflection. */
674 GLdouble e[4], k = -0.00001;
681 glClipPlane(GL_CLIP_PLANE0, e);
684 static void game_clip_ball(int d, const float *p)
686 GLdouble r, c[3], pz[4], nz[4];
688 /* Compute the plane giving the front of the ball, as seen from view_p. */
694 pz[0] = view_p[0] - c[0];
695 pz[1] = view_p[1] - c[1];
696 pz[2] = view_p[2] - c[2];
698 r = sqrt(pz[0] * pz[0] + pz[1] * pz[1] + pz[2] * pz[2]);
703 pz[3] = -(pz[0] * c[0] +
707 /* Find the plane giving the back of the ball, as seen from view_p. */
714 /* Reflect these planes as necessary, and store them in the GL state. */
719 glClipPlane(GL_CLIP_PLANE1, nz);
720 glClipPlane(GL_CLIP_PLANE2, pz);
723 static void game_draw_fore(int pose, const float *M, int d, float t)
725 const float *ball_p = file.uv->p;
726 const float ball_r = file.uv->r;
730 /* Rotate the environment about the position of the ball. */
734 /* Compute clipping planes for reflection and ball facing. */
737 game_clip_ball(d, ball_p);
740 glEnable(GL_CLIP_PLANE0);
743 sol_draw(&file, 0, 1);
746 /* Draw the coins. */
748 game_draw_items(&file, t);
750 /* Draw the floor. */
752 sol_draw(&file, 0, 1);
754 /* Draw the ball shadow. */
756 if (d > 0 && config_get_d(CONFIG_SHADOW))
758 shad_draw_set(ball_p, ball_r);
765 game_draw_balls(&file, M, t);
768 /* Draw the particles and light columns. */
770 glEnable(GL_COLOR_MATERIAL);
771 glDisable(GL_LIGHTING);
772 glDepthMask(GL_FALSE);
774 glColor3f(1.0f, 1.0f, 1.0f);
776 sol_bill(&file, M, t);
777 part_draw_coin(M, t);
779 glDisable(GL_TEXTURE_2D);
781 game_draw_goals(&file, M, t);
782 game_draw_jumps(&file);
783 game_draw_swchs(&file);
785 glEnable(GL_TEXTURE_2D);
787 glColor3f(1.0f, 1.0f, 1.0f);
789 glDepthMask(GL_TRUE);
790 glEnable(GL_LIGHTING);
791 glDisable(GL_COLOR_MATERIAL);
794 glDisable(GL_CLIP_PLANE0);
799 void game_draw(int pose, float t)
801 float fov = view_fov;
803 if (jump_b) fov *= 2.f * fabsf(jump_dt - 0.5);
807 config_push_persp(fov, 0.1f, FAR_DIST);
810 float T[16], U[16], M[16], v[3];
812 /* Compute direct and reflected view bases. */
818 m_view(T, view_c, view_p, view_e[1]);
819 m_view(U, view_c, v, view_e[1]);
823 /* Apply current the view. */
825 v_sub(v, view_c, view_p);
827 glTranslatef(0.f, 0.f, -v_len(v));
829 glTranslatef(-view_c[0], -view_c[1], -view_c[2]);
831 if (reflective && config_get_d(CONFIG_REFLECTION))
833 glEnable(GL_STENCIL_TEST);
835 /* Draw the mirrors only into the stencil buffer. */
837 glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
838 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
839 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
840 glDepthMask(GL_FALSE);
844 glDepthMask(GL_TRUE);
845 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
846 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
847 glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
849 /* Draw the scene reflected into color and depth buffers. */
854 glScalef(+1.0f, -1.0f, +1.0f);
857 game_draw_back(pose, -1, t);
858 game_draw_fore(pose, U, -1, t);
863 glDisable(GL_STENCIL_TEST);
866 /* Draw the scene normally. */
870 game_draw_back(pose, +1, t);
871 game_draw_fore(pose, T, +1, t);
876 /* Draw the fade overlay. */
882 /*---------------------------------------------------------------------------*/
884 static void game_update_grav(float h[3], const float g[3])
887 float y[3] = { 0.0f, 1.0f, 0.0f };
893 /* Compute the gravity vector from the given world rotations. */
895 z[0] = fsinf(V_RAD(view_a));
897 z[2] = fcosf(V_RAD(view_a));
904 m_rot (Z, z, V_RAD(game_rz));
905 m_rot (X, x, V_RAD(game_rx));
910 static void game_update_view(float dt)
912 float dc = view_dc * (jump_b ? 2.0f * fabsf(jump_dt - 0.5f) : 1.0f);
913 float da = input_get_r() * dt * 90.0f;
916 float M[16], v[3], Y[3] = { 0.0f, 1.0f, 0.0f };
920 /* Center the view about the ball. */
922 v_cpy(view_c, file.uv->p);
923 v_inv(view_v, file.uv->v);
925 view_e[2][0] = fsinf(V_RAD(view_a));
927 view_e[2][2] = fcosf(V_RAD(view_a));
929 switch (input_get_c())
931 case 1: /* Camera 1: Viewpoint chases the ball position. */
933 v_sub(view_e[2], view_p, view_c);
937 case 2: /* Camera 2: View vector is given by view angle. */
941 default: /* Default: View vector approaches the ball velocity vector. */
943 v_mad(view_e[2], view_e[2], view_v, v_dot(view_v, view_v) * dt / 4);
948 /* Orthonormalize the new view reference frame. */
950 v_crs(view_e[0], view_e[1], view_e[2]);
951 v_crs(view_e[2], view_e[0], view_e[1]);
952 v_nrm(view_e[0], view_e[0]);
953 v_nrm(view_e[2], view_e[2]);
955 /* Compute the new view position. */
957 k = 1.0f + v_dot(view_e[2], view_v) / 10.0f;
959 view_k = view_k + (k - view_k) * dt;
961 if (view_k < 0.5) view_k = 0.5;
963 v_scl(v, view_e[1], view_dp * view_k);
964 v_mad(v, v, view_e[2], view_dz * view_k);
965 m_rot(M, Y, V_RAD(da));
966 m_vxfm(view_p, M, v);
967 v_add(view_p, view_p, file.uv->p);
969 /* Compute the new view center. */
971 v_cpy(view_c, file.uv->p);
972 v_mad(view_c, view_c, view_e[1], dc);
974 /* Note the current view angle. */
976 view_a = V_DEG(fatan2f(view_e[2][0], view_e[2][2]));
979 static void game_update_time(float dt, int b)
981 if (goal_e && goal_k < 1.0f)
984 /* The ticking clock. */
999 static int game_update_state(int bt)
1001 struct s_file *fp = &file;
1008 /* Test for an item. */
1010 if (bt && (hp = sol_item_test(fp, p, ITEM_RADIUS)))
1015 grow_init(fp, hp->t);
1017 if (hp->t == ITEM_COIN)
1020 audio_play(AUD_COIN, 1.f);
1027 /* Test for a switch. */
1029 if (sol_swch_test(fp, 0))
1030 audio_play(AUD_SWITCH, 1.f);
1032 /* Test for a jump. */
1034 if (jump_e == 1 && jump_b == 0 && sol_jump_test(fp, jump_p, 0) == 1)
1040 audio_play(AUD_JUMP, 1.f);
1042 if (jump_e == 0 && jump_b == 0 && sol_jump_test(fp, jump_p, 0) == 0)
1045 /* Test for a goal. */
1047 if (bt && goal_e && (zp = sol_goal_test(fp, p, 0)))
1049 audio_play(AUD_GOAL, 1.0f);
1053 /* Test for time-out. */
1055 if (bt && timer_down && timer <= 0.f)
1057 audio_play(AUD_TIME, 1.0f);
1061 /* Test for fall-out. */
1063 if (bt && fp->uv[0].p[1] < fp->vv[0].p[1])
1065 audio_play(AUD_FALL, 1.0f);
1072 int game_step(const float g[3], float dt, int bt)
1076 struct s_file *fp = &file;
1080 /* Smooth jittery or discontinuous input. */
1082 game_rx += (input_get_x() - game_rx) * dt / RESPONSE;
1083 game_rz += (input_get_z() - game_rz) * dt / RESPONSE;
1087 game_update_grav(h, g);
1094 /* Handle a jump. */
1098 fp->uv[0].p[0] = jump_p[0];
1099 fp->uv[0].p[1] = jump_p[1];
1100 fp->uv[0].p[2] = jump_p[2];
1109 float b = sol_step(fp, h, dt, 0, NULL);
1111 /* Mix the sound of a ball bounce. */
1115 float k = (b - 0.5f) * 2.0f;
1119 if (fp->uv->r > grow_orig) audio_play(AUD_BUMPL, k);
1120 else if (fp->uv->r < grow_orig) audio_play(AUD_BUMPS, k);
1121 else audio_play(AUD_BUMPM, k);
1123 else audio_play(AUD_BUMPM, k);
1128 game_update_view(dt);
1129 game_update_time(dt, bt);
1131 return game_update_state(bt);
1136 /*---------------------------------------------------------------------------*/
1138 void game_set_goal(void)
1140 audio_play(AUD_SWITCH, 1.0f);
1144 void game_clr_goal(void)
1149 /*---------------------------------------------------------------------------*/
1151 void game_set_x(int k)
1153 input_set_x(-ANGLE_BOUND * k / JOY_MAX);
1156 void game_set_z(int k)
1158 input_set_z(+ANGLE_BOUND * k / JOY_MAX);
1161 void game_set_ang(int x, int z)
1167 void game_set_pos(int x, int y)
1169 input_set_x(input_get_x() + 40.0f * y / config_get_d(CONFIG_MOUSE_SENSE));
1170 input_set_z(input_get_z() + 40.0f * x / config_get_d(CONFIG_MOUSE_SENSE));
1173 void game_set_cam(int c)
1178 void game_set_rot(float r)
1183 /*---------------------------------------------------------------------------*/
1185 void game_set_fly(float k)
1187 struct s_file *fp = &file;
1189 float x[3] = { 1.f, 0.f, 0.f };
1190 float y[3] = { 0.f, 1.f, 0.f };
1191 float z[3] = { 0.f, 0.f, 1.f };
1192 float c0[3] = { 0.f, 0.f, 0.f };
1193 float p0[3] = { 0.f, 0.f, 0.f };
1194 float c1[3] = { 0.f, 0.f, 0.f };
1195 float p1[3] = { 0.f, 0.f, 0.f };
1198 z[0] = fsinf(V_RAD(view_a));
1199 z[2] = fcosf(V_RAD(view_a));
1201 v_cpy(view_e[0], x);
1202 v_cpy(view_e[1], y);
1203 v_cpy(view_e[2], z);
1205 /* k = 0.0 view is at the ball. */
1209 v_cpy(c0, fp->uv[0].p);
1210 v_cpy(p0, fp->uv[0].p);
1213 v_mad(p0, p0, y, view_dp);
1214 v_mad(p0, p0, z, view_dz);
1215 v_mad(c0, c0, y, view_dc);
1217 /* k = +1.0 view is s_view 0 */
1219 if (k >= 0 && fp->wc > 0)
1221 v_cpy(p1, fp->wv[0].p);
1222 v_cpy(c1, fp->wv[0].q);
1225 /* k = -1.0 view is s_view 1 */
1227 if (k <= 0 && fp->wc > 1)
1229 v_cpy(p1, fp->wv[1].p);
1230 v_cpy(c1, fp->wv[1].q);
1233 /* Interpolate the views. */
1236 v_mad(view_p, p0, v, k * k);
1239 v_mad(view_c, c0, v, k * k);
1241 /* Orthonormalize the view basis. */
1243 v_sub(view_e[2], view_p, view_c);
1244 v_crs(view_e[0], view_e[1], view_e[2]);
1245 v_crs(view_e[2], view_e[0], view_e[1]);
1246 v_nrm(view_e[0], view_e[0]);
1247 v_nrm(view_e[2], view_e[2]);
1250 void game_look(float phi, float theta)
1252 view_c[0] = view_p[0] + fsinf(V_RAD(theta)) * fcosf(V_RAD(phi));
1253 view_c[1] = view_p[1] + fsinf(V_RAD(phi));
1254 view_c[2] = view_p[2] - fcosf(V_RAD(theta)) * fcosf(V_RAD(phi));
1257 /*---------------------------------------------------------------------------*/
1259 void game_kill_fade(void)
1265 void game_step_fade(float dt)
1267 if ((fade_k < 1.0f && fade_d > 0.0f) ||
1268 (fade_k > 0.0f && fade_d < 0.0f))
1269 fade_k += fade_d * dt;
1283 void game_fade(float d)
1288 /*---------------------------------------------------------------------------*/
1290 const char *status_to_str(int s)
1294 case GAME_NONE: return _("Aborted");
1295 case GAME_TIME: return _("Time-out");
1296 case GAME_GOAL: return _("Success");
1297 case GAME_FALL: return _("Fall-out");
1298 default: return _("Unknown");
1302 /*---------------------------------------------------------------------------*/