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