s/TRANSLATORS/Translators/ in xgettext comments
[neverball] / share / geom.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
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.
8  *
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.
13  */
14
15 #include <SDL.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19
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"
27
28 #define PI 3.1415926535897932
29
30 /*---------------------------------------------------------------------------*/
31
32 static GLuint mark_list;
33
34 void mark_init(int b)
35 {
36     int i, slices = b ? 32 : 16;
37
38     mark_list = glGenLists(1);
39
40     glNewList(mark_list, GL_COMPILE);
41     {
42         glBegin(GL_TRIANGLE_FAN);
43         {
44             glNormal3f(0.f, 1.f, 0.f);
45
46             for (i = 0; i < slices; i++)
47             {
48                 float x = fcosf(-2.f * PI * i / slices);
49                 float y = fsinf(-2.f * PI * i / slices);
50
51                 glVertex3f(x, 0, y);
52             }
53         }
54         glEnd();
55     }
56     glEndList();
57 }
58
59 void mark_draw(void)
60 {
61     glEnable(GL_COLOR_MATERIAL);
62     glDisable(GL_TEXTURE_2D);
63     glDepthMask(GL_FALSE);
64     {
65         glCallList(mark_list);
66     }
67     glDepthMask(GL_TRUE);
68     glEnable(GL_TEXTURE_2D);
69     glDisable(GL_COLOR_MATERIAL);
70 }
71
72 void mark_free(void)
73 {
74     if (glIsList(mark_list))
75         glDeleteLists(mark_list, 1);
76
77     mark_list = 0;
78 }
79
80 /*---------------------------------------------------------------------------*/
81
82 static void coin_head(int n, float radius, float thick)
83 {
84     int i;
85
86     glBegin(GL_TRIANGLE_FAN);
87     {
88         glNormal3f(0.f, 0.f, +1.f);
89
90         for (i = 0; i < n; i++)
91         {
92             float x = fcosf(+2.f * PI * i / n);
93             float y = fsinf(+2.f * PI * i / n);
94
95             glTexCoord2f(-x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
96             glVertex3f(radius * x, radius * y, +thick);
97         }
98     }
99     glEnd();
100 }
101
102 static void coin_tail(int n, float radius, float thick)
103 {
104     int i;
105
106     glBegin(GL_TRIANGLE_FAN);
107     {
108         glNormal3f(0.f, 0.f, -1.f);
109
110         for (i = 0; i < n; i++)
111         {
112             float x = fcosf(-2.f * PI * i / n);
113             float y = fsinf(-2.f * PI * i / n);
114
115             glTexCoord2f(+x * 0.5f + 0.5f, +y * 0.5f + 0.5f);
116             glVertex3f(radius * x, radius * y, -thick);
117         }
118     }
119     glEnd();
120 }
121
122 static void coin_edge(int n, float radius, float thick)
123 {
124     int i;
125
126     glBegin(GL_QUAD_STRIP);
127     {
128         for (i = 0; i <= n; i++)
129         {
130             float x = fcosf(2.f * PI * i / n);
131             float y = fsinf(2.f * PI * i / n);
132
133             glNormal3f(x, y, 0.0f);
134             glVertex3f(radius * x, radius * y, +thick);
135             glVertex3f(radius * x, radius * y, -thick);
136         }
137     }
138     glEnd();
139 }
140
141 /*---------------------------------------------------------------------------*/
142
143 static GLuint item_coin_text;
144 static GLuint item_grow_text;
145 static GLuint item_shrink_text;
146 static GLuint item_list;
147
148 void item_color(const struct s_item *hp, float *c)
149 {
150     switch (hp->t)
151     {
152
153     case ITEM_COIN:
154
155         if (hp->n >= 1)
156         {
157             c[0] = 1.0f;
158             c[1] = 1.0f;
159             c[2] = 0.2f;
160         }
161         if (hp->n >= 5)
162         {
163             c[0] = 1.0f;
164             c[1] = 0.2f;
165             c[2] = 0.2f;
166         }
167         if (hp->n >= 10)
168         {
169             c[0] = 0.2f;
170             c[1] = 0.2f;
171             c[2] = 1.0f;
172         }
173         break;
174
175     case ITEM_GROW:
176     case ITEM_SHRINK:
177
178     default:
179
180         c[0] = 1.0f;
181         c[1] = 1.0f;
182         c[2] = 1.0f;
183
184         break;
185     }
186 }
187
188 void item_init(int b)
189 {
190     int n = b ? 32 : 8;
191
192     item_coin_text   = make_image_from_file(IMG_ITEM_COIN);
193     item_grow_text   = make_image_from_file(IMG_ITEM_GROW);
194     item_shrink_text = make_image_from_file(IMG_ITEM_SHRINK);
195
196     item_list = glGenLists(1);
197
198     glNewList(item_list, GL_COMPILE);
199     {
200         glDisable(GL_TEXTURE_2D);
201         coin_edge(n, COIN_RADIUS, COIN_THICK);
202         glEnable (GL_TEXTURE_2D);
203         coin_head(n, COIN_RADIUS, COIN_THICK);
204         coin_tail(n, COIN_RADIUS, COIN_THICK);
205     }
206     glEndList();
207 }
208
209 void item_free(void)
210 {
211     if (glIsList(item_list))
212         glDeleteLists(item_list, 1);
213
214     if (glIsTexture(item_coin_text))
215         glDeleteTextures(1, &item_coin_text);
216
217     if (glIsTexture(item_grow_text))
218         glDeleteTextures(1, &item_grow_text);
219
220     if (glIsTexture(item_shrink_text))
221         glDeleteTextures(1, &item_shrink_text);
222
223     item_list = 0;
224     item_coin_text = 0;
225     item_grow_text = 0;
226     item_shrink_text = 0;
227 }
228
229 void item_push(int type)
230 {
231     static const float  a[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
232     static const float  s[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
233     static const float  e[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
234     static const float  h[1] = { 10.0f };
235
236     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   a);
237     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  s);
238     glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  e);
239     glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, h);
240
241     glEnable(GL_COLOR_MATERIAL);
242
243     switch (type)
244     {
245     case ITEM_COIN:
246         glBindTexture(GL_TEXTURE_2D, item_coin_text);
247         break;
248
249     case ITEM_GROW:
250         glBindTexture(GL_TEXTURE_2D, item_grow_text);
251         break;
252
253     case ITEM_SHRINK:
254         glBindTexture(GL_TEXTURE_2D, item_shrink_text);
255         break;
256     }
257 }
258
259 void item_draw(const struct s_item *hp, float r)
260 {
261     float c[3];
262
263     item_color(hp, c);
264
265     glColor3fv(c);
266     glCallList(item_list);
267 }
268
269 void item_pull(void)
270 {
271     glColor3f(1.0f, 1.0f, 1.0f);
272     glDisable(GL_COLOR_MATERIAL);
273 }
274
275 /*---------------------------------------------------------------------------*/
276
277 static GLuint goal_list;
278
279 void goal_init(int b)
280 {
281     int i, n = b ? 32 : 8;
282
283     goal_list = glGenLists(1);
284
285     glNewList(goal_list, GL_COMPILE);
286     {
287         glBegin(GL_QUAD_STRIP);
288         {
289             for (i = 0; i <= n; i++)
290             {
291                 float x = fcosf(2.f * PI * i / n);
292                 float y = fsinf(2.f * PI * i / n);
293
294                 glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
295                 glVertex3f(x, 0.0f, y);
296
297                 glColor4f(1.0f, 1.0f, 0.0f, 0.0f);
298                 glVertex3f(x, GOAL_HEIGHT, y);
299             }
300         }
301         glEnd();
302     }
303     glEndList();
304 }
305
306 void goal_free(void)
307 {
308     if (glIsList(goal_list))
309         glDeleteLists(goal_list, 1);
310
311     goal_list = 0;
312 }
313
314 void goal_draw(void)
315 {
316     glCallList(goal_list);
317 }
318
319 /*---------------------------------------------------------------------------*/
320
321 static GLuint jump_list;
322
323 void jump_init(int b)
324 {
325     int k, i, n = b ? 32 : 8;
326
327     jump_list = glGenLists(2);
328
329     for (k = 0; k < 2; k++)
330     {
331         glNewList(jump_list + k, GL_COMPILE);
332         {
333             glBegin(GL_QUAD_STRIP);
334             {
335                 for (i = 0; i <= n; i++)
336                 {
337                     float x = fcosf(2.f * PI * i / n);
338                     float y = fsinf(2.f * PI * i / n);
339
340                     glColor4f(1.0f, 1.0f, 1.0f, (k == 0 ? 0.5f : 0.8f));
341                     glVertex3f(x, 0.0f, y);
342
343                     glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
344                     glVertex3f(x, JUMP_HEIGHT, y);
345                 }
346             }
347             glEnd();
348         }
349         glEndList();
350     }
351 }
352
353 void jump_free(void)
354 {
355     glDeleteLists(jump_list, 2);
356     jump_list = 0;
357 }
358
359 void jump_draw(int highlight)
360 {
361     glCallList(jump_list + highlight);
362 }
363
364 /*---------------------------------------------------------------------------*/
365
366 static GLuint swch_list;
367
368 static GLfloat swch_colors[8][4] = {
369     { 1.0f, 0.0f, 0.0f, 0.5f }, /* red out */
370     { 1.0f, 0.0f, 0.0f, 0.0f },
371     { 1.0f, 0.0f, 0.0f, 0.8f }, /* red in */
372     { 1.0f, 0.0f, 0.0f, 0.0f },
373     { 0.0f, 1.0f, 0.0f, 0.5f }, /* green out */
374     { 0.0f, 1.0f, 0.0f, 0.0f },
375     { 0.0f, 1.0f, 0.0f, 0.8f }, /* green in */
376     { 0.0f, 1.0f, 0.0f, 0.0f }};
377
378 void swch_init(int b)
379 {
380     int k, i, n = b ? 32 : 8;
381
382     swch_list = glGenLists(4);
383
384     /* Create the display lists. */
385
386     for (k = 0; k < 4; k++)
387     {
388         glNewList(swch_list + k, GL_COMPILE);
389         {
390             glBegin(GL_QUAD_STRIP);
391             {
392                 for (i = 0; i <= n; i++)
393                 {
394                     float x = fcosf(2.f * PI * i / n);
395                     float y = fsinf(2.f * PI * i / n);
396
397                     glColor4fv(swch_colors[2 * k + 0]);
398                     glVertex3f(x, 0.0f, y);
399
400                     glColor4fv(swch_colors[2 * k + 1]);
401                     glVertex3f(x, SWCH_HEIGHT, y);
402                 }
403             }
404             glEnd();
405         }
406         glEndList();
407     }
408 }
409
410 void swch_free(void)
411 {
412     if (glIsList(swch_list))
413         glDeleteLists(swch_list, 2);
414
415     swch_list = 0;
416 }
417
418 void swch_draw(int b, int e)
419 {
420     glCallList(swch_list + b * 2 + e);
421 }
422
423 /*---------------------------------------------------------------------------*/
424
425 static GLuint flag_list;
426
427 void flag_init(int b)
428 {
429     int i, n = b ? 8 : 4;
430
431     flag_list = glGenLists(1);
432
433     glNewList(flag_list, GL_COMPILE);
434     {
435         glEnable(GL_COLOR_MATERIAL);
436         glDisable(GL_LIGHTING);
437         glDisable(GL_TEXTURE_2D);
438         {
439             glBegin(GL_TRIANGLES);
440             {
441                 glColor3f(1.0f, 0.0f, 0.0f);
442
443                 glVertex3f(              0.0f, GOAL_HEIGHT,        0.0f);
444                 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
445                 glVertex3f(              0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
446
447                 glVertex3f(              0.0f, GOAL_HEIGHT,        0.0f);
448                 glVertex3f(              0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
449                 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
450             }
451             glEnd();
452
453             glBegin(GL_QUAD_STRIP);
454             {
455                 for (i = 0; i <= n; i++)
456                 {
457                     float x = fcosf(2.f * PI * i / n) * 0.01f;
458                     float y = fsinf(2.f * PI * i / n) * 0.01f;
459
460                     glColor3f(1.0f, 1.0f, 1.0f);
461                     glVertex3f(x, 0.0f,        y);
462                     glVertex3f(x, GOAL_HEIGHT, y);
463                 }
464             }
465             glEnd();
466         }
467         glEnable(GL_TEXTURE_2D);
468         glEnable(GL_LIGHTING);
469         glDisable(GL_COLOR_MATERIAL);
470     }
471     glEndList();
472 }
473
474 void flag_free(void)
475 {
476     if (glIsList(flag_list))
477         glDeleteLists(flag_list, 1);
478
479     flag_list = 0;
480 }
481
482 void flag_draw(void)
483 {
484     glCallList(flag_list);
485 }
486
487 /*---------------------------------------------------------------------------*/
488 /*
489  * A note about lighting and shadow: technically speaking, it's wrong.
490  * The  light  position  and   shadow  projection  behave  as  if  the
491  * light-source rotates with the  floor.  However, the skybox does not
492  * rotate, thus the light should also remain stationary.
493  *
494  * The  correct behavior  would eliminate  a significant  3D  cue: the
495  * shadow of  the ball indicates  the ball's position relative  to the
496  * floor even  when the ball is  in the air.  This  was the motivating
497  * idea  behind the  shadow  in  the first  place,  so correct  shadow
498  * projection would only magnify the problem.
499  */
500
501 static GLuint shad_text;
502
503 void shad_init(void)
504 {
505     shad_text = make_image_from_file(IMG_SHAD);
506
507     if (config_get_d(CONFIG_SHADOW) == 2)
508     {
509         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
510         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
511     }
512 }
513
514 void shad_free(void)
515 {
516     if (glIsTexture(shad_text))
517         glDeleteTextures(1, &shad_text);
518 }
519
520 void shad_draw_set(const float *p, float r)
521 {
522     glMatrixMode(GL_TEXTURE);
523     {
524         float k = 0.25f / r;
525
526         glBindTexture(GL_TEXTURE_2D, shad_text);
527
528         glLoadIdentity();
529         glTranslatef(0.5f - k * p[0],
530                      0.5f - k * p[2], 0.f);
531         glScalef(k, k, 1.0f);
532     }
533     glMatrixMode(GL_MODELVIEW);
534 }
535
536 void shad_draw_clr(void)
537 {
538     glMatrixMode(GL_TEXTURE);
539     {
540         glLoadIdentity();
541     }
542     glMatrixMode(GL_MODELVIEW);
543 }
544
545 /*---------------------------------------------------------------------------*/
546
547 void fade_draw(float k)
548 {
549     if (k > 0.0f)
550     {
551         int w = config_get_d(CONFIG_WIDTH);
552         int h = config_get_d(CONFIG_HEIGHT);
553
554         config_push_ortho();
555         {
556             glEnable(GL_COLOR_MATERIAL);
557             glDisable(GL_LIGHTING);
558             glDisable(GL_DEPTH_TEST);
559             glDisable(GL_TEXTURE_2D);
560
561             glColor4f(0.0f, 0.0f, 0.0f, k);
562
563             glBegin(GL_QUADS);
564             {
565                 glVertex2i(0, 0);
566                 glVertex2i(w, 0);
567                 glVertex2i(w, h);
568                 glVertex2i(0, h);
569             }
570             glEnd();
571
572             glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
573
574             glEnable(GL_TEXTURE_2D);
575             glEnable(GL_DEPTH_TEST);
576             glEnable(GL_LIGHTING);
577             glDisable(GL_COLOR_MATERIAL);
578         }
579         config_pop_matrix();
580     }
581 }
582
583 /*---------------------------------------------------------------------------*/