2
* Animation plugin for compiz/beryl
6
* Copyright : (C) 2006 Erkin Bahceci
7
* E-mail : erkinbah@gmail.com
9
* Based on Wobbly and Minimize plugins by
11
* E-mail : davidr@novell.com>
13
* Particle system added by : (C) 2006 Dennis Kasprzyk
14
* E-mail : onestone@beryl-project.org
16
* Beam-Up added by : Florencio Guimaraes
17
* E-mail : florencio@nexcorp.com.br
19
* Hexagon tessellator added by : Mike Slegeir
20
* E-mail : mikeslegeir@mail.utexas.edu>
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.
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.
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.
39
// ===================== Effect: Dodge =========================
41
GridAnim::GridModel::GridObject::GridObject () :
44
mOffsetTexCoordForQuadBefore (0, 0),
45
mOffsetTexCoordForQuadAfter (0, 0)
50
GridAnim::GridModel::GridObject::setGridPosition (Point &gridPosition)
52
mGridPosition = gridPosition;
55
GridAnim::GridModel::GridModel (CompWindow *w,
56
WindowEvent curWindowEvent,
61
int decorBottomHeight) :
65
mNumObjects = (unsigned)(gridWidth * gridHeight);
66
mObjects = new GridObject[mNumObjects];
68
initObjects (curWindowEvent,
70
gridWidth, gridHeight,
71
decorTopHeight, decorBottomHeight);
74
GridAnim::GridModel::~GridModel ()
80
GridAnim::GridModel::initObjects (WindowEvent curWindowEvent,
82
int gridWidth, int gridHeight,
83
int decorTopHeight, int decorBottomHeight)
86
int nGridCellsX, nGridCellsY;
88
// number of grid cells in x direction
89
nGridCellsX = gridWidth - 1;
91
if (curWindowEvent == WindowEventShade ||
92
curWindowEvent == WindowEventUnshade)
94
// Number of grid cells in y direction.
95
// One allocated for top, one for bottom.
96
nGridCellsY = gridHeight - 3;
98
float winContentsHeight =
99
height - decorTopHeight - decorBottomHeight;
102
for (gridX = 0; gridX < gridWidth; gridX++)
104
Point gridPos ((float)gridX / nGridCellsX, 0);
106
mObjects[gridX].setGridPosition (gridPos);
110
for (gridY = 1; gridY < gridHeight - 1; gridY++)
113
(gridY - 1) * winContentsHeight / nGridCellsY +
115
float gridPosY = inWinY / height;
117
for (gridX = 0; gridX < gridWidth; gridX++)
119
Point gridPos ((float)gridX / nGridCellsX, gridPosY);
120
mObjects[gridY * gridWidth + gridX].setGridPosition (gridPos);
124
// Bottom (gridY is gridHeight-1 now)
125
for (gridX = 0; gridX < gridWidth; gridX++)
127
Point gridPos ((float)gridX / nGridCellsX, 1);
128
mObjects[gridY * gridWidth + gridX].setGridPosition (gridPos);
135
// number of grid cells in y direction
136
nGridCellsY = gridHeight - 1;
138
for (gridY = 0; gridY < gridHeight; gridY++)
140
for (gridX = 0; gridX < gridWidth; gridX++)
143
Point gridPos ((float)gridX / nGridCellsX,
144
(float)gridY / nGridCellsY);
145
mObjects[objIndex].setGridPosition (gridPos);
153
GridAnim::GridModel::move (float tx,
156
GridObject *object = mObjects;
157
for (unsigned int i = 0; i < mNumObjects; i++, object++)
159
object->mPosition.add (Point3d (tx, ty, 0));
164
GridAnim::updateBB (CompOutput &output)
166
GridModel::GridObject *object = mModel->mObjects;
167
for (unsigned int i = 0; i < mModel->mNumObjects; i++, object++)
169
mAWindow->expandBBWithPoint (object->position ().x () + 0.5,
170
object->position ().y () + 0.5);
175
GridAnim::initGrid ()
181
GridAnim::GridAnim (CompWindow *w,
182
WindowEvent curWindowEvent,
184
const AnimEffect info,
185
const CompRect &icon) :
186
Animation::Animation (w, curWindowEvent, duration, info, icon),
188
mUseQTexCoord (false)
197
CompRect outRect (mAWindow->savedRectsValid () ?
198
mAWindow->savedOutRect () :
199
mWindow->outputRect ());
201
mModel = new GridModel (mWindow, mCurWindowEvent,
203
mGridWidth, mGridHeight,
204
mDecorTopHeight, mDecorBottomHeight);
207
GridAnim::~GridAnim ()
214
GridAnim::addGeometry (const GLTexture::MatrixList &matrix,
215
const CompRegion ®ion,
216
const CompRegion &clip,
217
unsigned int maxGridWidth,
218
unsigned int maxGridHeight)
220
unsigned int nMatrix = matrix.size ();
221
int nVertices, nIndices;
225
float winContentsY, winContentsHeight;
226
float deformedX, deformedY;
232
bool notUsing3dCoords = !using3D ();
234
if (region.isEmpty ()) // nothing to do
237
GLWindow::Geometry &geometry = GLWindow::get (mWindow)->geometry ();
239
for (unsigned int it = 0; it < nMatrix; it++)
241
if (matrix[it].xy != 0.0f || matrix[it].yx != 0.0f)
248
CompRect outRect (mAWindow->savedRectsValid () ?
249
mAWindow->savedOutRect () :
250
mWindow->outputRect ());
251
CompWindowExtents outExtents (mAWindow->savedRectsValid () ?
252
mAWindow->savedOutExtents () :
255
// window output (contents + decorations + shadows) coordinates and size
256
int ox = outRect.x ();
257
int oy = outRect.y ();
258
int owidth = outRect.width ();
259
int oheight = outRect.height ();
261
// to be used if event is shade/unshade
262
winContentsY = oy + outExtents.top;
263
winContentsHeight = oheight - outExtents.top - outExtents.bottom;
265
geometry.texUnits = (int)nMatrix;
267
if (geometry.vCount == 0)
270
geometry.indexCount = 0;
271
geometry.texCoordSize = 4;
273
geometry.vertexStride = 3 + geometry.texUnits * geometry.texCoordSize;
274
vSize = geometry.vertexStride;
276
nVertices = geometry.vCount;
277
nIndices = geometry.indexCount;
279
v = geometry.vertices + (nVertices * vSize);
280
i = geometry.indices + nIndices;
282
// For each clip passed to this function
283
foreach (const CompRect &pClip, region.rects ())
290
gridW = (float)owidth / (mGridWidth - 1);
292
if (mCurWindowEvent == WindowEventShade ||
293
mCurWindowEvent == WindowEventUnshade)
295
if (y1 < winContentsY) // if at top part
297
gridH = mDecorTopHeight;
299
else if (y2 > winContentsY + winContentsHeight) // if at bottom
301
gridH = mDecorBottomHeight;
303
else // in window contents (only in Y coords)
305
float winContentsHeight =
306
oheight - (mDecorTopHeight + mDecorBottomHeight);
307
gridH = winContentsHeight / (mGridHeight - 3);
311
gridH = (float)oheight / (mGridHeight - 1);
313
// nVertX, nVertY: number of vertices for this clip in x and y dimensions
314
// + 2 to avoid running short of vertices in some cases
315
nVertX = ceil ((x2 - x1) / gridW) + 2;
316
nVertY = (gridH ? ceil ((y2 - y1) / gridH) : 0) + 2;
318
// Allocate 4 indices for each quad
319
int newIndexSize = nIndices + ((nVertX - 1) * (nVertY - 1) * 4);
321
if (newIndexSize > geometry.indexSize)
323
if (!geometry.moreIndices (newIndexSize))
326
i = geometry.indices + nIndices;
328
// Assign quad vertices to indices
329
for (int jy = 0; jy < nVertY - 1; jy++)
331
for (int jx = 0; jx < nVertX - 1; jx++)
333
*i++ = nVertices + nVertX * (2 * jy + 1) + jx;
334
*i++ = nVertices + nVertX * (2 * jy + 1) + jx + 1;
335
*i++ = nVertices + nVertX * 2 * jy + jx + 1;
336
*i++ = nVertices + nVertX * 2 * jy + jx;
344
(nVertices + nVertX * (2 * nVertY - 2)) * vSize;
345
if (newVertexSize > geometry.vertexSize)
347
if (!geometry.moreVertices (newVertexSize))
350
v = geometry.vertices + (nVertices * vSize);
353
float rowTexCoordQ = 1;
354
float prevRowCellWidth = 0; // this initial value won't be used
355
float rowCellWidth = 0;
356
int clipRowSize = nVertX * vSize;
360
for (int jy = 0; jy < nVertY; jy++)
363
bool applyOffsets = true;
368
// Do calculations for y here to avoid repeating
369
// them unnecessarily in the x loop
371
if (mCurWindowEvent == WindowEventShade ||
372
mCurWindowEvent == WindowEventUnshade)
374
if (y1 < winContentsY) // if at top part
376
topiyFloat = (y - oy) / mDecorTopHeight;
377
topiyFloat = MIN (topiyFloat, 0.999); // avoid 1.0
378
applyOffsets = false;
380
else if (y2 > winContentsY + winContentsHeight) // if at bottom
382
topiyFloat = (mGridHeight - 2) +
383
(mDecorBottomHeight ? (y - winContentsY -
385
mDecorBottomHeight : 0);
386
applyOffsets = false;
388
else // in window contents (only in Y coords)
390
topiyFloat = (mGridHeight - 3) *
391
(y - winContentsY) / winContentsHeight + 1;
396
topiyFloat = (mGridHeight - 1) * (y - oy) / oheight;
398
// topiy should be at most (mGridHeight - 2)
399
int topiy = (int)(topiyFloat + 1e-4);
401
if (topiy == mGridHeight - 1)
403
int bottomiy = topiy + 1;
404
float iny = topiyFloat - topiy;
405
float inyRest = 1 - iny;
407
// End of calculations for y
410
for (int jx = 0; jx < nVertX; jx++)
415
// find containing grid cell (leftix rightix) x (topiy bottomiy)
417
(mGridWidth - 1) * (x - ox) / owidth;
418
int leftix = (int)(leftixFloat + 1e-4);
420
if (leftix == mGridWidth - 1)
422
int rightix = leftix + 1;
424
// GridModel::GridObjects that are at top, bottom, left, right corners of quad
425
GridModel::GridObject *objToTopLeft =
426
&(mModel->mObjects[topiy * mGridWidth + leftix]);
427
GridModel::GridObject *objToTopRight =
428
&(mModel->mObjects[topiy * mGridWidth + rightix]);
429
GridModel::GridObject *objToBottomLeft =
430
&(mModel->mObjects[bottomiy * mGridWidth + leftix]);
431
GridModel::GridObject *objToBottomRight =
432
&(mModel->mObjects[bottomiy * mGridWidth + rightix]);
434
Point3d &objToTopLeftPos = objToTopLeft->mPosition;
435
Point3d &objToTopRightPos = objToTopRight->mPosition;
436
Point3d &objToBottomLeftPos = objToBottomLeft->mPosition;
437
Point3d &objToBottomRightPos = objToBottomRight->mPosition;
439
// find position in cell by taking remainder of flooring
440
float inx = leftixFloat - leftix;
441
float inxRest = 1 - inx;
443
// Interpolate to find deformed coordinates
445
float hor1x = (inxRest * objToTopLeftPos.x () +
446
inx * objToTopRightPos.x ());
447
float hor1y = (inxRest * objToTopLeftPos.y () +
448
inx * objToTopRightPos.y ());
449
float hor1z = (notUsing3dCoords ? 0 :
450
inxRest * objToTopLeftPos.z () +
451
inx * objToTopRightPos.z ());
452
float hor2x = (inxRest * objToBottomLeftPos.x () +
453
inx * objToBottomRightPos.x ());
454
float hor2y = (inxRest * objToBottomLeftPos.y () +
455
inx * objToBottomRightPos.y ());
456
float hor2z = (notUsing3dCoords ? 0 :
457
inxRest * objToBottomLeftPos.z () +
458
inx * objToBottomRightPos.z ());
460
deformedX = inyRest * hor1x + iny * hor2x;
461
deformedY = inyRest * hor1y + iny * hor2y;
462
deformedZ = inyRest * hor1z + iny * hor2z;
464
// Texture coordinates (s, t, r, q)
469
rowCellWidth = deformedX - v[-3];
471
// do only once per row for all rows except row 0
472
if (jy > 0 && jx == 1)
474
rowTexCoordQ = (rowCellWidth / prevRowCellWidth);
476
for (unsigned int it = 0; it < nMatrix; it++, v += 4)
478
// update first column
479
// (since we didn't know rowTexCoordQ before)
480
v[-vSize] *= rowTexCoordQ; // multiply s & t by q
481
v[-vSize + 1] *= rowTexCoordQ;
482
v[-vSize + 3] = rowTexCoordQ; // copy q
488
// Loop for each texture element
489
// (4 texture coordinates for each one)
490
for (unsigned int it = 0; it < nMatrix; it++, v += 4)
496
if (applyOffsets && y < y2)
497
offsetY = objToTopLeft->mOffsetTexCoordForQuadAfter.y ();
498
v[0] = COMP_TEX_COORD_X (matrix[it], x); // s
499
v[1] = COMP_TEX_COORD_Y (matrix[it], y + offsetY); // t
503
if (applyOffsets && y < y2)
505
// The correct y offset below produces wrong
506
// texture coordinates for some reason.
508
// offsetY = objToTopLeft->offsetTexCoordForQuadAfter.y;
509
v[0] = COMP_TEX_COORD_XY (matrix[it], x, y + offsetY); // s
510
v[1] = COMP_TEX_COORD_YX (matrix[it], x, y + offsetY); // t
514
if (0 < jy && jy < nVertY - 1)
516
// copy s, t, r to duplicate row
517
memcpy (v + clipRowSize, v, 3 * sizeof (GLfloat));
518
v[3 + clipRowSize] = 1; // q
522
objToTopLeft->mOffsetTexCoordForQuadBefore.y () != 0)
524
// After copying to next row, update texture y coord
525
// by following object's offset
526
offsetY = objToTopLeft->mOffsetTexCoordForQuadBefore.y ();
529
v[1] = COMP_TEX_COORD_Y (matrix[it], y + offsetY);
533
v[0] = COMP_TEX_COORD_XY (matrix[it],
535
v[1] = COMP_TEX_COORD_YX (matrix[it],
541
v[3] = rowTexCoordQ; // q
543
if (jx > 0) // since column 0 is updated when jx == 1
545
// multiply s & t by q
546
v[0] *= rowTexCoordQ;
547
v[1] *= rowTexCoordQ;
560
// Copy vertex coordinates to duplicate row
561
if (0 < jy && jy < nVertY - 1)
562
memcpy (v + clipRowSize, v, 3 * sizeof (GLfloat));
566
// increment x properly (so that coordinates fall on grid intersections)
567
x = rightix * gridW + ox;
569
v += 3; // move on to next vertex
572
prevRowCellWidth = rowCellWidth;
574
if (0 < jy && jy < nVertY - 1)
576
v += clipRowSize; // skip the duplicate row
579
// increment y properly (so that coordinates fall on grid intersections)
580
if (mCurWindowEvent == WindowEventShade ||
581
mCurWindowEvent == WindowEventUnshade)
587
y = bottomiy * gridH + oy;
591
geometry.vCount = nVertices;
592
geometry.indexCount = nIndices;
596
GridAnim::drawGeometry ()
598
GLWindow::Geometry &geometry = GLWindow::get (mWindow)->geometry ();
600
int texUnit = geometry.texUnits;
601
int currentTexUnit = 0;
602
int stride = geometry.vertexStride;
603
GLfloat *vertices = geometry.vertices + (stride - 3);
605
stride *= (int) sizeof (GLfloat);
607
glVertexPointer (3, GL_FLOAT, stride, vertices);
611
if (texUnit != currentTexUnit)
613
(*GL::clientActiveTexture) ((GLenum)(GL_TEXTURE0_ARB + texUnit));
614
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
615
currentTexUnit = texUnit;
617
vertices -= geometry.texCoordSize;
618
glTexCoordPointer (geometry.texCoordSize,
619
GL_FLOAT, stride, vertices);
622
glDrawElements (GL_QUADS, geometry.indexCount,
623
GL_UNSIGNED_SHORT, geometry.indices);
625
// disable all texture coordinate arrays except 0
626
texUnit = geometry.texUnits;
631
(*GL::clientActiveTexture) ((GLenum)(GL_TEXTURE0_ARB + texUnit));
632
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
635
(*GL::clientActiveTexture) (GL_TEXTURE0_ARB);
639
GridTransformAnim::GridTransformAnim (CompWindow *w,
640
WindowEvent curWindowEvent,
642
const AnimEffect info,
643
const CompRect &icon) :
644
Animation::Animation (w, curWindowEvent, duration, info, icon),
645
TransformAnim::TransformAnim (w, curWindowEvent, duration, info, icon),
646
GridAnim::GridAnim (w, curWindowEvent, duration, info, icon),
647
mUsingTransform (true)
652
GridTransformAnim::init ()
655
TransformAnim::init ();
659
GridTransformAnim::updateBB (CompOutput &output)
665
// center for perspective correction
666
Point center = getCenter ();
668
GLMatrix fullTransform (mTransform.getMatrix ());
669
applyPerspectiveSkew (output, fullTransform, center);
671
prepareTransform (output, wTransform, fullTransform);
673
mAWindow->expandBBWithPoints3DTransform (output,
677
mModel->numObjects ());
681
GridModel::GridObject *object = mModel->objects ();
682
unsigned int n = mModel->numObjects ();
683
for (unsigned int i = 0; i < n; i++, object++)
685
GLVector coords (object->mPosition.x (),
686
object->mPosition.y (), 0, 1);
687
mAWindow->expandBBWithPoint2DTransform (coords, mTransform);
693
GridTransformAnim::updateTransform (GLMatrix &wTransform)
695
if (!mUsingTransform)
698
TransformAnim::updateTransform (wTransform);
702
// center for perspective correction
703
Point center = getCenter ();
705
GLMatrix skewTransform;
706
applyPerspectiveSkew (AnimScreen::get (::screen)->output (),
707
skewTransform, center);
708
wTransform *= skewTransform;