#include "vec3.h"
#include "geom.h"
#include "ball.h"
-#include "back.h"
#include "hole.h"
#include "hud.h"
#include "image.h"
#include "audio.h"
-#include "solid_gl.h"
#include "config.h"
+#include "video.h"
+
+#include "solid_draw.h"
+#include "solid_sim.h"
+#include "solid_all.h"
/*---------------------------------------------------------------------------*/
-static struct s_file file;
+static struct s_full file;
static int ball;
+static int state;
+
static float view_a; /* Ideal view rotation about Y axis */
static float view_m;
static float view_ry; /* Angular velocity about Y axis */
static float jump_e = 1; /* Jumping enabled flag */
static float jump_b = 0; /* Jump-in-progress flag */
-static int jump_u = 0; /* Which ball is jumping? */
static float jump_dt; /* Jump duration */
static float jump_p[3]; /* Jump destination */
+static float idle_t; /* Idling timeout */
+
/*---------------------------------------------------------------------------*/
static void view_init(void)
view_e[2][2] = 1.f;
}
-void game_init(const char *s)
+int game_init(const char *s)
{
+ int i;
+
jump_e = 1;
jump_b = 0;
- jump_u = 0;
-
- view_init();
- sol_load_gl(&file, config_data(s), config_get_d(CONFIG_TEXTURES),
- config_get_d(CONFIG_SHADOW));
- game_set_play(-1, 0);
+ idle_t = 1.0f;
- file.uv->m = file.uv->P = 0;
-}
+ view_init();
-void game_free(void)
-{
- sol_free_gl(&file);
-}
+ if (!(state = sol_load_full(&file, s, config_get_d(CONFIG_SHADOW))))
+ return 0;
-/*---------------------------------------------------------------------------*/
+ sol_init_sim(&file.vary);
-static void game_handle_balls(struct s_file *fp)
-{
- float z[3] = {0.0f, 0.0f, 0.0f};
- int i, j;
-
- for (i = 0; i < fp->uc; i++)
+ for (i = 0; i < file.base.dc; i++)
{
- struct s_ball *up = fp->uv + i;
-
- if (!up->P)
- continue;
+ const char *k = file.base.av + file.base.dv[i].ai;
+ const char *v = file.base.av + file.base.dv[i].aj;
- /*
- * If a ball falls out, return the ball to the camera marker
- * and reset the play state for fair play
- */
- if (i != ball && up->p[1] < -10.f &&
- (up->p[1] > -199.9f || up->p[1] < -599.9f))
+ if (strcmp(k, "idle") == 0)
{
- up->P = 0;
- v_cpy(up->p, up->O);
- v_cpy(up->v, z);
- v_cpy(up->w, z);
- }
+ sscanf(v, "%f", &idle_t);
- /*
- * Hack: If the _player_'s ball somehow falls into the void before
- * its shot, return to camera marker. This usually happens when
- * when a ball gets knocked out and a penalty is called for one's
- * own ball.
- */
-
- if (i == ball && up->p[1] < -30.0f)
- {
- v_cpy(up->p, up->O);
- v_cpy(up->v, z);
- v_cpy(up->w, z);
- }
-
- /*
- * If an OTHER ball stops in a hole, mark it as done
- * and drop it -200.0 units to allow room for more balls
- */
- if (i != ball && !(v_len(up->v) > 0.0f))
- {
- if (up->P && sol_goal_test(fp, NULL, i) == 2)
- {
- up->P = 0;
- up->p[1] = -200.0f;
- v_cpy(up->v, z);
- v_cpy(up->w, z);
- hole_goal(i);
- }
- }
-
- /*
- * Check for intesecting balls.
- * If there are any, reset the proper
- * ball's play state
- */
- for (j = i + 1; j < fp->uc; j++)
- {
- struct s_ball *u2p = fp->uv + j;
- float d[3];
- if (!u2p->P)
- continue;
- v_sub(d, up->p, u2p->p);
- if (v_len(up->v) > 0.005f || v_len(u2p->v) > 0.005f)
- continue;
- if (v_len(d) < (fsqrtf((up->r + u2p->r) *
- (up->r + u2p->r))) * 1.0f && i != ball)
- up->P = 0;
- else if (v_len(d) < (fsqrtf((up->r + u2p->r) *
- (up->r + u2p->r)) * 1.0f))
- u2p->P = 0;
+ if (idle_t < 1.0f)
+ idle_t = 1.0f;
}
}
+ return 1;
}
-/*---------------------------------------------------------------------------*/
-
-static void game_draw_vect_prim(const struct s_file *fp, GLenum mode)
+void game_free(void)
{
- float p[3];
- float x[3];
- float z[3];
- float r;
-
- v_cpy(p, fp->uv[ball].p);
- v_cpy(x, view_e[0]);
- v_cpy(z, view_e[2]);
-
- r = fp->uv[ball].r;
-
- glBegin(mode);
- {
- glColor4f(1.0f, 1.0f, 0.5f, 0.5f);
- glVertex3f(p[0] - x[0] * r,
- p[1] - x[1] * r,
- p[2] - x[2] * r);
-
- glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
- glVertex3f(p[0] + z[0] * view_m,
- p[1] + z[1] * view_m,
- p[2] + z[2] * view_m);
-
- glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
- glVertex3f(p[0] + x[0] * r,
- p[1] + x[1] * r,
- p[2] + x[2] * r);
- }
- glEnd();
+ sol_quit_sim();
+ sol_free_full(&file);
}
-static void game_draw_vect(const struct s_file *fp)
+/*---------------------------------------------------------------------------*/
+
+static void game_draw_vect(struct s_rend *rend, const struct s_vary *fp)
{
if (view_m > 0.f)
{
- glPushAttrib(GL_TEXTURE_BIT);
- glPushAttrib(GL_POLYGON_BIT);
- glPushAttrib(GL_LIGHTING_BIT);
- glPushAttrib(GL_DEPTH_BUFFER_BIT);
+ glDisable(GL_LIGHTING);
+ glPushMatrix();
{
- glEnable(GL_COLOR_MATERIAL);
- glDisable(GL_LIGHTING);
- glDisable(GL_TEXTURE_2D);
- glDepthMask(GL_FALSE);
-
- glEnable(GL_DEPTH_TEST);
- game_draw_vect_prim(fp, GL_TRIANGLES);
-
- glDisable(GL_DEPTH_TEST);
- game_draw_vect_prim(fp, GL_LINE_STRIP);
+ glTranslatef(fp->uv[ball].p[0],
+ fp->uv[ball].p[1],
+ fp->uv[ball].p[2]);
+ glRotatef(view_a, 0.0f, 1.0f, 0.0f);
+ glScalef(fp->uv[ball].r,
+ fp->uv[ball].r * 0.1f, view_m);
+
+ vect_draw(rend);
}
- glPopAttrib();
- glPopAttrib();
- glPopAttrib();
- glPopAttrib();
+ glPopMatrix();
+ glEnable(GL_LIGHTING);
}
}
-static void game_draw_balls(const struct s_file *fp,
+static void game_draw_balls(struct s_rend *rend,
+ const struct s_vary *fp,
const float *bill_M, float t)
{
static const GLfloat color[5][4] = {
int ui;
- for (ui = 1; ui < fp->uc; ui++)
+ glEnable(GL_COLOR_MATERIAL);
+
+ for (ui = curr_party(); ui > 0; ui--)
{
- if (ui == ball || fp->uv[ui].P)
+ if (ui == ball)
{
float ball_M[16];
float pend_M[16];
fp->uv[ui].r,
fp->uv[ui].r);
- glEnable(GL_COLOR_MATERIAL);
- glColor4fv(color[ui]);
-
- ball_draw(ball_M, pend_M, bill_M, t);
- glDisable(GL_COLOR_MATERIAL);
+ glColor4f(color[ui][0],
+ color[ui][1],
+ color[ui][2],
+ color[ui][3]);
+ ball_draw(rend, ball_M, pend_M, bill_M, t);
}
glPopMatrix();
}
-
- else if (ui <= curr_party())
+ else
{
glPushMatrix();
{
color[ui][1],
color[ui][2], 0.5f);
- mark_draw();
+ mark_draw(rend);
}
glPopMatrix();
}
}
+
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glDisable(GL_COLOR_MATERIAL);
}
-static void game_draw_goals(const struct s_file *fp)
+static void game_draw_goals(struct s_rend *rend, const struct s_base *fp)
{
int zi;
glTranslatef(fp->zv[zi].p[0],
fp->zv[zi].p[1],
fp->zv[zi].p[2]);
- flag_draw();
+ flag_draw(rend);
}
glPopMatrix();
}
}
-static void game_draw_jumps(const struct s_file *fp)
+static void game_draw_jumps(struct s_rend *rend, const struct s_base *fp)
{
+ float t = 0.001f * SDL_GetTicks();
int ji;
for (ji = 0; ji < fp->jc; ji++)
fp->jv[ji].p[2]);
glScalef(fp->jv[ji].r, 1.f, fp->jv[ji].r);
- jump_draw(!jump_e);
+ jump_draw(rend, t, !jump_e);
}
glPopMatrix();
}
}
-static void game_draw_swchs(const struct s_file *fp)
+static void game_draw_swchs(struct s_rend *rend, const struct s_vary *fp)
{
int xi;
for (xi = 0; xi < fp->xc; xi++)
{
+ struct v_swch *xp = fp->xv + xi;
+
+ if (xp->base->i)
+ continue;
+
glPushMatrix();
{
- glTranslatef(fp->xv[xi].p[0],
- fp->xv[xi].p[1],
- fp->xv[xi].p[2]);
+ glTranslatef(xp->base->p[0],
+ xp->base->p[1],
+ xp->base->p[2]);
- glScalef(fp->xv[xi].r, 1.f, fp->xv[xi].r);
- swch_draw(fp->xv[xi].f, fp->xv[xi].e);
+ glScalef(xp->base->r, 1.f, xp->base->r);
+ swch_draw(rend, xp->f, xp->e);
}
glPopMatrix();
}
void game_draw(int pose, float t)
{
- 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 light_p[4] = { 8.f, 32.f, 8.f, 0.f };
- const float light_p[4] = { 8.f, 32.f, 8.f, 1.f };
-
- const struct s_file *fp = &file;
+ struct s_draw *fp = &file.draw;
+ struct s_rend rend = { NULL };
float fov = FOV;
- int i = 0;
+ if (!state)
+ return;
- if (jump_b)
- {
- if (jump_u == ball)
- fov *= 2.0f * fabsf(jump_dt - 0.5f);
+ fp->shadow_ui = ball;
- else
- fov /= 1.9f * fabsf(jump_dt - 0.5f);
- }
+ sol_draw_enable(&rend);
- config_push_persp(fov, 0.1f, FAR_DIST);
- glPushAttrib(GL_LIGHTING_BIT);
+ if (jump_b) fov *= 2.0f * fabsf(jump_dt - 0.5f);
+
+ video_push_persp(fov, 0.1f, FAR_DIST);
glPushMatrix();
{
float T[16], M[16], v[3], rx, ry;
glPushMatrix();
{
glTranslatef(view_p[0], view_p[1], view_p[2]);
- back_draw(0);
+ back_draw(&rend, 0);
}
glPopMatrix();
/* Draw the floor. */
- sol_draw(fp, 0, 1);
-
- if (config_get_d(CONFIG_SHADOW) && !pose)
- {
- for (i = 0; i < fp->uc; i++)
- {
- if (fp->uv[i].P)
- {
- shad_draw_set(fp->uv[i].p, fp->uv[i].r);
- sol_shad(fp);
- shad_draw_clr();
- }
- }
-
- shad_draw_set(fp->uv[ball].p, fp->uv[ball].r);
- sol_shad(fp);
- shad_draw_clr();
- }
+ sol_draw(fp, &rend, 0, 1);
/* Draw the game elements. */
if (pose == 0)
{
- game_draw_balls(fp, T, t);
- game_draw_vect(fp);
+ game_draw_balls(&rend, fp->vary, T, t);
+ game_draw_vect(&rend, fp->vary);
}
- 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);
-
- game_draw_goals(fp);
-
glEnable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
- glDisable(GL_TEXTURE_2D);
glDepthMask(GL_FALSE);
{
- game_draw_jumps(fp);
- game_draw_swchs(fp);
+ game_draw_goals(&rend, fp->base);
+ game_draw_jumps(&rend, fp->base);
+ game_draw_swchs(&rend, fp->vary);
}
glDepthMask(GL_TRUE);
- glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
}
glPopMatrix();
- glPopAttrib();
- config_pop_matrix();
+ video_pop_matrix();
+
+ sol_draw_disable(&rend);
}
/*---------------------------------------------------------------------------*/
float d[3];
float s = 2.f * dt;
+ if (!state)
+ return;
+
/* Center the view about the ball. */
- v_cpy(view_c, file.uv[ball].p);
- v_inv(view_v, file.uv[ball].v);
+ v_cpy(view_c, file.vary.uv[ball].p);
+ v_inv(view_v, file.vary.uv[ball].v);
switch (config_get_d(CONFIG_CAMERA))
{
{
static float t = 0.f;
- struct s_file *fp = &file;
+ struct s_vary *fp = &file.vary;
float p[3];
- int i;
-
if (dt > 0.f)
t += dt;
else
t = 0.f;
/* Test for a switch. */
- if (sol_swch_test(fp))
+
+ if (sol_swch_test(fp, ball) == SWCH_INSIDE)
audio_play(AUD_SWITCH, 1.f);
/* Test for a jump. */
- for (i = 0; i < fp->uc; i++)
+ if (jump_e == 1 && jump_b == 0 && (sol_jump_test(fp, jump_p, ball) ==
+ JUMP_INSIDE))
{
- if (jump_e == 1 &&
- jump_b == 0 &&
- sol_jump_test(fp, jump_p, i) == 1)
- {
- /* Initialize a jump */
- jump_b = 1;
- jump_e = 0;
- jump_dt = 0.f;
- jump_u = i;
+ jump_b = 1;
+ jump_e = 0;
+ jump_dt = 0.f;
- audio_play(AUD_JUMP, 1.f);
- }
- if (jump_e == 0 &&
- jump_b == 0 &&
- jump_u == i &&
- sol_jump_test(fp, jump_p, i) == 0)
- {
- /* Enable jumping after jump finished */
- jump_e = 1;
- }
+ audio_play(AUD_JUMP, 1.f);
+ }
+ if (jump_e == 0 && jump_b == 0 && (sol_jump_test(fp, jump_p, ball) ==
+ JUMP_OUTSIDE))
+ {
+ jump_e = 1;
}
/* Test for fall-out. */
/* Test for a goal or stop. */
- if (t > 1.f)
+ if (t > 1.f && sol_goal_test(fp, p, ball))
{
t = 0.f;
+ return GAME_GOAL;
+ }
- switch (sol_goal_test(fp, p, ball) & ((fp->uv[ball].P) ? (3) : (1)))
- {
- case 2: /* All balls stopped & Player's ball stopped in hole */
- t = 0.0f;
- fp->uv[ball].P = 0;
- return GAME_GOAL;
- break;
- case 1: /* All balls stopped */
- t = 0.0f;
- return GAME_STOP;
- break;
- case 0: /* At least one ball is still in motion */
- return GAME_NONE;
- break;
- default: /* Should never reach this */
- break;
- }
+ if (t > idle_t)
+ {
+ t = 0.f;
+ return GAME_STOP;
}
return GAME_NONE;
int game_step(const float g[3], float dt)
{
- struct s_file *fp = &file;
+ struct s_vary *fp = &file.vary;
static float s = 0.f;
static float t = 0.f;
float st = 0.f;
int i, n = 1, m = 0;
+ if (!state)
+ return GAME_NONE;
+
s = (7.f * s + dt) / 8.f;
t = s;
if (0.5 < jump_dt)
{
- fp->uv[jump_u].p[0] = jump_p[0];
- fp->uv[jump_u].p[1] = jump_p[1];
- fp->uv[jump_u].p[2] = jump_p[2];
+ fp->uv[ball].p[0] = jump_p[0];
+ fp->uv[ball].p[1] = jump_p[1];
+ fp->uv[ball].p[2] = jump_p[2];
}
-
if (1.f < jump_dt)
- {
jump_b = 0;
- }
}
else
{
{
d = sol_step(fp, g, t, ball, &m);
- game_handle_balls(fp);
-
if (b < d)
b = d;
if (m)
* friction too early and stopping the ball prematurely.
*/
- file.uv[ball].v[0] = -4.f * view_e[2][0] * view_m;
- file.uv[ball].v[1] = -4.f * view_e[2][1] * view_m + BALL_FUDGE;
- file.uv[ball].v[2] = -4.f * view_e[2][2] * view_m;
+ file.vary.uv[ball].v[0] = -4.f * view_e[2][0] * view_m;
+ file.vary.uv[ball].v[1] = -4.f * view_e[2][1] * view_m + BALL_FUDGE;
+ file.vary.uv[ball].v[2] = -4.f * view_e[2][2] * view_m;
view_m = 0.f;
}
/*---------------------------------------------------------------------------*/
-/*
- * Set ball B's play state as S. Additional values can be used for b:
- * 0: Set current ball to s
- * -1: Set all balls to s
- * -2: Set all balls under player control to s
- *
- * Note that the first ball (Or really where fall-out balls return / camera
- * spot) is never affected.
- */
-
-void game_set_play(int b, int s)
-{
- int i;
-
- if (b > 0 && b < file.uc)
- file.uv[b].P = s;
-
- if (b == 0 && ball < file.uc)
- file.uv[ball].P = s;
-
- if (b == -1)
- for (i = 1; i < file.uc; i++)
- file.uv[i].P = s;
-
- if (b == -2)
- for (i = 1; i <= curr_party() && i < file.uc; i++)
- file.uv[i].P = s;
-}
-
-/*---------------------------------------------------------------------------*/
-
void game_set_rot(int d)
{
view_a += (float) (30.f * d) / config_get_d(CONFIG_MOUSE_SENSE);
void game_set_fly(float k)
{
- struct s_file *fp = &file;
+ struct s_vary *fp = &file.vary;
float x[3] = { 1.f, 0.f, 0.f };
float y[3] = { 0.f, 1.f, 0.f };
float p1[3] = { 0.f, 0.f, 0.f };
float v[3];
+ if (!state)
+ return;
+
v_cpy(view_e[0], x);
v_cpy(view_e[1], y);
- v_sub(view_e[2], fp->uv[ball].p, fp->zv[0].p);
+ v_sub(view_e[2], fp->uv[ball].p, fp->base->zv[0].p);
if (fabs(v_dot(view_e[1], view_e[2])) > 0.999)
v_cpy(view_e[2], z);
/* k = +1.0 view is s_view 0 */
- if (k >= 0 && fp->wc > 0)
+ if (k >= 0 && fp->base->wc > 0)
{
- v_cpy(p1, fp->wv[0].p);
- v_cpy(c1, fp->wv[0].q);
+ v_cpy(p1, fp->base->wv[0].p);
+ v_cpy(c1, fp->base->wv[0].q);
}
/* k = -1.0 view is s_view 1 */
- if (k <= 0 && fp->wc > 1)
+ if (k <= 0 && fp->base->wc > 1)
{
- v_cpy(p1, fp->wv[1].p);
- v_cpy(c1, fp->wv[1].q);
+ v_cpy(p1, fp->base->wv[1].p);
+ v_cpy(c1, fp->base->wv[1].q);
}
/* Interpolate the views. */
jump_e = 1;
jump_b = 0;
- for (ui = 0; ui < file.uc; ui++)
+ for (ui = 0; ui < file.vary.uc; ui++)
{
- file.uv[ui].v[0] = 0.f;
- file.uv[ui].v[1] = 0.f;
- file.uv[ui].v[2] = 0.f;
+ file.vary.uv[ui].v[0] = 0.f;
+ file.vary.uv[ui].v[1] = 0.f;
+ file.vary.uv[ui].v[2] = 0.f;
- file.uv[ui].w[0] = 0.f;
- file.uv[ui].w[1] = 0.f;
- file.uv[ui].w[2] = 0.f;
+ file.vary.uv[ui].w[0] = 0.f;
+ file.vary.uv[ui].w[1] = 0.f;
+ file.vary.uv[ui].w[2] = 0.f;
}
}
void game_get_pos(float p[3], float e[3][3])
{
- v_cpy(p, file.uv[ball].p);
- v_cpy(e[0], file.uv[ball].e[0]);
- v_cpy(e[1], file.uv[ball].e[1]);
- v_cpy(e[2], file.uv[ball].e[2]);
+ v_cpy(p, file.vary.uv[ball].p);
+ v_cpy(e[0], file.vary.uv[ball].e[0]);
+ v_cpy(e[1], file.vary.uv[ball].e[1]);
+ v_cpy(e[2], file.vary.uv[ball].e[2]);
}
void game_set_pos(float p[3], float e[3][3])
{
- v_cpy(file.uv[ball].p, p);
- v_cpy(file.uv[ball].e[0], e[0]);
- v_cpy(file.uv[ball].e[1], e[1]);
- v_cpy(file.uv[ball].e[2], e[2]);
+ v_cpy(file.vary.uv[ball].p, p);
+ v_cpy(file.vary.uv[ball].e[0], e[0]);
+ v_cpy(file.vary.uv[ball].e[1], e[1]);
+ v_cpy(file.vary.uv[ball].e[2], e[2]);
}
/*---------------------------------------------------------------------------*/