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