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 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
45 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
47 config_get_s(CONFIG_BALL_BONUS, name, MAXSTR);
48 ball_text[1] = make_image_from_file(NULL, NULL, NULL, NULL, name);
50 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
51 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
53 ball_list = glGenLists(1);
55 glNewList(ball_list, GL_COMPILE);
57 for (i = 0; i < stacks; i++)
59 float k0 = (float) i / stacks;
60 float k1 = (float) (i + 1) / stacks;
62 float s0 = fsinf(V_PI * (k0 - 0.5));
63 float c0 = fcosf(V_PI * (k0 - 0.5));
64 float s1 = fsinf(V_PI * (k1 - 0.5));
65 float c1 = fcosf(V_PI * (k1 - 0.5));
67 glBegin(GL_QUAD_STRIP);
69 for (j = 0; j <= slices; j++)
71 float k = (float) j / slices;
72 float s = fsinf(V_PI * k * 2.0);
73 float c = fcosf(V_PI * k * 2.0);
76 glNormal3f(s * c0, c * c0, s0);
77 glVertex3f(s * c0, c * c0, s0);
80 glNormal3f(s * c1, c * c1, s1);
81 glVertex3f(s * c1, c * c1, s1);
92 if (glIsList(ball_list))
93 glDeleteLists(ball_list, 1);
95 if (glIsTexture(ball_text[0]))
96 glDeleteTextures(1, &ball_text[0]);
98 if (glIsTexture(ball_text[1]))
99 glDeleteTextures(1, &ball_text[1]);
106 void ball_draw(int i)
108 glPushAttrib(GL_POLYGON_BIT |
110 GL_DEPTH_BUFFER_BIT);
112 static const float s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
113 static const float e[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
114 static const float h[1] = { 64.0f };
116 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s);
117 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e);
118 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
120 glEnable(GL_COLOR_MATERIAL);
122 glBindTexture(GL_TEXTURE_2D, ball_text[i]);
124 /* Render the ball back to front in case it is translucent. */
126 glDepthMask(GL_FALSE);
128 glCullFace(GL_FRONT);
129 glCallList(ball_list);
131 glCallList(ball_list);
133 /* Render the ball into the depth buffer. */
135 glDepthMask(GL_TRUE);
136 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
138 glCallList(ball_list);
140 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
142 /* Ensure the ball is visible even when obscured by geometry. */
144 glDisable(GL_DEPTH_TEST);
146 glColor4f(1.0f, 1.0f, 1.0f, 0.1f);
147 glCallList(ball_list);
152 /*---------------------------------------------------------------------------*/
154 static GLuint mark_list;
156 void mark_init(int b)
158 int i, slices = b ? 32 : 16;
160 mark_list = glGenLists(1);
162 glNewList(mark_list, GL_COMPILE);
164 glBegin(GL_TRIANGLE_FAN);
166 glNormal3f(0.f, 1.f, 0.f);
168 for (i = 0; i < slices; i++)
170 float x = fcosf(-2.f * PI * i / slices);
171 float y = fsinf(-2.f * PI * i / slices);
183 glPushAttrib(GL_TEXTURE_BIT);
184 glPushAttrib(GL_LIGHTING_BIT);
185 glPushAttrib(GL_DEPTH_BUFFER_BIT);
187 glEnable(GL_COLOR_MATERIAL);
188 glDisable(GL_TEXTURE_2D);
189 glDepthMask(GL_FALSE);
191 glCallList(mark_list);
200 if (glIsList(mark_list))
201 glDeleteLists(mark_list, 1);
206 /*---------------------------------------------------------------------------*/
208 static void coin_head(int n, float radius, float thick)
212 glBegin(GL_TRIANGLE_FAN);
214 glNormal3f(0.f, 0.f, +1.f);
216 for (i = 0; i < n; i++)
218 float x = fcosf(+2.f * PI * i / n);
219 float y = fsinf(+2.f * PI * i / n);
221 glTexCoord2f(-x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
222 glVertex3f(radius * x, radius * y, +thick);
228 static void coin_tail(int n, float radius, float thick)
232 glBegin(GL_TRIANGLE_FAN);
234 glNormal3f(0.f, 0.f, -1.f);
236 for (i = 0; i < n; i++)
238 float x = fcosf(-2.f * PI * i / n);
239 float y = fsinf(-2.f * PI * i / n);
241 glTexCoord2f(+x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
242 glVertex3f(radius * x, radius * y, -thick);
248 static void coin_edge(int n, float radius, float thick)
252 glBegin(GL_QUAD_STRIP);
254 for (i = 0; i <= n; i++)
256 float x = fcosf(2.f * PI * i / n);
257 float y = fsinf(2.f * PI * i / n);
259 glNormal3f(x, y, 0.f);
260 glVertex3f(radius * x, radius * y, +thick);
261 glVertex3f(radius * x, radius * y, -thick);
267 /*---------------------------------------------------------------------------*/
269 static GLuint item_coin_text;
270 static GLuint item_grow_text;
271 static GLuint item_shrink_text;
272 static GLuint item_list;
274 void item_color(const struct s_item *hp, float *c)
314 void item_init(int b)
318 item_coin_text = make_image_from_file(NULL, NULL, NULL, NULL,
320 item_grow_text = make_image_from_file(NULL, NULL, NULL, NULL,
322 item_shrink_text = make_image_from_file(NULL, NULL, NULL, NULL,
324 item_list = glGenLists(1);
326 glNewList(item_list, GL_COMPILE);
328 coin_edge(n, COIN_RADIUS, COIN_THICK);
329 coin_head(n, COIN_RADIUS, COIN_THICK);
330 coin_tail(n, COIN_RADIUS, COIN_THICK);
337 if (glIsList(item_list))
338 glDeleteLists(item_list, 1);
340 if (glIsTexture(item_coin_text))
341 glDeleteTextures(1, &item_coin_text);
343 if (glIsTexture(item_grow_text))
344 glDeleteTextures(1, &item_grow_text);
346 if (glIsTexture(item_shrink_text))
347 glDeleteTextures(1, &item_shrink_text);
352 item_shrink_text = 0;
355 void item_push(int type)
357 static const float a[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
358 static const float s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
359 static const float e[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
360 static const float h[1] = { 32.0f };
362 glPushAttrib(GL_LIGHTING_BIT);
364 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, a);
365 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s);
366 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e);
367 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
369 glEnable(GL_COLOR_MATERIAL);
374 glBindTexture(GL_TEXTURE_2D, item_coin_text);
378 glBindTexture(GL_TEXTURE_2D, item_grow_text);
382 glBindTexture(GL_TEXTURE_2D, item_shrink_text);
387 void item_draw(const struct s_item *hp, float r)
394 glCallList(item_list);
402 /*---------------------------------------------------------------------------*/
404 static GLuint goal_list;
406 void goal_init(int b)
408 int i, n = b ? 32 : 8;
410 goal_list = glGenLists(1);
412 glNewList(goal_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, 0.0f, 0.5f);
431 glVertex3f(x, 0.0f, y);
433 glColor4f(1.0f, 1.0f, 0.0f, 0.0f);
434 glVertex3f(x, GOAL_HEIGHT, y);
446 if (glIsList(goal_list))
447 glDeleteLists(goal_list, 1);
454 glCallList(goal_list);
457 /*---------------------------------------------------------------------------*/
459 static GLuint jump_list;
461 void jump_init(int b)
463 int k, i, n = b ? 32 : 8;
465 jump_list = glGenLists(2);
467 for (k = 0; k < 2; k++)
469 glNewList(jump_list + k, 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, 1.0f, 1.0f, (k == 0 ? 0.5f : 0.8f));
488 glVertex3f(x, 0.0f, y);
490 glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
491 glVertex3f(x, JUMP_HEIGHT, y);
504 glDeleteLists(jump_list, 2);
508 void jump_draw(int highlight)
510 glCallList(jump_list + highlight);
513 /*---------------------------------------------------------------------------*/
515 static GLuint swch_list;
517 static GLfloat swch_colors[8][4] = {
518 {1.0f, 0.0f, 0.0f, 0.5f}, /* red out */
519 {1.0f, 0.0f, 0.0f, 0.0f},
520 {1.0f, 0.0f, 0.0f, 0.8f}, /* red in */
521 {1.0f, 0.0f, 0.0f, 0.0f},
522 {0.0f, 1.0f, 0.0f, 0.5f}, /* green out */
523 {0.0f, 1.0f, 0.0f, 0.0f},
524 {0.0f, 1.0f, 0.0f, 0.8f}, /* green in */
525 {0.0f, 1.0f, 0.0f, 0.0f}};
527 void swch_init(int b)
529 int k, i, n = b ? 32 : 8;
531 swch_list = glGenLists(4);
533 /* Create the display lists. */
535 for (k = 0; k < 4; k++)
537 glNewList(swch_list + k, GL_COMPILE);
539 glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
541 glEnable(GL_COLOR_MATERIAL);
542 glDisable(GL_LIGHTING);
543 glDisable(GL_TEXTURE_2D);
544 glDepthMask(GL_FALSE);
546 glBegin(GL_QUAD_STRIP);
548 for (i = 0; i <= n; i++)
550 float x = fcosf(2.f * PI * i / n);
551 float y = fsinf(2.f * PI * i / n);
553 glColor4fv(swch_colors[2 * k]);
554 glVertex3f(x, 0.0f, y);
556 glColor4fv(swch_colors[2 * k + 1]);
557 glVertex3f(x, SWCH_HEIGHT, y);
570 if (glIsList(swch_list))
571 glDeleteLists(swch_list, 2);
576 void swch_draw(int b, int e)
578 glCallList(swch_list + b * 2 + e);
581 /*---------------------------------------------------------------------------*/
583 static GLuint flag_list;
585 void flag_init(int b)
587 int i, n = b ? 8 : 4;
589 flag_list = glGenLists(1);
591 glNewList(flag_list, GL_COMPILE);
593 glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT);
595 glEnable(GL_COLOR_MATERIAL);
596 glDisable(GL_LIGHTING);
597 glDisable(GL_TEXTURE_2D);
599 glBegin(GL_QUAD_STRIP);
601 for (i = 0; i <= n; i++)
603 float x = fcosf(2.f * PI * i / n) * 0.01f;
604 float y = fsinf(2.f * PI * i / n) * 0.01f;
606 glColor3f(1.0f, 1.0f, 1.0f);
607 glVertex3f(x, 0.0f, y);
608 glVertex3f(x, GOAL_HEIGHT, y);
613 glBegin(GL_TRIANGLES);
615 glColor3f(1.0f, 0.0f, 0.0f);
617 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
618 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
619 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
621 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
622 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
623 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
634 if (glIsList(flag_list))
635 glDeleteLists(flag_list, 1);
642 glCallList(flag_list);
645 /*---------------------------------------------------------------------------*/
647 * A note about lighting and shadow: technically speaking, it's wrong.
648 * The light position and shadow projection behave as if the
649 * light-source rotates with the floor. However, the skybox does not
650 * rotate, thus the light should also remain stationary.
652 * The correct behavior would eliminate a significant 3D cue: the
653 * shadow of the ball indicates the ball's position relative to the
654 * floor even when the ball is in the air. This was the motivating
655 * idea behind the shadow in the first place, so correct shadow
656 * projection would only magnify the problem.
659 static GLuint shad_text;
663 shad_text = make_image_from_file(NULL, NULL, NULL, NULL, IMG_SHAD);
665 if (config_get_d(CONFIG_SHADOW) == 2)
667 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
668 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
674 if (glIsTexture(shad_text))
675 glDeleteTextures(1, &shad_text);
678 void shad_draw_set(const float *p, float r)
680 glMatrixMode(GL_TEXTURE);
684 glBindTexture(GL_TEXTURE_2D, shad_text);
687 glTranslatef(0.5f - k * p[0],
688 0.5f - k * p[2], 0.f);
689 glScalef(k, k, 1.0f);
691 glMatrixMode(GL_MODELVIEW);
694 void shad_draw_clr(void)
696 glMatrixMode(GL_TEXTURE);
700 glMatrixMode(GL_MODELVIEW);
703 /*---------------------------------------------------------------------------*/
705 void fade_draw(float k)
707 int w = config_get_d(CONFIG_WIDTH);
708 int h = config_get_d(CONFIG_HEIGHT);
713 glPushAttrib(GL_TEXTURE_BIT |
715 GL_COLOR_BUFFER_BIT |
716 GL_DEPTH_BUFFER_BIT);
718 glEnable(GL_COLOR_MATERIAL);
719 glDisable(GL_LIGHTING);
720 glDisable(GL_DEPTH_TEST);
721 glDisable(GL_TEXTURE_2D);
723 glColor4f(0.0f, 0.0f, 0.0f, k);
739 /*---------------------------------------------------------------------------*/