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.
25 #include "solid_draw.h"
27 #include "game_draw.h"
29 /*---------------------------------------------------------------------------*/
31 static void game_draw_balls(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]);
42 glPushAttrib(GL_LIGHTING_BIT);
45 glTranslatef(vary->uv[0].p[0],
46 vary->uv[0].p[1] + BALL_FUDGE,
48 glScalef(vary->uv[0].r,
53 ball_draw(ball_M, pend_M, bill_M, t);
59 static void game_draw_items(const struct s_vary *vary, float t)
64 glPushAttrib(GL_LIGHTING_BIT);
68 for (hi = 0; hi < vary->hc; hi++)
70 if (vary->hv[hi].t == ITEM_COIN && vary->hv[hi].n > 0)
74 glTranslatef(vary->hv[hi].p[0],
77 glRotatef(r, 0.0f, 1.0f, 0.0f);
78 item_draw(&vary->hv[hi], r);
85 item_push(ITEM_SHRINK);
87 for (hi = 0; hi < vary->hc; hi++)
89 if (vary->hv[hi].t == ITEM_SHRINK)
93 glTranslatef(vary->hv[hi].p[0],
96 glRotatef(r, 0.0f, 1.0f, 0.0f);
97 item_draw(&vary->hv[hi], r);
104 item_push(ITEM_GROW);
106 for (hi = 0; hi < vary->hc; hi++)
108 if (vary->hv[hi].t == ITEM_GROW)
112 glTranslatef(vary->hv[hi].p[0],
115 glRotatef(r, 0.0f, 1.0f, 0.0f);
116 item_draw(&vary->hv[hi], r);
126 static void game_draw_goals(const struct game_draw *gd,
127 const float *M, float t)
129 const struct s_base *base = &gd->file.base;
135 /* Draw the goal particles. */
137 glEnable(GL_TEXTURE_2D);
139 for (zi = 0; zi < base->zc; zi++)
143 glTranslatef(base->zv[zi].p[0],
147 part_draw_goal(M, base->zv[zi].r, gd->goal_k, t);
152 glDisable(GL_TEXTURE_2D);
154 /* Draw the goal column. */
156 for (zi = 0; zi < base->zc; zi++)
160 glTranslatef(base->zv[zi].p[0],
164 glScalef(base->zv[zi].r,
175 static void game_draw_jumps(const struct game_draw *gd,
176 const float *M, float t)
178 const struct s_base *base = &gd->file.base;
182 glEnable(GL_TEXTURE_2D);
184 for (ji = 0; ji < base->jc; ji++)
188 glTranslatef(base->jv[ji].p[0],
192 part_draw_jump(M, base->jv[ji].r, 1.0f, t);
197 glDisable(GL_TEXTURE_2D);
199 for (ji = 0; ji < base->jc; ji++)
203 glTranslatef(base->jv[ji].p[0],
206 glScalef(base->jv[ji].r,
210 jump_draw(!gd->jump_e);
216 static void game_draw_swchs(const struct s_vary *vary)
220 for (xi = 0; xi < vary->xc; xi++)
222 struct v_swch *xp = vary->xv + xi;
229 glTranslatef(xp->base->p[0],
232 glScalef(xp->base->r,
236 swch_draw(xp->f, xp->e);
242 /*---------------------------------------------------------------------------*/
244 static void game_draw_tilt(const struct game_draw *gd, int d)
246 const struct game_tilt *tilt = &gd->tilt;
247 const float *ball_p = gd->file.vary.uv[0].p;
249 /* Rotate the environment about the position of the ball. */
251 glTranslatef(+ball_p[0], +ball_p[1] * d, +ball_p[2]);
252 glRotatef(-tilt->rz * d, tilt->z[0], tilt->z[1], tilt->z[2]);
253 glRotatef(-tilt->rx * d, tilt->x[0], tilt->x[1], tilt->x[2]);
254 glTranslatef(-ball_p[0], -ball_p[1] * d, -ball_p[2]);
257 static void game_refl_all(const struct game_draw *gd)
261 game_draw_tilt(gd, 1);
263 /* Draw the floor. */
265 sol_refl(&gd->file.draw);
270 /*---------------------------------------------------------------------------*/
272 static void game_draw_light(void)
274 const float light_p[2][4] = {
275 { -8.0f, +32.0f, -8.0f, 0.0f },
276 { +8.0f, +32.0f, +8.0f, 0.0f },
278 const float light_c[2][4] = {
279 { 1.0f, 0.8f, 0.8f, 1.0f },
280 { 0.8f, 1.0f, 0.8f, 1.0f },
283 /* Configure the lighting. */
286 glLightfv(GL_LIGHT0, GL_POSITION, light_p[0]);
287 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_c[0]);
288 glLightfv(GL_LIGHT0, GL_SPECULAR, light_c[0]);
291 glLightfv(GL_LIGHT1, GL_POSITION, light_p[1]);
292 glLightfv(GL_LIGHT1, GL_DIFFUSE, light_c[1]);
293 glLightfv(GL_LIGHT1, GL_SPECULAR, light_c[1]);
296 static void game_draw_back(const struct game_draw *gd, int pose, int d, float t)
298 if (pose == POSE_BALL)
303 const struct game_view *view = &gd->view;
307 const struct game_tilt *tilt = &gd->tilt;
309 glRotatef(tilt->rz * 2, tilt->z[0], tilt->z[1], tilt->z[2]);
310 glRotatef(tilt->rx * 2, tilt->x[0], tilt->x[1], tilt->x[2]);
313 glTranslatef(view->p[0], view->p[1] * d, view->p[2]);
315 if (config_get_d(CONFIG_BACKGROUND))
317 /* Draw all background layers back to front. */
319 sol_back(&gd->back.draw, BACK_DIST, FAR_DIST, t);
321 sol_back(&gd->back.draw, 0, BACK_DIST, t);
328 static void game_clip_refl(int d)
330 /* Fudge to eliminate the floor from reflection. */
332 GLdouble e[4], k = -0.00001;
339 glClipPlane(GL_CLIP_PLANE0, e);
342 static void game_clip_ball(const struct game_draw *gd, int d, const float *p)
344 GLdouble r, c[3], pz[4], nz[4];
346 /* Compute the plane giving the front of the ball, as seen from view.p. */
352 pz[0] = gd->view.p[0] - c[0];
353 pz[1] = gd->view.p[1] - c[1];
354 pz[2] = gd->view.p[2] - c[2];
356 r = sqrt(pz[0] * pz[0] + pz[1] * pz[1] + pz[2] * pz[2]);
361 pz[3] = -(pz[0] * c[0] +
365 /* Find the plane giving the back of the ball, as seen from view.p. */
372 /* Reflect these planes as necessary, and store them in the GL state. */
377 glClipPlane(GL_CLIP_PLANE1, nz);
378 glClipPlane(GL_CLIP_PLANE2, pz);
381 static void game_draw_fore(const struct game_draw *gd,
382 int pose, const float *M,
385 const float *ball_p = gd->file.vary.uv[0].p;
386 const float ball_r = gd->file.vary.uv[0].r;
388 const struct s_draw *draw = &gd->file.draw;
392 /* Rotate the environment about the position of the ball. */
394 game_draw_tilt(gd, d);
396 /* Compute clipping planes for reflection and ball facing. */
399 game_clip_ball(gd, d, ball_p);
402 glEnable(GL_CLIP_PLANE0);
407 sol_draw(draw, 0, 1);
411 /* Draw the coins. */
413 game_draw_items(draw->vary, t);
415 /* Draw the floor. */
417 sol_draw(draw, 0, 1);
423 /* Draw the ball shadow. */
425 if (d > 0 && config_get_d(CONFIG_SHADOW))
427 shad_draw_set(ball_p, ball_r);
434 game_draw_balls(draw->vary, M, t);
439 /* Draw the particles and light columns. */
441 glEnable(GL_COLOR_MATERIAL);
442 glDisable(GL_LIGHTING);
443 glDepthMask(GL_FALSE);
445 glColor3f(1.0f, 1.0f, 1.0f);
447 sol_bill(draw, M, t);
448 part_draw_coin(M, t);
450 glDisable(GL_TEXTURE_2D);
452 game_draw_goals(gd, M, t);
453 game_draw_jumps(gd, M, t);
454 game_draw_swchs(draw->vary);
456 glEnable(GL_TEXTURE_2D);
458 glColor3f(1.0f, 1.0f, 1.0f);
460 glDepthMask(GL_TRUE);
461 glEnable(GL_LIGHTING);
462 glDisable(GL_COLOR_MATERIAL);
465 glDisable(GL_CLIP_PLANE0);
470 /*---------------------------------------------------------------------------*/
472 void game_draw(const struct game_draw *gd, int pose, float t)
474 float fov = (float) config_get_d(CONFIG_VIEW_FOV);
476 if (gd->jump_b) fov *= 2.f * fabsf(gd->jump_dt - 0.5);
480 const struct game_view *view = &gd->view;
482 video_push_persp(fov, 0.1f, FAR_DIST);
485 float T[16], U[16], M[16], v[3];
488 /* Compute direct and reflected view bases. */
494 m_view(T, view->c, view->p, view->e[1]);
495 m_view(U, view->c, v, view->e[1]);
499 /* Apply the current view. */
501 v_sub(v, view->c, view->p);
503 glTranslatef(0.f, 0.f, -v_len(v));
505 glTranslatef(-view->c[0], -view->c[1], -view->c[2]);
507 if (gd->reflective && config_get_d(CONFIG_REFLECTION))
509 glEnable(GL_STENCIL_TEST);
511 /* Draw the mirrors only into the stencil buffer. */
513 glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
514 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
515 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
516 glDepthMask(GL_FALSE);
520 glDepthMask(GL_TRUE);
521 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
522 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
523 glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
525 /* Draw the scene reflected into color and depth buffers. */
530 glScalef(+1.0f, -1.0f, +1.0f);
533 game_draw_back(gd, pose, -1, t);
534 game_draw_fore(gd, pose, U, -1, t);
539 glDisable(GL_STENCIL_TEST);
542 /* Draw the scene normally. */
548 if (config_get_d(CONFIG_REFLECTION))
550 /* Draw background while preserving reflections. */
552 glEnable(GL_STENCIL_TEST);
554 glStencilFunc(GL_NOTEQUAL, 1, 0xFFFFFFFF);
555 game_draw_back(gd, pose, +1, t);
557 glDisable(GL_STENCIL_TEST);
565 /* Draw background. */
567 game_draw_back(gd, pose, +1, t);
570 * Draw mirrors, first fully opaque with a custom
571 * material color, then blending normally with the
572 * opaque surfaces using their original material
573 * properties. (Keeps background from showing
577 glEnable(GL_COLOR_MATERIAL);
579 glColor4f(0.0, 0.0, 0.05, 1.0);
581 glColor4f(1.0, 1.0, 1.0, 1.0);
583 glDisable(GL_COLOR_MATERIAL);
590 game_draw_back(gd, pose, +1, t);
594 game_draw_fore(gd, pose, T, +1, t);
599 /* Draw the fade overlay. */
601 fade_draw(gd->fade_k);
605 /*---------------------------------------------------------------------------*/