s/TRANSLATORS/Translators/ in xgettext comments
[neverball] / share / part.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 "part.h"
22 #include "vec3.h"
23 #include "image.h"
24
25 /*---------------------------------------------------------------------------*/
26
27 struct part
28 {
29     float t;
30     float a;
31     float w;
32     float c[3];
33     float p[3];
34     float v[3];
35 };
36
37 static struct part part_coin[PART_MAX_COIN];
38 static struct part part_goal[PART_MAX_GOAL];
39 static GLuint      part_text;
40 static GLuint      part_list;
41
42 /*---------------------------------------------------------------------------*/
43
44 #define PI 3.1415927f
45
46 static float rnd(float l, float h)
47 {
48     return l + (h - l) * rand() / RAND_MAX;
49 }
50
51 /*---------------------------------------------------------------------------*/
52
53 void part_reset(float h)
54 {
55     int i;
56
57     for (i = 0; i < PART_MAX_GOAL; i++)
58     {
59         float t = rnd(+0.1f,      +1.0f);
60         float a = rnd(-1.0f * PI, +1.0f * PI);
61         float w = rnd(-2.0f * PI, +2.0f * PI);
62
63         part_goal[i].t = t;
64         part_goal[i].a = V_DEG(a);
65         part_goal[i].w = V_DEG(w);
66
67         part_goal[i].c[0] = 1.0f;
68         part_goal[i].c[1] = 1.0f;
69         part_goal[i].c[2] = 0.0f;
70
71         part_goal[i].p[0] = fsinf(a);
72         part_goal[i].p[1] = (1.f - t) * h;
73         part_goal[i].p[2] = fcosf(a);
74
75         part_goal[i].v[0] = 0.f;
76         part_goal[i].v[1] = 0.f;
77         part_goal[i].v[2] = 0.f;
78
79         part_coin[i].t    = 0.0f;
80     }
81 }
82
83 void part_init(float h)
84 {
85     memset(part_coin, 0, PART_MAX_COIN * sizeof (struct part));
86     memset(part_goal, 0, PART_MAX_GOAL * sizeof (struct part));
87
88     part_text = make_image_from_file(IMG_PART);
89     part_list = glGenLists(1);
90
91     glNewList(part_list, GL_COMPILE);
92     {
93         glBegin(GL_QUADS);
94         {
95             glTexCoord2f(0.f, 0.f);
96             glVertex2f(-PART_SIZE, -PART_SIZE);
97
98             glTexCoord2f(1.f, 0.f);
99             glVertex2f(+PART_SIZE, -PART_SIZE);
100
101             glTexCoord2f(1.f, 1.f);
102             glVertex2f(+PART_SIZE, +PART_SIZE);
103
104             glTexCoord2f(0.f, 1.f);
105             glVertex2f(-PART_SIZE, +PART_SIZE);
106         }
107         glEnd();
108     }
109     glEndList();
110
111     part_reset(h);
112 }
113
114 void part_free(void)
115 {
116     if (glIsList(part_list))
117         glDeleteLists(part_list, 1);
118
119     if (glIsTexture(part_text))
120         glDeleteTextures(1, &part_text);
121 }
122
123 /*---------------------------------------------------------------------------*/
124
125 void part_burst(const float *p, const float *c)
126 {
127     int i, n = 0;
128
129     for (i = 0; n < 10 && i < PART_MAX_COIN; i++)
130         if (part_coin[i].t <= 0.f)
131         {
132             float a = rnd(-1.0f * PI, +1.0f * PI);
133             float b = rnd(+0.3f * PI, +0.5f * PI);
134             float w = rnd(-4.0f * PI, +4.0f * PI);
135
136             part_coin[i].p[0] = p[0];
137             part_coin[i].p[1] = p[1];
138             part_coin[i].p[2] = p[2];
139
140             part_coin[i].v[0] = 4.f * fcosf(a) * fcosf(b);
141             part_coin[i].v[1] = 4.f *            fsinf(b);
142             part_coin[i].v[2] = 4.f * fsinf(a) * fcosf(b);
143
144             part_coin[i].c[0] = c[0];
145             part_coin[i].c[1] = c[1];
146             part_coin[i].c[2] = c[2];
147
148             part_coin[i].t = 1.f;
149             part_coin[i].a = 0.f;
150             part_coin[i].w = V_DEG(w);
151
152             n++;
153         }
154 }
155
156 /*---------------------------------------------------------------------------*/
157
158 static void part_fall(struct part *part, int n, const float *g, float dt)
159 {
160     int i;
161
162     for (i = 0; i < n; i++)
163         if (part[i].t > 0.f)
164         {
165             part[i].t -= dt;
166
167             part[i].v[0] += (g[0] * dt);
168             part[i].v[1] += (g[1] * dt);
169             part[i].v[2] += (g[2] * dt);
170
171             part[i].p[0] += (part[i].v[0] * dt);
172             part[i].p[1] += (part[i].v[1] * dt);
173             part[i].p[2] += (part[i].v[2] * dt);
174         }
175 }
176
177 static void part_spin(struct part *part, int n, const float *g, float dt)
178 {
179     int i;
180
181     for (i = 0; i < n; i++)
182         if (part[i].t > 0.f)
183         {
184             part[i].a += 30.f * dt;
185
186             part[i].p[0] = fsinf(V_RAD(part[i].a));
187             part[i].p[2] = fcosf(V_RAD(part[i].a));
188         }
189 }
190
191 void part_step(const float *g, float dt)
192 {
193     part_fall(part_coin, PART_MAX_COIN, g, dt);
194
195     if (g[1] > 0.f)
196         part_fall(part_goal, PART_MAX_GOAL, g, dt);
197     else
198         part_spin(part_goal, PART_MAX_GOAL, g, dt);
199 }
200
201 /*---------------------------------------------------------------------------*/
202
203 static void part_draw(const float *M,
204                       const float *p, float r, float rz)
205 {
206     glPushMatrix();
207     {
208         glTranslatef(r * p[0], p[1], r * p[2]);
209         glMultMatrixf(M);
210         glRotatef(rz, 0.f, 0.f, 1.f);
211
212         glCallList(part_list);
213     }
214     glPopMatrix();
215 }
216
217 void part_draw_coin(const float *M, float t)
218 {
219     int i;
220
221     glBindTexture(GL_TEXTURE_2D, part_text);
222
223     for (i = 0; i < PART_MAX_COIN; i++)
224         if (part_coin[i].t > 0.f)
225         {
226             glColor4f(part_coin[i].c[0],
227                       part_coin[i].c[1],
228                       part_coin[i].c[2],
229                       part_coin[i].t);
230
231             part_draw(M, part_coin[i].p, 1.0f, t * part_coin[i].w);
232         }
233 }
234
235 void part_draw_goal(const float *M, float radius, float a, float t)
236 {
237     int i;
238
239     glBindTexture(GL_TEXTURE_2D, part_text);
240
241     glColor4f(1.0f, 1.0f, 0.0f, a);
242
243     for (i = 0; i < PART_MAX_GOAL; i++)
244         if (part_goal[i].t > 0.0f)
245             part_draw(M, part_goal[i].p, radius - 0.05f, t * part_goal[i].w);
246 }
247
248 /*---------------------------------------------------------------------------*/