/*
* 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"
// ===================== Effect: Zoom and Sidekick =========================
void fxSidekickInit(CompScreen * s, CompWindow * w)
{
ANIM_SCREEN(s);
ANIM_WINDOW(w);
// determine number of rotations randomly in [0.75, 1.25] range
aw->numZoomRotations =
animGetF(as, aw, ANIM_SCREEN_OPTION_SIDEKICK_NUM_ROTATIONS) *
(1.0f + 0.2f * rand() / RAND_MAX - 0.1f);
fxZoomInit(s, w);
}
static float
fxZoomGetSpringiness(AnimScreen *as, AnimWindow *aw)
{
if (aw->curAnimEffect == AnimEffectZoom)
return 2 * animGetF(as, aw, ANIM_SCREEN_OPTION_ZOOM_SPRINGINESS);
else if (aw->curAnimEffect == AnimEffectSidekick)
return 1.6 * animGetF(as, aw, ANIM_SCREEN_OPTION_SIDEKICK_SPRINGINESS);
else
return 0.0f;
}
void fxZoomInit(CompScreen * s, CompWindow * w)
{
ANIM_SCREEN(s);
ANIM_WINDOW(w);
if ((aw->curAnimEffect == AnimEffectSidekick &&
(animGetI(as, aw, ANIM_SCREEN_OPTION_SIDEKICK_ZOOM_FROM_CENTER) ==
ZoomFromCenterOn ||
((aw->curWindowEvent == WindowEventMinimize ||
aw->curWindowEvent == WindowEventUnminimize) &&
animGetI(as, aw, ANIM_SCREEN_OPTION_SIDEKICK_ZOOM_FROM_CENTER) ==
ZoomFromCenterMin) ||
((aw->curWindowEvent == WindowEventOpen ||
aw->curWindowEvent == WindowEventClose) &&
animGetI(as, aw, ANIM_SCREEN_OPTION_SIDEKICK_ZOOM_FROM_CENTER) ==
ZoomFromCenterCreate))) ||
(aw->curAnimEffect == AnimEffectZoom &&
(animGetI(as, aw, ANIM_SCREEN_OPTION_ZOOM_FROM_CENTER) ==
ZoomFromCenterOn ||
((aw->curWindowEvent == WindowEventMinimize ||
aw->curWindowEvent == WindowEventUnminimize) &&
animGetI(as, aw, ANIM_SCREEN_OPTION_ZOOM_FROM_CENTER) ==
ZoomFromCenterMin) ||
((aw->curWindowEvent == WindowEventOpen ||
aw->curWindowEvent == WindowEventClose) &&
animGetI(as, aw, ANIM_SCREEN_OPTION_ZOOM_FROM_CENTER) ==
ZoomFromCenterCreate))))
{
aw->icon.x =
WIN_X(w) + WIN_W(w) / 2 - aw->icon.width / 2;
aw->icon.y =
WIN_Y(w) + WIN_H(w) / 2 - aw->icon.height / 2;
}
// allow extra time for spring damping / deceleration
if ((aw->curWindowEvent == WindowEventUnminimize ||
aw->curWindowEvent == WindowEventOpen) &&
fxZoomGetSpringiness(as, aw) > 1e-4)
{
aw->animTotalTime /= SPRINGY_ZOOM_PERCEIVED_T;
}
else if ((aw->curAnimEffect == AnimEffectZoom ||
aw->curAnimEffect == AnimEffectSidekick) &&
(aw->curWindowEvent == WindowEventOpen ||
aw->curWindowEvent == WindowEventClose))
{
aw->animTotalTime /= NONSPRINGY_ZOOM_PERCEIVED_T;
}
else
{
aw->animTotalTime /= ZOOM_PERCEIVED_T;
}
aw->animRemainingTime = aw->animTotalTime;
defaultAnimInit(s, w);
}
void fxZoomAnimProgress(AnimScreen * as,
AnimWindow * aw,
float *moveProgress,
float *scaleProgress,
Bool neverSpringy)
{
float forwardProgress =
1 - aw->animRemainingTime /
(aw->animTotalTime - aw->timestep);
forwardProgress = MIN(forwardProgress, 1);
forwardProgress = MAX(forwardProgress, 0);
float x = forwardProgress;
Bool backwards = FALSE;
int animProgressDir = 1;
if (aw->curWindowEvent == WindowEventUnminimize ||
aw->curWindowEvent == WindowEventOpen)
animProgressDir = 2;
if (aw->animOverrideProgressDir != 0)
animProgressDir = aw->animOverrideProgressDir;
if ((animProgressDir == 1 &&
(aw->curWindowEvent == WindowEventUnminimize ||
aw->curWindowEvent == WindowEventOpen)) ||
(animProgressDir == 2 &&
(aw->curWindowEvent == WindowEventMinimize ||
aw->curWindowEvent == WindowEventClose)))
backwards = TRUE;
if (backwards)
x = 1 - x;
float dampBase = (pow(1-pow(x,1.2)*0.5,10)-pow(0.5,10))/(1-pow(0.5,10));
float nonSpringyProgress =
1 - pow(decelerateProgressCustom(1 - x, .5f, .8f), 1.7f);
if (moveProgress && scaleProgress)
{
float damping =
pow(dampBase, 0.5);
float damping2 =
((pow(1-(pow(x,0.7)*0.5),10)-pow(0.5,10))/(1-pow(0.5,10))) *
0.7 + 0.3;
float springiness = 0;
// springy only when appearing
if ((aw->curWindowEvent == WindowEventUnminimize ||
aw->curWindowEvent == WindowEventOpen) &&
!neverSpringy)
{
springiness = fxZoomGetSpringiness(as, aw);
}
float springyMoveProgress =
cos(2*M_PI*pow(x,1)*1.25) * damping * damping2;
if (springiness > 1e-4f)
{
if (x > 0.2)
{
springyMoveProgress *= springiness;
}
else
{
// interpolate between (springyMoveProgress * springiness)
// and springyMoveProgress for smooth transition at 0.2
// (where it crosses y=0)
float progressUpto02 = x / 0.2f;
springyMoveProgress =
(1 - progressUpto02) * springyMoveProgress +
progressUpto02 * springyMoveProgress * springiness;
}
*moveProgress = 1 - springyMoveProgress;
}
else
{
*moveProgress = nonSpringyProgress;
}
if (aw->curWindowEvent == WindowEventUnminimize ||
aw->curWindowEvent == WindowEventOpen)
*moveProgress = 1 - *moveProgress;
if (backwards)
*moveProgress = 1 - *moveProgress;
float scProgress = nonSpringyProgress;
if (aw->curWindowEvent == WindowEventUnminimize ||
aw->curWindowEvent == WindowEventOpen)
scProgress = 1 - scProgress;
if (backwards)
scProgress = 1 - scProgress;
*scaleProgress =
pow(scProgress, 1.25);
}
}
void
fxZoomUpdateWindowAttrib(AnimScreen * as,
CompWindow * w,
WindowPaintAttrib * wAttrib)
{
ANIM_WINDOW(w);
float forwardProgress;
float dummy;
fxZoomAnimProgress(as, aw, &dummy, &forwardProgress, FALSE);
wAttrib->opacity =
(GLushort) (aw->storedOpacity * (1 - forwardProgress));
}
void
applyZoomTransform (CompWindow * w, CompTransform *transform)
{
ANIM_SCREEN(w->screen);
ANIM_WINDOW(w);
Point winCenter =
{(WIN_X(w) + WIN_W(w) / 2.0),
(WIN_Y(w) + WIN_H(w) / 2.0)};
Point iconCenter =
{aw->icon.x + aw->icon.width / 2.0,
aw->icon.y + aw->icon.height / 2.0};
Point winSize =
{WIN_W(w), WIN_H(w)};
winSize.x = (winSize.x == 0 ? 1 : winSize.x);
winSize.y = (winSize.y == 0 ? 1 : winSize.y);
float scaleProgress;
float moveProgress;
float rotateProgress = 0;
if (aw->curAnimEffect == AnimEffectSidekick)
{
fxZoomAnimProgress(as, aw, &moveProgress, &scaleProgress, FALSE);
rotateProgress = moveProgress;
}
else if (aw->curAnimEffect == AnimEffectZoom)
{
fxZoomAnimProgress(as, aw, &moveProgress, &scaleProgress, FALSE);
}
else
{
// other effects use this for minimization
fxZoomAnimProgress(as, aw, &moveProgress, &scaleProgress, TRUE);
}
Point curCenter =
{(1 - moveProgress) * winCenter.x + moveProgress * iconCenter.x,
(1 - moveProgress) * winCenter.y + moveProgress * iconCenter.y};
Point curScale =
{((1 - scaleProgress) * winSize.x + scaleProgress * aw->icon.width) /
winSize.x,
((1 - scaleProgress) * winSize.y + scaleProgress * aw->icon.height) /
winSize.y};
if (fxZoomGetSpringiness(as, aw) == 0.0f &&
(aw->curAnimEffect == AnimEffectZoom ||
aw->curAnimEffect == AnimEffectSidekick) &&
(aw->curWindowEvent == WindowEventOpen ||
aw->curWindowEvent == WindowEventClose))
{
matrixTranslate (transform,
iconCenter.x, iconCenter.y, 0);
matrixScale (transform, curScale.x, curScale.y, 1.0f);
matrixTranslate (transform,
-iconCenter.x, -iconCenter.y, 0);
if (aw->curAnimEffect == AnimEffectSidekick)
{
matrixTranslate (transform, winCenter.x, winCenter.y, 0);
matrixRotate (transform, rotateProgress * 360 * aw->numZoomRotations,
0.0f, 0.0f, 1.0f);
matrixTranslate (transform, -winCenter.x, -winCenter.y, 0);
}
}
else
{
matrixTranslate (transform, winCenter.x, winCenter.y, 0);
float tx, ty;
if (aw->curAnimEffect != AnimEffectZoom)
{
// avoid parallelogram look
float maxScale = MAX(curScale.x, curScale.y);
matrixScale (transform, maxScale, maxScale, 1.0f);
tx = (curCenter.x - winCenter.x) / maxScale;
ty = (curCenter.y - winCenter.y) / maxScale;
}
else
{
matrixScale (transform, curScale.x, curScale.y, 1.0f);
tx = (curCenter.x - winCenter.x) / curScale.x;
ty = (curCenter.y - winCenter.y) / curScale.y;
}
matrixTranslate (transform, tx, ty, 0);
if (aw->curAnimEffect == AnimEffectSidekick)
{
matrixRotate (transform, rotateProgress * 360 * aw->numZoomRotations,
0.0f, 0.0f, 1.0f);
}
matrixTranslate (transform, -winCenter.x, -winCenter.y, 0);
}
}
void
fxZoomUpdateWindowTransform (CompScreen *s,
CompWindow *w,
CompTransform *wTransform)
{
ANIM_WINDOW(w);
// Apply transform to wTransform
matmul4 (wTransform->m, wTransform->m, aw->transform.m);
}
syntax highlighted by Code2HTML, v. 0.9.1