Import from neverball-1.3.1.tar.gz
[neverball-archive.git] / share / geom.c
blob5d4566a18d518d22198b55523bfc6d721574fc25
1 /*
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.
15 #include <SDL.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
20 #include "glext.h"
21 #include "geom.h"
22 #include "part.h"
23 #include "vec3.h"
24 #include "solid.h"
25 #include "image.h"
26 #include "config.h"
28 #define PI 3.1415926535897932
30 /*---------------------------------------------------------------------------*/
32 static GLUquadric *ball_quad;
33 static GLuint ball_list;
34 static GLuint ball_text;
36 void ball_init(int b)
38 char name[MAXSTR];
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);
62 glEndList();
66 void ball_free(void)
68 if (glIsList(ball_list))
69 glDeleteLists(ball_list, 1);
71 if (ball_quad)
72 gluDeleteQuadric(ball_quad);
74 if (glIsTexture(ball_text))
75 glDeleteTextures(1, &ball_text);
77 ball_quad = NULL;
78 ball_list = 0;
79 ball_text = 0;
82 void ball_draw(void)
84 glPushAttrib(GL_POLYGON_BIT |
85 GL_LIGHTING_BIT |
86 GL_DEPTH_BUFFER_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);
106 glCullFace(GL_BACK);
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);
125 glPopAttrib();
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);
149 glEndList();
153 void mark_draw(void)
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);
165 glPopAttrib();
166 glPopAttrib();
167 glPopAttrib();
170 void mark_free(void)
172 if (glIsList(mark_list))
173 glDeleteLists(mark_list, 1);
175 if (mark_quad)
176 gluDeleteQuadric(mark_quad);
178 mark_quad = NULL;
179 mark_list = 0;
182 /*---------------------------------------------------------------------------*/
184 static GLuint coin_text;
185 static GLuint coin_list;
187 static void coin_head(int n, float radius, float thick)
189 int i;
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);
204 glEnd();
207 static void coin_tail(int n, float radius, float thick)
209 int i;
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);
224 glEnd();
227 static void coin_edge(int n, float radius, float thick)
229 int i;
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);
243 glEnd();
246 void coin_color(float *c, int n)
248 if (n >= 1)
250 c[0] = 1.0f;
251 c[1] = 1.0f;
252 c[2] = 0.2f;
254 if (n >= 5)
256 c[0] = 1.0f;
257 c[1] = 0.2f;
258 c[2] = 0.2f;
260 if (n >= 10)
262 c[0] = 0.2f;
263 c[1] = 0.2f;
264 c[2] = 1.0f;
268 void coin_init(int b)
270 char name[MAXSTR];
271 int n = b ? 32 : 8;
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);
284 glEndList();
287 void coin_free(void)
289 if (glIsList(coin_list))
290 glDeleteLists(coin_list, 1);
292 if (glIsTexture(coin_text))
293 glDeleteTextures(1, &coin_text);
295 coin_list = 0;
296 coin_text = 0;
299 void coin_push(void)
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)
319 float c[3];
321 coin_color(c, n);
323 glColor3fv(c);
324 glCallList(coin_list);
327 void coin_pull(void)
329 glPopAttrib();
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 |
345 GL_LIGHTING_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);
367 glEnd();
369 glPopAttrib();
371 glEndList();
374 void goal_free(void)
376 if (glIsList(goal_list))
377 glDeleteLists(goal_list, 1);
379 goal_list = 0;
382 void goal_draw(void)
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 |
400 GL_LIGHTING_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);
422 glEnd();
424 glPopAttrib();
426 glEndList();
429 void jump_free(void)
431 if (glIsList(jump_list))
432 glDeleteLists(jump_list, 1);
434 jump_list = 0;
437 void jump_draw(void)
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 |
457 GL_LIGHTING_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);
479 glEnd();
481 glPopAttrib();
483 glEndList();
485 /* Create the OFF display list. */
487 glNewList(swch_list + 1, GL_COMPILE);
489 glPushAttrib(GL_TEXTURE_BIT |
490 GL_LIGHTING_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);
512 glEnd();
514 glPopAttrib();
516 glEndList();
519 void swch_free(void)
521 if (glIsList(swch_list))
522 glDeleteLists(swch_list, 2);
524 swch_list = 0;
527 void swch_draw(int b)
529 if (b)
530 glCallList(swch_list + 1);
531 else
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);
565 glEnd();
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);
579 glEnd();
581 glPopAttrib();
583 glEndList();
586 void flag_free(void)
588 if (glIsList(flag_list))
589 glDeleteLists(flag_list, 1);
591 flag_list = 0;
594 void flag_draw(void)
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;
615 void shad_init(void)
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);
626 void shad_free(void)
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);
639 float k = 0.5f / r;
641 glEnable(GL_TEXTURE_2D);
643 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
644 glBindTexture(GL_TEXTURE_2D, shad_text);
646 glLoadIdentity();
647 glTranslatef(0.5f - p[0] * k,
648 0.5f - p[2] * k, 0.f);
649 glScalef(k, k, 1.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);
675 if (k > 0.0f)
677 config_push_ortho();
678 glPushAttrib(GL_TEXTURE_BIT |
679 GL_LIGHTING_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);
690 glBegin(GL_QUADS);
692 glVertex2i(0, 0);
693 glVertex2i(w, 0);
694 glVertex2i(w, h);
695 glVertex2i(0, h);
697 glEnd();
699 glPopAttrib();
700 config_pop_matrix();
704 /*---------------------------------------------------------------------------*/