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