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, IMG_PART_STAR
59 static struct d_mtrl coin_draw_mtrl;
61 /*---------------------------------------------------------------------------*/
65 static float rnd(float l, float h)
67 return l + (h - l) * rand() / RAND_MAX;
70 /*---------------------------------------------------------------------------*/
80 static struct part_lerp part_lerp_coin[PART_MAX_COIN];
82 void part_lerp_copy(void)
86 for (i = 0; i < PART_MAX_COIN; i++)
87 v_cpy(part_lerp_coin[i].p[PREV],
88 part_lerp_coin[i].p[CURR]);
91 void part_lerp_init(void)
95 void part_lerp_burst(int i)
97 if (coin_draw[i].t >= 1.0f)
99 v_cpy(part_lerp_coin[i].p[PREV], coin_draw[i].p);
100 v_cpy(part_lerp_coin[i].p[CURR], coin_draw[i].p);
104 void part_lerp_apply(float a)
108 for (i = 0; i < PART_MAX_COIN; i++)
109 if (coin_draw[i].t > 0.0f)
110 v_lerp(coin_draw[i].p,
111 part_lerp_coin[i].p[PREV],
112 part_lerp_coin[i].p[CURR], a);
114 /* Upload the current state of the particles. It would be best to limit */
115 /* this upload to only active particles, but it's more important to do */
116 /* it all in a single call. */
119 glBindBuffer_ (GL_ARRAY_BUFFER, coin_vbo);
120 glBufferSubData_(GL_ARRAY_BUFFER, 0, sizeof (coin_draw), coin_draw);
121 glBindBuffer_ (GL_ARRAY_BUFFER, 0);
125 /*---------------------------------------------------------------------------*/
127 void part_reset(void)
131 for (i = 0; i < PART_MAX_COIN; i++)
132 coin_draw[i].t = 0.0f;
139 sol_load_mtrl(&coin_draw_mtrl, &coin_base_mtrl);
141 memset(coin_vary, 0, PART_MAX_COIN * sizeof (struct part_vary));
142 memset(coin_draw, 0, PART_MAX_COIN * sizeof (struct part_draw));
145 glGenBuffers_(1, &coin_vbo);
146 glBindBuffer_(GL_ARRAY_BUFFER, coin_vbo);
147 glBufferData_(GL_ARRAY_BUFFER, sizeof (coin_draw),
148 coin_draw, GL_DYNAMIC_DRAW);
149 glBindBuffer_(GL_ARRAY_BUFFER, 0);
157 if (glIsBuffer_(coin_vbo))
158 glDeleteBuffers_(1, &coin_vbo);
160 sol_free_mtrl(&coin_draw_mtrl);
163 /*---------------------------------------------------------------------------*/
165 void part_burst(const float *p, const float *c)
169 for (i = 0; n < 10 && i < PART_MAX_COIN; i++)
170 if (coin_draw[i].t <= 0.f)
172 float a = rnd(-1.0f * PI, +1.0f * PI);
173 float b = rnd(+0.3f * PI, +0.5f * PI);
175 coin_draw[i].c[0] = c[0];
176 coin_draw[i].c[1] = c[1];
177 coin_draw[i].c[2] = c[2];
179 coin_draw[i].p[0] = p[0];
180 coin_draw[i].p[1] = p[1];
181 coin_draw[i].p[2] = p[2];
183 coin_vary[i].v[0] = 4.f * fcosf(a) * fcosf(b);
184 coin_vary[i].v[1] = 4.f * fsinf(b);
185 coin_vary[i].v[2] = 4.f * fsinf(a) * fcosf(b);
187 coin_draw[i].t = 1.f;
195 /*---------------------------------------------------------------------------*/
197 static void part_fall(struct part_lerp *lerp,
198 struct part_vary *vary,
199 struct part_draw *draw,
200 int n, const float *g, float dt)
204 for (i = 0; i < n; i++)
209 v_mad(vary[i].v, vary[i].v, g, dt);
211 v_mad(lerp[i].p[CURR], lerp[i].p[CURR], vary[i].v, dt);
213 else draw[i].t = 0.0f;
216 void part_step(const float *g, float dt)
219 part_fall(part_lerp_coin, coin_vary, coin_draw, PART_MAX_COIN, g, dt);
222 /*---------------------------------------------------------------------------*/
224 void part_draw_coin(struct s_rend *rend)
226 const GLfloat c[3] = { 0.0f, 1.0f, 0.0f };
227 GLint s = config_get_d(CONFIG_HEIGHT) / 8;
229 sol_apply_mtrl(&coin_draw_mtrl, rend);
231 /* Draw the entire buffer. Dead particles have zero opacity anyway. */
234 glBindBuffer_(GL_ARRAY_BUFFER, coin_vbo);
236 glBindBuffer_(GL_ARRAY_BUFFER, 0);
239 glClientActiveTexture_(GL_TEXTURE2);
240 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
241 glClientActiveTexture_(GL_TEXTURE1);
242 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
243 glClientActiveTexture_(GL_TEXTURE0);
244 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
246 glDisableClientState(GL_NORMAL_ARRAY);
247 glEnableClientState(GL_COLOR_ARRAY);
250 glColorPointer (4, GL_FLOAT, sizeof (struct part_draw),
251 (GLvoid *) offsetof (struct part_draw, c));
252 glVertexPointer(3, GL_FLOAT, sizeof (struct part_draw),
253 (GLvoid *) offsetof (struct part_draw, p));
255 glColorPointer (4, GL_FLOAT, sizeof (struct part_draw), coin_draw[0].c);
256 glVertexPointer(3, GL_FLOAT, sizeof (struct part_draw), coin_draw[0].p);
259 glEnable(GL_POINT_SPRITE);
261 glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
262 glPointParameterfv_(GL_POINT_DISTANCE_ATTENUATION, c);
265 glDrawArrays(GL_POINTS, 0, PART_MAX_COIN);
267 glDisable(GL_POINT_SPRITE);
269 glDisableClientState(GL_COLOR_ARRAY);
270 glEnableClientState(GL_NORMAL_ARRAY);
272 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
273 glClientActiveTexture_(GL_TEXTURE2);
274 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
275 glClientActiveTexture_(GL_TEXTURE1);
276 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
277 glClientActiveTexture_(GL_TEXTURE0);
280 /*---------------------------------------------------------------------------*/