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.
26 /*---------------------------------------------------------------------------*/
33 GLfloat v[3]; /* Velocity */
38 GLfloat p[3]; /* Position */
39 GLfloat c[3]; /* Color */
40 GLfloat t; /* Time until death. Doubles as opacity. */
43 static struct part_vary coin_vary[PART_MAX_COIN];
44 static struct part_draw coin_draw[PART_MAX_COIN];
46 static GLuint coin_vbo;
48 /*---------------------------------------------------------------------------*/
50 static struct b_mtrl coin_base_mtrl =
52 { 0.8f, 0.8f, 0.8f, 1.0f },
53 { 0.2f, 0.2f, 0.2f, 1.0f },
54 { 0.0f, 0.0f, 0.0f, 1.0f },
55 { 0.0f, 0.0f, 0.0f, 1.0f },
56 { 0.0f }, 0.0f, M_TRANSPARENT, ""
59 static struct d_mtrl coin_draw_mtrl =
64 /*---------------------------------------------------------------------------*/
68 static float rnd(float l, float h)
70 return l + (h - l) * rand() / RAND_MAX;
73 /*---------------------------------------------------------------------------*/
83 static struct part_lerp part_lerp_coin[PART_MAX_COIN];
85 void part_lerp_copy(void)
89 for (i = 0; i < PART_MAX_COIN; i++)
90 v_cpy(part_lerp_coin[i].p[PREV],
91 part_lerp_coin[i].p[CURR]);
94 void part_lerp_init(void)
98 void part_lerp_burst(int i)
100 if (coin_draw[i].t >= 1.0f)
102 v_cpy(part_lerp_coin[i].p[PREV], coin_draw[i].p);
103 v_cpy(part_lerp_coin[i].p[CURR], coin_draw[i].p);
107 void part_lerp_apply(float a)
111 for (i = 0; i < PART_MAX_COIN; i++)
112 if (coin_draw[i].t > 0.0f)
113 v_lerp(coin_draw[i].p,
114 part_lerp_coin[i].p[PREV],
115 part_lerp_coin[i].p[CURR], a);
117 /* Upload the current state of the particles. It would be best to limit */
118 /* this upload to only active particles, but it's more important to do */
119 /* it all in a single call. */
122 glBindBuffer (GL_ARRAY_BUFFER, coin_vbo);
123 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof (coin_draw), coin_draw);
124 glBindBuffer (GL_ARRAY_BUFFER, 0);
128 /*---------------------------------------------------------------------------*/
130 void part_reset(void)
134 for (i = 0; i < PART_MAX_COIN; i++)
135 coin_draw[i].t = 0.0f;
142 coin_draw_mtrl.o = make_image_from_file(IMG_PART_STAR);
144 memset(coin_vary, 0, PART_MAX_COIN * sizeof (struct part_vary));
145 memset(coin_draw, 0, PART_MAX_COIN * sizeof (struct part_draw));
148 glGenBuffers(1, &coin_vbo);
149 glBindBuffer(GL_ARRAY_BUFFER, coin_vbo);
150 glBufferData(GL_ARRAY_BUFFER, sizeof (coin_draw),
151 coin_draw, GL_DYNAMIC_DRAW);
152 glBindBuffer(GL_ARRAY_BUFFER, 0);
160 if (glIsBuffer_(coin_vbo))
161 glDeleteBuffers_(1, &coin_vbo);
163 if (glIsTexture(coin_draw_mtrl.o))
164 glDeleteTextures(1, &coin_draw_mtrl.o);
167 /*---------------------------------------------------------------------------*/
169 void part_burst(const float *p, const float *c)
173 for (i = 0; n < 10 && i < PART_MAX_COIN; i++)
174 if (coin_draw[i].t <= 0.f)
176 float a = rnd(-1.0f * PI, +1.0f * PI);
177 float b = rnd(+0.3f * PI, +0.5f * PI);
179 coin_draw[i].c[0] = c[0];
180 coin_draw[i].c[1] = c[1];
181 coin_draw[i].c[2] = c[2];
183 coin_draw[i].p[0] = p[0];
184 coin_draw[i].p[1] = p[1];
185 coin_draw[i].p[2] = p[2];
187 coin_vary[i].v[0] = 4.f * fcosf(a) * fcosf(b);
188 coin_vary[i].v[1] = 4.f * fsinf(b);
189 coin_vary[i].v[2] = 4.f * fsinf(a) * fcosf(b);
191 coin_draw[i].t = 1.f;
199 /*---------------------------------------------------------------------------*/
201 static void part_fall(struct part_lerp *lerp,
202 struct part_vary *vary,
203 struct part_draw *draw,
204 int n, const float *g, float dt)
208 for (i = 0; i < n; i++)
213 v_mad(vary[i].v, vary[i].v, g, dt);
215 v_mad(lerp[i].p[CURR], lerp[i].p[CURR], vary[i].v, dt);
217 else draw[i].t = 0.0f;
220 void part_step(const float *g, float dt)
223 part_fall(part_lerp_coin, coin_vary, coin_draw, PART_MAX_COIN, g, dt);
226 /*---------------------------------------------------------------------------*/
228 const struct d_mtrl *part_draw_coin(const struct d_mtrl *mq)
230 const GLfloat c[3] = { 0.0f, 1.0f, 0.0f };
231 GLint s = config_get_d(CONFIG_HEIGHT) / 8;
233 mq = sol_apply_mtrl(&coin_draw_mtrl, mq);
235 /* Draw the entire buffer. Dead particles have zero opacity anyway. */
238 glBindBuffer_(GL_ARRAY_BUFFER, coin_vbo);
240 glBindBuffer_(GL_ARRAY_BUFFER, 0);
243 glClientActiveTexture_(GL_TEXTURE1);
244 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
245 glClientActiveTexture_(GL_TEXTURE0);
246 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
248 glDisableClientState(GL_NORMAL_ARRAY);
249 glEnableClientState(GL_COLOR_ARRAY);
252 glColorPointer (4, GL_FLOAT, sizeof (struct part_draw),
253 (GLvoid *) offsetof (struct part_draw, c));
254 glVertexPointer(3, GL_FLOAT, sizeof (struct part_draw),
255 (GLvoid *) offsetof (struct part_draw, p));
257 glColorPointer (4, GL_FLOAT, sizeof (struct part_draw), coin_draw[0].c);
258 glVertexPointer(3, GL_FLOAT, sizeof (struct part_draw), coin_draw[0].p);
261 glEnable(GL_POINT_SPRITE);
263 glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
264 glPointParameterfv_(GL_POINT_DISTANCE_ATTENUATION, c);
267 glDrawArrays(GL_POINTS, 0, PART_MAX_COIN);
269 glDisable(GL_POINT_SPRITE);
271 glDisableClientState(GL_COLOR_ARRAY);
272 glEnableClientState(GL_NORMAL_ARRAY);
274 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
275 glClientActiveTexture_(GL_TEXTURE1);
276 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
277 glClientActiveTexture_(GL_TEXTURE0);
282 /*---------------------------------------------------------------------------*/