Fantasia Lite: New Silverlight Painting Tool

Jul 22, 2010

Edit: Fantasia Painter (full version), is now available here: http://fantasia.nokola.com

Edit 2: The Fantasia Lite version below, has been updated to include the new Rainbow brush (source code included too).

Here’s what I built tonight – a drawing tool that utilizes procedural brushes to enable almost everyone to create fluffy rabbits like this:

rabbit

Note that it took me about 2 minutes to “build the rabbit”. I’m sure someone else can do better. Supposedly, it lives in the hole on the right.

Here’s the live app:

As usual: Download source code

Note that this whole thing is inspired by http://mrdoob.com/120/Harmony (HTML5 – doesn’t work in IE8 as I write this) which was originally inspired by http://www.zefrank.com/scribbler/gallery/index_ran.html. By the way, make sure to check the funny videos “How To Dance Properly” on Ze’s page: http://www.zefrank.com/invite/swfs/index2.html

I talked way back (March or something) with Mr. Doob and he released his Harmony code under the MIT license. His latest source code is now released under GPL though. I didn’t look at it since I wanted my sources to be MS-PL license-able.

What Is A Procedural Brush?

A typical “brush” will just draw whatever it is supposed to draw (e.g. connect dots with lines). It just needs the current and previous mouse position.

A procedural brush is “smarter”, since it takes more variables into account.

Fantasia’s brushes make use of the following data to modify the drawing output:

  • mouse position
  • velocity (how fast the mouse moved)
  • time between 2 consecutive dots
  • distance between dots
  • slope (angle) of the line between the last and current dot
  • the last N previous dots (N varies between 2 and 100000)

The Fantasia brushes modify these outputs:

  • Color (e.g. color can be changed based on angle which can produce cool output – I haven’t published this brush yet)
  • Opacity (the faster you move, the less visible the trace is, such as in the OldPen sample
  • Stroke width (again can be controlled by speed, or maybe by slope (angle), which produces a nice caligraphy effect)
  • Drawing other random lines

Here is the source code of few of the brushes:

The Line Brush – same as a “regular” brush, just connects dots with straight lines:

public override void Stroke(double x, double y, double dx, double dy, double timeMsec, double distance)
{
    _surface.Render(new Line() { X1 = _prevX, Y1 = _prevY, X2 = x, Y2 = y, Stroke = _brush }, null);
}

The Old Pen brush, uses velocity = distance / time, to modify the color intensity:

public override void Stroke(double x, double y, double dx, double dy, double timeMsec, double distance)
{
    _surface.Render(new Line()
    {
        X1 = _prevX,
        Y1 = _prevY,
        X2 = x,
        Y2 = y,
        Stroke = new SolidColorBrush(
            new Color()
                {
                    A = (byte)(255 - distance / timeMsec * 100),
                    R = (byte) (_color.R * (distance / timeMsec * 100)),
                    G = (byte) (_color.G * (distance / timeMsec * 100)),
                    B = (byte) (_color.B * (distance / timeMsec * 100)),
                })
    }, null);
}

The History brush, most complex so far and used for the sketch and Furs:

public override void Stroke(double x, double y, double dx, double dy, double timeMsec, double distance)
{
    _points.Add(new Point(x, y));
    if ((Memory > 0) && (_points.Count > Memory)) _points.RemoveAt(0);

    _surface.Render(new Line() { X1 = _prevX, Y1 = _prevY, X2 = x, Y2 = y, Stroke = _solidBrush }, null);

    foreach (Point p in _points)
    {
        double cdx = p.X - x;
        double cdy = p.Y - y;

        double dist2 = cdx * cdx + cdy * cdy;

        if ((dist2 < _activationDistance2) && (_random.NextDouble() > (dist2 / (_activationDistance2 * ActivationChance))))
        {
            _surface.Render(new Line() { X1 = x + cdx * ReachSource, Y1 = y + cdy * ReachSource, X2 = p.X - cdx * ReachDest, Y2 = p.Y - cdy * ReachDest, Stroke = _stroke }, null);
        }
    }
}

The history brush can also do internal highlights if the _stroke is set to a LinearGradientBrush.

There is also a prototyping Test brush: I’m trying to “smoothen” the line as it is getting drawn. It’s using binaries by Charlez Petzold: http://www.charlespetzold.com/blog/2009/01/Canonical-Splines-in-WPF-and-Silverlight.html

Hope you like it! Please comment!

  
blog comments powered by Disqus

nokola.com | Terms | Log in

Recent

About the author

Happy & enjoying life. Software enthusiast.
The opinions I express here and on nokola.com are mine and not my employeer's (Microsoft).
This is the official blog of nokola.com. You can find Silverlight samples, coding stuff, and hopefully other interesting things here.