X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=ball%2Fgame.c;h=785d16ef2dac1fa1a92d2047415a8cb7665ab879;hb=4438862ba8c07519eff35ebf65e55f5a8f221ee3;hp=bca262faa81e933cf2b54856f0de74fe9484f6dc;hpb=c137bf72879da4470d7545c58a5bf84b7955afed;p=neverball diff --git a/ball/game.c b/ball/game.c index bca262f..785d16e 100644 --- a/ball/game.c +++ b/ball/game.c @@ -38,13 +38,10 @@ static struct s_file back; static float clock = 0.f; /* Clock time */ static int clock_down = 1; /* Clock go up or down? */ -static float game_ix; /* Input rotation about X axis */ -static float game_iz; /* Input rotation about Z axis */ static float game_rx; /* Floor rotation about X axis */ static float game_rz; /* Floor rotation about Z axis */ static float view_a; /* Ideal view rotation about Y axis */ -static float view_ry; /* Angular velocity about Y axis */ static float view_dc; /* Ideal view distance above ball */ static float view_dp; /* Ideal view distance above ball */ static float view_dz; /* Ideal view distance behind ball */ @@ -68,6 +65,119 @@ static float fade_d = 0.0; /* Fade in/out direction */ /*---------------------------------------------------------------------------*/ +/* + * This is an abstraction of the game's input state. All input is + * encapsulated here, and all references to the input by the game are made + * here. This has the effect of homogenizing input for use in replay + * recording and playback. + * + * x and z: + * -32767 = -ANGLE_BOUND + * +32767 = +ANGLE_BOUND + * + * r: + * -32767 = -VIEWR_BOUND + * +32767 = +VIEWR_BOUND + * + */ + +struct input +{ + short x; + short z; + short r; + short c; +}; + +static struct input input_current; + +static void input_init(void) +{ + input_current.x = 0; + input_current.z = 0; + input_current.r = 0; + input_current.c = 0; +} + +static void input_set_x(float x) +{ + if (x < -ANGLE_BOUND) x = -ANGLE_BOUND; + if (x > ANGLE_BOUND) x = ANGLE_BOUND; + + input_current.x = (short) (32767.0f * x / ANGLE_BOUND); +} + +static void input_set_z(float z) +{ + if (z < -ANGLE_BOUND) z = -ANGLE_BOUND; + if (z > ANGLE_BOUND) z = ANGLE_BOUND; + + input_current.z = (short) (32767.0f * z / ANGLE_BOUND); +} + +static void input_set_r(float r) +{ + if (r < -VIEWR_BOUND) r = -VIEWR_BOUND; + if (r > VIEWR_BOUND) r = VIEWR_BOUND; + + input_current.r = (short) (32767.0f * r / VIEWR_BOUND); +} + +static void input_set_c(int c) +{ + input_current.c = (short) c; +} + +static float input_get_x(void) +{ + return ANGLE_BOUND * (float) input_current.x / 32767.0f; +} + +static float input_get_z(void) +{ + return ANGLE_BOUND * (float) input_current.z / 32767.0f; +} + +static float input_get_r(void) +{ + return VIEWR_BOUND * (float) input_current.r / 32767.0f; +} + +static int input_get_c(void) +{ + return (int) input_current.c; +} + +int input_put(FILE *fout) +{ + if (game_state) + { + put_short(fout, &input_current.x); + put_short(fout, &input_current.z); + put_short(fout, &input_current.r); + put_short(fout, &input_current.c); + + return 1; + } + return 0; +} + +int input_get(FILE *fin) +{ + if (game_state) + { + get_short(fin, &input_current.x); + get_short(fin, &input_current.z); + get_short(fin, &input_current.r); + get_short(fin, &input_current.c); + + return (feof(fin) ? 0 : 1); + } + return 0; +} + +/*---------------------------------------------------------------------------*/ + static int grow = 0; /* Should the ball be changing size? */ static float grow_orig = 0; /* the original ball size */ static float grow_goal = 0; /* how big or small to get! */ @@ -175,14 +285,12 @@ static void grow_step(const struct s_file *fp, float dt) static void view_init(void) { - view_a = 0.f; - view_ry = 0.f; - view_fov = (float) config_get_d(CONFIG_VIEW_FOV); view_dp = (float) config_get_d(CONFIG_VIEW_DP) / 100.0f; view_dc = (float) config_get_d(CONFIG_VIEW_DC) / 100.0f; view_dz = (float) config_get_d(CONFIG_VIEW_DZ) / 100.0f; view_k = 1.0f; + view_a = 0.0f; view_c[0] = 0.f; view_c[1] = view_dc; @@ -219,10 +327,10 @@ int game_init(const struct level *level, int t, int g) game_state = 1; - game_ix = 0.f; - game_iz = 0.f; - game_rx = 0.f; - game_rz = 0.f; + input_init(); + + game_rx = 0.0f; + game_rz = 0.0f; /* Initialize jump and goal states. */ @@ -289,6 +397,7 @@ static void game_draw_balls(const struct s_file *fp) m_basis(M, fp->uv[0].e[0], fp->uv[0].e[1], fp->uv[0].e[2]); + glPushAttrib(GL_LIGHTING_BIT); glPushMatrix(); { glTranslatef(fp->uv[0].p[0], @@ -303,6 +412,7 @@ static void game_draw_balls(const struct s_file *fp) ball_draw(); } glPopMatrix(); + glPopAttrib(); } static void game_draw_items(const struct s_file *fp) @@ -310,62 +420,66 @@ static void game_draw_items(const struct s_file *fp) float r = 360.f * SDL_GetTicks() / 1000.f; int hi; - item_push(ITEM_COIN); + glPushAttrib(GL_LIGHTING_BIT); { - for (hi = 0; hi < fp->hc; hi++) + item_push(ITEM_COIN); + { + for (hi = 0; hi < fp->hc; hi++) - if (fp->hv[hi].t == ITEM_COIN && fp->hv[hi].n > 0) - { - glPushMatrix(); + if (fp->hv[hi].t == ITEM_COIN && fp->hv[hi].n > 0) { - glTranslatef(fp->hv[hi].p[0], - fp->hv[hi].p[1], - fp->hv[hi].p[2]); - glRotatef(r, 0.0f, 1.0f, 0.0f); - item_draw(&fp->hv[hi], r); + glPushMatrix(); + { + glTranslatef(fp->hv[hi].p[0], + fp->hv[hi].p[1], + fp->hv[hi].p[2]); + glRotatef(r, 0.0f, 1.0f, 0.0f); + item_draw(&fp->hv[hi], r); + } + glPopMatrix(); } - glPopMatrix(); - } - } - item_pull(); + } + item_pull(); - item_push(ITEM_SHRINK); - { - for (hi = 0; hi < fp->hc; hi++) + item_push(ITEM_SHRINK); + { + for (hi = 0; hi < fp->hc; hi++) - if (fp->hv[hi].t == ITEM_SHRINK) - { - glPushMatrix(); + if (fp->hv[hi].t == ITEM_SHRINK) { - glTranslatef(fp->hv[hi].p[0], - fp->hv[hi].p[1], - fp->hv[hi].p[2]); - glRotatef(r, 0.0f, 1.0f, 0.0f); - item_draw(&fp->hv[hi], r); + glPushMatrix(); + { + glTranslatef(fp->hv[hi].p[0], + fp->hv[hi].p[1], + fp->hv[hi].p[2]); + glRotatef(r, 0.0f, 1.0f, 0.0f); + item_draw(&fp->hv[hi], r); + } + glPopMatrix(); } - glPopMatrix(); - } - } - item_pull(); + } + item_pull(); - item_push(ITEM_GROW); - { - for (hi = 0; hi < fp->hc; hi++) + item_push(ITEM_GROW); + { + for (hi = 0; hi < fp->hc; hi++) - if (fp->hv[hi].t == ITEM_GROW) - { - glPushMatrix(); + if (fp->hv[hi].t == ITEM_GROW) { - glTranslatef(fp->hv[hi].p[0], - fp->hv[hi].p[1], - fp->hv[hi].p[2]); - glRotatef(r, 0.0f, 1.0f, 0.0f); - item_draw(&fp->hv[hi], r); + glPushMatrix(); + { + glTranslatef(fp->hv[hi].p[0], + fp->hv[hi].p[1], + fp->hv[hi].p[2]); + glRotatef(r, 0.0f, 1.0f, 0.0f); + item_draw(&fp->hv[hi], r); + } + glPopMatrix(); } - glPopMatrix(); - } + } + item_pull(); } - item_pull(); + glPopAttrib(); } static void game_draw_goals(const struct s_file *fp, float rx, float ry) @@ -545,11 +659,6 @@ static void game_draw_back(int pose, int d, const float p[3]) static void game_draw_fore(int pose, float rx, float ry, int d, const float p[3]) { - static const float a[4] = { 0.2f, 0.2f, 0.2f, 1.0f }; - static const float s[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - static const float e[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - static const float h[1] = { 0.0f }; - const float *ball_p = file.uv->p; const float ball_r = file.uv->r; @@ -603,11 +712,6 @@ static void game_draw_fore(int pose, float rx, /* Draw the particles and light columns. */ - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, a); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s); - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e); - glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h); - glEnable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); glDepthMask(GL_FALSE); @@ -624,6 +728,8 @@ static void game_draw_fore(int pose, float rx, game_draw_swchs(&file); } glEnable(GL_TEXTURE_2D); + + glColor3f(1.0f, 1.0f, 1.0f); } glDepthMask(GL_TRUE); glEnable(GL_LIGHTING); @@ -721,8 +827,6 @@ void game_draw(int pose, float st) static void game_update_grav(float h[3], const float g[3]) { - struct s_file *fp = &file; - float x[3]; float y[3] = { 0.f, 1.f, 0.f }; float z[3]; @@ -732,7 +836,10 @@ static void game_update_grav(float h[3], const float g[3]) /* Compute the gravity vector from the given world rotations. */ - v_sub(z, view_p, fp->uv->p); + z[0] = fsinf(V_RAD(view_a)); + z[1] = 0.0; + z[2] = fcosf(V_RAD(view_a)); + v_crs(x, y, z); v_crs(z, x, y); v_nrm(x, x); @@ -747,39 +854,37 @@ static void game_update_grav(float h[3], const float g[3]) static void game_update_view(float dt) { float dc = view_dc * (jump_b ? 2.0f * fabsf(jump_dt - 0.5f) : 1.0f); - float dx = view_ry * dt * 5.0f; + float da = input_get_r() * dt * 90.0f; float k; - view_a += view_ry * dt * 90.f; + float M[16], v[3], Y[3] = { 0.0f, 1.0f, 0.0f }; + + view_a += da; /* Center the view about the ball. */ v_cpy(view_c, file.uv->p); v_inv(view_v, file.uv->v); - switch (config_get_d(CONFIG_CAMERA)) + view_e[2][0] = fsinf(V_RAD(view_a)); + view_e[2][1] = 0.0; + view_e[2][2] = fcosf(V_RAD(view_a)); + + switch (input_get_c()) { - case 1: /* Camera 1: Viewpoint chases the ball position. */ + case 1: /* Camera 1: Viewpoint chases the ball position. */ + + /* TODO: This camera no longer exists. */ - v_sub(view_e[2], view_p, view_c); break; case 2: /* Camera 2: View vector is given by view angle. */ - view_e[2][0] = fsinf(V_RAD(view_a)); - view_e[2][1] = 0.f; - view_e[2][2] = fcosf(V_RAD(view_a)); - - dx = 0.0f; - break; default: /* Default: View vector approaches the ball velocity vector. */ - k = v_dot(view_v, view_v); - - v_sub(view_e[2], view_p, view_c); - v_mad(view_e[2], view_e[2], view_v, k * dt / 4); + v_mad(view_e[2], view_e[2], view_v, v_dot(view_v, view_v) * dt / 4); break; } @@ -799,10 +904,11 @@ static void game_update_view(float dt) if (view_k < 0.5) view_k = 0.5; - v_cpy(view_p, file.uv->p); - v_mad(view_p, view_p, view_e[0], dx * view_k); - v_mad(view_p, view_p, view_e[1], view_dp * view_k); - v_mad(view_p, view_p, view_e[2], view_dz * view_k); + v_scl(v, view_e[1], view_dp * view_k); + v_mad(v, v, view_e[2], view_dz * view_k); + m_rot(M, Y, V_RAD(da)); + m_vxfm(view_p, M, v); + v_add(view_p, view_p, file.uv->p); /* Compute the new view center. */ @@ -844,6 +950,7 @@ static int game_update_state(int bt) float c[3]; /* Test for an item. */ + if (bt && (hp = sol_item_test(fp, p, COIN_RADIUS))) { const char *sound = AUD_COIN; @@ -858,6 +965,7 @@ static int game_update_state(int bt) coins += hp->n; /* Check for goal open. */ + if (goal_c > 0) { goal_c -= hp->n; @@ -871,10 +979,12 @@ static int game_update_state(int bt) audio_play(sound, 1.f); /* Reset item type. */ + hp->t = ITEM_NONE; } /* Test for a switch. */ + if (sol_swch_test(fp, 0)) audio_play(AUD_SWITCH, 1.f); @@ -918,85 +1028,48 @@ static int game_update_state(int bt) return GAME_NONE; } -/* - * On most hardware, rendering requires much more computing power than - * physics. Since physics takes less time than graphics, it make sense to - * detach the physics update time step from the graphics frame rate. By - * performing multiple physics updates for each graphics update, we get away - * with higher quality physics with little impact on overall performance. - * - * Toward this end, we establish a baseline maximum physics time step. If - * the measured frame time exceeds this maximum, we cut the time step in - * half, and do two updates. If THIS time step exceeds the maximum, we do - * four updates. And so on. In this way, the physics system is allowed to - * seek an optimal update rate independent of, yet in integral sync with, the - * graphics frame rate. - */ - int game_step(const float g[3], float dt, int bt) { - struct s_file *fp = &file; - - float h[3]; - float d = 0.f; - float b = 0.f; - float t; - int i, n = 1; - if (game_state) { - t = dt; + struct s_file *fp = &file; + + float h[3]; /* Smooth jittery or discontinuous input. */ - if (t < RESPONSE) - { - game_rx += (game_ix - game_rx) * t / RESPONSE; - game_rz += (game_iz - game_rz) * t / RESPONSE; - } - else - { - game_rx = game_ix; - game_rz = game_iz; - } + game_rx += (input_get_x() - game_rx) * dt / RESPONSE; + game_rz += (input_get_z() - game_rz) * dt / RESPONSE; grow_step(fp, dt); game_update_grav(h, g); - part_step(h, t); + part_step(h, dt); if (jump_b) { - jump_dt += t; + jump_dt += dt; /* Handle a jump. */ - if (0.5 < jump_dt) + if (0.5f < jump_dt) { fp->uv[0].p[0] = jump_p[0]; fp->uv[0].p[1] = jump_p[1]; fp->uv[0].p[2] = jump_p[2]; } - if (1.f < jump_dt) + if (1.0f < jump_dt) jump_b = 0; } else { /* Run the sim. */ - while (t > MAX_DT && n < MAX_DN) - { - t /= 2; - n *= 2; - } - - for (i = 0; i < n; i++) - if (b < (d = sol_step(fp, h, t, 0, NULL))) - b = d; + float b = sol_step(fp, h, dt, 0, NULL); /* Mix the sound of a ball bounce. */ - if (b > 0.5) + if (b > 0.5f) { float k = (b - 0.5f) * 2.0f; @@ -1021,51 +1094,36 @@ int game_step(const float g[3], float dt, int bt) /*---------------------------------------------------------------------------*/ -void game_no_aa(void) +void game_set_x(int k) { - float max = game_ix * game_ix + game_iz * game_iz; - if (max > ANGLE_BOUND * ANGLE_BOUND) - { - max = ANGLE_BOUND / sqrt(max); - game_ix *= max; - game_iz *= max; - } + input_set_x(-ANGLE_BOUND * k / JOY_MAX); } -void game_set_x(int k) +void game_set_z(int k) { - game_ix = -(ANGLE_BOUND) * k / JOY_MAX; -#if NO_AA - game_no_aa(); -#endif + input_set_z(+ANGLE_BOUND * k / JOY_MAX); } -void game_set_z(int k) +void game_set_ang(int x, int z) { - game_iz = +ANGLE_BOUND * k / JOY_MAX; -#if NO_AA - game_no_aa(); -#endif + input_set_x(x); + input_set_z(z); } void game_set_pos(int x, int y) { - game_ix += 40.f * y / config_get_d(CONFIG_MOUSE_SENSE); - game_iz += 40.f * x / config_get_d(CONFIG_MOUSE_SENSE); - -#if NO_AA - game_no_aa(); -#else - if (game_ix > +ANGLE_BOUND) game_ix = +ANGLE_BOUND; - if (game_ix < -ANGLE_BOUND) game_ix = -ANGLE_BOUND; - if (game_iz > +ANGLE_BOUND) game_iz = +ANGLE_BOUND; - if (game_iz < -ANGLE_BOUND) game_iz = -ANGLE_BOUND; -#endif + input_set_x(input_get_x() + 40.0f * y / config_get_d(CONFIG_MOUSE_SENSE)); + input_set_z(input_get_z() + 40.0f * x / config_get_d(CONFIG_MOUSE_SENSE)); +} + +void game_set_cam(int c) +{ + input_set_c(c); } void game_set_rot(float r) { - view_ry = r; + input_set_r(r); } /*---------------------------------------------------------------------------*/ @@ -1174,45 +1232,3 @@ void game_fade(float d) } /*---------------------------------------------------------------------------*/ - -int put_game_state(FILE *fout) -{ - if (game_state) - { - /* Write the view and tilt state. */ - - put_float(fout, &game_rx); - put_float(fout, &game_rz); - put_array(fout, view_c, 3); - put_array(fout, view_p, 3); - - /* Write the game simulation state. */ - - put_file_state(fout, &file); - - return 1; - } - return 0; -} - -int get_game_state(FILE *fin) -{ - if (game_state) - { - /* Read the view and tilt state. */ - - get_float(fin, &game_rx); - get_float(fin, &game_rz); - get_array(fin, view_c, 3); - get_array(fin, view_p, 3); - - /* Read the game simulation state. */ - - get_file_state(fin, &file); - - return (feof(fin) ? 0 : 1); - } - return 0; -} - -/*---------------------------------------------------------------------------*/