~vanvugt/compiz-plugins-main/fix-915236

« back to all changes in this revision

Viewing changes to animation/src/magiclamp.cpp

  • Committer: Sam Spilsbury
  • Date: 2011-08-12 06:41:38 UTC
  • Revision ID: sam.spilsbury@canonical.com-20110812064138-sg45sswip9zgk0og
Sync in changes from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "private.h"
 
38
 
 
39
// =====================  Effect: Magic Lamp  =========================
 
40
 
 
41
void
 
42
MagicLampAnim::initGrid ()
 
43
{
 
44
    mGridWidth = 2;
 
45
    mGridHeight = optValI (AnimationOptions::MagicLampGridRes);
 
46
}
 
47
 
 
48
void
 
49
MagicLampWavyAnim::initGrid ()
 
50
{
 
51
    mGridWidth = 2;
 
52
    mGridHeight = optValI (AnimationOptions::MagicLampWavyGridRes);
 
53
}
 
54
 
 
55
MagicLampAnim::MagicLampAnim (CompWindow *w,
 
56
                              WindowEvent curWindowEvent,
 
57
                              float duration,
 
58
                              const AnimEffect info,
 
59
                              const CompRect &icon) :
 
60
    Animation::Animation (w, curWindowEvent, duration, info, icon),
 
61
    GridAnim::GridAnim (w, curWindowEvent, duration, info, icon)
 
62
{
 
63
    CompRect outRect (mAWindow->savedRectsValid () ?
 
64
                      mAWindow->savedOutRect () :
 
65
                      w->outputRect ());
 
66
 
 
67
    mTargetTop = ((outRect.y () + outRect.height () / 2) >
 
68
                  (icon.y () + icon.height () / 2));
 
69
 
 
70
    mUseQTexCoord = true;
 
71
}
 
72
 
 
73
MagicLampWavyAnim::MagicLampWavyAnim (CompWindow *w,
 
74
                                      WindowEvent curWindowEvent,
 
75
                                      float duration,
 
76
                                      const AnimEffect info,
 
77
                                      const CompRect &icon) :
 
78
    Animation::Animation (w, curWindowEvent, duration, info, icon),
 
79
    MagicLampAnim::MagicLampAnim (w, curWindowEvent, duration, info, icon)
 
80
{
 
81
    unsigned int maxWaves;
 
82
    float waveAmpMin, waveAmpMax;
 
83
    float distance;
 
84
 
 
85
    maxWaves = (unsigned) optValI (AnimationOptions::MagicLampWavyMaxWaves);
 
86
    waveAmpMin = optValF (AnimationOptions::MagicLampWavyAmpMin);
 
87
    waveAmpMax = optValF (AnimationOptions::MagicLampWavyAmpMax);
 
88
 
 
89
    if (waveAmpMax < waveAmpMin)
 
90
        waveAmpMax = waveAmpMin;
 
91
 
 
92
    // Initialize waves
 
93
 
 
94
    CompRect outRect (mAWindow->savedRectsValid () ?
 
95
                      mAWindow->savedOutRect () :
 
96
                      w->outputRect ());
 
97
    if (mTargetTop)
 
98
        distance = outRect.y () + outRect.height () - mIcon.y ();
 
99
    else
 
100
        distance = mIcon.y () - outRect.y ();
 
101
 
 
102
    mNumWaves =
 
103
        1 + (float)maxWaves *distance / ::screen->height ();
 
104
 
 
105
    mWaves = new WaveParam[mNumWaves];
 
106
 
 
107
    // Compute wave parameters
 
108
 
 
109
    int ampDirection = (RAND_FLOAT () < 0.5 ? 1 : -1);
 
110
    float minHalfWidth = 0.22f;
 
111
    float maxHalfWidth = 0.38f;
 
112
 
 
113
    for (unsigned int i = 0; i < mNumWaves; i++)
 
114
    {
 
115
        mWaves[i].amp =
 
116
            ampDirection * (waveAmpMax - waveAmpMin) *
 
117
            rand () / RAND_MAX + ampDirection * waveAmpMin;
 
118
        mWaves[i].halfWidth =
 
119
            RAND_FLOAT () * (maxHalfWidth - minHalfWidth) + minHalfWidth;
 
120
 
 
121
        // avoid offset at top and bottom part by added waves
 
122
        float availPos = 1 - 2 * mWaves[i].halfWidth;
 
123
        float posInAvailSegment = 0;
 
124
 
 
125
        if (i > 0)
 
126
            posInAvailSegment =
 
127
                (availPos / mNumWaves) * RAND_FLOAT ();
 
128
 
 
129
        mWaves[i].pos =
 
130
            (posInAvailSegment +
 
131
             i * availPos / mNumWaves +
 
132
             mWaves[i].halfWidth);
 
133
 
 
134
        // switch wave direction
 
135
        ampDirection *= -1;
 
136
    }
 
137
}
 
138
 
 
139
MagicLampWavyAnim::~MagicLampWavyAnim ()
 
140
{
 
141
    delete[] mWaves;
 
142
}
 
143
 
 
144
/// Makes sure the window gets fully damaged with
 
145
/// effects that possibly have models that don't cover
 
146
/// the whole window (like in MagicLampAnim with menus).
 
147
MagicLampAnim::~MagicLampAnim ()
 
148
{
 
149
    if (mCurWindowEvent == WindowEventOpen ||
 
150
        mCurWindowEvent == WindowEventUnminimize ||
 
151
        mCurWindowEvent == WindowEventUnshade)
 
152
    {
 
153
        mAWindow->expandBBWithWindow ();
 
154
    }
 
155
}
 
156
 
 
157
bool
 
158
MagicLampWavyAnim::hasMovingEnd ()
 
159
{
 
160
    return optValB (AnimationOptions::MagicLampWavyMovingEnd);
 
161
}
 
162
 
 
163
bool
 
164
MagicLampAnim::hasMovingEnd ()
 
165
{
 
166
    return optValB (AnimationOptions::MagicLampMovingEnd);
 
167
}
 
168
 
 
169
/// Applies waves (at each step of the animation).
 
170
void
 
171
MagicLampWavyAnim::filterTargetX (float &targetX, float x)
 
172
{
 
173
    for (unsigned int i = 0; i < mNumWaves; i++)
 
174
    {
 
175
        float cosx = ((x - mWaves[i].pos) /
 
176
                       mWaves[i].halfWidth);
 
177
        if (cosx < -1 || cosx > 1)
 
178
            continue;
 
179
        targetX += (mWaves[i].amp * mModel->scale ().x () *
 
180
                    (cos (cosx * M_PI) + 1) / 2);
 
181
    }
 
182
}
 
183
 
 
184
void
 
185
MagicLampAnim::step ()
 
186
{
 
187
    if ((curWindowEvent () == WindowEventOpen ||
 
188
         curWindowEvent () == WindowEventClose) &&
 
189
        hasMovingEnd ())
 
190
    {
 
191
        short x, y;
 
192
        // Update icon position
 
193
        AnimScreen::get (::screen)->getMousePointerXY (&x, &y);
 
194
        mIcon.setX (x);
 
195
        mIcon.setY (y);
 
196
    }
 
197
    float forwardProgress = progressLinear ();
 
198
 
 
199
    float iconCloseEndY;
 
200
    float iconFarEndY;
 
201
    float winFarEndY;
 
202
    float winVisibleCloseEndY;
 
203
 
 
204
    CompRect inRect (mAWindow->savedRectsValid () ?
 
205
                     mAWindow->savedInRect () :
 
206
                     mWindow->borderRect ());
 
207
    CompRect outRect (mAWindow->savedRectsValid () ?
 
208
                      mAWindow->savedOutRect () :
 
209
                      mWindow->outputRect ());
 
210
    CompWindowExtents outExtents (mAWindow->savedRectsValid () ?
 
211
                                  mAWindow->savedOutExtents () :
 
212
                                  mWindow->output ());
 
213
 
 
214
    float iconShadowLeft =
 
215
        ((float)(outRect.x () - inRect.x ())) *
 
216
        mIcon.width () / mWindow->width ();
 
217
    float iconShadowRight =
 
218
        ((float)(outRect.x2 () - inRect.x2 ())) *
 
219
        mIcon.width () / mWindow->width ();
 
220
 
 
221
    float sigmoid0 = sigmoid (0);
 
222
    float sigmoid1 = sigmoid (1);
 
223
 
 
224
    float winw = outRect.width ();
 
225
    float winh = outRect.height ();
 
226
 
 
227
    if (mTargetTop)
 
228
    {
 
229
        iconFarEndY = mIcon.y ();
 
230
        iconCloseEndY = mIcon.y () + mIcon.height ();
 
231
        winFarEndY = outRect.y () + winh;
 
232
        winVisibleCloseEndY = outRect.y ();
 
233
        if (winVisibleCloseEndY < iconCloseEndY)
 
234
            winVisibleCloseEndY = iconCloseEndY;
 
235
    }
 
236
    else
 
237
    {
 
238
        iconFarEndY = mIcon.y () + mIcon.height ();
 
239
        iconCloseEndY = mIcon.y ();
 
240
        winFarEndY = outRect.y ();
 
241
        winVisibleCloseEndY = outRect.y () + winh;
 
242
        if (winVisibleCloseEndY > iconCloseEndY)
 
243
            winVisibleCloseEndY = iconCloseEndY;
 
244
    }
 
245
 
 
246
    float preShapePhaseEnd = 0.22f;
 
247
    float preShapeProgress  = 0;
 
248
    float postStretchProgress = 0;
 
249
    float stretchProgress = 0;
 
250
    float stretchPhaseEnd =
 
251
        preShapePhaseEnd + (1 - preShapePhaseEnd) *
 
252
        (iconCloseEndY -
 
253
         winVisibleCloseEndY) / ((iconCloseEndY - winFarEndY) +
 
254
                                 (iconCloseEndY - winVisibleCloseEndY));
 
255
    if (stretchPhaseEnd < preShapePhaseEnd + 0.1)
 
256
        stretchPhaseEnd = preShapePhaseEnd + 0.1;
 
257
 
 
258
    if (forwardProgress < preShapePhaseEnd)
 
259
    {
 
260
        preShapeProgress = forwardProgress / preShapePhaseEnd;
 
261
 
 
262
        // Slow down "shaping" toward the end
 
263
        preShapeProgress = 1 - progressDecelerate (1 - preShapeProgress);
 
264
    }
 
265
 
 
266
    if (forwardProgress < preShapePhaseEnd)
 
267
    {
 
268
        stretchProgress = forwardProgress / stretchPhaseEnd;
 
269
    }
 
270
    else
 
271
    {
 
272
        if (forwardProgress < stretchPhaseEnd)
 
273
        {
 
274
            stretchProgress = forwardProgress / stretchPhaseEnd;
 
275
        }
 
276
        else
 
277
        {
 
278
            postStretchProgress =
 
279
                (forwardProgress - stretchPhaseEnd) / (1 - stretchPhaseEnd);
 
280
        }
 
281
    }
 
282
 
 
283
    // The other objects are squeezed into a horizontal line behind the icon
 
284
    int topmostMovingObjectIdx = -1;
 
285
    int bottommostMovingObjectIdx = -1;
 
286
 
 
287
    unsigned int n = mModel->numObjects ();
 
288
    float fx;
 
289
    GridModel::GridObject *object = mModel->objects ();
 
290
    for (unsigned int i = 0; i < n; i++, object++)
 
291
    {
 
292
        Point3d &objPos = object->position ();
 
293
        float objGridX = object->gridPosition ().x ();
 
294
 
 
295
        if (i % 2 == 0) // object is at the left side
 
296
        {
 
297
            float objGridY = object->gridPosition ().y ();
 
298
 
 
299
            float origY = (mWindow->y () +
 
300
                           (winh * objGridY - outExtents.top) *
 
301
                           mModel->scale ().y ());
 
302
            float iconY = (mIcon.y () + mIcon.height () * objGridY);
 
303
 
 
304
            float stretchedPos;
 
305
            if (mTargetTop)
 
306
                stretchedPos = objGridY * origY + (1 - objGridY) * iconY;
 
307
            else
 
308
                stretchedPos = (1 - objGridY) * origY + objGridY * iconY;
 
309
 
 
310
            // Compute current y position
 
311
            if (forwardProgress < preShapePhaseEnd)
 
312
            {
 
313
                objPos.setY ((1 - stretchProgress) * origY +
 
314
                             stretchProgress * stretchedPos);
 
315
            }
 
316
            else
 
317
            {
 
318
                if (forwardProgress < stretchPhaseEnd)
 
319
                {
 
320
                    objPos.setY ((1 - stretchProgress) * origY +
 
321
                                 stretchProgress * stretchedPos);
 
322
                }
 
323
                else
 
324
                {
 
325
                    objPos.setY ((1 - postStretchProgress) * stretchedPos +
 
326
                                 postStretchProgress *
 
327
                                 (stretchedPos + (iconCloseEndY - winFarEndY)));
 
328
                }
 
329
            }
 
330
 
 
331
            if (mTargetTop)
 
332
            {
 
333
                // pick the first one that is below icon's bottom (close) edge
 
334
                if (objPos.y () > iconCloseEndY &&
 
335
                    topmostMovingObjectIdx < 0)
 
336
                    topmostMovingObjectIdx = (int)i;
 
337
 
 
338
                if (objPos.y () < iconFarEndY)
 
339
                    objPos.setY (iconFarEndY);
 
340
            }
 
341
            else
 
342
            {
 
343
                // pick the first one that is below icon's top (close) edge
 
344
                if (objPos.y () > iconCloseEndY &&
 
345
                    bottommostMovingObjectIdx < 0)
 
346
                    bottommostMovingObjectIdx = (int)i;
 
347
 
 
348
                if (objPos.y () > iconFarEndY)
 
349
                    objPos.setY (iconFarEndY);
 
350
            }
 
351
 
 
352
            fx = ((iconCloseEndY - objPos.y ()) /
 
353
                  (iconCloseEndY - winFarEndY));
 
354
        }
 
355
        else // object is at the right side
 
356
        {
 
357
            // Set y position to the y position of the object at the left
 
358
            // on the same row (previous object)
 
359
            objPos.setY ((object - 1)->position ().y ());
 
360
        }
 
361
 
 
362
        float origX = (mWindow->x () +
 
363
                       (winw * objGridX - outExtents.left) *
 
364
                       mModel->scale ().x ());
 
365
        float iconX =
 
366
            (mIcon.x () - iconShadowLeft) +
 
367
            (mIcon.width () + iconShadowLeft + iconShadowRight) * objGridX;
 
368
 
 
369
        // Compute "target shape" x position
 
370
        float fy = ((sigmoid (fx) - sigmoid0) /
 
371
                    (sigmoid1 - sigmoid0));
 
372
        float targetX = fy * (origX - iconX) + iconX;
 
373
 
 
374
        filterTargetX (targetX, fx);
 
375
 
 
376
        // Compute current x position
 
377
        if (forwardProgress < preShapePhaseEnd)
 
378
            objPos.setX ((1 - preShapeProgress) * origX +
 
379
                         preShapeProgress * targetX);
 
380
        else
 
381
            objPos.setX (targetX);
 
382
 
 
383
        // No need to set objPos.z () to 0, since they won't be used
 
384
        // due to modelAnimIs3D being false for magic lamp.
 
385
    }
 
386
 
 
387
    if (stepRegionUsed ())
 
388
    {
 
389
        // Pick objects that will act as the corners of rectangles subtracted
 
390
        // from this step's damaged region
 
391
 
 
392
        const float topCornerRowRatio =
 
393
            (mTargetTop ? 0.55 : 0.35);// 0.46 0.42; // rectangle corner row ratio
 
394
        const float bottomCornerRowRatio =
 
395
            (mTargetTop ? 0.65 : 0.42);// 0.46 0.42; // rectangle corner row ratio
 
396
 
 
397
        if (topmostMovingObjectIdx < 0)
 
398
            topmostMovingObjectIdx = 0;
 
399
        if (bottommostMovingObjectIdx < 0)
 
400
            bottommostMovingObjectIdx = (int)n - 2;
 
401
 
 
402
        int nRows = (bottommostMovingObjectIdx - topmostMovingObjectIdx) / 2;
 
403
        int firstMovingRow = topmostMovingObjectIdx / 2;
 
404
        mTopLeftCornerObject = &mModel->objects ()
 
405
            [(int)(firstMovingRow + topCornerRowRatio * nRows) * 2];
 
406
        mBottomLeftCornerObject = &mModel->objects ()
 
407
            [(int)(firstMovingRow + bottomCornerRowRatio * nRows) * 2];
 
408
    }
 
409
}
 
410
 
 
411
void
 
412
MagicLampAnim::updateBB (CompOutput &output)
 
413
{
 
414
    // Just consider the corner objects
 
415
 
 
416
    GridModel::GridObject *objects = mModel->objects ();
 
417
    unsigned int n = mModel->numObjects ();
 
418
    for (unsigned int i = 0; i < n; i++)
 
419
    {
 
420
        Point3d &objPos = objects[i].position ();
 
421
        mAWindow->expandBBWithPoint (objPos.x () + 0.5,
 
422
                                     objPos.y () + 0.5);
 
423
 
 
424
        // skip to the last row after considering the first row
 
425
        // (each row has 2 objects)
 
426
        if (i == 1)
 
427
            i = n - 3;
 
428
    }
 
429
 
 
430
    // Subtract a rectangle from each bounding box corner left empty by
 
431
    // the animation
 
432
 
 
433
    mAWindow->resetStepRegionWithBB ();
 
434
    BoxPtr BB = mAWindow->BB ();
 
435
    CompRegion &region = mAWindow->stepRegion ();
 
436
 
 
437
    // Left side
 
438
    if (objects[0].position ().x () >
 
439
        objects[n-2].position ().x ())
 
440
    {
 
441
        // Top-left corner is empty
 
442
 
 
443
        // Position of grid object to pick as the corner of the subtracted rect.
 
444
        Point3d &objPos = mTopLeftCornerObject->position ();
 
445
        region -= CompRect (BB->x1,
 
446
                            BB->y1,
 
447
                            objPos.x () - BB->x1,
 
448
                            objPos.y () - BB->y1);
 
449
    }
 
450
    else // Bottom-left corner is empty
 
451
    {
 
452
        // Position of grid object to pick as the corner of the subtracted rect.
 
453
        Point3d &objPos = mBottomLeftCornerObject->position ();
 
454
        region -= CompRect (BB->x1,
 
455
                            objPos.y (),
 
456
                            objPos.x () - BB->x1,
 
457
                            BB->y2);
 
458
    }
 
459
 
 
460
    // Right side
 
461
    if (objects[1].position ().x () <
 
462
        objects[n-1].position ().x ())
 
463
    {
 
464
        // Top-right corner is empty
 
465
 
 
466
        // Position of grid object to pick as the corner of the subtracted rect.
 
467
        Point3d &objPos = (mTopLeftCornerObject + 1)->position ();
 
468
        region -= CompRect (objPos.x (),
 
469
                            BB->y1,
 
470
                            BB->x2,
 
471
                            objPos.y () - BB->y1);
 
472
    }
 
473
    else // Bottom-right corner is empty
 
474
    {
 
475
        // Position of grid object to pick as the corner of the subtracted rect.
 
476
        Point3d &objPos = (mBottomLeftCornerObject + 1)->position ();
 
477
        region -= CompRect (objPos.x (),
 
478
                            objPos.y (),
 
479
                            BB->x2,
 
480
                            BB->y2);
 
481
    }
 
482
}
 
483
 
 
484
void
 
485
MagicLampWavyAnim::updateBB (CompOutput &output)
 
486
{
 
487
    GridAnim::updateBB (output);
 
488
}
 
489
 
 
490
void
 
491
MagicLampAnim::adjustPointerIconSize ()
 
492
{
 
493
    mIcon.setWidth (MAX (4, optValI
 
494
                         (AnimationOptions::MagicLampOpenStartWidth)));
 
495
 
 
496
    // Adjust position so that the icon is centered at the original position.
 
497
    mIcon.setX (mIcon.x () - mIcon.width () / 2);
 
498
}
 
499
 
 
500
void
 
501
MagicLampWavyAnim::adjustPointerIconSize ()
 
502
{
 
503
    mIcon.setWidth (MAX (4, optValI
 
504
                         (AnimationOptions::MagicLampWavyOpenStartWidth)));
 
505
 
 
506
    // Adjust position so that the icon is centered at the original position.
 
507
    mIcon.setX (mIcon.x () - mIcon.width () / 2);
 
508
}
 
509