* General Public License for more details.
*/
-#include "solid.h"
#include "vec3.h"
#include "glext.h"
#include "ball.h"
#include "item.h"
#include "part.h"
#include "geom.h"
-#include "solid_gl.h"
#include "config.h"
-#include "back.h"
#include "video.h"
+#include "solid_draw.h"
+
#include "game_draw.h"
/*---------------------------------------------------------------------------*/
-static void game_draw_balls(const struct s_file *fp,
+static void game_draw_balls(struct s_rend *rend,
+ const struct s_vary *vary,
const float *bill_M, float t)
{
float c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
float ball_M[16];
float pend_M[16];
- m_basis(ball_M, fp->uv[0].e[0], fp->uv[0].e[1], fp->uv[0].e[2]);
- m_basis(pend_M, fp->uv[0].E[0], fp->uv[0].E[1], fp->uv[0].E[2]);
+ m_basis(ball_M, vary->uv[0].e[0], vary->uv[0].e[1], vary->uv[0].e[2]);
+ m_basis(pend_M, vary->uv[0].E[0], vary->uv[0].E[1], vary->uv[0].E[2]);
- glPushAttrib(GL_LIGHTING_BIT);
glPushMatrix();
{
- glTranslatef(fp->uv[0].p[0],
- fp->uv[0].p[1] + BALL_FUDGE,
- fp->uv[0].p[2]);
- glScalef(fp->uv[0].r,
- fp->uv[0].r,
- fp->uv[0].r);
-
- glColor4fv(c);
- ball_draw(ball_M, pend_M, bill_M, t);
+ glTranslatef(vary->uv[0].p[0],
+ vary->uv[0].p[1] + BALL_FUDGE,
+ vary->uv[0].p[2]);
+ glScalef(vary->uv[0].r,
+ vary->uv[0].r,
+ vary->uv[0].r);
+
+ glColor4f(c[0], c[1], c[2], c[3]);
+ ball_draw(rend, ball_M, pend_M, bill_M, t);
}
glPopMatrix();
- glPopAttrib();
}
-static void game_draw_items(const struct s_file *fp, float t)
+static void game_draw_items(struct s_rend *rend,
+ const struct s_vary *vary,
+ const float *bill_M, float t)
{
- float r = 360.f * t;
int hi;
- glPushAttrib(GL_LIGHTING_BIT);
+ glEnable(GL_COLOR_MATERIAL);
{
- item_push(ITEM_COIN);
- {
- for (hi = 0; hi < fp->hc; hi++)
-
- if (fp->hv[hi].t == ITEM_COIN && fp->hv[hi].n > 0)
+ for (hi = 0; hi < vary->hc; hi++)
+ if (vary->hv[hi].t == ITEM_COIN && vary->hv[hi].n > 0)
+ {
+ glPushMatrix();
{
- 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();
+ glTranslatef(vary->hv[hi].p[0],
+ vary->hv[hi].p[1],
+ vary->hv[hi].p[2]);
+ item_draw(rend, &vary->hv[hi], bill_M, t);
}
- }
- item_pull();
-
- item_push(ITEM_SHRINK);
- {
- for (hi = 0; hi < fp->hc; hi++)
+ glPopMatrix();
+ }
- if (fp->hv[hi].t == ITEM_SHRINK)
+ for (hi = 0; hi < vary->hc; hi++)
+ if (vary->hv[hi].t == ITEM_SHRINK)
+ {
+ glPushMatrix();
{
- 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();
+ glTranslatef(vary->hv[hi].p[0],
+ vary->hv[hi].p[1],
+ vary->hv[hi].p[2]);
+ item_draw(rend, &vary->hv[hi], bill_M, t);
}
- }
- item_pull();
-
- item_push(ITEM_GROW);
- {
- for (hi = 0; hi < fp->hc; hi++)
+ glPopMatrix();
+ }
- if (fp->hv[hi].t == ITEM_GROW)
+ for (hi = 0; hi < vary->hc; hi++)
+ if (vary->hv[hi].t == ITEM_GROW)
+ {
+ glPushMatrix();
{
- 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();
+ glTranslatef(vary->hv[hi].p[0],
+ vary->hv[hi].p[1],
+ vary->hv[hi].p[2]);
+ item_draw(rend, &vary->hv[hi], bill_M, t);
}
- }
- item_pull();
+ glPopMatrix();
+ }
}
- glPopAttrib();
+
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glDisable(GL_COLOR_MATERIAL);
}
-static void game_draw_goals(const struct game_draw *dr,
- const struct s_file *fp,
+static void game_draw_goals(struct s_rend *rend,
+ const struct game_draw *gd,
const float *M, float t)
{
- if (dr->goal_e)
+ const struct s_base *base = gd->vary.base;
+
+ if (gd->goal_e)
{
int zi;
- /* Draw the goal particles. */
-
- glEnable(GL_TEXTURE_2D);
- {
- for (zi = 0; zi < fp->zc; zi++)
- {
- glPushMatrix();
- {
- glTranslatef(fp->zv[zi].p[0],
- fp->zv[zi].p[1],
- fp->zv[zi].p[2]);
-
- part_draw_goal(M, fp->zv[zi].r, dr->goal_k, t);
- }
- glPopMatrix();
- }
- }
- glDisable(GL_TEXTURE_2D);
-
/* Draw the goal column. */
- for (zi = 0; zi < fp->zc; zi++)
+ for (zi = 0; zi < base->zc; zi++)
{
glPushMatrix();
{
- glTranslatef(fp->zv[zi].p[0],
- fp->zv[zi].p[1],
- fp->zv[zi].p[2]);
+ glTranslatef(base->zv[zi].p[0],
+ base->zv[zi].p[1],
+ base->zv[zi].p[2]);
- glScalef(fp->zv[zi].r,
- dr->goal_k,
- fp->zv[zi].r);
+ glScalef(base->zv[zi].r,
+ gd->goal_k,
+ base->zv[zi].r);
- goal_draw();
+ goal_draw(rend, t);
}
glPopMatrix();
}
}
}
-static void game_draw_jumps(const struct game_draw *dr,
- const struct s_file *fp,
+static void game_draw_jumps(struct s_rend *rend,
+ const struct game_draw *gd,
const float *M, float t)
{
- int ji;
+ const struct s_base *base = gd->vary.base;
- glEnable(GL_TEXTURE_2D);
- {
- for (ji = 0; ji < fp->jc; ji++)
- {
- glPushMatrix();
- {
- glTranslatef(fp->jv[ji].p[0],
- fp->jv[ji].p[1],
- fp->jv[ji].p[2]);
-
- part_draw_jump(M, fp->jv[ji].r, 1.0f, t);
- }
- glPopMatrix();
- }
- }
- glDisable(GL_TEXTURE_2D);
+ int ji;
- for (ji = 0; ji < fp->jc; ji++)
+ for (ji = 0; ji < base->jc; ji++)
{
glPushMatrix();
{
- glTranslatef(fp->jv[ji].p[0],
- fp->jv[ji].p[1],
- fp->jv[ji].p[2]);
- glScalef(fp->jv[ji].r,
+ glTranslatef(base->jv[ji].p[0],
+ base->jv[ji].p[1],
+ base->jv[ji].p[2]);
+ glScalef(base->jv[ji].r,
1.0f,
- fp->jv[ji].r);
+ base->jv[ji].r);
- jump_draw(!dr->jump_e);
+ jump_draw(rend, t, !gd->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 *vary)
{
int xi;
- for (xi = 0; xi < fp->xc; xi++)
+ for (xi = 0; xi < vary->xc; xi++)
{
- if (fp->xv[xi].i)
+ struct v_swch *xp = vary->xv + xi;
+
+ if (xp->base->i)
continue;
glPushMatrix();
{
- glTranslatef(fp->xv[xi].p[0],
- fp->xv[xi].p[1],
- fp->xv[xi].p[2]);
- glScalef(fp->xv[xi].r,
+ glTranslatef(xp->base->p[0],
+ xp->base->p[1],
+ xp->base->p[2]);
+ glScalef(xp->base->r,
1.0f,
- fp->xv[xi].r);
+ xp->base->r);
- swch_draw(fp->xv[xi].f, fp->xv[xi].e);
+ swch_draw(rend, xp->f, xp->e);
}
glPopMatrix();
}
/*---------------------------------------------------------------------------*/
-static void game_draw_tilt(const struct game_draw *dr, int d)
+static void game_draw_tilt(const struct game_draw *gd, int d)
{
- const struct game_tilt *tilt = &dr->tilt;
- const float *ball_p = dr->file.uv->p;
+ const struct game_tilt *tilt = &gd->tilt;
+ const float *ball_p = gd->vary.uv[0].p;
/* Rotate the environment about the position of the ball. */
glTranslatef(-ball_p[0], -ball_p[1] * d, -ball_p[2]);
}
-static void game_refl_all(const struct game_draw *dr)
+static void game_refl_all(struct s_rend *rend, const struct game_draw *gd)
{
glPushMatrix();
{
- game_draw_tilt(dr, 1);
+ game_draw_tilt(gd, 1);
/* Draw the floor. */
- sol_refl(&dr->file);
+ sol_refl(&gd->draw, rend);
}
glPopMatrix();
}
glLightfv(GL_LIGHT1, GL_SPECULAR, light_c[1]);
}
-static void game_draw_back(const struct game_draw *dr, int pose, int d, float t)
+static void game_draw_back(struct s_rend *rend,
+ const struct game_draw *gd,
+ int pose, int d, float t)
{
if (pose == POSE_BALL)
return;
glPushMatrix();
{
+ const struct game_view *view = &gd->view;
+
if (d < 0)
{
- const struct game_tilt *tilt = &dr->tilt;
+ const struct game_tilt *tilt = &gd->tilt;
glRotatef(tilt->rz * 2, tilt->z[0], tilt->z[1], tilt->z[2]);
glRotatef(tilt->rx * 2, tilt->x[0], tilt->x[1], tilt->x[2]);
}
- glTranslatef(dr->view.p[0], dr->view.p[1] * d, dr->view.p[2]);
+ glTranslatef(view->p[0], view->p[1] * d, view->p[2]);
if (config_get_d(CONFIG_BACKGROUND))
{
- /* Draw all background layers back to front. */
-
- sol_back(&dr->back, BACK_DIST, FAR_DIST, t);
- back_draw(0);
- sol_back(&dr->back, 0, BACK_DIST, t);
+ back_draw(rend, 0);
+ sol_back(&gd->back.draw, rend, 0, FAR_DIST, t);
}
- else back_draw(0);
+ else back_draw(rend, 0);
}
glPopMatrix();
}
{
/* Fudge to eliminate the floor from reflection. */
- GLdouble e[4], k = -0.00001;
-
- e[0] = 0;
- e[1] = 1;
- e[2] = 0;
- e[3] = k;
-
- glClipPlane(GL_CLIP_PLANE0, e);
+ glClipPlane4f_(GL_CLIP_PLANE0, 0, 1, 0, -0.00001);
}
-static void game_clip_ball(const struct game_draw *dr, int d, const float *p)
+static void game_clip_ball(const struct game_draw *gd, int d, const float *p)
{
- GLdouble r, c[3], pz[4], nz[4];
+ GLfloat r, c[3], pz[4], nz[4];
/* Compute the plane giving the front of the ball, as seen from view.p. */
c[1] = p[1] * d;
c[2] = p[2];
- pz[0] = dr->view.p[0] - c[0];
- pz[1] = dr->view.p[1] - c[1];
- pz[2] = dr->view.p[2] - c[2];
+ pz[0] = gd->view.p[0] - c[0];
+ pz[1] = gd->view.p[1] - c[1];
+ pz[2] = gd->view.p[2] - c[2];
r = sqrt(pz[0] * pz[0] + pz[1] * pz[1] + pz[2] * pz[2]);
pz[1] *= d;
nz[1] *= d;
- glClipPlane(GL_CLIP_PLANE1, nz);
- glClipPlane(GL_CLIP_PLANE2, pz);
+ glClipPlane4f_(GL_CLIP_PLANE1, nz[0], nz[1], nz[2], nz[3]);
+ glClipPlane4f_(GL_CLIP_PLANE2, pz[0], pz[1], pz[2], pz[3]);
}
-static void game_draw_fore(const struct game_draw *dr,
+static void game_draw_fore(struct s_rend *rend,
+ struct game_draw *gd,
int pose, const float *M,
int d, float t)
{
- const float *ball_p = dr->file.uv->p;
- const float ball_r = dr->file.uv->r;
+ const float *ball_p = gd->vary.uv[0].p;
- const struct s_file *fp = &dr->file;
+ struct s_draw *draw = &gd->draw;
glPushMatrix();
{
/* Rotate the environment about the position of the ball. */
- game_draw_tilt(dr, d);
+ game_draw_tilt(gd, d);
/* Compute clipping planes for reflection and ball facing. */
game_clip_refl(d);
- game_clip_ball(dr, d, ball_p);
+ game_clip_ball(gd, d, ball_p);
if (d < 0)
glEnable(GL_CLIP_PLANE0);
switch (pose)
{
case POSE_LEVEL:
- sol_draw(fp, 0, 1);
+ sol_draw(draw, rend, 0, 1);
break;
case POSE_NONE:
- /* Draw the coins. */
+ /* Draw the floor. */
- game_draw_items(fp, t);
+ sol_draw(draw, rend, 0, 1);
- /* Draw the floor. */
+ /* Draw the coins. */
- sol_draw(fp, 0, 1);
+ game_draw_items(rend, draw->vary, M, t);
/* Fall through. */
case POSE_BALL:
- /* Draw the ball shadow. */
-
- if (d > 0 && config_get_d(CONFIG_SHADOW))
- {
- shad_draw_set(ball_p, ball_r);
- sol_shad(fp);
- shad_draw_clr();
- }
-
/* Draw the ball. */
- game_draw_balls(fp, M, t);
+ game_draw_balls(rend, draw->vary, M, t);
break;
}
- /* Draw the particles and light columns. */
+ /* Draw the billboards, entities, and particles. */
glEnable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
glDepthMask(GL_FALSE);
{
- glColor3f(1.0f, 1.0f, 1.0f);
+ sol_bill(draw, rend, M, t);
- sol_bill(fp, M, t);
- part_draw_coin(M, t);
+ game_draw_goals(rend, gd, M, t);
+ game_draw_jumps(rend, gd, M, t);
+ game_draw_swchs(rend, draw->vary);
- glDisable(GL_TEXTURE_2D);
- {
- game_draw_goals(dr, fp, M, t);
- game_draw_jumps(dr, fp, M, t);
- game_draw_swchs(fp);
- }
- glEnable(GL_TEXTURE_2D);
-
- glColor3f(1.0f, 1.0f, 1.0f);
+ part_draw_coin(rend);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
glDepthMask(GL_TRUE);
glEnable(GL_LIGHTING);
/*---------------------------------------------------------------------------*/
-void game_draw(const struct game_draw *dr, int pose, float t)
+void game_draw(struct game_draw *gd, int pose, float t)
{
float fov = (float) config_get_d(CONFIG_VIEW_FOV);
+ int sh = config_get_d(CONFIG_SHADOW);
+
+ if (pose == POSE_LEVEL)
+ config_set_d(CONFIG_SHADOW, 0);
- if (dr->jump_b) fov *= 2.f * fabsf(dr->jump_dt - 0.5);
+ if (gd->jump_b) fov *= 2.f * fabsf(gd->jump_dt - 0.5);
- if (dr->state)
+ if (gd->state)
{
- const struct game_view *view = &dr->view;
+ const struct game_view *view = &gd->view;
+ struct s_rend rend;
+
+ gd->draw.shadow_ui = 0;
+
+ sol_draw_enable(&rend);
video_push_persp(fov, 0.1f, FAR_DIST);
glPushMatrix();
{
float T[16], U[16], M[16], v[3];
-
/* Compute direct and reflected view bases. */
v[0] = +view->p[0];
glMultMatrixf(M);
glTranslatef(-view->c[0], -view->c[1], -view->c[2]);
- if (dr->reflective && config_get_d(CONFIG_REFLECTION))
+ /* Draw the background. */
+
+ game_draw_back(&rend, gd, pose, +1, t);
+
+ /* Draw the reflection. */
+
+ if (gd->draw.reflective && config_get_d(CONFIG_REFLECTION))
{
glEnable(GL_STENCIL_TEST);
{
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
- game_refl_all(dr);
+ game_refl_all(&rend, gd);
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glScalef(+1.0f, -1.0f, +1.0f);
game_draw_light();
- game_draw_back(dr, pose, -1, t);
- game_draw_fore(dr, pose, U, -1, t);
+
+ game_draw_back(&rend, gd, pose, -1, t);
+ game_draw_fore(&rend, gd, pose, U, -1, t);
}
glPopMatrix();
glFrontFace(GL_CCW);
+
+ glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFF);
}
glDisable(GL_STENCIL_TEST);
}
- /* Draw the scene normally. */
+ /* Ready the lights for foreground rendering. */
game_draw_light();
- if (dr->reflective)
- {
- if (config_get_d(CONFIG_REFLECTION))
- {
- /* Draw background while preserving reflections. */
-
- glEnable(GL_STENCIL_TEST);
- {
- glStencilFunc(GL_NOTEQUAL, 1, 0xFFFFFFFF);
- game_draw_back(dr, pose, +1, t);
- }
- glDisable(GL_STENCIL_TEST);
-
- /* Draw mirrors. */
+ /* When reflection is disabled, mirrors must be rendered opaque */
+ /* to prevent the background from showing. */
- game_refl_all(dr);
- }
- else
+ if (gd->draw.reflective && !config_get_d(CONFIG_REFLECTION))
+ {
+ glEnable(GL_COLOR_MATERIAL);
{
- /* Draw background. */
-
- game_draw_back(dr, pose, +1, t);
-
- /*
- * Draw mirrors, first fully opaque with a custom
- * material color, then blending normally with the
- * opaque surfaces using their original material
- * properties. (Keeps background from showing
- * through.)
- */
-
- glEnable(GL_COLOR_MATERIAL);
- {
- glColor4f(0.0, 0.0, 0.05, 1.0);
- game_refl_all(dr);
- glColor4f(1.0, 1.0, 1.0, 1.0);
- }
- glDisable(GL_COLOR_MATERIAL);
-
- game_refl_all(dr);
+ glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
+ game_refl_all(&rend, gd);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
- }
- else
- {
- game_draw_back(dr, pose, +1, t);
- game_refl_all(dr);
+ glDisable(GL_COLOR_MATERIAL);
}
- game_draw_fore(dr, pose, T, +1, t);
+ /* Draw the mirrors and the rest of the foreground. */
+
+ game_refl_all (&rend, gd);
+ game_draw_fore(&rend, gd, pose, T, +1, t);
}
glPopMatrix();
video_pop_matrix();
/* Draw the fade overlay. */
- fade_draw(dr->fade_k);
+ sol_fade(&gd->draw, gd->fade_k);
+ sol_draw_disable(&rend);
}
+
+ if (pose == POSE_LEVEL)
+ config_set_d(CONFIG_SHADOW, sh);
+}
+
+/*---------------------------------------------------------------------------*/
+
+#define CURR 0
+#define PREV 1
+
+void game_lerp_init(struct game_lerp *gl, struct game_draw *gd)
+{
+ gl->alpha = 1.0f;
+
+ sol_load_lerp(&gl->lerp, &gd->vary);
+
+ gl->tilt[PREV] = gl->tilt[CURR] = gd->tilt;
+ gl->view[PREV] = gl->view[CURR] = gd->view;
+
+ gl->goal_k[PREV] = gl->goal_k[CURR] = gd->goal_k;
+ gl->jump_dt[PREV] = gl->jump_dt[CURR] = gd->jump_dt;
+}
+
+void game_lerp_free(struct game_lerp *gl)
+{
+ sol_free_lerp(&gl->lerp);
+}
+
+void game_lerp_copy(struct game_lerp *gl)
+{
+ sol_lerp_copy(&gl->lerp);
+
+ gl->tilt[PREV] = gl->tilt[CURR];
+ gl->view[PREV] = gl->view[CURR];
+
+ gl->goal_k[PREV] = gl->goal_k[CURR];
+ gl->jump_dt[PREV] = gl->jump_dt[CURR];
+}
+
+void game_lerp_apply(struct game_lerp *gl, struct game_draw *gd)
+{
+ float a = gl->alpha;
+
+ /* Solid. */
+
+ sol_lerp_apply(&gl->lerp, a);
+
+ /* Particles. */
+
+ part_lerp_apply(a);
+
+ /* Tilt. */
+
+ v_lerp(gd->tilt.x, gl->tilt[PREV].x, gl->tilt[CURR].x, a);
+ v_lerp(gd->tilt.z, gl->tilt[PREV].z, gl->tilt[CURR].z, a);
+
+ gd->tilt.rx = (gl->tilt[PREV].rx * (1.0f - a) + gl->tilt[CURR].rx * a);
+ gd->tilt.rz = (gl->tilt[PREV].rz * (1.0f - a) + gl->tilt[CURR].rz * a);
+
+ /* View. */
+
+ v_lerp(gd->view.c, gl->view[PREV].c, gl->view[CURR].c, a);
+ v_lerp(gd->view.p, gl->view[PREV].p, gl->view[CURR].p, a);
+ e_lerp(gd->view.e, gl->view[PREV].e, gl->view[CURR].e, a);
+
+ /* Effects. */
+
+ gd->goal_k = (gl->goal_k[PREV] * (1.0f - a) + gl->goal_k[CURR] * a);
+ gd->jump_dt = (gl->jump_dt[PREV] * (1.0f - a) + gl->jump_dt[CURR] * a);
}
/*---------------------------------------------------------------------------*/