• Immutable Page
  • Info
  • Attachments

Animation Plugin - Creating New Effects

Architecture

The Compiz 0.9 Animation plugin is highly object-oriented in design - it follows a philosophy of providing as many base classes as possible for you to build simple animations on top of (rather than having to reimplement complicated systems of texture management etc).

In order to start building a new animation, you just need to create a class for that animation and then inherit the Animation class. You can then overload the many methods specified in Animation

class EgAnim :
    public Animation
{
    public:

        EgAnim (CompWindow  *w,
                WindowEvent curWindowEvent,
                float       duration,
                const AnimEffect *info,
                const CompRect   &icon) :
            Animation::Animation (w, curWindowEvent, duration, info, icon) {};

        void init ();
        void step ();

        virtual void foo () {};

};

void
EgAnim::init ()
{
    compLogMessage ("animationeg", CompLogLevelInfo, "EgAnim build-up code created");
}

void
EgAnim::step ()
{
    compLogMessage ("animationeg", CompLogLevelInfo, "Stepping the animation");
    foo ();
}

;

That represents a very simple animation. It should work fine, if you follow the similar instructions from the last set of documentation. Of course, it doesn't do very much except log some messages, but as you can see, we made foo (); virtual, so we can now create a new animation with this as a base.

class EgPlusPlusAnim :
    public EgAnim,
    virtual public Animation
{
    public:

        EgPlusPlusAnim (CompWindow  *w,
                        WindowEvent curWindowEvent,
                        float       duration,
                        const AnimEffect *info,
                        const CompRect   &icon) :
            EgAnim::EgAnim (w, curWindowEvent, duration, info, icon),
            Animation::Animation (w, curWindowEvent, duration, info, icon) {};

        void foo ();
};

void
EgPlusPlusAnim::foo ()
{
    compLogMessage ("animationeg", CompLogLevelInfo, "I just did a foo!");
}

That will extend EgAnim as a base class to do something on foo (). More complex versions of this are more powerful, for example the GridAnim, ParticleAnim and PolygonAnim which implement extendable grid, particle and polygon systems to build many animations on top of.

Animation base class definition

class Animation
{
    
public:
    
    Animation (CompWindow *w,
               WindowEvent curWindowEvent,
               float duration,
               const AnimEffect info,
               const CompRect &icon);
    virtual ~Animation ();
    
    inline AnimEffect info () { return mInfo; }
    
    // Overridable animation methods.
    
    /// Needed since virtual method calls can't be done in the constructor.
    virtual void init () {}
    
    /// To be called during post-animation clean up.
    virtual void cleanUp (bool closing,
                          bool destructing) {}
                          
    /// Returns true if frame should be skipped (e.g. due to
    /// higher timestep values). In that case no drawing is
    /// needed for that window in current frame.
    virtual bool shouldSkipFrame (int msSinceLastPaintActual);

    /// Advances the animation time by the given time amount.
    /// Returns true if more animation time is left.
    virtual bool advanceTime (int msSinceLastPaint);

    /// Computes new animation state based on remaining time.
    virtual void step () {}
    virtual void updateAttrib (GLWindowPaintAttrib &) {}
    virtual void updateTransform (GLMatrix &) {}
    virtual void prePaintWindow () {}
    virtual void postPaintWindow () {}
    virtual bool postPaintWindowUsed () { return false; }

    /// Returns true if the animation is still in progress.
    virtual bool prePreparePaint (int msSinceLastPaint) { return false; }
    virtual void postPreparePaint () {}

    /// Updates the bounding box of damaged region. Should be implemented for
    /// any animation that doesn't update the whole screen.
    virtual void updateBB (CompOutput &) {}
    virtual bool updateBBUsed () { return false; }

    /// Should return true for effects that make use of a region
    /// instead of just a bounding box for damaged area.
    virtual bool stepRegionUsed () { return false; }

    virtual bool shouldDamageWindowOnStart ();
    virtual bool shouldDamageWindowOnEnd ();

    /// Should return false if the animation should be stopped on move
    virtual bool moveUpdate (int dx, int dy) { return true; }

    /// Should return false if the animation should be stopped on resize
    virtual bool resizeUpdate (int dx, int dy,
                                int dwidth, int dheight) { return true; }

    virtual void adjustPointerIconSize () {}
    virtual void addGeometry (const GLTexture::MatrixList &matrix,
                            const CompRegion            &region,
                            const CompRegion            &clip,
                            unsigned int                maxGridWidth,
                            unsigned int                maxGridHeight);
    virtual void drawGeometry ();

    virtual bool paintWindowUsed () { return false; }
    virtual bool paintWindow (GLWindow                  *gWindow,
                            const GLWindowPaintAttrib &attrib,
                            const GLMatrix              &transform,
                            const CompRegion            &region,
                            unsigned int                mask)
    {
        return gWindow->glPaint (attrib, transform, region, mask);
    }

    /// Gets info about the (extension) plugin that implements this animation.
    /// Should be overriden by a base animation class in every extension plugin.
    virtual ExtensionPluginInfo *getExtensionPluginInfo ();

    void drawTexture (GLTexture          *texture,
                      GLFragment::Attrib &attrib,
                      unsigned int       mask);

    // Utility methods

    void reverse ();
    inline bool inProgress () { return (mRemainingTime > 0); }

    inline WindowEvent curWindowEvent () { return mCurWindowEvent; }
    inline float totalTime () { return mTotalTime; }
    inline float remainingTime () { return mRemainingTime; }

    float progressLinear ();
    float progressEaseInEaseOut ();
    float progressDecelerateCustom (float progress,
                                    float minx, float maxx);
    float progressDecelerate (float progress);
    AnimDirection getActualAnimDirection (AnimDirection dir,
                                          bool openDir);
    void perspectiveDistortAndResetZ (GLMatrix &transform);

    static void prepareTransform (CompOutput &output,
                                  GLMatrix &resultTransform,
                                  GLMatrix &transform);
    void setInitialized () { mInitialized = true; }
    inline bool initialized () { return mInitialized; }
    inline void setCurPaintAttrib (GLFragment::Attrib &newAttrib)
    { mCurPaintAttrib = newAttrib; }
};

Building up the animation

Like most classes, you should do all of your construction in the constructor of your class. However, in the case that you need to call functions which you have overloaded, you should implement a virtual function ::init () and finish constructing in there.

Handling a new frame change

Overloading ::step () is the way to be notified that your animation needs to paint a new frame. In this case, the base class remaining times would have been automatically updated, so you can call the various progress utility functions (more on them later) to find out the percentage of how complete your animation should be.

Note that you can't necessarily begin painting things here, since we have no initialized OpenGL context or matrices. Instead, you'll be able to calculate what you need to paint here and then paint is quickly when those functions get called.

1st Phase Paint Modifications

On the 1st Phase of painting, we have no OpenGL context active and only work with an attrib describing the brightness, saturation and opacity of a window texture as well as a basic 4x4 transformation GLMatrix. Here we can hook both of ::updateAttrib () and ::updateTransform () to update these. If you need to do other things here, you can also hook ::prePaintWindow and ::postPaintWindow for internal compiz setup for how the window might be painted.

3rd Phase Paint Modifications

On the 3rd Phase of painting, we have an OpenGL context set up and are calculating the window texture vertex geometry. Much like the way the Paint Cycle already works, you can hook both of ::addGeometry () and ::drawGeometry (). They work fairly similarly to their ::glAddGeometry and ::glDrawGeometry counterparts, except that we don't reset the geometry every time a new one is added.

On ::glAddGeometry your animation is basically free to tweak the geometry however it likes - you'll probably want to do this for grid animations and the like.

4th Phase Paint Modifications

On the 4th Phase of painting, we have our OpenGL context set up and are about to paint a texture with a fragment program - this is your last chance to do any manipulation on the passed texture for your animation (you'll get gWindow->texture, as well as the decoration texture, and friends)

Setting the update region for the next paint

Since compiz only updates certain parts of the screen on each redraw in order to save CPU usage, the animation plugin will query your animation for the appropriate bounding box to update on the next screen redraw. Most base animation classes should be able to calculate this automatically, but otherwise you should be able to specify it on ::updateBB

Getting the point of animation for different progress types

To the animation plugin, the base animation class is only updated to reflect the amount of time remaining given an initial starting time and ending time. However, there are several functions which can interpret this data and return a value from 0.0 to 1.0 representing the percentage completeness of your animation.

::progressLinear ()

Returns 1.0f - (timeRemaining / totalTime), which gives a linear animation

::progressEaseInEaseOut ()

Returns a value such that the animation accelerates in and deccelerates out

::progressDecelerate () 

Returns ::progressLinear () except slightly decelerating more as we creep towards totalTime

Other Animation Base Classes

  • TransformAnim : Base animation class to facilitate simple matrix operations on windows

  • GridAnim : Base animation class which creates a Grid and allows you to move points in that grid (thereby stretching the texture in whatever way you want)

  • PolygonAnim : Base animation class which tessellates the window texture into several polygons - each polygon can be moved independently

  • PartialWindowAnim : Base animation class which allows you to set a clip region for a window (so that only part of texture is displayed

  • ParticleAnim : Base animation class which draws particles on windows

  • RestackAnim : Base animation class which controls restacking of windows

  • MultiAnim : Special template class which allows multiple copies of windows with the same animation to be drawn, each at different points of animation

Development/zero-nine/PluginClasses/Animation/CreatingNewEffects (last edited 2010-10-17 00:30:45 by 58-7-165-35)