Sketched in possible alternatives for jump and goal particles.
[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 #include "solid_draw.h"
29
30 /*---------------------------------------------------------------------------*/
31
32 static struct s_full beam;
33 static struct s_full jump;
34 static struct s_full goal;
35 static struct s_full flag;
36 static struct s_full mark;
37 static struct s_full back;
38
39 static GLuint back_text;
40
41 /*---------------------------------------------------------------------------*/
42
43 void geom_init(void)
44 {
45     sol_load_full(&beam, "geom/beam/beam.sol", 0);
46     sol_load_full(&jump, "geom/jump/jump.sol", 0);
47     sol_load_full(&goal, "geom/goal/goal.sol", 0);
48     sol_load_full(&flag, "geom/flag/flag.sol", 0);
49     sol_load_full(&mark, "geom/mark/mark.sol", 0);
50     sol_load_full(&back, "geom/back/back.sol", 0);
51 }
52
53 void geom_free(void)
54 {
55     sol_free_full(&back);
56     sol_free_full(&mark);
57     sol_free_full(&flag);
58     sol_free_full(&goal);
59     sol_free_full(&jump);
60     sol_free_full(&beam);
61 }
62
63 /*---------------------------------------------------------------------------*/
64
65 void back_init(const char *name)
66 {
67     back_free();
68     back_text = make_image_from_file(name);
69
70     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
71 }
72
73 void back_free(void)
74 {
75     if (glIsTexture(back_text))
76         glDeleteTextures(1, &back_text);
77
78     back_text = 0;
79 }
80
81 /*---------------------------------------------------------------------------*/
82
83 static void jump_part_draw(GLfloat s, GLfloat a)
84 {
85     glMatrixMode(GL_TEXTURE);
86     glTranslatef(s, 0.0f, 0.0f);
87     glMatrixMode(GL_MODELVIEW);
88
89     glRotatef(a, 0.0f, 1.0f, 0.0f);
90     sol_draw(&jump.draw, 1, 1);
91     glScalef(0.9f, 0.9f, 0.9f);
92 }
93
94 static void goal_part_draw(GLfloat s, GLfloat a)
95 {
96     glMatrixMode(GL_TEXTURE);
97     glTranslatef(0.0f, -s, 0.0f);
98     glMatrixMode(GL_MODELVIEW);
99
100     glRotatef(a, 0.0f, 1.0f, 0.0f);
101     sol_draw(&goal.draw, 1, 1);
102     glScalef(0.75f, 1.1f, 0.9f);
103 }
104
105 /*---------------------------------------------------------------------------*/
106
107 void goal_draw(void)
108 {
109     const GLfloat t = SDL_GetTicks() * 0.001f;
110
111     glPushMatrix();
112     {
113         glScalef(1.0f, 3.0f, 1.0f);
114
115         glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
116         sol_draw(&beam.draw, 1, 1);
117
118         goal_part_draw(t * 0.1f, 20.0f);
119         goal_part_draw(t * 0.2f, 30.0f);
120         goal_part_draw(t * 0.3f, 70.0f);
121
122         glMatrixMode(GL_TEXTURE);
123         glLoadIdentity();
124         glMatrixMode(GL_MODELVIEW);
125
126         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
127     }
128     glPopMatrix();
129 }
130
131 void jump_draw(int highlight)
132 {
133     const GLfloat t = SDL_GetTicks() * 0.001f;
134
135     static GLfloat jump_colors[4][4] = {
136         { 0.75f, 0.5f, 1.0f, 0.5f },
137         { 0.75f, 0.5f, 1.0f, 0.8f },
138     };
139
140     glPushMatrix();
141     {
142         glColor4fv(jump_colors[highlight]);
143
144         glScalef(1.0f, 2.0f, 1.0f);
145         sol_draw(&beam.draw, 1, 1);
146
147         jump_part_draw(t * 0.1f, t * 360.0f);
148         jump_part_draw(t * 0.2f, t * 360.0f);
149         jump_part_draw(t * 0.3f, t * 360.0f);
150
151         glMatrixMode(GL_TEXTURE);
152         glLoadIdentity();
153         glMatrixMode(GL_MODELVIEW);
154
155         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
156     }
157     glPopMatrix();
158 }
159
160 void swch_draw(int b, int e)
161 {
162     static GLfloat swch_colors[4][4] = {
163         { 1.0f, 0.0f, 0.0f, 0.5f }, /* red out */
164         { 1.0f, 0.0f, 0.0f, 0.8f }, /* red in */
165         { 0.0f, 1.0f, 0.0f, 0.5f }, /* green out */
166         { 0.0f, 1.0f, 0.0f, 0.8f }, /* green in */
167     };
168
169     glPushMatrix();
170     {
171         glScalef(1.0f, 2.0f, 1.0f);
172
173         glColor4fv(swch_colors[b * 2 + e]);
174         sol_draw(&beam.draw, 1, 1);
175         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
176     }
177     glPopMatrix();
178 }
179
180 void flag_draw(void)
181 {
182     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
183     sol_draw(&flag.draw, 1, 1);
184 }
185
186 void mark_draw(void)
187 {
188     sol_draw(&mark.draw, 1, 1);
189 }
190
191 void back_draw(float t)
192 {
193     glPushMatrix();
194     {
195         GLfloat dx =  60.0f * fsinf(t / 10.0f);
196         GLfloat dz = 180.0f * fsinf(t / 12.0f);
197
198         glDisable(GL_LIGHTING);
199         glDepthMask(GL_FALSE);
200         {
201             glScalef(-BACK_DIST, BACK_DIST, -BACK_DIST);
202             glRotatef(dz, 0.0f, 0.0f, 1.0f);
203             glRotatef(dx, 1.0f, 0.0f, 0.0f);
204
205             glBindTexture(GL_TEXTURE_2D, back_text);
206             sol_draw(&back.draw, 1, 1);
207             glBindTexture(GL_TEXTURE_2D, 0);
208         }
209         glDepthMask(GL_TRUE);
210         glEnable(GL_LIGHTING);
211     }
212     glPopMatrix();
213 }
214
215 /*---------------------------------------------------------------------------*/
216
217 static GLuint clip_text;
218
219 static GLubyte clip_data[] = { 0xff, 0xff, 0x0, 0x0 };
220
221 void clip_init(void)
222 {
223     if (!glActiveTexture_)
224         return;
225
226     glActiveTexture_(GL_TEXTURE1);
227     {
228         glGenTextures(1, &clip_text);
229         glBindTexture(GL_TEXTURE_1D, clip_text);
230
231         glTexImage1D(GL_TEXTURE_1D, 0,
232                      GL_LUMINANCE_ALPHA, 2, 0,
233                      GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, clip_data);
234
235         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
236         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
237
238         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
239     }
240     glActiveTexture_(GL_TEXTURE0);
241 }
242
243 void clip_free(void)
244 {
245     if (glIsTexture(clip_text))
246         glDeleteTextures(1, &clip_text);
247 }
248
249 void clip_draw_set(void)
250 {
251     if (!glActiveTexture_)
252         return;
253
254     glActiveTexture_(GL_TEXTURE1);
255     {
256         glBindTexture(GL_TEXTURE_1D, clip_text);
257
258         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
259
260         glEnable(GL_TEXTURE_GEN_S);
261         glEnable(GL_TEXTURE_1D);
262     }
263     glActiveTexture_(GL_TEXTURE0);
264 }
265
266 void clip_draw_clr(void)
267 {
268     if (!glActiveTexture_)
269         return;
270
271     glActiveTexture_(GL_TEXTURE1);
272     {
273         glDisable(GL_TEXTURE_GEN_S);
274         glDisable(GL_TEXTURE_1D);
275     }
276     glActiveTexture_(GL_TEXTURE0);
277 }
278
279 /*---------------------------------------------------------------------------*/
280
281 /*
282  * A note about lighting and shadow: technically speaking, it's wrong.
283  * The  light  position  and   shadow  projection  behave  as  if  the
284  * light-source rotates with the  floor.  However, the skybox does not
285  * rotate, thus the light should also remain stationary.
286  *
287  * The  correct behavior  would eliminate  a significant  3D  cue: the
288  * shadow of  the ball indicates  the ball's position relative  to the
289  * floor even  when the ball is  in the air.  This  was the motivating
290  * idea  behind the  shadow  in  the first  place,  so correct  shadow
291  * projection would only magnify the problem.
292  */
293
294 static GLuint shad_text;
295
296 void shad_init(void)
297 {
298     shad_text = make_image_from_file(IMG_SHAD);
299
300     if (config_get_d(CONFIG_SHADOW) == 2)
301     {
302         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
303         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
304     }
305
306 #if 0
307     clip_init();
308 #endif
309 }
310
311 void shad_free(void)
312 {
313     if (glIsTexture(shad_text))
314         glDeleteTextures(1, &shad_text);
315 #if 0
316     clip_free();
317 #endif
318 }
319
320 void shad_draw_set(void)
321 {
322     glActiveTexture_(GL_TEXTURE1);
323     {
324         glEnable(GL_TEXTURE_2D);
325         glBindTexture(GL_TEXTURE_2D, shad_text);
326         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
327     }
328     glActiveTexture_(GL_TEXTURE0);
329
330
331 #if 0
332     glMatrixMode(GL_TEXTURE);
333     {
334         glLoadIdentity();
335     }
336     glMatrixMode(GL_MODELVIEW);
337
338     glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
339     glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
340
341     glEnable(GL_TEXTURE_GEN_S);
342     glEnable(GL_TEXTURE_GEN_T);
343
344     clip_draw_set();
345 #endif
346 }
347
348 void shad_draw_clr(void)
349 {
350     glActiveTexture_(GL_TEXTURE1);
351     {
352         glBindTexture(GL_TEXTURE_2D, 0);
353         glDisable(GL_TEXTURE_2D);
354     }
355     glActiveTexture_(GL_TEXTURE0);
356
357 #if 0
358     glDisable(GL_TEXTURE_GEN_S);
359     glDisable(GL_TEXTURE_GEN_T);
360
361     clip_draw_clr();
362 #endif
363 }
364
365 /*---------------------------------------------------------------------------*/