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(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 static const float a[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
100 static const float s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
101 static const float e[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
102 static const float h[1] = { 20.0f };
104 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, a);
105 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s);
106 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e);
107 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
109 glEnable(GL_COLOR_MATERIAL);
111 glBindTexture(GL_TEXTURE_2D, ball_text);
113 /* Render the ball back to front in case it is translucent. */
115 glDepthMask(GL_FALSE);
117 glCullFace(GL_FRONT);
118 glCallList(ball_list);
120 glCallList(ball_list);
122 glDepthMask(GL_TRUE);
124 /* Render the ball into the depth buffer. */
126 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
128 glCallList(ball_list);
130 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
132 /* Ensure the ball is visible even when obscured by geometry. */
134 glDisable(GL_DEPTH_TEST);
136 glColor4f(1.0f, 1.0f, 1.0f, 0.1f);
137 glCallList(ball_list);
139 glEnable(GL_DEPTH_TEST);
141 glDisable(GL_COLOR_MATERIAL);
144 /*---------------------------------------------------------------------------*/
146 static GLuint mark_list;
148 void mark_init(int b)
150 int i, slices = b ? 32 : 16;
152 mark_list = glGenLists(1);
154 glNewList(mark_list, GL_COMPILE);
156 glBegin(GL_TRIANGLE_FAN);
158 glNormal3f(0.f, 1.f, 0.f);
160 for (i = 0; i < slices; i++)
162 float x = fcosf(-2.f * PI * i / slices);
163 float y = fsinf(-2.f * PI * i / slices);
175 glEnable(GL_COLOR_MATERIAL);
176 glDisable(GL_TEXTURE_2D);
177 glDepthMask(GL_FALSE);
179 glCallList(mark_list);
181 glDepthMask(GL_TRUE);
182 glEnable(GL_TEXTURE_2D);
183 glDisable(GL_COLOR_MATERIAL);
188 if (glIsList(mark_list))
189 glDeleteLists(mark_list, 1);
194 /*---------------------------------------------------------------------------*/
196 static void coin_head(int n, float radius, float thick)
200 glBegin(GL_TRIANGLE_FAN);
202 glNormal3f(0.f, 0.f, +1.f);
204 for (i = 0; i < n; i++)
206 float x = fcosf(+2.f * PI * i / n);
207 float y = fsinf(+2.f * PI * i / n);
209 glTexCoord2f(-x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
210 glVertex3f(radius * x, radius * y, +thick);
216 static void coin_tail(int n, float radius, float thick)
220 glBegin(GL_TRIANGLE_FAN);
222 glNormal3f(0.f, 0.f, -1.f);
224 for (i = 0; i < n; i++)
226 float x = fcosf(-2.f * PI * i / n);
227 float y = fsinf(-2.f * PI * i / n);
229 glTexCoord2f(+x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
230 glVertex3f(radius * x, radius * y, -thick);
236 static void coin_edge(int n, float radius, float thick)
240 glBegin(GL_QUAD_STRIP);
242 for (i = 0; i <= n; i++)
244 float x = fcosf(2.f * PI * i / n);
245 float y = fsinf(2.f * PI * i / n);
247 glNormal3f(x, y, 0.f);
248 glVertex3f(radius * x, radius * y, +thick);
249 glVertex3f(radius * x, radius * y, -thick);
255 /*---------------------------------------------------------------------------*/
257 static GLuint item_coin_text;
258 static GLuint item_grow_text;
259 static GLuint item_shrink_text;
260 static GLuint item_list;
262 void item_color(const struct s_item *hp, float *c)
302 void item_init(int b)
306 item_coin_text = make_image_from_file(IMG_ITEM_COIN);
307 item_grow_text = make_image_from_file(IMG_ITEM_GROW);
308 item_shrink_text = make_image_from_file(IMG_ITEM_SHRINK);
310 item_list = glGenLists(1);
312 glNewList(item_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(item_list))
324 glDeleteLists(item_list, 1);
326 if (glIsTexture(item_coin_text))
327 glDeleteTextures(1, &item_coin_text);
329 if (glIsTexture(item_grow_text))
330 glDeleteTextures(1, &item_grow_text);
332 if (glIsTexture(item_shrink_text))
333 glDeleteTextures(1, &item_shrink_text);
338 item_shrink_text = 0;
341 void item_push(int type)
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] = { 10.0f };
348 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, a);
349 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s);
350 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e);
351 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
353 glEnable(GL_COLOR_MATERIAL);
358 glBindTexture(GL_TEXTURE_2D, item_coin_text);
362 glBindTexture(GL_TEXTURE_2D, item_grow_text);
366 glBindTexture(GL_TEXTURE_2D, item_shrink_text);
371 void item_draw(const struct s_item *hp, float r)
378 glCallList(item_list);
383 glColor3f(1.0f, 1.0f, 1.0f);
384 glDisable(GL_COLOR_MATERIAL);
387 /*---------------------------------------------------------------------------*/
389 static GLuint goal_list;
391 void goal_init(int b)
393 int i, n = b ? 32 : 8;
395 goal_list = glGenLists(1);
397 glNewList(goal_list, GL_COMPILE);
399 glBegin(GL_QUAD_STRIP);
401 for (i = 0; i <= n; i++)
403 float x = fcosf(2.f * PI * i / n);
404 float y = fsinf(2.f * PI * i / n);
406 glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
407 glVertex3f(x, 0.0f, y);
409 glColor4f(1.0f, 1.0f, 0.0f, 0.0f);
410 glVertex3f(x, GOAL_HEIGHT, y);
420 if (glIsList(goal_list))
421 glDeleteLists(goal_list, 1);
428 glCallList(goal_list);
431 /*---------------------------------------------------------------------------*/
433 static GLuint jump_list;
435 void jump_init(int b)
437 int k, i, n = b ? 32 : 8;
439 jump_list = glGenLists(2);
441 for (k = 0; k < 2; k++)
443 glNewList(jump_list + k, GL_COMPILE);
445 glBegin(GL_QUAD_STRIP);
447 for (i = 0; i <= n; i++)
449 float x = fcosf(2.f * PI * i / n);
450 float y = fsinf(2.f * PI * i / n);
452 glColor4f(1.0f, 1.0f, 1.0f, (k == 0 ? 0.5f : 0.8f));
453 glVertex3f(x, 0.0f, y);
455 glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
456 glVertex3f(x, JUMP_HEIGHT, y);
467 glDeleteLists(jump_list, 2);
471 void jump_draw(int highlight)
473 glCallList(jump_list + highlight);
476 /*---------------------------------------------------------------------------*/
478 static GLuint swch_list;
480 static GLfloat swch_colors[8][4] = {
481 { 1.0f, 0.0f, 0.0f, 0.5f }, /* red out */
482 { 1.0f, 0.0f, 0.0f, 0.0f },
483 { 1.0f, 0.0f, 0.0f, 0.8f }, /* red in */
484 { 1.0f, 0.0f, 0.0f, 0.0f },
485 { 0.0f, 1.0f, 0.0f, 0.5f }, /* green out */
486 { 0.0f, 1.0f, 0.0f, 0.0f },
487 { 0.0f, 1.0f, 0.0f, 0.8f }, /* green in */
488 { 0.0f, 1.0f, 0.0f, 0.0f }};
490 void swch_init(int b)
492 int k, i, n = b ? 32 : 8;
494 swch_list = glGenLists(4);
496 /* Create the display lists. */
498 for (k = 0; k < 4; k++)
500 glNewList(swch_list + k, GL_COMPILE);
502 glBegin(GL_QUAD_STRIP);
504 for (i = 0; i <= n; i++)
506 float x = fcosf(2.f * PI * i / n);
507 float y = fsinf(2.f * PI * i / n);
509 glColor4fv(swch_colors[2 * k + 0]);
510 glVertex3f(x, 0.0f, y);
512 glColor4fv(swch_colors[2 * k + 1]);
513 glVertex3f(x, SWCH_HEIGHT, y);
524 if (glIsList(swch_list))
525 glDeleteLists(swch_list, 2);
530 void swch_draw(int b, int e)
532 glCallList(swch_list + b * 2 + e);
535 /*---------------------------------------------------------------------------*/
537 static GLuint flag_list;
539 void flag_init(int b)
541 int i, n = b ? 8 : 4;
543 flag_list = glGenLists(1);
545 glNewList(flag_list, GL_COMPILE);
547 glEnable(GL_COLOR_MATERIAL);
548 glDisable(GL_LIGHTING);
549 glDisable(GL_TEXTURE_2D);
551 glBegin(GL_TRIANGLES);
553 glColor3f(1.0f, 0.0f, 0.0f);
555 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
556 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
557 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
559 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
560 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
561 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
565 glBegin(GL_QUAD_STRIP);
567 for (i = 0; i <= n; i++)
569 float x = fcosf(2.f * PI * i / n) * 0.01f;
570 float y = fsinf(2.f * PI * i / n) * 0.01f;
572 glColor3f(1.0f, 1.0f, 1.0f);
573 glVertex3f(x, 0.0f, y);
574 glVertex3f(x, GOAL_HEIGHT, y);
579 glEnable(GL_TEXTURE_2D);
580 glEnable(GL_LIGHTING);
581 glDisable(GL_COLOR_MATERIAL);
588 if (glIsList(flag_list))
589 glDeleteLists(flag_list, 1);
596 glCallList(flag_list);
599 /*---------------------------------------------------------------------------*/
601 * A note about lighting and shadow: technically speaking, it's wrong.
602 * The light position and shadow projection behave as if the
603 * light-source rotates with the floor. However, the skybox does not
604 * rotate, thus the light should also remain stationary.
606 * The correct behavior would eliminate a significant 3D cue: the
607 * shadow of the ball indicates the ball's position relative to the
608 * floor even when the ball is in the air. This was the motivating
609 * idea behind the shadow in the first place, so correct shadow
610 * projection would only magnify the problem.
613 static GLuint shad_text;
617 shad_text = make_image_from_file(IMG_SHAD);
619 if (config_get_d(CONFIG_SHADOW) == 2)
621 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
622 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
628 if (glIsTexture(shad_text))
629 glDeleteTextures(1, &shad_text);
632 void shad_draw_set(const float *p, float r)
634 glMatrixMode(GL_TEXTURE);
638 glBindTexture(GL_TEXTURE_2D, shad_text);
641 glTranslatef(0.5f - k * p[0],
642 0.5f - k * p[2], 0.f);
643 glScalef(k, k, 1.0f);
645 glMatrixMode(GL_MODELVIEW);
648 void shad_draw_clr(void)
650 glMatrixMode(GL_TEXTURE);
654 glMatrixMode(GL_MODELVIEW);
657 /*---------------------------------------------------------------------------*/
659 void fade_draw(float k)
663 int w = config_get_d(CONFIG_WIDTH);
664 int h = config_get_d(CONFIG_HEIGHT);
668 glEnable(GL_COLOR_MATERIAL);
669 glDisable(GL_LIGHTING);
670 glDisable(GL_DEPTH_TEST);
671 glDisable(GL_TEXTURE_2D);
673 glColor4f(0.0f, 0.0f, 0.0f, k);
684 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
686 glEnable(GL_TEXTURE_2D);
687 glEnable(GL_DEPTH_TEST);
688 glEnable(GL_LIGHTING);
689 glDisable(GL_COLOR_MATERIAL);
695 /*---------------------------------------------------------------------------*/