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.
28 /*---------------------------------------------------------------------------*/
32 GLfloat v[3]; /* Velocity */
37 GLfloat p[3]; /* Position */
38 GLfloat c[3]; /* Color */
39 GLfloat t; /* Time until death. Doubles as opacity. */
42 static struct part_vary coin_vary[PART_MAX_COIN];
43 static struct part_draw coin_draw[PART_MAX_COIN];
45 static GLuint coin_vbo;
47 /*---------------------------------------------------------------------------*/
49 static struct b_mtrl coin_base_mtrl =
51 { 0.8f, 0.8f, 0.8f, 1.0f },
52 { 0.2f, 0.2f, 0.2f, 1.0f },
53 { 0.0f, 0.0f, 0.0f, 1.0f },
54 { 0.0f, 0.0f, 0.0f, 1.0f },
55 { 0.0f }, 0.0f, M_TRANSPARENT, ""
58 static struct d_mtrl coin_draw_mtrl =
63 /*---------------------------------------------------------------------------*/
67 static float rnd(float l, float h)
69 return l + (h - l) * rand() / RAND_MAX;
72 /*---------------------------------------------------------------------------*/
82 static struct part_lerp part_lerp_coin[PART_MAX_COIN];
84 void part_lerp_copy(void)
88 for (i = 0; i < PART_MAX_COIN; i++)
89 v_cpy(part_lerp_coin[i].p[PREV],
90 part_lerp_coin[i].p[CURR]);
93 void part_lerp_init(void)
97 void part_lerp_burst(int i)
99 if (coin_draw[i].t >= 1.0f)
101 v_cpy(part_lerp_coin[i].p[PREV], coin_draw[i].p);
102 v_cpy(part_lerp_coin[i].p[CURR], coin_draw[i].p);
106 void part_lerp_apply(float a)
110 for (i = 0; i < PART_MAX_COIN; i++)
111 if (coin_draw[i].t > 0.0f)
112 v_lerp(coin_draw[i].p,
113 part_lerp_coin[i].p[PREV],
114 part_lerp_coin[i].p[CURR], a);
116 /* Upload the current state of the particles. It would be best to limit */
117 /* this upload to only active particles, but it's more important to do */
118 /* it all in a single call. */
121 glBindBuffer (GL_ARRAY_BUFFER, coin_vbo);
122 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof (coin_draw), coin_draw);
123 glBindBuffer (GL_ARRAY_BUFFER, 0);
127 /*---------------------------------------------------------------------------*/
129 void part_reset(void)
133 for (i = 0; i < PART_MAX_COIN; i++)
134 coin_draw[i].t = 0.0f;
141 coin_draw_mtrl.o = make_image_from_file(IMG_PART_STAR);
143 memset(coin_vary, 0, PART_MAX_COIN * sizeof (struct part_vary));
144 memset(coin_draw, 0, PART_MAX_COIN * sizeof (struct part_draw));
147 glGenBuffers(1, &coin_vbo);
148 glBindBuffer(GL_ARRAY_BUFFER, coin_vbo);
149 glBufferData(GL_ARRAY_BUFFER, sizeof (coin_draw),
150 coin_draw, GL_DYNAMIC_DRAW);
151 glBindBuffer(GL_ARRAY_BUFFER, 0);
159 if (glIsBuffer(coin_vbo))
160 glDeleteBuffers(1, &coin_vbo);
162 if (glIsTexture(coin_draw_mtrl.o))
163 glDeleteTextures(1, &coin_draw_mtrl.o);
166 /*---------------------------------------------------------------------------*/
168 void part_burst(const float *p, const float *c)
172 for (i = 0; n < 10 && i < PART_MAX_COIN; i++)
173 if (coin_draw[i].t <= 0.f)
175 float a = rnd(-1.0f * PI, +1.0f * PI);
176 float b = rnd(+0.3f * PI, +0.5f * PI);
178 coin_draw[i].c[0] = c[0];
179 coin_draw[i].c[1] = c[1];
180 coin_draw[i].c[2] = c[2];
182 coin_draw[i].p[0] = p[0];
183 coin_draw[i].p[1] = p[1];
184 coin_draw[i].p[2] = p[2];
186 coin_vary[i].v[0] = 4.f * fcosf(a) * fcosf(b);
187 coin_vary[i].v[1] = 4.f * fsinf(b);
188 coin_vary[i].v[2] = 4.f * fsinf(a) * fcosf(b);
190 coin_draw[i].t = 1.f;
198 /*---------------------------------------------------------------------------*/
200 static void part_fall(struct part_lerp *lerp,
201 struct part_vary *vary,
202 struct part_draw *draw,
203 int n, const float *g, float dt)
207 for (i = 0; i < n; i++)
212 v_mad(vary[i].v, vary[i].v, g, dt);
214 v_mad(lerp[i].p[CURR], lerp[i].p[CURR], vary[i].v, dt);
216 else draw[i].t = 0.0f;
219 void part_step(const float *g, float dt)
222 part_fall(part_lerp_coin, coin_vary, coin_draw, PART_MAX_COIN, g, dt);
225 /*---------------------------------------------------------------------------*/
227 const struct d_mtrl *part_draw_coin(const struct d_mtrl *mq)
229 const GLfloat c[3] = { 0.0f, 1.0f, 0.0f };
230 GLint s = config_get_d(CONFIG_HEIGHT) / 8;
232 mq = sol_apply_mtrl(&coin_draw_mtrl, mq);
234 /* Draw the entire buffer. Dead particles have zero opacity anyway. */
237 glBindBuffer(GL_ARRAY_BUFFER, coin_vbo);
239 glBindBuffer(GL_ARRAY_BUFFER, 0);
242 glClientActiveTexture(GL_TEXTURE1);
243 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
244 glClientActiveTexture(GL_TEXTURE0);
245 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
247 glDisableClientState(GL_NORMAL_ARRAY);
248 glEnableClientState(GL_COLOR_ARRAY);
251 glColorPointer (4, GL_FLOAT, sizeof (struct part_draw),
252 (GLvoid *) offsetof (struct part_draw, c));
253 glVertexPointer(3, GL_FLOAT, sizeof (struct part_draw),
254 (GLvoid *) offsetof (struct part_draw, p));
256 glColorPointer (4, GL_FLOAT, sizeof (struct part_draw), coin_draw[0].c);
257 glVertexPointer(3, GL_FLOAT, sizeof (struct part_draw), coin_draw[0].p);
260 glEnable(GL_POINT_SPRITE);
262 glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
263 glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, c);
266 glDrawArrays(GL_POINTS, 0, PART_MAX_COIN);
268 glDisable(GL_POINT_SPRITE);
270 glDisableClientState(GL_COLOR_ARRAY);
271 glEnableClientState(GL_NORMAL_ARRAY);
273 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
274 glClientActiveTexture(GL_TEXTURE1);
275 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
276 glClientActiveTexture(GL_TEXTURE0);
281 /*---------------------------------------------------------------------------*/