Inspired By Flash Math Creativity: WPF Flowers


I’ve recently picked up a great book called Flash Math Creativity.  I been inspired by some of the techniques it outlines and have played around with similar ideas in WPF.  The exercise has been a fruitful one, in that I’m making some pleasing computer art while also learning about the differences between Action Script animation and WPF animation.  The first one I played with is flowers, inspired by the work of Glen Rhodes, which is actually featured on the cover of the book.  You can see the results here and download the code here.


The first flower, which has no animation, is pretty simple. I just create 125 rectangles with a fill using a DrawingBrush I created in Blend.  I place each of the petals on the “stage”, which in the case is a Grid.  I use Grid instead of Canvas so that I get the goodness of the WPF layout engine for free without having to handle any positioning of the rectangles.  I then tranform the rotation and scale of each one to create the flower effect.  I also swap the ZIndex so that the large petals are in back and the smaller ones are in front.



void OnLoaded(object sender, EventArgs e)
{
    int r = 0;
    double s = 0;
    for (int i=0; i < 125; i++)
    {
        Rectangle rect = new Rectangle();
        rect.Width = 50;
        rect.Height = 50;
        rect.Fill = (DrawingBrush)this.FindResource(“petal”);
        TransformGroup tg = new TransformGroup();
        s += .01;
        ScaleTransform st = new ScaleTransform(s * s * s + .1, s * s * s + .1);
        r += 27;
        RotateTransform rt = new RotateTransform(r);
        tg.Children.Add(st);
        tg.Children.Add(rt);
        rect.RenderTransform = tg;
        Grid.SetZIndex(rect, -i);
        stage.Children.Add(rect);
    }
}


Where things get a little more interesting is when it comes to animating the flower. In Action Script, this kind of dynamic animation is handled through the very convenient onEnterFrame.  This handler provides a per-frame callback for each individual movie clip, in which a function can be wired up.  There is no equivalent in WPF such that you get a per-frame callback for each element.  The closest thing to this concept is the CompositionTarget.Rendering handler, which gets called per-frame for the entire tree (or page or stage, if you will.)


It is possible to find each element you are looking for when this event gets fired and achieve a similar effect to onEnterFrame.  I did just this in Page3.xaml, which ends up adding the following in addition to the loaded method:


void CompositionTarget_Rendering(object sender, EventArgs e)
{
    foreach (UIElement uie in stage.Children)
    {
        TransformGroup tg = uie.RenderTransform as TransformGroup;
        ScaleTransform st = tg.Children[0] as ScaleTransform;
        if (st.ScaleX > -3)
           st.ScaleX -= .1;
    }
}


 


You can see how I end up having to walk the tree, extracting the children and then acting on the children.  While this works, there are several disadvantages to this methodology.  First, having to figure out the animation for every UI element within a single callback has the potential to get quite unwieldy.  Second, using this method means we don’t get all of the goodness of the WPF animation system, things like frame rate indepence, timelines, storyboards, repeat behaviors, autoreverse, etc.  So, let’s see what this animation would look like using the WPF animation system:


void Page2_Loaded(object sender, RoutedEventArgs e)
{
    int r = 0;
    double s = 0;
    DoubleAnimation d = new DoubleAnimation(-3, new Duration(TimeSpan.FromSeconds(2)));
    d.AutoReverse = true;
    d.RepeatBehavior = RepeatBehavior.Forever;
    for (int i = 0; i < 125; i++)
    {
        Rectangle rect = new Rectangle();
        rect.Width = 50;
        rect.Height = 50;
        rect.Opacity = .5;
        rect.Fill = (DrawingBrush)this.FindResource(“petal2”);
        TransformGroup tg = new TransformGroup();
        s += .01;
        ScaleTransform st = new ScaleTransform(s * s * s + .1, s * s * s + .1);
        r += 27;
        RotateTransform rt = new RotateTransform(r);
        tg.Children.Add(st);
        tg.Children.Add(rt);
        rect.RenderTransform = tg;
        Grid.SetZIndex(rect, -i);
        st.BeginAnimation(ScaleTransform.ScaleXProperty, d);
        stage.Children.Add(rect);
    }
}


With this code, I get to wire up an animation to each element — in fact I’m wiring up the same animation, which simply animates the scale.  I get to use some of the features of the animation system, like AutoReverse and RepeatBehaviors.  And, I’m letting WPF calculate the timing instead of me doing it per-frame.  Much nicer, methinks.


Those seasoned with the WPF samples can probably deduce where I derived the harness you toggle between the different animations. I took the basic idea from Kevin Moore’s Bag-o-Tricks and then added the fading between frames from the custom frame in the WPF Feature Fest sample. 


I’m also now pointing all my WPF samples to an HTML page which checks to see if you have the framework installed and directs you to where you get it if you don’t.  I took this from the Windows SDK and modified to to auto-redirect if .NET 3.0 is installed.  It is included in the source.


 

Comments (7)

  1. Ericga says:

    Useless but pretty:-)

    Could WPF handle fractals?

  2. FKruesch says:

    this looks pretty!

    But I’m wondering why you guys always favor CompositionTarget.Rendering over DispatcherTimer?

    cheers

    Florian

  3. If you look under the hood of CompositionTarget with Reflector, you’ll find a Dispatcher, so really it is just a wrapper that is designed for frame callbacks, as opposed to the DispatcherTimer, which has other purposes and is a little trickier to wire up, given the different priorities one can set, etc. You are less likely to get into trouble with CompositionTarget, although you certainly can misuse/abuse/dig yourself into problems…

  4. FKruesch says:

    "If you look under the hood of CompositionTarget with Reflector, you’ll find a Dispatcher, so really it is just a wrapper that is designed for frame callbacks"

    that’s interesting, thanks!

    "…although you certainly can misuse/abuse/dig yourself into problems…"

    probably your talking about stuff like setting priority to render and not beeing able to close the window anymore? :)

    The reason I was thinking DispatcherTimer would come a little more handy is that it

    allows finer control of timing/framerate… actually that’s what I’m missing in

    CompositionTarget.Rendering.

  5. There’s actually been some good work done on this front as far as making CompositionTarget more timing/framerate friendly. Have you seen this SDK sample? http://msdn2.microsoft.com/en-us/library/ms771738.aspx It adds a timer to CompositionTarget to insure consistent behavior no matter the cpu.

  6. Kurtis says:

    Ah, yes, the re-balkanization of the Web — I love the smell of burning graphics engines in the morning.

    Just like the good-ol’, bad-ol’ days with you people, isn’t it? "Sorry, you aren’t welcome to play in our little corner of the Web". By which I mean to say: no WPF, no picture — no fallback rendering of an encapsulated static image, no indicator that that’s even possible, no attempt at accessibility, no cross-platform compatibility.

    Thanks anyway — I’ll stick with SVG and Flash, at least everyone will be able to see what I’ve made.

    Kk

  7. karstenj says:

    Kk —

    I’m interested in your (and anyone else who wants to comment) take on experiences on the web that only run on Windows.  Would this be less offensive if it launched a Windows app instead of running inside the browser?

    Also, have you heard of WPF/e?  Runs on a Mac, is entirely text based (javascript + xml) meaning indexable and transparent.