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 "animation-internal.h"
38
39 // ===================== Effect: Zoom and Sidekick =========================
40
41 Bool
fxSidekickInit(CompWindow * w)42 fxSidekickInit (CompWindow * w)
43 {
44 ANIM_WINDOW(w);
45
46 // determine number of rotations randomly in [0.9, 1.1] range
47 aw->numZoomRotations =
48 animGetF (w, ANIM_SCREEN_OPTION_SIDEKICK_NUM_ROTATIONS) *
49 (1.0f + 0.2f * rand() / RAND_MAX - 0.1f);
50
51 float winCenterX = WIN_X(w) + WIN_W(w) / 2.0;
52 float iconCenterX = aw->com.icon.x + aw->com.icon.width / 2.0;
53
54 // if window is to the right of icon, rotate clockwise instead
55 // to make rotation look more pleasant
56 if (winCenterX > iconCenterX)
57 aw->numZoomRotations *= -1;
58
59 return fxZoomInit (w);
60 }
61
62 static float
fxZoomGetSpringiness(CompWindow * w)63 fxZoomGetSpringiness (CompWindow *w)
64 {
65 ANIM_WINDOW(w);
66
67 if (aw->com.curAnimEffect == AnimEffectZoom)
68 return 2 * animGetF (w, ANIM_SCREEN_OPTION_ZOOM_SPRINGINESS);
69 else if (aw->com.curAnimEffect == AnimEffectSidekick)
70 return 1.6 * animGetF (w, ANIM_SCREEN_OPTION_SIDEKICK_SPRINGINESS);
71 else
72 return 0.0f;
73 }
74
75 Bool
fxZoomInit(CompWindow * w)76 fxZoomInit (CompWindow * w)
77 {
78 ANIM_WINDOW(w);
79
80 if ((aw->com.curAnimEffect == AnimEffectSidekick &&
81 (animGetI (w, ANIM_SCREEN_OPTION_SIDEKICK_ZOOM_FROM_CENTER) ==
82 ZoomFromCenterOn ||
83 ((aw->com.curWindowEvent == WindowEventMinimize ||
84 aw->com.curWindowEvent == WindowEventUnminimize) &&
85 animGetI (w, ANIM_SCREEN_OPTION_SIDEKICK_ZOOM_FROM_CENTER) ==
86 ZoomFromCenterMin) ||
87 ((aw->com.curWindowEvent == WindowEventOpen ||
88 aw->com.curWindowEvent == WindowEventClose) &&
89 animGetI (w, ANIM_SCREEN_OPTION_SIDEKICK_ZOOM_FROM_CENTER) ==
90 ZoomFromCenterCreate))) ||
91 (aw->com.curAnimEffect == AnimEffectZoom &&
92 (animGetI (w, ANIM_SCREEN_OPTION_ZOOM_FROM_CENTER) ==
93 ZoomFromCenterOn ||
94 ((aw->com.curWindowEvent == WindowEventMinimize ||
95 aw->com.curWindowEvent == WindowEventUnminimize) &&
96 animGetI (w, ANIM_SCREEN_OPTION_ZOOM_FROM_CENTER) ==
97 ZoomFromCenterMin) ||
98 ((aw->com.curWindowEvent == WindowEventOpen ||
99 aw->com.curWindowEvent == WindowEventClose) &&
100 animGetI (w, ANIM_SCREEN_OPTION_ZOOM_FROM_CENTER) ==
101 ZoomFromCenterCreate))))
102 {
103 aw->com.icon.x =
104 WIN_X(w) + WIN_W(w) / 2 - aw->com.icon.width / 2;
105 aw->com.icon.y =
106 WIN_Y(w) + WIN_H(w) / 2 - aw->com.icon.height / 2;
107 }
108
109 // allow extra time for spring damping / deceleration
110 if ((aw->com.curWindowEvent == WindowEventUnminimize ||
111 aw->com.curWindowEvent == WindowEventOpen) &&
112 fxZoomGetSpringiness (w) > 1e-4)
113 {
114 aw->com.animTotalTime /= SPRINGY_ZOOM_PERCEIVED_T;
115 }
116 else if ((aw->com.curAnimEffect == AnimEffectZoom ||
117 aw->com.curAnimEffect == AnimEffectSidekick) &&
118 (aw->com.curWindowEvent == WindowEventOpen ||
119 aw->com.curWindowEvent == WindowEventClose))
120 {
121 aw->com.animTotalTime /= NONSPRINGY_ZOOM_PERCEIVED_T;
122 }
123 else
124 {
125 aw->com.animTotalTime /= ZOOM_PERCEIVED_T;
126 }
127 aw->com.animRemainingTime = aw->com.animTotalTime;
128
129 aw->com.usingTransform = TRUE;
130
131 return defaultAnimInit (w);
132 }
133
fxZoomAnimProgress(CompWindow * w,float * moveProgress,float * scaleProgress,Bool neverSpringy)134 void fxZoomAnimProgress (CompWindow *w,
135 float *moveProgress,
136 float *scaleProgress,
137 Bool neverSpringy)
138 {
139 ANIM_WINDOW(w);
140
141 float forwardProgress =
142 1 - aw->com.animRemainingTime /
143 (aw->com.animTotalTime - aw->com.timestep);
144 forwardProgress = MIN(forwardProgress, 1);
145 forwardProgress = MAX(forwardProgress, 0);
146
147 float x = forwardProgress;
148 Bool backwards = FALSE;
149 int animProgressDir = 1;
150
151 if (aw->com.curWindowEvent == WindowEventUnminimize ||
152 aw->com.curWindowEvent == WindowEventOpen)
153 animProgressDir = 2;
154 if (aw->com.animOverrideProgressDir != 0)
155 animProgressDir = aw->com.animOverrideProgressDir;
156 if ((animProgressDir == 1 &&
157 (aw->com.curWindowEvent == WindowEventUnminimize ||
158 aw->com.curWindowEvent == WindowEventOpen)) ||
159 (animProgressDir == 2 &&
160 (aw->com.curWindowEvent == WindowEventMinimize ||
161 aw->com.curWindowEvent == WindowEventClose)))
162 backwards = TRUE;
163 if (backwards)
164 x = 1 - x;
165
166 float dampBase = (pow(1-pow(x,1.2)*0.5,10)-pow(0.5,10))/(1-pow(0.5,10));
167 float nonSpringyProgress =
168 1 - pow(decelerateProgressCustom(1 - x, .5f, .8f), 1.7f);
169
170 if (moveProgress && scaleProgress)
171 {
172 float damping =
173 pow(dampBase, 0.5);
174
175 float damping2 =
176 ((pow(1-(pow(x,0.7)*0.5),10)-pow(0.5,10))/(1-pow(0.5,10))) *
177 0.7 + 0.3;
178 float springiness = 0;
179
180 // springy only when appearing
181 if ((aw->com.curWindowEvent == WindowEventUnminimize ||
182 aw->com.curWindowEvent == WindowEventOpen) &&
183 !neverSpringy)
184 {
185 springiness = fxZoomGetSpringiness (w);
186 }
187
188 float springyMoveProgress =
189 cos(2*M_PI*pow(x,1)*1.25) * damping * damping2;
190
191 if (springiness > 1e-4f)
192 {
193 if (x > 0.2)
194 {
195 springyMoveProgress *= springiness;
196 }
197 else
198 {
199 // interpolate between (springyMoveProgress * springiness)
200 // and springyMoveProgress for smooth transition at 0.2
201 // (where it crosses y=0)
202 float progressUpto02 = x / 0.2f;
203 springyMoveProgress =
204 (1 - progressUpto02) * springyMoveProgress +
205 progressUpto02 * springyMoveProgress * springiness;
206 }
207 *moveProgress = 1 - springyMoveProgress;
208 }
209 else
210 {
211 *moveProgress = nonSpringyProgress;
212 }
213 if (aw->com.curWindowEvent == WindowEventUnminimize ||
214 aw->com.curWindowEvent == WindowEventOpen)
215 *moveProgress = 1 - *moveProgress;
216 if (backwards)
217 *moveProgress = 1 - *moveProgress;
218
219 float scProgress = nonSpringyProgress;
220 if (aw->com.curWindowEvent == WindowEventUnminimize ||
221 aw->com.curWindowEvent == WindowEventOpen)
222 scProgress = 1 - scProgress;
223 if (backwards)
224 scProgress = 1 - scProgress;
225
226 *scaleProgress =
227 pow(scProgress, 1.25);
228 }
229 }
230
231 void
fxZoomUpdateWindowAttrib(CompWindow * w,WindowPaintAttrib * wAttrib)232 fxZoomUpdateWindowAttrib (CompWindow * w,
233 WindowPaintAttrib * wAttrib)
234 {
235 ANIM_WINDOW(w);
236
237 float forwardProgress;
238 float dummy;
239
240 fxZoomAnimProgress (w, &dummy, &forwardProgress, FALSE);
241
242 wAttrib->opacity =
243 (GLushort) (aw->com.storedOpacity * (1 - forwardProgress));
244 }
245
246 static void
getZoomCenterScaleFull(CompWindow * w,Point * pCurCenter,Point * pCurScale,Point * pWinCenter,Point * pIconCenter,float * pRotateProgress)247 getZoomCenterScaleFull (CompWindow *w,
248 Point *pCurCenter, Point *pCurScale,
249 Point *pWinCenter, Point *pIconCenter,
250 float *pRotateProgress)
251 {
252 ANIM_WINDOW(w);
253
254 Point winCenter =
255 {(WIN_X(w) + WIN_W(w) / 2.0),
256 (WIN_Y(w) + WIN_H(w) / 2.0)};
257 Point iconCenter =
258 {aw->com.icon.x + aw->com.icon.width / 2.0,
259 aw->com.icon.y + aw->com.icon.height / 2.0};
260 Point winSize =
261 {WIN_W(w), WIN_H(w)};
262 winSize.x = (winSize.x == 0 ? 1 : winSize.x);
263 winSize.y = (winSize.y == 0 ? 1 : winSize.y);
264
265 float scaleProgress;
266 float moveProgress;
267 float rotateProgress = 0;
268
269 if (aw->com.curAnimEffect == AnimEffectSidekick)
270 {
271 fxZoomAnimProgress (w, &moveProgress, &scaleProgress, FALSE);
272 rotateProgress = moveProgress;
273 }
274 else if (aw->com.curAnimEffect == AnimEffectZoom)
275 {
276 fxZoomAnimProgress (w, &moveProgress, &scaleProgress, FALSE);
277 }
278 else
279 {
280 // other effects use this for minimization
281 fxZoomAnimProgress (w, &moveProgress, &scaleProgress, TRUE);
282 }
283
284 Point curCenter =
285 {(1 - moveProgress) * winCenter.x + moveProgress * iconCenter.x,
286 (1 - moveProgress) * winCenter.y + moveProgress * iconCenter.y};
287 Point curScale =
288 {((1 - scaleProgress) * winSize.x + scaleProgress * aw->com.icon.width) /
289 winSize.x,
290 ((1 - scaleProgress) * winSize.y + scaleProgress * aw->com.icon.height) /
291 winSize.y};
292
293 // Copy calculated variables
294 if (pCurCenter)
295 *pCurCenter = curCenter;
296 if (pCurScale)
297 *pCurScale = curScale;
298 if (pWinCenter)
299 *pWinCenter = winCenter;
300 if (pIconCenter)
301 *pIconCenter = iconCenter;
302 if (pRotateProgress)
303 *pRotateProgress = rotateProgress;
304 }
305
306 inline void
getZoomCenterScale(CompWindow * w,Point * pCurCenter,Point * pCurScale)307 getZoomCenterScale (CompWindow *w,
308 Point *pCurCenter, Point *pCurScale)
309 {
310 getZoomCenterScaleFull (w, pCurCenter, pCurScale, NULL, NULL, NULL);
311 }
312
313 void
applyZoomTransform(CompWindow * w)314 applyZoomTransform (CompWindow * w)
315 {
316 ANIM_WINDOW(w);
317
318 CompTransform *transform = &aw->com.transform;
319
320 Point curCenter;
321 Point curScale;
322 Point winCenter;
323 Point iconCenter;
324 float rotateProgress;
325
326 getZoomCenterScaleFull (w, &curCenter, &curScale,
327 &winCenter, &iconCenter, &rotateProgress);
328
329 if (fxZoomGetSpringiness (w) == 0.0f &&
330 (aw->com.curAnimEffect == AnimEffectZoom ||
331 aw->com.curAnimEffect == AnimEffectSidekick) &&
332 (aw->com.curWindowEvent == WindowEventOpen ||
333 aw->com.curWindowEvent == WindowEventClose))
334 {
335 matrixTranslate (transform,
336 iconCenter.x, iconCenter.y, 0);
337 matrixScale (transform, curScale.x, curScale.y, curScale.y);
338 matrixTranslate (transform,
339 -iconCenter.x, -iconCenter.y, 0);
340
341 if (aw->com.curAnimEffect == AnimEffectSidekick)
342 {
343 matrixTranslate (transform, winCenter.x, winCenter.y, 0);
344 matrixRotate (transform, rotateProgress * 360 * aw->numZoomRotations,
345 0.0f, 0.0f, 1.0f);
346 matrixTranslate (transform, -winCenter.x, -winCenter.y, 0);
347 }
348 }
349 else
350 {
351 matrixTranslate (transform, winCenter.x, winCenter.y, 0);
352 float tx, ty;
353 if (aw->com.curAnimEffect != AnimEffectZoom)
354 {
355 // avoid parallelogram look
356 float maxScale = MAX(curScale.x, curScale.y);
357 matrixScale (transform, maxScale, maxScale, maxScale);
358 tx = (curCenter.x - winCenter.x) / maxScale;
359 ty = (curCenter.y - winCenter.y) / maxScale;
360 }
361 else
362 {
363 matrixScale (transform, curScale.x, curScale.y, curScale.y);
364 tx = (curCenter.x - winCenter.x) / curScale.x;
365 ty = (curCenter.y - winCenter.y) / curScale.y;
366 }
367 matrixTranslate (transform, tx, ty, 0);
368 if (aw->com.curAnimEffect == AnimEffectSidekick)
369 {
370 matrixRotate (transform, rotateProgress * 360 * aw->numZoomRotations,
371 0.0f, 0.0f, 1.0f);
372 }
373 matrixTranslate (transform, -winCenter.x, -winCenter.y, 0);
374 }
375 }
376
377