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 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 void coin_head(int n, float radius, float thick)
203 glBegin(GL_TRIANGLE_FAN);
205 glNormal3f(0.f, 0.f, +1.f);
207 for (i = 0; i < n; i++)
209 float x = fcosf(+2.f * PI * i / n);
210 float y = fsinf(+2.f * PI * i / n);
212 glTexCoord2f(-x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
213 glVertex3f(radius * x, radius * y, +thick);
219 static void coin_tail(int n, float radius, float thick)
223 glBegin(GL_TRIANGLE_FAN);
225 glNormal3f(0.f, 0.f, -1.f);
227 for (i = 0; i < n; i++)
229 float x = fcosf(-2.f * PI * i / n);
230 float y = fsinf(-2.f * PI * i / n);
232 glTexCoord2f(+x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
233 glVertex3f(radius * x, radius * y, -thick);
239 static void coin_edge(int n, float radius, float thick)
243 glBegin(GL_QUAD_STRIP);
245 for (i = 0; i <= n; i++)
247 float x = fcosf(2.f * PI * i / n);
248 float y = fsinf(2.f * PI * i / n);
250 glNormal3f(x, y, 0.f);
251 glVertex3f(radius * x, radius * y, +thick);
252 glVertex3f(radius * x, radius * y, -thick);
258 /*---------------------------------------------------------------------------*/
260 static GLuint item_coin_text;
261 static GLuint item_grow_text;
262 static GLuint item_shrink_text;
263 static GLuint item_list;
265 void item_color(const struct s_item *hp, float *c)
305 void item_init(int b)
309 item_coin_text = make_image_from_file(IMG_ITEM_COIN);
310 item_grow_text = make_image_from_file(IMG_ITEM_GROW);
311 item_shrink_text = make_image_from_file(IMG_ITEM_SHRINK);
312 item_list = glGenLists(1);
314 glNewList(item_list, GL_COMPILE);
316 coin_edge(n, COIN_RADIUS, COIN_THICK);
317 coin_head(n, COIN_RADIUS, COIN_THICK);
318 coin_tail(n, COIN_RADIUS, COIN_THICK);
325 if (glIsList(item_list))
326 glDeleteLists(item_list, 1);
328 if (glIsTexture(item_coin_text))
329 glDeleteTextures(1, &item_coin_text);
331 if (glIsTexture(item_grow_text))
332 glDeleteTextures(1, &item_grow_text);
334 if (glIsTexture(item_shrink_text))
335 glDeleteTextures(1, &item_shrink_text);
340 item_shrink_text = 0;
343 void item_push(int type)
345 static const float a[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
346 static const float s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
347 static const float e[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
348 static const float h[1] = { 32.0f };
350 glPushAttrib(GL_LIGHTING_BIT);
352 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, a);
353 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, s);
354 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, e);
355 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
357 glEnable(GL_COLOR_MATERIAL);
362 glBindTexture(GL_TEXTURE_2D, item_coin_text);
366 glBindTexture(GL_TEXTURE_2D, item_grow_text);
370 glBindTexture(GL_TEXTURE_2D, item_shrink_text);
375 void item_draw(const struct s_item *hp, float r)
382 glCallList(item_list);
390 /*---------------------------------------------------------------------------*/
392 static GLuint goal_list;
394 void goal_init(int b)
396 int i, n = b ? 32 : 8;
398 goal_list = glGenLists(1);
400 glNewList(goal_list, GL_COMPILE);
402 glPushAttrib(GL_TEXTURE_BIT |
404 GL_DEPTH_BUFFER_BIT);
406 glEnable(GL_COLOR_MATERIAL);
407 glDisable(GL_LIGHTING);
408 glDisable(GL_TEXTURE_2D);
409 glDepthMask(GL_FALSE);
411 glBegin(GL_QUAD_STRIP);
413 for (i = 0; i <= n; i++)
415 float x = fcosf(2.f * PI * i / n);
416 float y = fsinf(2.f * PI * i / n);
418 glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
419 glVertex3f(x, 0.0f, y);
421 glColor4f(1.0f, 1.0f, 0.0f, 0.0f);
422 glVertex3f(x, GOAL_HEIGHT, y);
434 if (glIsList(goal_list))
435 glDeleteLists(goal_list, 1);
442 glCallList(goal_list);
445 /*---------------------------------------------------------------------------*/
447 static GLuint jump_list;
449 void jump_init(int b)
451 int k, i, n = b ? 32 : 8;
453 jump_list = glGenLists(2);
455 for (k = 0; k < 2; k++)
457 glNewList(jump_list + k, GL_COMPILE);
459 glPushAttrib(GL_TEXTURE_BIT |
461 GL_DEPTH_BUFFER_BIT);
463 glEnable(GL_COLOR_MATERIAL);
464 glDisable(GL_LIGHTING);
465 glDisable(GL_TEXTURE_2D);
466 glDepthMask(GL_FALSE);
468 glBegin(GL_QUAD_STRIP);
470 for (i = 0; i <= n; i++)
472 float x = fcosf(2.f * PI * i / n);
473 float y = fsinf(2.f * PI * i / n);
475 glColor4f(1.0f, 1.0f, 1.0f, (k == 0 ? 0.5f : 0.8f));
476 glVertex3f(x, 0.0f, y);
478 glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
479 glVertex3f(x, JUMP_HEIGHT, y);
492 glDeleteLists(jump_list, 2);
496 void jump_draw(int highlight)
498 glCallList(jump_list + highlight);
501 /*---------------------------------------------------------------------------*/
503 static GLuint swch_list;
505 static GLfloat swch_colors[8][4] = {
506 {1.0f, 0.0f, 0.0f, 0.5f}, /* red out */
507 {1.0f, 0.0f, 0.0f, 0.0f},
508 {1.0f, 0.0f, 0.0f, 0.8f}, /* red in */
509 {1.0f, 0.0f, 0.0f, 0.0f},
510 {0.0f, 1.0f, 0.0f, 0.5f}, /* green out */
511 {0.0f, 1.0f, 0.0f, 0.0f},
512 {0.0f, 1.0f, 0.0f, 0.8f}, /* green in */
513 {0.0f, 1.0f, 0.0f, 0.0f}};
515 void swch_init(int b)
517 int k, i, n = b ? 32 : 8;
519 swch_list = glGenLists(4);
521 /* Create the display lists. */
523 for (k = 0; k < 4; k++)
525 glNewList(swch_list + k, GL_COMPILE);
527 glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
529 glEnable(GL_COLOR_MATERIAL);
530 glDisable(GL_LIGHTING);
531 glDisable(GL_TEXTURE_2D);
532 glDepthMask(GL_FALSE);
534 glBegin(GL_QUAD_STRIP);
536 for (i = 0; i <= n; i++)
538 float x = fcosf(2.f * PI * i / n);
539 float y = fsinf(2.f * PI * i / n);
541 glColor4fv(swch_colors[2 * k]);
542 glVertex3f(x, 0.0f, y);
544 glColor4fv(swch_colors[2 * k + 1]);
545 glVertex3f(x, SWCH_HEIGHT, y);
558 if (glIsList(swch_list))
559 glDeleteLists(swch_list, 2);
564 void swch_draw(int b, int e)
566 glCallList(swch_list + b * 2 + e);
569 /*---------------------------------------------------------------------------*/
571 static GLuint flag_list;
573 void flag_init(int b)
575 int i, n = b ? 8 : 4;
577 flag_list = glGenLists(1);
579 glNewList(flag_list, GL_COMPILE);
581 glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT);
583 glEnable(GL_COLOR_MATERIAL);
584 glDisable(GL_LIGHTING);
585 glDisable(GL_TEXTURE_2D);
587 glBegin(GL_QUAD_STRIP);
589 for (i = 0; i <= n; i++)
591 float x = fcosf(2.f * PI * i / n) * 0.01f;
592 float y = fsinf(2.f * PI * i / n) * 0.01f;
594 glColor3f(1.0f, 1.0f, 1.0f);
595 glVertex3f(x, 0.0f, y);
596 glVertex3f(x, GOAL_HEIGHT, y);
601 glBegin(GL_TRIANGLES);
603 glColor3f(1.0f, 0.0f, 0.0f);
605 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
606 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
607 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
609 glVertex3f( 0.0f, GOAL_HEIGHT, 0.0f);
610 glVertex3f( 0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
611 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
622 if (glIsList(flag_list))
623 glDeleteLists(flag_list, 1);
630 glCallList(flag_list);
633 /*---------------------------------------------------------------------------*/
635 * A note about lighting and shadow: technically speaking, it's wrong.
636 * The light position and shadow projection behave as if the
637 * light-source rotates with the floor. However, the skybox does not
638 * rotate, thus the light should also remain stationary.
640 * The correct behavior would eliminate a significant 3D cue: the
641 * shadow of the ball indicates the ball's position relative to the
642 * floor even when the ball is in the air. This was the motivating
643 * idea behind the shadow in the first place, so correct shadow
644 * projection would only magnify the problem.
647 static GLuint shad_text;
651 shad_text = make_image_from_file(IMG_SHAD);
653 if (config_get_d(CONFIG_SHADOW) == 2)
655 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
656 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
662 if (glIsTexture(shad_text))
663 glDeleteTextures(1, &shad_text);
666 void shad_draw_set(const float *p, float r)
668 glMatrixMode(GL_TEXTURE);
672 glBindTexture(GL_TEXTURE_2D, shad_text);
675 glTranslatef(0.5f - k * p[0],
676 0.5f - k * p[2], 0.f);
677 glScalef(k, k, 1.0f);
679 glMatrixMode(GL_MODELVIEW);
682 void shad_draw_clr(void)
684 glMatrixMode(GL_TEXTURE);
688 glMatrixMode(GL_MODELVIEW);
691 /*---------------------------------------------------------------------------*/
693 void fade_draw(float k)
695 int w = config_get_d(CONFIG_WIDTH);
696 int h = config_get_d(CONFIG_HEIGHT);
701 glPushAttrib(GL_TEXTURE_BIT |
703 GL_COLOR_BUFFER_BIT |
704 GL_DEPTH_BUFFER_BIT);
706 glEnable(GL_COLOR_MATERIAL);
707 glDisable(GL_LIGHTING);
708 glDisable(GL_DEPTH_TEST);
709 glDisable(GL_TEXTURE_2D);
711 glColor4f(0.0f, 0.0f, 0.0f, k);
727 /*---------------------------------------------------------------------------*/