Move lines around
[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  * A note about lighting and shadow: technically speaking, it's wrong.
295  * The  light  position  and   shadow  projection  behave  as  if  the
296  * light-source rotates with the  floor.  However, the skybox does not
297  * rotate, thus the light should also remain stationary.
298  *
299  * The  correct behavior  would eliminate  a significant  3D  cue: the
300  * shadow of  the ball indicates  the ball's position relative  to the
301  * floor even  when the ball is  in the air.  This  was the motivating
302  * idea  behind the  shadow  in  the first  place,  so correct  shadow
303  * projection would only magnify the problem.
304  */
305
306 static GLuint shad_text;
307
308 void shad_init(void)
309 {
310     shad_text = make_image_from_file(IMG_SHAD);
311
312     if (config_get_d(CONFIG_SHADOW) == 2)
313     {
314         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
315         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
316     }
317 }
318
319 void shad_free(void)
320 {
321     if (glIsTexture(shad_text))
322         glDeleteTextures(1, &shad_text);
323 }
324
325 void shad_draw_set(const float *p, float r)
326 {
327     glBindTexture(GL_TEXTURE_2D, shad_text);
328
329     glMatrixMode(GL_TEXTURE);
330     {
331         float k = 0.25f / r;
332
333         glLoadIdentity();
334         glTranslatef(0.5f - k * p[0],
335                      0.5f - k * p[2], 0.f);
336         glScalef(k, k, 1.0f);
337     }
338     glMatrixMode(GL_MODELVIEW);
339
340     glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
341     glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
342
343     glEnable(GL_TEXTURE_GEN_S);
344     glEnable(GL_TEXTURE_GEN_T);
345 }
346
347 void shad_draw_clr(void)
348 {
349     glMatrixMode(GL_TEXTURE);
350     {
351         glLoadIdentity();
352     }
353     glMatrixMode(GL_MODELVIEW);
354
355     glDisable(GL_TEXTURE_GEN_S);
356     glDisable(GL_TEXTURE_GEN_T);
357 }
358
359 /*---------------------------------------------------------------------------*/
360
361 void fade_draw(float k)
362 {
363     if (k > 0.0f)
364     {
365         int w = config_get_d(CONFIG_WIDTH);
366         int h = config_get_d(CONFIG_HEIGHT);
367
368         video_push_ortho();
369         {
370             glEnable(GL_COLOR_MATERIAL);
371             glDisable(GL_LIGHTING);
372             glDisable(GL_DEPTH_TEST);
373             glDisable(GL_TEXTURE_2D);
374
375             glColor4f(0.0f, 0.0f, 0.0f, k);
376
377             glBegin(GL_QUADS);
378             {
379                 glVertex2i(0, 0);
380                 glVertex2i(w, 0);
381                 glVertex2i(w, h);
382                 glVertex2i(0, h);
383             }
384             glEnd();
385
386             glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
387
388             glEnable(GL_TEXTURE_2D);
389             glEnable(GL_DEPTH_TEST);
390             glEnable(GL_LIGHTING);
391             glDisable(GL_COLOR_MATERIAL);
392         }
393         video_pop_matrix();
394     }
395 }
396
397 /*---------------------------------------------------------------------------*/