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[2];
38 int i, slices = b ? 32 : 16;
39 int j, stacks = b ? 16 : 8;
41 config_get_s(CONFIG_BALL, name, MAXSTR);
42 ball_text[0] = make_image_from_file(NULL, NULL, NULL, NULL, name);
44 config_get_s(CONFIG_BALL_BONUS, name, MAXSTR);
45 ball_text[1] = make_image_from_file(NULL, NULL, NULL, NULL, name);
47 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
48 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
50 ball_list = glGenLists(1);
52 glNewList(ball_list, GL_COMPILE);
54 for (i = 0; i < stacks; i++)
56 float k0 = (float) i / stacks;
57 float k1 = (float) (i + 1) / stacks;
59 float s0 = fsinf(V_PI * (k0 - 0.5));
60 float c0 = fcosf(V_PI * (k0 - 0.5));
61 float s1 = fsinf(V_PI * (k1 - 0.5));
62 float c1 = fcosf(V_PI * (k1 - 0.5));
64 glBegin(GL_QUAD_STRIP);
66 for (j = 0; j <= slices; j++)
68 float k = (float) j / slices;
69 float s = fsinf(V_PI * k * 2.0);
70 float c = fcosf(V_PI * k * 2.0);
73 glNormal3f(s * c0, c * c0, s0);
74 glVertex3f(s * c0, c * c0, s0);
77 glNormal3f(s * c1, c * c1, s1);
78 glVertex3f(s * c1, c * c1, s1);
89 if (glIsList(ball_list))
90 glDeleteLists(ball_list, 1);
92 if (glIsTexture(ball_text[0]))
93 glDeleteTextures(1, &ball_text[0]);
95 if (glIsTexture(ball_text[1]))
96 glDeleteTextures(1, &ball_text[1]);
103 void ball_draw(int i)
105 glPushAttrib(GL_POLYGON_BIT |
107 GL_DEPTH_BUFFER_BIT);
109 static const float s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
110 static const float e[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
111 static const float h[1] = { 64.0f };
113 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s);
114 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e);
115 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
117 glEnable(GL_COLOR_MATERIAL);
119 glBindTexture(GL_TEXTURE_2D, ball_text[i]);
121 /* Render the ball back to front in case it is translucent. */
123 glDepthMask(GL_FALSE);
125 glCullFace(GL_FRONT);
126 glCallList(ball_list);
128 glCallList(ball_list);
130 /* Render the ball into the depth buffer. */
132 glDepthMask(GL_TRUE);
133 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
135 glCallList(ball_list);
137 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
139 /* Ensure the ball is visible even when obscured by geometry. */
141 glDisable(GL_DEPTH_TEST);
143 glColor4f(1.0f, 1.0f, 1.0f, 0.1f);
144 glCallList(ball_list);
149 /*---------------------------------------------------------------------------*/
151 static GLuint mark_list;
153 void mark_init(int b)
155 int i, slices = b ? 32 : 16;
157 mark_list = glGenLists(1);
159 glNewList(mark_list, GL_COMPILE);
161 glBegin(GL_TRIANGLE_FAN);
163 glNormal3f(0.f, 1.f, 0.f);
165 for (i = 0; i < slices; i++)
167 float x = fcosf(-2.f * PI * i / slices);
168 float y = fsinf(-2.f * PI * i / slices);
180 glPushAttrib(GL_TEXTURE_BIT);
181 glPushAttrib(GL_LIGHTING_BIT);
182 glPushAttrib(GL_DEPTH_BUFFER_BIT);
184 glEnable(GL_COLOR_MATERIAL);
185 glDisable(GL_TEXTURE_2D);
186 glDepthMask(GL_FALSE);
188 glCallList(mark_list);
197 if (glIsList(mark_list))
198 glDeleteLists(mark_list, 1);
203 /*---------------------------------------------------------------------------*/
205 static GLuint coin_text;
206 static GLuint coin_grup;
207 static GLuint coin_grdn;
208 static GLuint coin_list;
210 static void coin_head(int n, float radius, float thick)
214 glBegin(GL_TRIANGLE_FAN);
216 glNormal3f(0.f, 0.f, +1.f);
218 for (i = 0; i < n; i++)
220 float x = fcosf(+2.f * PI * i / n);
221 float y = fsinf(+2.f * PI * i / n);
223 glTexCoord2f(-x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
224 glVertex3f(radius * x, radius * y, +thick);
230 static void coin_tail(int n, float radius, float thick)
234 glBegin(GL_TRIANGLE_FAN);
236 glNormal3f(0.f, 0.f, -1.f);
238 for (i = 0; i < n; i++)
240 float x = fcosf(-2.f * PI * i / n);
241 float y = fsinf(-2.f * PI * i / n);
243 glTexCoord2f(+x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
244 glVertex3f(radius * x, radius * y, -thick);
250 static void coin_edge(int n, float radius, float thick)
254 glBegin(GL_QUAD_STRIP);
256 for (i = 0; i <= n; i++)
258 float x = fcosf(2.f * PI * i / n);
259 float y = fsinf(2.f * PI * i / n);
261 glNormal3f(x, y, 0.f);
262 glVertex3f(radius * x, radius * y, +thick);
263 glVertex3f(radius * x, radius * y, -thick);
269 void coin_color(float *c, int n)
289 if (n == 50) /*white's kind of boring, but you can do a colored png that way.*/
303 void coin_init(int b)
307 coin_text = make_image_from_file(NULL, NULL, NULL, NULL, IMG_COIN);
308 coin_grup = make_image_from_file(NULL, NULL, NULL, NULL, IMG_COIN_GRUP);
309 coin_grdn = make_image_from_file(NULL, NULL, NULL, NULL, IMG_COIN_GRDN);
310 coin_list = glGenLists(1);
312 glNewList(coin_list, GL_COMPILE);
314 coin_edge(n, COIN_RADIUS, COIN_THICK);
315 coin_head(n, COIN_RADIUS, COIN_THICK);
316 coin_tail(n, COIN_RADIUS, COIN_THICK);
323 if (glIsList(coin_list))
324 glDeleteLists(coin_list, 1);
326 if (glIsTexture(coin_text))
327 glDeleteTextures(1, &coin_text);
329 if (glIsTexture(coin_grup))
330 glDeleteTextures(1, &coin_grup);
332 if (glIsTexture(coin_grdn))
333 glDeleteTextures(1, &coin_grdn);
343 static const float a[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
344 static const float s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
345 static const float e[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
346 static const float h[1] = { 32.0f };
348 glPushAttrib(GL_LIGHTING_BIT);
350 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, a);
351 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s);
352 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e);
353 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
356 void coin_push_text(int n)
358 glEnable(GL_COLOR_MATERIAL);
360 glBindTexture(GL_TEXTURE_2D, coin_grdn);
362 glBindTexture(GL_TEXTURE_2D, coin_grup);
364 glBindTexture(GL_TEXTURE_2D, coin_text);
367 void coin_draw(int n, float r)
374 glCallList(coin_list);
382 /*---------------------------------------------------------------------------*/
384 static GLuint goal_list;
386 void goal_init(int b)
388 int i, n = b ? 32 : 8;
390 goal_list = glGenLists(1);
392 glNewList(goal_list, GL_COMPILE);
394 glPushAttrib(GL_TEXTURE_BIT |
396 GL_DEPTH_BUFFER_BIT);
398 glEnable(GL_COLOR_MATERIAL);
399 glDisable(GL_LIGHTING);
400 glDisable(GL_TEXTURE_2D);
401 glDepthMask(GL_FALSE);
403 glBegin(GL_QUAD_STRIP);
405 for (i = 0; i <= n; i++)
407 float x = fcosf(2.f * PI * i / n);
408 float y = fsinf(2.f * PI * i / n);
410 glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
411 glVertex3f(x, 0.0f, y);
413 glColor4f(1.0f, 1.0f, 0.0f, 0.0f);
414 glVertex3f(x, GOAL_HEIGHT, y);
426 if (glIsList(goal_list))
427 glDeleteLists(goal_list, 1);
434 glCallList(goal_list);
437 /*---------------------------------------------------------------------------*/
439 static GLuint jump_list;
441 void jump_init(int b)
443 int k, i, n = b ? 32 : 8;
445 jump_list = glGenLists(2);
447 for (k = 0; k < 12; k++)
449 glNewList(jump_list + k, GL_COMPILE);
451 glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
453 glEnable(GL_COLOR_MATERIAL);
454 glDisable(GL_LIGHTING);
455 glDisable(GL_TEXTURE_2D);
456 glDepthMask(GL_FALSE);
458 glBegin(GL_QUAD_STRIP);
460 for (i = 0; i <= n; i++)
462 float x = fcosf(2.f * PI * i / n);
463 float y = fsinf(2.f * PI * i / n);
465 glColor4f(1.0f, 1.0f, 1.0f, (k == 0 ? 0.5f : 0.8f));
466 glVertex3f(x, 0.0f, y);
468 glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
469 glVertex3f(x, JUMP_HEIGHT, y);
482 if (glIsList(jump_list))
483 glDeleteLists(jump_list, 1);
488 void jump_draw(int highlight)
490 glCallList(jump_list + highlight);
493 /*---------------------------------------------------------------------------*/
495 static GLuint swch_list;
497 static GLfloat swch_colors[8][4] = {
498 {1.0f, 0.0f, 0.0f, 0.5f}, /* red out */
499 {1.0f, 0.0f, 0.0f, 0.0f},
500 {1.0f, 0.0f, 0.0f, 0.8f}, /* red in */
501 {1.0f, 0.0f, 0.0f, 0.0f},
502 {0.0f, 1.0f, 0.0f, 0.5f}, /* green out */
503 {0.0f, 1.0f, 0.0f, 0.0f},
504 {0.0f, 1.0f, 0.0f, 0.8f}, /* green in */
505 {0.0f, 1.0f, 0.0f, 0.0f}};
507 void swch_init(int b)
509 int k, i, n = b ? 32 : 8;
511 swch_list = glGenLists(4);
513 /* Create the display lists. */
515 for (k = 0; k < 4; k++)
517 glNewList(swch_list + k, GL_COMPILE);
519 glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
521 glEnable(GL_COLOR_MATERIAL);
522 glDisable(GL_LIGHTING);
523 glDisable(GL_TEXTURE_2D);
524 glDepthMask(GL_FALSE);
526 glBegin(GL_QUAD_STRIP);
528 for (i = 0; i <= n; i++)
530 float x = fcosf(2.f * PI * i / n);
531 float y = fsinf(2.f * PI * i / n);
533 glColor4fv(swch_colors[2 * k]);
534 glVertex3f(x, 0.0f, y);
536 glColor4fv(swch_colors[2 * k + 1]);
537 glVertex3f(x, SWCH_HEIGHT, y);
550 if (glIsList(swch_list))
551 glDeleteLists(swch_list, 2);
556 void swch_draw(int b, int e)
558 glCallList(swch_list + b * 2 + e);
561 /*---------------------------------------------------------------------------*/
563 static GLuint flag_list;
565 void flag_init(int b)
567 int i, n = b ? 8 : 4;
569 flag_list = glGenLists(1);
571 glNewList(flag_list, GL_COMPILE);
573 glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT);
575 glEnable(GL_COLOR_MATERIAL);
576 glDisable(GL_LIGHTING);
577 glDisable(GL_TEXTURE_2D);
579 glBegin(GL_QUAD_STRIP);
581 for (i = 0; i <= n; i++)
583 float x = fcosf(2.f * PI * i / n) * 0.01f;
584 float y = fsinf(2.f * PI * i / n) * 0.01f;
586 glColor3f(1.0f, 1.0f, 1.0f);
587 glVertex3f(x, 0.0f, y);
588 glVertex3f(x, GOAL_HEIGHT, y);
593 glBegin(GL_TRIANGLES);
595 glColor3f(1.0f, 0.0f, 0.0f);
597 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
598 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
599 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
601 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
602 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
603 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
614 if (glIsList(flag_list))
615 glDeleteLists(flag_list, 1);
622 glCallList(flag_list);
625 /*---------------------------------------------------------------------------*/
627 * A note about lighting and shadow: technically speaking, it's wrong.
628 * The light position and shadow projection behave as if the
629 * light-source rotates with the floor. However, the skybox does not
630 * rotate, thus the light should also remain stationary.
632 * The correct behavior would eliminate a significant 3D cue: the
633 * shadow of the ball indicates the ball's position relative to the
634 * floor even when the ball is in the air. This was the motivating
635 * idea behind the shadow in the first place, so correct shadow
636 * projection would only magnify the problem.
639 static GLuint shad_text;
643 shad_text = make_image_from_file(NULL, NULL, NULL, NULL, IMG_SHAD);
645 if (config_get_d(CONFIG_SHADOW) == 2)
647 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
648 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
654 if (glIsTexture(shad_text))
655 glDeleteTextures(1, &shad_text);
658 void shad_draw_set(const float *p, float r)
660 glMatrixMode(GL_TEXTURE);
664 glBindTexture(GL_TEXTURE_2D, shad_text);
667 glTranslatef(0.5f - k * p[0],
668 0.5f - k * p[2], 0.f);
669 glScalef(k, k, 1.0f);
671 glMatrixMode(GL_MODELVIEW);
674 void shad_draw_clr(void)
676 glMatrixMode(GL_TEXTURE);
680 glMatrixMode(GL_MODELVIEW);
683 /*---------------------------------------------------------------------------*/
685 void fade_draw(float k)
687 int w = config_get_d(CONFIG_WIDTH);
688 int h = config_get_d(CONFIG_HEIGHT);
693 glPushAttrib(GL_TEXTURE_BIT |
695 GL_COLOR_BUFFER_BIT |
696 GL_DEPTH_BUFFER_BIT);
698 glEnable(GL_COLOR_MATERIAL);
699 glDisable(GL_LIGHTING);
700 glDisable(GL_DEPTH_TEST);
701 glDisable(GL_TEXTURE_2D);
703 glColor4f(0.0f, 0.0f, 0.0f, k);
719 /*---------------------------------------------------------------------------*/