1 /*
2 * Animation plugin for compiz/beryl
3 *
4 * animation.c
5 *
6 * Copyright : (C) 2006 Erkin Bahceci
7 * E-mail : erkinbah@gmail.com
8 *
9 * Based on Wobbly and Minimize plugins by
10 * : David Reveman
11 * E-mail : davidr@novell.com>
12 *
13 * Particle system added by : (C) 2006 Dennis Kasprzyk
14 * E-mail : onestone@beryl-project.org
15 *
16 * Beam-Up added by : Florencio Guimaraes
17 * E-mail : florencio@nexcorp.com.br
18 *
19 * Hexagon tessellator added by : Mike Slegeir
20 * E-mail : mikeslegeir@mail.utexas.edu>
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version 2
25 * of the License, or (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
35 */
36
37 #include "animationaddon.h"
38
initParticles(int numParticles,ParticleSystem * ps)39 void initParticles(int numParticles, ParticleSystem * ps)
40 {
41 if (ps->particles)
42 free(ps->particles);
43 ps->particles = (Particle *) malloc (numParticles * sizeof (Particle));
44 ps->tex = 0;
45 ps->numParticles = numParticles;
46 ps->slowdown = 1;
47 ps->active = FALSE;
48
49 // Initialize cache
50 ps->vertices_cache = NULL;
51 ps->colors_cache = NULL;
52 ps->coords_cache = NULL;
53 ps->dcolors_cache = NULL;
54 ps->vertex_cache_count = 0;
55 ps->color_cache_count = 0;
56 ps->coords_cache_count = 0;
57 ps->dcolors_cache_count = 0;
58
59 Particle *part = ps->particles;
60 int i;
61 for (i = 0; i < numParticles; i++, part++)
62 part->life = 0.0f;
63 }
64
drawParticles(CompWindow * w,ParticleSystem * ps)65 void drawParticles (CompWindow * w, ParticleSystem * ps)
66 {
67 CompScreen *s = w->screen;
68
69 glPushMatrix();
70 if (w)
71 glTranslated(WIN_X(w) - ps->x, WIN_Y(w) - ps->y, 0);
72
73 glEnable(GL_BLEND);
74 if (ps->tex)
75 {
76 glBindTexture(GL_TEXTURE_2D, ps->tex);
77 glEnable(GL_TEXTURE_2D);
78 }
79 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
80
81 /* Check that the cache is big enough */
82 if (ps->numParticles > ps->vertex_cache_count)
83 {
84 ps->vertices_cache =
85 realloc(ps->vertices_cache,
86 ps->numParticles * 4 * 3 * sizeof(GLfloat));
87 ps->vertex_cache_count = ps->numParticles;
88 }
89
90 if (ps->numParticles > ps->coords_cache_count)
91 {
92 ps->coords_cache =
93 realloc(ps->coords_cache,
94 ps->numParticles * 4 * 2 * sizeof(GLfloat));
95 ps->coords_cache_count = ps->numParticles;
96 }
97
98 if (ps->numParticles > ps->color_cache_count)
99 {
100 ps->colors_cache =
101 realloc(ps->colors_cache,
102 ps->numParticles * 4 * 4 * sizeof(GLfloat));
103 ps->color_cache_count = ps->numParticles;
104 }
105
106 if (ps->darken > 0)
107 {
108 if (ps->dcolors_cache_count < ps->numParticles)
109 {
110 ps->dcolors_cache =
111 realloc(ps->dcolors_cache,
112 ps->numParticles * 4 * 4 * sizeof(GLfloat));
113 ps->dcolors_cache_count = ps->numParticles;
114 }
115 }
116
117 GLfloat *dcolors = ps->dcolors_cache;
118 GLfloat *vertices = ps->vertices_cache;
119 GLfloat *coords = ps->coords_cache;
120 GLfloat *colors = ps->colors_cache;
121
122 int cornersSize = sizeof (GLfloat) * 8;
123 int colorSize = sizeof (GLfloat) * 4;
124
125 GLfloat cornerCoords[8] = {0.0, 0.0,
126 0.0, 1.0,
127 1.0, 1.0,
128 1.0, 0.0};
129
130 int numActive = 0;
131
132 Particle *part = ps->particles;
133 int i;
134 for (i = 0; i < ps->numParticles; i++, part++)
135 {
136 if (part->life > 0.0f)
137 {
138 numActive += 4;
139
140 float w = part->width / 2;
141 float h = part->height / 2;
142
143 w += (w * part->w_mod) * part->life;
144 h += (h * part->h_mod) * part->life;
145
146 vertices[0] = part->x - w;
147 vertices[1] = part->y - h;
148 vertices[2] = part->z;
149
150 vertices[3] = part->x - w;
151 vertices[4] = part->y + h;
152 vertices[5] = part->z;
153
154 vertices[6] = part->x + w;
155 vertices[7] = part->y + h;
156 vertices[8] = part->z;
157
158 vertices[9] = part->x + w;
159 vertices[10] = part->y - h;
160 vertices[11] = part->z;
161
162 vertices += 12;
163
164 memcpy (coords, cornerCoords, cornersSize);
165
166 coords += 8;
167
168 colors[0] = part->r;
169 colors[1] = part->g;
170 colors[2] = part->b;
171 colors[3] = part->life * part->a;
172 memcpy (colors + 4, colors, colorSize);
173 memcpy (colors + 8, colors, colorSize);
174 memcpy (colors + 12, colors, colorSize);
175
176 colors += 16;
177
178 if (ps->darken > 0)
179 {
180 dcolors[0] = part->r;
181 dcolors[1] = part->g;
182 dcolors[2] = part->b;
183 dcolors[3] = part->life * part->a * ps->darken;
184 memcpy (dcolors + 4, dcolors, colorSize);
185 memcpy (dcolors + 8, dcolors, colorSize);
186 memcpy (dcolors + 12, dcolors, colorSize);
187
188 dcolors += 16;
189 }
190 }
191 }
192
193 glEnableClientState(GL_COLOR_ARRAY);
194
195 glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), ps->coords_cache);
196 glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), ps->vertices_cache);
197
198 // darken the background
199 if (ps->darken > 0)
200 {
201 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
202 glColorPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), ps->dcolors_cache);
203 glDrawArrays(GL_QUADS, 0, numActive);
204 }
205 // draw particles
206 glBlendFunc(GL_SRC_ALPHA, ps->blendMode);
207
208 glColorPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), ps->colors_cache);
209
210 glDrawArrays(GL_QUADS, 0, numActive);
211
212 glDisableClientState(GL_COLOR_ARRAY);
213
214 glPopMatrix();
215 glColor4usv(defaultColor);
216 screenTexEnvMode(s, GL_REPLACE);
217 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
218 glDisable(GL_TEXTURE_2D);
219 glDisable(GL_BLEND);
220 }
221
drawParticleSystems(CompWindow * w)222 void drawParticleSystems (CompWindow * w)
223 {
224 ANIMADDON_WINDOW (w);
225
226 if (aw->eng.numPs && !WINDOW_INVISIBLE(w))
227 {
228 int i = 0;
229
230 for (i = 0; i < aw->eng.numPs; i++)
231 {
232 if (aw->eng.ps[i].active)
233 drawParticles (w, &aw->eng.ps[i]);
234 }
235 }
236 }
237
updateParticles(ParticleSystem * ps,float time)238 void updateParticles(ParticleSystem * ps, float time)
239 {
240 int i;
241 Particle *part;
242 float speed = (time / 50.0);
243 float slowdown = ps->slowdown * (1 - MAX(0.99, time / 1000.0)) * 1000;
244
245 ps->active = FALSE;
246
247 part = ps->particles;
248
249 for (i = 0; i < ps->numParticles; i++, part++)
250 {
251 if (part->life > 0.0f)
252 {
253 // move particle
254 part->x += part->xi / slowdown;
255 part->y += part->yi / slowdown;
256 part->z += part->zi / slowdown;
257
258 // modify speed
259 part->xi += part->xg * speed;
260 part->yi += part->yg * speed;
261 part->zi += part->zg * speed;
262
263 // modify life
264 part->life -= part->fade * speed;
265 ps->active = TRUE;
266 }
267 }
268 }
269
finiParticles(ParticleSystem * ps)270 void finiParticles(ParticleSystem * ps)
271 {
272 free(ps->particles);
273 if (ps->tex)
274 glDeleteTextures(1, &ps->tex);
275
276 if (ps->vertices_cache)
277 free(ps->vertices_cache);
278 if (ps->colors_cache)
279 free(ps->colors_cache);
280 if (ps->coords_cache)
281 free(ps->coords_cache);
282 if (ps->dcolors_cache)
283 free(ps->dcolors_cache);
284 }
285
286 void
particlesUpdateBB(CompOutput * output,CompWindow * w,Box * BB)287 particlesUpdateBB (CompOutput *output,
288 CompWindow * w,
289 Box *BB)
290 {
291 ANIMADDON_DISPLAY (w->screen->display);
292 ANIMADDON_WINDOW (w);
293
294 int i;
295 for (i = 0; i < aw->eng.numPs; i++)
296 {
297 ParticleSystem * ps = &aw->eng.ps[i];
298 if (ps->active)
299 {
300 Particle *part = ps->particles;
301 int j;
302 for (j = 0; j < ps->numParticles; j++, part++)
303 {
304 if (part->life <= 0.0f) // Ignore dead particles
305 continue;
306
307 float w = part->width / 2;
308 float h = part->height / 2;
309
310 w += (w * part->w_mod) * part->life;
311 h += (h * part->h_mod) * part->life;
312
313 Box particleBox =
314 {part->x - w, part->x + w,
315 part->y - h, part->y + h};
316
317 ad->animBaseFunctions->expandBoxWithBox (BB, &particleBox);
318 }
319 }
320 }
321 if (aw->com->useDrawRegion)
322 {
323 int nClip = aw->com->drawRegion->numRects;
324 Box *pClip = aw->com->drawRegion->rects;
325
326 for (; nClip--; pClip++)
327 ad->animBaseFunctions->expandBoxWithBox (BB, pClip);
328 }
329 else // drawing full window
330 ad->animBaseFunctions->updateBBWindow (output, w, BB);
331 }
332
333 void
particlesCleanup(CompWindow * w)334 particlesCleanup (CompWindow * w)
335 {
336 ANIMADDON_WINDOW (w);
337
338 if (aw->eng.numPs)
339 {
340 int i = 0;
341
342 for (i = 0; i < aw->eng.numPs; i++)
343 finiParticles (aw->eng.ps + i);
344 free (aw->eng.ps);
345 aw->eng.ps = NULL;
346 aw->eng.numPs = 0;
347 }
348 }
349
350 Bool
particlesPrePrepPaintScreen(CompWindow * w,int msSinceLastPaint)351 particlesPrePrepPaintScreen (CompWindow * w, int msSinceLastPaint)
352 {
353 ANIMADDON_WINDOW (w);
354
355 Bool particleAnimInProgress = FALSE;
356
357 if (aw->eng.numPs)
358 {
359 int i;
360 for (i = 0; i < aw->eng.numPs; i++)
361 {
362 if (aw->eng.ps[i].active)
363 {
364 updateParticles (&aw->eng.ps[i], msSinceLastPaint);
365 particleAnimInProgress = TRUE;
366 }
367 }
368 }
369
370 return particleAnimInProgress;
371 }
372
373