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 /*---------------------------------------------------------------------------*/
26 static int has_solid = 0;
27 static int has_inner = 0;
28 static int has_outer = 0;
30 static struct s_file solid;
31 static struct s_file inner;
32 static struct s_file outer;
38 #define F_DEPTHTEST 16
40 static int solid_flags;
41 static int inner_flags;
42 static int outer_flags;
44 static float solid_alpha;
45 static float inner_alpha;
46 static float outer_alpha;
48 /*---------------------------------------------------------------------------*/
50 #define SET(B, v, b) ((v) ? ((B) | (b)) : ((B) & ~(b)))
52 static int ball_opts(const struct s_file *fp, float *alpha)
54 int flags = F_DEPTHTEST;
57 for (di = 0; di < fp->dc; ++di)
59 char *k = fp->av + fp->dv[di].ai;
60 char *v = fp->av + fp->dv[di].aj;
62 if (strcmp(k, "pendulum") == 0)
63 flags = SET(flags, atoi(v), F_PENDULUM);
64 if (strcmp(k, "drawback") == 0)
65 flags = SET(flags, atoi(v), F_DRAWBACK);
66 if (strcmp(k, "drawclip") == 0)
67 flags = SET(flags, atoi(v), F_DRAWCLIP);
68 if (strcmp(k, "depthmask") == 0)
69 flags = SET(flags, atoi(v), F_DEPTHMASK);
70 if (strcmp(k, "depthtest") == 0)
71 flags = SET(flags, atoi(v), F_DEPTHTEST);
72 if (strcmp(k, "alphatest") == 0)
73 sscanf(v, "%f", alpha);
81 char *solid_file = concat_string(config_get_s(CONFIG_BALL_FILE),
83 char *inner_file = concat_string(config_get_s(CONFIG_BALL_FILE),
85 char *outer_file = concat_string(config_get_s(CONFIG_BALL_FILE),
96 if ((has_solid = sol_load_gl(&solid, solid_file, 0)))
97 solid_flags = ball_opts(&solid, &solid_alpha);
99 if ((has_inner = sol_load_gl(&inner, inner_file, 0)))
100 inner_flags = ball_opts(&inner, &inner_alpha);
102 if ((has_outer = sol_load_gl(&outer, outer_file, 0)))
103 outer_flags = ball_opts(&outer, &outer_alpha);
112 if (has_outer) sol_free_gl(&outer);
113 if (has_inner) sol_free_gl(&inner);
114 if (has_solid) sol_free_gl(&solid);
116 has_solid = has_inner = has_outer = 0;
119 /*---------------------------------------------------------------------------*/
121 static void ball_draw_solid(const float *ball_M,
122 const float *ball_bill_M, float t)
126 const int mask = (solid_flags & F_DEPTHMASK);
127 const int test = (solid_flags & F_DEPTHTEST);
129 if (solid_alpha < 1.0f)
131 glEnable(GL_ALPHA_TEST);
132 glAlphaFunc(GL_GEQUAL, solid_alpha);
137 /* Apply the ball rotation. */
139 glMultMatrixf(ball_M);
141 /* Draw the solid billboard geometry. */
145 if (test == 0) glDisable(GL_DEPTH_TEST);
146 if (mask == 0) glDepthMask(GL_FALSE);
147 glDisable(GL_LIGHTING);
149 sol_bill(&solid, ball_bill_M, t);
151 glEnable(GL_LIGHTING);
152 if (mask == 0) glDepthMask(GL_TRUE);
153 if (test == 0) glEnable(GL_DEPTH_TEST);
156 /* Draw the solid opaque and transparent geometry. */
158 sol_draw(&solid, mask, test);
162 if (solid_alpha < 1.0f)
163 glDisable(GL_ALPHA_TEST);
167 static void ball_draw_inner(const float *pend_M,
169 const float *pend_bill_M, float t)
173 const int pend = (inner_flags & F_PENDULUM);
174 const int mask = (inner_flags & F_DEPTHMASK);
175 const int test = (inner_flags & F_DEPTHTEST);
177 if (inner_alpha < 1.0f)
179 glEnable(GL_ALPHA_TEST);
180 glAlphaFunc(GL_GEQUAL, inner_alpha);
183 /* Apply the pendulum rotation. */
188 glMultMatrixf(pend_M);
191 /* Draw the inner opaque and transparent geometry. */
193 sol_draw(&inner, mask, test);
195 /* Draw the inner billboard geometry. */
199 if (test == 0) glDisable(GL_DEPTH_TEST);
200 if (mask == 0) glDepthMask(GL_FALSE);
201 glDisable(GL_LIGHTING);
204 sol_bill(&inner, pend_bill_M, t);
206 sol_bill(&inner, bill_M, t);
209 glEnable(GL_LIGHTING);
210 if (mask == 0) glDepthMask(GL_TRUE);
211 if (test == 0) glEnable(GL_DEPTH_TEST);
217 if (inner_alpha < 1.0f)
218 glDisable(GL_ALPHA_TEST);
222 static void ball_draw_outer(const float *pend_M,
224 const float *pend_bill_M, float t)
228 const int pend = (outer_flags & F_PENDULUM);
229 const int mask = (outer_flags & F_DEPTHMASK);
230 const int test = (outer_flags & F_DEPTHTEST);
232 if (outer_alpha < 1.0f)
234 glEnable(GL_ALPHA_TEST);
235 glAlphaFunc(GL_GEQUAL, outer_alpha);
238 /* Apply the pendulum rotation. */
243 glMultMatrixf(pend_M);
246 /* Draw the outer opaque and transparent geometry. */
248 sol_draw(&outer, mask, test);
250 /* Draw the outer billboard geometry. */
254 if (test == 0) glDisable(GL_DEPTH_TEST);
255 if (mask == 0) glDepthMask(GL_FALSE);
256 glDisable(GL_LIGHTING);
259 sol_bill(&outer, pend_bill_M, t);
261 sol_bill(&outer, bill_M, t);
263 glEnable(GL_LIGHTING);
264 if (mask == 0) glDepthMask(GL_TRUE);
265 if (test == 0) glEnable(GL_DEPTH_TEST);
271 if (outer_alpha < 1.0f)
272 glDisable(GL_ALPHA_TEST);
276 /*---------------------------------------------------------------------------*/
278 static void ball_pass_inner(const float *ball_M,
281 const float *ball_bill_M,
282 const float *pend_bill_M, float t)
284 /* Sort the inner ball using clip planes. */
286 if (inner_flags & F_DRAWCLIP)
288 glEnable(GL_CLIP_PLANE1);
289 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
290 glDisable(GL_CLIP_PLANE1);
292 glEnable(GL_CLIP_PLANE2);
293 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
294 glDisable(GL_CLIP_PLANE2);
297 /* Sort the inner ball using face culling. */
299 else if (inner_flags & F_DRAWBACK)
301 glCullFace(GL_FRONT);
302 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
304 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
307 /* Draw the inner ball normally. */
311 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
315 static void ball_pass_solid(const float *ball_M,
318 const float *ball_bill_M,
319 const float *pend_bill_M, float t)
321 /* Sort the solid ball with the inner ball using clip planes. */
323 if (solid_flags & F_DRAWCLIP)
325 glEnable(GL_CLIP_PLANE1);
326 ball_draw_solid(ball_M, ball_bill_M, t);
327 glDisable(GL_CLIP_PLANE1);
329 ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
331 glEnable(GL_CLIP_PLANE2);
332 ball_draw_solid(ball_M, ball_bill_M, t);
333 glDisable(GL_CLIP_PLANE2);
336 /* Sort the solid ball with the inner ball using face culling. */
338 else if (solid_flags & F_DRAWBACK)
340 glCullFace(GL_FRONT);
341 ball_draw_solid(ball_M, ball_bill_M, t);
344 ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
345 ball_draw_solid(ball_M, ball_bill_M, t);
348 /* Draw the solid ball after the inner ball. */
352 ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
353 ball_draw_solid(ball_M, ball_bill_M, t);
357 static void ball_pass_outer(const float *ball_M,
360 const float *ball_bill_M,
361 const float *pend_bill_M, float t)
363 /* Sort the outer ball with the solid ball using clip planes. */
365 if (outer_flags & F_DRAWCLIP)
367 glEnable(GL_CLIP_PLANE1);
368 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
369 glDisable(GL_CLIP_PLANE1);
371 ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
373 glEnable(GL_CLIP_PLANE2);
374 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
375 glDisable(GL_CLIP_PLANE2);
378 /* Sort the outer ball with the solid ball using face culling. */
380 else if (outer_flags & F_DRAWBACK)
382 glCullFace(GL_FRONT);
383 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
386 ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
387 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
390 /* Draw the outer ball after the solid ball. */
394 ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
395 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
399 /*---------------------------------------------------------------------------*/
401 void ball_draw(const float *ball_M,
403 const float *bill_M, float t)
405 /* Compute transforms for ball and pendulum billboards. */
407 float ball_T[16], ball_bill_M[16];
408 float pend_T[16], pend_bill_M[16];
410 m_xps(ball_T, ball_M);
411 m_xps(pend_T, pend_M);
413 m_mult(ball_bill_M, ball_T, bill_M);
414 m_mult(pend_bill_M, pend_T, bill_M);
416 /* Go to GREAT pains to ensure all layers are drawn back-to-front. */
418 ball_pass_outer(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
421 /*---------------------------------------------------------------------------*/