/*
* Animation plugin for compiz/beryl
*
* animation.c
*
* Copyright : (C) 2006 Erkin Bahceci
* E-mail : erkinbah@gmail.com
*
* Based on Wobbly and Minimize plugins by
* : David Reveman
* E-mail : davidr@novell.com>
*
* Particle system added by : (C) 2006 Dennis Kasprzyk
* E-mail : onestone@beryl-project.org
*
* Beam-Up added by : Florencio Guimaraes
* E-mail : florencio@nexcorp.com.br
*
* Hexagon tessellator added by : Mike Slegeir
* E-mail : mikeslegeir@mail.utexas.edu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "animation-internal.h"
void initParticles(int numParticles, ParticleSystem * ps)
{
if (ps->particles)
free(ps->particles);
ps->particles = calloc(numParticles, sizeof(Particle));
ps->tex = 0;
ps->numParticles = numParticles;
ps->slowdown = 1;
ps->active = FALSE;
// Initialize cache
ps->vertices_cache = NULL;
ps->colors_cache = NULL;
ps->coords_cache = NULL;
ps->dcolors_cache = NULL;
ps->vertex_cache_count = 0;
ps->color_cache_count = 0;
ps->coords_cache_count = 0;
ps->dcolors_cache_count = 0;
int i;
for (i = 0; i < numParticles; i++)
{
ps->particles[i].life = 0.0f;
}
}
void drawParticles(CompScreen * s, CompWindow * w, ParticleSystem * ps)
{
glPushMatrix();
if (w)
glTranslated(WIN_X(w) - ps->x, WIN_Y(w) - ps->y, 0);
glEnable(GL_BLEND);
if (ps->tex)
{
glBindTexture(GL_TEXTURE_2D, ps->tex);
glEnable(GL_TEXTURE_2D);
}
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
int i;
Particle *part;
/* Check that the cache is big enough */
if (ps->numParticles > ps->vertex_cache_count)
{
ps->vertices_cache =
realloc(ps->vertices_cache,
ps->numParticles * 4 * 3 * sizeof(GLfloat));
ps->vertex_cache_count = ps->numParticles;
}
if (ps->numParticles > ps->coords_cache_count)
{
ps->coords_cache =
realloc(ps->coords_cache,
ps->numParticles * 4 * 2 * sizeof(GLfloat));
ps->coords_cache_count = ps->numParticles;
}
if (ps->numParticles > ps->color_cache_count)
{
ps->colors_cache =
realloc(ps->colors_cache,
ps->numParticles * 4 * 4 * sizeof(GLfloat));
ps->color_cache_count = ps->numParticles;
}
if (ps->darken > 0)
{
if (ps->dcolors_cache_count < ps->numParticles)
{
ps->dcolors_cache =
realloc(ps->dcolors_cache,
ps->numParticles * 4 * 4 * sizeof(GLfloat));
ps->dcolors_cache_count = ps->numParticles;
}
}
GLfloat *dcolors = ps->dcolors_cache;
GLfloat *vertices = ps->vertices_cache;
GLfloat *coords = ps->coords_cache;
GLfloat *colors = ps->colors_cache;
int numActive = 0;
for (i = 0; i < ps->numParticles; i++)
{
part = &ps->particles[i];
if (part->life > 0.0f)
{
numActive += 4;
float w = part->width / 2;
float h = part->height / 2;
w += (w * part->w_mod) * part->life;
h += (h * part->h_mod) * part->life;
vertices[0] = part->x - w;
vertices[1] = part->y - h;
vertices[2] = part->z;
vertices[3] = part->x - w;
vertices[4] = part->y + h;
vertices[5] = part->z;
vertices[6] = part->x + w;
vertices[7] = part->y + h;
vertices[8] = part->z;
vertices[9] = part->x + w;
vertices[10] = part->y - h;
vertices[11] = part->z;
vertices += 12;
coords[0] = 0.0;
coords[1] = 0.0;
coords[2] = 0.0;
coords[3] = 1.0;
coords[4] = 1.0;
coords[5] = 1.0;
coords[6] = 1.0;
coords[7] = 0.0;
coords += 8;
colors[0] = part->r;
colors[1] = part->g;
colors[2] = part->b;
colors[3] = part->life * part->a;
colors[4] = part->r;
colors[5] = part->g;
colors[6] = part->b;
colors[7] = part->life * part->a;
colors[8] = part->r;
colors[9] = part->g;
colors[10] = part->b;
colors[11] = part->life * part->a;
colors[12] = part->r;
colors[13] = part->g;
colors[14] = part->b;
colors[15] = part->life * part->a;
colors += 16;
if (ps->darken > 0)
{
dcolors[0] = part->r;
dcolors[1] = part->g;
dcolors[2] = part->b;
dcolors[3] = part->life * part->a * ps->darken;
dcolors[4] = part->r;
dcolors[5] = part->g;
dcolors[6] = part->b;
dcolors[7] = part->life * part->a * ps->darken;
dcolors[8] = part->r;
dcolors[9] = part->g;
dcolors[10] = part->b;
dcolors[11] = part->life * part->a * ps->darken;
dcolors[12] = part->r;
dcolors[13] = part->g;
dcolors[14] = part->b;
dcolors[15] = part->life * part->a * ps->darken;
dcolors += 16;
}
}
}
glEnableClientState(GL_COLOR_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), ps->coords_cache);
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), ps->vertices_cache);
// darken the background
if (ps->darken > 0)
{
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
glColorPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), ps->dcolors_cache);
glDrawArrays(GL_QUADS, 0, numActive);
}
// draw particles
glBlendFunc(GL_SRC_ALPHA, ps->blendMode);
glColorPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), ps->colors_cache);
glDrawArrays(GL_QUADS, 0, numActive);
glDisableClientState(GL_COLOR_ARRAY);
glPopMatrix();
glColor4usv(defaultColor);
screenTexEnvMode(s, GL_REPLACE);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
void drawParticleSystems(CompScreen * s, CompWindow * w)
{
ANIM_WINDOW(w);
if (aw->numPs)
{
int i = 0;
for (i = 0; i < aw->numPs; i++)
{
if (aw->ps[i].active && !WINDOW_INVISIBLE(w))
{
drawParticles(s, w, &aw->ps[i]);
}
}
}
}
void updateParticles(ParticleSystem * ps, float time)
{
int i;
Particle *part;
float speed = (time / 50.0);
float slowdown = ps->slowdown * (1 - MAX(0.99, time / 1000.0)) * 1000;
ps->active = FALSE;
for (i = 0; i < ps->numParticles; i++)
{
part = &ps->particles[i];
if (part->life > 0.0f)
{
// move particle
part->x += part->xi / slowdown;
part->y += part->yi / slowdown;
part->z += part->zi / slowdown;
// modify speed
part->xi += part->xg * speed;
part->yi += part->yg * speed;
part->zi += part->zg * speed;
// modify life
part->life -= part->fade * speed;
ps->active = TRUE;
}
}
}
void finiParticles(ParticleSystem * ps)
{
free(ps->particles);
if (ps->tex)
glDeleteTextures(1, &ps->tex);
if (ps->vertices_cache)
free(ps->vertices_cache);
if (ps->colors_cache)
free(ps->colors_cache);
if (ps->coords_cache)
free(ps->coords_cache);
if (ps->dcolors_cache)
free(ps->dcolors_cache);
}
void
particlesUpdateBB (CompOutput *output,
CompWindow * w)
{
ANIM_WINDOW(w);
int i;
for (i = 0; i < aw->numPs; i++)
{
ParticleSystem * ps = &aw->ps[i];
if (ps->active)
{
int j;
for (j = 0; j < ps->numParticles; j++)
{
Particle *part = &ps->particles[j];
float w = part->width / 2;
float h = part->height / 2;
w += (w * part->w_mod) * part->life;
h += (h * part->h_mod) * part->life;
Box particleBox =
{part->x - w, part->x + w,
part->y - h, part->y + h};
expandBoxWithBox (&aw->BB, &particleBox);
}
}
}
if (aw->useDrawRegion)
{
int nClip = aw->drawRegion->numRects;
Box *pClip = aw->drawRegion->rects;
for (; nClip--; pClip++)
expandBoxWithBox (&aw->BB, pClip);
}
else // drawing full window
updateBBWindow (output, w);
}
syntax highlighted by Code2HTML, v. 0.9.1