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(struct s_rend *rend,
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.draw, rend, 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.draw, rend, mask, test);
164 if (solid_alpha < 1.0f)
165 glDisable(GL_ALPHA_TEST);
169 static void ball_draw_inner(struct s_rend *rend,
172 const float *pend_bill_M, float t)
176 const int pend = (inner_flags & F_PENDULUM);
177 const int mask = (inner_flags & F_DEPTHMASK);
178 const int test = (inner_flags & F_DEPTHTEST);
180 if (inner_alpha < 1.0f)
182 glEnable(GL_ALPHA_TEST);
183 glAlphaFunc(GL_GEQUAL, inner_alpha);
186 /* Apply the pendulum rotation. */
191 glMultMatrixf(pend_M);
194 /* Draw the inner opaque and transparent geometry. */
196 sol_draw(&inner.draw, rend, mask, test);
198 /* Draw the inner billboard geometry. */
202 if (test == 0) glDisable(GL_DEPTH_TEST);
203 if (mask == 0) glDepthMask(GL_FALSE);
204 glDisable(GL_LIGHTING);
207 sol_bill(&inner.draw, rend, pend_bill_M, t);
209 sol_bill(&inner.draw, rend, bill_M, t);
212 glEnable(GL_LIGHTING);
213 if (mask == 0) glDepthMask(GL_TRUE);
214 if (test == 0) glEnable(GL_DEPTH_TEST);
220 if (inner_alpha < 1.0f)
221 glDisable(GL_ALPHA_TEST);
225 static void ball_draw_outer(struct s_rend *rend,
228 const float *pend_bill_M, float t)
232 const int pend = (outer_flags & F_PENDULUM);
233 const int mask = (outer_flags & F_DEPTHMASK);
234 const int test = (outer_flags & F_DEPTHTEST);
236 if (outer_alpha < 1.0f)
238 glEnable(GL_ALPHA_TEST);
239 glAlphaFunc(GL_GEQUAL, outer_alpha);
242 /* Apply the pendulum rotation. */
247 glMultMatrixf(pend_M);
250 /* Draw the outer opaque and transparent geometry. */
252 sol_draw(&outer.draw, rend, mask, test);
254 /* Draw the outer billboard geometry. */
258 if (test == 0) glDisable(GL_DEPTH_TEST);
259 if (mask == 0) glDepthMask(GL_FALSE);
260 glDisable(GL_LIGHTING);
263 sol_bill(&outer.draw, rend, pend_bill_M, t);
265 sol_bill(&outer.draw, rend, bill_M, t);
267 glEnable(GL_LIGHTING);
268 if (mask == 0) glDepthMask(GL_TRUE);
269 if (test == 0) glEnable(GL_DEPTH_TEST);
275 if (outer_alpha < 1.0f)
276 glDisable(GL_ALPHA_TEST);
280 /*---------------------------------------------------------------------------*/
282 static void ball_pass_inner(struct s_rend *rend,
286 const float *ball_bill_M,
287 const float *pend_bill_M, float t)
289 /* Sort the inner ball using clip planes. */
291 if (inner_flags & F_DRAWCLIP)
293 glEnable(GL_CLIP_PLANE1);
294 ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
295 glDisable(GL_CLIP_PLANE1);
297 glEnable(GL_CLIP_PLANE2);
298 ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
299 glDisable(GL_CLIP_PLANE2);
302 /* Sort the inner ball using face culling. */
304 else if (inner_flags & F_DRAWBACK)
306 glCullFace(GL_FRONT);
307 ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
309 ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
312 /* Draw the inner ball normally. */
316 ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
320 static void ball_pass_solid(struct s_rend *rend,
324 const float *ball_bill_M,
325 const float *pend_bill_M, float t)
327 /* Sort the solid ball with the inner ball using clip planes. */
329 if (solid_flags & F_DRAWCLIP)
331 glEnable(GL_CLIP_PLANE1);
332 ball_draw_solid(rend, ball_M, ball_bill_M, t);
333 glDisable(GL_CLIP_PLANE1);
335 ball_pass_inner(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
337 glEnable(GL_CLIP_PLANE2);
338 ball_draw_solid(rend, ball_M, ball_bill_M, t);
339 glDisable(GL_CLIP_PLANE2);
342 /* Sort the solid ball with the inner ball using face culling. */
344 else if (solid_flags & F_DRAWBACK)
346 glCullFace(GL_FRONT);
347 ball_draw_solid(rend, ball_M, ball_bill_M, t);
350 ball_pass_inner(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
351 ball_draw_solid(rend, ball_M, ball_bill_M, t);
354 /* Draw the solid ball after the inner ball. */
358 ball_pass_inner(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
359 ball_draw_solid(rend, ball_M, ball_bill_M, t);
363 static void ball_pass_outer(struct s_rend *rend,
367 const float *ball_bill_M,
368 const float *pend_bill_M, float t)
370 /* Sort the outer ball with the solid ball using clip planes. */
372 if (outer_flags & F_DRAWCLIP)
374 glEnable(GL_CLIP_PLANE1);
375 ball_draw_outer(rend, pend_M, bill_M, pend_bill_M, t);
376 glDisable(GL_CLIP_PLANE1);
378 ball_pass_solid(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
380 glEnable(GL_CLIP_PLANE2);
381 ball_draw_outer(rend, pend_M, bill_M, pend_bill_M, t);
382 glDisable(GL_CLIP_PLANE2);
385 /* Sort the outer ball with the solid ball using face culling. */
387 else if (outer_flags & F_DRAWBACK)
389 glCullFace(GL_FRONT);
390 ball_draw_outer(rend, pend_M, bill_M, pend_bill_M, t);
393 ball_pass_solid(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
394 ball_draw_outer(rend, pend_M, bill_M, pend_bill_M, t);
397 /* Draw the outer ball after the solid ball. */
401 ball_pass_solid(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
402 ball_draw_outer(rend, pend_M, bill_M, pend_bill_M, t);
406 /*---------------------------------------------------------------------------*/
408 void ball_draw(struct s_rend *rend,
411 const float *bill_M, float t)
413 /* Compute transforms for ball and pendulum billboards. */
415 float ball_T[16], ball_bill_M[16];
416 float pend_T[16], pend_bill_M[16];
418 m_xps(ball_T, ball_M);
419 m_xps(pend_T, pend_M);
421 m_mult(ball_bill_M, ball_T, bill_M);
422 m_mult(pend_bill_M, pend_T, bill_M);
424 /* Go to GREAT pains to ensure all layers are drawn back-to-front. */
426 ball_pass_outer(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
429 /*---------------------------------------------------------------------------*/