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.
24 #include "solid_draw.h"
26 #include "game_draw.h"
28 /*---------------------------------------------------------------------------*/
30 static void game_draw_balls(const struct s_vary *vary,
31 const float *bill_M, float t)
33 float c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
38 m_basis(ball_M, vary->uv[0].e[0], vary->uv[0].e[1], vary->uv[0].e[2]);
39 m_basis(pend_M, vary->uv[0].E[0], vary->uv[0].E[1], vary->uv[0].E[2]);
41 glPushAttrib(GL_LIGHTING_BIT);
44 glTranslatef(vary->uv[0].p[0],
45 vary->uv[0].p[1] + BALL_FUDGE,
47 glScalef(vary->uv[0].r,
52 ball_draw(ball_M, pend_M, bill_M, t);
58 static void game_draw_items(const struct s_vary *vary, float t)
63 glPushAttrib(GL_LIGHTING_BIT);
67 for (hi = 0; hi < vary->hc; hi++)
69 if (vary->hv[hi].t == ITEM_COIN && vary->hv[hi].n > 0)
73 glTranslatef(vary->hv[hi].p[0],
76 glRotatef(r, 0.0f, 1.0f, 0.0f);
77 item_draw(&vary->hv[hi], r);
84 item_push(ITEM_SHRINK);
86 for (hi = 0; hi < vary->hc; hi++)
88 if (vary->hv[hi].t == ITEM_SHRINK)
92 glTranslatef(vary->hv[hi].p[0],
95 glRotatef(r, 0.0f, 1.0f, 0.0f);
96 item_draw(&vary->hv[hi], r);
103 item_push(ITEM_GROW);
105 for (hi = 0; hi < vary->hc; hi++)
107 if (vary->hv[hi].t == ITEM_GROW)
111 glTranslatef(vary->hv[hi].p[0],
114 glRotatef(r, 0.0f, 1.0f, 0.0f);
115 item_draw(&vary->hv[hi], r);
125 static void game_draw_goals(const struct game_draw *gd,
126 const float *M, float t)
128 const struct s_base *base = gd->vary.base;
134 /* Draw the goal particles. */
136 for (zi = 0; zi < base->zc; zi++)
140 glTranslatef(base->zv[zi].p[0],
144 part_draw_goal(M, base->zv[zi].r, gd->goal_k, t);
149 /* Draw the goal column. */
151 for (zi = 0; zi < base->zc; zi++)
155 glTranslatef(base->zv[zi].p[0],
159 glScalef(base->zv[zi].r,
170 static void game_draw_jumps(const struct game_draw *gd,
171 const float *M, float t)
173 const struct s_base *base = gd->vary.base;
177 for (ji = 0; ji < base->jc; ji++)
181 glTranslatef(base->jv[ji].p[0],
185 part_draw_jump(M, base->jv[ji].r, 1.0f, t);
190 for (ji = 0; ji < base->jc; ji++)
194 glTranslatef(base->jv[ji].p[0],
197 glScalef(base->jv[ji].r,
201 jump_draw(!gd->jump_e);
207 static void game_draw_swchs(const struct s_vary *vary)
211 for (xi = 0; xi < vary->xc; xi++)
213 struct v_swch *xp = vary->xv + xi;
220 glTranslatef(xp->base->p[0],
223 glScalef(xp->base->r,
227 swch_draw(xp->f, xp->e);
233 /*---------------------------------------------------------------------------*/
235 static void game_draw_tilt(const struct game_draw *gd, int d)
237 const struct game_tilt *tilt = &gd->tilt;
238 const float *ball_p = gd->vary.uv[0].p;
240 /* Rotate the environment about the position of the ball. */
242 glTranslatef(+ball_p[0], +ball_p[1] * d, +ball_p[2]);
243 glRotatef(-tilt->rz * d, tilt->z[0], tilt->z[1], tilt->z[2]);
244 glRotatef(-tilt->rx * d, tilt->x[0], tilt->x[1], tilt->x[2]);
245 glTranslatef(-ball_p[0], -ball_p[1] * d, -ball_p[2]);
248 static void game_refl_all(const struct game_draw *gd)
252 game_draw_tilt(gd, 1);
254 /* Draw the floor. */
261 /*---------------------------------------------------------------------------*/
263 static void game_draw_light(void)
265 const float light_p[2][4] = {
266 { -8.0f, +32.0f, -8.0f, 0.0f },
267 { +8.0f, +32.0f, +8.0f, 0.0f },
269 const float light_c[2][4] = {
270 { 1.0f, 0.8f, 0.8f, 1.0f },
271 { 0.8f, 1.0f, 0.8f, 1.0f },
274 /* Configure the lighting. */
277 glLightfv(GL_LIGHT0, GL_POSITION, light_p[0]);
278 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_c[0]);
279 glLightfv(GL_LIGHT0, GL_SPECULAR, light_c[0]);
282 glLightfv(GL_LIGHT1, GL_POSITION, light_p[1]);
283 glLightfv(GL_LIGHT1, GL_DIFFUSE, light_c[1]);
284 glLightfv(GL_LIGHT1, GL_SPECULAR, light_c[1]);
287 static void game_draw_back(const struct game_draw *gd, int pose, int d, float t)
289 if (pose == POSE_BALL)
294 const struct game_view *view = &gd->view;
298 const struct game_tilt *tilt = &gd->tilt;
300 glRotatef(tilt->rz * 2, tilt->z[0], tilt->z[1], tilt->z[2]);
301 glRotatef(tilt->rx * 2, tilt->x[0], tilt->x[1], tilt->x[2]);
304 glTranslatef(view->p[0], view->p[1] * d, view->p[2]);
306 if (config_get_d(CONFIG_BACKGROUND))
308 /* Draw all background layers back to front. */
310 sol_back(&gd->back.draw, BACK_DIST, FAR_DIST, t);
312 sol_back(&gd->back.draw, 0, BACK_DIST, t);
319 static void game_clip_refl(int d)
321 /* Fudge to eliminate the floor from reflection. */
323 GLdouble e[4], k = -0.00001;
330 glClipPlane(GL_CLIP_PLANE0, e);
333 static void game_clip_ball(const struct game_draw *gd, int d, const float *p)
335 GLdouble r, c[3], pz[4], nz[4];
337 /* Compute the plane giving the front of the ball, as seen from view.p. */
343 pz[0] = gd->view.p[0] - c[0];
344 pz[1] = gd->view.p[1] - c[1];
345 pz[2] = gd->view.p[2] - c[2];
347 r = sqrt(pz[0] * pz[0] + pz[1] * pz[1] + pz[2] * pz[2]);
352 pz[3] = -(pz[0] * c[0] +
356 /* Find the plane giving the back of the ball, as seen from view.p. */
363 /* Reflect these planes as necessary, and store them in the GL state. */
368 glClipPlane(GL_CLIP_PLANE1, nz);
369 glClipPlane(GL_CLIP_PLANE2, pz);
372 static void game_draw_fore(const struct game_draw *gd,
373 int pose, const float *M,
376 const float *ball_p = gd->vary.uv[0].p;
378 const struct s_draw *draw = &gd->draw;
382 /* Rotate the environment about the position of the ball. */
384 game_draw_tilt(gd, d);
386 /* Compute clipping planes for reflection and ball facing. */
389 game_clip_ball(gd, d, ball_p);
392 glEnable(GL_CLIP_PLANE0);
397 sol_draw(draw, 0, 1);
401 /* Draw the coins. */
403 game_draw_items(draw->vary, t);
405 /* Draw the floor. */
407 sol_draw(draw, 0, 1);
413 /* Draw the ball shadow. */
415 if (d > 0 && config_get_d(CONFIG_SHADOW))
424 game_draw_balls(draw->vary, M, t);
429 /* Draw the particles and light columns. */
431 glEnable(GL_COLOR_MATERIAL);
432 glDisable(GL_LIGHTING);
433 glDepthMask(GL_FALSE);
435 sol_bill(draw, M, t);
436 part_draw_coin(M, t);
438 game_draw_goals(gd, M, t);
439 game_draw_jumps(gd, M, t);
440 game_draw_swchs(draw->vary);
442 glDepthMask(GL_TRUE);
443 glEnable(GL_LIGHTING);
444 glDisable(GL_COLOR_MATERIAL);
447 glDisable(GL_CLIP_PLANE0);
452 /*---------------------------------------------------------------------------*/
454 void game_draw(const struct game_draw *gd, int pose, float t)
456 float fov = (float) config_get_d(CONFIG_VIEW_FOV);
458 if (gd->jump_b) fov *= 2.f * fabsf(gd->jump_dt - 0.5);
462 const struct game_view *view = &gd->view;
464 video_push_persp(fov, 0.1f, FAR_DIST);
467 float T[16], U[16], M[16], v[3];
469 /* Compute direct and reflected view bases. */
475 m_view(T, view->c, view->p, view->e[1]);
476 m_view(U, view->c, v, view->e[1]);
480 /* Apply the current view. */
482 v_sub(v, view->c, view->p);
484 glTranslatef(0.f, 0.f, -v_len(v));
486 glTranslatef(-view->c[0], -view->c[1], -view->c[2]);
488 if (gd->draw.reflective && config_get_d(CONFIG_REFLECTION))
490 glEnable(GL_STENCIL_TEST);
492 /* Draw the mirrors only into the stencil buffer. */
494 glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
495 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
496 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
497 glDepthMask(GL_FALSE);
501 glDepthMask(GL_TRUE);
502 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
503 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
504 glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
506 /* Draw the scene reflected into color and depth buffers. */
511 glScalef(+1.0f, -1.0f, +1.0f);
514 game_draw_back(gd, pose, -1, t);
515 game_draw_fore(gd, pose, U, -1, t);
520 glDisable(GL_STENCIL_TEST);
523 /* Draw the scene normally. */
527 if (gd->draw.reflective)
529 if (config_get_d(CONFIG_REFLECTION))
531 /* Draw background while preserving reflections. */
533 glEnable(GL_STENCIL_TEST);
535 glStencilFunc(GL_NOTEQUAL, 1, 0xFFFFFFFF);
536 game_draw_back(gd, pose, +1, t);
538 glDisable(GL_STENCIL_TEST);
546 /* Draw background. */
548 game_draw_back(gd, pose, +1, t);
551 * Draw mirrors, first fully opaque with a custom
552 * material color, then blending normally with the
553 * opaque surfaces using their original material
554 * properties. (Keeps background from showing
558 glEnable(GL_COLOR_MATERIAL);
560 glColor4f(0.0, 0.0, 0.05, 1.0);
562 glColor4f(1.0, 1.0, 1.0, 1.0);
564 glDisable(GL_COLOR_MATERIAL);
571 game_draw_back(gd, pose, +1, t);
575 game_draw_fore(gd, pose, T, +1, t);
580 /* Draw the fade overlay. */
582 sol_fade(&gd->draw, gd->fade_k);
586 /*---------------------------------------------------------------------------*/
591 void game_lerp_init(struct game_lerp *gl, struct game_draw *gd)
595 sol_load_lerp(&gl->lerp, &gd->vary);
597 gl->tilt[PREV] = gl->tilt[CURR] = gd->tilt;
598 gl->view[PREV] = gl->view[CURR] = gd->view;
600 gl->goal_k[PREV] = gl->goal_k[CURR] = gd->goal_k;
601 gl->jump_dt[PREV] = gl->jump_dt[CURR] = gd->jump_dt;
604 void game_lerp_free(struct game_lerp *gl)
606 sol_free_lerp(&gl->lerp);
609 void game_lerp_copy(struct game_lerp *gl)
611 sol_lerp_copy(&gl->lerp);
613 gl->tilt[PREV] = gl->tilt[CURR];
614 gl->view[PREV] = gl->view[CURR];
616 gl->goal_k[PREV] = gl->goal_k[CURR];
617 gl->jump_dt[PREV] = gl->jump_dt[CURR];
620 void game_lerp_apply(struct game_lerp *gl, struct game_draw *gd)
626 sol_lerp_apply(&gl->lerp, a);
634 v_lerp(gd->tilt.x, gl->tilt[PREV].x, gl->tilt[CURR].x, a);
635 v_lerp(gd->tilt.z, gl->tilt[PREV].z, gl->tilt[CURR].z, a);
637 gd->tilt.rx = (gl->tilt[PREV].rx * (1.0f - a) + gl->tilt[CURR].rx * a);
638 gd->tilt.rz = (gl->tilt[PREV].rz * (1.0f - a) + gl->tilt[CURR].rz * a);
642 v_lerp(gd->view.c, gl->view[PREV].c, gl->view[CURR].c, a);
643 v_lerp(gd->view.p, gl->view[PREV].p, gl->view[CURR].p, a);
644 e_lerp(gd->view.e, gl->view[PREV].e, gl->view[CURR].e, a);
648 gd->goal_k = (gl->goal_k[PREV] * (1.0f - a) + gl->goal_k[CURR] * a);
649 gd->jump_dt = (gl->jump_dt[PREV] * (1.0f - a) + gl->jump_dt[CURR] * a);
652 /*---------------------------------------------------------------------------*/