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 /*---------------------------------------------------------------------------*/
25 static int has_solid = 0;
26 static int has_inner = 0;
27 static int has_outer = 0;
29 static struct s_file solid;
30 static struct s_file inner;
31 static struct s_file outer;
37 #define F_DEPTHTEST 16
39 static int solid_flags;
40 static int inner_flags;
41 static int outer_flags;
43 static float solid_alpha;
44 static float inner_alpha;
45 static float outer_alpha;
47 /*---------------------------------------------------------------------------*/
49 #define SET(B, v, b) ((v) ? ((B) | (b)) : ((B) & ~(b)))
51 static int ball_opts(const struct s_file *fp, float *alpha)
53 int flags = F_DEPTHTEST;
56 for (di = 0; di < fp->dc; ++di)
58 char *k = fp->av + fp->dv[di].ai;
59 char *v = fp->av + fp->dv[di].aj;
61 if (strcmp(k, "pendulum") == 0)
62 flags = SET(flags, atoi(v), F_PENDULUM);
63 if (strcmp(k, "drawback") == 0)
64 flags = SET(flags, atoi(v), F_DRAWBACK);
65 if (strcmp(k, "drawclip") == 0)
66 flags = SET(flags, atoi(v), F_DRAWCLIP);
67 if (strcmp(k, "depthmask") == 0)
68 flags = SET(flags, atoi(v), F_DEPTHMASK);
69 if (strcmp(k, "depthtest") == 0)
70 flags = SET(flags, atoi(v), F_DEPTHTEST);
71 if (strcmp(k, "alphatest") == 0)
72 sscanf(v, "%f", alpha);
80 int T = config_get_d(CONFIG_TEXTURES);
82 char solid_file[PATHMAX];
83 char inner_file[PATHMAX];
84 char outer_file[PATHMAX];
86 config_get_s(CONFIG_BALL, solid_file, PATHMAX - 12);
87 config_get_s(CONFIG_BALL, inner_file, PATHMAX - 12);
88 config_get_s(CONFIG_BALL, outer_file, PATHMAX - 12);
90 strcat(solid_file, "-solid.sol");
91 strcat(inner_file, "-inner.sol");
92 strcat(outer_file, "-outer.sol");
102 if ((has_solid = sol_load_gl(&solid, config_data(solid_file), T, 0)))
103 solid_flags = ball_opts(&solid, &solid_alpha);
105 if ((has_inner = sol_load_gl(&inner, config_data(inner_file), T, 0)))
106 inner_flags = ball_opts(&inner, &inner_alpha);
108 if ((has_outer = sol_load_gl(&outer, config_data(outer_file), T, 0)))
109 outer_flags = ball_opts(&outer, &outer_alpha);
114 if (has_outer) sol_free_gl(&outer);
115 if (has_inner) sol_free_gl(&inner);
116 if (has_solid) sol_free_gl(&solid);
118 has_solid = has_inner = has_outer = 0;
121 /*---------------------------------------------------------------------------*/
123 static void ball_draw_solid(const float *ball_M,
124 const float *ball_bill_M, float t)
128 const int mask = (solid_flags & F_DEPTHMASK);
129 const int test = (solid_flags & F_DEPTHTEST);
131 if (solid_alpha < 1.0f)
133 glEnable(GL_ALPHA_TEST);
134 glAlphaFunc(GL_GEQUAL, solid_alpha);
139 /* Apply the ball rotation. */
141 glMultMatrixf(ball_M);
143 /* Draw the solid billboard geometry. */
147 if (test == 0) glDisable(GL_DEPTH_TEST);
148 if (mask == 0) glDepthMask(GL_FALSE);
149 glDisable(GL_LIGHTING);
151 sol_bill(&solid, ball_bill_M, t);
153 glEnable(GL_LIGHTING);
154 if (mask == 0) glDepthMask(GL_TRUE);
155 if (test == 0) glEnable(GL_DEPTH_TEST);
158 /* Draw the solid opaque and transparent geometry. */
160 sol_draw(&solid, mask, test);
164 if (solid_alpha < 1.0f)
165 glDisable(GL_ALPHA_TEST);
169 static void ball_draw_inner(const float *pend_M,
171 const float *pend_bill_M, float t)
175 const int pend = (inner_flags & F_PENDULUM);
176 const int mask = (inner_flags & F_DEPTHMASK);
177 const int test = (inner_flags & F_DEPTHTEST);
179 if (inner_alpha < 1.0f)
181 glEnable(GL_ALPHA_TEST);
182 glAlphaFunc(GL_GEQUAL, inner_alpha);
185 /* Apply the pendulum rotation. */
190 glMultMatrixf(pend_M);
193 /* Draw the inner opaque and transparent geometry. */
195 sol_draw(&inner, mask, test);
197 /* Draw the inner billboard geometry. */
201 if (test == 0) glDisable(GL_DEPTH_TEST);
202 if (mask == 0) glDepthMask(GL_FALSE);
203 glDisable(GL_LIGHTING);
206 sol_bill(&inner, pend_bill_M, t);
208 sol_bill(&inner, bill_M, t);
211 glEnable(GL_LIGHTING);
212 if (mask == 0) glDepthMask(GL_TRUE);
213 if (test == 0) glEnable(GL_DEPTH_TEST);
219 if (inner_alpha < 1.0f)
220 glDisable(GL_ALPHA_TEST);
224 static void ball_draw_outer(const float *pend_M,
226 const float *pend_bill_M, float t)
230 const int pend = (outer_flags & F_PENDULUM);
231 const int mask = (outer_flags & F_DEPTHMASK);
232 const int test = (outer_flags & F_DEPTHTEST);
234 if (outer_alpha < 1.0f)
236 glEnable(GL_ALPHA_TEST);
237 glAlphaFunc(GL_GEQUAL, outer_alpha);
240 /* Apply the pendulum rotation. */
245 glMultMatrixf(pend_M);
248 /* Draw the outer opaque and transparent geometry. */
250 sol_draw(&outer, mask, test);
252 /* Draw the outer billboard geometry. */
256 if (test == 0) glDisable(GL_DEPTH_TEST);
257 if (mask == 0) glDepthMask(GL_FALSE);
258 glDisable(GL_LIGHTING);
261 sol_bill(&outer, pend_bill_M, t);
263 sol_bill(&outer, bill_M, t);
265 glEnable(GL_LIGHTING);
266 if (mask == 0) glDepthMask(GL_TRUE);
267 if (test == 0) glEnable(GL_DEPTH_TEST);
273 if (outer_alpha < 1.0f)
274 glDisable(GL_ALPHA_TEST);
278 /*---------------------------------------------------------------------------*/
280 static void ball_pass_inner(const float *ball_M,
283 const float *ball_bill_M,
284 const float *pend_bill_M, float t)
286 /* Sort the inner ball using clip planes. */
288 if (inner_flags & F_DRAWCLIP)
290 glEnable(GL_CLIP_PLANE1);
291 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
292 glDisable(GL_CLIP_PLANE1);
294 glEnable(GL_CLIP_PLANE2);
295 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
296 glDisable(GL_CLIP_PLANE2);
299 /* Sort the inner ball using face culling. */
301 else if (inner_flags & F_DRAWBACK)
303 glCullFace(GL_FRONT);
304 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
306 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
309 /* Draw the inner ball normally. */
313 ball_draw_inner( pend_M, bill_M, pend_bill_M, t);
317 static void ball_pass_solid(const float *ball_M,
320 const float *ball_bill_M,
321 const float *pend_bill_M, float t)
323 /* Sort the solid ball with the inner ball using clip planes. */
325 if (solid_flags & F_DRAWCLIP)
327 glEnable(GL_CLIP_PLANE1);
328 ball_draw_solid(ball_M, ball_bill_M, t);
329 glDisable(GL_CLIP_PLANE1);
331 ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
333 glEnable(GL_CLIP_PLANE2);
334 ball_draw_solid(ball_M, ball_bill_M, t);
335 glDisable(GL_CLIP_PLANE2);
338 /* Sort the solid ball with the inner ball using face culling. */
340 else if (solid_flags & F_DRAWBACK)
342 glCullFace(GL_FRONT);
343 ball_draw_solid(ball_M, ball_bill_M, t);
346 ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
347 ball_draw_solid(ball_M, ball_bill_M, t);
350 /* Draw the solid ball after the inner ball. */
354 ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
355 ball_draw_solid(ball_M, ball_bill_M, t);
359 static void ball_pass_outer(const float *ball_M,
362 const float *ball_bill_M,
363 const float *pend_bill_M, float t)
365 /* Sort the outer ball with the solid ball using clip planes. */
367 if (outer_flags & F_DRAWCLIP)
369 glEnable(GL_CLIP_PLANE1);
370 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
371 glDisable(GL_CLIP_PLANE1);
373 ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
375 glEnable(GL_CLIP_PLANE2);
376 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
377 glDisable(GL_CLIP_PLANE2);
380 /* Sort the outer ball with the solid ball using face culling. */
382 else if (outer_flags & F_DRAWBACK)
384 glCullFace(GL_FRONT);
385 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
388 ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
389 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
392 /* Draw the outer ball after the solid ball. */
396 ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
397 ball_draw_outer( pend_M, bill_M, pend_bill_M, t);
401 /*---------------------------------------------------------------------------*/
403 void ball_draw(const float *ball_M,
405 const float *bill_M, float t)
407 /* Compute transforms for ball and pendulum billboards. */
409 float ball_T[16], ball_bill_M[16];
410 float pend_T[16], pend_bill_M[16];
412 m_xps(ball_T, ball_M);
413 m_xps(pend_T, pend_M);
414 m_xps(pend_T, pend_M);
416 m_mult(ball_bill_M, ball_T, bill_M);
417 m_mult(pend_bill_M, pend_T, bill_M);
419 /* Go to GREAT pains to ensure all layers are drawn back-to-front. */
421 ball_pass_outer(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
424 /*---------------------------------------------------------------------------*/