Fix accidental switch/teleporter behavior changes
[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 #include "video.h"
28
29 #define PI 3.1415926535897932
30
31 /*---------------------------------------------------------------------------*/
32
33 static GLuint mark_list;
34
35 void mark_init(void)
36 {
37     int i, slices = 32;
38
39     mark_list = glGenLists(1);
40
41     glNewList(mark_list, GL_COMPILE);
42     {
43         glBegin(GL_TRIANGLE_FAN);
44         {
45             glNormal3f(0.f, 1.f, 0.f);
46
47             for (i = 0; i < slices; i++)
48             {
49                 float x = fcosf(-2.f * PI * i / slices);
50                 float y = fsinf(-2.f * PI * i / slices);
51
52                 glVertex3f(x, 0, y);
53             }
54         }
55         glEnd();
56     }
57     glEndList();
58 }
59
60 void mark_draw(void)
61 {
62     glEnable(GL_COLOR_MATERIAL);
63     glDisable(GL_TEXTURE_2D);
64     glDepthMask(GL_FALSE);
65     {
66         glCallList(mark_list);
67     }
68     glDepthMask(GL_TRUE);
69     glEnable(GL_TEXTURE_2D);
70     glDisable(GL_COLOR_MATERIAL);
71 }
72
73 void mark_free(void)
74 {
75     if (glIsList(mark_list))
76         glDeleteLists(mark_list, 1);
77
78     mark_list = 0;
79 }
80
81 /*---------------------------------------------------------------------------*/
82
83 static GLuint goal_list;
84
85 void goal_init(void)
86 {
87     int i, n = 32;
88
89     goal_list = glGenLists(1);
90
91     glNewList(goal_list, GL_COMPILE);
92     {
93         glBegin(GL_QUAD_STRIP);
94         {
95             for (i = 0; i <= n; i++)
96             {
97                 float x = fcosf(2.f * PI * i / n);
98                 float y = fsinf(2.f * PI * i / n);
99
100                 glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
101                 glVertex3f(x, 0.0f, y);
102
103                 glColor4f(1.0f, 1.0f, 0.0f, 0.0f);
104                 glVertex3f(x, GOAL_HEIGHT, y);
105             }
106         }
107         glEnd();
108     }
109     glEndList();
110 }
111
112 void goal_free(void)
113 {
114     if (glIsList(goal_list))
115         glDeleteLists(goal_list, 1);
116
117     goal_list = 0;
118 }
119
120 void goal_draw(void)
121 {
122     glCallList(goal_list);
123 }
124
125 /*---------------------------------------------------------------------------*/
126
127 static GLuint jump_list;
128
129 void jump_init(void)
130 {
131     int k, i, n = 32;
132
133     jump_list = glGenLists(2);
134
135     for (k = 0; k < 2; k++)
136     {
137         glNewList(jump_list + k, GL_COMPILE);
138         {
139             glBegin(GL_QUAD_STRIP);
140             {
141                 for (i = 0; i <= n; i++)
142                 {
143                     float x = fcosf(2.f * PI * i / n);
144                     float y = fsinf(2.f * PI * i / n);
145
146                     glColor4f(0.75f, 0.5f, 1.0f, (k == 0 ? 0.5f : 0.8f));
147                     glVertex3f(x, 0.0f, y);
148
149                     glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
150                     glVertex3f(x, JUMP_HEIGHT, y);
151                 }
152             }
153             glEnd();
154         }
155         glEndList();
156     }
157 }
158
159 void jump_free(void)
160 {
161     glDeleteLists(jump_list, 2);
162     jump_list = 0;
163 }
164
165 void jump_draw(int highlight)
166 {
167     glCallList(jump_list + highlight);
168 }
169
170 /*---------------------------------------------------------------------------*/
171
172 static GLuint swch_list;
173
174 static GLfloat swch_colors[8][4] = {
175     { 1.0f, 0.0f, 0.0f, 0.5f }, /* red out */
176     { 1.0f, 0.0f, 0.0f, 0.0f },
177     { 1.0f, 0.0f, 0.0f, 0.8f }, /* red in */
178     { 1.0f, 0.0f, 0.0f, 0.0f },
179     { 0.0f, 1.0f, 0.0f, 0.5f }, /* green out */
180     { 0.0f, 1.0f, 0.0f, 0.0f },
181     { 0.0f, 1.0f, 0.0f, 0.8f }, /* green in */
182     { 0.0f, 1.0f, 0.0f, 0.0f }};
183
184 void swch_init(void)
185 {
186     int k, i, n = 32;
187
188     swch_list = glGenLists(4);
189
190     /* Create the display lists. */
191
192     for (k = 0; k < 4; k++)
193     {
194         glNewList(swch_list + k, GL_COMPILE);
195         {
196             glBegin(GL_QUAD_STRIP);
197             {
198                 for (i = 0; i <= n; i++)
199                 {
200                     float x = fcosf(2.f * PI * i / n);
201                     float y = fsinf(2.f * PI * i / n);
202
203                     glColor4fv(swch_colors[2 * k + 0]);
204                     glVertex3f(x, 0.0f, y);
205
206                     glColor4fv(swch_colors[2 * k + 1]);
207                     glVertex3f(x, SWCH_HEIGHT, y);
208                 }
209             }
210             glEnd();
211         }
212         glEndList();
213     }
214 }
215
216 void swch_free(void)
217 {
218     if (glIsList(swch_list))
219         glDeleteLists(swch_list, 2);
220
221     swch_list = 0;
222 }
223
224 void swch_draw(int b, int e)
225 {
226     glCallList(swch_list + b * 2 + e);
227 }
228
229 /*---------------------------------------------------------------------------*/
230
231 static GLuint flag_list;
232
233 void flag_init(void)
234 {
235     int i, n = 8;
236
237     flag_list = glGenLists(1);
238
239     glNewList(flag_list, GL_COMPILE);
240     {
241         glEnable(GL_COLOR_MATERIAL);
242         glDisable(GL_LIGHTING);
243         glDisable(GL_TEXTURE_2D);
244         {
245             glBegin(GL_TRIANGLES);
246             {
247                 glColor3f(1.0f, 0.0f, 0.0f);
248
249                 glVertex3f(              0.0f, GOAL_HEIGHT,        0.0f);
250                 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
251                 glVertex3f(              0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
252
253                 glVertex3f(              0.0f, GOAL_HEIGHT,        0.0f);
254                 glVertex3f(              0.0f, GOAL_HEIGHT * 0.8f, 0.0f);
255                 glVertex3f(GOAL_HEIGHT * 0.2f, GOAL_HEIGHT * 0.9f, 0.0f);
256             }
257             glEnd();
258
259             glBegin(GL_QUAD_STRIP);
260             {
261                 for (i = 0; i <= n; i++)
262                 {
263                     float x = fcosf(2.f * PI * i / n) * 0.01f;
264                     float y = fsinf(2.f * PI * i / n) * 0.01f;
265
266                     glColor3f(1.0f, 1.0f, 1.0f);
267                     glVertex3f(x, 0.0f,        y);
268                     glVertex3f(x, GOAL_HEIGHT, y);
269                 }
270             }
271             glEnd();
272         }
273         glEnable(GL_TEXTURE_2D);
274         glEnable(GL_LIGHTING);
275         glDisable(GL_COLOR_MATERIAL);
276     }
277     glEndList();
278 }
279
280 void flag_free(void)
281 {
282     if (glIsList(flag_list))
283         glDeleteLists(flag_list, 1);
284
285     flag_list = 0;
286 }
287
288 void flag_draw(void)
289 {
290     glCallList(flag_list);
291 }
292
293 /*---------------------------------------------------------------------------*/
294 /*
295  * A note about lighting and shadow: technically speaking, it's wrong.
296  * The  light  position  and   shadow  projection  behave  as  if  the
297  * light-source rotates with the  floor.  However, the skybox does not
298  * rotate, thus the light should also remain stationary.
299  *
300  * The  correct behavior  would eliminate  a significant  3D  cue: the
301  * shadow of  the ball indicates  the ball's position relative  to the
302  * floor even  when the ball is  in the air.  This  was the motivating
303  * idea  behind the  shadow  in  the first  place,  so correct  shadow
304  * projection would only magnify the problem.
305  */
306
307 static GLuint shad_text;
308
309 void shad_init(void)
310 {
311     shad_text = make_image_from_file(IMG_SHAD);
312
313     if (config_get_d(CONFIG_SHADOW) == 2)
314     {
315         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
316         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
317     }
318 }
319
320 void shad_free(void)
321 {
322     if (glIsTexture(shad_text))
323         glDeleteTextures(1, &shad_text);
324 }
325
326 void shad_draw_set(const float *p, float r)
327 {
328     glMatrixMode(GL_TEXTURE);
329     {
330         float k = 0.25f / r;
331
332         glBindTexture(GL_TEXTURE_2D, shad_text);
333
334         glLoadIdentity();
335         glTranslatef(0.5f - k * p[0],
336                      0.5f - k * p[2], 0.f);
337         glScalef(k, k, 1.0f);
338     }
339     glMatrixMode(GL_MODELVIEW);
340 }
341
342 void shad_draw_clr(void)
343 {
344     glMatrixMode(GL_TEXTURE);
345     {
346         glLoadIdentity();
347     }
348     glMatrixMode(GL_MODELVIEW);
349 }
350
351 /*---------------------------------------------------------------------------*/
352
353 void fade_draw(float k)
354 {
355     if (k > 0.0f)
356     {
357         int w = config_get_d(CONFIG_WIDTH);
358         int h = config_get_d(CONFIG_HEIGHT);
359
360         video_push_ortho();
361         {
362             glEnable(GL_COLOR_MATERIAL);
363             glDisable(GL_LIGHTING);
364             glDisable(GL_DEPTH_TEST);
365             glDisable(GL_TEXTURE_2D);
366
367             glColor4f(0.0f, 0.0f, 0.0f, k);
368
369             glBegin(GL_QUADS);
370             {
371                 glVertex2i(0, 0);
372                 glVertex2i(w, 0);
373                 glVertex2i(w, h);
374                 glVertex2i(0, h);
375             }
376             glEnd();
377
378             glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
379
380             glEnable(GL_TEXTURE_2D);
381             glEnable(GL_DEPTH_TEST);
382             glEnable(GL_LIGHTING);
383             glDisable(GL_COLOR_MATERIAL);
384         }
385         video_pop_matrix();
386     }
387 }
388
389 /*---------------------------------------------------------------------------*/