2 * Copyright (C) 2003 Robert Kooima
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.
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.
25 /*---------------------------------------------------------------------------*/
37 static struct part part_coin[PART_MAX_COIN];
38 static struct part part_goal[PART_MAX_GOAL];
39 static struct part part_jump[PART_MAX_JUMP];
40 static GLuint part_text_star;
41 static GLuint part_text_squiggle;
42 static GLuint part_list;
44 static float goal_height;
45 static float jump_height;
47 /*---------------------------------------------------------------------------*/
51 static float rnd(float l, float h)
53 return l + (h - l) * rand() / RAND_MAX;
56 /*---------------------------------------------------------------------------*/
66 static struct part_lerp part_lerp_coin[PART_MAX_COIN];
67 static struct part_lerp part_lerp_goal[PART_MAX_GOAL];
68 static struct part_lerp part_lerp_jump[PART_MAX_JUMP];
70 void part_lerp_copy(void)
74 for (i = 0; i < PART_MAX_COIN; i++)
75 v_cpy(part_lerp_coin[i].p[PREV], part_lerp_coin[i].p[CURR]);
77 for (i = 0; i < PART_MAX_GOAL; i++)
78 v_cpy(part_lerp_goal[i].p[PREV], part_lerp_goal[i].p[CURR]);
80 for (i = 0; i < PART_MAX_JUMP; i++)
81 v_cpy(part_lerp_jump[i].p[PREV], part_lerp_jump[i].p[CURR]);
84 void part_lerp_init(void)
88 for (i = 0; i < PART_MAX_GOAL; i++)
89 if (part_goal[i].t > 0.0f)
91 v_cpy(part_lerp_goal[i].p[PREV], part_goal[i].p);
92 v_cpy(part_lerp_goal[i].p[CURR], part_goal[i].p);
95 for (i = 0; i < PART_MAX_JUMP; i++)
96 if (part_jump[i].t > 0.0f)
98 v_cpy(part_lerp_jump[i].p[PREV], part_jump[i].p);
99 v_cpy(part_lerp_jump[i].p[CURR], part_jump[i].p);
103 void part_lerp_burst(int i)
105 if (part_coin[i].t >= 1.0f)
107 v_cpy(part_lerp_coin[i].p[PREV], part_coin[i].p);
108 v_cpy(part_lerp_coin[i].p[CURR], part_coin[i].p);
112 void part_lerp_apply(float a)
116 for (i = 0; i < PART_MAX_COIN; i++)
117 if (part_coin[i].t > 0.0f)
119 v_lerp(part_coin[i].p,
120 part_lerp_coin[i].p[PREV],
121 part_lerp_coin[i].p[CURR], a);
124 for (i = 0; i < PART_MAX_GOAL; i++)
125 if (part_goal[i].t > 0.0f)
127 v_lerp(part_goal[i].p,
128 part_lerp_goal[i].p[PREV],
129 part_lerp_goal[i].p[CURR], a);
132 for (i = 0; i < PART_MAX_GOAL; i++)
133 if (part_jump[i].t > 0.0f)
135 v_lerp(part_jump[i].p,
136 part_lerp_jump[i].p[PREV],
137 part_lerp_jump[i].p[CURR], a);
141 /*---------------------------------------------------------------------------*/
143 void part_reset(float zh, float jh)
150 for (i = 0; i < PART_MAX_COIN; i++)
151 part_coin[i].t = 0.0f;
153 for (i = 0; i < PART_MAX_GOAL; i++)
155 float t = rnd(+0.1f, +1.0f);
156 float a = rnd(-1.0f * PI, +1.0f * PI);
157 float w = rnd(-2.0f * PI, +2.0f * PI);
160 part_goal[i].a = V_DEG(a);
161 part_goal[i].w = V_DEG(w);
163 part_goal[i].c[0] = 1.0f;
164 part_goal[i].c[1] = 1.0f;
165 part_goal[i].c[2] = 0.0f;
167 part_goal[i].p[0] = fsinf(a);
168 part_goal[i].p[1] = (1.f - t) * goal_height;
169 part_goal[i].p[2] = fcosf(a);
171 part_goal[i].v[0] = 0.f;
172 part_goal[i].v[1] = 0.f;
173 part_goal[i].v[2] = 0.f;
176 for (i = 0; i < PART_MAX_JUMP; i++)
178 float t = rnd(+0.1f, +1.0f);
179 float a = rnd(-1.0f * PI, +1.0f * PI);
180 float w = rnd(+0.5f, +2.5f);
182 float vy = rnd(+0.025f, +0.25f);
185 part_jump[i].a = V_DEG(a);
188 part_jump[i].c[0] = 1.0f;
189 part_jump[i].c[1] = 1.0f;
190 part_jump[i].c[2] = 1.0f;
192 part_jump[i].p[0] = fsinf(a);
193 part_jump[i].p[1] = (1.f - t) * jump_height;
194 part_jump[i].p[2] = fcosf(a);
196 part_jump[i].v[0] = 0.f;
197 part_jump[i].v[1] = vy;
198 part_jump[i].v[2] = 0.f;
204 void part_init(float zh, float jh)
206 memset(part_coin, 0, PART_MAX_COIN * sizeof (struct part));
207 memset(part_goal, 0, PART_MAX_GOAL * sizeof (struct part));
208 memset(part_jump, 0, PART_MAX_JUMP * sizeof (struct part));
210 part_text_star = make_image_from_file(IMG_PART_STAR);
211 part_text_squiggle = make_image_from_file(IMG_PART_SQUIGGLE);
213 part_list = glGenLists(1);
215 glNewList(part_list, GL_COMPILE);
219 glTexCoord2f(0.f, 0.f);
220 glVertex2f(-PART_SIZE, -PART_SIZE);
222 glTexCoord2f(1.f, 0.f);
223 glVertex2f(+PART_SIZE, -PART_SIZE);
225 glTexCoord2f(1.f, 1.f);
226 glVertex2f(+PART_SIZE, +PART_SIZE);
228 glTexCoord2f(0.f, 1.f);
229 glVertex2f(-PART_SIZE, +PART_SIZE);
240 if (glIsList(part_list))
241 glDeleteLists(part_list, 1);
243 if (glIsTexture(part_text_star))
244 glDeleteTextures(1, &part_text_star);
246 if (glIsTexture(part_text_squiggle))
247 glDeleteTextures(1, &part_text_squiggle);
250 /*---------------------------------------------------------------------------*/
252 void part_burst(const float *p, const float *c)
256 for (i = 0; n < 10 && i < PART_MAX_COIN; i++)
257 if (part_coin[i].t <= 0.f)
259 float a = rnd(-1.0f * PI, +1.0f * PI);
260 float b = rnd(+0.3f * PI, +0.5f * PI);
261 float w = rnd(-4.0f * PI, +4.0f * PI);
263 part_coin[i].p[0] = p[0];
264 part_coin[i].p[1] = p[1];
265 part_coin[i].p[2] = p[2];
267 part_coin[i].v[0] = 4.f * fcosf(a) * fcosf(b);
268 part_coin[i].v[1] = 4.f * fsinf(b);
269 part_coin[i].v[2] = 4.f * fsinf(a) * fcosf(b);
271 part_coin[i].c[0] = c[0];
272 part_coin[i].c[1] = c[1];
273 part_coin[i].c[2] = c[2];
275 part_coin[i].t = 1.f;
276 part_coin[i].a = 0.f;
277 part_coin[i].w = V_DEG(w);
285 /*---------------------------------------------------------------------------*/
287 static void part_fall(struct part_lerp *lerp,
288 struct part *part, int n,
289 const float *g, float dt)
293 for (i = 0; i < n; i++)
298 v_mad(part[i].v, part[i].v, g, dt);
300 v_mad(lerp[i].p[CURR], lerp[i].p[CURR], part[i].v, dt);
304 static void part_spin(struct part_lerp *lerp,
305 struct part *part, int n,
306 const float *g, float dt)
310 for (i = 0; i < n; i++)
313 part[i].a += 30.f * dt;
315 lerp[i].p[CURR][0] = fsinf(V_RAD(part[i].a));
316 lerp[i].p[CURR][2] = fcosf(V_RAD(part[i].a));
320 void part_step(const float *g, float dt)
326 part_fall(part_lerp_coin, part_coin, PART_MAX_COIN, g, dt);
329 part_fall(part_lerp_goal, part_goal, PART_MAX_GOAL, g, dt);
331 part_spin(part_lerp_goal, part_goal, PART_MAX_GOAL, g, dt);
333 for (i = 0; i < PART_MAX_JUMP; i++)
335 part_lerp_jump[i].p[CURR][1] += part_jump[i].v[1] * dt;
337 if (part_lerp_jump[i].p[PREV][1] > jump_height)
339 part_lerp_jump[i].p[PREV][1] = 0.0f;
340 part_lerp_jump[i].p[CURR][1] = 0.0f;
345 /*---------------------------------------------------------------------------*/
347 static void part_draw(const float *M,
348 const float *p, float r, float rz, float s)
352 glTranslatef(r * p[0], p[1], r * p[2]);
354 glRotatef(rz, 0.f, 0.f, 1.f);
355 glScalef(s, s, 1.0f);
357 glCallList(part_list);
362 void part_draw_coin(const float *M, float t)
366 glBindTexture(GL_TEXTURE_2D, part_text_star);
368 for (i = 0; i < PART_MAX_COIN; i++)
369 if (part_coin[i].t > 0.f)
371 glColor4f(part_coin[i].c[0],
376 part_draw(M, part_coin[i].p, 1.0f, t * part_coin[i].w, 1.0f);
379 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
382 void part_draw_goal(const float *M, float radius, float a, float t)
386 glBindTexture(GL_TEXTURE_2D, part_text_star);
388 glColor4f(1.0f, 1.0f, 0.0f, a);
390 for (i = 0; i < PART_MAX_GOAL; i++)
391 if (part_goal[i].t > 0.0f)
392 part_draw(M, part_goal[i].p, radius - 0.05f,
393 t * part_goal[i].w, 1.0f);
395 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
398 void part_draw_jump(const float *M, float radius, float a, float t)
402 glBindTexture(GL_TEXTURE_2D, part_text_squiggle);
404 for (i = 0; i < PART_MAX_JUMP; i++)
406 glColor4f(part_jump[i].c[0],
409 1.0f - part_jump[i].p[1] / jump_height);
412 * X is the current time since some Epoch, Y is the time it
413 * takes for a squiggle to grow to its full size and then
414 * shrink again. F is the current scale of the squiggle in
415 * the interval [0.0, 1.0].
418 #define F(x, y) fabsf(fcosf(((x) / (y)) * PI))
420 part_draw(M, part_jump[i].p, radius - 0.05f,
421 0.0f, F(t, part_jump[i].w));
426 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
429 /*---------------------------------------------------------------------------*/