I just finished my first Silverlight 2 Beta application. You can see the demo here. I started by writing a simple physics demo using C# and WinForms. I then ported this to WPF and from there ported it to Silverlight. I've tested the Silverlight version on IE 7, Firefox 3.0.1 and Safari on the Mac. It appears to run exactly the same in all browsers. The WPF version appears to run slightly better than the Silverlight version.

WinForms to WPF

I only had to make two changes to the code to port from WinForms to WPF.

  1. Animation Loop. In the WinForms version, the animation loop is implemented using a custom application run loop and some timing code. In WPF the animation loop is implemented by hooking up to the Composition Target Rendering event.
  2. Triangle Rendering. In the WinForms version, the Graphics object (provided by the form Paint method) was referenced directly to fill traingles. In the WPF version, I refactored this out to a Renderer interface and implemented a custom WPF version that added polygons to the Children container of a canvas object.

The WinForms animation loop looks like this.

while (!isClosing)
{
    long frameStartTime = GetTime();
 
    Application.DoEvents();
    _form.UpdateForm(ref isClosing, IntervalInMilliseconds);
 
    long sleepTime = CalculateSleepTime(frameStartTime);
    Thread.Sleep((int)sleepTime);
}

The code below shows the WPF version. Notice the Rendering method is hooked up to the Composition Target Rendering event.

public Window1()
{
    InitializeComponent();
    CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
 
    _viewPort = new ViewPort(90, 400, 400);
    _simulation = new SimulationEngine(_viewPort);
    _intervalInMilliseconds = 16;
}
 
void CompositionTarget_Rendering(object sender, EventArgs e)
{
    _simulation.run(_intervalInMilliseconds);
    _simulation.paint(new WpfRenderer(myCanvas));
}

The Renderer interface and WPF version are shown below. This code shows how to draw triangles at a very high level in WPF. A more efficient way to do this would be to use the Visual Layer directly.

public interface Renderer
{
    void BeginRender();
    void EndRender();
    void DrawTriangle(Point[] points, Color color);
}
 
public class WpfRenderer : Renderer
{
    private Canvas _canvas;
 
    public WpfRenderer(Canvas canvas)
    {
        _canvas = canvas;
    }
 
    public void BeginRender()
    {
        _canvas.Children.Clear();
    }
 
    public void EndRender() { }
 
    public void DrawTriangle(Point[] points, Color color)
    {
        Polygon triangle = new Polygon();
 
        triangle.Points = new PointCollection(points);
        triangle.Fill = new SolidColorBrush(color);
 
        _canvas.Children.Add(triangle);
    }
}

WPF to Silverlight 2 Beta

Silverlight seems to be converging with WPF slowly but surely. Although, porting to Silverlight wasn't as straight forward as porting to WPF. I had to make two additional changes to the code to port from WPF to Silverlight.

  1. Again, the animation loop. I've been told that when Silverlight 2 is finally released it will have the same Composition Target Rendering event support as WPF. Currently it does not, so I used a customised StoryBoard to implement the animation loop. This approach seems to be quite common.
  2. The Winforms/WPF version uses the XmlSerializer to load the 3D mesh data. As far as I can see, XmlSerializer is not supported in Silverlight 2 Beta (the project refused to accept a reference), so I rewrote the loader using XDocument instead.

The code below shows the main parts of the Storyboard.

public StoryboardAnimationLoop( FrameworkElement parent, double frameDuration )
{
    _animationLoop.Duration = TimeSpan.FromMilliseconds( frameDuration );
    _animationLoop.SetValue( FrameworkElement.NameProperty, "animationloop" );
    parent.Resources.Add( "animationloop", _animationLoop );
    _animationLoop.Completed += new EventHandler( animationLoop_Completed );
}
 
void animationLoop_Completed( object sender, EventArgs e )
{
    if( _stopped )
        return;
    base.Tick();
    (sender as Storyboard).Begin();
}

The demo uses my own physics code and 3D pipeline. I'm not using any external libraries. If you're not experienced with writing physics code or 3D code for that matter, never fear. Check CodePlex for some open source libraries to help get you started if this is the type of application you're interested in writing.

Comments