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 void
fxMagicLampInitGrid(CompWindow * w,int * gridWidth,int * gridHeight)40 fxMagicLampInitGrid (CompWindow *w,
41 		     int *gridWidth, int *gridHeight)
42 {
43     *gridWidth = 2;
44     *gridHeight = animGetI (w, ANIM_SCREEN_OPTION_MAGIC_LAMP_GRID_RES);
45 }
46 
47 void
fxVacuumInitGrid(CompWindow * w,int * gridWidth,int * gridHeight)48 fxVacuumInitGrid (CompWindow *w,
49 		  int *gridWidth, int *gridHeight)
50 {
51     *gridWidth = 2;
52     *gridHeight = animGetI (w, ANIM_SCREEN_OPTION_VACUUM_GRID_RES);
53 }
54 
55 Bool
fxMagicLampInit(CompWindow * w)56 fxMagicLampInit (CompWindow * w)
57 {
58     ANIM_WINDOW(w);
59 
60     XRectangle *icon = &aw->com.icon;
61     int screenHeight = w->screen->height;
62     aw->minimizeToTop = (WIN_Y(w) + WIN_H(w) / 2) >
63 	(icon->y + icon->height / 2);
64     int maxWaves;
65     float waveAmpMin, waveAmpMax;
66     float distance;
67 
68     if (aw->com.curAnimEffect == AnimEffectMagicLamp)
69     {
70 	maxWaves = animGetI (w, ANIM_SCREEN_OPTION_MAGIC_LAMP_MAX_WAVES);
71 	waveAmpMin =
72 	    animGetF (w, ANIM_SCREEN_OPTION_MAGIC_LAMP_WAVE_AMP_MIN);
73 	waveAmpMax =
74 	    animGetF (w, ANIM_SCREEN_OPTION_MAGIC_LAMP_WAVE_AMP_MAX);
75     }
76     else
77     {
78 	maxWaves = 0;
79 	waveAmpMin = 0;
80 	waveAmpMax = 0;
81     }
82     if (waveAmpMax < waveAmpMin)
83 	waveAmpMax = waveAmpMin;
84 
85     if (maxWaves == 0)
86     {
87 	aw->magicLampWaveCount = 0;
88 	return TRUE;
89     }
90 
91     // Initialize waves
92 
93     if (aw->minimizeToTop)
94 	distance = WIN_Y(w) + WIN_H(w) - icon->y;
95     else
96 	distance = icon->y - WIN_Y(w);
97 
98     aw->magicLampWaveCount =
99 	1 + (float)maxWaves *distance / screenHeight;
100 
101     if (!(aw->magicLampWaves))
102     {
103 	aw->magicLampWaves =
104 	    calloc(aw->magicLampWaveCount, sizeof(WaveParam));
105 	if (!aw->magicLampWaves)
106 	{
107 	    compLogMessage ("animation", CompLogLevelError,
108 			    "Not enough memory");
109 	    return FALSE;
110 	}
111     }
112     // Compute wave parameters
113 
114     int ampDirection = (RAND_FLOAT() < 0.5 ? 1 : -1);
115     int i;
116     float minHalfWidth = 0.22f;
117     float maxHalfWidth = 0.38f;
118 
119     for (i = 0; i < aw->magicLampWaveCount; i++)
120     {
121 	aw->magicLampWaves[i].amp =
122 	    ampDirection * (waveAmpMax - waveAmpMin) *
123 	    rand() / RAND_MAX + ampDirection * waveAmpMin;
124 	aw->magicLampWaves[i].halfWidth =
125 	    RAND_FLOAT() * (maxHalfWidth -
126 			    minHalfWidth) + minHalfWidth;
127 
128 	// avoid offset at top and bottom part by added waves
129 	float availPos = 1 - 2 * aw->magicLampWaves[i].halfWidth;
130 	float posInAvailSegment = 0;
131 
132 	if (i > 0)
133 	    posInAvailSegment =
134 		(availPos / aw->magicLampWaveCount) * rand() / RAND_MAX;
135 
136 	aw->magicLampWaves[i].pos =
137 	    (posInAvailSegment +
138 	     i * availPos / aw->magicLampWaveCount +
139 	     aw->magicLampWaves[i].halfWidth);
140 
141 	// switch wave direction
142 	ampDirection *= -1;
143     }
144 
145     return TRUE;
146 }
147 
148 void
fxMagicLampModelStep(CompWindow * w,float time)149 fxMagicLampModelStep (CompWindow *w, float time)
150 {
151     defaultAnimStep (w, time);
152 
153     ANIM_WINDOW(w);
154 
155     Model *model = aw->com.model;
156     XRectangle *icon = &aw->com.icon;
157 
158     if ((aw->com.curWindowEvent == WindowEventOpen ||
159 	 aw->com.curWindowEvent == WindowEventClose) &&
160 	((aw->com.curAnimEffect == AnimEffectMagicLamp &&
161 	  animGetB (w, ANIM_SCREEN_OPTION_MAGIC_LAMP_MOVING_END)) ||
162 	 (aw->com.curAnimEffect == AnimEffectVacuum &&
163 	  animGetB (w, ANIM_SCREEN_OPTION_VACUUM_MOVING_END))))
164     {
165 	// Update icon position
166 	getMousePointerXY (w->screen, &icon->x, &icon->y);
167     }
168     float forwardProgress = defaultAnimProgress (w);
169 
170     if (aw->magicLampWaveCount > 0 && !aw->magicLampWaves)
171 	return;
172 
173     float iconCloseEndY;
174     float iconFarEndY;
175     float winFarEndY;
176     float winVisibleCloseEndY;
177 
178     float iconShadowLeft =
179 	((float)(w->output.left - w->input.left)) *
180 	icon->width / w->width;
181     float iconShadowRight =
182 	((float)(w->output.right - w->input.right)) *
183 	icon->width / w->width;
184 
185     float sigmoid0 = sigmoid(0);
186     float sigmoid1 = sigmoid(1);
187     float winw = WIN_W(w);
188     float winh = WIN_H(w);
189 
190     if (aw->minimizeToTop)
191     {
192 	iconFarEndY = icon->y;
193 	iconCloseEndY = icon->y + icon->height;
194 	winFarEndY = WIN_Y(w) + winh;
195 	winVisibleCloseEndY = WIN_Y(w);
196 	if (winVisibleCloseEndY < iconCloseEndY)
197 	    winVisibleCloseEndY = iconCloseEndY;
198     }
199     else
200     {
201 	iconFarEndY = icon->y + icon->height;
202 	iconCloseEndY = icon->y;
203 	winFarEndY = WIN_Y(w);
204 	winVisibleCloseEndY = WIN_Y(w) + winh;
205 	if (winVisibleCloseEndY > iconCloseEndY)
206 	    winVisibleCloseEndY = iconCloseEndY;
207     }
208 
209     float preShapePhaseEnd = 0.22f;
210     float preShapeProgress  = 0;
211     float postStretchProgress = 0;
212     float stretchProgress = 0;
213     float stretchPhaseEnd =
214 	preShapePhaseEnd + (1 - preShapePhaseEnd) *
215 	(iconCloseEndY -
216 	 winVisibleCloseEndY) / ((iconCloseEndY - winFarEndY) +
217 				 (iconCloseEndY - winVisibleCloseEndY));
218     if (stretchPhaseEnd < preShapePhaseEnd + 0.1)
219 	stretchPhaseEnd = preShapePhaseEnd + 0.1;
220 
221     if (forwardProgress < preShapePhaseEnd)
222     {
223 	preShapeProgress = forwardProgress / preShapePhaseEnd;
224 
225 	// Slow down "shaping" toward the end
226 	preShapeProgress = 1 - decelerateProgress(1 - preShapeProgress);
227     }
228 
229     if (forwardProgress < preShapePhaseEnd)
230     {
231 	stretchProgress = forwardProgress / stretchPhaseEnd;
232     }
233     else
234     {
235 	if (forwardProgress < stretchPhaseEnd)
236 	{
237 	    stretchProgress = forwardProgress / stretchPhaseEnd;
238 	}
239 	else
240 	{
241 	    postStretchProgress =
242 		(forwardProgress - stretchPhaseEnd) / (1 - stretchPhaseEnd);
243 	}
244     }
245 
246     Object *object = model->objects;
247     int i;
248     for (i = 0; i < model->numObjects; i++, object++)
249     {
250 	float origx = w->attrib.x + (winw * object->gridPosition.x -
251 				     w->output.left) * model->scale.x;
252 	float origy = w->attrib.y + (winh * object->gridPosition.y -
253 				     w->output.top) * model->scale.y;
254 
255 	float iconx =
256 	    (icon->x - iconShadowLeft) +
257 	    (icon->width + iconShadowLeft + iconShadowRight) *
258 	    object->gridPosition.x;
259 	float icony = icon->y + icon->height * object->gridPosition.y;
260 
261 	float stretchedPos;
262 	if (aw->minimizeToTop)
263 	    stretchedPos =
264 		object->gridPosition.y * origy +
265 		(1 - object->gridPosition.y) * icony;
266 	else
267 	    stretchedPos =
268 		(1 - object->gridPosition.y) * origy +
269 		object->gridPosition.y * icony;
270 
271 	// Compute current y position
272 	if (forwardProgress < preShapePhaseEnd)
273 	{
274 	    object->position.y =
275 		(1 - stretchProgress) * origy +
276 		stretchProgress * stretchedPos;
277 	}
278 	else
279 	{
280 	    if (forwardProgress < stretchPhaseEnd)
281 	    {
282 		object->position.y =
283 		    (1 - stretchProgress) * origy +
284 		    stretchProgress * stretchedPos;
285 	    }
286 	    else
287 	    {
288 		object->position.y =
289 		    (1 - postStretchProgress) *
290 		    stretchedPos +
291 		    postStretchProgress *
292 		    (stretchedPos + (iconCloseEndY - winFarEndY));
293 	    }
294 	}
295 
296 	// Compute "target shape" x position
297 	float fx = ((iconCloseEndY - object->position.y) /
298 		    (iconCloseEndY - winFarEndY));
299 	float fy = ((sigmoid(fx) - sigmoid0) /
300 		    (sigmoid1 - sigmoid0));
301 	float targetx = fy * (origx - iconx) + iconx;
302 
303 	// Apply waves
304 	int i;
305 	for (i = 0; i < aw->magicLampWaveCount; i++)
306 	{
307 	    float cosfx = ((fx - aw->magicLampWaves[i].pos) /
308 			   aw->magicLampWaves[i].halfWidth);
309 	    if (cosfx < -1 || cosfx > 1)
310 		continue;
311 	    targetx +=
312 		aw->magicLampWaves[i].amp * model->scale.x *
313 		(cos(cosfx * M_PI) + 1) / 2;
314 	}
315 
316 	// Compute current x position
317 	if (forwardProgress < preShapePhaseEnd)
318 	    object->position.x =
319 		(1 - preShapeProgress) * origx + preShapeProgress * targetx;
320 	else
321 	    object->position.x = targetx;
322 
323 	if (aw->minimizeToTop)
324 	{
325 	    if (object->position.y < iconFarEndY)
326 		object->position.y = iconFarEndY;
327 	}
328 	else
329 	{
330 	    if (object->position.y > iconFarEndY)
331 		object->position.y = iconFarEndY;
332 	}
333 
334 	// No need to set object->position.z to 0, since they won't be used
335 	// due to modelAnimIs3D being FALSE for magic lamp.
336     }
337 }
338 
339