Fix remaining errors when compiling against GL ES 1.1 headers
[neverball] / ball / game_draw.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 "vec3.h"
16 #include "glext.h"
17 #include "ball.h"
18 #include "item.h"
19 #include "part.h"
20 #include "geom.h"
21 #include "config.h"
22 #include "video.h"
23
24 #include "solid_draw.h"
25
26 #include "game_draw.h"
27
28 /*---------------------------------------------------------------------------*/
29
30 static const struct d_mtrl *game_draw_balls(const struct d_mtrl *mq,
31                                             const struct s_vary *vary,
32                                             const float *bill_M, float t)
33 {
34     float c[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
35
36     float ball_M[16];
37     float pend_M[16];
38
39     m_basis(ball_M, vary->uv[0].e[0], vary->uv[0].e[1], vary->uv[0].e[2]);
40     m_basis(pend_M, vary->uv[0].E[0], vary->uv[0].E[1], vary->uv[0].E[2]);
41
42     glPushMatrix();
43     {
44         glTranslatef(vary->uv[0].p[0],
45                      vary->uv[0].p[1] + BALL_FUDGE,
46                      vary->uv[0].p[2]);
47         glScalef(vary->uv[0].r,
48                  vary->uv[0].r,
49                  vary->uv[0].r);
50
51         glColor4f(c[0], c[1], c[2], c[3]);
52         mq = ball_draw(mq, ball_M, pend_M, bill_M, t);
53     }
54     glPopMatrix();
55
56     return mq;
57 }
58
59 static const struct d_mtrl *game_draw_items(const struct d_mtrl *mq,
60                                             const struct s_vary *vary,
61                                             const float *bill_M, float t)
62 {
63     int hi;
64
65     glEnable(GL_COLOR_MATERIAL);
66     {
67         for (hi = 0; hi < vary->hc; hi++)
68             if (vary->hv[hi].t == ITEM_COIN && vary->hv[hi].n > 0)
69             {
70                 glPushMatrix();
71                 {
72                     glTranslatef(vary->hv[hi].p[0],
73                                  vary->hv[hi].p[1],
74                                  vary->hv[hi].p[2]);
75                     mq = item_draw(mq, &vary->hv[hi], bill_M, t);
76                 }
77                 glPopMatrix();
78             }
79
80         for (hi = 0; hi < vary->hc; hi++)
81             if (vary->hv[hi].t == ITEM_SHRINK)
82             {
83                 glPushMatrix();
84                 {
85                     glTranslatef(vary->hv[hi].p[0],
86                                  vary->hv[hi].p[1],
87                                  vary->hv[hi].p[2]);
88                     mq = item_draw(mq, &vary->hv[hi], bill_M, t);
89                 }
90                 glPopMatrix();
91             }
92
93         for (hi = 0; hi < vary->hc; hi++)
94             if (vary->hv[hi].t == ITEM_GROW)
95             {
96                 glPushMatrix();
97                 {
98                     glTranslatef(vary->hv[hi].p[0],
99                                  vary->hv[hi].p[1],
100                                  vary->hv[hi].p[2]);
101                     mq = item_draw(mq, &vary->hv[hi], bill_M, t);
102                 }
103                 glPopMatrix();
104             }
105     }
106
107     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
108     glDisable(GL_COLOR_MATERIAL);
109
110     return mq;
111 }
112
113 static const struct d_mtrl *game_draw_goals(const struct d_mtrl *mq,
114                                             const struct game_draw *gd,
115                                             const float *M, float t)
116 {
117     const struct s_base *base = gd->vary.base;
118
119     if (gd->goal_e)
120     {
121         int zi;
122
123         /* Draw the goal column. */
124
125         for (zi = 0; zi < base->zc; zi++)
126         {
127             glPushMatrix();
128             {
129                 glTranslatef(base->zv[zi].p[0],
130                              base->zv[zi].p[1],
131                              base->zv[zi].p[2]);
132
133                 glScalef(base->zv[zi].r,
134                          gd->goal_k,
135                          base->zv[zi].r);
136
137                 mq = goal_draw(mq, t);
138             }
139             glPopMatrix();
140         }
141     }
142     return mq;
143 }
144
145 static const struct d_mtrl *game_draw_jumps(const struct d_mtrl *mq,
146                                             const struct game_draw *gd,
147                                             const float *M, float t)
148 {
149     const struct s_base *base = gd->vary.base;
150
151     int ji;
152
153     for (ji = 0; ji < base->jc; ji++)
154     {
155         glPushMatrix();
156         {
157             glTranslatef(base->jv[ji].p[0],
158                          base->jv[ji].p[1],
159                          base->jv[ji].p[2]);
160             glScalef(base->jv[ji].r,
161                      1.0f,
162                      base->jv[ji].r);
163
164             mq = jump_draw(mq, t, !gd->jump_e);
165         }
166         glPopMatrix();
167     }
168     return mq;
169 }
170
171 static const struct d_mtrl *game_draw_swchs(const struct d_mtrl *mq,
172                                             const struct s_vary *vary)
173 {
174     int xi;
175
176     for (xi = 0; xi < vary->xc; xi++)
177     {
178         struct v_swch *xp = vary->xv + xi;
179
180         if (xp->base->i)
181             continue;
182
183         glPushMatrix();
184         {
185             glTranslatef(xp->base->p[0],
186                          xp->base->p[1],
187                          xp->base->p[2]);
188             glScalef(xp->base->r,
189                      1.0f,
190                      xp->base->r);
191
192             mq = swch_draw(mq, xp->f, xp->e);
193         }
194         glPopMatrix();
195     }
196     return mq;
197 }
198
199 /*---------------------------------------------------------------------------*/
200
201 static void game_draw_tilt(const struct game_draw *gd, int d)
202 {
203     const struct game_tilt *tilt = &gd->tilt;
204     const float *ball_p = gd->vary.uv[0].p;
205
206     /* Rotate the environment about the position of the ball. */
207
208     glTranslatef(+ball_p[0], +ball_p[1] * d, +ball_p[2]);
209     glRotatef(-tilt->rz * d, tilt->z[0], tilt->z[1], tilt->z[2]);
210     glRotatef(-tilt->rx * d, tilt->x[0], tilt->x[1], tilt->x[2]);
211     glTranslatef(-ball_p[0], -ball_p[1] * d, -ball_p[2]);
212 }
213
214 static const struct d_mtrl *game_refl_all(const struct d_mtrl *mq,
215                                           const struct game_draw *gd)
216 {
217     glPushMatrix();
218     {
219         game_draw_tilt(gd, 1);
220
221         /* Draw the floor. */
222
223         mq = sol_refl(&gd->draw, mq);
224     }
225     glPopMatrix();
226
227     return mq;
228 }
229
230 /*---------------------------------------------------------------------------*/
231
232 static void game_draw_light(void)
233 {
234     const float light_p[2][4] = {
235         { -8.0f, +32.0f, -8.0f, 0.0f },
236         { +8.0f, +32.0f, +8.0f, 0.0f },
237     };
238     const float light_c[2][4] = {
239         { 1.0f, 0.8f, 0.8f, 1.0f },
240         { 0.8f, 1.0f, 0.8f, 1.0f },
241     };
242
243     /* Configure the lighting. */
244
245     glEnable(GL_LIGHT0);
246     glLightfv(GL_LIGHT0, GL_POSITION, light_p[0]);
247     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_c[0]);
248     glLightfv(GL_LIGHT0, GL_SPECULAR, light_c[0]);
249
250     glEnable(GL_LIGHT1);
251     glLightfv(GL_LIGHT1, GL_POSITION, light_p[1]);
252     glLightfv(GL_LIGHT1, GL_DIFFUSE,  light_c[1]);
253     glLightfv(GL_LIGHT1, GL_SPECULAR, light_c[1]);
254 }
255
256 static const struct d_mtrl *game_draw_back(const struct d_mtrl *mq,
257                                            const struct game_draw *gd,
258                                            int pose, int d, float t)
259 {
260     if (pose == POSE_BALL)
261         return mq;
262
263     glPushMatrix();
264     {
265         const struct game_view *view = &gd->view;
266
267         if (d < 0)
268         {
269             const struct game_tilt *tilt = &gd->tilt;
270
271             glRotatef(tilt->rz * 2, tilt->z[0], tilt->z[1], tilt->z[2]);
272             glRotatef(tilt->rx * 2, tilt->x[0], tilt->x[1], tilt->x[2]);
273         }
274
275         glTranslatef(view->p[0], view->p[1] * d, view->p[2]);
276
277         if (config_get_d(CONFIG_BACKGROUND))
278         {
279             mq = back_draw(mq, 0);
280             mq = sol_back(&gd->back.draw, mq, 0, FAR_DIST, t);
281         }
282         else back_draw(mq, 0);
283     }
284     glPopMatrix();
285
286     return mq;
287 }
288
289 static void game_clip_refl(int d)
290 {
291     /* Fudge to eliminate the floor from reflection. */
292
293     glClipPlane4f(GL_CLIP_PLANE0, 0, 1, 0, -0.00001);
294 }
295
296 static void game_clip_ball(const struct game_draw *gd, int d, const float *p)
297 {
298     GLfloat r, c[3], pz[4], nz[4];
299
300     /* Compute the plane giving the front of the ball, as seen from view.p. */
301
302     c[0] = p[0];
303     c[1] = p[1] * d;
304     c[2] = p[2];
305
306     pz[0] = gd->view.p[0] - c[0];
307     pz[1] = gd->view.p[1] - c[1];
308     pz[2] = gd->view.p[2] - c[2];
309
310     r = sqrt(pz[0] * pz[0] + pz[1] * pz[1] + pz[2] * pz[2]);
311
312     pz[0] /= r;
313     pz[1] /= r;
314     pz[2] /= r;
315     pz[3] = -(pz[0] * c[0] +
316               pz[1] * c[1] +
317               pz[2] * c[2]);
318
319     /* Find the plane giving the back of the ball, as seen from view.p. */
320
321     nz[0] = -pz[0];
322     nz[1] = -pz[1];
323     nz[2] = -pz[2];
324     nz[3] = -pz[3];
325
326     /* Reflect these planes as necessary, and store them in the GL state. */
327
328     pz[1] *= d;
329     nz[1] *= d;
330
331     glClipPlane4f(GL_CLIP_PLANE1, nz[0], nz[1], nz[2], nz[3]);
332     glClipPlane4f(GL_CLIP_PLANE2, pz[0], pz[1], pz[2], pz[3]);
333 }
334
335 static const struct d_mtrl *game_draw_fore(const struct d_mtrl *mq,
336                                            const struct game_draw *gd,
337                                            int pose, const float *M,
338                                            int d, float t)
339 {
340     const float *ball_p = gd->vary.uv[0].p;
341
342     const struct s_draw *draw = &gd->draw;
343
344     glPushMatrix();
345     {
346         /* Rotate the environment about the position of the ball. */
347
348         game_draw_tilt(gd, d);
349
350         /* Compute clipping planes for reflection and ball facing. */
351
352         game_clip_refl(d);
353         game_clip_ball(gd, d, ball_p);
354
355         if (d < 0)
356             glEnable(GL_CLIP_PLANE0);
357
358         switch (pose)
359         {
360         case POSE_LEVEL:
361             mq = sol_draw(draw, mq, 0, 1);
362             break;
363
364         case POSE_NONE:
365             /* Draw the floor. */
366
367             mq = sol_draw(draw, mq, 0, 1);
368
369             /* Draw the coins. */
370
371             mq = game_draw_items(mq, draw->vary, M, t);
372
373             /* Fall through. */
374
375         case POSE_BALL:
376
377             /* Draw the ball. */
378
379             mq = game_draw_balls(mq, draw->vary, M, t);
380
381             break;
382         }
383
384         /* Draw the billboards, entities, and  particles. */
385
386         glEnable(GL_COLOR_MATERIAL);
387         glDisable(GL_LIGHTING);
388         glDepthMask(GL_FALSE);
389         {
390             mq = sol_bill(draw, mq, M, t);
391
392             mq = game_draw_goals(mq, gd, M, t);
393             mq = game_draw_jumps(mq, gd, M, t);
394             mq = game_draw_swchs(mq, draw->vary);
395
396             mq = part_draw_coin(mq);
397         }
398         glDepthMask(GL_TRUE);
399         glEnable(GL_LIGHTING);
400         glDisable(GL_COLOR_MATERIAL);
401
402         if (d < 0)
403             glDisable(GL_CLIP_PLANE0);
404     }
405     glPopMatrix();
406
407     return mq;
408 }
409
410 /*---------------------------------------------------------------------------*/
411
412 void game_draw(const struct game_draw *gd, int pose, float t)
413 {
414     float fov = (float) config_get_d(CONFIG_VIEW_FOV);
415
416     if (gd->jump_b) fov *= 2.f * fabsf(gd->jump_dt - 0.5);
417
418     if (gd->state)
419     {
420         const struct game_view *view = &gd->view;
421         const struct d_mtrl *mq = sol_draw_enable();
422
423         video_push_persp(fov, 0.1f, FAR_DIST);
424         glPushMatrix();
425         {
426             float T[16], U[16], M[16], v[3];
427
428             /* Compute direct and reflected view bases. */
429
430             v[0] = +view->p[0];
431             v[1] = -view->p[1];
432             v[2] = +view->p[2];
433
434             m_view(T, view->c, view->p, view->e[1]);
435             m_view(U, view->c, v,       view->e[1]);
436
437             m_xps(M, T);
438
439             /* Apply the current view. */
440
441             v_sub(v, view->c, view->p);
442
443             glTranslatef(0.f, 0.f, -v_len(v));
444             glMultMatrixf(M);
445             glTranslatef(-view->c[0], -view->c[1], -view->c[2]);
446
447             /* Draw the background. */
448
449             mq = game_draw_back(mq, gd, pose, +1, t);
450
451             /* Draw the reflection. */
452
453             if (gd->draw.reflective && config_get_d(CONFIG_REFLECTION))
454             {
455                 glEnable(GL_STENCIL_TEST);
456                 {
457                     /* Draw the mirrors only into the stencil buffer. */
458
459                     glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
460                     glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
461                     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
462                     glDepthMask(GL_FALSE);
463
464                     mq = game_refl_all(mq, gd);
465
466                     glDepthMask(GL_TRUE);
467                     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
468                     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
469                     glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
470
471                     /* Draw the scene reflected into color and depth buffers. */
472                     
473                     glFrontFace(GL_CW);
474                     glPushMatrix();
475                     {
476                         glScalef(+1.0f, -1.0f, +1.0f);
477
478                         game_draw_light();
479
480                         mq = game_draw_back(mq, gd, pose,    -1, t);
481                         mq = game_draw_fore(mq, gd, pose, U, -1, t);
482                     }
483                     glPopMatrix();
484                     glFrontFace(GL_CCW);
485
486                     glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFF);
487                 }
488                 glDisable(GL_STENCIL_TEST);
489             }
490
491             /* Ready the lights for foreground rendering. */
492
493             game_draw_light();
494
495             /* When reflection is disabled, mirrors must be rendered opaque  */
496             /* to prevent the background from showing.                       */
497
498             if (gd->draw.reflective && !config_get_d(CONFIG_REFLECTION))
499             {
500                 glEnable(GL_COLOR_MATERIAL);
501                 {
502                     glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
503                     mq = game_refl_all(mq, gd);
504                     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
505                 }
506                 glDisable(GL_COLOR_MATERIAL);
507             }
508
509             /* Draw the mirrors and the rest of the foreground. */
510
511             mq = game_refl_all (mq, gd);
512             mq = game_draw_fore(mq, gd, pose, T, +1, t);
513         }
514         glPopMatrix();
515         video_pop_matrix();
516
517         /* Draw the fade overlay. */
518
519         sol_fade(&gd->draw, gd->fade_k);
520         sol_draw_disable(mq);
521     }
522 }
523
524 /*---------------------------------------------------------------------------*/
525
526 #define CURR 0
527 #define PREV 1
528
529 void game_lerp_init(struct game_lerp *gl, struct game_draw *gd)
530 {
531     gl->alpha = 1.0f;
532
533     sol_load_lerp(&gl->lerp, &gd->vary);
534
535     gl->tilt[PREV] = gl->tilt[CURR] = gd->tilt;
536     gl->view[PREV] = gl->view[CURR] = gd->view;
537
538     gl->goal_k[PREV] = gl->goal_k[CURR] = gd->goal_k;
539     gl->jump_dt[PREV] = gl->jump_dt[CURR] = gd->jump_dt;
540 }
541
542 void game_lerp_free(struct game_lerp *gl)
543 {
544     sol_free_lerp(&gl->lerp);
545 }
546
547 void game_lerp_copy(struct game_lerp *gl)
548 {
549     sol_lerp_copy(&gl->lerp);
550
551     gl->tilt[PREV] = gl->tilt[CURR];
552     gl->view[PREV] = gl->view[CURR];
553
554     gl->goal_k[PREV] = gl->goal_k[CURR];
555     gl->jump_dt[PREV] = gl->jump_dt[CURR];
556 }
557
558 void game_lerp_apply(struct game_lerp *gl, struct game_draw *gd)
559 {
560     float a = gl->alpha;
561
562     /* Solid. */
563
564     sol_lerp_apply(&gl->lerp, a);
565
566     /* Particles. */
567
568     part_lerp_apply(a);
569
570     /* Tilt. */
571
572     v_lerp(gd->tilt.x, gl->tilt[PREV].x, gl->tilt[CURR].x, a);
573     v_lerp(gd->tilt.z, gl->tilt[PREV].z, gl->tilt[CURR].z, a);
574
575     gd->tilt.rx = (gl->tilt[PREV].rx * (1.0f - a) + gl->tilt[CURR].rx * a);
576     gd->tilt.rz = (gl->tilt[PREV].rz * (1.0f - a) + gl->tilt[CURR].rz * a);
577
578     /* View. */
579
580     v_lerp(gd->view.c, gl->view[PREV].c, gl->view[CURR].c, a);
581     v_lerp(gd->view.p, gl->view[PREV].p, gl->view[CURR].p, a);
582     e_lerp(gd->view.e, gl->view[PREV].e, gl->view[CURR].e, a);
583
584     /* Effects. */
585
586     gd->goal_k = (gl->goal_k[PREV] * (1.0f - a) + gl->goal_k[CURR] * a);
587     gd->jump_dt = (gl->jump_dt[PREV] * (1.0f - a) + gl->jump_dt[CURR] * a);
588 }
589
590 /*---------------------------------------------------------------------------*/