/*
* 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
fxMagicLampInitGrid(AnimScreen *as, AnimWindow *aw,
int *gridWidth, int *gridHeight)
{
*gridWidth = 2;
*gridHeight = animGetI(as, aw, ANIM_SCREEN_OPTION_MAGIC_LAMP_GRID_RES);
}
void
fxVacuumInitGrid(AnimScreen * as, AnimWindow *aw,
int *gridWidth, int *gridHeight)
{
*gridWidth = 2;
*gridHeight = animGetI(as, aw, ANIM_SCREEN_OPTION_VACUUM_GRID_RES);
}
void fxMagicLampInit(CompScreen * s, CompWindow * w)
{
ANIM_SCREEN(s);
ANIM_WINDOW(w);
Model *model = aw->model;
int screenHeight = s->height;
aw->minimizeToTop = (WIN_Y(w) + WIN_H(w) / 2) >
(aw->icon.y + aw->icon.height / 2);
int maxWaves;
float waveAmpMin, waveAmpMax;
if (aw->curAnimEffect == AnimEffectMagicLamp)
{
maxWaves = animGetI(as, aw, ANIM_SCREEN_OPTION_MAGIC_LAMP_MAX_WAVES);
waveAmpMin =
animGetF(as, aw, ANIM_SCREEN_OPTION_MAGIC_LAMP_WAVE_AMP_MIN);
waveAmpMax =
animGetF(as, aw, ANIM_SCREEN_OPTION_MAGIC_LAMP_WAVE_AMP_MAX);
}
else
{
maxWaves = 0;
waveAmpMin = 0;
waveAmpMax = 0;
}
if (waveAmpMax < waveAmpMin)
waveAmpMax = waveAmpMin;
if (maxWaves > 0)
{
float distance;
if (aw->minimizeToTop)
distance = WIN_Y(w) + WIN_H(w) - aw->icon.y;
else
distance = aw->icon.y - WIN_Y(w);
// Initialize waves
model->magicLampWaveCount =
1 + (float)maxWaves *distance / screenHeight;
if (!(model->magicLampWaves))
model->magicLampWaves =
calloc(model->magicLampWaveCount, sizeof(WaveParam));
int ampDirection = (RAND_FLOAT() < 0.5 ? 1 : -1);
int i;
float minHalfWidth = 0.22f;
float maxHalfWidth = 0.38f;
for (i = 0; i < model->magicLampWaveCount; i++)
{
model->magicLampWaves[i].amp =
ampDirection * (waveAmpMax - waveAmpMin) *
rand() / RAND_MAX + ampDirection * waveAmpMin;
model->magicLampWaves[i].halfWidth =
RAND_FLOAT() * (maxHalfWidth -
minHalfWidth) + minHalfWidth;
// avoid offset at top and bottom part by added waves
float availPos = 1 - 2 * model->magicLampWaves[i].halfWidth;
float posInAvailSegment = 0;
if (i > 0)
posInAvailSegment =
(availPos /
model->magicLampWaveCount) * rand() / RAND_MAX;
model->magicLampWaves[i].pos =
(posInAvailSegment +
i * availPos / model->magicLampWaveCount +
model->magicLampWaves[i].halfWidth);
// switch wave direction
ampDirection *= -1;
}
}
else
model->magicLampWaveCount = 0;
}
static void
fxMagicLampModelStepObject(CompWindow * w,
Model * model,
Object * object,
float forwardProgress)
{
ANIM_WINDOW(w);
float iconCloseEndY;
float iconFarEndY;
float winFarEndY;
float winVisibleCloseEndY;
if (aw->minimizeToTop)
{
iconFarEndY = aw->icon.y;
iconCloseEndY = aw->icon.y + aw->icon.height;
winFarEndY = WIN_Y(w) + WIN_H(w);
winVisibleCloseEndY = WIN_Y(w);
if (winVisibleCloseEndY < iconCloseEndY)
winVisibleCloseEndY = iconCloseEndY;
}
else
{
iconFarEndY = aw->icon.y + aw->icon.height;
iconCloseEndY = aw->icon.y;
winFarEndY = WIN_Y(w);
winVisibleCloseEndY = WIN_Y(w) + WIN_H(w);
if (winVisibleCloseEndY > iconCloseEndY)
winVisibleCloseEndY = iconCloseEndY;
}
float preShapePhaseEnd = 0.22f;
float stretchPhaseEnd =
preShapePhaseEnd + (1 - preShapePhaseEnd) *
(iconCloseEndY -
winVisibleCloseEndY) / ((iconCloseEndY - winFarEndY) +
(iconCloseEndY - winVisibleCloseEndY));
if (stretchPhaseEnd < preShapePhaseEnd + 0.1)
stretchPhaseEnd = preShapePhaseEnd + 0.1;
float origx = w->attrib.x + (WIN_W(w) * object->gridPosition.x -
w->output.left) * model->scale.x;
float origy = w->attrib.y + (WIN_H(w) * object->gridPosition.y -
w->output.top) * model->scale.y;
float iconShadowLeft =
((float)(w->output.left - w->input.left)) *
aw->icon.width / w->width;
float iconShadowRight =
((float)(w->output.right - w->input.right)) *
aw->icon.width / w->width;
float iconx =
(aw->icon.x - iconShadowLeft) +
(aw->icon.width + iconShadowLeft + iconShadowRight) *
object->gridPosition.x;
float icony = aw->icon.y + aw->icon.height * object->gridPosition.y;
float stretchedPos;
if (aw->minimizeToTop)
stretchedPos =
object->gridPosition.y * origy +
(1 - object->gridPosition.y) * icony;
else
stretchedPos =
(1 - object->gridPosition.y) * origy +
object->gridPosition.y * icony;
if (forwardProgress < preShapePhaseEnd)
{
float preShapeProgress = forwardProgress / preShapePhaseEnd;
float stretchProgress = forwardProgress / stretchPhaseEnd;
float fx = (iconCloseEndY - object->position.y) /
(iconCloseEndY - winFarEndY);
float fy = (sigmoid(fx) - sigmoid(0)) / (sigmoid(1) - sigmoid(0));
float targetx = fy * (origx - iconx) + iconx;
int i;
for (i = 0; i < model->magicLampWaveCount; i++)
{
float cosfx =
(fx - model->magicLampWaves[i].pos) /
model->magicLampWaves[i].halfWidth;
if (cosfx < -1 || cosfx > 1)
continue;
targetx +=
model->magicLampWaves[i].amp * model->scale.x *
(cos(cosfx * M_PI) + 1) / 2;
}
preShapeProgress = 1 - decelerateProgress(1 - preShapeProgress);
object->position.x =
(1 - preShapeProgress) * origx + preShapeProgress * targetx;
object->position.y =
(1 - stretchProgress) * origy +
stretchProgress * stretchedPos;
}
else
{
if (forwardProgress < stretchPhaseEnd)
{
float stretchProgress = forwardProgress / stretchPhaseEnd;
object->position.y =
(1 - stretchProgress) * origy +
stretchProgress * stretchedPos;
}
else
{
float postStretchProgress =
(forwardProgress - stretchPhaseEnd) / (1 - stretchPhaseEnd);
object->position.y =
(1 - postStretchProgress) *
stretchedPos +
postStretchProgress *
(stretchedPos + (iconCloseEndY - winFarEndY));
}
float fx =
(iconCloseEndY - object->position.y) / (iconCloseEndY -
winFarEndY);
float fy = (sigmoid(fx) - sigmoid(0)) / (sigmoid(1) - sigmoid(0));
int i;
object->position.x = fy * (origx - iconx) + iconx;
for (i = 0; i < model->magicLampWaveCount; i++)
{
float cosfx =
(fx -
model->magicLampWaves[i].pos) /
model->magicLampWaves[i].halfWidth;
if (cosfx < -1 || cosfx > 1)
continue;
object->position.x +=
model->magicLampWaves[i].amp * model->scale.x *
(cos(cosfx * M_PI) + 1) / 2;
}
}
if (aw->minimizeToTop)
{
if (object->position.y < iconFarEndY)
object->position.y = iconFarEndY;
}
else
{
if (object->position.y > iconFarEndY)
object->position.y = iconFarEndY;
}
}
Bool fxMagicLampModelStep(CompScreen * s, CompWindow * w, float time)
{
if (!defaultAnimStep(s, w, time))
return FALSE;
ANIM_SCREEN(s);
ANIM_WINDOW(w);
Model *model = aw->model;
if ((aw->curWindowEvent == WindowEventOpen ||
aw->curWindowEvent == WindowEventClose) &&
((aw->curAnimEffect == AnimEffectMagicLamp &&
animGetB(as, aw, ANIM_SCREEN_OPTION_MAGIC_LAMP_MOVING_END)) ||
(aw->curAnimEffect == AnimEffectVacuum &&
animGetB(as, aw, ANIM_SCREEN_OPTION_VACUUM_MOVING_END))))
{
// Update icon position
getMousePointerXY(s, &aw->icon.x, &aw->icon.y);
}
float forwardProgress = defaultAnimProgress(aw);
int i;
for (i = 0; i < model->numObjects; i++)
fxMagicLampModelStepObject(w, model, &model->objects[i],
forwardProgress);
return TRUE;
}
syntax highlighted by Code2HTML, v. 0.9.1