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(struct s_rend *rend,
31 const struct s_vary *vary,
32 const float *bill_M, float t)
34 float c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
39 m_basis(ball_M, vary->uv[0].e[0], vary->uv[0].e[1], vary->uv[0].e[2]);
40 m_basis(pend_M, vary->uv[0].E[0], vary->uv[0].E[1], vary->uv[0].E[2]);
44 glTranslatef(vary->uv[0].p[0],
45 vary->uv[0].p[1] + BALL_FUDGE,
47 glScalef(vary->uv[0].r,
51 glColor4f(c[0], c[1], c[2], c[3]);
52 ball_draw(rend, ball_M, pend_M, bill_M, t);
57 static void game_draw_items(struct s_rend *rend,
58 const struct s_vary *vary,
59 const float *bill_M, float t)
63 glEnable(GL_COLOR_MATERIAL);
65 for (hi = 0; hi < vary->hc; hi++)
66 if (vary->hv[hi].t == ITEM_COIN && vary->hv[hi].n > 0)
70 glTranslatef(vary->hv[hi].p[0],
73 item_draw(rend, &vary->hv[hi], bill_M, t);
78 for (hi = 0; hi < vary->hc; hi++)
79 if (vary->hv[hi].t == ITEM_SHRINK)
83 glTranslatef(vary->hv[hi].p[0],
86 item_draw(rend, &vary->hv[hi], bill_M, t);
91 for (hi = 0; hi < vary->hc; hi++)
92 if (vary->hv[hi].t == ITEM_GROW)
96 glTranslatef(vary->hv[hi].p[0],
99 item_draw(rend, &vary->hv[hi], bill_M, t);
105 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
106 glDisable(GL_COLOR_MATERIAL);
109 static void game_draw_goals(struct s_rend *rend,
110 const struct game_draw *gd,
111 const float *M, float t)
113 const struct s_base *base = gd->vary.base;
119 /* Draw the goal column. */
121 for (zi = 0; zi < base->zc; zi++)
125 glTranslatef(base->zv[zi].p[0],
129 glScalef(base->zv[zi].r,
140 static void game_draw_jumps(struct s_rend *rend,
141 const struct game_draw *gd,
142 const float *M, float t)
144 const struct s_base *base = gd->vary.base;
148 for (ji = 0; ji < base->jc; ji++)
152 glTranslatef(base->jv[ji].p[0],
155 glScalef(base->jv[ji].r,
159 jump_draw(rend, t, !gd->jump_e);
165 static void game_draw_swchs(struct s_rend *rend, const struct s_vary *vary)
169 for (xi = 0; xi < vary->xc; xi++)
171 struct v_swch *xp = vary->xv + xi;
178 glTranslatef(xp->base->p[0],
181 glScalef(xp->base->r,
185 swch_draw(rend, xp->f, xp->e);
191 /*---------------------------------------------------------------------------*/
193 static void game_draw_tilt(const struct game_draw *gd, int d)
195 const struct game_tilt *tilt = &gd->tilt;
196 const float *ball_p = gd->vary.uv[0].p;
198 /* Rotate the environment about the position of the ball. */
200 glTranslatef(+ball_p[0], +ball_p[1] * d, +ball_p[2]);
201 glRotatef(-tilt->rz * d, tilt->z[0], tilt->z[1], tilt->z[2]);
202 glRotatef(-tilt->rx * d, tilt->x[0], tilt->x[1], tilt->x[2]);
203 glTranslatef(-ball_p[0], -ball_p[1] * d, -ball_p[2]);
206 static void game_refl_all(struct s_rend *rend, const struct game_draw *gd)
210 game_draw_tilt(gd, 1);
212 /* Draw the floor. */
214 sol_refl(&gd->draw, rend);
219 /*---------------------------------------------------------------------------*/
221 static void game_draw_light(void)
223 const float light_p[2][4] = {
224 { -8.0f, +32.0f, -8.0f, 0.0f },
225 { +8.0f, +32.0f, +8.0f, 0.0f },
227 const float light_c[2][4] = {
228 { 1.0f, 0.8f, 0.8f, 1.0f },
229 { 0.8f, 1.0f, 0.8f, 1.0f },
232 /* Configure the lighting. */
235 glLightfv(GL_LIGHT0, GL_POSITION, light_p[0]);
236 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_c[0]);
237 glLightfv(GL_LIGHT0, GL_SPECULAR, light_c[0]);
240 glLightfv(GL_LIGHT1, GL_POSITION, light_p[1]);
241 glLightfv(GL_LIGHT1, GL_DIFFUSE, light_c[1]);
242 glLightfv(GL_LIGHT1, GL_SPECULAR, light_c[1]);
245 static void game_draw_back(struct s_rend *rend,
246 const struct game_draw *gd,
247 int pose, int d, float t)
249 if (pose == POSE_BALL)
254 const struct game_view *view = &gd->view;
258 const struct game_tilt *tilt = &gd->tilt;
260 glRotatef(tilt->rz * 2, tilt->z[0], tilt->z[1], tilt->z[2]);
261 glRotatef(tilt->rx * 2, tilt->x[0], tilt->x[1], tilt->x[2]);
264 glTranslatef(view->p[0], view->p[1] * d, view->p[2]);
266 if (config_get_d(CONFIG_BACKGROUND))
269 sol_back(&gd->back.draw, rend, 0, FAR_DIST, t);
271 else back_draw(rend, 0);
276 static void game_clip_refl(int d)
278 /* Fudge to eliminate the floor from reflection. */
280 glClipPlane4f(GL_CLIP_PLANE0, 0, 1, 0, -0.00001);
283 static void game_clip_ball(const struct game_draw *gd, int d, const float *p)
285 GLfloat r, c[3], pz[4], nz[4];
287 /* Compute the plane giving the front of the ball, as seen from view.p. */
293 pz[0] = gd->view.p[0] - c[0];
294 pz[1] = gd->view.p[1] - c[1];
295 pz[2] = gd->view.p[2] - c[2];
297 r = sqrt(pz[0] * pz[0] + pz[1] * pz[1] + pz[2] * pz[2]);
302 pz[3] = -(pz[0] * c[0] +
306 /* Find the plane giving the back of the ball, as seen from view.p. */
313 /* Reflect these planes as necessary, and store them in the GL state. */
318 glClipPlane4f(GL_CLIP_PLANE1, nz[0], nz[1], nz[2], nz[3]);
319 glClipPlane4f(GL_CLIP_PLANE2, pz[0], pz[1], pz[2], pz[3]);
322 static void game_draw_fore(struct s_rend *rend,
323 const struct game_draw *gd,
324 int pose, const float *M,
327 const float *ball_p = gd->vary.uv[0].p;
329 const struct s_draw *draw = &gd->draw;
333 /* Rotate the environment about the position of the ball. */
335 game_draw_tilt(gd, d);
337 /* Compute clipping planes for reflection and ball facing. */
340 game_clip_ball(gd, d, ball_p);
343 glEnable(GL_CLIP_PLANE0);
348 sol_draw(draw, rend, 0, 1);
352 /* Draw the floor. */
354 sol_draw(draw, rend, 0, 1);
356 /* Draw the coins. */
358 game_draw_items(rend, draw->vary, M, t);
366 game_draw_balls(rend, draw->vary, M, t);
371 /* Draw the billboards, entities, and particles. */
373 glEnable(GL_COLOR_MATERIAL);
374 glDisable(GL_LIGHTING);
375 glDepthMask(GL_FALSE);
377 sol_bill(draw, rend, M, t);
379 game_draw_goals(rend, gd, M, t);
380 game_draw_jumps(rend, gd, M, t);
381 game_draw_swchs(rend, draw->vary);
383 part_draw_coin(rend);
384 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
386 glDepthMask(GL_TRUE);
387 glEnable(GL_LIGHTING);
388 glDisable(GL_COLOR_MATERIAL);
391 glDisable(GL_CLIP_PLANE0);
396 /*---------------------------------------------------------------------------*/
398 void game_draw(const struct game_draw *gd, int pose, float t)
400 float fov = (float) config_get_d(CONFIG_VIEW_FOV);
402 if (gd->jump_b) fov *= 2.f * fabsf(gd->jump_dt - 0.5);
406 const struct game_view *view = &gd->view;
409 sol_draw_enable(&rend);
411 video_push_persp(fov, 0.1f, FAR_DIST);
414 float T[16], U[16], M[16], v[3];
416 /* Compute direct and reflected view bases. */
422 m_view(T, view->c, view->p, view->e[1]);
423 m_view(U, view->c, v, view->e[1]);
427 /* Apply the current view. */
429 v_sub(v, view->c, view->p);
431 glTranslatef(0.f, 0.f, -v_len(v));
433 glTranslatef(-view->c[0], -view->c[1], -view->c[2]);
435 /* Draw the background. */
437 game_draw_back(&rend, gd, pose, +1, t);
439 /* Draw the reflection. */
441 if (gd->draw.reflective && config_get_d(CONFIG_REFLECTION))
443 glEnable(GL_STENCIL_TEST);
445 /* Draw the mirrors only into the stencil buffer. */
447 glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
448 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
449 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
450 glDepthMask(GL_FALSE);
452 game_refl_all(&rend, gd);
454 glDepthMask(GL_TRUE);
455 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
456 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
457 glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
459 /* Draw the scene reflected into color and depth buffers. */
464 glScalef(+1.0f, -1.0f, +1.0f);
468 game_draw_back(&rend, gd, pose, -1, t);
469 game_draw_fore(&rend, gd, pose, U, -1, t);
474 glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFF);
476 glDisable(GL_STENCIL_TEST);
479 /* Ready the lights for foreground rendering. */
483 /* When reflection is disabled, mirrors must be rendered opaque */
484 /* to prevent the background from showing. */
486 if (gd->draw.reflective && !config_get_d(CONFIG_REFLECTION))
488 glEnable(GL_COLOR_MATERIAL);
490 glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
491 game_refl_all(&rend, gd);
492 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
494 glDisable(GL_COLOR_MATERIAL);
497 /* Draw the mirrors and the rest of the foreground. */
499 game_refl_all (&rend, gd);
500 game_draw_fore(&rend, gd, pose, T, +1, t);
505 /* Draw the fade overlay. */
507 sol_fade(&gd->draw, gd->fade_k);
508 sol_draw_disable(&rend);
512 /*---------------------------------------------------------------------------*/
517 void game_lerp_init(struct game_lerp *gl, struct game_draw *gd)
521 sol_load_lerp(&gl->lerp, &gd->vary);
523 gl->tilt[PREV] = gl->tilt[CURR] = gd->tilt;
524 gl->view[PREV] = gl->view[CURR] = gd->view;
526 gl->goal_k[PREV] = gl->goal_k[CURR] = gd->goal_k;
527 gl->jump_dt[PREV] = gl->jump_dt[CURR] = gd->jump_dt;
530 void game_lerp_free(struct game_lerp *gl)
532 sol_free_lerp(&gl->lerp);
535 void game_lerp_copy(struct game_lerp *gl)
537 sol_lerp_copy(&gl->lerp);
539 gl->tilt[PREV] = gl->tilt[CURR];
540 gl->view[PREV] = gl->view[CURR];
542 gl->goal_k[PREV] = gl->goal_k[CURR];
543 gl->jump_dt[PREV] = gl->jump_dt[CURR];
546 void game_lerp_apply(struct game_lerp *gl, struct game_draw *gd)
552 sol_lerp_apply(&gl->lerp, a);
560 v_lerp(gd->tilt.x, gl->tilt[PREV].x, gl->tilt[CURR].x, a);
561 v_lerp(gd->tilt.z, gl->tilt[PREV].z, gl->tilt[CURR].z, a);
563 gd->tilt.rx = (gl->tilt[PREV].rx * (1.0f - a) + gl->tilt[CURR].rx * a);
564 gd->tilt.rz = (gl->tilt[PREV].rz * (1.0f - a) + gl->tilt[CURR].rz * a);
568 v_lerp(gd->view.c, gl->view[PREV].c, gl->view[CURR].c, a);
569 v_lerp(gd->view.p, gl->view[PREV].p, gl->view[CURR].p, a);
570 e_lerp(gd->view.e, gl->view[PREV].e, gl->view[CURR].e, a);
574 gd->goal_k = (gl->goal_k[PREV] * (1.0f - a) + gl->goal_k[CURR] * a);
575 gd->jump_dt = (gl->jump_dt[PREV] * (1.0f - a) + gl->jump_dt[CURR] * a);
578 /*---------------------------------------------------------------------------*/