5d8ab3ed619d39148e8d1b2170f6462aa715af80
[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 "image.h"
25 #include "config.h"
26 #include "video.h"
27
28 #define PI 3.1415926535897932
29
30 /*---------------------------------------------------------------------------*/
31
32 static GLuint mark_list;
33
34 void mark_init(void)
35 {
36     int i, slices = 32;
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 GLuint goal_list;
83
84 void goal_init(void)
85 {
86     int i, n = 32;
87
88     goal_list = glGenLists(1);
89
90     glNewList(goal_list, GL_COMPILE);
91     {
92         glBegin(GL_QUAD_STRIP);
93         {
94             for (i = 0; i <= n; i++)
95             {
96                 float x = fcosf(2.f * PI * i / n);
97                 float y = fsinf(2.f * PI * i / n);
98
99                 glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
100                 glVertex3f(x, 0.0f, y);
101
102                 glColor4f(1.0f, 1.0f, 0.0f, 0.0f);
103                 glVertex3f(x, GOAL_HEIGHT, y);
104             }
105         }
106         glEnd();
107     }
108     glEndList();
109 }
110
111 void goal_free(void)
112 {
113     if (glIsList(goal_list))
114         glDeleteLists(goal_list, 1);
115
116     goal_list = 0;
117 }
118
119 void goal_draw(void)
120 {
121     glCallList(goal_list);
122 }
123
124 /*---------------------------------------------------------------------------*/
125
126 static GLuint jump_list;
127
128 void jump_init(void)
129 {
130     int k, i, n = 32;
131
132     jump_list = glGenLists(2);
133
134     for (k = 0; k < 2; k++)
135     {
136         glNewList(jump_list + k, GL_COMPILE);
137         {
138             glBegin(GL_QUAD_STRIP);
139             {
140                 for (i = 0; i <= n; i++)
141                 {
142                     float x = fcosf(2.f * PI * i / n);
143                     float y = fsinf(2.f * PI * i / n);
144
145                     glColor4f(0.75f, 0.5f, 1.0f, (k == 0 ? 0.5f : 0.8f));
146                     glVertex3f(x, 0.0f, y);
147
148                     glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
149                     glVertex3f(x, JUMP_HEIGHT, y);
150                 }
151             }
152             glEnd();
153         }
154         glEndList();
155     }
156 }
157
158 void jump_free(void)
159 {
160     glDeleteLists(jump_list, 2);
161     jump_list = 0;
162 }
163
164 void jump_draw(int highlight)
165 {
166     glCallList(jump_list + highlight);
167 }
168
169 /*---------------------------------------------------------------------------*/
170
171 static GLuint swch_list;
172
173 static GLfloat swch_colors[8][4] = {
174     { 1.0f, 0.0f, 0.0f, 0.5f }, /* red out */
175     { 1.0f, 0.0f, 0.0f, 0.0f },
176     { 1.0f, 0.0f, 0.0f, 0.8f }, /* red in */
177     { 1.0f, 0.0f, 0.0f, 0.0f },
178     { 0.0f, 1.0f, 0.0f, 0.5f }, /* green out */
179     { 0.0f, 1.0f, 0.0f, 0.0f },
180     { 0.0f, 1.0f, 0.0f, 0.8f }, /* green in */
181     { 0.0f, 1.0f, 0.0f, 0.0f }};
182
183 void swch_init(void)
184 {
185     int k, i, n = 32;
186
187     swch_list = glGenLists(4);
188
189     /* Create the display lists. */
190
191     for (k = 0; k < 4; k++)
192     {
193         glNewList(swch_list + k, GL_COMPILE);
194         {
195             glBegin(GL_QUAD_STRIP);
196             {
197                 for (i = 0; i <= n; i++)
198                 {
199                     float x = fcosf(2.f * PI * i / n);
200                     float y = fsinf(2.f * PI * i / n);
201
202                     glColor4fv(swch_colors[2 * k + 0]);
203                     glVertex3f(x, 0.0f, y);
204
205                     glColor4fv(swch_colors[2 * k + 1]);
206                     glVertex3f(x, SWCH_HEIGHT, y);
207                 }
208             }
209             glEnd();
210         }
211         glEndList();
212     }
213 }
214
215 void swch_free(void)
216 {
217     if (glIsList(swch_list))
218         glDeleteLists(swch_list, 4);
219
220     swch_list = 0;
221 }
222
223 void swch_draw(int b, int e)
224 {
225     glCallList(swch_list + b * 2 + e);
226 }
227
228 /*---------------------------------------------------------------------------*/
229
230 static GLuint flag_list;
231
232 void flag_init(void)
233 {
234     int i, n = 8;
235
236     flag_list = glGenLists(1);
237
238     glNewList(flag_list, GL_COMPILE);
239     {
240         glEnable(GL_COLOR_MATERIAL);
241         glDisable(GL_LIGHTING);
242         glDisable(GL_TEXTURE_2D);
243         {
244             glBegin(GL_TRIANGLES);
245             {
246                 glColor3f(1.0f, 0.0f, 0.0f);
247
248                 glVertex3f(              0.0f, GOAL_HEIGHT,        0.0f);
249                 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
250                 glVertex3f(              0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
251
252                 glVertex3f(              0.0f, GOAL_HEIGHT,        0.0f);
253                 glVertex3f(              0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
254                 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
255             }
256             glEnd();
257
258             glBegin(GL_QUAD_STRIP);
259             {
260                 for (i = 0; i <= n; i++)
261                 {
262                     float x = fcosf(2.f * PI * i / n) * 0.01f;
263                     float y = fsinf(2.f * PI * i / n) * 0.01f;
264
265                     glColor3f(1.0f, 1.0f, 1.0f);
266                     glVertex3f(x, 0.0f,        y);
267                     glVertex3f(x, GOAL_HEIGHT, y);
268                 }
269             }
270             glEnd();
271         }
272         glEnable(GL_TEXTURE_2D);
273         glEnable(GL_LIGHTING);
274         glDisable(GL_COLOR_MATERIAL);
275     }
276     glEndList();
277 }
278
279 void flag_free(void)
280 {
281     if (glIsList(flag_list))
282         glDeleteLists(flag_list, 1);
283
284     flag_list = 0;
285 }
286
287 void flag_draw(void)
288 {
289     glCallList(flag_list);
290 }
291
292 /*---------------------------------------------------------------------------*/
293
294 static GLuint clip_text;
295
296 static GLubyte clip_data[] = { 0xff, 0xff, 0x0, 0x0 };
297
298 void clip_init(void)
299 {
300     if (!glActiveTextureARB_)
301         return;
302
303     glActiveTextureARB_(GL_TEXTURE1_ARB);
304     {
305         glGenTextures(1, &clip_text);
306         glBindTexture(GL_TEXTURE_1D, clip_text);
307
308         glTexImage1D(GL_TEXTURE_1D, 0,
309                      GL_LUMINANCE_ALPHA, 2, 0,
310                      GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, clip_data);
311
312         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
313         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
314
315         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
316     }
317     glActiveTextureARB_(GL_TEXTURE0_ARB);
318 }
319
320 void clip_free(void)
321 {
322     if (glIsTexture(clip_text))
323         glDeleteTextures(1, &clip_text);
324 }
325
326 void clip_draw_set(void)
327 {
328     if (!glActiveTextureARB_)
329         return;
330
331     glActiveTextureARB_(GL_TEXTURE1_ARB);
332     {
333         glBindTexture(GL_TEXTURE_1D, clip_text);
334
335         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
336
337         glEnable(GL_TEXTURE_GEN_S);
338         glEnable(GL_TEXTURE_1D);
339     }
340     glActiveTextureARB_(GL_TEXTURE0_ARB);
341 }
342
343 void clip_draw_clr(void)
344 {
345     if (!glActiveTextureARB_)
346         return;
347
348     glActiveTextureARB_(GL_TEXTURE1_ARB);
349     {
350         glDisable(GL_TEXTURE_GEN_S);
351         glDisable(GL_TEXTURE_1D);
352     }
353     glActiveTextureARB_(GL_TEXTURE0_ARB);
354 }
355
356 /*---------------------------------------------------------------------------*/
357
358 /*
359  * A note about lighting and shadow: technically speaking, it's wrong.
360  * The  light  position  and   shadow  projection  behave  as  if  the
361  * light-source rotates with the  floor.  However, the skybox does not
362  * rotate, thus the light should also remain stationary.
363  *
364  * The  correct behavior  would eliminate  a significant  3D  cue: the
365  * shadow of  the ball indicates  the ball's position relative  to the
366  * floor even  when the ball is  in the air.  This  was the motivating
367  * idea  behind the  shadow  in  the first  place,  so correct  shadow
368  * projection would only magnify the problem.
369  */
370
371 static GLuint shad_text;
372
373 void shad_init(void)
374 {
375     shad_text = make_image_from_file(IMG_SHAD);
376
377     if (config_get_d(CONFIG_SHADOW) == 2)
378     {
379         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
380         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
381     }
382
383     clip_init();
384 }
385
386 void shad_free(void)
387 {
388     if (glIsTexture(shad_text))
389         glDeleteTextures(1, &shad_text);
390
391     clip_free();
392 }
393
394 void shad_draw_set(void)
395 {
396     glBindTexture(GL_TEXTURE_2D, shad_text);
397
398     glMatrixMode(GL_TEXTURE);
399     {
400         glLoadIdentity();
401     }
402     glMatrixMode(GL_MODELVIEW);
403
404     glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
405     glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
406
407     glEnable(GL_TEXTURE_GEN_S);
408     glEnable(GL_TEXTURE_GEN_T);
409
410     clip_draw_set();
411 }
412
413 void shad_draw_clr(void)
414 {
415     glDisable(GL_TEXTURE_GEN_S);
416     glDisable(GL_TEXTURE_GEN_T);
417
418     clip_draw_clr();
419 }
420
421 /*---------------------------------------------------------------------------*/
422
423 void fade_draw(float k)
424 {
425     if (k > 0.0f)
426     {
427         int w = config_get_d(CONFIG_WIDTH);
428         int h = config_get_d(CONFIG_HEIGHT);
429
430         video_push_ortho();
431         {
432             glEnable(GL_COLOR_MATERIAL);
433             glDisable(GL_LIGHTING);
434             glDisable(GL_DEPTH_TEST);
435             glDisable(GL_TEXTURE_2D);
436
437             glColor4f(0.0f, 0.0f, 0.0f, k);
438
439             glBegin(GL_QUADS);
440             {
441                 glVertex2i(0, 0);
442                 glVertex2i(w, 0);
443                 glVertex2i(w, h);
444                 glVertex2i(0, h);
445             }
446             glEnd();
447
448             glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
449
450             glEnable(GL_TEXTURE_2D);
451             glEnable(GL_DEPTH_TEST);
452             glEnable(GL_LIGHTING);
453             glDisable(GL_COLOR_MATERIAL);
454         }
455         video_pop_matrix();
456     }
457 }
458
459 /*---------------------------------------------------------------------------*/