Hi

As you may (skinkie) or not (hi koos) know, i am developing a video
compositing engine on top of clutter and gstreamer.

Attached is a preview (work in progress) of a simple animation wrapper
in python, with an effect example. It wraps the depth, opacity and
position behaviours. It features a "wait_for_completion" handler
(allow or not an animation to be fired before completion) and offers
some default parameters (overridable) that lets try them out fast.
It's far from complete, and it lacks a plugin architecture (on our
roadmap) but i'm very curious about what you guys may think of such an
approach.

I'd be glad to know:
* what language you will/want to develop your glSMIL player(s) in ?
* what you think of this preliminary proposal (it's not that elegant
nor scalable, yet i implemented a bunch of effects quite easily with
such wrappers)
* the thing with SMIL is that it's not taking 3D effects into account
(AFAIK). How to keep both worlds in the same rendering and compositing
engine ?
* for the SMIL effects, there are a lot of cropping-based effects, i
don't know how well clutter would perform by re-clipping incrementally
a texture using a timeline...

On my side, i am very interested in SMIL support as well, yet not only
for playback but rather for "recording"/animation archival purposes.
Please let me know when/if you join forces !

Cheers

Florent
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import clutter

class AnimatedEffectTemplate:
    # in ms:
    DEFAULT_DURATION = 3000
    DEFAULT_FPS = 30

    def __init__(self, duration=None, alphatype=None, looped=False):
        if duration is None: 
            self.duration = self.DEFAULT_DURATION
        else : self.duration = duration

        self.timeline = clutter.Timeline(fps=self.DEFAULT_FPS, duration=self.duration)

        if looped != False: self.timeline.set_loop(True)

        if alphatype is None: self.alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func)
        elif alphatype is "ramp_inc": self.alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func)
        elif alphatype is "ramp_dec": self.alpha = clutter.Alpha(self.timeline, clutter.ramp_dec_func)
        elif alphatype is "sine_inc": self.alpha = clutter.Alpha(self.timeline, clutter.sine_inc_func)
        elif alphatype is "sine_dec": self.alpha = clutter.Alpha(self.timeline, clutter.sine_dec_func)
        # TODO: changer par dict et clutter.Alpha.set_func et .set_timeline, compléter l'implémentation

class Effect:
    def __init__(self, duration, alphatype, actor, looped, wait_for_completion):
        self.actor = actor
        self.looped = looped
        self.effect_is_applied = False
        self.autoremove_active = False
        self.wait_for_completion = wait_for_completion
        self.template = AnimatedEffectTemplate(duration=duration, alphatype=alphatype, looped=looped)
        #self.effect = clutter.Behaviour()

    def on_completion_cb(self, timeline):
        self.effect.remove(self.actor)
        self.template.timeline.disconnect_by_func(self.on_completion_cb)
        self.effect_is_applied = False
        self.autoremove_active = False

    def run(self, stage, actor):
        # First call, activate effect auto-removal after completion
        if self.looped is False and self.autoremove_active is False:
            self.template.timeline.connect('completed', self.on_completion_cb)
            self.autoremove_active = True
        # Apply effect and run it
        if self.template.timeline.is_playing() is False and self.effect_is_applied is False:
            self.effect.apply(self.actor)
            self.template.timeline.start()
            self.effect_is_applied = True
        # Case where an effect not completed is called again
        elif self.template.timeline.is_playing() is True:
            if self.wait_for_completion is True:
                print "Wait for the effect to finish before issuing a new call"
            else : 
                self.template.timeline.rewind()
                self.template.timeline.start()

class OpacityEffect(Effect):
    def __init__(self, duration, alphatype, actor, looped=False, wait_for_completion=False, opacity_start=0, opacity_end=255):
        Effect.__init__(self, duration=duration, alphatype=alphatype, actor=actor, looped=looped, wait_for_completion=wait_for_completion)
        self.opacity_start = opacity_start
        self.opacity_end = opacity_end
        self.effect = clutter.BehaviourOpacity(alpha = self.template.alpha, opacity_start=self.opacity_start, opacity_end=self.opacity_end)

class RotateEffect(Effect):
    def __init__(self, duration, alphatype, actor, looped=False, wait_for_completion=False, axis=None, angle_start=None, angle_end=None, direction=clutter.ROTATE_CW):
        Effect.__init__(self, duration=duration, alphatype=alphatype, actor=actor, looped=looped, wait_for_completion=wait_for_completion) 
        self.angle_start = angle_start
        self.angle_end = angle_end
        self.x_center = self.y_center = self.z_center = 0
        if axis is None or axis is "y":
            self.axis = clutter.Y_AXIS
            self.x_center = self.actor.get_width()/2
        elif axis is "x":
            self.axis = clutter.X_AXIS
            self.y_center = self.actor.get_height()/2
        elif axis is "z":
            self.axis = clutter.Z_AXIS
            self.x_center = self.actor.get_width()/2
            self.y_center = self.actor.get_height()/2
        self.effect = clutter.BehaviourRotate(alpha = self.template.alpha, axis=self.axis, direction=direction, angle_start=self.angle_start, angle_end=self.angle_end)
        self.effect.set_center(self.x_center, self.y_center, self.z_center)

class DepthEffect(Effect):
    def __init__(self, duration, alphatype, actor, looped=False, wait_for_completion=False, depth_start=0, depth_end=100):
        Effect.__init__(self, duration=duration, alphatype=alphatype, actor=actor, looped=looped, wait_for_completion=wait_for_completion) 
        self.depth_start = depth_start
        self.depth_end = depth_end
        self.effect = clutter.BehaviourDepth(alpha = self.template.alpha, depth_start = self.depth_start, depth_end = self.depth_end)

class MoveEffect(Effect):
    def __init__(self, duration, alphatype, actor, looped=False, wait_for_completion=False, x_move_offset=0, y_move_offset=0):
        Effect.__init__(self, duration=duration, alphatype=alphatype, actor=actor, looped=looped, wait_for_completion=wait_for_completion) 

        self.knots = ( \
                (   self.actor.get_x(),   self.actor.get_y() ),   \
                ( self.actor.get_x()+x_move_offset, self.actor.get_y()+y_move_offset ),   \
        )
        
        self.effect = clutter.BehaviourPath(alpha=self.template.alpha, knots=self.knots)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author: [EMAIL PROTECTED]
# LGPL terms

import clutter
from effects import MoveEffect

class LinearHMoveOut(MoveEffect):
    def __init__(self, duration, actor, looped):
        MoveEffect.__init__(self, duration=duration, alphatype="ramp_inc", actor=actor, looped=looped, x_move_offset=400)

class LinearVMoveOut(MoveEffect):
    def __init__(self, duration, actor, looped):
        MoveEffect.__init__(self, duration=duration, alphatype="ramp_inc", actor=actor, looped=looped, y_move_offset=400)

class LinearHMoveIn(MoveEffect):
    def __init__(self, duration, actor, looped, move_offset):
        actor.set_position(actor.get_x()-move_offset,actor.get_y())
        MoveEffect.__init__(self, duration=duration, alphatype="ramp_inc", actor=actor, looped=looped, x_move_offset=move_offset)

class SineVMoveIn(MoveEffect):
    def __init__(self, duration, actor, looped, move_offset):
        actor.set_position(actor.get_x(),actor.get_y()-move_offset)
        MoveEffect.__init__(self, duration=duration, alphatype="sine_inc", actor=actor, looped=looped, y_move_offset=move_offset)

class SineMoveTo(MoveEffect):
    def __init__(self, duration, actor, looped, x_move_offset, y_move_offset):
        MoveEffect.__init__(self, duration=duration, alphatype="sine_inc", actor=actor, looped=looped, x_move_offset=x_move_offset, y_move_offset=y_move_offset)

if __name__ == '__main__':
    stage = clutter.Stage()
    stage.set_color(clutter.Color(0xcc, 0xcc, 0xcc, 0xff))
    stage.set_size(640,480)

    test_actor = clutter.label_new_with_text("Sans 22", "Test actor")
    test_actor.set_position(200,200)
    #test_move = LinearHMoveOut(duration=500, actor=test_actor, looped=False)
    test_move = SineVMoveIn(duration=500, actor=test_actor, looped=False, move_offset=400)

    #test_move = SineMoveTo(duration=500, actor=test_actor, looped=False, x_move_offset=100, y_move_offset=50)

    stage.connect('key-press-event', test_move.run)

    stage.add(test_actor)
    stage.show_all()
    clutter.main()

Reply via email to