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 GLUquadric
*ball_quad
;
33 static GLuint ball_list
;
34 static GLuint ball_text
;
40 config_get_s(CONFIG_BALL
, name
, MAXSTR
);
42 ball_text
= 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 if ((ball_quad
= gluNewQuadric()))
49 int slices
= b
? 32 : 16;
50 int stacks
= b
? 16 : 8;
52 gluQuadricOrientation(ball_quad
, GLU_OUTSIDE
);
53 gluQuadricNormals(ball_quad
, GLU_SMOOTH
);
54 gluQuadricTexture(ball_quad
, GL_TRUE
);
56 ball_list
= glGenLists(1);
58 glNewList(ball_list
, GL_COMPILE
);
60 gluSphere(ball_quad
, 1.f
, slices
, stacks
);
68 if (glIsList(ball_list
))
69 glDeleteLists(ball_list
, 1);
72 gluDeleteQuadric(ball_quad
);
74 if (glIsTexture(ball_text
))
75 glDeleteTextures(1, &ball_text
);
84 glPushAttrib(GL_POLYGON_BIT
|
88 static const float s
[4] = { 1.0f
, 1.0f
, 1.0f
, 1.0f
};
89 static const float e
[4] = { 0.2f
, 0.2f
, 0.2f
, 1.0f
};
90 static const float h
[1] = { 64.0f
};
92 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, s
);
93 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, e
);
94 glMaterialfv(GL_FRONT_AND_BACK
, GL_SHININESS
, h
);
96 glEnable(GL_COLOR_MATERIAL
);
98 glBindTexture(GL_TEXTURE_2D
, ball_text
);
100 /* Render the ball back to front in case it is translucent. */
102 glDepthMask(GL_FALSE
);
104 glCullFace(GL_FRONT
);
105 glCallList(ball_list
);
107 glCallList(ball_list
);
109 /* Render the ball into the depth buffer. */
111 glDepthMask(GL_TRUE
);
112 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
114 glCallList(ball_list
);
116 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
118 /* Ensure the ball is visible even when obscured by geometry. */
120 glDisable(GL_DEPTH_TEST
);
122 glColor4f(1.0f
, 1.0f
, 1.0f
, 0.1f
);
123 glCallList(ball_list
);
128 /*---------------------------------------------------------------------------*/
130 static GLUquadric
*mark_quad
;
131 static GLuint mark_list
;
133 void mark_init(int b
)
135 if ((mark_quad
= gluNewQuadric()))
137 int slices
= b
? 32 : 16;
139 gluQuadricOrientation(mark_quad
, GLU_OUTSIDE
);
140 gluQuadricTexture(mark_quad
, GL_TRUE
);
142 mark_list
= glGenLists(1);
144 glNewList(mark_list
, GL_COMPILE
);
146 glRotatef(-90.0f
, 1.0f
, 0.0f
, 0.0f
);
147 gluDisk(mark_quad
, 0.0, 1.0, slices
, 1);
155 glPushAttrib(GL_TEXTURE_BIT
);
156 glPushAttrib(GL_LIGHTING_BIT
);
157 glPushAttrib(GL_DEPTH_BUFFER_BIT
);
159 glEnable(GL_COLOR_MATERIAL
);
160 glDisable(GL_TEXTURE_2D
);
161 glDepthMask(GL_FALSE
);
163 glCallList(mark_list
);
172 if (glIsList(mark_list
))
173 glDeleteLists(mark_list
, 1);
176 gluDeleteQuadric(mark_quad
);
182 /*---------------------------------------------------------------------------*/
184 static GLuint coin_text
;
185 static GLuint coin_list
;
187 static void coin_head(int n
, float radius
, float thick
)
191 glBegin(GL_TRIANGLE_FAN
);
193 glNormal3f(0.f
, 0.f
, +1.f
);
195 for (i
= 0; i
< n
; i
++)
197 float x
= fcosf(+2.f
* PI
* i
/ n
);
198 float y
= fsinf(+2.f
* PI
* i
/ n
);
200 glTexCoord2f(-x
* 0.5f
+ 0.5f
, +y
* 0.5f
+ 0.5f
);
201 glVertex3f(radius
* x
, radius
* y
, +thick
);
207 static void coin_tail(int n
, float radius
, float thick
)
211 glBegin(GL_TRIANGLE_FAN
);
213 glNormal3f(0.f
, 0.f
, -1.f
);
215 for (i
= 0; i
< n
; i
++)
217 float x
= fcosf(-2.f
* PI
* i
/ n
);
218 float y
= fsinf(-2.f
* PI
* i
/ n
);
220 glTexCoord2f(+x
* 0.5f
+ 0.5f
, +y
* 0.5f
+ 0.5f
);
221 glVertex3f(radius
* x
, radius
* y
, -thick
);
227 static void coin_edge(int n
, float radius
, float thick
)
231 glBegin(GL_QUAD_STRIP
);
233 for (i
= 0; i
<= n
; i
++)
235 float x
= fcosf(2.f
* PI
* i
/ n
);
236 float y
= fsinf(2.f
* PI
* i
/ n
);
238 glNormal3f(x
, y
, 0.f
);
239 glVertex3f(radius
* x
, radius
* y
, +thick
);
240 glVertex3f(radius
* x
, radius
* y
, -thick
);
246 void coin_color(float *c
, int n
)
268 void coin_init(int b
)
273 config_get_s(CONFIG_COIN
, name
, MAXSTR
);
275 coin_text
= make_image_from_file(NULL
, NULL
, NULL
, NULL
, name
);
276 coin_list
= glGenLists(1);
278 glNewList(coin_list
, GL_COMPILE
);
280 coin_edge(n
, COIN_RADIUS
, COIN_THICK
);
281 coin_head(n
, COIN_RADIUS
, COIN_THICK
);
282 coin_tail(n
, COIN_RADIUS
, COIN_THICK
);
289 if (glIsList(coin_list
))
290 glDeleteLists(coin_list
, 1);
292 if (glIsTexture(coin_text
))
293 glDeleteTextures(1, &coin_text
);
301 static const float a
[4] = { 0.2f
, 0.2f
, 0.2f
, 1.0f
};
302 static const float s
[4] = { 1.0f
, 1.0f
, 1.0f
, 1.0f
};
303 static const float e
[4] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
};
304 static const float h
[1] = { 32.0f
};
306 glPushAttrib(GL_LIGHTING_BIT
);
308 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT
, a
);
309 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, s
);
310 glMaterialfv(GL_FRONT_AND_BACK
, GL_EMISSION
, e
);
311 glMaterialfv(GL_FRONT_AND_BACK
, GL_SHININESS
, h
);
313 glEnable(GL_COLOR_MATERIAL
);
314 glBindTexture(GL_TEXTURE_2D
, coin_text
);
317 void coin_draw(int n
, float r
)
324 glCallList(coin_list
);
332 /*---------------------------------------------------------------------------*/
334 static GLuint goal_list
;
336 void goal_init(int b
)
338 int i
, n
= b
? 32 : 8;
340 goal_list
= glGenLists(1);
342 glNewList(goal_list
, GL_COMPILE
);
344 glPushAttrib(GL_TEXTURE_BIT
|
346 GL_DEPTH_BUFFER_BIT
);
348 glEnable(GL_COLOR_MATERIAL
);
349 glDisable(GL_LIGHTING
);
350 glDisable(GL_TEXTURE_2D
);
351 glDepthMask(GL_FALSE
);
353 glBegin(GL_QUAD_STRIP
);
355 for (i
= 0; i
<= n
; i
++)
357 float x
= fcosf(2.f
* PI
* i
/ n
);
358 float y
= fsinf(2.f
* PI
* i
/ n
);
360 glColor4f(1.0f
, 1.0f
, 0.0f
, 0.5f
);
361 glVertex3f(x
, 0.0f
, y
);
363 glColor4f(1.0f
, 1.0f
, 0.0f
, 0.0f
);
364 glVertex3f(x
, GOAL_HEIGHT
, y
);
376 if (glIsList(goal_list
))
377 glDeleteLists(goal_list
, 1);
384 glCallList(goal_list
);
387 /*---------------------------------------------------------------------------*/
389 static GLuint jump_list
;
391 void jump_init(int b
)
393 int i
, n
= b
? 32 : 8;
395 jump_list
= glGenLists(1);
397 glNewList(jump_list
, GL_COMPILE
);
399 glPushAttrib(GL_TEXTURE_BIT
|
401 GL_DEPTH_BUFFER_BIT
);
403 glEnable(GL_COLOR_MATERIAL
);
404 glDisable(GL_LIGHTING
);
405 glDisable(GL_TEXTURE_2D
);
406 glDepthMask(GL_FALSE
);
408 glBegin(GL_QUAD_STRIP
);
410 for (i
= 0; i
<= n
; i
++)
412 float x
= fcosf(2.f
* PI
* i
/ n
);
413 float y
= fsinf(2.f
* PI
* i
/ n
);
415 glColor4f(1.0f
, 1.0f
, 1.0f
, 0.5f
);
416 glVertex3f(x
, 0.0f
, y
);
418 glColor4f(1.0f
, 1.0f
, 1.0f
, 0.0f
);
419 glVertex3f(x
, JUMP_HEIGHT
, y
);
431 if (glIsList(jump_list
))
432 glDeleteLists(jump_list
, 1);
439 glCallList(jump_list
);
442 /*---------------------------------------------------------------------------*/
444 static GLuint swch_list
;
446 void swch_init(int b
)
448 int i
, n
= b
? 32 : 8;
450 swch_list
= glGenLists(2);
452 /* Create the ON display list. */
454 glNewList(swch_list
, GL_COMPILE
);
456 glPushAttrib(GL_TEXTURE_BIT
|
458 GL_DEPTH_BUFFER_BIT
);
460 glEnable(GL_COLOR_MATERIAL
);
461 glDisable(GL_LIGHTING
);
462 glDisable(GL_TEXTURE_2D
);
463 glDepthMask(GL_FALSE
);
465 glBegin(GL_QUAD_STRIP
);
467 for (i
= 0; i
<= n
; i
++)
469 float x
= fcosf(2.f
* PI
* i
/ n
);
470 float y
= fsinf(2.f
* PI
* i
/ n
);
472 glColor4f(1.0f
, 0.0f
, 0.0f
, 0.5f
);
473 glVertex3f(x
, 0.0f
, y
);
475 glColor4f(1.0f
, 0.0f
, 0.0f
, 0.0f
);
476 glVertex3f(x
, SWCH_HEIGHT
, y
);
485 /* Create the OFF display list. */
487 glNewList(swch_list
+ 1, GL_COMPILE
);
489 glPushAttrib(GL_TEXTURE_BIT
|
491 GL_DEPTH_BUFFER_BIT
);
493 glEnable(GL_COLOR_MATERIAL
);
494 glDisable(GL_LIGHTING
);
495 glDisable(GL_TEXTURE_2D
);
496 glDepthMask(GL_FALSE
);
498 glBegin(GL_QUAD_STRIP
);
500 for (i
= 0; i
<= n
; i
++)
502 float x
= fcosf(2.f
* PI
* i
/ n
);
503 float y
= fsinf(2.f
* PI
* i
/ n
);
505 glColor4f(0.0f
, 1.0f
, 0.0f
, 0.5f
);
506 glVertex3f(x
, 0.0f
, y
);
508 glColor4f(0.0f
, 1.0f
, 0.0f
, 0.0f
);
509 glVertex3f(x
, SWCH_HEIGHT
, y
);
521 if (glIsList(swch_list
))
522 glDeleteLists(swch_list
, 2);
527 void swch_draw(int b
)
530 glCallList(swch_list
+ 1);
532 glCallList(swch_list
);
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 glPushAttrib(GL_TEXTURE_BIT
| GL_LIGHTING_BIT
);
549 glEnable(GL_COLOR_MATERIAL
);
550 glDisable(GL_LIGHTING
);
551 glDisable(GL_TEXTURE_2D
);
553 glBegin(GL_QUAD_STRIP
);
555 for (i
= 0; i
<= n
; i
++)
557 float x
= fcosf(2.f
* PI
* i
/ n
) * 0.01f
;
558 float y
= fsinf(2.f
* PI
* i
/ n
) * 0.01f
;
560 glColor3f(1.0f
, 1.0f
, 1.0f
);
561 glVertex3f(x
, 0.0f
, y
);
562 glVertex3f(x
, GOAL_HEIGHT
, y
);
567 glBegin(GL_TRIANGLES
);
569 glColor3f(1.0f
, 0.0f
, 0.0f
);
571 glVertex3f( 0.0f
, GOAL_HEIGHT
, 0.0f
);
572 glVertex3f(GOAL_HEIGHT
* 0.2f
, GOAL_HEIGHT
* 0.9f
, 0.0f
);
573 glVertex3f( 0.0f
, GOAL_HEIGHT
* 0.8f
, 0.0f
);
575 glVertex3f( 0.0f
, GOAL_HEIGHT
, 0.0f
);
576 glVertex3f( 0.0f
, GOAL_HEIGHT
* 0.8f
, 0.0f
);
577 glVertex3f(GOAL_HEIGHT
* 0.2f
, GOAL_HEIGHT
* 0.9f
, 0.0f
);
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(NULL
, NULL
, NULL
, NULL
, 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 if (config_get_d(CONFIG_SHADOW
))
636 glActiveTexture(GL_TEXTURE1
);
637 glMatrixMode(GL_TEXTURE
);
641 glEnable(GL_TEXTURE_2D
);
643 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
644 glBindTexture(GL_TEXTURE_2D
, shad_text
);
647 glTranslatef(0.5f
- p
[0] * k
,
648 0.5f
- p
[2] * k
, 0.f
);
651 glMatrixMode(GL_MODELVIEW
);
652 glActiveTexture(GL_TEXTURE0
);
656 void shad_draw_clr(void)
658 if (config_get_d(CONFIG_SHADOW
))
660 glActiveTexture(GL_TEXTURE1
);
662 glDisable(GL_TEXTURE_2D
);
664 glActiveTexture(GL_TEXTURE0
);
668 /*---------------------------------------------------------------------------*/
670 void fade_draw(float k
)
672 int w
= config_get_d(CONFIG_WIDTH
);
673 int h
= config_get_d(CONFIG_HEIGHT
);
678 glPushAttrib(GL_TEXTURE_BIT
|
680 GL_COLOR_BUFFER_BIT
|
681 GL_DEPTH_BUFFER_BIT
);
683 glEnable(GL_COLOR_MATERIAL
);
684 glDisable(GL_LIGHTING
);
685 glDisable(GL_DEPTH_TEST
);
686 glDisable(GL_TEXTURE_2D
);
688 glColor4f(0.0f
, 0.0f
, 0.0f
, k
);
704 /*---------------------------------------------------------------------------*/