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.
27 #include "game_draw.h"
29 /*---------------------------------------------------------------------------*/
31 static void game_draw_balls(const struct s_file *fp,
32 const float *bill_M, float t)
34 float c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
39 m_basis(ball_M, fp->uv[0].e[0], fp->uv[0].e[1], fp->uv[0].e[2]);
40 m_basis(pend_M, fp->uv[0].E[0], fp->uv[0].E[1], fp->uv[0].E[2]);
42 glPushAttrib(GL_LIGHTING_BIT);
45 glTranslatef(fp->uv[0].p[0],
46 fp->uv[0].p[1] + BALL_FUDGE,
53 ball_draw(ball_M, pend_M, bill_M, t);
59 static void game_draw_items(const struct s_file *fp, float t)
64 glPushAttrib(GL_LIGHTING_BIT);
68 for (hi = 0; hi < fp->hc; hi++)
70 if (fp->hv[hi].t == ITEM_COIN && fp->hv[hi].n > 0)
74 glTranslatef(fp->hv[hi].p[0],
77 glRotatef(r, 0.0f, 1.0f, 0.0f);
78 item_draw(&fp->hv[hi], r);
85 item_push(ITEM_SHRINK);
87 for (hi = 0; hi < fp->hc; hi++)
89 if (fp->hv[hi].t == ITEM_SHRINK)
93 glTranslatef(fp->hv[hi].p[0],
96 glRotatef(r, 0.0f, 1.0f, 0.0f);
97 item_draw(&fp->hv[hi], r);
104 item_push(ITEM_GROW);
106 for (hi = 0; hi < fp->hc; hi++)
108 if (fp->hv[hi].t == ITEM_GROW)
112 glTranslatef(fp->hv[hi].p[0],
115 glRotatef(r, 0.0f, 1.0f, 0.0f);
116 item_draw(&fp->hv[hi], r);
126 static void game_draw_goals(const struct game_draw *dr,
127 const struct s_file *fp,
128 const float *M, float t)
134 /* Draw the goal particles. */
136 glEnable(GL_TEXTURE_2D);
138 for (zi = 0; zi < fp->zc; zi++)
142 glTranslatef(fp->zv[zi].p[0],
146 part_draw_goal(M, fp->zv[zi].r, dr->goal_k, t);
151 glDisable(GL_TEXTURE_2D);
153 /* Draw the goal column. */
155 for (zi = 0; zi < fp->zc; zi++)
159 glTranslatef(fp->zv[zi].p[0],
163 glScalef(fp->zv[zi].r,
174 static void game_draw_jumps(const struct game_draw *dr,
175 const struct s_file *fp,
176 const float *M, float t)
180 glEnable(GL_TEXTURE_2D);
182 for (ji = 0; ji < fp->jc; ji++)
186 glTranslatef(fp->jv[ji].p[0],
190 part_draw_jump(M, fp->jv[ji].r, 1.0f, t);
195 glDisable(GL_TEXTURE_2D);
197 for (ji = 0; ji < fp->jc; ji++)
201 glTranslatef(fp->jv[ji].p[0],
204 glScalef(fp->jv[ji].r,
208 jump_draw(!dr->jump_e);
214 static void game_draw_swchs(const struct s_file *fp)
218 for (xi = 0; xi < fp->xc; xi++)
225 glTranslatef(fp->xv[xi].p[0],
228 glScalef(fp->xv[xi].r,
232 swch_draw(fp->xv[xi].f, fp->xv[xi].e);
238 /*---------------------------------------------------------------------------*/
240 static void game_draw_tilt(const struct game_draw *dr, int d)
242 const struct game_tilt *tilt = &dr->tilt;
243 const float *ball_p = dr->file.uv->p;
245 /* Rotate the environment about the position of the ball. */
247 glTranslatef(+ball_p[0], +ball_p[1] * d, +ball_p[2]);
248 glRotatef(-tilt->rz * d, tilt->z[0], tilt->z[1], tilt->z[2]);
249 glRotatef(-tilt->rx * d, tilt->x[0], tilt->x[1], tilt->x[2]);
250 glTranslatef(-ball_p[0], -ball_p[1] * d, -ball_p[2]);
253 static void game_refl_all(const struct game_draw *dr)
257 game_draw_tilt(dr, 1);
259 /* Draw the floor. */
266 /*---------------------------------------------------------------------------*/
268 static void game_draw_light(void)
270 const float light_p[2][4] = {
271 { -8.0f, +32.0f, -8.0f, 0.0f },
272 { +8.0f, +32.0f, +8.0f, 0.0f },
274 const float light_c[2][4] = {
275 { 1.0f, 0.8f, 0.8f, 1.0f },
276 { 0.8f, 1.0f, 0.8f, 1.0f },
279 /* Configure the lighting. */
282 glLightfv(GL_LIGHT0, GL_POSITION, light_p[0]);
283 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_c[0]);
284 glLightfv(GL_LIGHT0, GL_SPECULAR, light_c[0]);
287 glLightfv(GL_LIGHT1, GL_POSITION, light_p[1]);
288 glLightfv(GL_LIGHT1, GL_DIFFUSE, light_c[1]);
289 glLightfv(GL_LIGHT1, GL_SPECULAR, light_c[1]);
292 static void game_draw_back(const struct game_draw *dr, int pose, int d, float t)
294 if (pose == POSE_BALL)
301 const struct game_tilt *tilt = &dr->tilt;
303 glRotatef(tilt->rz * 2, tilt->z[0], tilt->z[1], tilt->z[2]);
304 glRotatef(tilt->rx * 2, tilt->x[0], tilt->x[1], tilt->x[2]);
307 glTranslatef(dr->view.p[0], dr->view.p[1] * d, dr->view.p[2]);
309 if (config_get_d(CONFIG_BACKGROUND))
311 /* Draw all background layers back to front. */
313 sol_back(&dr->back, BACK_DIST, FAR_DIST, t);
315 sol_back(&dr->back, 0, BACK_DIST, t);
322 static void game_clip_refl(int d)
324 /* Fudge to eliminate the floor from reflection. */
326 GLdouble e[4], k = -0.00001;
333 glClipPlane(GL_CLIP_PLANE0, e);
336 static void game_clip_ball(const struct game_draw *dr, int d, const float *p)
338 GLdouble r, c[3], pz[4], nz[4];
340 /* Compute the plane giving the front of the ball, as seen from view.p. */
346 pz[0] = dr->view.p[0] - c[0];
347 pz[1] = dr->view.p[1] - c[1];
348 pz[2] = dr->view.p[2] - c[2];
350 r = sqrt(pz[0] * pz[0] + pz[1] * pz[1] + pz[2] * pz[2]);
355 pz[3] = -(pz[0] * c[0] +
359 /* Find the plane giving the back of the ball, as seen from view.p. */
366 /* Reflect these planes as necessary, and store them in the GL state. */
371 glClipPlane(GL_CLIP_PLANE1, nz);
372 glClipPlane(GL_CLIP_PLANE2, pz);
375 static void game_draw_fore(const struct game_draw *dr,
376 int pose, const float *M,
379 const float *ball_p = dr->file.uv->p;
380 const float ball_r = dr->file.uv->r;
382 const struct s_file *fp = &dr->file;
386 /* Rotate the environment about the position of the ball. */
388 game_draw_tilt(dr, d);
390 /* Compute clipping planes for reflection and ball facing. */
393 game_clip_ball(dr, d, ball_p);
396 glEnable(GL_CLIP_PLANE0);
405 /* Draw the coins. */
407 game_draw_items(fp, t);
409 /* Draw the floor. */
417 /* Draw the ball shadow. */
419 if (d > 0 && config_get_d(CONFIG_SHADOW))
421 shad_draw_set(ball_p, ball_r);
428 game_draw_balls(fp, M, t);
433 /* Draw the particles and light columns. */
435 glEnable(GL_COLOR_MATERIAL);
436 glDisable(GL_LIGHTING);
437 glDepthMask(GL_FALSE);
439 glColor3f(1.0f, 1.0f, 1.0f);
442 part_draw_coin(M, t);
444 glDisable(GL_TEXTURE_2D);
446 game_draw_goals(dr, fp, M, t);
447 game_draw_jumps(dr, fp, M, t);
450 glEnable(GL_TEXTURE_2D);
452 glColor3f(1.0f, 1.0f, 1.0f);
454 glDepthMask(GL_TRUE);
455 glEnable(GL_LIGHTING);
456 glDisable(GL_COLOR_MATERIAL);
459 glDisable(GL_CLIP_PLANE0);
464 /*---------------------------------------------------------------------------*/
466 void game_draw(const struct game_draw *dr, int pose, float t)
468 float fov = (float) config_get_d(CONFIG_VIEW_FOV);
470 if (dr->jump_b) fov *= 2.f * fabsf(dr->jump_dt - 0.5);
474 const struct game_view *view = &dr->view;
476 video_push_persp(fov, 0.1f, FAR_DIST);
479 float T[16], U[16], M[16], v[3];
482 /* Compute direct and reflected view bases. */
488 m_view(T, view->c, view->p, view->e[1]);
489 m_view(U, view->c, v, view->e[1]);
493 /* Apply the current view. */
495 v_sub(v, view->c, view->p);
497 glTranslatef(0.f, 0.f, -v_len(v));
499 glTranslatef(-view->c[0], -view->c[1], -view->c[2]);
501 if (dr->reflective && config_get_d(CONFIG_REFLECTION))
503 glEnable(GL_STENCIL_TEST);
505 /* Draw the mirrors only into the stencil buffer. */
507 glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
508 glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
509 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
510 glDepthMask(GL_FALSE);
514 glDepthMask(GL_TRUE);
515 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
516 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
517 glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
519 /* Draw the scene reflected into color and depth buffers. */
524 glScalef(+1.0f, -1.0f, +1.0f);
527 game_draw_back(dr, pose, -1, t);
528 game_draw_fore(dr, pose, U, -1, t);
533 glDisable(GL_STENCIL_TEST);
536 /* Draw the scene normally. */
542 if (config_get_d(CONFIG_REFLECTION))
544 /* Draw background while preserving reflections. */
546 glEnable(GL_STENCIL_TEST);
548 glStencilFunc(GL_NOTEQUAL, 1, 0xFFFFFFFF);
549 game_draw_back(dr, pose, +1, t);
551 glDisable(GL_STENCIL_TEST);
559 /* Draw background. */
561 game_draw_back(dr, pose, +1, t);
564 * Draw mirrors, first fully opaque with a custom
565 * material color, then blending normally with the
566 * opaque surfaces using their original material
567 * properties. (Keeps background from showing
571 glEnable(GL_COLOR_MATERIAL);
573 glColor4f(0.0, 0.0, 0.05, 1.0);
575 glColor4f(1.0, 1.0, 1.0, 1.0);
577 glDisable(GL_COLOR_MATERIAL);
584 game_draw_back(dr, pose, +1, t);
588 game_draw_fore(dr, pose, T, +1, t);
593 /* Draw the fade overlay. */
595 fade_draw(dr->fade_k);
599 /*---------------------------------------------------------------------------*/