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.
28 #define PI 3.1415926535897932
30 /*---------------------------------------------------------------------------*/
32 static GLuint ball_list;
33 static GLuint ball_text;
38 int i, slices = b ? 32 : 16;
39 int j, stacks = b ? 16 : 8;
41 config_get_s(CONFIG_BALL, name, MAXSTR);
43 ball_text = make_image_from_file(NULL, NULL, NULL, NULL, name);
45 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
46 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
48 ball_list = glGenLists(1);
50 glNewList(ball_list, GL_COMPILE);
52 for (i = 0; i < stacks; i++)
54 float k0 = (float) i / stacks;
55 float k1 = (float) (i + 1) / stacks;
57 float s0 = fsinf(V_PI * (k0 - 0.5));
58 float c0 = fcosf(V_PI * (k0 - 0.5));
59 float s1 = fsinf(V_PI * (k1 - 0.5));
60 float c1 = fcosf(V_PI * (k1 - 0.5));
62 glBegin(GL_QUAD_STRIP);
64 for (j = 0; j <= slices; j++)
66 float k = (float) j / slices;
67 float s = fsinf(V_PI * k * 2.0);
68 float c = fcosf(V_PI * k * 2.0);
71 glNormal3f(s * c0, c * c0, s0);
72 glVertex3f(s * c0, c * c0, s0);
75 glNormal3f(s * c1, c * c1, s1);
76 glVertex3f(s * c1, c * c1, s1);
87 if (glIsList(ball_list))
88 glDeleteLists(ball_list, 1);
90 if (glIsTexture(ball_text))
91 glDeleteTextures(1, &ball_text);
99 glPushAttrib(GL_POLYGON_BIT |
101 GL_DEPTH_BUFFER_BIT);
103 static const float s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
104 static const float e[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
105 static const float h[1] = { 64.0f };
107 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s);
108 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e);
109 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
111 glEnable(GL_COLOR_MATERIAL);
113 glBindTexture(GL_TEXTURE_2D, ball_text);
115 /* Render the ball back to front in case it is translucent. */
117 glDepthMask(GL_FALSE);
119 glCullFace(GL_FRONT);
120 glCallList(ball_list);
122 glCallList(ball_list);
124 /* Render the ball into the depth buffer. */
126 glDepthMask(GL_TRUE);
127 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
129 glCallList(ball_list);
131 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
133 /* Ensure the ball is visible even when obscured by geometry. */
135 glDisable(GL_DEPTH_TEST);
137 glColor4f(1.0f, 1.0f, 1.0f, 0.1f);
138 glCallList(ball_list);
143 /*---------------------------------------------------------------------------*/
145 static GLuint mark_list;
147 void mark_init(int b)
149 int i, slices = b ? 32 : 16;
151 mark_list = glGenLists(1);
153 glNewList(mark_list, GL_COMPILE);
155 glBegin(GL_TRIANGLE_FAN);
157 glNormal3f(0.f, 1.f, 0.f);
159 for (i = 0; i < slices; i++)
161 float x = fcosf(-2.f * PI * i / slices);
162 float y = fsinf(-2.f * PI * i / slices);
174 glPushAttrib(GL_TEXTURE_BIT);
175 glPushAttrib(GL_LIGHTING_BIT);
176 glPushAttrib(GL_DEPTH_BUFFER_BIT);
178 glEnable(GL_COLOR_MATERIAL);
179 glDisable(GL_TEXTURE_2D);
180 glDepthMask(GL_FALSE);
182 glCallList(mark_list);
191 if (glIsList(mark_list))
192 glDeleteLists(mark_list, 1);
197 /*---------------------------------------------------------------------------*/
199 static GLuint coin_text;
200 static GLuint coin_list;
202 static void coin_head(int n, float radius, float thick)
206 glBegin(GL_TRIANGLE_FAN);
208 glNormal3f(0.f, 0.f, +1.f);
210 for (i = 0; i < n; i++)
212 float x = fcosf(+2.f * PI * i / n);
213 float y = fsinf(+2.f * PI * i / n);
215 glTexCoord2f(-x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
216 glVertex3f(radius * x, radius * y, +thick);
222 static void coin_tail(int n, float radius, float thick)
226 glBegin(GL_TRIANGLE_FAN);
228 glNormal3f(0.f, 0.f, -1.f);
230 for (i = 0; i < n; i++)
232 float x = fcosf(-2.f * PI * i / n);
233 float y = fsinf(-2.f * PI * i / n);
235 glTexCoord2f(+x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
236 glVertex3f(radius * x, radius * y, -thick);
242 static void coin_edge(int n, float radius, float thick)
246 glBegin(GL_QUAD_STRIP);
248 for (i = 0; i <= n; i++)
250 float x = fcosf(2.f * PI * i / n);
251 float y = fsinf(2.f * PI * i / n);
253 glNormal3f(x, y, 0.f);
254 glVertex3f(radius * x, radius * y, +thick);
255 glVertex3f(radius * x, radius * y, -thick);
261 void coin_color(float *c, int n)
283 void coin_init(int b)
288 config_get_s(CONFIG_COIN, name, MAXSTR);
290 coin_text = make_image_from_file(NULL, NULL, NULL, NULL, name);
291 coin_list = glGenLists(1);
293 glNewList(coin_list, GL_COMPILE);
295 coin_edge(n, COIN_RADIUS, COIN_THICK);
296 coin_head(n, COIN_RADIUS, COIN_THICK);
297 coin_tail(n, COIN_RADIUS, COIN_THICK);
304 if (glIsList(coin_list))
305 glDeleteLists(coin_list, 1);
307 if (glIsTexture(coin_text))
308 glDeleteTextures(1, &coin_text);
316 static const float a[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
317 static const float s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
318 static const float e[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
319 static const float h[1] = { 32.0f };
321 glPushAttrib(GL_LIGHTING_BIT);
323 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, a);
324 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s);
325 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e);
326 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
328 glEnable(GL_COLOR_MATERIAL);
329 glBindTexture(GL_TEXTURE_2D, coin_text);
332 void coin_draw(int n, float r)
339 glCallList(coin_list);
347 /*---------------------------------------------------------------------------*/
349 static GLuint goal_list;
351 void goal_init(int b)
353 int i, n = b ? 32 : 8;
355 goal_list = glGenLists(1);
357 glNewList(goal_list, GL_COMPILE);
359 glPushAttrib(GL_TEXTURE_BIT |
361 GL_DEPTH_BUFFER_BIT);
363 glEnable(GL_COLOR_MATERIAL);
364 glDisable(GL_LIGHTING);
365 glDisable(GL_TEXTURE_2D);
366 glDepthMask(GL_FALSE);
368 glBegin(GL_QUAD_STRIP);
370 for (i = 0; i <= n; i++)
372 float x = fcosf(2.f * PI * i / n);
373 float y = fsinf(2.f * PI * i / n);
375 glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
376 glVertex3f(x, 0.0f, y);
378 glColor4f(1.0f, 1.0f, 0.0f, 0.0f);
379 glVertex3f(x, GOAL_HEIGHT, y);
391 if (glIsList(goal_list))
392 glDeleteLists(goal_list, 1);
399 glCallList(goal_list);
402 /*---------------------------------------------------------------------------*/
404 static GLuint jump_list;
406 void jump_init(int b)
408 int i, n = b ? 32 : 8;
410 jump_list = glGenLists(1);
412 glNewList(jump_list, GL_COMPILE);
414 glPushAttrib(GL_TEXTURE_BIT |
416 GL_DEPTH_BUFFER_BIT);
418 glEnable(GL_COLOR_MATERIAL);
419 glDisable(GL_LIGHTING);
420 glDisable(GL_TEXTURE_2D);
421 glDepthMask(GL_FALSE);
423 glBegin(GL_QUAD_STRIP);
425 for (i = 0; i <= n; i++)
427 float x = fcosf(2.f * PI * i / n);
428 float y = fsinf(2.f * PI * i / n);
430 glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
431 glVertex3f(x, 0.0f, y);
433 glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
434 glVertex3f(x, JUMP_HEIGHT, y);
446 if (glIsList(jump_list))
447 glDeleteLists(jump_list, 1);
454 glCallList(jump_list);
457 /*---------------------------------------------------------------------------*/
459 static GLuint swch_list;
461 void swch_init(int b)
463 int i, n = b ? 32 : 8;
465 swch_list = glGenLists(2);
467 /* Create the ON display list. */
469 glNewList(swch_list, GL_COMPILE);
471 glPushAttrib(GL_TEXTURE_BIT |
473 GL_DEPTH_BUFFER_BIT);
475 glEnable(GL_COLOR_MATERIAL);
476 glDisable(GL_LIGHTING);
477 glDisable(GL_TEXTURE_2D);
478 glDepthMask(GL_FALSE);
480 glBegin(GL_QUAD_STRIP);
482 for (i = 0; i <= n; i++)
484 float x = fcosf(2.f * PI * i / n);
485 float y = fsinf(2.f * PI * i / n);
487 glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
488 glVertex3f(x, 0.0f, y);
490 glColor4f(1.0f, 0.0f, 0.0f, 0.0f);
491 glVertex3f(x, SWCH_HEIGHT, y);
500 /* Create the OFF display list. */
502 glNewList(swch_list + 1, GL_COMPILE);
504 glPushAttrib(GL_TEXTURE_BIT |
506 GL_DEPTH_BUFFER_BIT);
508 glEnable(GL_COLOR_MATERIAL);
509 glDisable(GL_LIGHTING);
510 glDisable(GL_TEXTURE_2D);
511 glDepthMask(GL_FALSE);
513 glBegin(GL_QUAD_STRIP);
515 for (i = 0; i <= n; i++)
517 float x = fcosf(2.f * PI * i / n);
518 float y = fsinf(2.f * PI * i / n);
520 glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
521 glVertex3f(x, 0.0f, y);
523 glColor4f(0.0f, 1.0f, 0.0f, 0.0f);
524 glVertex3f(x, SWCH_HEIGHT, y);
536 if (glIsList(swch_list))
537 glDeleteLists(swch_list, 2);
542 void swch_draw(int b)
545 glCallList(swch_list + 1);
547 glCallList(swch_list);
550 /*---------------------------------------------------------------------------*/
552 static GLuint flag_list;
554 void flag_init(int b)
556 int i, n = b ? 8 : 4;
558 flag_list = glGenLists(1);
560 glNewList(flag_list, GL_COMPILE);
562 glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT);
564 glEnable(GL_COLOR_MATERIAL);
565 glDisable(GL_LIGHTING);
566 glDisable(GL_TEXTURE_2D);
568 glBegin(GL_QUAD_STRIP);
570 for (i = 0; i <= n; i++)
572 float x = fcosf(2.f * PI * i / n) * 0.01f;
573 float y = fsinf(2.f * PI * i / n) * 0.01f;
575 glColor3f(1.0f, 1.0f, 1.0f);
576 glVertex3f(x, 0.0f, y);
577 glVertex3f(x, GOAL_HEIGHT, y);
582 glBegin(GL_TRIANGLES);
584 glColor3f(1.0f, 0.0f, 0.0f);
586 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
587 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
588 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
590 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
591 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
592 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
603 if (glIsList(flag_list))
604 glDeleteLists(flag_list, 1);
611 glCallList(flag_list);
614 /*---------------------------------------------------------------------------*/
616 * A note about lighting and shadow: technically speaking, it's wrong.
617 * The light position and shadow projection behave as if the
618 * light-source rotates with the floor. However, the skybox does not
619 * rotate, thus the light should also remain stationary.
621 * The correct behavior would eliminate a significant 3D cue: the
622 * shadow of the ball indicates the ball's position relative to the
623 * floor even when the ball is in the air. This was the motivating
624 * idea behind the shadow in the first place, so correct shadow
625 * projection would only magnify the problem.
628 static GLuint shad_text;
632 shad_text = make_image_from_file(NULL, NULL, NULL, NULL, IMG_SHAD);
634 if (config_get_d(CONFIG_SHADOW) == 2)
636 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
637 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
643 if (glIsTexture(shad_text))
644 glDeleteTextures(1, &shad_text);
647 void shad_draw_set(const float *p, float r)
649 glMatrixMode(GL_TEXTURE);
653 glBindTexture(GL_TEXTURE_2D, shad_text);
656 glTranslatef(0.5f - k * p[0],
657 0.5f - k * p[2], 0.f);
658 glScalef(k, k, 1.0f);
660 glMatrixMode(GL_MODELVIEW);
663 void shad_draw_clr(void)
665 glMatrixMode(GL_TEXTURE);
669 glMatrixMode(GL_MODELVIEW);
672 /*---------------------------------------------------------------------------*/
674 void fade_draw(float k)
676 int w = config_get_d(CONFIG_WIDTH);
677 int h = config_get_d(CONFIG_HEIGHT);
682 glPushAttrib(GL_TEXTURE_BIT |
684 GL_COLOR_BUFFER_BIT |
685 GL_DEPTH_BUFFER_BIT);
687 glEnable(GL_COLOR_MATERIAL);
688 glDisable(GL_LIGHTING);
689 glDisable(GL_DEPTH_TEST);
690 glDisable(GL_TEXTURE_2D);
692 glColor4f(0.0f, 0.0f, 0.0f, k);
708 /*---------------------------------------------------------------------------*/