/* * Animation plugin for beryl * * animation.c * * Copyright : (C) 2006 Erkin Bahceci * E-mail : cornelius@beryl-project.org * * 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 * * Added Beam-Up : Florencio Guimaraes * E-mail : florencio@nexcorp.com.br * * * 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. */ /* * TODO: * * - Auto direction option: Close in opposite direction of opening * - Proper side surface normals for lighting * - decoration shadows * - shadow quad generation * - shadow texture coords (from clip tex. matrices) * - draw shadows * - fade in shadows * * - Voronoi tessellation * - Brick tessellation * - Triangle tessellation * - Hexagonal tessellation * * Effects: * - Circular action for tornado type fx * - Tornado 3D (especially for minimize) * - Helix 3D (hor. strips descend while they rotate and fade in) * - Glass breaking 3D * - Gaussian distr. points (for gradually increasing polygon size * starting from center or near mouse pointer) * - Drawing cracks * - Gradual cracking * * - fix slowness during transparent cube with <100 opacity * - fix occasional wrong side color in some windows * - fix on top windows and panels * (These two only matter for viewing during Rotate Cube. * All windows should be painted with depth test on * like 3d-plugin does) * - play better with rotate (fix cube face drawn on top of polygons * after 45 deg. rotation) * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #ifdef USE_LIBRSVG #include #include #include #include #endif #include #include #include #include "animation_tex.h" #define FAKE_ICON_SIZE 4 #define ANIM_TEXTURE_LIST_INCREMENT 5 #define ANIM_CLIP_LIST_INCREMENT 20 #define NOT_INITIALIZED -10000 #define WIN_X(w) ((w)->attrib.x - (w)->output.left) #define WIN_Y(w) ((w)->attrib.y - (w)->output.top) #define WIN_W(w) ((w)->width + (w)->output.left + (w)->output.right) #define WIN_H(w) ((w)->height + (w)->output.top + (w)->output.bottom) #define BORDER_X(w) ((w)->attrib.x - (w)->input.left) #define BORDER_Y(w) ((w)->attrib.y - (w)->input.top) #define BORDER_W(w) ((w)->width + (w)->input.left + (w)->input.right) #define BORDER_H(w) ((w)->height + (w)->input.top + (w)->input.bottom) #define RAND_FLOAT() ((float)rand() / RAND_MAX) typedef struct _xy_pair { float x, y; } Point, Vector; typedef struct { float x1, x2, y1, y2; } Boxf; typedef struct _xyz_tuple { float x, y, z; } Point3d, Vector3d; // This is intended to be a closed 3D piece of a window with convex polygon // faces and quad-strip sides. Since decoration texture is separate from // the window texture, it is more complicated than it would be with a single // texture: we use glClipPlane with the rectangles (clips) to clip 3D space // to the region falling within that clip. // If the polygon is on an edge/corner, it also has 2D shadow quad(s) // (to be faded out at the beginning of 3D animation if necessary). typedef struct _PolygonObject { int nVertices; // number of total vertices (front + back) int nSides; // number of sides GLfloat *vertices; // Positions of vertices relative to center GLushort *sideIndices; // Indices of quad strip for "sides" GLfloat *normals; // Surface normals for 2+nSides faces Box boundingBox; // Bound. box to test intersection with clips GLfloat *vertexTexCoords4Clips; // Tex coords for each intersecting clip and for each vertex // ordered as c1.v1.x, c1.v1.y, c1.v2.x, c1.v2.y, c2.v1.x, c2.v1.y, ... /* int *vertexOnEdge; // 1,2,3,4: W,E,N,S edge 0: not edge // 5,6,7,8: NW,NE,SW,SE corner // (used for shadow quad generation) int nShadowQuads; GLfloat *shadowVertices; // Shadow vertices positions relative to center GLfloat *shadowTexCoords; // Texture coords of shadow vertices */ // Animation effect parameters Point3d centerPosStart; // Starting position of center float rotAngleStart; // Starting rotation angle Point3d centerPos; // Position of center Vector3d rotAxis; // Rotation axis vector float rotAngle; // Rotation angle Point3d rotAxisOffset; // Rotation axis translate amount Point centerRelPos; // Relative pos of center within the window Vector3d finalRelPos; // Velocity factor for scripted movement float finalRotAng; // Final rotation angle around rotAxis float moveStartTime; // Movement starts at this time ([0-1] range) float moveDuration; // Movement lasts this long ([0-1] range) float fadeStartTime; // Fade out starts at this time ([0,1] range) float fadeDuration; // Duration of fade out ([0,1] range) } PolygonObject; typedef struct _Clip4Polygons // Rectangular clips { // (to hold clips passed to AddWindowGeometry) int id; // clip id (what number this clip is among // passed clips) Box box; // Coords Boxf boxf; // Float coords (for small clipping adjustment) CompMatrix texMatrix; // Corresponding texture coord. matrix int *intersectingPolygons; int nIntersectingPolygons; // Clips (in PolygonSet) that intersect GLfloat *polygonVertexTexCoords; // Tex coords for each intersecting polygon and for each vertex // ordered as p1.v1.x, p1.v1.y, p1.v2.x, p1.v2.y, p2.v1.x, p2.v1.y, ... } Clip4Polygons; typedef struct _PolygonSet // Polygon objects with same thickness { int nClips; // Rect. clips collected in AddWindowGeometries Clip4Polygons *clips; // List of clips int clipCapacity; // # of clips this list can hold int firstNondrawnClip; int *lastClipInGroup; // index of the last clip in each group of clips // drawn in drawGeometry func. Bool doDepthTest; // whether depth testing should be used in the effect Bool doLighting; // whether lighting should be used in the effect Bool correctPerspective; // Whether perspective look should be neutralized PolygonObject *polygons; // The polygons in this set int nPolygons; float thickness; // Window thickness (depth along z axis) int nTotalFrontVertices; // Total # of polygon vertices on front faces float backAndSidesFadeDur; // How long side and back faces should fade in/out float allFadeDuration; // Duration of fade out at the end in [0,1] range // when all polygons fade out at the same time. // If >-1, this overrides fadeDuration in PolygonObject Bool includeShadows; // include shadows in polygon } PolygonSet; typedef struct _WaveParam { float halfWidth; float amp; float pos; } WaveParam; typedef enum { WindowEventNone = 0, WindowEventMinimize, WindowEventUnminimize, WindowEventClose, WindowEventCreate, WindowEventFocus, WindowEventShade, WindowEventUnshade } WindowEvent; typedef struct _Object { Point gridPosition; // position on window in [0,1] range Point position; // position on screen Point3d posRel3d; // position relative to model center // (for 3d looking effects) // Texture x, y coordinates will be offset by given amounts // for quads that fall after and before this object in x and y directions. // Currently only y offset can be used. Point offsetTexCoordForQuadBefore; Point offsetTexCoordForQuadAfter; } Object; typedef struct _Model { Object *objects; int numObjects; int gridWidth; int gridHeight; int winWidth; // keeps win. size when model was created int winHeight; // float remainderSteps; Vector scale; Point scaleOrigin; Point topLeft; Point bottomRight; int magicLampWaveCount; WaveParam *magicLampWaves; WindowEvent forWindowEvent; float topHeight; float bottomHeight; } Model; static void modelInitObjects(Model * model, int x, int y, int width, int height); static void postAnimationCleanup(CompWindow * w, Bool resetAnimation); #define ANIM_MAGIC_LAMP1_GRID_RES_DEFAULT 100 #define ANIM_MAGIC_LAMP1_GRID_RES_MIN 4 #define ANIM_MAGIC_LAMP1_GRID_RES_MAX 200 #define ANIM_MAGIC_LAMP1_MAX_WAVES_DEFAULT 5 #define ANIM_MAGIC_LAMP1_MAX_WAVES_MIN 3 #define ANIM_MAGIC_LAMP1_MAX_WAVES_MAX 20 #define ANIM_MAGIC_LAMP1_WAVE_AMP_MIN_DEFAULT 200 #define ANIM_MAGIC_LAMP1_WAVE_AMP_MIN_MIN 200 #define ANIM_MAGIC_LAMP1_WAVE_AMP_MIN_MAX 2000 #define ANIM_MAGIC_LAMP1_WAVE_AMP_MIN_PRECISION 5 #define ANIM_MAGIC_LAMP1_WAVE_AMP_MAX_DEFAULT 300 #define ANIM_MAGIC_LAMP1_WAVE_AMP_MAX_MIN 200 #define ANIM_MAGIC_LAMP1_WAVE_AMP_MAX_MAX 2000 #define ANIM_MAGIC_LAMP1_WAVE_AMP_MAX_PRECISION 5 #define ANIM_MAGIC_LAMP1_CREATE_START_WIDTH_DEFAULT 30 #define ANIM_MAGIC_LAMP1_CREATE_START_WIDTH_MIN 0 #define ANIM_MAGIC_LAMP1_CREATE_START_WIDTH_MAX 500 #define ANIM_MAGIC_LAMP2_GRID_RES_DEFAULT 100 #define ANIM_MAGIC_LAMP2_GRID_RES_MIN 2 #define ANIM_MAGIC_LAMP2_GRID_RES_MAX 200 #define ANIM_MAGIC_LAMP2_MAX_WAVES_DEFAULT 3 #define ANIM_MAGIC_LAMP2_MAX_WAVES_MIN 3 #define ANIM_MAGIC_LAMP2_MAX_WAVES_MAX 20 #define ANIM_MAGIC_LAMP2_WAVE_AMP_MIN_DEFAULT 200 #define ANIM_MAGIC_LAMP2_WAVE_AMP_MIN_MIN 200 #define ANIM_MAGIC_LAMP2_WAVE_AMP_MIN_MAX 2000 #define ANIM_MAGIC_LAMP2_WAVE_AMP_MIN_PRECISION 5 #define ANIM_MAGIC_LAMP2_WAVE_AMP_MAX_DEFAULT 300 #define ANIM_MAGIC_LAMP2_WAVE_AMP_MAX_MIN 200 #define ANIM_MAGIC_LAMP2_WAVE_AMP_MAX_MAX 2000 #define ANIM_MAGIC_LAMP2_WAVE_AMP_MAX_PRECISION 5 #define ANIM_MAGIC_LAMP2_CREATE_START_WIDTH_DEFAULT 30 #define ANIM_MAGIC_LAMP2_CREATE_START_WIDTH_MIN 0 #define ANIM_MAGIC_LAMP2_CREATE_START_WIDTH_MAX 500 #define ANIM_MAGIC_LAMP3_GRID_RES_DEFAULT 100 #define ANIM_MAGIC_LAMP3_GRID_RES_MIN 2 #define ANIM_MAGIC_LAMP3_GRID_RES_MAX 200 #define ANIM_MAGIC_LAMP3_MAX_WAVES_DEFAULT 0 #define ANIM_MAGIC_LAMP3_MAX_WAVES_MIN 0 #define ANIM_MAGIC_LAMP3_MAX_WAVES_MAX 20 #define ANIM_MAGIC_LAMP3_WAVE_AMP_MIN_DEFAULT 200 #define ANIM_MAGIC_LAMP3_WAVE_AMP_MIN_MIN 200 #define ANIM_MAGIC_LAMP3_WAVE_AMP_MIN_MAX 2000 #define ANIM_MAGIC_LAMP3_WAVE_AMP_MIN_PRECISION 5 #define ANIM_MAGIC_LAMP3_WAVE_AMP_MAX_DEFAULT 300 #define ANIM_MAGIC_LAMP3_WAVE_AMP_MAX_MIN 200 #define ANIM_MAGIC_LAMP3_WAVE_AMP_MAX_MAX 2000 #define ANIM_MAGIC_LAMP3_WAVE_AMP_MAX_PRECISION 5 #define ANIM_MAGIC_LAMP3_CREATE_START_WIDTH_DEFAULT 30 #define ANIM_MAGIC_LAMP3_CREATE_START_WIDTH_MIN 0 #define ANIM_MAGIC_LAMP3_CREATE_START_WIDTH_MAX 500 #define ANIM_SIDEKICK_NUM_ROTATIONS_DEFAULT 0.5 #define ANIM_SIDEKICK_NUM_ROTATIONS_MIN 0 #define ANIM_SIDEKICK_NUM_ROTATIONS_MAX 5.0 #define ANIM_SIDEKICK_NUM_ROTATIONS_PRECISION 0.01 #define ANIM_MINIMIZE_DURATION_DEFAULT 0.2 #define ANIM_MINIMIZE_DURATION_MIN 0.1 #define ANIM_MINIMIZE_DURATION_MAX 10 #define ANIM_MINIMIZE_DURATION_PRECISION 0.05 #define ANIM_UNMINIMIZE_DURATION_DEFAULT 0.2 #define ANIM_UNMINIMIZE_DURATION_MIN 0.1 #define ANIM_UNMINIMIZE_DURATION_MAX 10 #define ANIM_UNMINIMIZE_DURATION_PRECISION 0.05 #define ANIM_CREATE1_DURATION_DEFAULT 0.2 #define ANIM_CREATE1_DURATION_MIN 0.1 #define ANIM_CREATE1_DURATION_MAX 10 #define ANIM_CREATE1_DURATION_PRECISION 0.05 #define ANIM_CLOSE1_DURATION_DEFAULT 0.2 #define ANIM_CLOSE1_DURATION_MIN 0.1 #define ANIM_CLOSE1_DURATION_MAX 10 #define ANIM_CLOSE1_DURATION_PRECISION 0.05 #define ANIM_CREATE2_DURATION_DEFAULT 0.15 #define ANIM_CREATE2_DURATION_MIN 0.1 #define ANIM_CREATE2_DURATION_MAX 10 #define ANIM_CREATE2_DURATION_PRECISION 0.05 #define ANIM_CLOSE2_DURATION_DEFAULT 0.15 #define ANIM_CLOSE2_DURATION_MIN 0.1 #define ANIM_CLOSE2_DURATION_MAX 10 #define ANIM_CLOSE2_DURATION_PRECISION 0.05 #define ANIM_FOCUS_DURATION_DEFAULT 0.5 #define ANIM_FOCUS_DURATION_MIN 0.1 #define ANIM_FOCUS_DURATION_MAX 10 #define ANIM_FOCUS_DURATION_PRECISION 0.05 #define ANIM_SHADE_DURATION_DEFAULT 0.5 #define ANIM_SHADE_DURATION_MIN 0.1 #define ANIM_SHADE_DURATION_MAX 10 #define ANIM_SHADE_DURATION_PRECISION 0.05 #define ANIM_UNSHADE_DURATION_DEFAULT 0.5 #define ANIM_UNSHADE_DURATION_MIN 0.1 #define ANIM_UNSHADE_DURATION_MAX 10 #define ANIM_UNSHADE_DURATION_PRECISION 0.05 #define ANIM_FOCUS_WAVE_WIDTH_DEFAULT 0.7 #define ANIM_FOCUS_WAVE_WIDTH_MIN 0.02 #define ANIM_FOCUS_WAVE_WIDTH_MAX 3 #define ANIM_FOCUS_WAVE_WIDTH_PRECISION 0.02 #define ANIM_FOCUS_WAVE_AMP_DEFAULT 0.03 #define ANIM_FOCUS_WAVE_AMP_MIN 0 #define ANIM_FOCUS_WAVE_AMP_MAX 1 #define ANIM_FOCUS_WAVE_AMP_PRECISION 0.01 #define ANIM_CURVED_FOLD_AMP_DEFAULT 0.15 #define ANIM_CURVED_FOLD_AMP_MIN -0.5 #define ANIM_CURVED_FOLD_AMP_MAX 0.5 #define ANIM_CURVED_FOLD_AMP_PRECISION 0.01 #define ANIM_HORIZONTAL_FOLDS_NUM_FOLDS_DEFAULT 5 #define ANIM_HORIZONTAL_FOLDS_NUM_FOLDS_MIN 1 #define ANIM_HORIZONTAL_FOLDS_NUM_FOLDS_MAX 50 #define ANIM_HORIZONTAL_FOLDS_AMP_DEFAULT 0.07 #define ANIM_HORIZONTAL_FOLDS_AMP_MIN -0.5 #define ANIM_HORIZONTAL_FOLDS_AMP_MAX 0.5 #define ANIM_HORIZONTAL_FOLDS_AMP_PRECISION 0.01 #define ANIM_TIME_STEP_DEFAULT 10 #define ANIM_TIME_STEP_MIN 1 #define ANIM_TIME_STEP_MAX 400 #define ANIM_TIME_STEP_INTENSE_DEFAULT 30 #define ANIM_TIME_STEP_INTENSE_MIN 1 #define ANIM_TIME_STEP_INTENSE_MAX 400 #define ANIM_ROLLUP_FIXED_INTERIOR_DEFAULT FALSE #define ANIM_ALL_RANDOM_DEFAULT FALSE #define ANIM_FIRE_SIZE_DEFAULT 5.0 #define ANIM_FIRE_SIZE_MIN 0.1 #define ANIM_FIRE_SIZE_MAX 20.0 #define ANIM_FIRE_SIZE_PRECISION 0.1 #define ANIM_FIRE_SLOWDOWN_DEFAULT 0.5 #define ANIM_FIRE_SLOWDOWN_MIN 0.1 #define ANIM_FIRE_SLOWDOWN_MAX 10.0 #define ANIM_FIRE_SLOWDOWN_PRECISION 0.1 #define ANIM_FIRE_LIFE_DEFAULT 0.7 #define ANIM_FIRE_LIFE_MIN 0.1 #define ANIM_FIRE_LIFE_MAX 1.0 #define ANIM_FIRE_LIFE_PRECISION 0.1 #define ANIM_FIRE_PARTICLES_DEFAULT 1000 #define ANIM_FIRE_PARTICLES_MIN 100 #define ANIM_FIRE_PARTICLES_MAX 10000 #define ANIM_FIRE_COLOR_RED_DEFAULT 0xffff #define ANIM_FIRE_COLOR_GREEN_DEFAULT 0x3333 #define ANIM_FIRE_COLOR_BLUE_DEFAULT 0x0555 #define ANIM_FIRE_COLOR_ALPHA_DEFAULT 0xffff #define ANIM_FIRE_CONSTANT_SPEED_DEFAULT FALSE #define ANIM_FIRE_SMOKE_DEFAULT FALSE #define ANIM_FIRE_MYSTICAL_DEFAULT FALSE #define ANIM_BEAMUP_SIZE_DEFAULT 8.0 #define ANIM_BEAMUP_SIZE_MIN 0.1 #define ANIM_BEAMUP_SIZE_MAX 20.0 #define ANIM_BEAMUP_SIZE_PRECISION 0.1 #define ANIM_BEAMUP_LIFE_DEFAULT 0.7 #define ANIM_BEAMUP_LIFE_MIN 0.1 #define ANIM_BEAMUP_LIFE_MAX 1.0 #define ANIM_BEAMUP_LIFE_PRECISION 0.1 #define ANIM_BEAMUP_SLOWDOWN_DEFAULT 1.0 #define ANIM_BEAMUP_SLOWDOWN_MIN 0.1 #define ANIM_BEAMUP_SLOWDOWN_MAX 10.0 #define ANIM_BEAMUP_SLOWDOWN_PRECISION 0.1 #define ANIM_BEAMUP_SPACING_DEFAULT 5 #define ANIM_BEAMUP_SPACING_MIN 1 #define ANIM_BEAMUP_SPACING_MAX 20 #define ANIM_BEAMUP_COLOR_RED_DEFAULT 0x7fff #define ANIM_BEAMUP_COLOR_GREEN_DEFAULT 0x7fff #define ANIM_BEAMUP_COLOR_BLUE_DEFAULT 0x7fff #define ANIM_BEAMUP_COLOR_ALPHA_DEFAULT 0xffff #define ANIM_GLIDE1_AWAY_POS_DEFAULT 1.0 #define ANIM_GLIDE1_AWAY_POS_MIN -2.0 #define ANIM_GLIDE1_AWAY_POS_MAX 1.0 #define ANIM_GLIDE1_AWAY_POS_PRECISION 0.05 #define ANIM_GLIDE1_AWAY_ANGLE_DEFAULT 90.0 #define ANIM_GLIDE1_AWAY_ANGLE_MIN -540.0 #define ANIM_GLIDE1_AWAY_ANGLE_MAX 540.0 #define ANIM_GLIDE1_AWAY_ANGLE_PRECISION 5.0 #define ANIM_GLIDE1_THICKNESS_DEFAULT 0.0 #define ANIM_GLIDE1_THICKNESS_MIN 0.0 #define ANIM_GLIDE1_THICKNESS_MAX 500.0 #define ANIM_GLIDE1_THICKNESS_PRECISION 5.0 #define ANIM_GLIDE2_AWAY_POS_DEFAULT -0.4 #define ANIM_GLIDE2_AWAY_POS_MIN -2.0 #define ANIM_GLIDE2_AWAY_POS_MAX 1.0 #define ANIM_GLIDE2_AWAY_POS_PRECISION 0.05 #define ANIM_GLIDE2_AWAY_ANGLE_DEFAULT -45.0 #define ANIM_GLIDE2_AWAY_ANGLE_MIN -540.0 #define ANIM_GLIDE2_AWAY_ANGLE_MAX 540.0 #define ANIM_GLIDE2_AWAY_ANGLE_PRECISION 5.0 #define ANIM_GLIDE2_THICKNESS_DEFAULT 0.0 #define ANIM_GLIDE2_THICKNESS_MIN 0.0 #define ANIM_GLIDE2_THICKNESS_MAX 500.0 #define ANIM_GLIDE2_THICKNESS_PRECISION 5.0 typedef enum { AnimDirectionDown = 0, AnimDirectionUp, AnimDirectionLeft, AnimDirectionRight, AnimDirectionRandom, AnimDirectionAuto } AnimDirection; static char *animDirectionName[] = { N_("Down"), N_("Up"), N_("Left"), N_("Right"), N_("Random"), N_("Automatic") }; #define ANIM_FIRE_DIRECTION_DEFAULT AnimDirectionDown #define ANIM_DOMINO_DIRECTION_DEFAULT AnimDirectionAuto #define ANIM_RAZR_DIRECTION_DEFAULT AnimDirectionAuto typedef enum { PostprocessDisablingNone = 0, PostprocessDisablingWindow, PostprocessDisablingScreen } PostprocessDisabling; static char *ppDisablingName[] = { N_("No disabling"), N_("Animated window"), N_("All windows") }; typedef enum { ZoomFromCenterOff = 0, ZoomFromCenterMin, ZoomFromCenterCreate, ZoomFromCenterOn } ZoomFromCenter; static char *zoomFromCenterOption[] = { N_("Off"), N_("Minimize/Unminimize Only"), N_("Create/Close Only"), N_("On") }; #define ANIM_ZOOM_FROM_CENTER_DEFAULT 0 #define ANIM_DISABLE_PP_FX_DEFAULT PostprocessDisablingWindow // ===================== Particle engine ========================= typedef struct _Particle { float life; // particle life float fade; // fade speed float width; // particle width float height; // particle height float w_mod; // particle size modification during life float h_mod; // particle size modification during life float r; // red value float g; // green value float b; // blue value float a; // alpha value float x; // X position float y; // Y position float z; // Z position float xi; // X direction float yi; // Y direction float zi; // Z direction float xg; // X gravity float yg; // Y gravity float zg; // Z gravity float xo; // orginal X position float yo; // orginal Y position float zo; // orginal Z position } Particle; typedef struct _ParticleSystem { int numParticles; Particle *particles; float slowdown; GLuint tex; Bool active; int x, y; float darken; GLuint blendMode; // Moved from drawParticles to get rid of spurious malloc's GLfloat *vertices_cache; int vertex_cache_count; GLfloat *coords_cache; int coords_cache_count; GLfloat *colors_cache; int color_cache_count; GLfloat *dcolors_cache; int dcolors_cache_count; } ParticleSystem; static void initParticles(int numParticles, ParticleSystem * ps) { if (ps->particles) free(ps->particles); ps->particles = calloc(1, sizeof(Particle) * numParticles); ps->tex = 0; ps->numParticles = numParticles; ps->slowdown = 1; ps->active = FALSE; // Initialize cache ps->vertices_cache = NULL; ps->colors_cache = NULL; ps->coords_cache = NULL; ps->dcolors_cache = NULL; ps->vertex_cache_count = 0; ps->color_cache_count = 0; ps->coords_cache_count = 0; ps->dcolors_cache_count = 0; int i; for (i = 0; i < numParticles; i++) { ps->particles[i].life = 0.0f; } } static void drawParticles(CompScreen * s, CompWindow * w, ParticleSystem * ps) { glPushMatrix(); if (w) glTranslated(WIN_X(w) - ps->x, WIN_Y(w) - ps->y, 0); glEnable(GL_BLEND); if (ps->tex) { glBindTexture(GL_TEXTURE_2D, ps->tex); glEnable(GL_TEXTURE_2D); } glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); int i; Particle *part; /* Check that the cache is big enough */ if (ps->numParticles > ps->vertex_cache_count) { ps->vertices_cache = realloc(ps->vertices_cache, ps->numParticles * 4 * 3 * sizeof(GLfloat)); ps->vertex_cache_count = ps->numParticles; } if (ps->numParticles > ps->coords_cache_count) { ps->coords_cache = realloc(ps->coords_cache, ps->numParticles * 4 * 2 * sizeof(GLfloat)); ps->coords_cache_count = ps->numParticles; } if (ps->numParticles > ps->color_cache_count) { ps->colors_cache = realloc(ps->colors_cache, ps->numParticles * 4 * 4 * sizeof(GLfloat)); ps->color_cache_count = ps->numParticles; } if (ps->darken > 0) { if (ps->dcolors_cache_count < ps->numParticles) { ps->dcolors_cache = realloc(ps->dcolors_cache, ps->numParticles * 4 * 4 * sizeof(GLfloat)); ps->dcolors_cache_count = ps->numParticles; } } GLfloat *dcolors = ps->dcolors_cache; GLfloat *vertices = ps->vertices_cache; GLfloat *coords = ps->coords_cache; GLfloat *colors = ps->colors_cache; int numActive = 0; for (i = 0; i < ps->numParticles; i++) { part = &ps->particles[i]; if (part->life > 0.0f) { numActive += 4; float w = part->width / 2; float h = part->height / 2; w += (w * part->w_mod) * part->life; h += (h * part->h_mod) * part->life; vertices[0] = part->x - w; vertices[1] = part->y - h; vertices[2] = part->z; vertices[3] = part->x - w; vertices[4] = part->y + h; vertices[5] = part->z; vertices[6] = part->x + w; vertices[7] = part->y + h; vertices[8] = part->z; vertices[9] = part->x + w; vertices[10] = part->y - h; vertices[11] = part->z; vertices += 12; coords[0] = 0.0; coords[1] = 0.0; coords[2] = 0.0; coords[3] = 1.0; coords[4] = 1.0; coords[5] = 1.0; coords[6] = 1.0; coords[7] = 0.0; coords += 8; colors[0] = part->r; colors[1] = part->g; colors[2] = part->b; colors[3] = part->life * part->a; colors[4] = part->r; colors[5] = part->g; colors[6] = part->b; colors[7] = part->life * part->a; colors[8] = part->r; colors[9] = part->g; colors[10] = part->b; colors[11] = part->life * part->a; colors[12] = part->r; colors[13] = part->g; colors[14] = part->b; colors[15] = part->life * part->a; colors += 16; if (ps->darken > 0) { dcolors[0] = part->r; dcolors[1] = part->g; dcolors[2] = part->b; dcolors[3] = part->life * part->a * ps->darken; dcolors[4] = part->r; dcolors[5] = part->g; dcolors[6] = part->b; dcolors[7] = part->life * part->a * ps->darken; dcolors[8] = part->r; dcolors[9] = part->g; dcolors[10] = part->b; dcolors[11] = part->life * part->a * ps->darken; dcolors[12] = part->r; dcolors[13] = part->g; dcolors[14] = part->b; dcolors[15] = part->life * part->a * ps->darken; dcolors += 16; } } } glEnableClientState(GL_COLOR_ARRAY); glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), ps->coords_cache); glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), ps->vertices_cache); // darken the background if (ps->darken > 0) { glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); glColorPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), ps->dcolors_cache); glDrawArrays(GL_QUADS, 0, numActive); } // draw particles glBlendFunc(GL_SRC_ALPHA, ps->blendMode); glColorPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), ps->colors_cache); glDrawArrays(GL_QUADS, 0, numActive); glDisableClientState(GL_COLOR_ARRAY); glPopMatrix(); glColor4usv(defaultColor); screenTexEnvMode(s, GL_REPLACE); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); } static void updateParticles(ParticleSystem * ps, float time) { int i; Particle *part; float speed = (time / 50.0); float slowdown = ps->slowdown * (1 - MAX(0.99, time / 1000.0)) * 1000; ps->active = FALSE; for (i = 0; i < ps->numParticles; i++) { part = &ps->particles[i]; if (part->life > 0.0f) { // move particle part->x += part->xi / slowdown; part->y += part->yi / slowdown; part->z += part->zi / slowdown; // modify speed part->xi += part->xg * speed; part->yi += part->yg * speed; part->zi += part->zg * speed; // modify life part->life -= part->fade * speed; ps->active = TRUE; } } } static void finiParticles(ParticleSystem * ps) { free(ps->particles); if (ps->tex) glDeleteTextures(1, &ps->tex); if (ps->vertices_cache) free(ps->vertices_cache); if (ps->colors_cache) free(ps->colors_cache); if (ps->coords_cache) free(ps->coords_cache); if (ps->dcolors_cache) free(ps->dcolors_cache); } // ===================== END: Particle engine ========================= static char *allEffectName[] = { N_("None"), N_("Random"), N_("Beam Up"), N_("Burn"), N_("Curved Fold"), N_("Domino (3D)"), N_("Dream"), N_("Explode (3D)"), N_("Fade"), N_("Glide 1 (3D)"), N_("Glide 2 (3D)"), N_("Horizontal Folds"), N_("Leaf Spread (3D)"), N_("Magic Lamp 1"), N_("Magic Lamp 2"), N_("Magic Lamp 3 (Vacuum)"), N_("Razr (3D)"), N_("Roll Up"), N_("Sidekick"), N_("Wave"), N_("Zoom") }; typedef enum { AnimEffectNone = 0, AnimEffectRandom, AnimEffectBeamUp, AnimEffectBurn, AnimEffectCurvedFold, AnimEffectDomino3D, AnimEffectDream, AnimEffectExplode3D, AnimEffectFade, AnimEffectGlide3D1, AnimEffectGlide3D2, AnimEffectHorizontalFolds, AnimEffectLeafSpread3D, AnimEffectMagicLamp1, AnimEffectMagicLamp2, AnimEffectMagicLamp3, AnimEffectRazr3D, AnimEffectRollUp, AnimEffectSidekick, AnimEffectWave, AnimEffectZoom, AnimEffectNum } AnimEffect; #define ANIM_MINIMIZE_DEFAULT AnimEffectMagicLamp2 #define ANIM_UNMINIMIZE_DEFAULT AnimEffectMagicLamp2 #define ANIM_CLOSE1_DEFAULT AnimEffectZoom #define ANIM_CREATE1_DEFAULT AnimEffectZoom #define ANIM_CLOSE2_DEFAULT AnimEffectFade #define ANIM_CREATE2_DEFAULT AnimEffectFade #define ANIM_FOCUS_DEFAULT AnimEffectNone #define ANIM_SHADE_DEFAULT AnimEffectRollUp #define ANIM_UNSHADE_DEFAULT AnimEffectRollUp static char *minimizeEffectName[] = { N_("None"), N_("Random"), N_("Beam Up"), N_("Burn"), N_("Curved Fold"), N_("Domino (3D)"), N_("Dream"), N_("Explode (3D)"), N_("Fade"), N_("Glide 1 (3D)"), N_("Glide 2 (3D)"), N_("Horizontal Folds"), N_("Leaf Spread (3D)"), N_("Magic Lamp 1"), N_("Magic Lamp 2"), N_("Razr (3D)"), N_("Sidekick"), N_("Zoom") }; static AnimEffect minimizeEffectType[] = { AnimEffectNone, AnimEffectRandom, AnimEffectBeamUp, AnimEffectBurn, AnimEffectCurvedFold, AnimEffectDomino3D, AnimEffectDream, AnimEffectExplode3D, AnimEffectFade, AnimEffectGlide3D1, AnimEffectGlide3D2, AnimEffectHorizontalFolds, AnimEffectLeafSpread3D, AnimEffectMagicLamp1, AnimEffectMagicLamp2, AnimEffectRazr3D, AnimEffectSidekick, AnimEffectZoom }; #define NUM_MINIMIZE_EFFECT (sizeof (minimizeEffectType) / sizeof (minimizeEffectType[0])) static char *closeEffectName[] = { N_("None"), N_("Random"), N_("Beam Up"), N_("Burn"), N_("Curved Fold"), N_("Domino (3D)"), N_("Dream"), N_("Explode (3D)"), N_("Fade"), N_("Glide 1 (3D)"), N_("Glide 2 (3D)"), N_("Horizontal Folds"), N_("Leaf Spread (3D)"), N_("Magic Lamp 1"), N_("Magic Lamp 2"), N_("Magic Lamp 3 (Vacuum)"), N_("Razr (3D)"), N_("Sidekick"), N_("Wave"), N_("Zoom") }; static AnimEffect closeEffectType[] = { AnimEffectNone, AnimEffectRandom, AnimEffectBeamUp, AnimEffectBurn, AnimEffectCurvedFold, AnimEffectDomino3D, AnimEffectDream, AnimEffectExplode3D, AnimEffectFade, AnimEffectGlide3D1, AnimEffectGlide3D2, AnimEffectHorizontalFolds, AnimEffectLeafSpread3D, AnimEffectMagicLamp1, AnimEffectMagicLamp2, AnimEffectMagicLamp3, AnimEffectRazr3D, AnimEffectSidekick, AnimEffectWave, AnimEffectZoom }; #define NUM_CLOSE_EFFECT (sizeof (closeEffectType) / sizeof (closeEffectType[0])) static char *focusEffectName[] = { N_("None"), N_("Wave") }; static AnimEffect focusEffectType[] = { AnimEffectNone, AnimEffectWave }; #define NUM_FOCUS_EFFECT (sizeof (focusEffectType) / sizeof (focusEffectType[0])) static char *shadeEffectName[] = { N_("None"), N_("Random"), N_("Curved Fold"), N_("Horizontal Folds"), N_("Roll Up") }; static AnimEffect shadeEffectType[] = { AnimEffectNone, AnimEffectRandom, AnimEffectCurvedFold, AnimEffectHorizontalFolds, AnimEffectRollUp }; #define NUM_SHADE_EFFECT (sizeof (shadeEffectType) / sizeof (shadeEffectType[0])) static char *minimizeDefaultWinType[] = { N_("Normal"), N_("Dialog"), N_("ModalDialog"), N_("Utility") }; #define N_MINIMIZE_DEFAULT_WIN_TYPE (sizeof (minimizeDefaultWinType) / sizeof (minimizeDefaultWinType[0])) static char *close1DefaultWinType[] = { N_("Normal"), N_("Dialog"), N_("ModalDialog"), N_("Utility") }; #define N_CLOSE1_DEFAULT_WIN_TYPE (sizeof (close1DefaultWinType) / sizeof (close1DefaultWinType[0])) static char *close2DefaultWinType[] = { N_("Unknown"), N_("Menu"), N_("PopupMenu"), N_("DropdownMenu"), N_("Tooltip") }; #define N_CLOSE2_DEFAULT_WIN_TYPE (sizeof (close2DefaultWinType) / sizeof (close2DefaultWinType[0])) static char *focusDefaultWinType[] = { N_("Normal"), N_("Dialog"), N_("ModalDialog"), N_("Dnd") }; #define N_FOCUS_DEFAULT_WIN_TYPE (sizeof (focusDefaultWinType) / sizeof (focusDefaultWinType[0])) static char *shadeDefaultWinType[] = { N_("Normal"), N_("Dialog"), N_("ModalDialog"), N_("Utility") }; #define N_SHADE_DEFAULT_WIN_TYPE (sizeof (shadeDefaultWinType) / sizeof (shadeDefaultWinType[0])) static int displayPrivateIndex; typedef struct _AnimDisplay { int screenPrivateIndex; Atom wmHintsAtom; Atom winIconGeometryAtom; HandleEventProc handleEvent; } AnimDisplay; typedef enum { // Event settings ANIM_SCREEN_OPTION_MINIMIZE_EFFECT = 0, ANIM_SCREEN_OPTION_MINIMIZE_WINDOW_TYPE, ANIM_SCREEN_OPTION_MINIMIZE_DURATION, ANIM_SCREEN_OPTION_MINIMIZE_RANDOM_EFFECTS, ANIM_SCREEN_OPTION_UNMINIMIZE_EFFECT, ANIM_SCREEN_OPTION_UNMINIMIZE_WINDOW_TYPE, ANIM_SCREEN_OPTION_UNMINIMIZE_DURATION, ANIM_SCREEN_OPTION_UNMINIMIZE_RANDOM_EFFECTS, ANIM_SCREEN_OPTION_CLOSE1_EFFECT, ANIM_SCREEN_OPTION_CLOSE1_WINDOW_TYPE, ANIM_SCREEN_OPTION_CLOSE1_DURATION, ANIM_SCREEN_OPTION_CLOSE1_RANDOM_EFFECTS, ANIM_SCREEN_OPTION_CREATE1_EFFECT, ANIM_SCREEN_OPTION_CREATE1_WINDOW_TYPE, ANIM_SCREEN_OPTION_CREATE1_DURATION, ANIM_SCREEN_OPTION_CREATE1_RANDOM_EFFECTS, ANIM_SCREEN_OPTION_CLOSE2_EFFECT, ANIM_SCREEN_OPTION_CLOSE2_WINDOW_TYPE, ANIM_SCREEN_OPTION_CLOSE2_DURATION, ANIM_SCREEN_OPTION_CLOSE2_RANDOM_EFFECTS, ANIM_SCREEN_OPTION_CREATE2_EFFECT, ANIM_SCREEN_OPTION_CREATE2_WINDOW_TYPE, ANIM_SCREEN_OPTION_CREATE2_DURATION, ANIM_SCREEN_OPTION_CREATE2_RANDOM_EFFECTS, ANIM_SCREEN_OPTION_FOCUS_EFFECT, ANIM_SCREEN_OPTION_FOCUS_WINDOW_TYPE, ANIM_SCREEN_OPTION_FOCUS_DURATION, ANIM_SCREEN_OPTION_SHADE_EFFECT, ANIM_SCREEN_OPTION_SHADE_WINDOW_TYPE, ANIM_SCREEN_OPTION_SHADE_DURATION, ANIM_SCREEN_OPTION_SHADE_RANDOM_EFFECTS, ANIM_SCREEN_OPTION_UNSHADE_EFFECT, ANIM_SCREEN_OPTION_UNSHADE_WINDOW_TYPE, ANIM_SCREEN_OPTION_UNSHADE_DURATION, ANIM_SCREEN_OPTION_UNSHADE_RANDOM_EFFECTS, ANIM_SCREEN_OPTION_ROLLUP_FIXED_INTERIOR, // Misc. settings ANIM_SCREEN_OPTION_ALL_RANDOM, ANIM_SCREEN_OPTION_ZOOM_FROM_CENTER, ANIM_SCREEN_OPTION_DISABLE_PP_FX, ANIM_SCREEN_OPTION_TIME_STEP, ANIM_SCREEN_OPTION_TIME_STEP_INTENSE, // Effect settings ANIM_SCREEN_OPTION_BEAMUP_SIZE, ANIM_SCREEN_OPTION_BEAMUP_SPACING, ANIM_SCREEN_OPTION_BEAMUP_COLOR, ANIM_SCREEN_OPTION_BEAMUP_SLOWDOWN, ANIM_SCREEN_OPTION_BEAMUP_LIFE, ANIM_SCREEN_OPTION_CURVED_FOLD_AMP, ANIM_SCREEN_OPTION_DOMINO_DIRECTION, ANIM_SCREEN_OPTION_RAZR_DIRECTION, ANIM_SCREEN_OPTION_FIRE_PARTICLES, ANIM_SCREEN_OPTION_FIRE_SIZE, ANIM_SCREEN_OPTION_FIRE_SLOWDOWN, ANIM_SCREEN_OPTION_FIRE_LIFE, ANIM_SCREEN_OPTION_FIRE_COLOR, ANIM_SCREEN_OPTION_FIRE_DIRECTION, ANIM_SCREEN_OPTION_FIRE_CONSTANT_SPEED, ANIM_SCREEN_OPTION_FIRE_SMOKE, ANIM_SCREEN_OPTION_FIRE_MYSTICAL, ANIM_SCREEN_OPTION_FOCUS_WAVE_WIDTH, ANIM_SCREEN_OPTION_FOCUS_WAVE_AMP, ANIM_SCREEN_OPTION_GLIDE1_AWAY_POS, ANIM_SCREEN_OPTION_GLIDE1_AWAY_ANGLE, ANIM_SCREEN_OPTION_GLIDE1_THICKNESS, ANIM_SCREEN_OPTION_GLIDE2_AWAY_POS, ANIM_SCREEN_OPTION_GLIDE2_AWAY_ANGLE, ANIM_SCREEN_OPTION_GLIDE2_THICKNESS, ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_AMP, ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_NUM_FOLDS, ANIM_SCREEN_OPTION_MAGIC_LAMP1_GRID_RES, ANIM_SCREEN_OPTION_MAGIC_LAMP1_MAX_WAVES, ANIM_SCREEN_OPTION_MAGIC_LAMP1_WAVE_AMP_MIN, ANIM_SCREEN_OPTION_MAGIC_LAMP1_WAVE_AMP_MAX, ANIM_SCREEN_OPTION_MAGIC_LAMP1_CREATE_START_WIDTH, ANIM_SCREEN_OPTION_MAGIC_LAMP2_GRID_RES, ANIM_SCREEN_OPTION_MAGIC_LAMP2_MAX_WAVES, ANIM_SCREEN_OPTION_MAGIC_LAMP2_WAVE_AMP_MIN, ANIM_SCREEN_OPTION_MAGIC_LAMP2_WAVE_AMP_MAX, ANIM_SCREEN_OPTION_MAGIC_LAMP2_CREATE_START_WIDTH, ANIM_SCREEN_OPTION_MAGIC_LAMP3_GRID_RES, ANIM_SCREEN_OPTION_MAGIC_LAMP3_MAX_WAVES, ANIM_SCREEN_OPTION_MAGIC_LAMP3_WAVE_AMP_MIN, ANIM_SCREEN_OPTION_MAGIC_LAMP3_WAVE_AMP_MAX, ANIM_SCREEN_OPTION_MAGIC_LAMP3_CREATE_START_WIDTH, ANIM_SCREEN_OPTION_SIDEKICK_NUM_ROTATIONS, ANIM_SCREEN_OPTION_NUM } AnimScreenOptions; typedef struct _AnimScreen { int windowPrivateIndex; PreparePaintScreenProc preparePaintScreen; DonePaintScreenProc donePaintScreen; PaintScreenProc paintScreen; PaintWindowProc paintWindow; DamageWindowRectProc damageWindowRect; AddWindowGeometryProc addWindowGeometry; DrawWindowGeometryProc drawWindowGeometry; DrawWindowTextureProc drawWindowTexture; WindowResizeNotifyProc windowResizeNotify; WindowMoveNotifyProc windowMoveNotify; WindowGrabNotifyProc windowGrabNotify; WindowUngrabNotifyProc windowUngrabNotify; CompOption opt[ANIM_SCREEN_OPTION_NUM]; PostprocessDisabling ppDisabling; ZoomFromCenter zoomFC; Bool animInProgress; AnimEffect minimizeEffect; AnimEffect unminimizeEffect; AnimEffect create1Effect; AnimEffect create2Effect; AnimEffect close1Effect; AnimEffect close2Effect; AnimEffect focusEffect; AnimEffect shadeEffect; AnimEffect unshadeEffect; unsigned int minimizeWMask; unsigned int unminimizeWMask; unsigned int create1WMask; unsigned int create2WMask; unsigned int close1WMask; unsigned int close2WMask; unsigned int focusWMask; unsigned int shadeWMask; unsigned int unshadeWMask; AnimEffect close1RandomEffects[NUM_CLOSE_EFFECT]; AnimEffect close2RandomEffects[NUM_CLOSE_EFFECT]; AnimEffect create1RandomEffects[NUM_CLOSE_EFFECT]; AnimEffect create2RandomEffects[NUM_CLOSE_EFFECT]; AnimEffect minimizeRandomEffects[NUM_MINIMIZE_EFFECT]; AnimEffect unminimizeRandomEffects[NUM_MINIMIZE_EFFECT]; AnimEffect shadeRandomEffects[NUM_SHADE_EFFECT]; AnimEffect unshadeRandomEffects[NUM_SHADE_EFFECT]; unsigned int nClose1RandomEffects; unsigned int nClose2RandomEffects; unsigned int nCreate1RandomEffects; unsigned int nCreate2RandomEffects; unsigned int nMinimizeRandomEffects; unsigned int nUnminimizeRandomEffects; unsigned int nShadeRandomEffects; unsigned int nUnshadeRandomEffects; } AnimScreen; typedef struct _AnimWindow { Model *model; int numPs; ParticleSystem *ps; unsigned int state; unsigned int newState; PolygonSet *polygonSet; float mvm[16]; Region drawRegion; Bool useDrawRegion; XRectangle icon; XRectangle origWindowRect; XRectangle lastKnownCoords; // used to determine if paintWindow is drawing // on the viewport that the animation started float numZoomRotations; GLushort storedOpacity; float timestep; // to be used in updateWindowAttribFunc int nDrawGeometryCalls; Bool animInitialized; // whether the animation effect (not the window) is initialized float animTotalTime; float animRemainingTime; int animOverrideProgressDir; // 0: default dir, 1: forward, 2: backward Bool nowShaded; Bool grabbed; WindowEvent curWindowEvent; AnimEffect curAnimEffect; int unmapCnt; int destroyCnt; int nClipsPassed; // # of clips passed to animAddWindowGeometry so far // in this draw step Bool clipsUpdated; // whether stored clips are updated in this anim step WindowPaintAttrib curPaintAttrib; CompTexture *curTexture; int curTextureFilter; int animatedAtom; int animFireDirection; int subEffectNo; // For effects that share same functions Bool deceleratingMotion; // For effects that have decel. motion } AnimWindow; typedef struct _AnimEffectProperties { void (*updateWindowAttribFunc) (AnimScreen *, AnimWindow *, WindowPaintAttrib *); void (*prePaintWindowFunc) (CompScreen *, CompWindow *); void (*postPaintWindowFunc) (CompScreen *, CompWindow *); void (*animStepFunc) (CompScreen *, CompWindow *, float time); void (*initFunc) (CompScreen *, CompWindow *); void (*initGridFunc) (AnimScreen *, WindowEvent, int *, int *); void (*addCustomGeometryFunc) (CompScreen *, CompWindow *, int, Box *, int, CompMatrix *); void (*drawCustomGeometryFunc) (CompScreen *, CompWindow *); Bool dontUseQTexCoord; // TRUE if effect doesn't need Q coord. void (*animStepPolygonFunc) (CompWindow *, PolygonObject *, float); int subEffectNo; // For effects that share same functions } AnimEffectProperties; AnimEffectProperties *animEffectPropertiesTmp; #define GET_ANIM_DISPLAY(d) \ ((AnimDisplay *) (d)->privates[displayPrivateIndex].ptr) #define ANIM_DISPLAY(d) \ AnimDisplay *ad = GET_ANIM_DISPLAY (d) #define GET_ANIM_SCREEN(s, ad) \ ((AnimScreen *) (s)->privates[(ad)->screenPrivateIndex].ptr) #define ANIM_SCREEN(s) \ AnimScreen *as = GET_ANIM_SCREEN (s, GET_ANIM_DISPLAY (s->display)) #define GET_ANIM_WINDOW(w, as) \ ((AnimWindow *) (w)->privates[(as)->windowPrivateIndex].ptr) #define ANIM_WINDOW(w) \ AnimWindow *aw = GET_ANIM_WINDOW (w, \ GET_ANIM_SCREEN (w->screen, \ GET_ANIM_DISPLAY (w->screen->display))) #define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption)) #define LIST_SIZE(l) (sizeof (l) / sizeof (l[0])) // iterate over given list // check if given effect name matches any implemented effect // Check if it was already in the stored list // if not, store the effect // if no valid effect is given, use the default effect #define STORE_RANDOM_EFFECT_LIST(option, nFxChoices, defaultValue, nStoredRandomFx, storedRandomFx, fxNames, fxIds) \ { \ CompOptionValue *effect = as->opt[(option)].value.list.value; \ int nListItems = as->opt[(option)].value.list.nValue; \ \ as->nStoredRandomFx = 0; \ int j; \ for (j = 0; j < nListItems; j++, effect++) \ { \ int i; \ for (i = 2; i < (nFxChoices); i++) \ { \ if (strcmp(effect->s, fxNames[i]) == 0) \ { \ Bool duplicate = FALSE; \ int k; \ for (k = 0; k < as->nStoredRandomFx; k++) \ if (as->storedRandomFx[k] == \ fxIds[i]) \ { \ duplicate = TRUE; \ break; \ } \ if (!duplicate) \ { \ as->storedRandomFx[as->nStoredRandomFx] \ = fxIds[i]; \ as->nStoredRandomFx++; \ } \ break; \ } \ } \ } \ if (nListItems == 0 || as->nStoredRandomFx == 0) \ { \ as->storedRandomFx[0] = (defaultValue); \ as->nStoredRandomFx = 1; \ } \ } #define INIT_RANDOM_EFFECT_LIST(poption, pname, pgroup, psubgroup, nFxChoices, fxNames) \ { \ o = &as->opt[(poption)]; \ o->advanced = False; \ o->name = pname "_random_effects"; \ o->group = N_(pgroup); \ o->subGroup = N_(psubgroup); \ o->displayHints = ""; \ o->shortDesc = N_("Random Effect Pool"); \ o->longDesc = \ N_("Pool of effects to be chosen from if Random effect is " \ "selected. Click reset to restore full list. If the list " \ "is empty, the default effect will be used."); \ o->type = CompOptionTypeList; \ o->value.list.type = CompOptionTypeString; \ o->value.list.nValue = (nFxChoices) - 2; \ o->value.list.value = \ malloc(sizeof(CompOptionValue) * ((nFxChoices) - 2)); \ for (i = 2; i < (nFxChoices); i++) \ o->value.list.value[i - 2].s = strdup(fxNames[i]); \ o->rest.s.string = fxNames+2; \ o->rest.s.nString = (nFxChoices) - 2; \ } #define sigmoid(fx) (1.0f/(1.0f+exp(-5.0f*2*((fx)-0.5)))) #define sigmoid2(fx, s) (1.0f/(1.0f+exp(-(s)*2*((fx)-0.5)))) static void modelCalcBounds(Model * model) { int i; model->topLeft.x = MAXSHORT; model->topLeft.y = MAXSHORT; model->bottomRight.x = MINSHORT; model->bottomRight.y = MINSHORT; for (i = 0; i < model->numObjects; i++) { if (model->objects[i].position.x < model->topLeft.x) model->topLeft.x = model->objects[i].position.x; else if (model->objects[i].position.x > model->bottomRight.x) model->bottomRight.x = model->objects[i].position.x; if (model->objects[i].position.y < model->topLeft.y) model->topLeft.y = model->objects[i].position.y; else if (model->objects[i].position.y > model->bottomRight.y) model->bottomRight.y = model->objects[i].position.y; } } static Bool ensureLargerClipCapacity(PolygonSet * pset) { if (pset->clipCapacity == pset->nClips) // if list full { Clip4Polygons *newList = realloc (pset->clips, sizeof(Clip4Polygons) * (pset->clipCapacity + ANIM_CLIP_LIST_INCREMENT)); if (!newList) return FALSE; // reset newly allocated part of this memory to 0 memset(newList + pset->clipCapacity, 0, sizeof(Clip4Polygons) * ANIM_CLIP_LIST_INCREMENT); int *newList2 = realloc (pset->lastClipInGroup, sizeof(int) * (pset->clipCapacity + ANIM_CLIP_LIST_INCREMENT)); if (!newList2) { free(newList); pset->clips = 0; pset->lastClipInGroup = 0; return FALSE; } // reset newly allocated part of this memory to 0 memset(newList2 + pset->clipCapacity, 0, sizeof(int) * ANIM_CLIP_LIST_INCREMENT); pset->clips = newList; pset->clipCapacity += ANIM_CLIP_LIST_INCREMENT; pset->lastClipInGroup = newList2; } return TRUE; } static float defaultAnimProgress(AnimWindow * aw) { float forwardProgress = 1 - (aw->animRemainingTime - aw->timestep) / (aw->animTotalTime - aw->timestep); if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventUnshade) forwardProgress = 1 - forwardProgress; return forwardProgress; } // Converts animation direction string to an integer direction // (up, down, left, or right) static AnimDirection getAnimationDirection(CompWindow * w, char *optionValue, Bool openDir) { ANIM_WINDOW(w); AnimDirection dir = AnimDirectionUp; int i; for (i = 0; i < LIST_SIZE(animDirectionName); i++) { if (strcmp(optionValue, animDirectionName[i]) == 0) { dir = i; } } if (dir == AnimDirectionRandom) { dir = rand() % 4; } else if (dir == AnimDirectionAuto) { // away from icon int centerX = BORDER_X(w) + BORDER_W(w) / 2; int centerY = BORDER_Y(w) + BORDER_H(w) / 2; float relDiffX = ((float)centerX - aw->icon.x) / BORDER_W(w); float relDiffY = ((float)centerY - aw->icon.y) / BORDER_H(w); if (openDir) { if (aw->curWindowEvent == WindowEventMinimize || aw->curWindowEvent == WindowEventUnminimize) // min/unmin. should always result in +/- y direction dir = aw->icon.y < w->screen->height - aw->icon.y ? AnimDirectionDown : AnimDirectionUp; else if (fabs(relDiffY) > fabs(relDiffX)) dir = relDiffY > 0 ? AnimDirectionDown : AnimDirectionUp; else dir = relDiffX > 0 ? AnimDirectionRight : AnimDirectionLeft; } else { if (aw->curWindowEvent == WindowEventMinimize || aw->curWindowEvent == WindowEventUnminimize) // min/unmin. should always result in +/- y direction dir = aw->icon.y < w->screen->height - aw->icon.y ? AnimDirectionUp : AnimDirectionDown; else if (fabs(relDiffY) > fabs(relDiffX)) dir = relDiffY > 0 ? AnimDirectionUp : AnimDirectionDown; else dir = relDiffX > 0 ? AnimDirectionLeft : AnimDirectionRight; } } return dir; } // Gives some acceleration (when closing a window) // or deceleration (when opening a window) // Applies a sigmoid with slope s, // where minx and maxx are the // starting and ending points on the sigmoid static float decelerateProgressCustom(float progress, float minx, float maxx) { float x = 1 - progress; float s = 8; return (1 - ((sigmoid2(minx + (x * (maxx - minx)), s) - sigmoid2(minx, s)) / (sigmoid2(maxx, s) - sigmoid2(minx, s)))); } // default x limits for deceleration sigmoid #define DECEL_SIG_DEF_START 0.9 #define DECEL_SIG_DEF_END 1.3 /* static float decelerateProgress(float progress) { return decelerateProgressCustom (progress, DECEL_SIG_DEF_START, DECEL_SIG_DEF_END); } */ static float decelerateProgress2(float progress) { return decelerateProgressCustom(progress, 0.5, 0.75); } static void applyTransformToObject(Object *obj, GLfloat *mat) { Point3d o = obj->posRel3d; float x = o.x * mat[0] + o.y * mat[4] + o.z * mat[8] + 1 * mat[12]; float y = o.x * mat[1] + o.y * mat[5] + o.z * mat[9] + 1 * mat[13]; // ignore z float w = o.x * mat[3] + o.y * mat[7] + o.z * mat[11] + 1 * mat[15]; obj->position.x = x / w; obj->position.y = y / w; } static void obtainTransformMatrix (CompScreen *s, GLfloat *mat, float rotAngle, Vector3d rotAxis, Point3d translation) { glPushMatrix(); glLoadIdentity(); // column-major order GLfloat perspMat[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1.0/s->width, 0, 0, 1, 1}; glTranslatef(0, 0, DEFAULT_Z_CAMERA * s->width); glMultMatrixf(perspMat); glTranslatef(translation.x, translation.y, translation.z); glRotatef(rotAngle, rotAxis.x, rotAxis.y, rotAxis.z); glGetFloatv(GL_MODELVIEW_MATRIX, mat); glPopMatrix(); } static void polygonsAnimStep(CompScreen * s, CompWindow * w, float time) { int i, j, steps; ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); aw->timestep = timestep; model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); for (j = 0; j < steps; j++) { float forwardProgress = defaultAnimProgress(aw); if (aw->polygonSet) { if (animEffectPropertiesTmp[aw->curAnimEffect]. animStepPolygonFunc) { for (i = 0; i < aw->polygonSet->nPolygons; i++) animEffectPropertiesTmp[aw->curAnimEffect]. animStepPolygonFunc (w, &aw->polygonSet->polygons[i], forwardProgress); } } else fprintf(stderr, "%s: pset null at line %d\n", __FILE__, __LINE__); aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } modelCalcBounds(model); } // ===================== Effect: Magic Lamp ========================= static void fxMagicLamp1InitGrid(AnimScreen * as, WindowEvent forWindowEvent, int *gridWidth, int *gridHeight) { *gridWidth = 2; *gridHeight = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_GRID_RES].value.i; } static void fxMagicLamp2InitGrid(AnimScreen * as, WindowEvent forWindowEvent, int *gridWidth, int *gridHeight) { *gridWidth = 2; *gridHeight = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP2_GRID_RES].value.i; } static void fxMagicLamp3InitGrid(AnimScreen * as, WindowEvent forWindowEvent, int *gridWidth, int *gridHeight) { *gridWidth = 2; *gridHeight = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP3_GRID_RES].value.i; } static void fxMagicLampInit(CompScreen * s, CompWindow * w) { ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; int screenHeight = s->height; Bool minimizeToTop = (WIN_Y(w) + WIN_H(w) / 2) > (aw->icon.y + aw->icon.height / 2); int maxWaves; float waveAmpMin, waveAmpMax; if (aw->curAnimEffect == AnimEffectMagicLamp1) { maxWaves = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_MAX_WAVES].value.i; waveAmpMin = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_WAVE_AMP_MIN].value.f; waveAmpMax = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_WAVE_AMP_MAX].value.f; } else if (aw->curAnimEffect == AnimEffectMagicLamp2) { maxWaves = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP2_MAX_WAVES].value.i; waveAmpMin = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP2_WAVE_AMP_MIN].value.f; waveAmpMax = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP2_WAVE_AMP_MAX].value.f; } else { maxWaves = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP3_MAX_WAVES].value.i; waveAmpMin = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP3_WAVE_AMP_MIN].value.f; waveAmpMax = as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP3_WAVE_AMP_MAX].value.f; } if (waveAmpMax < waveAmpMin) waveAmpMax = waveAmpMin; if (maxWaves > 0) { float distance; if (minimizeToTop) distance = WIN_Y(w) + WIN_H(w) - aw->icon.y; else distance = aw->icon.y - WIN_Y(w); // Initialize waves model->magicLampWaveCount = 1 + (float)maxWaves *distance / screenHeight; if (!(model->magicLampWaves)) model->magicLampWaves = calloc(1, model->magicLampWaveCount * sizeof(WaveParam)); int ampDirection = (RAND_FLOAT() < 0.5 ? 1 : -1); int i; float minHalfWidth = 0.22f; float maxHalfWidth = 0.38f; for (i = 0; i < model->magicLampWaveCount; i++) { model->magicLampWaves[i].amp = ampDirection * (waveAmpMax - waveAmpMin) * rand() / RAND_MAX + ampDirection * waveAmpMin; model->magicLampWaves[i].halfWidth = RAND_FLOAT() * (maxHalfWidth - minHalfWidth) + minHalfWidth; // avoid offset at top and bottom part by added waves float availPos = 1 - 2 * model->magicLampWaves[i].halfWidth; float posInAvailSegment = 0; if (i > 0) posInAvailSegment = (availPos / model->magicLampWaveCount) * rand() / RAND_MAX; model->magicLampWaves[i].pos = (posInAvailSegment + i * availPos / model->magicLampWaveCount + model->magicLampWaves[i].halfWidth); // switch wave direction ampDirection *= -1; } } else model->magicLampWaveCount = 0; } static void fxMagicLampModelStepObject(CompWindow * w, Model * model, Object * object, float forwardProgress, Bool minimizeToTop) { ANIM_WINDOW(w); float iconCloseEndY; float iconFarEndY; float winFarEndY; float winVisibleCloseEndY; if (minimizeToTop) { iconFarEndY = aw->icon.y; iconCloseEndY = aw->icon.y + aw->icon.height; winFarEndY = WIN_Y(w) + WIN_H(w); winVisibleCloseEndY = WIN_Y(w); if (winVisibleCloseEndY < iconCloseEndY) winVisibleCloseEndY = iconCloseEndY; } else { iconFarEndY = aw->icon.y + aw->icon.height; iconCloseEndY = aw->icon.y; winFarEndY = WIN_Y(w); winVisibleCloseEndY = WIN_Y(w) + WIN_H(w); if (winVisibleCloseEndY > iconCloseEndY) winVisibleCloseEndY = iconCloseEndY; } float preShapePhaseEnd = 0.17f; float stretchPhaseEnd = preShapePhaseEnd + (1 - preShapePhaseEnd) * (iconCloseEndY - winVisibleCloseEndY) / ((iconCloseEndY - winFarEndY) + (iconCloseEndY - winVisibleCloseEndY)); if (stretchPhaseEnd < preShapePhaseEnd + 0.1) stretchPhaseEnd = preShapePhaseEnd + 0.1; float origx = w->attrib.x + (WIN_W(w) * object->gridPosition.x - w->output.left) * model->scale.x; float origy = w->attrib.y + (WIN_H(w) * object->gridPosition.y - w->output.top) * model->scale.y; float iconShadowLeft = ((float)(w->output.left - w->input.left)) * aw->icon.width / w->width; float iconShadowRight = ((float)(w->output.right - w->input.right)) * aw->icon.width / w->width; float iconx = (aw->icon.x - iconShadowLeft) + (aw->icon.width + iconShadowLeft + iconShadowRight) * object->gridPosition.x; float icony = aw->icon.y + aw->icon.height * object->gridPosition.y; if (forwardProgress < preShapePhaseEnd) { float preShapeProgress = forwardProgress / preShapePhaseEnd; float fx = (iconCloseEndY - object->position.y) / (iconCloseEndY - winFarEndY); float fy = (sigmoid(fx) - sigmoid(0)) / (sigmoid(1) - sigmoid(0)); int i; float targetx = fy * (origx - iconx) + iconx; for (i = 0; i < model->magicLampWaveCount; i++) { float cosfx = (fx - model->magicLampWaves[i].pos) / model->magicLampWaves[i].halfWidth; if (cosfx < -1 || cosfx > 1) continue; targetx += model->magicLampWaves[i].amp * model->scale.x * (cos(cosfx * M_PI) + 1) / 2; } object->position.x = (1 - preShapeProgress) * origx + preShapeProgress * targetx; object->position.y = origy; } else { float stretchedPos; if (minimizeToTop) stretchedPos = object->gridPosition.y * origy + (1 - object->gridPosition.y) * icony; else stretchedPos = (1 - object->gridPosition.y) * origy + object->gridPosition.y * icony; if (forwardProgress < stretchPhaseEnd) { float stretchProgress = (forwardProgress - preShapePhaseEnd) / (stretchPhaseEnd - preShapePhaseEnd); object->position.y = (1 - stretchProgress) * origy + stretchProgress * stretchedPos; } else { float postStretchProgress = (forwardProgress - stretchPhaseEnd) / (1 - stretchPhaseEnd); object->position.y = (1 - postStretchProgress) * stretchedPos + postStretchProgress * (stretchedPos + (iconCloseEndY - winFarEndY)); } float fx = (iconCloseEndY - object->position.y) / (iconCloseEndY - winFarEndY); float fy = (sigmoid(fx) - sigmoid(0)) / (sigmoid(1) - sigmoid(0)); int i; object->position.x = fy * (origx - iconx) + iconx; for (i = 0; i < model->magicLampWaveCount; i++) { float cosfx = (fx - model->magicLampWaves[i].pos) / model->magicLampWaves[i].halfWidth; if (cosfx < -1 || cosfx > 1) continue; object->position.x += model->magicLampWaves[i].amp * model->scale.x * (cos(cosfx * M_PI) + 1) / 2; } } if (minimizeToTop) { if (object->position.y < iconFarEndY) object->position.y = iconFarEndY; } else { if (object->position.y > iconFarEndY) object->position.y = iconFarEndY; } } static void fxMagicLampModelStep(CompScreen * s, CompWindow * w, float time) { int i, j, steps; ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); Bool minimizeToTop = (WIN_Y(w) + WIN_H(w) / 2) > (aw->icon.y + aw->icon.height / 2); for (j = 0; j < steps; j++) { float forwardProgress = 1 - (aw->animRemainingTime - timestep) / (aw->animTotalTime - timestep); if (aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventCreate) forwardProgress = 1 - forwardProgress; for (i = 0; i < model->numObjects; i++) { fxMagicLampModelStepObject(w, model, &model->objects[i], forwardProgress, minimizeToTop); } aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } modelCalcBounds(model); } // ===================== Effect: Dream ========================= static void fxDreamInit(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); ANIM_SCREEN(s); // store window opacity aw->storedOpacity = w->paint.opacity; aw->timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); } static void fxDreamModelStepObject(CompWindow * w, Model * model, Object * object, float forwardProgress) { float waveAmpMax = MIN(WIN_H(w), WIN_W(w)) * 0.125f; float waveWidth = 10.0f; float waveSpeed = 7.0f; float origx = w->attrib.x + (WIN_W(w) * object->gridPosition.x - w->output.left) * model->scale.x; float origy = w->attrib.y + (WIN_H(w) * object->gridPosition.y - w->output.top) * model->scale.y; object->position.y = origy; object->position.x = origx + forwardProgress * waveAmpMax * model->scale.x * sin(object->gridPosition.y * M_PI * waveWidth + waveSpeed * forwardProgress); } static void fxDreamModelStep(CompScreen * s, CompWindow * w, float time) { int i, j, steps; ANIM_WINDOW(w); ANIM_SCREEN(s); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); aw->timestep = timestep; model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); for (j = 0; j < steps; j++) { float forwardProgress = 1 - (aw->animRemainingTime - timestep) / (aw->animTotalTime - timestep); if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize) forwardProgress = 1 - forwardProgress; for (i = 0; i < model->numObjects; i++) { fxDreamModelStepObject(w, model, &model->objects[i], forwardProgress); } aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } modelCalcBounds(model); } static void fxDreamUpdateWindowAttrib(AnimScreen * as, AnimWindow * aw, WindowPaintAttrib * wAttrib) { float forwardProgress = 1 - (aw->animRemainingTime - aw->timestep) / (aw->animTotalTime - aw->timestep); forwardProgress = MIN(forwardProgress, 1); forwardProgress = MAX(forwardProgress, 0); if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize) forwardProgress = 1 - forwardProgress; wAttrib->opacity = (GLushort) (aw->storedOpacity * (1 - forwardProgress)); } // ===================== Effect: Wave ========================= static void fxWaveModelStepObject(CompWindow * w, Model * model, Object * object, float forwardProgress, float waveAmp, float waveHalfWidth) { float origx = w->attrib.x + (WIN_W(w) * object->gridPosition.x - w->output.left) * model->scale.x; float origy = w->attrib.y + (WIN_H(w) * object->gridPosition.y - w->output.top) * model->scale.y; float wavePosition = WIN_Y(w) - waveHalfWidth + forwardProgress * (WIN_H(w) * model->scale.y + 2 * waveHalfWidth); object->position.y = origy; object->position.x = origx; if (fabs(object->position.y - wavePosition) < waveHalfWidth) object->position.x += (object->gridPosition.x - 0.5) * waveAmp * (cos ((object->position.y - wavePosition) * M_PI / waveHalfWidth) + 1) / 2; } static void fxWaveModelStep(CompScreen * s, CompWindow * w, float time) { int i, j, steps; ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); for (j = 0; j < steps; j++) { float forwardProgress = 1 - (aw->animRemainingTime - timestep) / (aw->animTotalTime - timestep); for (i = 0; i < model->numObjects; i++) { fxWaveModelStepObject(w, model, &model->objects[i], forwardProgress, WIN_H(w) * model->scale.y * as-> opt [ANIM_SCREEN_OPTION_FOCUS_WAVE_AMP]. value.f, WIN_H(w) * model->scale.y * as-> opt [ANIM_SCREEN_OPTION_FOCUS_WAVE_WIDTH]. value.f / 2); } aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } modelCalcBounds(model); } // ===================== Effect: Zoom and Sidekick ========================= static void fxSidekickInit(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); ANIM_SCREEN(s); // determine number of rotations randomly in [0.75, 1.25] range aw->numZoomRotations = as->opt[ANIM_SCREEN_OPTION_SIDEKICK_NUM_ROTATIONS].value.f * (1.0 + 0.2 * rand() / RAND_MAX - 0.1); // store window opacity aw->storedOpacity = w->paint.opacity; aw->timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); } static void fxZoomInit(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); ANIM_SCREEN(s); // store window opacity aw->storedOpacity = w->paint.opacity; aw->timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); } // Provides the animation progress for Zoom static float fxZoomAnimProgressDirCustom(AnimWindow * aw, float maxSigX) { // maxSig is the max x for the deceleration sigmoid float forwardProgress = 1 - (aw->animRemainingTime - aw->timestep) / (aw->animTotalTime - aw->timestep); int animProgressDir = 1; if (aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventCreate) animProgressDir = 2; if (aw->animOverrideProgressDir != 0) animProgressDir = aw->animOverrideProgressDir; float x = forwardProgress; if ((animProgressDir == 1 && (aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventCreate)) || (animProgressDir == 2 && (aw->curWindowEvent == WindowEventMinimize || aw->curWindowEvent == WindowEventClose))) x = 1 - forwardProgress; forwardProgress = decelerateProgressCustom (1 - x, DECEL_SIG_DEF_START, maxSigX); if (animProgressDir == 1) forwardProgress = 1 - forwardProgress; return forwardProgress; } static float fxZoomAnimProgressDir(AnimWindow * aw) { return fxZoomAnimProgressDirCustom(aw, DECEL_SIG_DEF_END); } static void fxSidekickModelStepObject(CompWindow * w, Model * model, Object * object, Point currentCenter, Point currentSize, float sinRot, float cosRot) { float x = currentCenter.x - currentSize.x / 2 + currentSize.x * object->gridPosition.x; float y = currentCenter.y - currentSize.y / 2 + currentSize.y * object->gridPosition.y; x -= currentCenter.x; y -= currentCenter.y; object->position.x = cosRot * x - sinRot * y; object->position.y = sinRot * x + cosRot * y; object->position.x += currentCenter.x; object->position.y += currentCenter.y; } static void fxZoomModelStepObject(CompScreen *s, CompWindow * w, Model * model, Object * object, Point currentCenter, Point currentSize) { object->position.x = currentCenter.x - currentSize.x / 2 + currentSize.x * object->gridPosition.x; object->position.y = currentCenter.y - currentSize.y / 2 + currentSize.y * object->gridPosition.y; } static void fxZoomModelStep(CompScreen * s, CompWindow * w, float time) { int i, j, steps; ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); aw->timestep = timestep; model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); for (j = 0; j < steps; j++) { float sinRot = 0; float cosRot = 0; Point winCenter = {(WIN_X(w) + WIN_W(w) * model->scale.x / 2), (WIN_Y(w) + WIN_H(w) * model->scale.y / 2)}; Point iconCenter = {aw->icon.x + aw->icon.width / 2, aw->icon.y + aw->icon.height / 2}; Point winSize = {WIN_W(w) * model->scale.x, WIN_H(w) * model->scale.y}; //float xDiff = fabs(winCenter.x - iconCenter.x); //float yDiff = fabs(winCenter.y - iconCenter.y); float xMaxSig; float yMaxSig; xMaxSig = DECEL_SIG_DEF_END; yMaxSig = DECEL_SIG_DEF_END; float xProgress = fxZoomAnimProgressDirCustom(aw, xMaxSig); float yProgress = fxZoomAnimProgressDirCustom(aw, yMaxSig); float progress = (xProgress + yProgress) / 2; Point currentCenter = {(1 - xProgress) * winCenter.x + xProgress * iconCenter.x, (1 - yProgress) * winCenter.y + yProgress * iconCenter.y}; Point currentSize = {(1 - progress) * winSize.x + progress * aw->icon.width, (1 - progress) * winSize.y + progress * aw->icon.height}; if (aw->curAnimEffect == AnimEffectSidekick) { sinRot = sin(2 * M_PI * progress * aw->numZoomRotations); cosRot = cos(2 * M_PI * progress * aw->numZoomRotations); for (i = 0; i < model->numObjects; i++) fxSidekickModelStepObject(w, model, &model-> objects[i], currentCenter, currentSize, sinRot, cosRot); } else for (i = 0; i < model->numObjects; i++) fxZoomModelStepObject(s, w, model, &model->objects[i], currentCenter, currentSize); aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } modelCalcBounds(model); } static void fxZoomUpdateWindowAttrib(AnimScreen * as, AnimWindow * aw, WindowPaintAttrib * wAttrib) { if (aw->model->scale.x < 1.0 && // if Scale plugin in progress aw->curWindowEvent == WindowEventUnminimize) // and if unminimizing return; // then allow Fade to take over opacity float forwardProgress = fxZoomAnimProgressDir(aw); forwardProgress = MIN(forwardProgress, 1); forwardProgress = MAX(forwardProgress, 0); wAttrib->opacity = (GLushort) (aw->storedOpacity * pow(1 - forwardProgress, 0.75)); } // ===================== Effect: Glide ========================= static void fxGlideGetParams (AnimScreen *as, AnimWindow *aw, float *finalDistFac, float *finalRotAng, float *thickness) { // Sub effects: // 1: Glide 1 // 2: Glide 2 if (aw->subEffectNo == 1) { *finalDistFac = as->opt[ANIM_SCREEN_OPTION_GLIDE1_AWAY_POS].value.f; *finalRotAng = as->opt[ANIM_SCREEN_OPTION_GLIDE1_AWAY_ANGLE].value.f; *thickness = as->opt[ANIM_SCREEN_OPTION_GLIDE1_THICKNESS].value.f; } else { *finalDistFac = as->opt[ANIM_SCREEN_OPTION_GLIDE2_AWAY_POS].value.f; *finalRotAng = as->opt[ANIM_SCREEN_OPTION_GLIDE2_AWAY_ANGLE].value.f; *thickness = as->opt[ANIM_SCREEN_OPTION_GLIDE2_THICKNESS].value.f; } } static float fxGlideAnimProgress(AnimWindow * aw) { float forwardProgress = 1 - (aw->animRemainingTime - aw->timestep) / (aw->animTotalTime - aw->timestep); if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventUnshade) forwardProgress = 1 - forwardProgress; return decelerateProgress2(forwardProgress); } static void fxGlideModelStepObject(CompWindow * w, Model * model, Object * obj, GLfloat *mat, Point3d rotAxisOffset) { float origx = w->attrib.x + (WIN_W(w) * obj->gridPosition.x - w->output.left) * model->scale.x; float origy = w->attrib.y + (WIN_H(w) * obj->gridPosition.y - w->output.top) * model->scale.y; obj->posRel3d.x = origx - rotAxisOffset.x; obj->posRel3d.y = origy - rotAxisOffset.y; applyTransformToObject(obj, mat); obj->position.x += rotAxisOffset.x; obj->position.y += rotAxisOffset.y; } static void fxGlideAnimStep(CompScreen * s, CompWindow * w, float time) { ANIM_SCREEN(s); ANIM_WINDOW(w); float finalDistFac; float finalRotAng; float thickness; fxGlideGetParams(as, aw, &finalDistFac, &finalRotAng, &thickness); if (thickness > 1e-5) // the effect is 3D { polygonsAnimStep(s, w, time); // do 3D anim step instead return; } // for 2D glide effect // ------------------------ int i, j, steps; Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); aw->timestep = timestep; model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); for (j = 0; j < steps; j++) { float forwardProgress = fxGlideAnimProgress(aw); float finalz = finalDistFac * 0.8 * DEFAULT_Z_CAMERA * s->width; Vector3d rotAxis = {1, 0, 0}; Point3d rotAxisOffset = {WIN_X(w) + WIN_W(w) * model->scale.x / 2, WIN_Y(w) + WIN_H(w) * model->scale.y / 2, 0}; Point3d modelPos = {0, 0, finalz * forwardProgress}; GLfloat mat[16]; obtainTransformMatrix(s, mat, finalRotAng * forwardProgress, rotAxis, modelPos); for (i = 0; i < model->numObjects; i++) fxGlideModelStepObject(w, model, &model->objects[i], mat, rotAxisOffset); aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } modelCalcBounds(model); } static void fxGlideUpdateWindowAttrib(AnimScreen * as, AnimWindow * aw, WindowPaintAttrib * wAttrib) { float finalDistFac; float finalRotAng; float thickness; fxGlideGetParams(as, aw, &finalDistFac, &finalRotAng, &thickness); if (thickness > 1e-5) // the effect is 3D return; // the effect is 2D if (aw->model->scale.x < 1.0 && // if Scale plugin in progress aw->curWindowEvent == WindowEventUnminimize) // and if unminimizing return; // then allow Fade to take over opacity float forwardProgress = fxGlideAnimProgress(aw); wAttrib->opacity = aw->storedOpacity * (1 - forwardProgress); } // ===================== Effect: Curved Fold ========================= static void fxCurvedFoldModelStepObject(CompWindow * w, Model * model, Object * object, float forwardProgress, float curveMaxAmp) { ANIM_WINDOW(w); float origx = w->attrib.x + (WIN_W(w) * object->gridPosition.x - w->output.left) * model->scale.x; float origy = w->attrib.y + (WIN_H(w) * object->gridPosition.y - w->output.top) * model->scale.y; if (aw->curWindowEvent == WindowEventShade || aw->curWindowEvent == WindowEventUnshade) { // Execute shade mode // find position in window contents // (window contents correspond to 0.0-1.0 range) float relPosInWinContents = (object->gridPosition.y * WIN_H(w) - model->topHeight) / w->height; float relDistToCenter = fabs(relPosInWinContents - 0.5); if (object->gridPosition.y == 0) { object->position.x = origx; object->position.y = WIN_Y(w); } else if (object->gridPosition.y == 1) { object->position.x = origx; object->position.y = (1 - forwardProgress) * origy + forwardProgress * (WIN_Y(w) + model->topHeight + model->bottomHeight); } else { object->position.x = origx + sin(forwardProgress * M_PI / 2) * (0.5 - object->gridPosition.x) * 2 * model->scale.x * (curveMaxAmp - curveMaxAmp * 4 * relDistToCenter * relDistToCenter); object->position.y = (1 - forwardProgress) * origy + forwardProgress * (WIN_Y(w) + model->topHeight); } } else { // Execute normal mode // find position within window borders // (border contents correspond to 0.0-1.0 range) float relPosInWinBorders = (object->gridPosition.y * WIN_H(w) - (w->output.top - w->input.top)) / BORDER_H(w); float relDistToCenter = fabs(relPosInWinBorders - 0.5); // prevent top & bottom shadows from extending too much if (relDistToCenter > 0.5) relDistToCenter = 0.5; object->position.x = origx + sin(forwardProgress * M_PI / 2) * (0.5 - object->gridPosition.x) * 2 * model->scale.x * (curveMaxAmp - curveMaxAmp * 4 * relDistToCenter * relDistToCenter); object->position.y = (1 - forwardProgress) * origy + forwardProgress * BORDER_Y(w); } } static void fxCurvedFoldModelStep(CompScreen * s, CompWindow * w, float time) { int i, j, steps; ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); for (j = 0; j < steps; j++) { float forwardProgress = 1 - (aw->animRemainingTime - timestep) / (aw->animTotalTime - timestep); if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventUnshade) forwardProgress = 1 - forwardProgress; for (i = 0; i < model->numObjects; i++) fxCurvedFoldModelStepObject(w, model, &model->objects[i], forwardProgress, as-> opt [ANIM_SCREEN_OPTION_CURVED_FOLD_AMP]. value.f * WIN_W(w)); aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } modelCalcBounds(model); } // ===================== Effect: Horizontal Folds ========================= static void fxHorizontalFoldsInitGrid(AnimScreen * as, WindowEvent forWindowEvent, int *gridWidth, int *gridHeight) { *gridWidth = 2; if (forWindowEvent == WindowEventShade || forWindowEvent == WindowEventUnshade) *gridHeight = 3 + 2 * as->opt[ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_NUM_FOLDS].value. i; else *gridHeight = 1 + 2 * as->opt[ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_NUM_FOLDS].value. i; } static void fxHorizontalFoldsModelStepObject(CompWindow * w, Model * model, Object * object, float forwardProgress, float curveMaxAmp, int rowNo) { ANIM_WINDOW(w); float origx = w->attrib.x + (WIN_W(w) * object->gridPosition.x - w->output.left) * model->scale.x; float origy = w->attrib.y + (WIN_H(w) * object->gridPosition.y - w->output.top) * model->scale.y; if (aw->curWindowEvent == WindowEventShade || aw->curWindowEvent == WindowEventUnshade) { // Execute shade mode float relDistToFoldCenter = (rowNo % 2 == 1 ? 0.5 : 0); if (object->gridPosition.y == 0) { object->position.x = origx; object->position.y = WIN_Y(w); } else if (object->gridPosition.y == 1) { object->position.x = origx; object->position.y = (1 - forwardProgress) * origy + forwardProgress * (WIN_Y(w) + model->topHeight + model->bottomHeight); } else { object->position.x = origx + sin(forwardProgress * M_PI / 2) * (0.5 - object->gridPosition.x) * 2 * model->scale.x * (curveMaxAmp - curveMaxAmp * 4 * relDistToFoldCenter * relDistToFoldCenter); object->position.y = (1 - forwardProgress) * origy + forwardProgress * (WIN_Y(w) + model->topHeight); } } else { // Execute normal mode float relDistToFoldCenter; relDistToFoldCenter = (rowNo % 2 == 0 ? 0.5 : 0); object->position.x = origx + sin(forwardProgress * M_PI / 2) * (0.5 - object->gridPosition.x) * 2 * model->scale.x * (curveMaxAmp - curveMaxAmp * 4 * relDistToFoldCenter * relDistToFoldCenter); object->position.y = (1 - forwardProgress) * origy + forwardProgress * BORDER_Y(w); } } static void fxHorizontalFoldsModelStep(CompScreen * s, CompWindow * w, float time) { int i, j, steps; ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); for (j = 0; j < steps; j++) { float forwardProgress = 1 - (aw->animRemainingTime - timestep) / (aw->animTotalTime - timestep); if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventUnshade) forwardProgress = 1 - forwardProgress; for (i = 0; i < model->numObjects; i++) fxHorizontalFoldsModelStepObject(w, model, &model-> objects[i], forwardProgress, as-> opt [ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_AMP]. value.f * WIN_W(w), i / model->gridWidth); aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } modelCalcBounds(model); } // ===================== Effect: Roll Up ========================= static void fxRollUpInitGrid(AnimScreen * as, WindowEvent forWindowEvent, int *gridWidth, int *gridHeight) { *gridWidth = 2; if (forWindowEvent == WindowEventShade || forWindowEvent == WindowEventUnshade) *gridHeight = 4; else *gridHeight = 2; } static void fxRollUpModelStepObject(CompWindow * w, Model * model, Object * object, float forwardProgress, Bool fixedInterior) { ANIM_WINDOW(w); float origx = WIN_X(w) + WIN_W(w) * object->gridPosition.x; if (aw->curWindowEvent == WindowEventShade || aw->curWindowEvent == WindowEventUnshade) { // Execute shade mode // find position in window contents // (window contents correspond to 0.0-1.0 range) float relPosInWinContents = (object->gridPosition.y * WIN_H(w) - model->topHeight) / w->height; if (object->gridPosition.y == 0) { object->position.x = origx; object->position.y = WIN_Y(w); } else if (object->gridPosition.y == 1) { object->position.x = origx; object->position.y = (1 - forwardProgress) * (WIN_Y(w) + WIN_H(w) * object->gridPosition.y) + forwardProgress * (WIN_Y(w) + model->topHeight + model->bottomHeight); } else { object->position.x = origx; if (relPosInWinContents > forwardProgress) { object->position.y = (1 - forwardProgress) * (WIN_Y(w) + WIN_H(w) * object->gridPosition.y) + forwardProgress * (WIN_Y(w) + model->topHeight); if (fixedInterior) object->offsetTexCoordForQuadBefore.y = -forwardProgress * w->height; } else { object->position.y = WIN_Y(w) + model->topHeight; if (!fixedInterior) object->offsetTexCoordForQuadAfter. y = (forwardProgress - relPosInWinContents) * w->height; } } } } static void fxRollUpModelStep(CompScreen * s, CompWindow * w, float time) { int i, j, steps; ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); for (j = 0; j < steps; j++) { float forwardProgress = 1 - (aw->animRemainingTime - timestep) / (aw->animTotalTime - timestep); forwardProgress = (sigmoid(forwardProgress) - sigmoid(0)) / (sigmoid(1) - sigmoid(0)); if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventUnshade) forwardProgress = 1 - forwardProgress; for (i = 0; i < model->numObjects; i++) fxRollUpModelStepObject(w, model, &model->objects[i], forwardProgress, as-> opt [ANIM_SCREEN_OPTION_ROLLUP_FIXED_INTERIOR]. value.b); aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } modelCalcBounds(model); } // ===================== Effect: Fade ========================= static void fxFadeInit(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); ANIM_SCREEN(s); // store window opacity aw->storedOpacity = w->paint.opacity; aw->timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); } static void fxFadeModelStep(CompScreen * s, CompWindow * w, float time) { int j, steps; ANIM_WINDOW(w); ANIM_SCREEN(s); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); aw->timestep = timestep; model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); for (j = 0; j < steps; j++) { aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) { aw->animRemainingTime = 0; // avoid sub-zero values break; } } } static void fxFadeUpdateWindowAttrib(AnimScreen * as, AnimWindow * aw, WindowPaintAttrib * wAttrib) { float forwardProgress = 1 - (aw->animRemainingTime - aw->timestep) / (aw->animTotalTime - aw->timestep); forwardProgress = MIN(forwardProgress, 1); forwardProgress = MAX(forwardProgress, 0); if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize) forwardProgress = 1 - forwardProgress; wAttrib->opacity = (GLushort) (aw->storedOpacity * (1 - forwardProgress)); } // ===================== Effect: Burn ========================= static void fxBurnInit(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); ANIM_SCREEN(s); modelInitObjects(aw->model, WIN_X(w), WIN_Y(w), WIN_W(w), WIN_H(w)); if (!aw->numPs) { aw->ps = calloc(1, 2 * sizeof(ParticleSystem)); if (!aw->ps) { postAnimationCleanup(w, TRUE); return; } aw->numPs = 2; } initParticles(as->opt[ANIM_SCREEN_OPTION_FIRE_PARTICLES].value.i / 10, &aw->ps[0]); initParticles(as->opt[ANIM_SCREEN_OPTION_FIRE_PARTICLES].value.i, &aw->ps[1]); aw->ps[1].slowdown = as->opt[ANIM_SCREEN_OPTION_FIRE_SLOWDOWN].value.f; aw->ps[1].darken = 0.5; aw->ps[1].blendMode = GL_ONE; aw->ps[0].slowdown = as->opt[ANIM_SCREEN_OPTION_FIRE_SLOWDOWN].value.f / 2.0; aw->ps[0].darken = 0.0; aw->ps[0].blendMode = GL_ONE_MINUS_SRC_ALPHA; if (!aw->ps[0].tex) glGenTextures(1, &aw->ps[0].tex); glBindTexture(GL_TEXTURE_2D, aw->ps[0].tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, fireTex); glBindTexture(GL_TEXTURE_2D, 0); if (!aw->ps[1].tex) glGenTextures(1, &aw->ps[1].tex); glBindTexture(GL_TEXTURE_2D, aw->ps[1].tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, fireTex); glBindTexture(GL_TEXTURE_2D, 0); aw->animFireDirection = getAnimationDirection (w, as->opt[ANIM_SCREEN_OPTION_FIRE_DIRECTION].value.s, FALSE); if (as->opt[ANIM_SCREEN_OPTION_FIRE_CONSTANT_SPEED].value.b) { aw->animTotalTime *= WIN_H(w) / 500.0; aw->animRemainingTime *= WIN_H(w) / 500.0; } } static void fxBurnGenNewFire(CompScreen * s, ParticleSystem * ps, int x, int y, int width, int height, float size, float time) { ANIM_SCREEN(s); float max_new = ps->numParticles * (time / 50) * (1.05 - as-> opt [ANIM_SCREEN_OPTION_FIRE_LIFE]. value.f); int i; Particle *part; float rVal; for (i = 0; i < ps->numParticles && max_new > 0; i++) { part = &ps->particles[i]; if (part->life <= 0.0f) { // give gt new life rVal = (float)(random() & 0xff) / 255.0; part->life = 1.0f; part->fade = (rVal * (1 - as->opt[ANIM_SCREEN_OPTION_FIRE_LIFE].value.f)) + (0.2f * (1.01 - as->opt[ANIM_SCREEN_OPTION_FIRE_LIFE].value.f)); // Random Fade Value // set size part->width = as->opt[ANIM_SCREEN_OPTION_FIRE_SIZE].value.f; part->height = as->opt[ANIM_SCREEN_OPTION_FIRE_SIZE].value.f * 1.5; rVal = (float)(random() & 0xff) / 255.0; part->w_mod = size * rVal; part->h_mod = size * rVal; // choose random position rVal = (float)(random() & 0xff) / 255.0; part->x = x + ((width > 1) ? (rVal * width) : 0); rVal = (float)(random() & 0xff) / 255.0; part->y = y + ((height > 1) ? (rVal * height) : 0); part->z = 0.0; part->xo = part->x; part->yo = part->y; part->zo = part->z; // set speed and direction rVal = (float)(random() & 0xff) / 255.0; part->xi = ((rVal * 20.0) - 10.0f); rVal = (float)(random() & 0xff) / 255.0; part->yi = ((rVal * 20.0) - 15.0f); part->zi = 0.0f; rVal = (float)(random() & 0xff) / 255.0; if (as->opt[ANIM_SCREEN_OPTION_FIRE_MYSTICAL].value.b) { // Random colors! (aka Mystical Fire) rVal = (float)(random() & 0xff) / 255.0; part->r = rVal; rVal = (float)(random() & 0xff) / 255.0; part->g = rVal; rVal = (float)(random() & 0xff) / 255.0; part->b = rVal; } else { // set color ABAB as->opt[ANIM_SCREEN_OPTION_FIRE_COLOR].value.f part->r = (float)as-> opt[ANIM_SCREEN_OPTION_FIRE_COLOR]. value.c[0] / 0xffff - (rVal / 1.7 * (float)as-> opt[ANIM_SCREEN_OPTION_FIRE_COLOR].value.c[0] / 0xffff); part->g = (float)as->opt[ANIM_SCREEN_OPTION_FIRE_COLOR].value. c[1] / 0xffff - (rVal / 1.7 * (float)as->opt[ANIM_SCREEN_OPTION_FIRE_COLOR].value. c[1] / 0xffff); part->b = (float)as->opt[ANIM_SCREEN_OPTION_FIRE_COLOR].value. c[2] / 0xffff - (rVal / 1.7 * (float)as->opt[ANIM_SCREEN_OPTION_FIRE_COLOR].value. c[2] / 0xffff); } // set transparancy part->a = (float)as->opt[ANIM_SCREEN_OPTION_FIRE_COLOR]. value.c[3] / 0xffff; // set gravity part->xg = (part->x < part->xo) ? 1.0 : -1.0; part->yg = -3.0f; part->zg = 0.0f; ps->active = TRUE; max_new -= 1; } else { part->xg = (part->x < part->xo) ? 1.0 : -1.0; } } } static void fxBurnGenNewSmoke(CompScreen * s, ParticleSystem * ps, int x, int y, int width, int height, float size, float time) { ANIM_SCREEN(s); float max_new = ps->numParticles * (time / 50) * (1.05 - as-> opt [ANIM_SCREEN_OPTION_FIRE_LIFE]. value.f); int i; Particle *part; float rVal; for (i = 0; i < ps->numParticles && max_new > 0; i++) { part = &ps->particles[i]; if (part->life <= 0.0f) { // give gt new life rVal = (float)(random() & 0xff) / 255.0; part->life = 1.0f; part->fade = (rVal * (1 - as->opt[ANIM_SCREEN_OPTION_FIRE_LIFE].value.f)) + (0.2f * (1.01 - as->opt[ANIM_SCREEN_OPTION_FIRE_LIFE].value.f)); // Random Fade Value // set size part->width = as->opt[ANIM_SCREEN_OPTION_FIRE_SIZE].value.f * size * 5; part->height = as->opt[ANIM_SCREEN_OPTION_FIRE_SIZE].value.f * size * 5; rVal = (float)(random() & 0xff) / 255.0; part->w_mod = -0.8; part->h_mod = -0.8; // choose random position rVal = (float)(random() & 0xff) / 255.0; part->x = x + ((width > 1) ? (rVal * width) : 0); rVal = (float)(random() & 0xff) / 255.0; part->y = y + ((height > 1) ? (rVal * height) : 0); part->z = 0.0; part->xo = part->x; part->yo = part->y; part->zo = part->z; // set speed and direction rVal = (float)(random() & 0xff) / 255.0; part->xi = ((rVal * 20.0) - 10.0f); rVal = (float)(random() & 0xff) / 255.0; part->yi = (rVal + 0.2) * -size; part->zi = 0.0f; // set color rVal = (float)(random() & 0xff) / 255.0; part->r = rVal / 4.0; part->g = rVal / 4.0; part->b = rVal / 4.0; rVal = (float)(random() & 0xff) / 255.0; part->a = 0.5 + (rVal / 2.0); // set gravity part->xg = (part->x < part->xo) ? size : -size; part->yg = -size; part->zg = 0.0f; ps->active = TRUE; max_new -= 1; } else { part->xg = (part->x < part->xo) ? size : -size; } } } static void fxBurnModelStep(CompScreen * s, CompWindow * w, float time) { int steps; ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; Bool smoke = as->opt[ANIM_SCREEN_OPTION_FIRE_SMOKE].value.b; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP_INTENSE].value.i); float old = 1 - (aw->animRemainingTime) / (aw->animTotalTime); float stepSize; model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) aw->animRemainingTime = 0; // avoid sub-zero values float new = 1 - (aw->animRemainingTime) / (aw->animTotalTime); stepSize = new - old; if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventUnshade) { old = 1 - old; new = 1 - new; } if (!aw->drawRegion) aw->drawRegion = XCreateRegion(); if (aw->animRemainingTime > 0) { XRectangle rect; switch (aw->animFireDirection) { case AnimDirectionUp: rect.x = 0; rect.y = 0; rect.width = WIN_W(w); rect.height = WIN_H(w) - (old * WIN_H(w)); break; case AnimDirectionRight: rect.x = (old * WIN_W(w)); rect.y = 0; rect.width = WIN_W(w) - (old * WIN_W(w)); rect.height = WIN_H(w); break; case AnimDirectionLeft: rect.x = 0; rect.y = 0; rect.width = WIN_W(w) - (old * WIN_W(w)); rect.height = WIN_H(w); break; case AnimDirectionDown: default: rect.x = 0; rect.y = (old * WIN_H(w)); rect.width = WIN_W(w); rect.height = WIN_H(w) - (old * WIN_H(w)); break; } XUnionRectWithRegion(&rect, getEmptyRegion(), aw->drawRegion); } else { XUnionRegion(getEmptyRegion(), getEmptyRegion(), aw->drawRegion); } if (new != 0) aw->useDrawRegion = TRUE; else aw->useDrawRegion = FALSE; if (aw->animRemainingTime > 0 && aw->ps) { switch (aw->animFireDirection) { case AnimDirectionUp: if (smoke) fxBurnGenNewSmoke(s, &aw->ps[0], WIN_X(w), WIN_Y(w) + ((1 - old) * WIN_H(w)), WIN_W(w), 1, WIN_W(w) / 40.0, time); fxBurnGenNewFire(s, &aw->ps[1], WIN_X(w), WIN_Y(w) + ((1 - old) * WIN_H(w)), WIN_W(w), (stepSize) * WIN_H(w), WIN_W(w) / 40.0, time); break; case AnimDirectionLeft: if (smoke) fxBurnGenNewSmoke(s, &aw->ps[0], WIN_X(w) + ((1 - old) * WIN_W(w)), WIN_Y(w), (stepSize) * WIN_W(w), WIN_H(w), WIN_H(w) / 40.0, time); fxBurnGenNewFire(s, &aw->ps[1], WIN_X(w) + ((1 - old) * WIN_W(w)), WIN_Y(w), (stepSize) * WIN_W(w), WIN_H(w), WIN_H(w) / 40.0, time); break; case AnimDirectionRight: if (smoke) fxBurnGenNewSmoke(s, &aw->ps[0], WIN_X(w) + (old * WIN_W(w)), WIN_Y(w), (stepSize) * WIN_W(w), WIN_H(w), WIN_H(w) / 40.0, time); fxBurnGenNewFire(s, &aw->ps[1], WIN_X(w) + (old * WIN_W(w)), WIN_Y(w), (stepSize) * WIN_W(w), WIN_H(w), WIN_H(w) / 40.0, time); break; case AnimDirectionDown: default: if (smoke) fxBurnGenNewSmoke(s, &aw->ps[0], WIN_X(w), WIN_Y(w) + (old * WIN_H(w)), WIN_W(w), 1, WIN_W(w) / 40.0, time); fxBurnGenNewFire(s, &aw->ps[1], WIN_X(w), WIN_Y(w) + (old * WIN_H(w)), WIN_W(w), (stepSize) * WIN_H(w), WIN_W(w) / 40.0, time); break; } } if (aw->animRemainingTime <= 0 && aw->numPs && (aw->ps[0].active || aw->ps[1].active)) aw->animRemainingTime = timestep; if (!aw->numPs) { if (aw->ps) { finiParticles(aw->ps); free(aw->ps); aw->ps = NULL; } return; // FIXME - is this correct behaviour? } int i; Particle *part; for (i = 0; i < aw->ps[0].numParticles && aw->animRemainingTime > 0 && smoke; i++) { part = &aw->ps[0].particles[i]; part->xg = (part->x < part->xo) ? WIN_W(w) / 40.0 : -WIN_W(w) / 40.0; } aw->ps[0].x = WIN_X(w); aw->ps[0].y = WIN_Y(w); for (i = 0; i < aw->ps[1].numParticles && aw->animRemainingTime > 0; i++) { part = &aw->ps[1].particles[i]; part->xg = (part->x < part->xo) ? 1.0 : -1.0; } aw->ps[1].x = WIN_X(w); aw->ps[1].y = WIN_Y(w); modelCalcBounds(model); } static void drawParticleSystems(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); if (aw->numPs) { int i = 0; for (i = 0; i < aw->numPs; i++) { if (aw->ps[i].active && !WINDOW_INVISIBLE(w)) { drawParticles(s, w, &aw->ps[i]); } } } } // ===================== Effect: Beam Up ========================= static void fxBeamUpInit(CompScreen * s, CompWindow * w) { int particles = WIN_W(w); fxFadeInit(s, w); ANIM_WINDOW(w); ANIM_SCREEN(s); if (!aw->numPs) { aw->ps = calloc(1, 2 * sizeof(ParticleSystem)); if (!aw->ps) { postAnimationCleanup(w, TRUE); return; } aw->numPs = 2; } initParticles(particles / 10, &aw->ps[0]); initParticles(particles, &aw->ps[1]); aw->ps[1].slowdown = as->opt[ANIM_SCREEN_OPTION_BEAMUP_SLOWDOWN].value.f; aw->ps[1].darken = 0.5; aw->ps[1].blendMode = GL_ONE; aw->ps[0].slowdown = as->opt[ANIM_SCREEN_OPTION_BEAMUP_SLOWDOWN].value.f / 2.0; aw->ps[0].darken = 0.0; aw->ps[0].blendMode = GL_ONE_MINUS_SRC_ALPHA; if (!aw->ps[0].tex) glGenTextures(1, &aw->ps[0].tex); glBindTexture(GL_TEXTURE_2D, aw->ps[0].tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, fireTex); glBindTexture(GL_TEXTURE_2D, 0); if (!aw->ps[1].tex) glGenTextures(1, &aw->ps[1].tex); glBindTexture(GL_TEXTURE_2D, aw->ps[1].tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, fireTex); glBindTexture(GL_TEXTURE_2D, 0); } static void fxBeamUpGenNewFire(CompScreen * s, ParticleSystem * ps, int x, int y, int width, int height, float size, float time) { ANIM_SCREEN(s); ps->numParticles = width / as->opt[ANIM_SCREEN_OPTION_BEAMUP_SPACING].value.i; float max_new = ps->numParticles * (time / 50) * (1.05 - as-> opt [ANIM_SCREEN_OPTION_BEAMUP_LIFE]. value.f); int i; Particle *part; float rVal; for (i = 0; i < ps->numParticles && max_new > 0; i++) { part = &ps->particles[i]; if (part->life <= 0.0f) { // give gt new life rVal = (float)(random() & 0xff) / 255.0; part->life = 1.0f; part->fade = (rVal * (1 - as->opt[ANIM_SCREEN_OPTION_BEAMUP_LIFE].value.f)) + (0.2f * (1.01 - as->opt[ANIM_SCREEN_OPTION_BEAMUP_LIFE].value.f)); // Random Fade Value // set size part->width = 2.5 * as->opt[ANIM_SCREEN_OPTION_BEAMUP_SIZE].value.f; part->height = height; part->w_mod = size * 0.2; part->h_mod = size * 0.02; // choose random x position rVal = (float)(random() & 0xff) / 255.0; part->x = x + ((width > 1) ? (rVal * width) : 0); part->y = y; part->z = 0.0; part->xo = part->x; part->yo = part->y; part->zo = part->z; // set speed and direction part->xi = 0.0f; part->yi = 0.0f; part->zi = 0.0f; // set color ABAB as->opt[ANIM_SCREEN_OPTION_BEAMUP_COLOR].value.f part->r = (float)as-> opt[ANIM_SCREEN_OPTION_BEAMUP_COLOR].value. c[0] / 0xffff - (rVal / 1.7 * (float)as-> opt[ANIM_SCREEN_OPTION_BEAMUP_COLOR].value.c[0] / 0xffff); part->g = (float)as->opt[ANIM_SCREEN_OPTION_BEAMUP_COLOR].value. c[1] / 0xffff - (rVal / 1.7 * (float)as->opt[ANIM_SCREEN_OPTION_BEAMUP_COLOR].value. c[1] / 0xffff); part->b = (float)as->opt[ANIM_SCREEN_OPTION_BEAMUP_COLOR].value. c[2] / 0xffff - (rVal / 1.7 * (float)as->opt[ANIM_SCREEN_OPTION_BEAMUP_COLOR].value. c[2] / 0xffff);; part->a = (float)as->opt[ANIM_SCREEN_OPTION_BEAMUP_COLOR].value. c[3] / 0xffff; // set gravity part->xg = 0.0f; part->yg = 0.0f; part->zg = 0.0f; ps->active = TRUE; max_new -= 1; } else { part->xg = (part->x < part->xo) ? 1.0 : -1.0; } } } static void fxBeamUpModelStep(CompScreen * s, CompWindow * w, float time) { int steps; int creating = 0; fxFadeModelStep(s, w, time); ANIM_SCREEN(s); ANIM_WINDOW(w); Model *model = aw->model; float timestep = (s->slowAnimations ? 2 : // For smooth slow-mo (refer to display.c) as->opt[ANIM_SCREEN_OPTION_TIME_STEP_INTENSE].value.i); float old = 1 - (aw->animRemainingTime) / (aw->animTotalTime); float stepSize; model->remainderSteps += time / timestep; steps = floor(model->remainderSteps); model->remainderSteps -= steps; if (!steps && aw->animRemainingTime < aw->animTotalTime) return; steps = MAX(1, steps); aw->animRemainingTime -= timestep; if (aw->animRemainingTime <= 0) aw->animRemainingTime = 0; // avoid sub-zero values float new = 1 - (aw->animRemainingTime) / (aw->animTotalTime); stepSize = new - old; if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize || aw->curWindowEvent == WindowEventUnshade) { old = 1 - old; new = 1 - new; creating = 1; } if (!aw->drawRegion) aw->drawRegion = XCreateRegion(); if (aw->animRemainingTime > 0) { XRectangle rect; rect.x = ((old / 2) * WIN_W(w)); rect.width = WIN_W(w) - (old * WIN_W(w)); rect.y = ((old / 2) * WIN_H(w)); rect.height = WIN_H(w) - (old * WIN_H(w)); XUnionRectWithRegion(&rect, getEmptyRegion(), aw->drawRegion); } else { XUnionRegion(getEmptyRegion(), getEmptyRegion(), aw->drawRegion); } if (new != 0) aw->useDrawRegion = TRUE; else aw->useDrawRegion = FALSE; if (aw->animRemainingTime > 0 && aw->ps) { fxBeamUpGenNewFire(s, &aw->ps[1], WIN_X(w), WIN_Y(w) + (WIN_H(w) / 2), WIN_W(w), creating ? WIN_H(w) - (old / 2 * WIN_H(w)) : (WIN_H(w) - (old * WIN_H(w))), WIN_W(w) / 40.0, time); } if (aw->animRemainingTime <= 0 && aw->numPs && (aw->ps[0].active || aw->ps[1].active)) aw->animRemainingTime = timestep; if (!aw->numPs) { if (aw->ps) { finiParticles(aw->ps); free(aw->ps); aw->ps = NULL; } return; // FIXME - is this correct behaviour? } int i; Particle *part; aw->ps[0].x = WIN_X(w); aw->ps[0].y = WIN_Y(w); for (i = 0; i < aw->ps[1].numParticles && aw->animRemainingTime > 0; i++) { part = &aw->ps[1].particles[i]; part->xg = (part->x < part->xo) ? 1.0 : -1.0; } aw->ps[1].x = WIN_X(w); aw->ps[1].y = WIN_Y(w); modelCalcBounds(model); } static void fxBeamupUpdateWindowAttrib(AnimScreen * as, AnimWindow * aw, WindowPaintAttrib * wAttrib) { float forwardProgress = 1 - (aw->animRemainingTime - aw->timestep) / (aw->animTotalTime - aw->timestep); forwardProgress = MIN(forwardProgress, 1); forwardProgress = MAX(forwardProgress, 0); if (aw->curWindowEvent == WindowEventCreate || aw->curWindowEvent == WindowEventUnminimize) { forwardProgress = forwardProgress * forwardProgress; forwardProgress = forwardProgress * forwardProgress; forwardProgress = 1 - forwardProgress; } wAttrib->opacity = (GLushort) (aw->storedOpacity * (1 - forwardProgress)); } // ===================== Effect: 3D Spread ========================= // Frees up polygon objects in pset static void freePolygonObjects(PolygonSet * pset) { PolygonObject *p = pset->polygons; if (!p) { pset->nPolygons = 0; return; } int i; for (i = 0; i < pset->nPolygons; i++, p++) { if (p->nVertices > 0) { if (p->vertices) free(p->vertices); if (p->sideIndices) free(p->sideIndices); if (p->normals) free(p->normals); p->vertices = 0; p->sideIndices = 0; p->normals = 0; p->nVertices = 0; } /*if (p->nShadowQuads > 0) { if (p->shadowVertices) free(p->shadowVertices); if (p->shadowTexCoords) free(p->shadowTexCoords); p->shadowVertices = 0; p->shadowTexCoords = 0; p->nShadowQuads = 0; } */ p->nSides = 0; } free(pset->polygons); pset->polygons = 0; pset->nPolygons = 0; } // Frees up intersecting polygon info of PolygonSet clips static void freeClipsPolygons(PolygonSet * pset) { int k; for (k = 0; k < pset->clipCapacity; k++) { if (pset->clips[k].intersectingPolygons) { free(pset->clips[k].intersectingPolygons); pset->clips[k].intersectingPolygons = 0; } if (pset->clips[k].polygonVertexTexCoords) { free(pset->clips[k].polygonVertexTexCoords); pset->clips[k].polygonVertexTexCoords = 0; } pset->clips[k].nIntersectingPolygons = 0; } } // Frees up the whole polygon set static void freePolygonSet(AnimWindow * aw) { PolygonSet *pset = aw->polygonSet; freePolygonObjects(pset); if (pset->clipCapacity > 0) { freeClipsPolygons(pset); free(pset->clips); pset->clips = 0; pset->nClips = 0; pset->firstNondrawnClip = 0; pset->clipCapacity = 0; } free(pset); aw->polygonSet = 0; } /* // Tessellates window into extruded rectangular objects // in a brick wall formation static Bool tessellateIntoBricks(CompWindow * w, int gridSizeX, int gridSizeY, float thickness) { } // Tessellates window into extruded hexagon objects static Bool tessellateIntoHexagons(CompWindow * w, int gridSizeX, int gridSizeY, float thickness) { } // Tessellates window into Voronoi segments static Bool tessellateVoronoi(CompWindow * w, float thickness) { } */ // Tessellates window into extruded rectangular objects static Bool tessellateIntoRectangles(CompWindow * w, int gridSizeX, int gridSizeY, float thickness) { ANIM_WINDOW(w); PolygonSet *pset = aw->polygonSet; if (!pset) return FALSE; int winLimitsX; // boundaries of polygon tessellation int winLimitsY; int winLimitsW; int winLimitsH; if (pset->includeShadows) { winLimitsX = WIN_X(w); winLimitsY = WIN_Y(w); winLimitsW = WIN_W(w) - 1; // avoid artifact on right edge winLimitsH = WIN_H(w); } else { winLimitsX = BORDER_X(w); winLimitsY = BORDER_Y(w); winLimitsW = BORDER_W(w); winLimitsH = BORDER_H(w); } float minRectSize = 20; float rectW = winLimitsW / (float)gridSizeX; float rectH = winLimitsH / (float)gridSizeY; if (rectW < minRectSize) gridSizeX = winLimitsW / minRectSize; // int div. if (rectH < minRectSize) gridSizeY = winLimitsH / minRectSize; // int div. if (pset->nPolygons != gridSizeX * gridSizeY) { if (pset->nPolygons > 0) freePolygonObjects(pset); pset->nPolygons = gridSizeX * gridSizeY; pset->polygons = calloc(1, sizeof(PolygonObject) * pset->nPolygons); if (!pset->polygons) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); pset->nPolygons = 0; return FALSE; } } thickness /= w->screen->width; pset->thickness = thickness; pset->nTotalFrontVertices = 0; float cellW = (float)winLimitsW / gridSizeX; float cellH = (float)winLimitsH / gridSizeY; float halfW = cellW / 2; float halfH = cellH / 2; float halfThick = pset->thickness / 2; PolygonObject *p = pset->polygons; int x, y; //float vec = 1 / sqrt(3); // vector component for normals for (y = 0; y < gridSizeY; y++) { float posY = winLimitsY + cellH * (y + 0.5); for (x = 0; x < gridSizeX; x++, p++) { p->centerPos.x = p->centerPosStart.x = winLimitsX + cellW * (x + 0.5); p->centerPos.y = p->centerPosStart.y = posY; p->centerPos.z = p->centerPosStart.z = -halfThick; p->rotAngle = p->rotAngleStart = 0; p->centerRelPos.x = (x + 0.5) / gridSizeX; p->centerRelPos.y = (y + 0.5) / gridSizeY; p->nSides = 4; p->nVertices = 2 * 4; pset->nTotalFrontVertices += 4; // 4 front, 4 back vertices if (!p->vertices) { p->vertices = calloc(1, sizeof(GLfloat) * 8 * 3); } //if (!p->vertexOnEdge) // p->vertexOnEdge = calloc (1, sizeof (int) * p->nSides); //p->vertexTexCoords4Clips = calloc (1, sizeof (GLfloat) * 4 * 2 * 2); if (!p->vertices) // || !p->vertexOnEdge)// || !p->vertexTexCoords4Clips) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); freePolygonObjects(pset); return FALSE; } GLfloat *pv = p->vertices; // Determine 4 front vertices in ccw direction pv[0] = -halfW; pv[1] = -halfH; pv[2] = halfThick; pv[3] = -halfW; pv[4] = halfH; pv[5] = halfThick; pv[6] = halfW; pv[7] = halfH; pv[8] = halfThick; pv[9] = halfW; pv[10] = -halfH; pv[11] = halfThick; // Determine 4 back vertices in cw direction pv[12] = halfW; pv[13] = -halfH; pv[14] = -halfThick; pv[15] = halfW; pv[16] = halfH; pv[17] = -halfThick; pv[18] = -halfW; pv[19] = halfH; pv[20] = -halfThick; pv[21] = -halfW; pv[22] = -halfH; pv[23] = -halfThick; // 10 indices for 4 sides (for quad strip) if (!p->sideIndices) { //p->sideIndices = calloc(1, sizeof(GLushort) * 2 * (4 + 1)); p->sideIndices = calloc(1, sizeof(GLushort) * 4 * 4); } if (!p->sideIndices) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); freePolygonObjects(pset); return FALSE; } GLushort *ind = p->sideIndices; /* ind[0] = 0; ind[1] = 7; ind[2] = 1; ind[3] = 6; ind[4] = 2; ind[5] = 5; ind[6] = 3; ind[7] = 4; ind[8] = 0; ind[9] = 7; */ int id = 0; ind[id++] = 0; ind[id++] = 7; ind[id++] = 6; ind[id++] = 1; ind[id++] = 1; ind[id++] = 6; ind[id++] = 5; ind[id++] = 2; ind[id++] = 2; ind[id++] = 5; ind[id++] = 4; ind[id++] = 3; ind[id++] = 3; ind[id++] = 4; ind[id++] = 7; ind[id++] = 0; // 4 front, 4 back vertex normals if (!p->normals) { p->normals = calloc(1, sizeof(GLfloat) * (2 + 4) * 3); } if (!p->normals) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); freePolygonObjects(pset); return FALSE; } // Surface normals GLfloat *nor = p->normals; // Front nor[0] = 0; nor[1] = 0; nor[2] = -1; // Back nor[3] = 0; nor[4] = 0; nor[5] = 1; // Sides nor[6] = -1; nor[7] = 0; nor[8] = 0; nor[9] = 0; nor[10] = 1; nor[11] = 0; nor[12] = 1; nor[13] = 0; nor[14] = 0; nor[15] = 0; nor[16] = -1; nor[17] = 0; // Determine bounding box (to test intersection with clips) p->boundingBox.x1 = -halfW + p->centerPos.x; p->boundingBox.y1 = -halfH + p->centerPos.y; p->boundingBox.x2 = ceil(halfW + p->centerPos.x); p->boundingBox.y2 = ceil(halfH + p->centerPos.y); /* // Determine edge/corner status if (x == 0) { p->nShadowQuads++; if (y == 0) p->vertexOnEdge[0] = 5; if (y == gridSizeY - 1) p->nShadowQuads++; } if (x == gridSizeX - 1) { p->nShadowQuads++; if (y == 0) p->nShadowQuads++; if (y == gridSizeY - 1) p->nShadowQuads++; } if (y == 0) p->nShadowQuads++; if (y == gridSizeY - 1) p->nShadowQuads++; */ } } return TRUE; } static void polygonsStoreClips(CompScreen * s, CompWindow * w, int nClip, BoxPtr pClip, int nMatrix, CompMatrix * matrix) { ANIM_WINDOW(w); PolygonSet *pset = aw->polygonSet; // if polygon set is not valid or effect is not 3D (glide w/thickness=0) if (!pset) return; // only draw windows on current viewport if (w->attrib.x > s->width || w->attrib.x + w->width < 0 || w->attrib.y > s->height || w->attrib.y + w->height < 0 || (aw->lastKnownCoords.x != NOT_INITIALIZED && (aw->lastKnownCoords.x != w->attrib.x || aw->lastKnownCoords.y != w->attrib.y))) { return; // since this is not the viewport the window was drawn // just before animation started } Bool dontStoreClips = TRUE; // If this clip doesn't match the corresponding stored clip, // clear the stored clips from this point (aw->nClipsPassed) // to the end and store the new ones instead. if (aw->nClipsPassed < pset->nClips) // if we have clips stored earlier { Clip4Polygons *c = pset->clips + aw->nClipsPassed; // the stored clip at position aw->nClipsPassed // if either clip coordinates or texture matrix is different if (memcmp(pClip, &c->box, sizeof(Box)) || memcmp(matrix, &c->texMatrix, sizeof(CompMatrix))) { // get rid of the clips from here (aw->nClipsPassed) to the end pset->nClips = aw->nClipsPassed; dontStoreClips = FALSE; } } else dontStoreClips = FALSE; if (dontStoreClips) { aw->nClipsPassed += nClip; return; } // For each clip passed to this function for (; nClip--; pClip++, aw->nClipsPassed++) { // New clip if (!ensureLargerClipCapacity(pset)) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); return; } Clip4Polygons *newClip = &pset->clips[pset->nClips]; newClip->id = aw->nClipsPassed; memcpy(&newClip->box, pClip, sizeof(Box)); memcpy(&newClip->texMatrix, matrix, sizeof(CompMatrix)); // nMatrix is not used for now // (i.e. only first texture matrix is considered) // avoid clipping along window edge // for the "window contents" clip if (pClip->x1 == BORDER_X(w) && pClip->y1 == BORDER_Y(w) && pClip->x2 == BORDER_X(w) + BORDER_W(w) && pClip->y2 == BORDER_Y(w) + BORDER_H(w)) { newClip->boxf.x1 = pClip->x1 - 0.1f; newClip->boxf.y1 = pClip->y1 - 0.1f; newClip->boxf.x2 = pClip->x2 + 0.1f; newClip->boxf.y2 = pClip->y2 + 0.1f; } else { newClip->boxf.x1 = pClip->x1; newClip->boxf.y1 = pClip->y1; newClip->boxf.x2 = pClip->x2; newClip->boxf.y2 = pClip->y2; } pset->nClips++; aw->clipsUpdated = TRUE; /* // Look for a container / contained clip to minimize # of clips. // Go backward, since such a clip is likely to be one of the last ones. // Go until you hit the clips corresponding to the previous texture. int i; for (i=pset->nClips-1; i>=pset->firstClipWithNoTex; i--) { Clip4Polygons *clip = &pset->clips[i]; // if tex matrices are different if (clip->texMatrix.xx != matrix->xx || clip->texMatrix.yy != matrix->yy || clip->texMatrix.x0 != matrix->x0 || clip->texMatrix.y0 != matrix->y0) continue; // if an old clip contains the new clip if (x1 >= clip->box.x1 && y1 >= clip->box.y1 && x2 <= clip->box.x2 && y2 <= clip->box.y2) { newClipNo = i; updateCoords = FALSE; break; } // if the new clip contains an old clip if (x1 <= clip->box.x1 && y1 <= clip->box.y1 && x2 >= clip->box.x2 && y2 >= clip->box.y2) { // update the old clip in this case newClipNo = i; break; } } if (pset->firstClipWithNoTex > 0) { // Go through clip's of earlier textures to look for // an identical clip. If such clips are found, their // texture should be updated with the latest one for (i=pset->firstClipWithNoTex-1; i>=0; i--) { Clip4Polygons *clip = &pset->clips[i]; // if tex matrices are different if (clip->texMatrix.xx != matrix->xx || clip->texMatrix.yy != matrix->yy || clip->texMatrix.x0 != matrix->x0 || clip->texMatrix.y0 != matrix->y0) continue; // if an old clip == the new clip if (x1 == clip->box.x1 && y1 == clip->box.y1 && x2 == clip->box.x2 && y2 == clip->box.y2) { newClipNo = i; updateCoords = FALSE; clip->textureNo = aw->nTextures; break; } } } if (newClipNo == pset->nClips && // if no such old clip is found !ensureLargerClipCapacity (pset)) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); return; } Clip4Polygons *newClip = &pset->clips[newClipNo]; if (updateCoords) { memcpy (&newClip->box, pClip, sizeof (Box)); memcpy (&newClip->texMatrix, matrix, sizeof (CompMatrix)); // nMatrix is not used for now // (i.e. only first texture matrix is considered) } if (newClipNo == pset->nClips) // if new clip is being added { //printf("adding x1: %4d, y1: %4d, x2: %4d, y2: %4d\n", // pClip->x1, pClip->y1, pClip->x2, pClip->y2); newClip->textureNo = aw->nTextures; pset->nClips++; } */ } } // For each rectangular clip, this function finds polygons which // have a bounding box that intersects the clip. For intersecting // polygons, it computes the texture coordinates for the vertices // of that polygon (to draw the clip texture). static Bool processIntersectingPolygons(PolygonSet * pset) { int j; for (j = pset->firstNondrawnClip; j < pset->nClips; j++) { Clip4Polygons *c = pset->clips + j; Box *cb = &c->box; int nFrontVerticesTilThisPoly = 0; c->nIntersectingPolygons = 0; // TODO: If it doesn't affect speed much, for each clip, // consider doing 2 passes, counting the intersecting polygons // in the 1st pass and allocating just enough space for those // polygons instead of all polygons in the 2nd pass. int i; for (i = 0; i < pset->nPolygons; i++) { PolygonObject *p = pset->polygons + i; Box *bb = &p->boundingBox; if (bb->x2 <= cb->x1) continue; // no intersection if (bb->y2 <= cb->y1) continue; // no intersection if (bb->x1 >= cb->x2) continue; // no intersection if (bb->y1 >= cb->y2) continue; // no intersection // There is intersection, add clip info if (!c->intersectingPolygons) { c->intersectingPolygons = calloc(1, sizeof(int) * pset->nPolygons); } // allocate tex coords // 2 {x, y} * 2 {front, back} * if (!c->polygonVertexTexCoords) { c->polygonVertexTexCoords = calloc(1, sizeof(GLfloat) * 2 * 2 * pset->nTotalFrontVertices); } if (!c->intersectingPolygons || !c->polygonVertexTexCoords) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); freeClipsPolygons(pset); return FALSE; } c->intersectingPolygons[c->nIntersectingPolygons] = i; int k; for (k = 0; k < p->nSides; k++) { float x = p->vertices[3 * k] + p->centerPosStart.x; float y = p->vertices[3 * k + 1] + p->centerPosStart.y; GLfloat tx; GLfloat ty; if (c->texMatrix.xy != 0.0f || c->texMatrix.yx != 0.0f) { // "non-rect" coordinates tx = COMP_TEX_COORD_XY(&c->texMatrix, x, y); ty = COMP_TEX_COORD_YX(&c->texMatrix, x, y); } else { tx = COMP_TEX_COORD_X(&c->texMatrix, x); ty = COMP_TEX_COORD_Y(&c->texMatrix, y); } // for front vertices int ti = 2 * (2 * nFrontVerticesTilThisPoly + k); c->polygonVertexTexCoords[ti] = tx; c->polygonVertexTexCoords[ti + 1] = ty; // for back vertices ti = 2 * (2 * nFrontVerticesTilThisPoly + (2 * p->nSides - 1 - k)); c->polygonVertexTexCoords[ti] = tx; c->polygonVertexTexCoords[ti + 1] = ty; } c->nIntersectingPolygons++; nFrontVerticesTilThisPoly += p->nSides; } } return TRUE; } /* static Bool computePolygonShadows(PolygonSet * pset) { PolygonObject *p = pset->polygons; int i; for (i=0; inPolygons; i++, p++) { p->nShadowQuads = 0; // If an edge polygon, determine shadow quads // First count them if (x == 0) { p->nShadowQuads++; if (y == 0) p->nShadowQuads++; if (y == gridSizeY - 1) p->nShadowQuads++; } if (x == gridSizeX - 1) { p->nShadowQuads++; if (y == 0) p->nShadowQuads++; if (y == gridSizeY - 1) p->nShadowQuads++; } if (y == 0) p->nShadowQuads++; if (y == gridSizeY - 1) p->nShadowQuads++; // Allocate them p->shadowVertices = calloc (1, sizeof (GLfloat) * 3 * 4 * p->nShadowQuads); if (!p->shadowVertices) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); freePolygonObjects (pset); return FALSE; } // Store them int n = 0; GLfloat *v = p->shadowVertices; if (x == 0) { // Left quad v[12 * n] = w->attrib.x - w->output.left; v[12 * n + 1] = w->attrib.x - w->output.left; v[12 * n + 2] = w->attrib.x - w->output.left; n++; if (y == 0) n++; if (y == gridSizeY - 1) n++; } if (x == gridSizeX - 1) { n++; if (y == 0) n++; if (y == gridSizeY - 1) n++; } if (y == 0) n++; if (y == gridSizeY - 1) n++; p->nShadowQuads = n; } return TRUE; } */ static void polygonsDrawCustomGeometry(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); if ( // only draw windows on current viewport w->attrib.x > s->width || w->attrib.x + w->width < 0 || w->attrib.y > s->height || w->attrib.y + w->height < 0 || (aw->lastKnownCoords.x != NOT_INITIALIZED && (aw->lastKnownCoords.x != w->attrib.x || aw->lastKnownCoords.y != w->attrib.y))) { return; // since this is not the viewport the window was drawn // just before animation started } PolygonSet *pset = aw->polygonSet; // if polygon set is not valid or effect is not 3D (glide w/thickness=0) if (!pset) return; // TODO: Fix the source of the crash problem // (uninitialized lastClipInGroup) // instead of doing this uninitialized value check if (pset->firstNondrawnClip < 0 || pset->firstNondrawnClip > pset->nClips || (!aw->clipsUpdated && (pset->lastClipInGroup[aw->nDrawGeometryCalls - 1] < 0 || pset->lastClipInGroup[aw->nDrawGeometryCalls - 1] >= pset->nClips))) { return; } if (aw->clipsUpdated && aw->nDrawGeometryCalls > 0) { if (!processIntersectingPolygons(pset)) { return; } } int lastClip; // last clip to draw if (aw->clipsUpdated) { lastClip = pset->nClips - 1; } else { lastClip = pset->lastClipInGroup[aw->nDrawGeometryCalls - 1]; } float forwardProgress = defaultAnimProgress(aw); // OpenGL stuff starts here if (pset->doLighting) { glPushAttrib(GL_LIGHT0); glPushAttrib(GL_COLOR_MATERIAL); glPushAttrib(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 0.3f }; GLfloat diffuseLight[] = { 0.9f, 0.9f, 0.9f, 0.9f }; GLfloat light0Position[] = { -0.5f, 0.5f, -9.0f, 0.0f }; glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); glLightfv(GL_LIGHT0, GL_POSITION, light0Position); } glPushMatrix(); // Store old blend values GLint blendSrcWas, blendDstWas; glGetIntegerv(GL_BLEND_SRC, &blendSrcWas); glGetIntegerv(GL_BLEND_DST, &blendDstWas); GLboolean blendWas = glIsEnabled(GL_BLEND); glPushAttrib(GL_STENCIL_BUFFER_BIT); glDisable(GL_STENCIL_TEST); //GLboolean normalArrayWas = glIsEnabled(GL_NORMAL_ARRAY); //glShadeModel(GL_FLAT); if (pset->doDepthTest) { // Depth test glPushAttrib(GL_DEPTH_FUNC); glPushAttrib(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); } // Clip planes GLdouble clipPlane0[] = { 1, 0, 0, 0 }; GLdouble clipPlane1[] = { 0, 1, 0, 0 }; GLdouble clipPlane2[] = { -1, 0, 0, 0 }; GLdouble clipPlane3[] = { 0, -1, 0, 0 }; // Save old color values GLfloat oldColor[4]; glGetFloatv(GL_CURRENT_COLOR, oldColor); // Determine where we are called from in paint.c's drawWindowTexture // to find out how we should change the opacity GLint prevActiveTexture = GL_TEXTURE0_ARB; Bool saturationFull = TRUE; if (w->screen->canDoSaturated && aw->curPaintAttrib.saturation != COLOR) { saturationFull = FALSE; if (w->screen->canDoSlightlySaturated && aw->curPaintAttrib.saturation > 0) { if (aw->curPaintAttrib.opacity < OPAQUE || aw->curPaintAttrib.brightness != BRIGHT) prevActiveTexture = GL_TEXTURE3_ARB; else prevActiveTexture = GL_TEXTURE2_ARB; } else prevActiveTexture = GL_TEXTURE1_ARB; } float brightness = aw->curPaintAttrib.brightness / 65535.0; float opacity = aw->curPaintAttrib.opacity / 65535.0; float newOpacity = opacity; float fadePassedBy; if (!blendWas) // if translucency is not already turned on in paint.c { glEnable(GL_BLEND); } if (saturationFull) { screenTexEnvMode(w->screen, GL_MODULATE); } else if (prevActiveTexture == GL_TEXTURE2_ARB) { w->screen->activeTexture(prevActiveTexture + 1); enableTexture(w->screen, aw->curTexture, aw->curTextureFilter); } glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // if fade-out duration is not specified per polygon if (pset->allFadeDuration > -1.0f) { fadePassedBy = forwardProgress - (1 - pset->allFadeDuration); // if "fade out starting point" is passed if (fadePassedBy > 1e-5) // if true, allFadeDuration should be > 0 { float opacityFac; if (aw->deceleratingMotion) opacityFac = 1 - decelerateProgress2 (fadePassedBy / pset->allFadeDuration); else opacityFac = 1 - fadePassedBy / pset->allFadeDuration; if (opacityFac < 0) opacityFac = 0; if (opacityFac > 1) opacityFac = 1; newOpacity = opacity * opacityFac; } } int pass; // 0: draw opaque ones // 2: draw transparent ones for (pass = 0; pass < 2; pass++) { int j; for (j = pset->firstNondrawnClip; j <= lastClip; j++) { Clip4Polygons *c = pset->clips + j; int nFrontVerticesTilThisPoly = 0; int nNewSides = 0; int i; for (i = 0; i < c->nIntersectingPolygons; i++, nFrontVerticesTilThisPoly += nNewSides) { PolygonObject *p = pset->polygons + c->intersectingPolygons[i]; nNewSides = p->nSides; float newOpacityPolygon = newOpacity; // if fade-out duration is specified per polygon if (pset->allFadeDuration == -1.0f) { fadePassedBy = forwardProgress - p->fadeStartTime; // if "fade out starting point" is passed if (fadePassedBy > 1e-5) // if true, then allFadeDuration > 0 { float opacityFac; if (aw->deceleratingMotion) opacityFac = 1 - decelerateProgress2 (fadePassedBy / p->fadeDuration); else opacityFac = 1 - fadePassedBy / p->fadeDuration; if (opacityFac < 0) opacityFac = 0; if (opacityFac > 1) opacityFac = 1; newOpacityPolygon = newOpacity * opacityFac; } } if (newOpacityPolygon < 1e-5) // if polygon object is invisible continue; if (pass == 0) { if (newOpacityPolygon < 0.9999) // if not fully opaque continue; // draw only opaque ones in pass 0 } else if (newOpacityPolygon > 0.9999) // if fully opaque continue; // draw only non-opaque ones in pass 1 glPushMatrix(); if (pset->correctPerspective) { // Correct perspective appearance by skewing GLfloat skewx = -((p->centerPos.x - s->width / 2) * 1.15); GLfloat skewy = -((p->centerPos.y - s->height / 2) * 1.15); // column-major order GLfloat skewMat[16] = {1,0,0,0, 0,1,0,0, skewx,skewy,1,0, 0,0,0,1}; glMultMatrixf( skewMat); } // Center glTranslatef(p->centerPos.x, p->centerPos.y, p->centerPos.z); // Scale z first glScalef(1.0f, 1.0f, 1.0f / s->width); // Move by "rotation axis offset" glTranslatef(p->rotAxisOffset.x, p->rotAxisOffset.y, p->rotAxisOffset.z); // Rotate by desired angle glRotatef(p->rotAngle, p->rotAxis.x, p->rotAxis.y, p->rotAxis.z); // Move back to center glTranslatef(-p->rotAxisOffset.x, -p->rotAxisOffset.y, -p->rotAxisOffset.z); // Scale back glScalef(1.0f, 1.0f, s->width); clipPlane0[3] = -(c->boxf.x1 - p->centerPosStart.x); clipPlane1[3] = -(c->boxf.y1 - p->centerPosStart.y); clipPlane2[3] = (c->boxf.x2 - p->centerPosStart.x); clipPlane3[3] = (c->boxf.y2 - p->centerPosStart.y); glClipPlane(GL_CLIP_PLANE0, clipPlane0); glClipPlane(GL_CLIP_PLANE1, clipPlane1); glClipPlane(GL_CLIP_PLANE2, clipPlane2); glClipPlane(GL_CLIP_PLANE3, clipPlane3); int k; for (k = 0; k < 4; k++) glEnable(GL_CLIP_PLANE0 + k); Bool fadeBackAndSides = pset->backAndSidesFadeDur > 0 && forwardProgress <= pset->backAndSidesFadeDur; float newOpacityPolygon2 = newOpacityPolygon; if (fadeBackAndSides) { // Fade-in opacity for back face and sides newOpacityPolygon2 *= (forwardProgress / pset->backAndSidesFadeDur); } if (saturationFull) glColor4f(brightness, brightness, brightness, newOpacityPolygon2); else if (prevActiveTexture == GL_TEXTURE1_ARB) { // From paint.c GLfloat constant2[4] = { 0.5f + 0.5f * RED_SATURATION_WEIGHT * brightness, 0.5f + 0.5f * GREEN_SATURATION_WEIGHT * brightness, 0.5f + 0.5f * BLUE_SATURATION_WEIGHT * brightness, newOpacityPolygon2 }; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant2); } else //if (prevActiveTexture >= GL_TEXTURE2_ARB) { GLfloat constant2[4] = { brightness, brightness, brightness, newOpacityPolygon2 }; // From paint.c glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant2); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT); glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT); glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); } //glEnableClientState(GL_NORMAL_ARRAY); //glEnable(GL_NORMALIZE); // Draw back face glVertexPointer(3, GL_FLOAT, 0, p->vertices + 3 * p->nSides); //glNormalPointer(GL_FLOAT, 0, // p->normals + 3 * p->nSides); glTexCoordPointer(2, GL_FLOAT, 0, c->polygonVertexTexCoords + 2 * (2 * nFrontVerticesTilThisPoly + p->nSides)); glNormal3f(p->normals[3], p->normals[4], p->normals[5]); glDrawArrays(GL_POLYGON, 0, p->nSides); // Front vertex coords glVertexPointer(3, GL_FLOAT, 0, p->vertices); //glNormalPointer(GL_FLOAT, 0, p->normals); glTexCoordPointer(2, GL_FLOAT, 0, c->polygonVertexTexCoords + 2 * 2 * nFrontVerticesTilThisPoly); //if (pset->thickness > 1e-5) { // TODO: Surface normals for sides // Draw quad strip for sides if (TRUE) { // Do each quad separately to be able to specify // different normals for (k = 0; k < p->nSides; k++) { /* int k2 = (k + 2) * 3; glNormal3f(p->normals[k2 + 0], p->normals[k2 + 1], p->normals[k2 + 2]); */ glNormal3f(p->normals[0], // front face normal for now p->normals[1], p->normals[2]); glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, p->sideIndices + k * 4); } } else // no need for separate quad rendering glDrawElements(GL_QUAD_STRIP, 2 * (p->nSides + 1), GL_UNSIGNED_SHORT, p->sideIndices); } if (fadeBackAndSides) // if opacity was changed just above { // Go back to normal opacity for front face if (saturationFull) glColor4f(brightness, brightness, brightness, newOpacityPolygon); else if (prevActiveTexture == GL_TEXTURE1_ARB) { GLfloat constant[4] = { 0.5f + 0.5f * RED_SATURATION_WEIGHT * brightness, 0.5f + 0.5f * GREEN_SATURATION_WEIGHT * brightness, 0.5f + 0.5f * BLUE_SATURATION_WEIGHT * brightness, newOpacityPolygon }; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant); } else { GLfloat constant[4] = { brightness, brightness, brightness, newOpacityPolygon }; glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant); } } // Draw front face glNormal3f(p->normals[0], p->normals[1], p->normals[2]); glDrawArrays(GL_POLYGON, 0, p->nSides); for (k = 0; k < 4; k++) glDisable(GL_CLIP_PLANE0 + k); glPopMatrix(); } } } // Restore // ----------------------------------------- // Restore old color values glColor4f(oldColor[0], oldColor[1], oldColor[2], oldColor[3]); //screenTexEnvMode(w->screen, GL_REPLACE); glPopAttrib(); if (pset->doDepthTest) { glPopAttrib(); glPopAttrib(); } //if (!normalArrayWas) // glDisableClientState(GL_NORMAL_ARRAY); // Restore texture stuff if (saturationFull) screenTexEnvMode(w->screen, GL_REPLACE); else if (prevActiveTexture == GL_TEXTURE2_ARB) { disableTexture(w->screen, aw->curTexture); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); w->screen->activeTexture(prevActiveTexture); } // Restore blend values if (!blendWas) glDisable(GL_BLEND); glBlendFunc(blendSrcWas, blendDstWas); glPopMatrix(); if (pset->doLighting) // && !s->lighting) { glPopAttrib(); glPopAttrib(); glPopAttrib(); } if (aw->clipsUpdated) // set end mark for this group of clips pset->lastClipInGroup[aw->nDrawGeometryCalls - 1] = lastClip; // Next time, start drawing from next group of clips pset->firstNondrawnClip = pset->lastClipInGroup[aw->nDrawGeometryCalls - 1] + 1; } static void polygonsPrePaintWindow(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); if (aw->polygonSet) aw->polygonSet->firstNondrawnClip = 0; } static void polygonsPostPaintWindow(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); if (aw->clipsUpdated && // clips should be dropped only in the 1st step aw->polygonSet && aw->nDrawGeometryCalls == 0) // if clips not drawn { // drop these unneeded clips (e.g. ones passed by blurfx) aw->polygonSet->nClips = aw->polygonSet->firstNondrawnClip; } } static void fxExplode3DInit(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); if (!tessellateIntoRectangles(w, 20, 14, 15.0f)) return; PolygonSet *pset = aw->polygonSet; PolygonObject *p = pset->polygons; float sqrt2 = sqrt(2); int i; for (i = 0; i < pset->nPolygons; i++, p++) { p->rotAxis.x = RAND_FLOAT(); p->rotAxis.y = RAND_FLOAT(); p->rotAxis.z = RAND_FLOAT(); float screenSizeFactor = (0.8 * DEFAULT_Z_CAMERA * s->width); float speed = screenSizeFactor / 10 * (0.2 + RAND_FLOAT()); float xx = 2 * (p->centerRelPos.x - 0.5); float yy = 2 * (p->centerRelPos.y - 0.5); float x = speed * (xx + 0.5 * (RAND_FLOAT() - 0.5)); float y = speed * (yy + 0.5 * (RAND_FLOAT() - 0.5)); float zbias = 0.3; float z = speed * 10 * (zbias + (sqrt2 - sqrt(xx * xx + yy * yy)) / sqrt2); p->finalRelPos.x = x; p->finalRelPos.y = y; p->finalRelPos.z = z; p->finalRotAng = 270; } pset->allFadeDuration = 0.2f; pset->doDepthTest = TRUE; pset->doLighting = TRUE; pset->correctPerspective = TRUE; pset->backAndSidesFadeDur = 0.2f; } static void fxLeafSpread3DInit(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); if (!tessellateIntoRectangles(w, 20, 14, 15.0f)) return; PolygonSet *pset = aw->polygonSet; PolygonObject *p = pset->polygons; float fadeDuration = 0.26; float life = 0.4; float spreadFac = 3.5; float randYMax = 0.07; float winFacX = WIN_W(w) / 800.0; float winFacY = WIN_H(w) / 800.0; float winFacZ = (WIN_H(w) + WIN_W(w)) / 2.0 / 800.0; int i; for (i = 0; i < pset->nPolygons; i++, p++) { p->rotAxis.x = RAND_FLOAT(); p->rotAxis.y = RAND_FLOAT(); p->rotAxis.z = RAND_FLOAT(); float screenSizeFactor = (0.8 * DEFAULT_Z_CAMERA * s->width); float speed = screenSizeFactor / 10 * (0.2 + RAND_FLOAT()); float xx = 2 * (p->centerRelPos.x - 0.5); float yy = 2 * (p->centerRelPos.y - 0.5); float x = speed * winFacX * spreadFac * (xx + 0.5 * (RAND_FLOAT() - 0.5)); float y = speed * winFacY * spreadFac * (yy + 0.5 * (RAND_FLOAT() - 0.5)); float z = speed * winFacZ * 7 * ((RAND_FLOAT() - 0.5) / 0.5); p->finalRelPos.x = x; p->finalRelPos.y = y; p->finalRelPos.z = z; p->moveStartTime = p->centerRelPos.y * (1 - fadeDuration - randYMax) + randYMax * RAND_FLOAT(); p->moveDuration = 1; p->fadeStartTime = p->moveStartTime + life; if (p->fadeStartTime > 1 - fadeDuration) p->fadeStartTime = 1 - fadeDuration; p->fadeDuration = fadeDuration; p->finalRotAng = 150; } pset->doDepthTest = TRUE; pset->doLighting = TRUE; pset->correctPerspective = TRUE; } static void fxDomino3DInit(CompScreen * s, CompWindow * w) { ANIM_WINDOW(w); ANIM_SCREEN(s); // Sub effects: // 1: Domino // 2: Razr int subEffectNo = aw->subEffectNo; int fallDir; if (subEffectNo == 2) fallDir = getAnimationDirection (w, as->opt[ANIM_SCREEN_OPTION_RAZR_DIRECTION].value.s, TRUE); else fallDir = getAnimationDirection (w, as->opt[ANIM_SCREEN_OPTION_DOMINO_DIRECTION].value.s, TRUE); int defaultGridSize = 20; float minCellSize = 30; int gridSizeX; int gridSizeY; int fallDirGridSize; float minDistStartEdge; // half piece size in [0,1] range float gridCellW; float gridCellH; float cellAspectRatio = 1.25; if (subEffectNo == 2) cellAspectRatio = 1; // Determine sensible domino piece sizes if (fallDir == AnimDirectionDown || fallDir == AnimDirectionUp) { if (minCellSize > BORDER_W(w)) minCellSize = BORDER_W(w); if (BORDER_W(w) / defaultGridSize < minCellSize) gridSizeX = (int)(BORDER_W(w) / minCellSize); else gridSizeX = defaultGridSize; gridCellW = BORDER_W(w) / gridSizeX; gridSizeY = (int)(BORDER_H(w) / (gridCellW * cellAspectRatio)); if (gridSizeY == 0) gridSizeY = 1; gridCellH = BORDER_H(w) / gridSizeY; fallDirGridSize = gridSizeY; } else { if (minCellSize > BORDER_H(w)) minCellSize = BORDER_H(w); if (BORDER_H(w) / defaultGridSize < minCellSize) gridSizeY = (int)(BORDER_H(w) / minCellSize); else gridSizeY = defaultGridSize; gridCellH = BORDER_H(w) / gridSizeY; gridSizeX = (int)(BORDER_W(w) / (gridCellH * cellAspectRatio)); if (gridSizeX == 0) gridSizeX = 1; gridCellW = BORDER_W(w) / gridSizeX; fallDirGridSize = gridSizeX; } minDistStartEdge = (1.0 / fallDirGridSize) / 2; float thickness = MIN(gridCellW, gridCellH) / 3.5; if (!tessellateIntoRectangles(w, gridSizeX, gridSizeY, thickness)) return; float rotAxisX = 0; float rotAxisY = 0; Point3d rotAxisOff = { 0, 0, thickness / 2 }; float posX = 0; // position of standing piece float posY = 0; float posZ = 0; int nFallingColumns = gridSizeX; float gridCellHalfW = gridCellW / 2; float gridCellHalfH = gridCellH / 2; switch (fallDir) { case AnimDirectionDown: rotAxisX = -1; if (subEffectNo == 2) rotAxisOff.y = -gridCellHalfH; else { posY = -(gridCellHalfH + thickness); posZ = gridCellHalfH - thickness / 2; } break; case AnimDirectionLeft: rotAxisY = -1; if (subEffectNo == 2) rotAxisOff.x = gridCellHalfW; else { posX = gridCellHalfW + thickness; posZ = gridCellHalfW - thickness / 2; } nFallingColumns = gridSizeY; break; case AnimDirectionUp: rotAxisX = 1; if (subEffectNo == 2) rotAxisOff.y = gridCellHalfH; else { posY = gridCellHalfH + thickness; posZ = gridCellHalfH - thickness / 2; } break; case AnimDirectionRight: rotAxisY = 1; if (subEffectNo == 2) rotAxisOff.x = -gridCellHalfW; else { posX = -(gridCellHalfW + thickness); posZ = gridCellHalfW - thickness / 2; } nFallingColumns = gridSizeY; break; } float fadeDuration; float riseDuration; float riseTimeRandMax = 0.2; if (subEffectNo == 2) { riseDuration = (1 - riseTimeRandMax) / fallDirGridSize; fadeDuration = riseDuration / 2; } else { fadeDuration = 0.18; riseDuration = 0.2; } float *riseTimeRandSeed = calloc(1, nFallingColumns * sizeof(float)); if (!riseTimeRandSeed) // TODO: log error here return; int i; for (i = 0; i < nFallingColumns; i++) riseTimeRandSeed[i] = RAND_FLOAT(); PolygonSet *pset = aw->polygonSet; PolygonObject *p = pset->polygons; for (i = 0; i < pset->nPolygons; i++, p++) { p->rotAxis.x = rotAxisX; p->rotAxis.y = rotAxisY; p->rotAxis.z = 0; p->finalRelPos.x = posX; p->finalRelPos.y = posY; p->finalRelPos.z = posZ; // dist. from rise-start / fall-end edge in window ([0,1] range) float distStartEdge = 0; // dist. from edge perpendicular to movement (for move start time) // so that same the blocks in same row/col. appear to knock down // the next one float distPerpEdge = 0; switch (fallDir) { case AnimDirectionUp: distStartEdge = p->centerRelPos.y; distPerpEdge = p->centerRelPos.x; break; case AnimDirectionRight: distStartEdge = 1 - p->centerRelPos.x; distPerpEdge = p->centerRelPos.y; break; case AnimDirectionDown: distStartEdge = 1 - p->centerRelPos.y; distPerpEdge = p->centerRelPos.x; break; case AnimDirectionLeft: distStartEdge = p->centerRelPos.x; distPerpEdge = p->centerRelPos.y; break; } float riseTimeRand = riseTimeRandSeed[(int)(distPerpEdge * nFallingColumns)] * riseTimeRandMax; p->moveDuration = riseDuration; float mult = 1; if (fallDirGridSize > 1) mult = ((distStartEdge - minDistStartEdge) / (1 - 2 * minDistStartEdge)); if (subEffectNo == 2) { p->moveStartTime = mult * (1 - riseDuration - riseTimeRandMax) + riseTimeRand; p->fadeStartTime = p->moveStartTime + riseDuration / 2; p->finalRotAng = -180; p->rotAxisOffset.x = rotAxisOff.x; p->rotAxisOffset.y = rotAxisOff.y; p->rotAxisOffset.z = rotAxisOff.z; } else { p->moveStartTime = mult * (1 - riseDuration - riseTimeRandMax) + riseTimeRand; p->fadeStartTime = p->moveStartTime + riseDuration - riseTimeRand + 0.03; p->finalRotAng = -90; } if (p->fadeStartTime > 1 - fadeDuration) p->fadeStartTime = 1 - fadeDuration; p->fadeDuration = fadeDuration; } free(riseTimeRandSeed); pset->doDepthTest = TRUE; pset->doLighting = TRUE; pset->correctPerspective = TRUE; } /* static void fxTornado3DInit(CompScreen * s, CompWindow * w) { //ANIM_WINDOW(w); if (!tessellateIntoRectangles(w, 20, 14, 15.0f)) return; } */ static void fxGlideInit(CompScreen * s, CompWindow * w) { ANIM_SCREEN(s); ANIM_WINDOW(w); float finalDistFac; float finalRotAng; float thickness; fxGlideGetParams(as, aw, &finalDistFac, &finalRotAng, &thickness); if (thickness < 1e-5) // if thicknes is 0, we'll make the effect 2D { // store window opacity aw->storedOpacity = w->paint.opacity; aw->timestep = (s->slowAnimations ? 2 : // For smooth slow-mo as->opt[ANIM_SCREEN_OPTION_TIME_STEP].value.i); return; // we're done with 2D initialization } // for 3D glide effect // ------------------------ PolygonSet *pset = aw->polygonSet; pset->includeShadows = (thickness < 1e-5); if (!tessellateIntoRectangles(w, 1, 1, thickness)) return; PolygonObject *p = pset->polygons; int i; for (i = 0; i < pset->nPolygons; i++, p++) { p->rotAxis.x = 1; p->rotAxis.y = 0; p->rotAxis.z = 0; p->finalRelPos.x = 0; p->finalRelPos.y = 0; p->finalRelPos.z = finalDistFac * 0.8 * DEFAULT_Z_CAMERA * s->width; p->finalRotAng = finalRotAng; } pset->allFadeDuration = 1.0f; pset->backAndSidesFadeDur = 0.2f; pset->doLighting = TRUE; pset->correctPerspective = TRUE; } // Computes polygon's new position and orientation // with linear movement static void polygonsLinearAnimStepPolygon(CompWindow * w, PolygonObject * p, float forwardProgress) { float moveProgress = forwardProgress - p->moveStartTime; if (p->moveDuration > 0) moveProgress /= p->moveDuration; if (moveProgress < 0) moveProgress = 0; else if (moveProgress > 1) moveProgress = 1; p->centerPos.x = moveProgress * p->finalRelPos.x + p->centerPosStart.x; p->centerPos.y = moveProgress * p->finalRelPos.y + p->centerPosStart.y; p->centerPos.z = 1.0f / w->screen->width * moveProgress * p->finalRelPos.z + p->centerPosStart.z; p->rotAngle = moveProgress * p->finalRotAng + p->rotAngleStart; } // Similar to polygonsLinearAnimStepPolygon, // but slightly ac/decelerates movement static void polygonsDeceleratingAnimStepPolygon(CompWindow * w, PolygonObject * p, float forwardProgress) { float moveProgress = forwardProgress - p->moveStartTime; if (p->moveDuration > 0) moveProgress /= p->moveDuration; if (moveProgress < 0) moveProgress = 0; else if (moveProgress > 1) moveProgress = 1; moveProgress = decelerateProgress2(moveProgress); p->centerPos.x = moveProgress * p->finalRelPos.x + p->centerPosStart.x; p->centerPos.y = moveProgress * p->finalRelPos.y + p->centerPosStart.y; p->centerPos.z = 1.0f / w->screen->width * moveProgress * p->finalRelPos.z + p->centerPosStart.z; p->rotAngle = moveProgress * p->finalRotAng + p->rotAngleStart; } // ===================== End of Effects ========================= AnimEffectProperties animEffectProperties[AnimEffectNum] = { // AnimEffectNone {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} , // AnimEffectRandom {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} , // AnimEffectBeamUp {fxBeamupUpdateWindowAttrib, 0, drawParticleSystems, fxBeamUpModelStep, fxBeamUpInit, 0, 0, 0, 1, 0, 0} , // AnimEffectBurn {0, 0, drawParticleSystems, fxBurnModelStep, fxBurnInit, 0, 0, 0, 1, 0, 0} , // AnimEffectCurvedFold {0, 0, 0, fxCurvedFoldModelStep, 0, fxMagicLamp1InitGrid, 0, 0, 0, 0, 0} , // AnimEffectDomino3D {0, polygonsPrePaintWindow, polygonsPostPaintWindow, polygonsAnimStep, fxDomino3DInit, 0, polygonsStoreClips, polygonsDrawCustomGeometry, 0, polygonsLinearAnimStepPolygon, 1} , // AnimEffectDream {fxDreamUpdateWindowAttrib, 0, 0, fxDreamModelStep, fxDreamInit, fxMagicLamp1InitGrid, 0, 0, 0, 0, 0} , // AnimEffectExplode3D {0, polygonsPrePaintWindow, polygonsPostPaintWindow, polygonsAnimStep, fxExplode3DInit, 0, polygonsStoreClips, polygonsDrawCustomGeometry, 0, polygonsLinearAnimStepPolygon, 0} , // AnimEffectFade {fxFadeUpdateWindowAttrib, 0, 0, fxFadeModelStep, fxFadeInit, 0, 0, 0, 0, 0, 0} , // AnimEffectGlide3D1 {fxGlideUpdateWindowAttrib, polygonsPrePaintWindow, polygonsPostPaintWindow, fxGlideAnimStep, fxGlideInit, 0, polygonsStoreClips, polygonsDrawCustomGeometry, 0, polygonsDeceleratingAnimStepPolygon, 1} , // AnimEffectGlide3D2 {fxGlideUpdateWindowAttrib, polygonsPrePaintWindow, polygonsPostPaintWindow, fxGlideAnimStep, fxGlideInit, 0, polygonsStoreClips, polygonsDrawCustomGeometry, 0, polygonsDeceleratingAnimStepPolygon, 2} , // AnimEffectHorizontalFolds {0, 0, 0, fxHorizontalFoldsModelStep, 0, fxHorizontalFoldsInitGrid, 0, 0, 0, 0, 0} , // AnimEffectLeafSpread3D {0, polygonsPrePaintWindow, polygonsPostPaintWindow, polygonsAnimStep, fxLeafSpread3DInit, 0, polygonsStoreClips, polygonsDrawCustomGeometry, 0, polygonsLinearAnimStepPolygon, 0} , // AnimEffectMagicLamp1 {0, 0, 0, fxMagicLampModelStep, fxMagicLampInit, fxMagicLamp1InitGrid, 0, 0, 0, 0, 0} , // AnimEffectMagicLamp2 {0, 0, 0, fxMagicLampModelStep, fxMagicLampInit, fxMagicLamp2InitGrid, 0, 0, 0, 0, 0} , // AnimEffectMagicLamp3 {0, 0, 0, fxMagicLampModelStep, fxMagicLampInit, fxMagicLamp3InitGrid, 0} , // AnimEffectRazr3D {0, polygonsPrePaintWindow, polygonsPostPaintWindow, polygonsAnimStep, fxDomino3DInit, 0, polygonsStoreClips, polygonsDrawCustomGeometry, 0, polygonsLinearAnimStepPolygon, 2} , // AnimEffectRollUp {0, 0, 0, fxRollUpModelStep, 0, fxRollUpInitGrid, 0, 0, 1, 0, 0} , // AnimEffectSidekick {fxZoomUpdateWindowAttrib, 0, 0, fxZoomModelStep, fxSidekickInit, 0, 0, 0, 1, 0, 0} , // AnimEffectWave {0, 0, 0, fxWaveModelStep, 0, fxMagicLamp1InitGrid, 0, 0, 0, 0, 0} , // AnimEffectZoom {fxZoomUpdateWindowAttrib, 0, 0, fxZoomModelStep, fxZoomInit, 0, 0, 0, 1, 0, 0} }; static Bool getMousePointerXY(CompScreen * s, short *x, short *y) { Window w1, w2; int xp, yp, xj, yj; unsigned int m; if (XQueryPointer (s->display->display, s->root, &w1, &w2, &xj, &yj, &xp, &yp, &m)) { *x = xp; *y = yp; return TRUE; } return FALSE; } static int animGetWindowState(CompWindow * w) { Atom actual; int result, format; unsigned long n, left; unsigned char *data; result = XGetWindowProperty(w->screen->display->display, w->id, w->screen->display->wmStateAtom, 0L, 1L, FALSE, w->screen->display->wmStateAtom, &actual, &format, &n, &left, &data); if (result == Success && n && data) { int state; memcpy(&state, data, sizeof(int)); XFree((void *)data); return state; } return WithdrawnState; } static Bool animSetScreenOption(CompScreen * screen, char *name, CompOptionValue * value) { CompOption *o; int index; ANIM_SCREEN(screen); o = compFindOption(as->opt, NUM_OPTIONS(as), name, &index); if (!o) return FALSE; switch (index) { case ANIM_SCREEN_OPTION_SIDEKICK_NUM_ROTATIONS: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_ZOOM_FROM_CENTER: if (compSetStringOption(o, value)) { int i; for (i = 0; i < 4; i++) { if (strcmp(o->value.s, zoomFromCenterOption[i]) == 0) { as->zoomFC = i; return TRUE; } } } break; case ANIM_SCREEN_OPTION_TIME_STEP: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_TIME_STEP_INTENSE: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_DISABLE_PP_FX: if (compSetStringOption(o, value)) { int i; for (i = 0; i < 3; i++) { if (strcmp(o->value.s, ppDisablingName[i]) == 0) { as->ppDisabling = i; return TRUE; } } } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP1_GRID_RES: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP1_MAX_WAVES: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP1_WAVE_AMP_MIN: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP1_WAVE_AMP_MAX: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP1_CREATE_START_WIDTH: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP2_GRID_RES: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP2_MAX_WAVES: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP2_WAVE_AMP_MIN: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP2_WAVE_AMP_MAX: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP2_CREATE_START_WIDTH: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP3_GRID_RES: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP3_MAX_WAVES: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP3_WAVE_AMP_MIN: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP3_WAVE_AMP_MAX: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MAGIC_LAMP3_CREATE_START_WIDTH: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_FOCUS_WAVE_WIDTH: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_FOCUS_WAVE_AMP: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_CURVED_FOLD_AMP: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_AMP: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_NUM_FOLDS: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_ROLLUP_FIXED_INTERIOR: if (compSetBoolOption(o, value)) return TRUE; break; case ANIM_SCREEN_OPTION_ALL_RANDOM: if (compSetBoolOption(o, value)) return TRUE; break; case ANIM_SCREEN_OPTION_MINIMIZE_EFFECT: if (compSetStringOption(o, value)) { int i; for (i = 0; i < NUM_MINIMIZE_EFFECT; i++) { if (strcmp(o->value.s, minimizeEffectName[i]) == 0) { as->minimizeEffect = minimizeEffectType[i]; return TRUE; } } } break; case ANIM_SCREEN_OPTION_UNMINIMIZE_EFFECT: if (compSetStringOption(o, value)) { int i; for (i = 0; i < NUM_MINIMIZE_EFFECT; i++) { if (strcmp(o->value.s, minimizeEffectName[i]) == 0) { as->unminimizeEffect = minimizeEffectType[i]; return TRUE; } } } break; case ANIM_SCREEN_OPTION_CLOSE1_EFFECT: if (compSetStringOption(o, value)) { int i; for (i = 0; i < NUM_CLOSE_EFFECT; i++) { if (strcmp(o->value.s, closeEffectName[i]) == 0) { as->close1Effect = closeEffectType[i]; return TRUE; } } } break; case ANIM_SCREEN_OPTION_CLOSE2_EFFECT: if (compSetStringOption(o, value)) { int i; for (i = 0; i < NUM_CLOSE_EFFECT; i++) { if (strcmp(o->value.s, closeEffectName[i]) == 0) { as->close2Effect = closeEffectType[i]; return TRUE; } } } break; case ANIM_SCREEN_OPTION_CREATE1_EFFECT: if (compSetStringOption(o, value)) { int i; for (i = 0; i < NUM_CLOSE_EFFECT; i++) { if (strcmp(o->value.s, closeEffectName[i]) == 0) { as->create1Effect = closeEffectType[i]; return TRUE; } } } break; case ANIM_SCREEN_OPTION_CREATE2_EFFECT: if (compSetStringOption(o, value)) { int i; for (i = 0; i < NUM_CLOSE_EFFECT; i++) { if (strcmp(o->value.s, closeEffectName[i]) == 0) { as->create2Effect = closeEffectType[i]; return TRUE; } } } break; case ANIM_SCREEN_OPTION_FOCUS_EFFECT: if (compSetStringOption(o, value)) { int i; for (i = 0; i < NUM_FOCUS_EFFECT; i++) { if (strcmp(o->value.s, focusEffectName[i]) == 0) { as->focusEffect = focusEffectType[i]; return TRUE; } } } break; case ANIM_SCREEN_OPTION_SHADE_EFFECT: if (compSetStringOption(o, value)) { int i; for (i = 0; i < NUM_SHADE_EFFECT; i++) { if (strcmp(o->value.s, shadeEffectName[i]) == 0) { as->shadeEffect = shadeEffectType[i]; return TRUE; } } } break; case ANIM_SCREEN_OPTION_UNSHADE_EFFECT: if (compSetStringOption(o, value)) { int i; for (i = 0; i < NUM_SHADE_EFFECT; i++) { if (strcmp(o->value.s, shadeEffectName[i]) == 0) { as->unshadeEffect = shadeEffectType[i]; return TRUE; } } } break; case ANIM_SCREEN_OPTION_MINIMIZE_WINDOW_TYPE: if (compSetOptionList(o, value)) { as->minimizeWMask = compWindowTypeMaskFromStringList(&o->value); return TRUE; } break; case ANIM_SCREEN_OPTION_UNMINIMIZE_WINDOW_TYPE: if (compSetOptionList(o, value)) { as->unminimizeWMask = compWindowTypeMaskFromStringList(&o->value); return TRUE; } break; case ANIM_SCREEN_OPTION_CLOSE1_WINDOW_TYPE: if (compSetOptionList(o, value)) { as->close1WMask = compWindowTypeMaskFromStringList(&o->value); return TRUE; } break; case ANIM_SCREEN_OPTION_CLOSE2_WINDOW_TYPE: if (compSetOptionList(o, value)) { as->close2WMask = compWindowTypeMaskFromStringList(&o->value); return TRUE; } break; case ANIM_SCREEN_OPTION_CREATE1_WINDOW_TYPE: if (compSetOptionList(o, value)) { as->create1WMask = compWindowTypeMaskFromStringList(&o->value); return TRUE; } break; case ANIM_SCREEN_OPTION_CREATE2_WINDOW_TYPE: if (compSetOptionList(o, value)) { as->create2WMask = compWindowTypeMaskFromStringList(&o->value); return TRUE; } break; case ANIM_SCREEN_OPTION_FOCUS_WINDOW_TYPE: if (compSetOptionList(o, value)) { as->focusWMask = compWindowTypeMaskFromStringList(&o->value); return TRUE; } break; case ANIM_SCREEN_OPTION_SHADE_WINDOW_TYPE: if (compSetOptionList(o, value)) { as->shadeWMask = compWindowTypeMaskFromStringList(&o->value); return TRUE; } break; case ANIM_SCREEN_OPTION_UNSHADE_WINDOW_TYPE: if (compSetOptionList(o, value)) { as->unshadeWMask = compWindowTypeMaskFromStringList(&o->value); return TRUE; } break; case ANIM_SCREEN_OPTION_MINIMIZE_DURATION: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_UNMINIMIZE_DURATION: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_CLOSE1_DURATION: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_CLOSE2_DURATION: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_CREATE1_DURATION: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_CREATE2_DURATION: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_FOCUS_DURATION: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_SHADE_DURATION: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_UNSHADE_DURATION: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_FIRE_PARTICLES: if (compSetIntOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_FIRE_SIZE: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_FIRE_SLOWDOWN: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_FIRE_LIFE: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_FIRE_COLOR: if (compSetColorOption(o, value)) { return TRUE; } case ANIM_SCREEN_OPTION_FIRE_DIRECTION: if (compSetStringOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_FIRE_CONSTANT_SPEED: if (compSetBoolOption(o, value)) return TRUE; break; case ANIM_SCREEN_OPTION_FIRE_SMOKE: if (compSetBoolOption(o, value)) return TRUE; break; case ANIM_SCREEN_OPTION_FIRE_MYSTICAL: if (compSetBoolOption(o, value)) return TRUE; break; case ANIM_SCREEN_OPTION_BEAMUP_SIZE: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_BEAMUP_SPACING: if (compSetIntOption(o, value)) { return TRUE; } case ANIM_SCREEN_OPTION_BEAMUP_COLOR: if (compSetColorOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_BEAMUP_SLOWDOWN: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_BEAMUP_LIFE: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_DOMINO_DIRECTION: if (compSetStringOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_RAZR_DIRECTION: if (compSetStringOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_GLIDE1_AWAY_POS: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_GLIDE1_AWAY_ANGLE: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_GLIDE1_THICKNESS: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_GLIDE2_AWAY_POS: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_GLIDE2_AWAY_ANGLE: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_GLIDE2_THICKNESS: if (compSetFloatOption(o, value)) { return TRUE; } break; case ANIM_SCREEN_OPTION_MINIMIZE_RANDOM_EFFECTS: if (compSetOptionList(o, value)) { STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_MINIMIZE_RANDOM_EFFECTS, NUM_MINIMIZE_EFFECT, ANIM_MINIMIZE_DEFAULT, nMinimizeRandomEffects, minimizeRandomEffects, minimizeEffectName, minimizeEffectType); return TRUE; } break; case ANIM_SCREEN_OPTION_UNMINIMIZE_RANDOM_EFFECTS: if (compSetOptionList(o, value)) { STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_UNMINIMIZE_RANDOM_EFFECTS, NUM_MINIMIZE_EFFECT, ANIM_UNMINIMIZE_DEFAULT, nUnminimizeRandomEffects, unminimizeRandomEffects, minimizeEffectName, minimizeEffectType); return TRUE; } break; case ANIM_SCREEN_OPTION_CLOSE1_RANDOM_EFFECTS: if (compSetOptionList(o, value)) { STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CLOSE1_RANDOM_EFFECTS, NUM_CLOSE_EFFECT, ANIM_CLOSE1_DEFAULT, nClose1RandomEffects, close1RandomEffects, closeEffectName, closeEffectType); return TRUE; } break; case ANIM_SCREEN_OPTION_CLOSE2_RANDOM_EFFECTS: if (compSetOptionList(o, value)) { STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CLOSE2_RANDOM_EFFECTS, NUM_CLOSE_EFFECT, ANIM_CLOSE2_DEFAULT, nClose2RandomEffects, close2RandomEffects, closeEffectName, closeEffectType); return TRUE; } break; case ANIM_SCREEN_OPTION_CREATE1_RANDOM_EFFECTS: if (compSetOptionList(o, value)) { STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CREATE1_RANDOM_EFFECTS, NUM_CLOSE_EFFECT, ANIM_CREATE1_DEFAULT, nCreate1RandomEffects, create1RandomEffects, closeEffectName, closeEffectType); return TRUE; } break; case ANIM_SCREEN_OPTION_CREATE2_RANDOM_EFFECTS: if (compSetOptionList(o, value)) { STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CREATE2_RANDOM_EFFECTS, NUM_CLOSE_EFFECT, ANIM_CREATE2_DEFAULT, nCreate2RandomEffects, create2RandomEffects, closeEffectName, closeEffectType); return TRUE; } break; case ANIM_SCREEN_OPTION_SHADE_RANDOM_EFFECTS: if (compSetOptionList(o, value)) { STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_SHADE_RANDOM_EFFECTS, NUM_SHADE_EFFECT, ANIM_SHADE_DEFAULT, nShadeRandomEffects, shadeRandomEffects, shadeEffectName, shadeEffectType); return TRUE; } break; case ANIM_SCREEN_OPTION_UNSHADE_RANDOM_EFFECTS: if (compSetOptionList(o, value)) { STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_UNSHADE_RANDOM_EFFECTS, NUM_SHADE_EFFECT, ANIM_UNSHADE_DEFAULT, nUnshadeRandomEffects, unshadeRandomEffects, shadeEffectName, shadeEffectType); return TRUE; } break; default: break; } return FALSE; } static void animScreenInitOptions(AnimScreen * as) { CompOption *o; int i; o = &as->opt[ANIM_SCREEN_OPTION_ALL_RANDOM]; o->name = "all_random"; o->group = N_("Misc. Settings"); o->subGroup = N_(""); o->shortDesc = N_("Random Animations For All Events"); o->advanced = False; o->longDesc = N_ ("All effects are chosen randomly, ignoring the selected effect. If None is selected for an event, that event won't be animated."); o->displayHints = ""; o->type = CompOptionTypeBool; o->value.b = ANIM_ALL_RANDOM_DEFAULT; o = &as->opt[ANIM_SCREEN_OPTION_ROLLUP_FIXED_INTERIOR]; o->name = "rollup_fixed_interior"; o->group = N_("(Un)Shade"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Rollup Fixed Interior"); o->longDesc = N_("Fixed window interior during the Rollup animation."); o->displayHints = ""; o->type = CompOptionTypeBool; o->value.b = ANIM_ROLLUP_FIXED_INTERIOR_DEFAULT; o = &as->opt[ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_NUM_FOLDS]; o->name = "horizontal_folds_num_folds"; o->group = N_("Horizontal Folds"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Number of Horizontal Folds"); o->longDesc = N_ ("The number of horizontal folds that occur in the Horizontal Fold animation."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_HORIZONTAL_FOLDS_NUM_FOLDS_DEFAULT; o->rest.i.min = ANIM_HORIZONTAL_FOLDS_NUM_FOLDS_MIN; o->rest.i.max = ANIM_HORIZONTAL_FOLDS_NUM_FOLDS_MAX; o = &as->opt[ANIM_SCREEN_OPTION_HORIZONTAL_FOLDS_AMP]; o->name = "horizontal_folds_amp"; o->group = N_("Horizontal Folds"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Horizontal Fold Amplitude"); o->longDesc = N_ ("Amplitude (size of the waves in the fold) of the Horizontal Folds relative to the window width. Negative values fold outward."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_HORIZONTAL_FOLDS_AMP_DEFAULT; o->rest.f.min = ANIM_HORIZONTAL_FOLDS_AMP_MIN; o->rest.f.max = ANIM_HORIZONTAL_FOLDS_AMP_MAX; o->rest.f.precision = ANIM_HORIZONTAL_FOLDS_AMP_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_CURVED_FOLD_AMP]; o->name = "curved_fold_amp"; o->group = N_("Curved Folds"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Curved Fold Amplitude"); o->longDesc = N_ ("Amplitude (size of the waves in the fold) of the curved fold relative to window width. Negative values fold outward."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_CURVED_FOLD_AMP_DEFAULT; o->rest.f.min = ANIM_CURVED_FOLD_AMP_MIN; o->rest.f.max = ANIM_CURVED_FOLD_AMP_MAX; o->rest.f.precision = ANIM_CURVED_FOLD_AMP_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_ZOOM_FROM_CENTER]; o->name = "zoom_from_center"; o->group = N_("Misc. Settings"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Zoom from Center"); o->longDesc = N_ ("Zoom from center when playing the Zoom and Sidekick animations."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(zoomFromCenterOption[ANIM_ZOOM_FROM_CENTER_DEFAULT]); o->rest.s.string = zoomFromCenterOption; o->rest.s.nString = 4; o = &as->opt[ANIM_SCREEN_OPTION_TIME_STEP]; o->name = "time_step"; o->group = N_("Misc. Settings"); o->subGroup = N_("Advanced"); o->advanced = False; o->shortDesc = N_("Animation Time Step"); o->longDesc = N_ ("The amount of time in milliseconds between each render of the animation. The higher the number, the jerkier the movements become."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_TIME_STEP_DEFAULT; o->rest.i.min = ANIM_TIME_STEP_MIN; o->rest.i.max = ANIM_TIME_STEP_MAX; o = &as->opt[ANIM_SCREEN_OPTION_TIME_STEP_INTENSE]; o->name = "time_step_intense"; o->group = N_("Misc. Settings"); o->subGroup = N_("Advanced"); o->advanced = False; o->shortDesc = N_("Animation Time Step For Intense Effects"); o->longDesc = N_ ("The amount of time in milliseconds between each render of the intense animation (Ex. Burn, Beam). The higher the number, the jerkier the movements become."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_TIME_STEP_INTENSE_DEFAULT; o->rest.i.min = ANIM_TIME_STEP_INTENSE_MIN; o->rest.i.max = ANIM_TIME_STEP_INTENSE_MAX; o = &as->opt[ANIM_SCREEN_OPTION_DISABLE_PP_FX]; o->name = "disable_pp_fx"; o->group = N_("Misc. Settings"); o->subGroup = N_("Advanced"); o->advanced = False; o->shortDesc = N_("Disable Post-processing Effects During Animation"); o->longDesc = N_("Disables Blur effects during animations."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(ppDisablingName[ANIM_DISABLE_PP_FX_DEFAULT]); o->rest.s.string = ppDisablingName; o->rest.s.nString = 3; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_GRID_RES]; o->name = "magic_lamp1_grid_res"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #1"); o->advanced = False; o->shortDesc = N_("Magic Lamp #1 Grid Y Resolution"); o->longDesc = N_ ("Vertex grid resolution for Magic Lamp #1 (Y dimension only). This is the number of points used to define the curves. The higher the number, the smoother the curves. However there will be a loss of performance (CPU usage increases)."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_MAGIC_LAMP1_GRID_RES_DEFAULT; o->rest.i.min = ANIM_MAGIC_LAMP1_GRID_RES_MIN; o->rest.i.max = ANIM_MAGIC_LAMP1_GRID_RES_MAX; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_MAX_WAVES]; o->name = "magic_lamp1_max_waves"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #1"); o->advanced = False; o->shortDesc = N_("Magic Lamp #1 Max Waves"); o->longDesc = N_("The maximum number of waves for Magic Lamp #1."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_MAGIC_LAMP1_MAX_WAVES_DEFAULT; o->rest.i.min = ANIM_MAGIC_LAMP1_MAX_WAVES_MIN; o->rest.i.max = ANIM_MAGIC_LAMP1_MAX_WAVES_MAX; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_WAVE_AMP_MIN]; o->name = "magic_lamp1_wave_amp_min"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #1"); o->advanced = False; o->shortDesc = N_("Magic Lamp #1 Wave Min Amplitude"); o->longDesc = N_ ("The minimum amplitude (size of the waves) Magic Lamp #1 will have."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_MAGIC_LAMP1_WAVE_AMP_MIN_DEFAULT; o->rest.f.min = ANIM_MAGIC_LAMP1_WAVE_AMP_MIN_MIN; o->rest.f.max = ANIM_MAGIC_LAMP1_WAVE_AMP_MIN_MAX; o->rest.f.precision = ANIM_MAGIC_LAMP1_WAVE_AMP_MIN_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_WAVE_AMP_MAX]; o->name = "magic_lamp1_wave_amp_max"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #1"); o->advanced = False; o->shortDesc = N_("Magic Lamp #1 Wave Max Amplitude"); o->longDesc = N_ ("The maxmimum amplitude (size of the waves) Magic Lamp #1 will have."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_MAGIC_LAMP1_WAVE_AMP_MAX_DEFAULT; o->rest.f.min = ANIM_MAGIC_LAMP1_WAVE_AMP_MAX_MIN; o->rest.f.max = ANIM_MAGIC_LAMP1_WAVE_AMP_MAX_MAX; o->rest.f.precision = ANIM_MAGIC_LAMP1_WAVE_AMP_MAX_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_CREATE_START_WIDTH]; o->name = "magic_lamp1_create_start_width"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #1"); o->advanced = False; o->shortDesc = N_("Magic Lamp #1 Create Start Width"); o->longDesc = N_ ("Starting width of create effect and ending width of close effect for Magic Lamp #1."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_MAGIC_LAMP1_CREATE_START_WIDTH_DEFAULT; o->rest.i.min = ANIM_MAGIC_LAMP1_CREATE_START_WIDTH_MIN; o->rest.i.max = ANIM_MAGIC_LAMP1_CREATE_START_WIDTH_MAX; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP2_GRID_RES]; o->name = "magic_lamp2_grid_res"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #2"); o->advanced = False; o->shortDesc = N_("Magic Lamp #2 Grid Y Resolution"); o->longDesc = N_ ("Vertex grid resolution for Magic Lamp #2 (Y dimension only). This is the number of points used to define the curves. The higher the number, the smoother the curves. However there will be a loss of performance (CPU usage increases)."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_MAGIC_LAMP2_GRID_RES_DEFAULT; o->rest.i.min = ANIM_MAGIC_LAMP2_GRID_RES_MIN; o->rest.i.max = ANIM_MAGIC_LAMP2_GRID_RES_MAX; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP2_MAX_WAVES]; o->name = "magic_lamp2_max_waves"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #2"); o->advanced = False; o->shortDesc = N_("Magic Lamp #2 Max Waves"); o->longDesc = N_("The maximum number of waves for Magic Lamp #2."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_MAGIC_LAMP2_MAX_WAVES_DEFAULT; o->rest.i.min = ANIM_MAGIC_LAMP2_MAX_WAVES_MIN; o->rest.i.max = ANIM_MAGIC_LAMP2_MAX_WAVES_MAX; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP2_WAVE_AMP_MIN]; o->name = "magic_lamp2_wave_amp_min"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #2"); o->advanced = False; o->shortDesc = N_("Magic Lamp #2 Wave Min Amplitude"); o->longDesc = N_ ("The minimum amplitude (size of the waves) Magic Lamp #2 will have."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_MAGIC_LAMP2_WAVE_AMP_MIN_DEFAULT; o->rest.f.min = ANIM_MAGIC_LAMP2_WAVE_AMP_MIN_MIN; o->rest.f.max = ANIM_MAGIC_LAMP2_WAVE_AMP_MIN_MAX; o->rest.f.precision = ANIM_MAGIC_LAMP2_WAVE_AMP_MIN_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP2_WAVE_AMP_MAX]; o->name = "magic_lamp2_wave_amp_max"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #2"); o->advanced = False; o->shortDesc = N_("Magic Lamp #2 Wave Max Amplitude"); o->longDesc = N_ ("The maxmimum amplitude (size of the waves) Magic Lamp #2 will have."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_MAGIC_LAMP2_WAVE_AMP_MAX_DEFAULT; o->rest.f.min = ANIM_MAGIC_LAMP2_WAVE_AMP_MAX_MIN; o->rest.f.max = ANIM_MAGIC_LAMP2_WAVE_AMP_MAX_MAX; o->rest.f.precision = ANIM_MAGIC_LAMP2_WAVE_AMP_MAX_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP2_CREATE_START_WIDTH]; o->name = "magic_lamp2_create_start_width"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #2"); o->advanced = False; o->shortDesc = N_("Magic Lamp #2 Create Start Width"); o->longDesc = N_ ("Starting width of create effect and ending width of close effect for Magic Lamp #2."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_MAGIC_LAMP2_CREATE_START_WIDTH_DEFAULT; o->rest.i.min = ANIM_MAGIC_LAMP2_CREATE_START_WIDTH_MIN; o->rest.i.max = ANIM_MAGIC_LAMP2_CREATE_START_WIDTH_MAX; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP3_GRID_RES]; o->name = "magic_lamp3_grid_res"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #3"); o->advanced = False; o->shortDesc = N_("Magic Lamp #3 Grid Y Resolution"); o->longDesc = N_ ("Vertex grid resolution for Magic Lamp #3 (Y dimension only). This is the number of points used to define the curves. The higher the number, the smoother the curves. However there will be a loss of performance (CPU usage increases)."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_MAGIC_LAMP3_GRID_RES_DEFAULT; o->rest.i.min = ANIM_MAGIC_LAMP3_GRID_RES_MIN; o->rest.i.max = ANIM_MAGIC_LAMP3_GRID_RES_MAX; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP3_MAX_WAVES]; o->name = "magic_lamp3_max_waves"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #3"); o->advanced = False; o->shortDesc = N_("Magic Lamp #3 Max Waves"); o->longDesc = N_("The maximum number of waves for Magic Lamp #3."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_MAGIC_LAMP3_MAX_WAVES_DEFAULT; o->rest.i.min = ANIM_MAGIC_LAMP3_MAX_WAVES_MIN; o->rest.i.max = ANIM_MAGIC_LAMP3_MAX_WAVES_MAX; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP3_WAVE_AMP_MIN]; o->name = "magic_lamp3_wave_amp_min"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #3"); o->advanced = False; o->shortDesc = N_("Magic Lamp #3 Wave Min Amplitude"); o->longDesc = N_ ("The minimum amplitude (size of the waves) Magic Lamp #3 will have."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_MAGIC_LAMP3_WAVE_AMP_MIN_DEFAULT; o->rest.f.min = ANIM_MAGIC_LAMP3_WAVE_AMP_MIN_MIN; o->rest.f.max = ANIM_MAGIC_LAMP3_WAVE_AMP_MIN_MAX; o->rest.f.precision = ANIM_MAGIC_LAMP3_WAVE_AMP_MIN_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP3_WAVE_AMP_MAX]; o->name = "magic_lamp3_wave_amp_max"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #3"); o->advanced = False; o->shortDesc = N_("Magic Lamp #3 Wave Max Amplitude"); o->longDesc = N_ ("The maxmimum amplitude (size of the waves) Magic Lamp #3 will have."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_MAGIC_LAMP3_WAVE_AMP_MAX_DEFAULT; o->rest.f.min = ANIM_MAGIC_LAMP3_WAVE_AMP_MAX_MIN; o->rest.f.max = ANIM_MAGIC_LAMP3_WAVE_AMP_MAX_MAX; o->rest.f.precision = ANIM_MAGIC_LAMP3_WAVE_AMP_MAX_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_MAGIC_LAMP3_CREATE_START_WIDTH]; o->name = "magic_lamp3_create_start_width"; o->group = N_("Magic Lamp"); o->subGroup = N_("Magic Lamp #3"); o->advanced = False; o->shortDesc = N_("Magic Lamp #3 Create Start Width"); o->longDesc = N_ ("Starting width of create effect and ending width of close effect for Magic Lamp #3."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_MAGIC_LAMP3_CREATE_START_WIDTH_DEFAULT; o->rest.i.min = ANIM_MAGIC_LAMP3_CREATE_START_WIDTH_MIN; o->rest.i.max = ANIM_MAGIC_LAMP3_CREATE_START_WIDTH_MAX; o = &as->opt[ANIM_SCREEN_OPTION_FOCUS_WAVE_WIDTH]; o->name = "focus_wave_width"; o->group = N_("Focus Wave"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Focus Wave Width"); o->longDesc = N_("The width of the focus wave relative to the window height."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_FOCUS_WAVE_WIDTH_DEFAULT; o->rest.f.min = ANIM_FOCUS_WAVE_WIDTH_MIN; o->rest.f.max = ANIM_FOCUS_WAVE_WIDTH_MAX; o->rest.f.precision = ANIM_FOCUS_WAVE_WIDTH_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_FOCUS_WAVE_AMP]; o->name = "focus_wave_amp"; o->group = N_("Focus Wave"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Focus Wave Amplitude"); o->longDesc = N_ ("The wave amplitude (size of the waves) relative to the window height."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_FOCUS_WAVE_AMP_DEFAULT; o->rest.f.min = ANIM_FOCUS_WAVE_AMP_MIN; o->rest.f.max = ANIM_FOCUS_WAVE_AMP_MAX; o->rest.f.precision = ANIM_FOCUS_WAVE_AMP_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_SIDEKICK_NUM_ROTATIONS]; o->name = "sidekick_num_rotations"; o->group = N_("Sidekick"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Sidekick Number of Rotations"); o->longDesc = N_ ("The number of rotations plus or minus 10% (for randomness) that Sidekick has."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_SIDEKICK_NUM_ROTATIONS_DEFAULT; o->rest.f.min = ANIM_SIDEKICK_NUM_ROTATIONS_MIN; o->rest.f.max = ANIM_SIDEKICK_NUM_ROTATIONS_MAX; o->rest.f.precision = ANIM_SIDEKICK_NUM_ROTATIONS_PRECISION; // Minimize o = &as->opt[ANIM_SCREEN_OPTION_MINIMIZE_EFFECT]; o->name = "minimize_effect"; o->group = N_("(Un)Minimize"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Minimize Animation"); o->longDesc = N_("The animation shown when minimizing a window."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(allEffectName[ANIM_MINIMIZE_DEFAULT]); o->rest.s.string = minimizeEffectName; o->rest.s.nString = NUM_MINIMIZE_EFFECT; o = &as->opt[ANIM_SCREEN_OPTION_MINIMIZE_WINDOW_TYPE]; o->name = "minimize_window_types"; o->group = N_("(Un)Minimize"); o->subGroup = N_("Minimize"); o->advanced = False; o->shortDesc = N_("Window Types"); o->longDesc = N_("The window types that will be animated."); o->displayHints = ""; o->type = CompOptionTypeList; o->value.list.type = CompOptionTypeString; o->value.list.nValue = N_MINIMIZE_DEFAULT_WIN_TYPE; o->value.list.value = malloc(sizeof(CompOptionValue) * N_MINIMIZE_DEFAULT_WIN_TYPE); for (i = 0; i < N_MINIMIZE_DEFAULT_WIN_TYPE; i++) o->value.list.value[i].s = strdup(minimizeDefaultWinType[i]); o->rest.s.string = (char **)windowTypeString; o->rest.s.nString = nWindowTypeString; as->minimizeWMask = compWindowTypeMaskFromStringList(&o->value); o = &as->opt[ANIM_SCREEN_OPTION_MINIMIZE_DURATION]; o->name = "minimize_duration"; o->group = N_("(Un)Minimize"); o->subGroup = N_("Minimize"); o->advanced = False; o->shortDesc = N_("Animation Duration"); o->longDesc = N_ ("The number of seconds that the Minimize animation will last."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_MINIMIZE_DURATION_DEFAULT; o->rest.f.min = ANIM_MINIMIZE_DURATION_MIN; o->rest.f.max = ANIM_MINIMIZE_DURATION_MAX; o->rest.f.precision = ANIM_MINIMIZE_DURATION_PRECISION; INIT_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_MINIMIZE_RANDOM_EFFECTS, "minimize", "(Un)Minimize", "Minimize", NUM_MINIMIZE_EFFECT, minimizeEffectName); STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_MINIMIZE_RANDOM_EFFECTS, NUM_MINIMIZE_EFFECT, ANIM_MINIMIZE_DEFAULT, nMinimizeRandomEffects, minimizeRandomEffects, minimizeEffectName, minimizeEffectType); // Unminimize o = &as->opt[ANIM_SCREEN_OPTION_UNMINIMIZE_EFFECT]; o->name = "unminimize_effect"; o->group = N_("(Un)Minimize"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Unminimize Animation"); o->longDesc = N_("The animation shown when unminimizing a window."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(allEffectName[ANIM_UNMINIMIZE_DEFAULT]); o->rest.s.string = minimizeEffectName; o->rest.s.nString = NUM_MINIMIZE_EFFECT; o = &as->opt[ANIM_SCREEN_OPTION_UNMINIMIZE_WINDOW_TYPE]; o->name = "unminimize_window_types"; o->group = N_("(Un)Minimize"); o->subGroup = N_("Unminimize"); o->advanced = False; o->shortDesc = N_("Window Types"); o->longDesc = N_("The window types that will be animated."); o->displayHints = ""; o->type = CompOptionTypeList; o->value.list.type = CompOptionTypeString; o->value.list.nValue = N_MINIMIZE_DEFAULT_WIN_TYPE; o->value.list.value = malloc(sizeof(CompOptionValue) * N_MINIMIZE_DEFAULT_WIN_TYPE); for (i = 0; i < N_MINIMIZE_DEFAULT_WIN_TYPE; i++) o->value.list.value[i].s = strdup(minimizeDefaultWinType[i]); o->rest.s.string = (char **)windowTypeString; o->rest.s.nString = nWindowTypeString; as->unminimizeWMask = compWindowTypeMaskFromStringList(&o->value); o = &as->opt[ANIM_SCREEN_OPTION_UNMINIMIZE_DURATION]; o->name = "unminimize_duration"; o->group = N_("(Un)Minimize"); o->subGroup = N_("Unminimize"); o->advanced = False; o->shortDesc = N_("Animation Duration"); o->longDesc = N_ ("The number of seconds that the Unminimize animation will last."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_UNMINIMIZE_DURATION_DEFAULT; o->rest.f.min = ANIM_UNMINIMIZE_DURATION_MIN; o->rest.f.max = ANIM_UNMINIMIZE_DURATION_MAX; o->rest.f.precision = ANIM_UNMINIMIZE_DURATION_PRECISION; INIT_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_UNMINIMIZE_RANDOM_EFFECTS, "unminimize", "(Un)Minimize", "Unminimize", NUM_MINIMIZE_EFFECT, minimizeEffectName); STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_UNMINIMIZE_RANDOM_EFFECTS, NUM_MINIMIZE_EFFECT, ANIM_UNMINIMIZE_DEFAULT, nUnminimizeRandomEffects, unminimizeRandomEffects, minimizeEffectName, minimizeEffectType); // Close 1 o = &as->opt[ANIM_SCREEN_OPTION_CLOSE1_EFFECT]; o->name = "close1_effect"; o->group = N_("Close"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Close #1 Animation"); o->longDesc = N_("The animation shown when closing a window."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(allEffectName[ANIM_CLOSE1_DEFAULT]); o->rest.s.string = closeEffectName; o->rest.s.nString = NUM_CLOSE_EFFECT; o = &as->opt[ANIM_SCREEN_OPTION_CLOSE1_WINDOW_TYPE]; o->name = "close1_window_types"; o->group = N_("Close"); o->subGroup = N_("Close #1"); o->advanced = False; o->shortDesc = N_("Window Types"); o->longDesc = N_("The window types that will be animated."); o->displayHints = ""; o->type = CompOptionTypeList; o->value.list.type = CompOptionTypeString; o->value.list.nValue = N_CLOSE1_DEFAULT_WIN_TYPE; o->value.list.value = malloc(sizeof(CompOptionValue) * N_CLOSE1_DEFAULT_WIN_TYPE); for (i = 0; i < N_CLOSE1_DEFAULT_WIN_TYPE; i++) o->value.list.value[i].s = strdup(close1DefaultWinType[i]); o->rest.s.string = (char **)windowTypeString; o->rest.s.nString = nWindowTypeString; as->close1WMask = compWindowTypeMaskFromStringList(&o->value); o = &as->opt[ANIM_SCREEN_OPTION_CLOSE1_DURATION]; o->name = "close1_duration"; o->group = N_("Close"); o->subGroup = N_("Close #1"); o->advanced = False; o->shortDesc = N_("Animation Duration"); o->longDesc = N_ ("The number of seconds that the Close #1 animation will last."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_CLOSE1_DURATION_DEFAULT; o->rest.f.min = ANIM_CLOSE1_DURATION_MIN; o->rest.f.max = ANIM_CLOSE1_DURATION_MAX; o->rest.f.precision = ANIM_CLOSE1_DURATION_PRECISION; INIT_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CLOSE1_RANDOM_EFFECTS, "close1", "Close", "Close #1", NUM_CLOSE_EFFECT, closeEffectName); STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CLOSE1_RANDOM_EFFECTS, NUM_CLOSE_EFFECT, ANIM_CLOSE1_DEFAULT, nClose1RandomEffects, close1RandomEffects, closeEffectName, closeEffectType); // Close 2 o = &as->opt[ANIM_SCREEN_OPTION_CLOSE2_EFFECT]; o->name = "close2_effect"; o->group = N_("Close"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Close #2 Animation"); o->longDesc = N_("The animation shown when closing a window."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(allEffectName[ANIM_CLOSE2_DEFAULT]); o->rest.s.string = closeEffectName; o->rest.s.nString = NUM_CLOSE_EFFECT; o = &as->opt[ANIM_SCREEN_OPTION_CLOSE2_WINDOW_TYPE]; o->name = "close2_window_types"; o->group = N_("Close"); o->subGroup = N_("Close #2"); o->advanced = False; o->shortDesc = N_("Window Types"); o->longDesc = N_("The window types that will be animated."); o->displayHints = ""; o->type = CompOptionTypeList; o->value.list.type = CompOptionTypeString; o->value.list.nValue = N_CLOSE2_DEFAULT_WIN_TYPE; o->value.list.value = malloc(sizeof(CompOptionValue) * N_CLOSE2_DEFAULT_WIN_TYPE); for (i = 0; i < N_CLOSE2_DEFAULT_WIN_TYPE; i++) o->value.list.value[i].s = strdup(close2DefaultWinType[i]); o->rest.s.string = (char **)windowTypeString; o->rest.s.nString = nWindowTypeString; as->close2WMask = compWindowTypeMaskFromStringList(&o->value); o = &as->opt[ANIM_SCREEN_OPTION_CLOSE2_DURATION]; o->name = "close2_duration"; o->group = N_("Close"); o->subGroup = N_("Close #2"); o->advanced = False; o->shortDesc = N_("Animation Duration"); o->longDesc = N_ ("The number of seconds that the Close #2 animation will last."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_CLOSE2_DURATION_DEFAULT; o->rest.f.min = ANIM_CLOSE2_DURATION_MIN; o->rest.f.max = ANIM_CLOSE2_DURATION_MAX; o->rest.f.precision = ANIM_CLOSE2_DURATION_PRECISION; INIT_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CLOSE2_RANDOM_EFFECTS, "close2", "Close", "Close #2", NUM_CLOSE_EFFECT, closeEffectName); STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CLOSE2_RANDOM_EFFECTS, NUM_CLOSE_EFFECT, ANIM_CLOSE2_DEFAULT, nClose2RandomEffects, close2RandomEffects, closeEffectName, closeEffectType); // Create 1 o = &as->opt[ANIM_SCREEN_OPTION_CREATE1_EFFECT]; o->name = "create1_effect"; o->group = N_("Create"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Create #1 Animation"); o->longDesc = N_("The animation shown when creating a window."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(allEffectName[ANIM_CREATE1_DEFAULT]); o->rest.s.string = closeEffectName; o->rest.s.nString = NUM_CLOSE_EFFECT; o = &as->opt[ANIM_SCREEN_OPTION_CREATE1_WINDOW_TYPE]; o->name = "create1_window_types"; o->group = N_("Create"); o->subGroup = N_("Create #1"); o->advanced = False; o->shortDesc = N_("Window Types"); o->longDesc = N_ ("Window types that should animate with this effect when created."); o->displayHints = ""; o->type = CompOptionTypeList; o->value.list.type = CompOptionTypeString; o->value.list.nValue = N_CLOSE1_DEFAULT_WIN_TYPE; o->value.list.value = malloc(sizeof(CompOptionValue) * N_CLOSE1_DEFAULT_WIN_TYPE); for (i = 0; i < N_CLOSE1_DEFAULT_WIN_TYPE; i++) o->value.list.value[i].s = strdup(close1DefaultWinType[i]); o->rest.s.string = (char **)windowTypeString; o->rest.s.nString = nWindowTypeString; as->create1WMask = compWindowTypeMaskFromStringList(&o->value); o = &as->opt[ANIM_SCREEN_OPTION_CREATE1_DURATION]; o->name = "create1_duration"; o->group = N_("Create"); o->subGroup = N_("Create #1"); o->advanced = False; o->shortDesc = N_("Animation Duration"); o->longDesc = N_("Animation duration in seconds for create effect #1."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_CREATE1_DURATION_DEFAULT; o->rest.f.min = ANIM_CREATE1_DURATION_MIN; o->rest.f.max = ANIM_CREATE1_DURATION_MAX; o->rest.f.precision = ANIM_CREATE1_DURATION_PRECISION; INIT_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CREATE1_RANDOM_EFFECTS, "create1", "Create", "Create #1", NUM_CLOSE_EFFECT, closeEffectName); STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CREATE1_RANDOM_EFFECTS, NUM_CLOSE_EFFECT, ANIM_CREATE1_DEFAULT, nCreate1RandomEffects, create1RandomEffects, closeEffectName, closeEffectType); // Create 2 o = &as->opt[ANIM_SCREEN_OPTION_CREATE2_EFFECT]; o->name = "create2_effect"; o->group = N_("Create"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Create #2 Animation"); o->longDesc = N_("The animation shown when creating a window."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(allEffectName[ANIM_CREATE2_DEFAULT]); o->rest.s.string = closeEffectName; o->rest.s.nString = NUM_CLOSE_EFFECT; o = &as->opt[ANIM_SCREEN_OPTION_CREATE2_WINDOW_TYPE]; o->name = "create2_window_types"; o->group = N_("Create"); o->subGroup = N_("Create #2"); o->advanced = False; o->shortDesc = N_("Window Types"); o->longDesc = N_ ("Window types that should animate with this effect when created."); o->displayHints = ""; o->type = CompOptionTypeList; o->value.list.type = CompOptionTypeString; o->value.list.nValue = N_CLOSE2_DEFAULT_WIN_TYPE; o->value.list.value = malloc(sizeof(CompOptionValue) * N_CLOSE2_DEFAULT_WIN_TYPE); for (i = 0; i < N_CLOSE2_DEFAULT_WIN_TYPE; i++) o->value.list.value[i].s = strdup(close2DefaultWinType[i]); o->rest.s.string = (char **)windowTypeString; o->rest.s.nString = nWindowTypeString; as->create2WMask = compWindowTypeMaskFromStringList(&o->value); o = &as->opt[ANIM_SCREEN_OPTION_CREATE2_DURATION]; o->name = "create2_duration"; o->group = N_("Create"); o->subGroup = N_("Create #2"); o->advanced = False; o->shortDesc = N_("Animation Duration"); o->longDesc = N_("Animation duration in seconds for create effect #2."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_CREATE2_DURATION_DEFAULT; o->rest.f.min = ANIM_CREATE2_DURATION_MIN; o->rest.f.max = ANIM_CREATE2_DURATION_MAX; o->rest.f.precision = ANIM_CREATE2_DURATION_PRECISION; INIT_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CREATE2_RANDOM_EFFECTS, "create2", "Create", "Create #2", NUM_CLOSE_EFFECT, closeEffectName); STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_CREATE2_RANDOM_EFFECTS, NUM_CLOSE_EFFECT, ANIM_CREATE2_DEFAULT, nCreate2RandomEffects, create2RandomEffects, closeEffectName, closeEffectType); // Focus o = &as->opt[ANIM_SCREEN_OPTION_FOCUS_EFFECT]; o->name = "focus_effect"; o->group = N_("Focus"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Animation"); o->longDesc = N_("Focus window effect."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(allEffectName[ANIM_FOCUS_DEFAULT]); o->rest.s.string = focusEffectName; o->rest.s.nString = NUM_FOCUS_EFFECT; o = &as->opt[ANIM_SCREEN_OPTION_FOCUS_WINDOW_TYPE]; o->name = "focus_window_types"; o->group = N_("Focus"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Window Types"); o->longDesc = N_ ("Window types that should animate with this effect when focused."); o->displayHints = ""; o->type = CompOptionTypeList; o->value.list.type = CompOptionTypeString; o->value.list.nValue = N_FOCUS_DEFAULT_WIN_TYPE; o->value.list.value = malloc(sizeof(CompOptionValue) * N_FOCUS_DEFAULT_WIN_TYPE); for (i = 0; i < N_FOCUS_DEFAULT_WIN_TYPE; i++) o->value.list.value[i].s = strdup(focusDefaultWinType[i]); o->rest.s.string = (char **)windowTypeString; o->rest.s.nString = nWindowTypeString; as->focusWMask = compWindowTypeMaskFromStringList(&o->value); o = &as->opt[ANIM_SCREEN_OPTION_FOCUS_DURATION]; o->name = "focus_duration"; o->group = N_("Focus"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Animation Duration"); o->longDesc = N_("Focus animation duration in seconds."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_FOCUS_DURATION_DEFAULT; o->rest.f.min = ANIM_FOCUS_DURATION_MIN; o->rest.f.max = ANIM_FOCUS_DURATION_MAX; o->rest.f.precision = ANIM_FOCUS_DURATION_PRECISION; // Shade o = &as->opt[ANIM_SCREEN_OPTION_SHADE_EFFECT]; o->name = "shade_effect"; o->group = N_("(Un)Shade"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Shade Animation"); o->longDesc = N_("Shade window effect."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(allEffectName[ANIM_SHADE_DEFAULT]); o->rest.s.string = shadeEffectName; o->rest.s.nString = NUM_SHADE_EFFECT; o = &as->opt[ANIM_SCREEN_OPTION_SHADE_WINDOW_TYPE]; o->name = "shade_window_types"; o->group = N_("(Un)Shade"); o->subGroup = N_("Shade"); o->advanced = False; o->shortDesc = N_("Window Types"); o->longDesc = N_ ("Window types that should animate with this effect when shaded."); o->displayHints = ""; o->type = CompOptionTypeList; o->value.list.type = CompOptionTypeString; o->value.list.nValue = N_SHADE_DEFAULT_WIN_TYPE; o->value.list.value = malloc(sizeof(CompOptionValue) * N_SHADE_DEFAULT_WIN_TYPE); for (i = 0; i < N_SHADE_DEFAULT_WIN_TYPE; i++) o->value.list.value[i].s = strdup(shadeDefaultWinType[i]); o->rest.s.string = (char **)windowTypeString; o->rest.s.nString = nWindowTypeString; as->shadeWMask = compWindowTypeMaskFromStringList(&o->value); o = &as->opt[ANIM_SCREEN_OPTION_SHADE_DURATION]; o->name = "shade_duration"; o->group = N_("(Un)Shade"); o->subGroup = N_("Shade"); o->advanced = False; o->shortDesc = N_("Animation Duration"); o->longDesc = N_("Shade animation duration in seconds."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_SHADE_DURATION_DEFAULT; o->rest.f.min = ANIM_SHADE_DURATION_MIN; o->rest.f.max = ANIM_SHADE_DURATION_MAX; o->rest.f.precision = ANIM_SHADE_DURATION_PRECISION; INIT_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_SHADE_RANDOM_EFFECTS, "shade", "(Un)Shade", "Shade", NUM_SHADE_EFFECT, shadeEffectName); STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_SHADE_RANDOM_EFFECTS, NUM_SHADE_EFFECT, ANIM_SHADE_DEFAULT, nShadeRandomEffects, shadeRandomEffects, shadeEffectName, shadeEffectType); // Unshade o = &as->opt[ANIM_SCREEN_OPTION_UNSHADE_EFFECT]; o->name = "unshade_effect"; o->group = N_("(Un)Shade"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Unshade Animation"); o->longDesc = N_("Unshade window effect."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(allEffectName[ANIM_UNSHADE_DEFAULT]); o->rest.s.string = shadeEffectName; o->rest.s.nString = NUM_SHADE_EFFECT; o = &as->opt[ANIM_SCREEN_OPTION_UNSHADE_WINDOW_TYPE]; o->name = "unshade_window_types"; o->group = N_("(Un)Shade"); o->subGroup = N_("Unshade"); o->advanced = False; o->shortDesc = N_("Window Types"); o->longDesc = N_ ("Window types that should animate with this effect when unshaded."); o->displayHints = ""; o->type = CompOptionTypeList; o->value.list.type = CompOptionTypeString; o->value.list.nValue = N_SHADE_DEFAULT_WIN_TYPE; o->value.list.value = malloc(sizeof(CompOptionValue) * N_SHADE_DEFAULT_WIN_TYPE); for (i = 0; i < N_SHADE_DEFAULT_WIN_TYPE; i++) o->value.list.value[i].s = strdup(shadeDefaultWinType[i]); o->rest.s.string = (char **)windowTypeString; o->rest.s.nString = nWindowTypeString; as->unshadeWMask = compWindowTypeMaskFromStringList(&o->value); o = &as->opt[ANIM_SCREEN_OPTION_UNSHADE_DURATION]; o->name = "unshade_duration"; o->group = N_("(Un)Shade"); o->subGroup = N_("Unshade"); o->advanced = False; o->shortDesc = N_("Animation Duration"); o->longDesc = N_("Unshade animation duration in seconds."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_UNSHADE_DURATION_DEFAULT; o->rest.f.min = ANIM_UNSHADE_DURATION_MIN; o->rest.f.max = ANIM_UNSHADE_DURATION_MAX; o->rest.f.precision = ANIM_UNSHADE_DURATION_PRECISION; INIT_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_UNSHADE_RANDOM_EFFECTS, "unshade", "(Un)Shade", "Unshade", NUM_SHADE_EFFECT, shadeEffectName); STORE_RANDOM_EFFECT_LIST (ANIM_SCREEN_OPTION_UNSHADE_RANDOM_EFFECTS, NUM_SHADE_EFFECT, ANIM_UNSHADE_DEFAULT, nUnshadeRandomEffects, unshadeRandomEffects, shadeEffectName, shadeEffectType); // Fire (Burn) o = &as->opt[ANIM_SCREEN_OPTION_FIRE_PARTICLES]; o->name = "fire_particles"; o->group = N_("Fire (A.K.A Burn)"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Number Of Fire Particles"); o->longDesc = N_("Number of fire particles."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_FIRE_PARTICLES_DEFAULT; o->rest.i.min = ANIM_FIRE_PARTICLES_MIN; o->rest.i.max = ANIM_FIRE_PARTICLES_MAX; o = &as->opt[ANIM_SCREEN_OPTION_FIRE_SIZE]; o->name = "fire_size"; o->group = N_("Fire (A.K.A Burn)"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Fire Particle Size"); o->longDesc = N_("Fire particle size."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_FIRE_SIZE_DEFAULT; o->rest.f.min = ANIM_FIRE_SIZE_MIN; o->rest.f.max = ANIM_FIRE_SIZE_MAX; o->rest.f.precision = ANIM_FIRE_SIZE_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_FIRE_SLOWDOWN]; o->name = "fire_slowdown"; o->group = N_("Fire (A.K.A Burn)"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Fire Particle Slowdown"); o->longDesc = N_("Fire particle slowdown."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_FIRE_SLOWDOWN_DEFAULT; o->rest.f.min = ANIM_FIRE_SLOWDOWN_MIN; o->rest.f.max = ANIM_FIRE_SLOWDOWN_MAX; o->rest.f.precision = ANIM_FIRE_SLOWDOWN_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_FIRE_LIFE]; o->name = "fire_life"; o->group = N_("Fire (A.K.A Burn)"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Fire Particle Life"); o->longDesc = N_("Fire particle life."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_FIRE_LIFE_DEFAULT; o->rest.f.min = ANIM_FIRE_LIFE_MIN; o->rest.f.max = ANIM_FIRE_LIFE_MAX; o->rest.f.precision = ANIM_FIRE_LIFE_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_FIRE_COLOR]; o->name = "fire_color"; o->group = N_("Fire (A.K.A Burn)"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Fire Particle Color"); o->longDesc = N_("Fire particle color."); o->displayHints = ""; o->type = CompOptionTypeColor; o->value.c[0] = ANIM_FIRE_COLOR_RED_DEFAULT; o->value.c[1] = ANIM_FIRE_COLOR_GREEN_DEFAULT; o->value.c[2] = ANIM_FIRE_COLOR_BLUE_DEFAULT; o->value.c[3] = ANIM_FIRE_COLOR_ALPHA_DEFAULT; o = &as->opt[ANIM_SCREEN_OPTION_FIRE_DIRECTION]; o->name = "fire_direction"; o->group = N_("Fire (A.K.A Burn)"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Fire direction"); o->longDesc = N_("Fire direction."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(animDirectionName[ANIM_FIRE_DIRECTION_DEFAULT]); o->rest.s.string = animDirectionName; o->rest.s.nString = LIST_SIZE(animDirectionName); o = &as->opt[ANIM_SCREEN_OPTION_FIRE_CONSTANT_SPEED]; o->name = "fire_constant_speed"; o->group = N_("Fire (A.K.A Burn)"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Fire constant speed"); o->longDesc = N_("Make fire effect duration be dependent on window height."); o->displayHints = ""; o->type = CompOptionTypeBool; o->value.b = ANIM_FIRE_CONSTANT_SPEED_DEFAULT; o = &as->opt[ANIM_SCREEN_OPTION_FIRE_SMOKE]; o->name = "fire_smoke"; o->group = N_("Fire (A.K.A Burn)"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Fire Smoke"); o->longDesc = N_("Fire smoke."); o->displayHints = ""; o->type = CompOptionTypeBool; o->value.b = ANIM_FIRE_SMOKE_DEFAULT; o = &as->opt[ANIM_SCREEN_OPTION_FIRE_MYSTICAL]; o->name = "fire_mystical"; o->group = N_("Fire (A.K.A Burn)"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Randomly Colored Fire"); o->longDesc = N_ ("Have random colors for the fire effect, also known as Mystical Fire."); o->displayHints = ""; o->type = CompOptionTypeBool; o->value.b = ANIM_FIRE_MYSTICAL_DEFAULT; // Beam Up o = &as->opt[ANIM_SCREEN_OPTION_BEAMUP_SIZE]; o->name = "beam_size"; o->group = N_("Beam"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Beam Width"); o->longDesc = N_("Beam width."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_BEAMUP_SIZE_DEFAULT; o->rest.f.min = ANIM_BEAMUP_SIZE_MIN; o->rest.f.max = ANIM_BEAMUP_SIZE_MAX; o->rest.f.precision = ANIM_BEAMUP_SIZE_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_BEAMUP_SPACING]; o->name = "beam_spacing"; o->group = N_("Beam"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Beam spacing"); o->longDesc = N_("Spacing between beams."); o->displayHints = ""; o->type = CompOptionTypeInt; o->value.i = ANIM_BEAMUP_SPACING_DEFAULT; o->rest.i.min = ANIM_BEAMUP_SPACING_MIN; o->rest.i.max = ANIM_BEAMUP_SPACING_MAX; o = &as->opt[ANIM_SCREEN_OPTION_BEAMUP_COLOR]; o->name = "beam_color"; o->group = N_("Beam"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Beam Color"); o->longDesc = N_("Beam color."); o->displayHints = ""; o->type = CompOptionTypeColor; o->value.c[0] = ANIM_BEAMUP_COLOR_RED_DEFAULT; o->value.c[1] = ANIM_BEAMUP_COLOR_GREEN_DEFAULT; o->value.c[2] = ANIM_BEAMUP_COLOR_BLUE_DEFAULT; o->value.c[3] = ANIM_BEAMUP_COLOR_ALPHA_DEFAULT; o = &as->opt[ANIM_SCREEN_OPTION_BEAMUP_SLOWDOWN]; o->name = "beam_slowdown"; o->group = N_("Beam"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Beam Slowdown"); o->longDesc = N_("Beam slowdown."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_BEAMUP_SLOWDOWN_DEFAULT; o->rest.f.min = ANIM_BEAMUP_SLOWDOWN_MIN; o->rest.f.max = ANIM_BEAMUP_SLOWDOWN_MAX; o->rest.f.precision = ANIM_BEAMUP_SLOWDOWN_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_BEAMUP_LIFE]; o->name = "beam_life"; o->group = N_("Beam"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Beam Life"); o->longDesc = N_("Beam life."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_BEAMUP_LIFE_DEFAULT; o->rest.f.min = ANIM_BEAMUP_LIFE_MIN; o->rest.f.max = ANIM_BEAMUP_LIFE_MAX; o->rest.f.precision = ANIM_BEAMUP_LIFE_PRECISION; // Domino / Razr o = &as->opt[ANIM_SCREEN_OPTION_DOMINO_DIRECTION]; o->name = "domino_direction"; o->group = N_("Domino/Razr"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Domino Piece Falling Direction"); o->longDesc = N_("Falling direction for Domino pieces."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(animDirectionName[ANIM_DOMINO_DIRECTION_DEFAULT]); o->rest.s.string = animDirectionName; o->rest.s.nString = LIST_SIZE(animDirectionName); o = &as->opt[ANIM_SCREEN_OPTION_RAZR_DIRECTION]; o->name = "razr_direction"; o->group = N_("Domino/Razr"); o->subGroup = N_(""); o->advanced = False; o->shortDesc = N_("Razr Fold Opening Direction"); o->longDesc = N_("Fold opening direction for pieces in Razr effect."); o->displayHints = ""; o->type = CompOptionTypeString; o->value.s = strdup(animDirectionName[ANIM_RAZR_DIRECTION_DEFAULT]); o->rest.s.string = animDirectionName; o->rest.s.nString = LIST_SIZE(animDirectionName); // Glide 1 o = &as->opt[ANIM_SCREEN_OPTION_GLIDE1_AWAY_POS]; o->name = "glide1_away_position"; o->group = N_("Glide"); o->subGroup = N_("Glide 1"); o->advanced = False; o->shortDesc = N_("Away Position"); o->longDesc = N_("Closeness of window to camera at the end of the " "animation " "(1.0: Close to camera, -2.0: Away from camera)."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_GLIDE1_AWAY_POS_DEFAULT; o->rest.f.min = ANIM_GLIDE1_AWAY_POS_MIN; o->rest.f.max = ANIM_GLIDE1_AWAY_POS_MAX; o->rest.f.precision = ANIM_GLIDE1_AWAY_POS_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_GLIDE1_AWAY_ANGLE]; o->name = "glide1_away_angle"; o->group = N_("Glide"); o->subGroup = N_("Glide 1"); o->advanced = False; o->shortDesc = N_("Away Angle"); o->longDesc = N_("Angle of window at the end of the animation."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_GLIDE1_AWAY_ANGLE_DEFAULT; o->rest.f.min = ANIM_GLIDE1_AWAY_ANGLE_MIN; o->rest.f.max = ANIM_GLIDE1_AWAY_ANGLE_MAX; o->rest.f.precision = ANIM_GLIDE1_AWAY_ANGLE_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_GLIDE1_THICKNESS]; o->name = "glide1_thickness"; o->group = N_("Glide"); o->subGroup = N_("Glide 1"); o->advanced = False; o->shortDesc = N_("Thickness"); o->longDesc = N_("Window thickness in pixels. Setting this to larger " "than 0 will disable shadow, blur, and reflection " "during the animation."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_GLIDE1_THICKNESS_DEFAULT; o->rest.f.min = ANIM_GLIDE1_THICKNESS_MIN; o->rest.f.max = ANIM_GLIDE1_THICKNESS_MAX; o->rest.f.precision = ANIM_GLIDE1_THICKNESS_PRECISION; // Glide 2 o = &as->opt[ANIM_SCREEN_OPTION_GLIDE2_AWAY_POS]; o->name = "glide2_away_position"; o->group = N_("Glide"); o->subGroup = N_("Glide 2"); o->advanced = False; o->shortDesc = N_("Away Position"); o->longDesc = N_("Closeness of window to camera at the end of the " "animation " "(1.0: Close to camera, -2.0: Away from camera)."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_GLIDE2_AWAY_POS_DEFAULT; o->rest.f.min = ANIM_GLIDE2_AWAY_POS_MIN; o->rest.f.max = ANIM_GLIDE2_AWAY_POS_MAX; o->rest.f.precision = ANIM_GLIDE2_AWAY_POS_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_GLIDE2_AWAY_ANGLE]; o->name = "glide2_away_angle"; o->group = N_("Glide"); o->subGroup = N_("Glide 2"); o->advanced = False; o->shortDesc = N_("Away Angle"); o->longDesc = N_("Angle of window at the end of the animation."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_GLIDE2_AWAY_ANGLE_DEFAULT; o->rest.f.min = ANIM_GLIDE2_AWAY_ANGLE_MIN; o->rest.f.max = ANIM_GLIDE2_AWAY_ANGLE_MAX; o->rest.f.precision = ANIM_GLIDE2_AWAY_ANGLE_PRECISION; o = &as->opt[ANIM_SCREEN_OPTION_GLIDE2_THICKNESS]; o->name = "glide2_thickness"; o->group = N_("Glide"); o->subGroup = N_("Glide 2"); o->advanced = False; o->shortDesc = N_("Thickness"); o->longDesc = N_("Window thickness in pixels. Setting this to larger " "than 0 will disable shadow, blur, and reflection " "during the animation."); o->displayHints = ""; o->type = CompOptionTypeFloat; o->value.f = ANIM_GLIDE2_THICKNESS_DEFAULT; o->rest.f.min = ANIM_GLIDE2_THICKNESS_MIN; o->rest.f.max = ANIM_GLIDE2_THICKNESS_MAX; o->rest.f.precision = ANIM_GLIDE2_THICKNESS_PRECISION; } static CompOption *animGetScreenOptions(CompScreen * screen, int *count) { if (screen) { ANIM_SCREEN(screen); *count = NUM_OPTIONS(as); return as->opt; } else { AnimScreen *as = calloc(1, sizeof(AnimScreen)); animScreenInitOptions(as); *count = NUM_OPTIONS(as); return as->opt; } } static void objectInit(Object * object, float positionX, float positionY, float gridPositionX, float gridPositionY) { object->gridPosition.x = gridPositionX; object->gridPosition.y = gridPositionY; object->position.x = positionX; object->position.y = positionY; object->offsetTexCoordForQuadBefore.x = 0; object->offsetTexCoordForQuadBefore.y = 0; object->offsetTexCoordForQuadAfter.x = 0; object->offsetTexCoordForQuadAfter.y = 0; } static void modelInitObjects(Model * model, int x, int y, int width, int height) { int gridX, gridY; int nGridCellsX, nGridCellsY; float x0, y0; x0 = model->scaleOrigin.x; y0 = model->scaleOrigin.y; // number of grid cells in x direction nGridCellsX = model->gridWidth - 1; if (model->forWindowEvent == WindowEventShade || model->forWindowEvent == WindowEventUnshade) { // number of grid cells in y direction nGridCellsY = model->gridHeight - 3; // One allocated for top, one for bottom float winContentsHeight = height - model->topHeight - model->bottomHeight; //Top float objectY = y + (0 - y0) * model->scale.y + y0; for (gridX = 0; gridX < model->gridWidth; gridX++) { objectInit(&model->objects[gridX], x + ((gridX * width / nGridCellsX) - x0) * model->scale.x + x0, objectY, (float)gridX / nGridCellsX, 0); } // Window contents for (gridY = 1; gridY < model->gridHeight - 1; gridY++) { float inWinY = (gridY - 1) * winContentsHeight / nGridCellsY + model->topHeight; float gridPosY = inWinY / height; objectY = y + (inWinY - y0) * model->scale.y + y0; for (gridX = 0; gridX < model->gridWidth; gridX++) { objectInit(&model-> objects[gridY * model->gridWidth + gridX], x + ((gridX * width / nGridCellsX) - x0) * model->scale.x + x0, objectY, (float)gridX / nGridCellsX, gridPosY); } } // Bottom (gridY is model->gridHeight-1 now) objectY = y + (height - y0) * model->scale.y + y0; for (gridX = 0; gridX < model->gridWidth; gridX++) { objectInit(&model-> objects[gridY * model->gridWidth + gridX], x + ((gridX * width / nGridCellsX) - x0) * model->scale.x + x0, objectY, (float)gridX / nGridCellsX, 1); } } else { // number of grid cells in y direction nGridCellsY = model->gridHeight - 1; int i = 0; for (gridY = 0; gridY < model->gridHeight; gridY++) { float objectY = y + ((gridY * height / nGridCellsY) - y0) * model->scale.y + y0; for (gridX = 0; gridX < model->gridWidth; gridX++) { objectInit(&model->objects[i], x + ((gridX * width / nGridCellsX) - x0) * model->scale.x + x0, objectY, (float)gridX / nGridCellsX, (float)gridY / nGridCellsY); i++; } } } } static Model *createModel(CompWindow * w, WindowEvent forWindowEvent, AnimEffect forAnimEffect, int gridWidth, int gridHeight) { int x = WIN_X(w); int y = WIN_Y(w); int width = WIN_W(w); int height = WIN_H(w); Model *model; model = calloc(1, sizeof(Model)); if (!model) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); return 0; } model->magicLampWaveCount = 0; model->magicLampWaves = NULL; model->gridWidth = gridWidth; model->gridHeight = gridHeight; model->numObjects = gridWidth * gridHeight; model->objects = calloc(1, sizeof(Object) * model->numObjects); if (!model->objects) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); free(model); return 0; } // Store win. size to check later model->winWidth = width; model->winHeight = height; // For shading model->forWindowEvent = forWindowEvent; model->topHeight = w->output.top; model->bottomHeight = w->output.bottom; model->remainderSteps = 0; model->scale.x = 1.0f; model->scale.y = 1.0f; model->scaleOrigin.x = 0.0f; model->scaleOrigin.y = 0.0f; modelInitObjects(model, x, y, width, height); modelCalcBounds(model); return model; } static Bool animEnsureModel(CompWindow * w, WindowEvent forWindowEvent, AnimEffect forAnimEffect) { ANIM_WINDOW(w); ANIM_SCREEN(w->screen); int gridWidth = 2; int gridHeight = 2; if (animEffectProperties[forAnimEffect].initGridFunc) animEffectProperties[forAnimEffect].initGridFunc(as, forWindowEvent, &gridWidth, &gridHeight); Bool isShadeUnshadeEvent = (forWindowEvent == WindowEventShade || forWindowEvent == WindowEventUnshade); Bool wasShadeUnshadeEvent = aw->model && (aw->model->forWindowEvent == WindowEventShade || aw->model->forWindowEvent == WindowEventUnshade); if (!aw->model || gridWidth != aw->model->gridWidth || gridHeight != aw->model->gridHeight || (isShadeUnshadeEvent != wasShadeUnshadeEvent) || aw->model->winWidth != WIN_W(w) || aw->model->winHeight != WIN_H(w)) { if (aw->model) { if (aw->model->magicLampWaves) free(aw->model->magicLampWaves); free(aw->model->objects); free(aw->model); } aw->model = createModel(w, forWindowEvent, forAnimEffect, gridWidth, gridHeight); if (!aw->model) return FALSE; } return TRUE; } static Bool playingPolygonEffect(AnimScreen *as, AnimWindow *aw) { if (!animEffectProperties[aw->curAnimEffect]. addCustomGeometryFunc) return FALSE; if (!(aw->curAnimEffect == AnimEffectGlide3D1 || aw->curAnimEffect == AnimEffectGlide3D2)) return TRUE; float finalDistFac; float finalRotAng; float thickness; fxGlideGetParams(as, aw, &finalDistFac, &finalRotAng, &thickness); return (thickness > 1e-5); // glide is 3D if thickness > 0 } static void postAnimationCleanup(CompWindow * w, Bool resetAnimation) { ANIM_WINDOW(w); ANIM_SCREEN(w->screen); IPCS_SetBool(IPCS_OBJECT(w), aw->animatedAtom, FALSE); if (resetAnimation) { // if 3d polygon fx if (playingPolygonEffect(as, aw)) { IPCS_SetBoolN(IPCS_OBJECT(w), "DISABLE_BLUR", FALSE); IPCS_SetBoolN(IPCS_OBJECT(w), "DISABLE_REFLECTION", FALSE); } if (as->ppDisabling == PostprocessDisablingWindow) IPCS_SetBoolN(IPCS_OBJECT(w), "DISABLE_BLUR", FALSE); if (!(as->animInProgress) && as->ppDisabling == PostprocessDisablingScreen) IPCS_SetBoolN(IPCS_OBJECT(w->screen), "DISABLE_BLUR", FALSE); aw->curWindowEvent = WindowEventNone; aw->curAnimEffect = AnimEffectNone; aw->animOverrideProgressDir = 0; if (aw->model) { if (aw->model->magicLampWaves) free(aw->model->magicLampWaves); aw->model->magicLampWaves = 0; } } aw->state = aw->newState; if (aw->drawRegion) XDestroyRegion(aw->drawRegion); aw->drawRegion = NULL; aw->useDrawRegion = FALSE; if (aw->numPs) { int i = 0; for (i = 0; i < aw->numPs; i++) { free(aw->ps[i].particles); if (aw->ps[i].tex) glDeleteTextures(1, &aw->ps[i].tex); } free(aw->ps); aw->ps = NULL; aw->numPs = 0; } if (aw->polygonSet) { freePolygonSet(aw); //aw->polygonSet->nClips = 0; } aw->animInitialized = FALSE; //if (aw->unmapCnt || aw->destroyCnt) // releaseWindow (w); while (aw->unmapCnt) { unmapWindow(w); aw->unmapCnt--; } while (aw->destroyCnt) { destroyWindow(w); aw->destroyCnt--; } } static void animPreparePaintScreen(CompScreen * s, int msSinceLastPaint) { CompWindow *w; ANIM_SCREEN(s); if (as->animInProgress) { AnimWindow *aw; BoxRec box; Point topLeft, bottomRight; if (as->ppDisabling == PostprocessDisablingScreen) IPCS_SetBoolN(IPCS_OBJECT(s), "DISABLE_BLUR", TRUE); else IPCS_SetBoolN(IPCS_OBJECT(s), "DISABLE_BLUR", FALSE); as->animInProgress = FALSE; for (w = s->windows; w; w = w->next) { aw = GET_ANIM_WINDOW(w, as); if (aw->numPs) { int i = 0; for (i = 0; i < aw->numPs; i++) { if (aw->ps[i].active) { updateParticles(&aw->ps[i], msSinceLastPaint); as->animInProgress = TRUE; } } } if (aw->animRemainingTime > 0) { if (!aw->animInitialized) // if animation is just starting { aw->subEffectNo = animEffectProperties[aw->curAnimEffect]. subEffectNo; aw->deceleratingMotion = animEffectProperties[aw->curAnimEffect]. animStepPolygonFunc == polygonsDeceleratingAnimStepPolygon; if (playingPolygonEffect(as, aw)) { // Allocate polygon set if null if (!aw->polygonSet) { //printf("calloc aw->polygonSet\n"); aw->polygonSet = calloc(1, sizeof(PolygonSet)); } if (!aw->polygonSet) { fprintf(stderr, "%s: Not enough memory at line %d!\n", __FILE__, __LINE__); return; } aw->polygonSet->allFadeDuration = -1.0f; } } //aw->drawCount = 0; //printf("aw->drawCount init: %d\n", aw->drawCount); if (as->ppDisabling == PostprocessDisablingWindow) IPCS_SetBoolN(IPCS_OBJECT(w), "DISABLE_BLUR", TRUE); else IPCS_SetBoolN(IPCS_OBJECT(w), "DISABLE_BLUR", FALSE); // if 3d polygon fx if (playingPolygonEffect(as, aw)) { aw->nClipsPassed = 0; aw->clipsUpdated = FALSE; IPCS_SetBoolN(IPCS_OBJECT(w), "DISABLE_BLUR", TRUE); IPCS_SetBoolN(IPCS_OBJECT(w), "DISABLE_REFLECTION", TRUE); } if (aw->model) { topLeft = aw->model->topLeft; bottomRight = aw->model->bottomRight; // If just starting, call fx init func. if (!aw->animInitialized && animEffectProperties[aw->curAnimEffect].initFunc) animEffectProperties[aw-> curAnimEffect].initFunc(s, w); aw->animInitialized = TRUE; if (aw->model->winWidth != WIN_W(w) || aw->model->winHeight != WIN_H(w)) { // model needs update // keep this value float remainderSteps = aw->model->remainderSteps; // re-create model animEnsureModel (w, aw->curWindowEvent, aw->curAnimEffect); if (aw->model == 0) continue; // skip this window aw->model->remainderSteps = remainderSteps; } // Call fx step func. if (animEffectProperties[aw->curAnimEffect].animStepFunc) { animEffectProperties[aw-> curAnimEffect]. animStepFunc(s, w, msSinceLastPaint); } if (aw->animRemainingTime <= 0) { // Animation done postAnimationCleanup(w, TRUE); } if (!(s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)) { if (aw->animRemainingTime > 0) { if (aw->model->topLeft.x < topLeft.x) topLeft.x = aw->model->topLeft.x; if (aw->model->topLeft.y < topLeft.y) topLeft.y = aw->model->topLeft.y; if (aw->model->bottomRight.x > bottomRight.x) bottomRight.x = aw->model->bottomRight.x; if (aw->model->bottomRight.y > bottomRight.y) bottomRight.y = aw->model->bottomRight.y; } else addWindowDamage(w); box.x1 = topLeft.x; box.y1 = topLeft.y; box.x2 = bottomRight.x + 0.5f; box.y2 = bottomRight.y + 0.5f; box.x1 -= w->attrib.x + w->attrib.border_width; box.y1 -= w->attrib.y + w->attrib.border_width; box.x2 -= w->attrib.x + w->attrib.border_width; box.y2 -= w->attrib.y + w->attrib.border_width; addWindowDamageRect(w, &box); } } as->animInProgress |= (aw->animRemainingTime > 0); } if (aw->animRemainingTime <= 0) { if (aw->curAnimEffect != AnimEffectNone || aw->unmapCnt > 0 || aw->destroyCnt > 0) postAnimationCleanup(w, TRUE); aw->curWindowEvent = WindowEventNone; aw->curAnimEffect = AnimEffectNone; } } } UNWRAP(as, s, preparePaintScreen); (*s->preparePaintScreen) (s, msSinceLastPaint); WRAP(as, s, preparePaintScreen, animPreparePaintScreen); } static void animDonePaintScreen(CompScreen * s) { ANIM_SCREEN(s); if (as->animInProgress) { damageScreen(s); } if (!(as->animInProgress) && as->ppDisabling == PostprocessDisablingScreen) IPCS_SetBoolN(IPCS_OBJECT(s), "DISABLE_BLUR", FALSE); UNWRAP(as, s, donePaintScreen); (*s->donePaintScreen) (s); WRAP(as, s, donePaintScreen, animDonePaintScreen); } static void animAddWindowGeometry(CompWindow * w, CompMatrix * matrix, int nMatrix, Region region, Region clip) { ANIM_WINDOW(w); ANIM_SCREEN(w->screen); // if model is lost during animation (e.g. when plugin just reloaded) if (aw->animRemainingTime > 0 && !aw->model) { aw->animRemainingTime = 0; postAnimationCleanup(w, TRUE); } // if window is being animated if (aw->animRemainingTime > 0 && aw->model) { BoxPtr pClip; int nClip; int nVertices, nIndices; GLushort *i; GLfloat *v; int x1, y1, x2, y2; float width, height; float winContentsY, winContentsHeight; float deformedX, deformedY; int nVertX, nVertY, wx, wy; int vSize, it; float gridW, gridH, x, y; Bool rect = TRUE; Bool useTextureQ = TRUE; Model *model = aw->model; Region awRegion = NULL; // Use Q texture coordinate to avoid jagged-looking quads // http://www.r3.nu/~cass/qcoord/ if (animEffectProperties[aw->curAnimEffect].dontUseQTexCoord) useTextureQ = FALSE; if (aw->useDrawRegion) { awRegion = XCreateRegion(); XOffsetRegion(aw->drawRegion, WIN_X(w), WIN_Y(w)); XIntersectRegion(region, aw->drawRegion, awRegion); XOffsetRegion(aw->drawRegion, -WIN_X(w), -WIN_Y(w)); nClip = awRegion->numRects; pClip = awRegion->rects; } else { nClip = region->numRects; pClip = region->rects; } if (nClip == 0) // nothing to do { if (awRegion) XDestroyRegion(awRegion); return; } for (it = 0; it < nMatrix; it++) { if (matrix[it].xy != 0.0f || matrix[it].yx != 0.0f) { rect = FALSE; break; } } if (aw->polygonSet && animEffectProperties[aw->curAnimEffect].addCustomGeometryFunc) { /*int nClip2 = nClip; BoxPtr pClip2 = pClip; // For each clip passed to this function for (; nClip2--; pClip2++) { x1 = pClip2->x1; y1 = pClip2->y1; x2 = pClip2->x2; y2 = pClip2->y2; printf("x1: %4d, y1: %4d, x2: %4d, y2: %4d", x1, y1, x2, y2); printf("\tm: %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n", matrix[0].xx, matrix[0].xy, matrix[0].yx, matrix[0].yy, matrix[0].x0, matrix[0].y0); } */ animEffectProperties[aw->curAnimEffect]. addCustomGeometryFunc(w->screen, w, nClip, pClip, nMatrix, matrix); // If addGeometryFunc exists, it is expected to do everthing // to add geometries (instead of the rest of this function). if (w->vCount == 0) // if there is no vertex { // put a dummy quad in vertices and indices if (4 > w->indexSize) { if (!moreWindowIndices(w, 4)) return; } if (4 > w->vertexSize) { if (!moreWindowVertices(w, 4)) return; } w->vCount = 4; w->indexCount = 4; w->texUnits = 1; memset(w->vertices, 0, sizeof(GLfloat) * 4); memset(w->indices, 0, sizeof(GLushort) * 4); } return; // We're done here. } // window coordinates and size wx = WIN_X(w); wy = WIN_Y(w); width = WIN_W(w); height = WIN_H(w); // to be used if event is shade/unshade winContentsY = w->attrib.y; winContentsHeight = w->height; w->texUnits = nMatrix; if (w->vCount == 0) { // reset w->indexCount = 0; w->texCoordSize = 4; } vSize = 2 + w->texUnits * w->texCoordSize; nVertices = w->vCount; nIndices = w->indexCount; v = w->vertices + (nVertices * vSize); i = w->indices + nIndices; // For each clip passed to this function for (; nClip--; pClip++) { x1 = pClip->x1; y1 = pClip->y1; x2 = pClip->x2; y2 = pClip->y2; /* printf("x1: %4d, y1: %4d, x2: %4d, y2: %4d", x1, y1, x2, y2); printf("\tm: %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n", matrix[0].xx, matrix[0].xy, matrix[0].yx, matrix[0].yy, matrix[0].x0, matrix[0].y0); */ gridW = (float)width / (model->gridWidth - 1); if (aw->curWindowEvent == WindowEventShade || aw->curWindowEvent == WindowEventUnshade) { if (y1 < w->attrib.y) // if at top part { gridH = model->topHeight; } else if (y2 > w->attrib.y + w->height) // if at bottom { gridH = model->bottomHeight; } else // in window contents (only in Y coords) { float winContentsHeight = height - model->topHeight - model->bottomHeight; gridH = winContentsHeight / (model->gridHeight - 3); } } else gridH = (float)height / (model->gridHeight - 1); // nVertX, nVertY: number of vertices for this clip in x and y dimensions // + 2 to avoid running short of vertices in some cases nVertX = ceil((x2 - x1) / gridW) + 2; nVertY = (gridH ? ceil((y2 - y1) / gridH) : 0) + 2; // Allocate 4 indices for each quad int newIndexSize = nIndices + ((nVertX - 1) * (nVertY - 1) * 4); if (newIndexSize > w->indexSize) { if (!moreWindowIndices(w, newIndexSize)) return; i = w->indices + nIndices; } // Assign quad vertices to indices int jx, jy; for (jy = 0; jy < nVertY - 1; jy++) { for (jx = 0; jx < nVertX - 1; jx++) { *i++ = nVertices + nVertX * (2 * jy + 1) + jx; *i++ = nVertices + nVertX * (2 * jy + 1) + jx + 1; *i++ = nVertices + nVertX * 2 * jy + jx + 1; *i++ = nVertices + nVertX * 2 * jy + jx; nIndices += 4; } } // Allocate vertices int newVertexSize = (nVertices + nVertX * (2 * nVertY - 2)) * vSize; if (newVertexSize > w->vertexSize) { if (!moreWindowVertices(w, newVertexSize)) return; v = w->vertices + (nVertices * vSize); } float rowTexCoordQ = 1; float prevRowCellWidth = 0; // this initial value won't be used float rowCellWidth = 0; // For each vertex for (jy = 0, y = y1; jy < nVertY; jy++) { if (y > y2) y = y2; // Do calculations for y here to avoid repeating // them unnecessarily in the x loop float topiyFloat; Bool applyOffsets = TRUE; if (aw->curWindowEvent == WindowEventShade || aw->curWindowEvent == WindowEventUnshade) { if (y1 < w->attrib.y) // if at top part { topiyFloat = (y - WIN_Y(w)) / model->topHeight; topiyFloat = MIN(topiyFloat, 0.999); // avoid 1.0 applyOffsets = FALSE; } else if (y2 > w->attrib.y + w->height) // if at bottom { topiyFloat = (model->gridHeight - 2) + (model-> bottomHeight ? (y - winContentsY - winContentsHeight) / model->bottomHeight : 0); applyOffsets = FALSE; } else // in window contents (only in Y coords) { topiyFloat = (model->gridHeight - 3) * (y - winContentsY) / winContentsHeight + 1; } } else { topiyFloat = (model->gridHeight - 1) * (y - wy) / height; } // topiy should be at most (model->gridHeight - 2) int topiy = (int)(topiyFloat + 1e-4); if (topiy == model->gridHeight - 1) topiy--; int bottomiy = topiy + 1; float iny = topiyFloat - topiy; // End of calculations for y for (jx = 0, x = x1; jx < nVertX; jx++) { if (x > x2) x = x2; // find containing grid cell (leftix rightix) x (topiy bottomiy) float leftixFloat = (model->gridWidth - 1) * (x - wx) / width; int leftix = (int)(leftixFloat + 1e-4); if (leftix == model->gridWidth - 1) leftix--; int rightix = leftix + 1; // Objects that are at top, bottom, left, right corners of quad Object *objToTopLeft = &(model-> objects[topiy * model->gridWidth + leftix]); Object *objToTopRight = &(model-> objects[topiy * model->gridWidth + rightix]); Object *objToBottomLeft = &(model-> objects[bottomiy * model->gridWidth + leftix]); Object *objToBottomRight = &(model-> objects[bottomiy * model->gridWidth + rightix]); // find position in cell by taking remainder of flooring float inx = leftixFloat - leftix; // Interpolate to find deformed coordinates float hor1x = (1 - inx) * objToTopLeft->position.x + inx * objToTopRight->position.x; float hor1y = (1 - inx) * objToTopLeft->position.y + inx * objToTopRight->position.y; float hor2x = (1 - inx) * objToBottomLeft->position.x + inx * objToBottomRight->position.x; float hor2y = (1 - inx) * objToBottomLeft->position.y + inx * objToBottomRight->position.y; deformedX = (1 - iny) * hor1x + iny * hor2x; deformedY = (1 - iny) * hor1y + iny * hor2y; if (useTextureQ) { if (jx == 1) rowCellWidth = deformedX - v[-2]; if (jy > 0 && jx == 1) // do only once per row for all rows except row 0 { rowTexCoordQ = (rowCellWidth / prevRowCellWidth); v[-3] = rowTexCoordQ; // update first column v[-6] *= rowTexCoordQ; // (since we didn't know rowTexCoordQ before) v[-5] *= rowTexCoordQ; } } if (rect) { for (it = 0; it < nMatrix; it++) { float offsetY = 0; if (applyOffsets && y < y2) offsetY = objToTopLeft-> offsetTexCoordForQuadAfter.y; *v++ = COMP_TEX_COORD_X(&matrix[it], x); *v++ = COMP_TEX_COORD_Y(&matrix[it], y + offsetY); *v++ = 0; if (useTextureQ) { *v++ = rowTexCoordQ; // Q texture coordinate if (0 < jy && jy < nVertY - 1) { // copy first 3 texture coords to duplicate row memcpy(v - 4 + nVertX * vSize, v - 4, 3 * sizeof(GLfloat)); *(v - 1 + nVertX * vSize) = 1; // Q texture coordinate } if (applyOffsets && /*0 < jy && */ objToTopLeft-> offsetTexCoordForQuadBefore.y != 0) { // After copying to next row, update texture y coord // by following object's offset offsetY = objToTopLeft-> offsetTexCoordForQuadBefore.y; v[-3] = COMP_TEX_COORD_Y(&matrix[it], y + offsetY); } if (jx > 0) // since column 0 is updated when jx == 1 { v[-4] *= rowTexCoordQ; v[-3] *= rowTexCoordQ; } } else { *v++ = 1; if (0 < jy && jy < nVertY - 1) { // copy first 3 texture coords to duplicate row memcpy(v - 4 + nVertX * vSize, v - 4, 3 * sizeof(GLfloat)); *(v - 1 + nVertX * vSize) = 1; // Q texture coordinate } if (applyOffsets && objToTopLeft-> offsetTexCoordForQuadBefore.y != 0) { // After copying to next row, update texture y coord // by following object's offset offsetY = objToTopLeft-> offsetTexCoordForQuadBefore.y; v[-3] = COMP_TEX_COORD_Y(&matrix[it], y + offsetY); } } } } else { for (it = 0; it < nMatrix; it++) { float offsetY = 0; if (applyOffsets && y < y2) offsetY = objToTopLeft-> offsetTexCoordForQuadAfter.y; *v++ = COMP_TEX_COORD_XY (&matrix[it], x, y + offsetY); *v++ = COMP_TEX_COORD_YX (&matrix[it], x, y + offsetY); *v++ = 0; if (useTextureQ) { *v++ = rowTexCoordQ; // Q texture coordinate if (0 < jy && jy < nVertY - 1) { // copy first 3 texture coords to duplicate row memcpy(v - 4 + nVertX * vSize, v - 4, 3 * sizeof(GLfloat)); *(v - 1 + nVertX * vSize) = 1; // Q texture coordinate } if (applyOffsets && objToTopLeft-> offsetTexCoordForQuadBefore.y != 0) { // After copying to next row, update texture y coord // by following object's offset offsetY = objToTopLeft-> offsetTexCoordForQuadBefore.y; v[-4] = COMP_TEX_COORD_XY(&matrix[it], x, y + offsetY); v[-3] = COMP_TEX_COORD_YX(&matrix[it], x, y + offsetY); } if (jx > 0) // column t should be updated when jx is t+1 { v[-4] *= rowTexCoordQ; v[-3] *= rowTexCoordQ; } } else { *v++ = 1; if (0 < jy && jy < nVertY - 1) { // copy first 3 texture coords to duplicate row memcpy(v - 4 + nVertX * vSize, v - 4, 3 * sizeof(GLfloat)); *(v - 1 + nVertX * vSize) = 1; // Q texture coordinate } if (applyOffsets && objToTopLeft-> offsetTexCoordForQuadBefore.y != 0) { // After copying to next row, update texture y coord // by following object's offset offsetY = objToTopLeft-> offsetTexCoordForQuadBefore.y; v[-4] = COMP_TEX_COORD_XY(&matrix[it], x, y + offsetY); v[-3] = COMP_TEX_COORD_YX(&matrix[it], x, y + offsetY); } } } } *v++ = deformedX; *v++ = deformedY; if (0 < jy && jy < nVertY - 1) memcpy(v - 2 + nVertX * vSize, v - 2, 2 * sizeof(GLfloat)); nVertices++; // increment x properly (so that coordinates fall on grid intersections) x = rightix * gridW + wx; } if (useTextureQ) prevRowCellWidth = rowCellWidth; if (0 < jy && jy < nVertY - 1) { v += nVertX * vSize; // skip the duplicate row nVertices += nVertX; } // increment y properly (so that coordinates fall on grid intersections) if (aw->curWindowEvent == WindowEventShade || aw->curWindowEvent == WindowEventUnshade) { y += gridH; } else { y = bottomiy * gridH + wy; } } } w->vCount = nVertices; w->indexCount = nIndices; if (awRegion) { XDestroyRegion(awRegion); awRegion = NULL; } } else { UNWRAP(as, w->screen, addWindowGeometry); (*w->screen->addWindowGeometry) (w, matrix, nMatrix, region, clip); WRAP(as, w->screen, addWindowGeometry, animAddWindowGeometry); } } static void animDrawWindowTexture(CompWindow * w, CompTexture * texture, const WindowPaintAttrib * attrib, unsigned int mask) { ANIM_WINDOW(w); ANIM_SCREEN(w->screen); if (aw->animRemainingTime > 0) // if animation in progress, store texture { //printf("%X animDrawWindowTexture, texture: %X\n", // (unsigned)aw, (unsigned)texture); aw->curTexture = texture; aw->curPaintAttrib = *attrib; } UNWRAP(as, w->screen, drawWindowTexture); (*w->screen->drawWindowTexture) (w, texture, attrib, mask); WRAP(as, w->screen, drawWindowTexture, animDrawWindowTexture); } static void animDrawWindowGeometry(CompWindow * w) { ANIM_WINDOW(w); if (aw->animRemainingTime > 0) { //printf("animDrawWindowGeometry: %X: coords: %d, %d, %f\n", // (unsigned)aw, WIN_X (w), WIN_Y (w), aw->animRemainingTime); aw->nDrawGeometryCalls++; ANIM_SCREEN(w->screen); if (playingPolygonEffect(as, aw) && animEffectProperties[aw->curAnimEffect].drawCustomGeometryFunc) { animEffectProperties[aw->curAnimEffect].drawCustomGeometryFunc (w->screen, w); return; } int texUnit = w->texUnits; int currentTexUnit = 0; int stride = 2 + texUnit * w->texCoordSize; GLfloat *vertices = w->vertices + (stride - 2); stride *= sizeof(GLfloat); glVertexPointer(2, GL_FLOAT, stride, vertices); while (texUnit--) { if (texUnit != currentTexUnit) { w->screen->clientActiveTexture(GL_TEXTURE0_ARB + texUnit); glEnableClientState(GL_TEXTURE_COORD_ARRAY); currentTexUnit = texUnit; } vertices -= w->texCoordSize; glTexCoordPointer(w->texCoordSize, GL_FLOAT, stride, vertices); } glDrawElements(GL_QUADS, w->indexCount, GL_UNSIGNED_SHORT, w->indices); // disable all texture coordinate arrays except 0 texUnit = w->texUnits; if (texUnit > 1) { while (--texUnit) { (*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB + texUnit); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } (*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB); } } else { ANIM_SCREEN(w->screen); UNWRAP(as, w->screen, drawWindowGeometry); (*w->screen->drawWindowGeometry) (w); WRAP(as, w->screen, drawWindowGeometry, animDrawWindowGeometry); } } static Bool animPaintWindow(CompWindow * w, const WindowPaintAttrib * attrib, Region region, unsigned int mask) { Bool status; ANIM_SCREEN(w->screen); ANIM_WINDOW(w); if (aw->animRemainingTime > 0) { //printf("animPaintWindow: %X: coords: %d, %d\n", // (unsigned)aw, WIN_X (w), WIN_X (w)); if (mask & PAINT_WINDOW_TRANSFORMED_MASK) { aw->curTextureFilter = w->screen->filter[WINDOW_TRANS_FILTER]; } else if (mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK) { aw->curTextureFilter = w->screen->filter[SCREEN_TRANS_FILTER]; } else { aw->curTextureFilter = w->screen->filter[NOTHING_TRANS_FILTER]; } w->indexCount = 0; WindowPaintAttrib wAttrib = *attrib; if (mask & PAINT_WINDOW_SOLID_MASK) return FALSE; mask |= PAINT_WINDOW_TRANSFORMED_MASK; wAttrib.xScale = 1.0f; wAttrib.yScale = 1.0f; aw->nDrawGeometryCalls = 0; if (animEffectProperties[aw->curAnimEffect].updateWindowAttribFunc) animEffectProperties[aw->curAnimEffect]. updateWindowAttribFunc(as, aw, &wAttrib); if (animEffectProperties[aw->curAnimEffect].prePaintWindowFunc) animEffectProperties[aw->curAnimEffect]. prePaintWindowFunc(w->screen, w); UNWRAP(as, w->screen, paintWindow); status = (*w->screen->paintWindow) (w, &wAttrib, region, mask); WRAP(as, w->screen, paintWindow, animPaintWindow); if (animEffectProperties[aw->curAnimEffect].postPaintWindowFunc) animEffectProperties[aw->curAnimEffect]. postPaintWindowFunc(w->screen, w); } else { UNWRAP(as, w->screen, paintWindow); status = (*w->screen->paintWindow) (w, attrib, region, mask); WRAP(as, w->screen, paintWindow, animPaintWindow); } return status; } static Bool animGetWindowIconGeometry(CompWindow * w, XRectangle * rect) { Atom actual; int result, format; unsigned long n, left; unsigned char *data; ANIM_DISPLAY(w->screen->display); result = XGetWindowProperty(w->screen->display->display, w->id, ad->winIconGeometryAtom, 0L, 4L, FALSE, XA_CARDINAL, &actual, &format, &n, &left, &data); if (result == Success && n && data) { if (n == 4) { unsigned long *geometry = (unsigned long *)data; rect->x = geometry[0]; rect->y = geometry[1]; rect->width = geometry[2]; rect->height = geometry[3]; XFree(data); return TRUE; } XFree(data); } return FALSE; } static void animHandleEvent(CompDisplay * d, XEvent * event) { Window activeWindow = 0; CompWindow *w; ANIM_DISPLAY(d); switch (event->type) { case PropertyNotify: if (event->xproperty.atom == d->winActiveAtom) activeWindow = d->activeWindow; break; case MapNotify: w = findWindowAtDisplay(d, event->xmap.window); if (w) { ANIM_WINDOW(w); if (aw->animRemainingTime > 0) { aw->state = aw->newState; } while (aw->unmapCnt) { unmapWindow(w); aw->unmapCnt--; } } break; case DestroyNotify: w = findWindowAtDisplay(d, event->xunmap.window); if (w) { ANIM_WINDOW(w); aw->destroyCnt++; w->destroyRefCnt++; addWindowDamage(w); } break; case UnmapNotify: w = findWindowAtDisplay(d, event->xunmap.window); if (w) { ANIM_SCREEN(w->screen); if (w->pendingUnmaps && onCurrentDesktop(w)) // Normal -> Iconic { ANIM_WINDOW(w); if (w->shaded) { // SHADE event! //printf("SHADE event! %X\n", (unsigned)aw); aw->nowShaded = TRUE; if (as->shadeEffect && (as->shadeWMask & w->type)) { IPCS_SetBool(IPCS_OBJECT(w), aw->animatedAtom, TRUE); Bool startingNew = TRUE; if (aw->curWindowEvent != WindowEventNone) { if (aw->curWindowEvent != WindowEventUnshade) postAnimationCleanup(w, TRUE); else { // Play the unshade effect backwards from where it left aw->animRemainingTime = aw->animTotalTime - aw->animRemainingTime; // avoid window remains if (aw->animRemainingTime <= 0) aw->animRemainingTime = 1; startingNew = FALSE; if (aw->animOverrideProgressDir == 0) aw->animOverrideProgressDir = 2; else if (aw->animOverrideProgressDir == 1) aw->animOverrideProgressDir = 0; } } as->animInProgress = TRUE; aw->curWindowEvent = WindowEventShade; if (startingNew) { if (as->shadeEffect == AnimEffectRandom || as-> opt[ANIM_SCREEN_OPTION_ALL_RANDOM].value.b) aw->curAnimEffect = // choose a random effect as->shadeRandomEffects[(int) (as-> nShadeRandomEffects * (double)rand() / RAND_MAX)]; else aw->curAnimEffect = as->shadeEffect; aw->animTotalTime = as-> opt [ANIM_SCREEN_OPTION_SHADE_DURATION]. value.f * 1000; aw->animRemainingTime = aw->animTotalTime; } // Store coords in this viewport to omit 3d effect // painting in other viewports aw->lastKnownCoords.x = w->attrib.x; aw->lastKnownCoords.y = w->attrib.y; if (!animEnsureModel (w, WindowEventShade, aw->curAnimEffect)) { postAnimationCleanup(w, TRUE); } aw->unmapCnt++; w->unmapRefCnt++; addWindowDamage(w); } } else if (w->minimized && as->minimizeEffect && (as->minimizeWMask & w->type)) { // MINIMIZE event! //printf("MINIMIZE event! %X\n", (unsigned)aw); IPCS_SetBool(IPCS_OBJECT(w), aw->animatedAtom, TRUE); Bool startingNew = TRUE; if (aw->curWindowEvent != WindowEventNone) { if (aw->curWindowEvent != WindowEventUnminimize) postAnimationCleanup(w, TRUE); else { // Play the unminimize effect backwards from where it left aw->animRemainingTime = aw->animTotalTime - aw->animRemainingTime; // avoid window remains if (aw->animRemainingTime == 0) aw->animRemainingTime = 1; startingNew = FALSE; if (aw->animOverrideProgressDir == 0) aw->animOverrideProgressDir = 2; else if (aw->animOverrideProgressDir == 1) aw->animOverrideProgressDir = 0; } } aw->newState = IconicState; as->animInProgress = TRUE; aw->curWindowEvent = WindowEventMinimize; if (startingNew) { if (as->minimizeEffect == AnimEffectRandom || as->opt[ANIM_SCREEN_OPTION_ALL_RANDOM].value.b) aw->curAnimEffect = // choose a random effect as->minimizeRandomEffects[(int) (as-> nMinimizeRandomEffects * (double)rand() / RAND_MAX)]; else aw->curAnimEffect = as->minimizeEffect; aw->animTotalTime = as-> opt [ANIM_SCREEN_OPTION_MINIMIZE_DURATION]. value.f * 1000; aw->animRemainingTime = aw->animTotalTime; } // Store coords in this viewport to omit 3d effect // painting in other viewports aw->lastKnownCoords.x = w->attrib.x; aw->lastKnownCoords.y = w->attrib.y; if (!animEnsureModel (w, WindowEventMinimize, aw->curAnimEffect)) { postAnimationCleanup(w, TRUE); } else { if (!animGetWindowIconGeometry(w, &aw->icon)) { // minimize to bottom-center if there is no window list aw->icon.x = w->screen->width / 2; aw->icon.y = w->screen->height; aw->icon.width = 100; aw->icon.height = 20; } if ((aw->curAnimEffect == AnimEffectZoom || aw-> curAnimEffect == AnimEffectSidekick) && (as->zoomFC == ZoomFromCenterOn || as->zoomFC == ZoomFromCenterMin)) { 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; } aw->unmapCnt++; w->unmapRefCnt++; addWindowDamage(w); } } } else // X -> Withdrawn { ANIM_WINDOW(w); AnimEffect windowsCloseEffect = AnimEffectNone; int whichClose = 1; // either 1 or 2 if (as->close1Effect && (as->close1WMask & w->type)) windowsCloseEffect = as->close1Effect; else if (as->close2Effect && (as->close2WMask & w->type)) { windowsCloseEffect = as->close2Effect; whichClose = 2; } // CLOSE event! if (windowsCloseEffect) { IPCS_SetBool(IPCS_OBJECT(w), aw->animatedAtom, TRUE); int tmpSteps = 0; //printf("CLOSE event! %X\n", (unsigned)aw); Bool startingNew = TRUE; if (aw->animRemainingTime > 0 && aw->curWindowEvent != WindowEventCreate) { tmpSteps = aw->animRemainingTime; aw->animRemainingTime = 0; } if (aw->curWindowEvent != WindowEventNone) { if (aw->curWindowEvent == WindowEventCreate) { // Play the create effect backward from where it left aw->animRemainingTime = aw->animTotalTime - aw->animRemainingTime; // avoid window remains if (aw->animRemainingTime <= 0) aw->animRemainingTime = 1; startingNew = FALSE; if (aw->animOverrideProgressDir == 0) aw->animOverrideProgressDir = 2; else if (aw->animOverrideProgressDir == 1) aw->animOverrideProgressDir = 0; } else if (aw->curWindowEvent == WindowEventClose) { if (aw->animOverrideProgressDir == 2) { aw->animRemainingTime = tmpSteps; startingNew = FALSE; } } else { postAnimationCleanup(w, TRUE); } } aw->state = NormalState; aw->newState = WithdrawnState; as->animInProgress = TRUE; aw->curWindowEvent = WindowEventClose; if (startingNew) { if (windowsCloseEffect == AnimEffectRandom || as->opt[ANIM_SCREEN_OPTION_ALL_RANDOM].value.b) { if (whichClose == 1) aw->curAnimEffect = // choose a random effect as->close1RandomEffects[(int) (as-> nClose1RandomEffects * (double) rand() / RAND_MAX)]; else aw->curAnimEffect = // choose a random effect as->close2RandomEffects[(int) (as-> nClose2RandomEffects * (double) rand() / RAND_MAX)]; } else aw->curAnimEffect = windowsCloseEffect; aw->animTotalTime = as->opt[whichClose == 1 ? ANIM_SCREEN_OPTION_CLOSE1_DURATION : ANIM_SCREEN_OPTION_CLOSE2_DURATION]. value.f * 1000; aw->animRemainingTime = aw->animTotalTime; } // Store coords in this viewport to omit 3d effect // painting in other viewports aw->lastKnownCoords.x = w->attrib.x; aw->lastKnownCoords.y = w->attrib.y; if (!animEnsureModel (w, WindowEventClose, aw->curAnimEffect)) { postAnimationCleanup(w, TRUE); } else if (getMousePointerXY (w->screen, &aw->icon.x, &aw->icon.y)) { aw->icon.width = FAKE_ICON_SIZE; aw->icon.height = FAKE_ICON_SIZE; if (aw->curAnimEffect == AnimEffectMagicLamp1 && aw->icon.width < as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP1_CREATE_START_WIDTH]. value.i) { aw->icon.width = as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP1_CREATE_START_WIDTH]. value.i; } else if (aw->curAnimEffect == AnimEffectMagicLamp2 && aw->icon.width < as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP2_CREATE_START_WIDTH]. value.i) { aw->icon.width = as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP2_CREATE_START_WIDTH]. value.i; } else if (aw->curAnimEffect == AnimEffectMagicLamp3 && aw->icon.width < as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP3_CREATE_START_WIDTH]. value.i) { aw->icon.width = as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP3_CREATE_START_WIDTH]. value.i; } if ((aw->curAnimEffect == AnimEffectZoom || aw-> curAnimEffect == AnimEffectSidekick) && (as->zoomFC == ZoomFromCenterOn || as->zoomFC == 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; } aw->unmapCnt++; w->unmapRefCnt++; addWindowDamage(w); } } else if ((as->create1Effect && (as->create1WMask & w->type)) || (as->create2Effect && (as->create2WMask & w->type))) { // stop the current animation and prevent it from rewinding if (aw->animRemainingTime > 0 && aw->curWindowEvent != WindowEventCreate) { aw->animRemainingTime = 0; } if ((aw->curWindowEvent != WindowEventNone) && (aw->curWindowEvent != WindowEventClose)) { postAnimationCleanup(w, TRUE); } // set some properties to make sure this window will use the // correct create effect the next time it's "created" aw->state = NormalState; aw->newState = WithdrawnState; as->animInProgress = TRUE; aw->curWindowEvent = WindowEventClose; aw->unmapCnt++; w->unmapRefCnt++; addWindowDamage(w); } } } break; default: break; } UNWRAP(ad, d, handleEvent); (*d->handleEvent) (d, event); WRAP(ad, d, handleEvent, animHandleEvent); switch (event->type) { case PropertyNotify: if (event->xproperty.atom == d->winActiveAtom) { if (d->activeWindow != activeWindow) { w = findWindowAtDisplay(d, d->activeWindow); if (w) { ANIM_WINDOW(w); ANIM_SCREEN(w->screen); if (aw->curWindowEvent != WindowEventNone) return; if ((as->focusWMask & w->type) && as->focusEffect && // On unminimization, focus event is fired first. // When this happens and minimize is in progress, // don't prevent rewinding of minimize when unminimize is fired // right after this focus event. aw->curWindowEvent != WindowEventMinimize && animEnsureModel(w, WindowEventFocus, as->focusEffect)) { // FOCUS event! //printf("FOCUS event! %X\n", (unsigned)aw); IPCS_SetBool(IPCS_OBJECT(w), aw->animatedAtom, TRUE); if (aw->curWindowEvent != WindowEventNone) { postAnimationCleanup(w, TRUE); } as->animInProgress = TRUE; aw->curWindowEvent = WindowEventFocus; aw->curAnimEffect = as->focusEffect; aw->animTotalTime = as-> opt [ANIM_SCREEN_OPTION_FOCUS_DURATION]. value.f * 1000; aw->animRemainingTime = aw->animTotalTime; // Store coords in this viewport to omit 3d effect // painting in other viewports aw->lastKnownCoords.x = w->attrib.x; aw->lastKnownCoords.y = w->attrib.y; damageScreen(w->screen); } } } } default: break; } } static Bool animDamageWindowRect(CompWindow * w, Bool initial, BoxPtr rect) { Bool status; ANIM_SCREEN(w->screen); if (initial) // Unminimize or Create { ANIM_WINDOW(w); if (aw->state == IconicState) { if (!w->invisible && as->unminimizeEffect && (as->unminimizeWMask & w->type)) { // UNMINIMIZE event! //printf("UNMINIMIZE event! %X\n", (unsigned)aw); IPCS_SetBool(IPCS_OBJECT(w), aw->animatedAtom, TRUE); Bool startingNew = TRUE; if (aw->curWindowEvent != WindowEventNone) { if (aw->curWindowEvent != WindowEventMinimize) postAnimationCleanup(w, TRUE); else { // Play the minimize effect backwards from where it left aw->animRemainingTime = aw->animTotalTime - aw->animRemainingTime; // avoid window remains if (aw->animRemainingTime <= 0) aw->animRemainingTime = 1; startingNew = FALSE; if (aw->animOverrideProgressDir == 0) aw->animOverrideProgressDir = 1; else if (aw->animOverrideProgressDir == 2) aw->animOverrideProgressDir = 0; } } as->animInProgress = TRUE; aw->curWindowEvent = WindowEventUnminimize; if (startingNew) { if (as->unminimizeEffect == AnimEffectRandom || as->opt[ANIM_SCREEN_OPTION_ALL_RANDOM].value.b) aw->curAnimEffect = // choose a random effect as->unminimizeRandomEffects[(int) (as-> nUnminimizeRandomEffects * (double)rand() / RAND_MAX)]; else aw->curAnimEffect = as->unminimizeEffect; aw->animTotalTime = as-> opt [ANIM_SCREEN_OPTION_UNMINIMIZE_DURATION]. value.f * 1000; aw->animRemainingTime = aw->animTotalTime; } // Store coords in this viewport to omit 3d effect // painting in other viewports aw->lastKnownCoords.x = w->attrib.x; aw->lastKnownCoords.y = w->attrib.y; if (animEnsureModel (w, WindowEventUnminimize, aw->curAnimEffect)) { if (!animGetWindowIconGeometry(w, &aw->icon)) { // minimize to bottom-center if there is no window list aw->icon.x = w->screen->width / 2; aw->icon.y = w->screen->height; aw->icon.width = 100; aw->icon.height = 20; } if ((aw->curAnimEffect == AnimEffectZoom || aw->curAnimEffect == AnimEffectSidekick) && (as->zoomFC == ZoomFromCenterOn || as->zoomFC == ZoomFromCenterMin)) { 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; } addWindowDamage(w); } else postAnimationCleanup(w, TRUE); } } else if (aw->nowShaded) { // UNSHADE event! //printf("UNSHADE event! %X\n", (unsigned)aw); IPCS_SetBool(IPCS_OBJECT(w), aw->animatedAtom, TRUE); aw->nowShaded = FALSE; if (as->unshadeEffect && (as->unshadeWMask & w->type)) { Bool startingNew = TRUE; if (aw->curWindowEvent != WindowEventNone) { if (aw->curWindowEvent != WindowEventShade) postAnimationCleanup(w, TRUE); else { // Play the shade effect backwards from where it left aw->animRemainingTime = aw->animTotalTime - aw->animRemainingTime; // avoid window remains if (aw->animRemainingTime <= 0) aw->animRemainingTime = 1; startingNew = FALSE; if (aw->animOverrideProgressDir == 0) aw->animOverrideProgressDir = 1; else if (aw->animOverrideProgressDir == 2) aw->animOverrideProgressDir = 0; } } as->animInProgress = TRUE; aw->curWindowEvent = WindowEventUnshade; if (startingNew) { if (as->unshadeEffect == AnimEffectRandom || as->opt[ANIM_SCREEN_OPTION_ALL_RANDOM].value.b) aw->curAnimEffect = // choose a random effect as->unshadeRandomEffects[(int) (as-> nUnshadeRandomEffects * (double)rand() / RAND_MAX)]; else aw->curAnimEffect = as->unshadeEffect; aw->animTotalTime = as-> opt [ANIM_SCREEN_OPTION_UNSHADE_DURATION].value.f * 1000; aw->animRemainingTime = aw->animTotalTime; } // Store coords in this viewport to omit 3d effect // painting in other viewports aw->lastKnownCoords.x = w->attrib.x; aw->lastKnownCoords.y = w->attrib.y; if (animEnsureModel(w, WindowEventUnshade, aw->curAnimEffect)) addWindowDamage(w); else postAnimationCleanup(w, TRUE); } } else if (aw->state != NormalState && !w->invisible) { AnimEffect windowsCreateEffect = AnimEffectNone; int whichCreate = 1; // either 1 or 2 if (as->create1Effect && (as->create1WMask & w->type)) windowsCreateEffect = as->create1Effect; else if (as->create2Effect && (as->create2WMask & w->type)) { windowsCreateEffect = as->create2Effect; whichCreate = 2; } if (windowsCreateEffect && getMousePointerXY(w->screen, &aw->icon.x, &aw->icon.y)) { // CREATE event! //printf("CREATE event! %X\n", (unsigned)aw); IPCS_SetBool(IPCS_OBJECT(w), aw->animatedAtom, TRUE); Bool startingNew = TRUE; if (aw->curWindowEvent != WindowEventNone) { if (aw->curWindowEvent != WindowEventClose) postAnimationCleanup(w, TRUE); else { // Play the close effect backwards from where it left aw->animRemainingTime = aw->animTotalTime - aw->animRemainingTime; // avoid window remains if (aw->animRemainingTime == 0) aw->animRemainingTime = 1; startingNew = FALSE; if (aw->animOverrideProgressDir == 0) aw->animOverrideProgressDir = 1; else if (aw->animOverrideProgressDir == 2) aw->animOverrideProgressDir = 0; } } as->animInProgress = TRUE; aw->curWindowEvent = WindowEventCreate; if (startingNew) { if (windowsCreateEffect == AnimEffectRandom || as->opt[ANIM_SCREEN_OPTION_ALL_RANDOM].value.b) { if (whichCreate == 1) aw->curAnimEffect = // choose a random effect as->create1RandomEffects[(int) (as-> nCreate1RandomEffects * (double)rand() / RAND_MAX)]; else aw->curAnimEffect = // choose a random effect as->create2RandomEffects[(int) (as-> nCreate2RandomEffects * (double)rand() / RAND_MAX)]; } else aw->curAnimEffect = windowsCreateEffect; aw->animTotalTime = as->opt[whichCreate == 1 ? ANIM_SCREEN_OPTION_CREATE1_DURATION : ANIM_SCREEN_OPTION_CREATE2_DURATION]. value.f * 1000; aw->animRemainingTime = aw->animTotalTime; } aw->icon.width = FAKE_ICON_SIZE; aw->icon.height = FAKE_ICON_SIZE; if (aw->curAnimEffect == AnimEffectMagicLamp1 && aw->icon.width < as-> opt[ANIM_SCREEN_OPTION_MAGIC_LAMP1_CREATE_START_WIDTH]. value.i) { aw->icon.width = as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP1_CREATE_START_WIDTH]. value.i; } else if (aw->curAnimEffect == AnimEffectMagicLamp2 && aw->icon.width < as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP2_CREATE_START_WIDTH]. value.i) { aw->icon.width = as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP2_CREATE_START_WIDTH]. value.i; } else if (aw->curAnimEffect == AnimEffectMagicLamp3 && aw->icon.width < as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP3_CREATE_START_WIDTH]. value.i) { aw->icon.width = as-> opt [ANIM_SCREEN_OPTION_MAGIC_LAMP3_CREATE_START_WIDTH]. value.i; } aw->icon.x -= aw->icon.width / 2; aw->icon.y -= aw->icon.height / 2; if ((aw->curAnimEffect == AnimEffectZoom || aw->curAnimEffect == AnimEffectSidekick) && (as->zoomFC == ZoomFromCenterOn || as->zoomFC == 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; } aw->state = IconicState; // we're doing this as a hack, it may not be necessary // Store coords in this viewport to omit 3d effect // painting in other viewports if (aw->lastKnownCoords.x != NOT_INITIALIZED) { aw->lastKnownCoords.x = w->attrib.x; aw->lastKnownCoords.y = w->attrib.y; } if (animEnsureModel(w, WindowEventCreate, aw->curAnimEffect)) addWindowDamage(w); else postAnimationCleanup(w, TRUE); } } aw->newState = NormalState; } UNWRAP(as, w->screen, damageWindowRect); status = (*w->screen->damageWindowRect) (w, initial, rect); WRAP(as, w->screen, damageWindowRect, animDamageWindowRect); return status; } static void animWindowResizeNotify(CompWindow * w, int dx, int dy, int dwidth, int dheight, Bool preview) { ANIM_SCREEN(w->screen); ANIM_WINDOW(w); if (aw->polygonSet && !aw->animInitialized) { // to refresh polygon coords freePolygonSet(aw); } if (!preview && (dx || dy || dwidth || dheight)) { if (aw->animRemainingTime > 0) { aw->animRemainingTime = 0; postAnimationCleanup(w, TRUE); } if (aw->model) { modelInitObjects(aw->model, WIN_X(w), WIN_Y(w), WIN_W(w), WIN_H(w)); } } aw->state = w->state; UNWRAP(as, w->screen, windowResizeNotify); (*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight, preview); WRAP(as, w->screen, windowResizeNotify, animWindowResizeNotify); } static void animWindowMoveNotify(CompWindow * w, int dx, int dy, Bool immediate) { ANIM_SCREEN(w->screen); ANIM_WINDOW(w); CompWindow *w2; if (aw->polygonSet && !aw->animInitialized) { // to refresh polygon coords freePolygonSet(aw); } if (aw->animRemainingTime > 0 && aw->grabbed) { aw->animRemainingTime = 0; if (as->animInProgress) { as->animInProgress = FALSE; for (w2 = w->screen->windows; w2; w2 = w2->next) { AnimWindow *aw2; aw2 = GET_ANIM_WINDOW(w2, as); if (aw2->animRemainingTime > 0) { as->animInProgress = TRUE; break; } } } postAnimationCleanup(w, TRUE); } if (aw->model) { modelInitObjects(aw->model, WIN_X(w), WIN_Y(w), WIN_W(w), WIN_H(w)); } UNWRAP(as, w->screen, windowMoveNotify); (*w->screen->windowMoveNotify) (w, dx, dy, immediate); WRAP(as, w->screen, windowMoveNotify, animWindowMoveNotify); } static void animWindowGrabNotify(CompWindow * w, int x, int y, unsigned int state, unsigned int mask) { ANIM_SCREEN(w->screen); ANIM_WINDOW(w); aw->grabbed = TRUE; UNWRAP(as, w->screen, windowGrabNotify); (*w->screen->windowGrabNotify) (w, x, y, state, mask); WRAP(as, w->screen, windowGrabNotify, animWindowGrabNotify); } static void animWindowUngrabNotify(CompWindow * w) { ANIM_SCREEN(w->screen); ANIM_WINDOW(w); aw->grabbed = FALSE; UNWRAP(as, w->screen, windowUngrabNotify); (*w->screen->windowUngrabNotify) (w); WRAP(as, w->screen, windowUngrabNotify, animWindowUngrabNotify); } static Bool animPaintScreen(CompScreen * s, const ScreenPaintAttrib * sAttrib, Region region, int output, unsigned int mask) { Bool status; ANIM_SCREEN(s); if (as->animInProgress) { // Find out if an animation running now uses depth test Bool depthUsed = FALSE; CompWindow *w; for (w = s->windows; w; w = w->next) { ANIM_WINDOW(w); if (aw->animRemainingTime > 0 && aw->polygonSet && aw->polygonSet->doDepthTest) { depthUsed = TRUE; break; } } if (depthUsed) { glClearDepth(1000.0f); glClear(GL_DEPTH_BUFFER_BIT); } mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK; } UNWRAP(as, s, paintScreen); status = (*s->paintScreen) (s, sAttrib, region, output, mask); WRAP(as, s, paintScreen, animPaintScreen); return status; } static Bool animInitDisplay(CompPlugin * p, CompDisplay * d) { AnimDisplay *ad; ad = calloc(1, sizeof(AnimDisplay)); if (!ad) return FALSE; ad->screenPrivateIndex = allocateScreenPrivateIndex(d); if (ad->screenPrivateIndex < 0) { free(ad); return FALSE; } ad->wmHintsAtom = XInternAtom(d->display, "WM_HINTS", FALSE); ad->winIconGeometryAtom = XInternAtom(d->display, "_NET_WM_ICON_GEOMETRY", 0); WRAP(ad, d, handleEvent, animHandleEvent); d->privates[displayPrivateIndex].ptr = ad; return TRUE; } static void animFiniDisplay(CompPlugin * p, CompDisplay * d) { ANIM_DISPLAY(d); freeScreenPrivateIndex(d, ad->screenPrivateIndex); UNWRAP(ad, d, handleEvent); free(ad); } static Bool animInitScreen(CompPlugin * p, CompScreen * s) { AnimScreen *as; ANIM_DISPLAY(s->display); as = calloc(1, sizeof(AnimScreen)); if (!as) return FALSE; as->windowPrivateIndex = allocateWindowPrivateIndex(s); if (as->windowPrivateIndex < 0) { free(as); return FALSE; } as->animInProgress = FALSE; as->minimizeEffect = ANIM_MINIMIZE_DEFAULT; as->unminimizeEffect = ANIM_UNMINIMIZE_DEFAULT; as->create1Effect = ANIM_CREATE1_DEFAULT; as->create2Effect = ANIM_CREATE2_DEFAULT; as->close1Effect = ANIM_CLOSE1_DEFAULT; as->close2Effect = ANIM_CLOSE2_DEFAULT; as->focusEffect = ANIM_FOCUS_DEFAULT; as->shadeEffect = ANIM_SHADE_DEFAULT; as->unshadeEffect = ANIM_UNSHADE_DEFAULT; as->zoomFC = ANIM_ZOOM_FROM_CENTER_DEFAULT; as->ppDisabling = ANIM_DISABLE_PP_FX_DEFAULT; animScreenInitOptions(as); WRAP(as, s, preparePaintScreen, animPreparePaintScreen); WRAP(as, s, donePaintScreen, animDonePaintScreen); WRAP(as, s, paintScreen, animPaintScreen); WRAP(as, s, paintWindow, animPaintWindow); WRAP(as, s, damageWindowRect, animDamageWindowRect); WRAP(as, s, addWindowGeometry, animAddWindowGeometry); WRAP(as, s, drawWindowTexture, animDrawWindowTexture); WRAP(as, s, drawWindowGeometry, animDrawWindowGeometry); WRAP(as, s, windowResizeNotify, animWindowResizeNotify); WRAP(as, s, windowMoveNotify, animWindowMoveNotify); WRAP(as, s, windowGrabNotify, animWindowGrabNotify); WRAP(as, s, windowUngrabNotify, animWindowUngrabNotify); s->privates[ad->screenPrivateIndex].ptr = as; return TRUE; } static void animFiniScreen(CompPlugin * p, CompScreen * s) { ANIM_SCREEN(s); freeWindowPrivateIndex(s, as->windowPrivateIndex); free(as->opt[ANIM_SCREEN_OPTION_MINIMIZE_EFFECT].value.s); free(as->opt[ANIM_SCREEN_OPTION_UNMINIMIZE_EFFECT].value.s); free(as->opt[ANIM_SCREEN_OPTION_CREATE1_EFFECT].value.s); free(as->opt[ANIM_SCREEN_OPTION_CREATE2_EFFECT].value.s); free(as->opt[ANIM_SCREEN_OPTION_CLOSE1_EFFECT].value.s); free(as->opt[ANIM_SCREEN_OPTION_CLOSE2_EFFECT].value.s); free(as->opt[ANIM_SCREEN_OPTION_FOCUS_EFFECT].value.s); free(as->opt[ANIM_SCREEN_OPTION_SHADE_EFFECT].value.s); free(as->opt[ANIM_SCREEN_OPTION_UNSHADE_EFFECT].value.s); UNWRAP(as, s, preparePaintScreen); UNWRAP(as, s, donePaintScreen); UNWRAP(as, s, paintScreen); UNWRAP(as, s, paintWindow); UNWRAP(as, s, damageWindowRect); UNWRAP(as, s, addWindowGeometry); UNWRAP(as, s, drawWindowTexture); UNWRAP(as, s, drawWindowGeometry); UNWRAP(as, s, windowResizeNotify); UNWRAP(as, s, windowMoveNotify); UNWRAP(as, s, windowGrabNotify); UNWRAP(as, s, windowUngrabNotify); free(as); } static Bool animInitWindow(CompPlugin * p, CompWindow * w) { AnimWindow *aw; ANIM_SCREEN(w->screen); aw = calloc(1, sizeof(AnimWindow)); if (!aw) return FALSE; aw->animatedAtom = IPCS_GetAtom(IPCS_OBJECT(w), IPCS_BOOL, "IS_ANIMATED", TRUE); IPCS_SetBool(IPCS_OBJECT(w), aw->animatedAtom, FALSE); aw->model = 0; aw->state = w->state; aw->animRemainingTime = 0; aw->animInitialized = FALSE; aw->curAnimEffect = AnimEffectNone; aw->curWindowEvent = WindowEventNone; aw->animOverrideProgressDir = 0; w->indexCount = 0; aw->polygonSet = NULL; aw->lastKnownCoords.x = NOT_INITIALIZED; aw->lastKnownCoords.y = NOT_INITIALIZED; aw->unmapCnt = 0; aw->destroyCnt = 0; aw->grabbed = FALSE; aw->useDrawRegion = FALSE; aw->drawRegion = NULL; if (w->shaded) { aw->state = aw->newState = NormalState; aw->nowShaded = TRUE; } else { aw->state = aw->newState = animGetWindowState(w); aw->nowShaded = FALSE; } w->privates[as->windowPrivateIndex].ptr = aw; return TRUE; } static void animFiniWindow(CompPlugin * p, CompWindow * w) { ANIM_WINDOW(w); postAnimationCleanup(w, FALSE); if (aw->model) { if (aw->model->magicLampWaves) free(aw->model->magicLampWaves); aw->model->magicLampWaves = 0; free(aw->model->objects); aw->model->objects = 0; free(aw->model); aw->model = 0; } while (aw->unmapCnt--) unmapWindow(w); free(aw); } static Bool animInit(CompPlugin * p) { displayPrivateIndex = allocateDisplayPrivateIndex(); if (displayPrivateIndex < 0) return FALSE; animEffectPropertiesTmp = animEffectProperties; return TRUE; } static void animFini(CompPlugin * p) { if (displayPrivateIndex >= 0) freeDisplayPrivateIndex(displayPrivateIndex); } CompPluginDep animDeps[] = { {CompPluginRuleAfter, "decoration"} }; CompPluginVTable animVTable = { "animation", N_("Animations"), N_("Use various animations as window effects"), animInit, animFini, animInitDisplay, animFiniDisplay, animInitScreen, animFiniScreen, animInitWindow, animFiniWindow, 0, 0, animGetScreenOptions, animSetScreenOption, animDeps, sizeof(animDeps) / sizeof(animDeps[0]), 0, 0, BERYL_ABI_INFO, "beryl-plugins", "effects", 0, 0, True, }; CompPluginVTable *getCompPluginInfo(void) { return &animVTable; }