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.
23 #include "solid_draw.h"
25 /*---------------------------------------------------------------------------*/
27 static int has_solid = 0;
28 static int has_inner = 0;
29 static int has_outer = 0;
31 static struct s_full solid;
32 static struct s_full inner;
33 static struct s_full outer;
39 #define F_DEPTHTEST 16
41 static int solid_flags;
42 static int inner_flags;
43 static int outer_flags;
45 static float solid_alpha;
46 static float inner_alpha;
47 static float outer_alpha;
49 /*---------------------------------------------------------------------------*/
51 #define SET(B, v, b) ((v) ? ((B) | (b)) : ((B) & ~(b)))
53 static int ball_opts(const struct s_base *base, float *alpha)
55 int flags = F_DEPTHTEST;
58 for (di = 0; di < base->dc; ++di)
60 char *k = base->av + base->dv[di].ai;
61 char *v = base->av + base->dv[di].aj;
63 if (strcmp(k, "pendulum") == 0)
64 flags = SET(flags, atoi(v), F_PENDULUM);
65 if (strcmp(k, "drawback") == 0)
66 flags = SET(flags, atoi(v), F_DRAWBACK);
67 if (strcmp(k, "drawclip") == 0)
68 flags = SET(flags, atoi(v), F_DRAWCLIP);
69 if (strcmp(k, "depthmask") == 0)
70 flags = SET(flags, atoi(v), F_DEPTHMASK);
71 if (strcmp(k, "depthtest") == 0)
72 flags = SET(flags, atoi(v), F_DEPTHTEST);
73 if (strcmp(k, "alphatest") == 0)
74 sscanf(v, "%f", alpha);
82 char *solid_file = concat_string(config_get_s(CONFIG_BALL_FILE),
84 char *inner_file = concat_string(config_get_s(CONFIG_BALL_FILE),
86 char *outer_file = concat_string(config_get_s(CONFIG_BALL_FILE),
97 if ((has_solid = sol_load_full(&solid, solid_file, 0)))
98 solid_flags = ball_opts(&solid.base, &solid_alpha);
100 if ((has_inner = sol_load_full(&inner, inner_file, 0)))
101 inner_flags = ball_opts(&inner.base, &inner_alpha);
103 if ((has_outer = sol_load_full(&outer, outer_file, 0)))
104 outer_flags = ball_opts(&outer.base, &outer_alpha);
113 if (has_outer) sol_free_full(&outer);
114 if (has_inner) sol_free_full(&inner);
115 if (has_solid) sol_free_full(&solid);
117 has_solid = has_inner = has_outer = 0;
120 /*---------------------------------------------------------------------------*/
122 static void ball_draw_solid(const float *ball_M,
123 const float *ball_bill_M, float t)
127 const int mask = (solid_flags & F_DEPTHMASK);
128 const int test = (solid_flags & F_DEPTHTEST);
130 if (solid_alpha < 1.0f)
132 glEnable(GL_ALPHA_TEST);
133 glAlphaFunc(GL_GEQUAL, solid_alpha);
138 /* Apply the ball rotation. */
140 glMultMatrixf(ball_M);
142 /* Draw the solid billboard geometry. */
146 if (test == 0) glDisable(GL_DEPTH_TEST);
147 if (mask == 0) glDepthMask(GL_FALSE);
148 glDisable(GL_LIGHTING);
150 sol_bill(&solid.draw, ball_bill_M, t);
152 glEnable(GL_LIGHTING);
153 if (mask == 0) glDepthMask(GL_TRUE);
154 if (test == 0) glEnable(GL_DEPTH_TEST);
157 /* Draw the solid opaque and transparent geometry. */
159 sol_draw(&solid.draw, mask, test);
163 if (solid_alpha < 1.0f)
164 glDisable(GL_ALPHA_TEST);
168 static void ball_draw_inner(const float *pend_M,
170 const float *pend_bill_M, float t)
174 const int pend = (inner_flags & F_PENDULUM);
175 const int mask = (inner_flags & F_DEPTHMASK);
176 const int test = (inner_flags & F_DEPTHTEST);
178 if (inner_alpha < 1.0f)
180 glEnable(GL_ALPHA_TEST);
181 glAlphaFunc(GL_GEQUAL, inner_alpha);
184 /* Apply the pendulum rotation. */
189 glMultMatrixf(pend_M);
192 /* Draw the inner opaque and transparent geometry. */
194 sol_draw(&inner.draw, mask, test);
196 /* Draw the inner billboard geometry. */
200 if (test == 0) glDisable(GL_DEPTH_TEST);
201 if (mask == 0) glDepthMask(GL_FALSE);
202 glDisable(GL_LIGHTING);
205 sol_bill(&inner.draw, pend_bill_M, t);
207 sol_bill(&inner.draw, bill_M, t);
210 glEnable(GL_LIGHTING);
211 if (mask == 0) glDepthMask(GL_TRUE);
212 if (test == 0) glEnable(GL_DEPTH_TEST);
218 if (inner_alpha < 1.0f)
219 glDisable(GL_ALPHA_TEST);
223 static void ball_draw_outer(const float *pend_M,
225 const float *pend_bill_M, float t)
229 const int pend = (outer_flags & F_PENDULUM);
230 const int mask = (outer_flags & F_DEPTHMASK);
231 const int test = (outer_flags & F_DEPTHTEST);
233 if (outer_alpha < 1.0f)
235 glEnable(GL_ALPHA_TEST);
236 glAlphaFunc(GL_GEQUAL, outer_alpha);
239 /* Apply the pendulum rotation. */
244 glMultMatrixf(pend_M);
247 /* Draw the outer opaque and transparent geometry. */
249 sol_draw(&outer.draw, mask, test);
251 /* Draw the outer billboard geometry. */
255 if (test == 0) glDisable(GL_DEPTH_TEST);
256 if (mask == 0) glDepthMask(GL_FALSE);
257 glDisable(GL_LIGHTING);
260 sol_bill(&outer.draw, pend_bill_M, t);
262 sol_bill(&outer.draw, bill_M, t);
264 glEnable(GL_LIGHTING);
265 if (mask == 0) glDepthMask(GL_TRUE);
266 if (test == 0) glEnable(GL_DEPTH_TEST);
272 if (outer_alpha < 1.0f)
273 glDisable(GL_ALPHA_TEST);
277 /*---------------------------------------------------------------------------*/
279 static void ball_pass_inner(const float *ball_M,
282 const float *ball_bill_M,
283 const float *pend_bill_M, float t)
285 /* Sort the inner ball using clip planes. */
287 if (inner_flags & F_DRAWCLIP)
289 glEnable(GL_CLIP_PLANE1);
290 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
291 glDisable(GL_CLIP_PLANE1);
293 glEnable(GL_CLIP_PLANE2);
294 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
295 glDisable(GL_CLIP_PLANE2);
298 /* Sort the inner ball using face culling. */
300 else if (inner_flags & F_DRAWBACK)
302 glCullFace(GL_FRONT);
303 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
305 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
308 /* Draw the inner ball normally. */
312 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
316 static void ball_pass_solid(const float *ball_M,
319 const float *ball_bill_M,
320 const float *pend_bill_M, float t)
322 /* Sort the solid ball with the inner ball using clip planes. */
324 if (solid_flags & F_DRAWCLIP)
326 glEnable(GL_CLIP_PLANE1);
327 ball_draw_solid(ball_M, ball_bill_M, t);
328 glDisable(GL_CLIP_PLANE1);
330 ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
332 glEnable(GL_CLIP_PLANE2);
333 ball_draw_solid(ball_M, ball_bill_M, t);
334 glDisable(GL_CLIP_PLANE2);
337 /* Sort the solid ball with the inner ball using face culling. */
339 else if (solid_flags & F_DRAWBACK)
341 glCullFace(GL_FRONT);
342 ball_draw_solid(ball_M, ball_bill_M, t);
345 ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
346 ball_draw_solid(ball_M, ball_bill_M, t);
349 /* Draw the solid ball after the inner ball. */
353 ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
354 ball_draw_solid(ball_M, ball_bill_M, t);
358 static void ball_pass_outer(const float *ball_M,
361 const float *ball_bill_M,
362 const float *pend_bill_M, float t)
364 /* Sort the outer ball with the solid ball using clip planes. */
366 if (outer_flags & F_DRAWCLIP)
368 glEnable(GL_CLIP_PLANE1);
369 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
370 glDisable(GL_CLIP_PLANE1);
372 ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
374 glEnable(GL_CLIP_PLANE2);
375 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
376 glDisable(GL_CLIP_PLANE2);
379 /* Sort the outer ball with the solid ball using face culling. */
381 else if (outer_flags & F_DRAWBACK)
383 glCullFace(GL_FRONT);
384 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
387 ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
388 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
391 /* Draw the outer ball after the solid ball. */
395 ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
396 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
400 /*---------------------------------------------------------------------------*/
402 void ball_draw(const float *ball_M,
404 const float *bill_M, float t)
406 /* Compute transforms for ball and pendulum billboards. */
408 float ball_T[16], ball_bill_M[16];
409 float pend_T[16], pend_bill_M[16];
411 m_xps(ball_T, ball_M);
412 m_xps(pend_T, pend_M);
414 m_mult(ball_bill_M, ball_T, bill_M);
415 m_mult(pend_bill_M, pend_T, bill_M);
417 /* Go to GREAT pains to ensure all layers are drawn back-to-front. */
419 ball_pass_outer(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
422 /*---------------------------------------------------------------------------*/