News

( My personal website has gone to dust, any links thereto will fail. This site will be home for a while. )

Tuesday, 9 February 2010

PyClutter recipes.

Here are a few scripts using pyClutter 1.0 that I have recently finished. They are only for demonstrating some of the abilities of Clutter -- which I must say is just awesome!

Clipping actors (and groups of groups of... etc.) into a path shape
So, you have a shape and you want to force all the children in that Group (groups are Actors) to show within that path? Here you go:
import clutter
from clutter import cogl

"""
pyClutter 1.0
Demonstration of how to clip groups to a path.
"""

zoom = 1
def zoomify(obj,evt):
global zoom
if evt.direction == clutter.SCROLL_UP:
zoom += .1
else:
zoom -= .1
# When the zoom gets small, the cogl clip goes all wonky...
obj.set_scale(zoom, zoom)

class ClipGroup(clutter.Group):
""" Custom Group to perform clipping from a path."""
# Vital line.
# Registers the specified Python class as a PyGTK type.
# Also enables the do_paint method. I am not sure why...
__gtype_name__ = 'ClipGroup'

def __init__(self,w,h):
clutter.Group.__init__(self)#,*args)
self.width, self.height = w, h

def do_paint(self):
# Draw a triangle.
cogl.path_move_to(self.width / 2, 0)
cogl.path_line_to(self.width, self.height)
cogl.path_line_to(0, self.height)
cogl.path_line_to(self.width / 2, 0)
cogl.path_close()
# Start the clip
cogl.clip_push_from_path()

# errr.. the idea is to have the other stuff in the group
# get painted -- I assume Group knows what to do.
clutter.Group.do_paint(self)

# Finish the clip
cogl.clip_pop()

def main():
stage = clutter.Stage()
stage.set_size(500, 500)
stage.set_color(clutter.color_from_string("#000"))

rect_red, rect_green, rect_blue, rect_bounce = \
clutter.Rectangle(), clutter.Rectangle(), clutter.Rectangle(), clutter.Rectangle()

# We make two of our special groups.
clipped_group = ClipGroup(300,300)
inner_group = ClipGroup(100,100)

rect_red.set_position(0, 0)
rect_red.set_size(550, 550) #Big to be backdrop.
rect_red.set_color(clutter.color_from_string("#FF0000FF"))

rect_green.set_position(120, 10)
rect_green.set_size(50, 50)
rect_green.set_color(clutter.color_from_string("#00FF0090"))

rect_bounce.set_position(0,0)
rect_bounce.set_size(500,20)
rect_bounce.set_color(clutter.color_from_string("#AABBCCFF"))

clipped_group.add(rect_red, rect_green)
clipped_group.add(inner_group) # Add entire inner_group into clipped_group

rect_blue.set_color(clutter.color_from_string("#0000FF90"))
rect_blue.set_size(50, 50)
rect_blue.set_position(50,50) #relative to inner_group...
inner_group.add(rect_blue) # even though this comes after set_position...

clipped_group.set_position(100, 100)
inner_group.set_position(100,50)

stage.add(rect_bounce)
stage.add(clipped_group)

# Make rect_blue move around somewhat.
path = clutter.Path('M 0 0 L 40 0 L 40 40 L 0 40 Z')
timeline = clutter.Timeline(4000)
timeline.set_loop(True)
alpha = clutter.Alpha(timeline,clutter.EASE_OUT_SINE)
p_behaviour = clutter.BehaviourPath(alpha, path)
p_behaviour.apply(rect_blue)
timeline.start()

# Make rect_bounce go up and down
animation = rect_bounce.animate(clutter.EASE_IN_OUT_BOUNCE, 2000, "y", 500)
animation.set_loop(True)

# Start the main clipped_group rotating around the Y axis. For giggles.
timeline = clutter.Timeline(15000)
timeline.set_loop(True)
alpha = clutter.Alpha(timeline, clutter.LINEAR)
r_behave = clutter.BehaviourRotate(clutter.Y_AXIS, 0.0, 360.0, alpha=alpha)
r_behave.set_center(150, 0, 0)
r_behave.apply(clipped_group)
timeline.start()

stage.show_all()

stage.connect('key-press-event', clutter.main_quit)
stage.connect('destroy', clutter.main_quit)
stage.connect('scroll-event', zoomify)

clutter.main()

if __name__ == '__main__':
main()
Adventures in Time(line)
I wanted to see for myself how Timelines could be controlled from a Score. This is very cool. Here, three rectangles fire in sequence given markers in their timelines. It sounds complicated, but the code should be easy to follow:
import clutter
from clutter import cogl

def main():
stage = clutter.Stage()
stage.set_size(500, 500)
stage.set_color(clutter.color_from_string("#000"))

rect_red, rect_green, rect_blue = \
clutter.Rectangle(), clutter.Rectangle(), clutter.Rectangle()

rect_red.set_position(30, 30)
rect_red.set_size(20, 20)
rect_red.set_color(clutter.color_from_string("#FF0000FF"))

rect_green.set_position(100, 100)
rect_green.set_size(50, 50)
rect_green.set_color(clutter.color_from_string("#00FF0090"))

rect_blue.set_color(clutter.color_from_string("#0000FF90"))
rect_blue.set_size(80, 80)
rect_blue.set_position(200,200)

stage.add(rect_red, rect_green, rect_blue)

t_red=clutter.Timeline(10000)
t_green=clutter.Timeline(5000)
t_blue=clutter.Timeline(5000)

a_blue=clutter.Alpha(t_blue,clutter.EASE_OUT_SINE)
a_green=clutter.Alpha(t_green,clutter.EASE_OUT_SINE)
a_red=clutter.Alpha(t_red,clutter.EASE_OUT_SINE)

b_red = clutter.BehaviourRotate(clutter.Z_AXIS, 0.0, 360.0, alpha=a_red)
b_green = clutter.BehaviourRotate(clutter.Z_AXIS, 0.0, 360.0, alpha=a_green)
b_blue = clutter.BehaviourRotate(clutter.Z_AXIS, 0.0, 360.0, alpha=a_blue)

b_blue.apply(rect_blue)
b_green.apply(rect_green)
b_red.apply(rect_red)

s=clutter.Score()

t_red.set_loop(True)
s.append(t_red)
t_red.add_marker_at_time("go_green",2000)
s.append_at_marker(t_red,"go_green",t_green)
t_green.add_marker_at_time("go_blue",5000)
s.append_at_marker(t_green,"go_blue", t_blue)

stage.show_all()
s.start()

stage.connect('key-press-event', clutter.main_quit)
stage.connect('destroy', clutter.main_quit)

clutter.main()

if __name__ == '__main__':
main()

No comments: