Ideal Binary

by Aidan Doolan 8/23/2009 2:40:27 AM 2 Comments

Well it’s been almost a year since I updated this blog! I’ve been pretty busy working at Pocket Kings here in Dublin.

Almost two years ago I decided to take a break from game/engine/porting development. I started researching web development technologies, in particular Rails, ASP.NET MVC, and Silverlight. After 10 months (and an MCTS) I started working for Pocket Kings as a Web Developer.

Essentially I wanted to ground the research I had done with some practical experience. And practical experience I got, in addition to a years experience using SCRUM in an agile development process. All together, the last two years have been an amazing learning experience.

On the 28th of this month I finish up at Pocket Kings and from September 1st I’ll be working with my brother at our own company, Ideal Binary. I intend to keep this blog alive, but not with technical posts. These will be published on my new Ideal Binary blog.

I hope you drop by and check out Ideal Binary.


My brother wrote a slick  lens panel control with Silverlight 2 recently. He modeled it on the look and behaviour of the Mac OSX Leopard dock. It was so slick, I had to write my own implementation. You can check it out here. After I got it up and running we decided to do a kind of distributed (by about 800 miles) pair programming session to see if we could come up with cleaner ways to structure our lens panel controls.

I'm not going to go into the low-level implementation details in this article. The behaviour of the control is pretty much the same as the Mac dock control. Kevin has described the high-level approach we ended up with on his own blog, but I will highlight some features of XAML we used to make the lens panel controls more easily extendable.

When we finished refactoring our code, both of our lens panel controls ended up making use of the ItemsControl, data templates, data binding and dependency injection though XAML, but neither of our controls started out that way.

Aidan's Mac OSX Leopard dock style Silverlight control

Dependency Injection

The first structural decision I made when I got far enough in to the code to start displaying items was to try to separate the source of the panel items from the lens panel control itself. The most basic way to do this is have a base class with the generic lens panel behaviour baked in, and then maybe derive versions for showing lens panel items from various different sources like Flickr, iStockPhoto, or custom menu items.

While this approach works, it tightly couples the base lens panel class with all other derived lens panels. What if you wanted to further customise the lens panel to display the individual items differently? You could derive some more classes with the new visuals baked in but again, this tightly couples even more classes together.

My first solution to this problem was to separate out each of the responsibilities into their own classes. The LensPanel class contained the logic to arrange and display the panel items. The LensPanel had a public property of type IPanelItemProvider. This allowed me to implement any number of concrete providers without directly coupling them to the lens panel control itself.

In addition to this, the providers contained a public property of type IPanelItemVisualFactory. This allowed me to further decouple the visual aspects of the panel items from the provider. All of these dependencies can be injected directly using XAML. Below is roughly how my first solution looked.

<LensPanel:LensPanel Width="1000" Height="300" NumberOfItems="12" >
    <LensPanel:LensPanel.PanelItemProvider>
        <LensPanel:iStockPanelItemProvider>
            <LensPanel:iStockPanelItemProvider.PanelItemVisualFactory>
                <LensPanel:ReflectionPanelItemVisualFactory />
            </LensPanel:iStockPanelItemProvider.PanelItemVisualFactory>
        </LensPanel:iStockPanelItemProvider>
    </LensPanel:LensPanel.PanelItemProvider>
</LensPanel:LensPanel>

The above solution has some nice benefits to offer. First, it makes use of the Single Responsibility Principle (SRP). Each of the objects has a single clear responsibility. The lens panel only lays out panel items. The panel item provider only provides panel items. The panel item visual factory only creates panel item visuals. Second, it also makes use of the Open/Closed Principle (OCP). This means that the solution is open for extension (by creating new concrete provider and factory objects) but closed for modification (providing new concrete providers and factories requires no modification of the base control). Third, this solution is very unit testable.

But it turns out there's a much simpler way to implement the same separation of concerns by exploiting several features already built-in to Silverlight 2.

Data Binding And Templates

Rather than creating the provider interface, IPanelItemProvider, and then managing the connection of the items from the provider with the items in the lens panel, we decided to exploit Silverlight's data binding support. Both of our controls derive from the Panel class and it wasn't immediately obvious how we were going to bind directly to an items list within the panel. Kevin discovered the ItemsControl which makes this very simple.

The ItemsControl allows you to create a panel control where you can specify a panel template for the type of panel you want, in addition to a data template for the individual panel items. With only a small amount of refactoring, and without losing any of the benefits of our earlier approaches, we had reworked our solutions to use the ItemsControl. Below you can see I'm creating an ItemsControl and specifying my custom LensPanel class as the panel template and my custom LensPanelItem class for the item template.

<ItemsControl x:Name="_lensPanelControl" ItemsSource="{StaticResource iStockPhotoProvider}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <l:LensPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <l:LensPanelItem />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

In addition to specifying the templates for the panel and panel items, I'm also binding the ItemsControl to an instance of the iStockPhotoProvider declared in the local resources. I chose to derive the iStockPhotoProvider directly from ObservableCollection so that once it is bound to the ItemsControl, any modifications to it result in an update of the ItemsControl. Again, this provides the same benefits as before. The provider is loosely coupled to the lens panel control. Below is the declaration for the concrete photo provider.

<UserControl.Resources>
    <l:iStockPhotoProvider x:Key="iStockPhotoProvider" />
</UserControl.Resources>

This makes it possible for a designer to swap out the provider with different providers by simply modifying the XAML. No code changes are required.

Conclusion

So far, I've been very impressed with WPF and Silverlight 2. It's very obvious that the features of these frameworks are based on solid practical foundations. I found Chris Anderson's book Essential Windows Presentation Foundation (WPF) (Microsoft .NET Development Series) to be an excellent guide to exploring how to use these features in practical ways. Also, he describes at a low level (and in very simple terms) the motivation behind some of these features and exposes details about their implementation. This was a big help in transitioning from a Windows Forms way of thinking to the more modern approach suggested by WPF and Silverlight 2.


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.


I had to review some physics code for a client recently. Although the physics model being used was very simple point physics, the code was quite long and the algorithms were not immediately obvious. This tends to happen when code isn't refactored as it is modified and extended.

I made a few suggestions about the code, one of which was to try and wrap the underlying math routines in unit tests. This is a really simple way to catch bugs that can otherwise result in strange behavior, like the ball disappearing or missing collisions. It also lays the foundation for performing code refactoring that can dramatically improve the quality of the code.

As a little test, I decided to write a small physics project to illustrate this in action.

Scope Of The Project

I didn't want to write a full physics engine for this test. I've written one before and it's not a small undertaking. Then I remembered an old Amiga demo I saw a million years ago that had a soft-body jelly vector object contained within a spinning cube. No, I can't for the life of me remember the name of the demo. I decided to try to recreate it in C# and then use unit tests and code refactoring to clean up the code.

softbody1

Cleaning Up The Code

The idea was simple. Write the most flat unstructured code and get it up an running. This code base represents the 'mess' that has to be cleaned up and refactored. Even basic code refactoring can have a dramatic effect on this code. Have a look below.

// Apply spring force
for (int l = 0; l < _jellyLines.Length / 2; l += 1)
{
    int line = l * 2;
    int vertex1 = _jellyLines[line] * 3;
    int vertex2 = _jellyLines[line + 1] * 3;
 
    // Get Spring length 
 
    float x1 = _jelly_os[vertex1];
    float y1 = _jelly_os[vertex1 + 1];
    float z1 = _jelly_os[vertex1 + 2];
 
    float x2 = _jelly_os[vertex2];
    float y2 = _jelly_os[vertex2 + 1];
    float z2 = _jelly_os[vertex2 + 2];
 
    float lineRestLength = _jellyLineLengths[l];
    float lineLength = (float)Math.Sqrt((z2 - z1) * (z2 - z1) + (y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
 
    // Get Relative Velocity of both end points
 
    float rvx = _jelly_velocity[vertex2] - _jelly_velocity[vertex1];
    float rvy = _jelly_velocity[vertex2 + 1] - _jelly_velocity[vertex1 + 1];
    float rvz = _jelly_velocity[vertex2 + 2] - _jelly_velocity[vertex1 + 2];
 
    float relativeVelocity = (float)Math.Sqrt(rvz * rvz + rvy * rvy + rvx * rvx);
 
    // Calculate Spring Force
 
    float force = _springK * (lineLength - lineRestLength) - _springB * relativeVelocity;
 
    // Get Spring Vector
 
    float vx = _jelly_os[vertex2] - _jelly_os[vertex1];
    float vy = _jelly_os[vertex2 + 1] - _jelly_os[vertex1 + 1];
    float vz = _jelly_os[vertex2 + 2] - _jelly_os[vertex1 + 2];
 
    // Normalise
 
    float vl = (float)Math.Sqrt(vz * vz + vy * vy + vx * vx);
    vx = vl != 0.0f ? vx / vl : 0.0f;
    vy = vl != 0.0f ? vy / vl : 0.0f;
    vz = vl != 0.0f ? vz / vl : 0.0f;
 
    // Apply force to both ends of the Spring
 
    _jelly_force[vertex1] += vx * -force;
    _jelly_force[vertex1 + 1] += vy * -force;
    _jelly_force[vertex1 + 2] += vz * -force;
 
    _jelly_force[vertex2] += vx * force;
    _jelly_force[vertex2 + 1] += vy * force;
    _jelly_force[vertex2 + 2] += vz * force;
}

I've made no attempt to use any OO design at all in the above code. It iterates over the lines/springs making up our soft-body jelly object and applies the spring forces to both ends of the spring. It stinks of many of the classic bad code smells. After a afternoon of refactoring the code for the entire project, the above code ended up as follows.

public void ApplyForceToEndPoints(PointMass[] points)
{
    Vector3 springVector = GetSpringVector(points);
    Vector3 relativeVelocityVector = GetEndPointsRelativeVelocityVector(points);
    Vector3 springForceVector = GetSpringForceVector(springVector, relativeVelocityVector);
 
    points[Point1].Force -= springForceVector;
    points[Point2].Force += springForceVector;
}

For a start the refactored code above is a lot smaller. This is because duplicate functionality has been extracted along with operators and methods and classes. Notice also that this method is a class method and operates on only one spring and not an array of springs. Finally, the need for comments is gone thanks to the new refactored method names.

Another example is shown below.

// Integrate
for (int v = 0; v < _jelly_os.Length / 3; v += 1)
{
    int vertex = v * 3;
 
    // Assume mass is 1.0, apply acceleration
    _jelly_velocity[vertex] += _jelly_force[vertex] * interval / 1000;
    _jelly_velocity[vertex + 1] += _jelly_force[vertex + 1] * interval / 1000;
    _jelly_velocity[vertex + 2] += _jelly_force[vertex + 2] * interval / 1000;
 
    // Apply velocity
    _jelly_os[vertex] += _jelly_velocity[vertex];
    _jelly_os[vertex + 1] += _jelly_velocity[vertex + 1];
    _jelly_os[vertex + 2] += _jelly_velocity[vertex + 2];
}
 
// Clip vertices
for (int v = 0; v < _jelly_os.Length / 3; v += 1)
{
    int vertex = v * 3;
 
    float x = _jelly_os[vertex];
    float y = _jelly_os[vertex + 1];
    float z = _jelly_os[vertex + 2];
 
    for (int p = 0; p < _cubePlanes_ws.Length / 4; p++)
    {
        int plane = p * 4;
 
        float px = _cubePlanes_ws[plane];
        float py = _cubePlanes_ws[plane + 1];
        float pz = _cubePlanes_ws[plane + 2];
        float pd = _cubePlanes_ws[plane + 3];
 
        float clipD = px * x + py * y + pz * z;
 
        if (clipD < pd)
        {
            x += px * -(clipD - pd);
            y += py * -(clipD - pd);
            z += pz * -(clipD - pd);
 
            // Remove this vector component from the velocity vector
 
            float velocityD = px * _jelly_velocity[vertex] + py * _jelly_velocity[vertex + 1] + pz * _jelly_velocity[vertex + 2];
 
            _jelly_velocity[vertex] -= px * velocityD;
            _jelly_velocity[vertex + 1] -= py * velocityD;
            _jelly_velocity[vertex + 2] -= pz * velocityD;
        }
    }
 
    _jelly_os[vertex] = x;
    _jelly_os[vertex + 1] = y;
    _jelly_os[vertex + 2] = z;
}

The above code uses Euler integration to move the soft-body jelly object forward in time. It then clips the vertices or points of the soft-body against the planes of the cube in which it is contained. Both operations occur within for loops. The same bad code smells from earlier are also evident here.

Both of the above for loops iterate over the points of the soft-body. That's where I started when I began to refactor the code. When I was finished, I ended up with a PointMass class that housed most of the above functionality.

public class PointMass
{
    public Vector3 Point { get; set; }
    public Vector3 Velocity { get; set; }
    public Vector3 Force { get; set; }
    public float Mass { get; set; }
 
    public PointMass()
    {
        Point = new Vector3();
        Velocity = new Vector3();
        Force = new Vector3();
        Mass = 1;
    }
 
    public void Integrate(int intervalInMilliseconds)
    {
        Velocity += Force * (((float)intervalInMilliseconds / 1000) / Mass);
        Point += Velocity;
    }
 
    public void ClipToPlanes(PipelinePlane[] planes)
    {
        foreach(PipelinePlane plane in planes)
            ClipPointAndVelocityToPlane(plane.WorldPlane);
    }
 
    private void ClipPointAndVelocityToPlane(Plane plane)
    {
        float distance;
        if (!plane.IsPointInfront( Point, out distance))
        {
            Point = plane.Clip(Point);
            RemoveVectorComponentFromVelocity(plane.normal);
        }
    }
 
    private void RemoveVectorComponentFromVelocity(Vector3 vector)
    {
        float velocityDistanceAlongVector = vector.DotProduct(Velocity);
        Velocity -= vector * velocityDistanceAlongVector;
    }
}

The above code is much easier to read and is easy to debug and maintain. Again, the need for comments is largely gone.

Unit Tests

The unit test project contains 21 tests covering most of the maths routines. These tests are extremely simple and are by no means complete. But if the project is developed further, more tests can be added easily. Likewise, if bugs are found, new tests can be added to confirm the fix and ensure it doesn't pop up again.

Another benefit of having unit tests in place appears when optimizations are required. Take the Length method of the 3D Vector object as shown below.

public float Length()
{
    return (float)System.Math.Sqrt(z * z + y * y + x * x);
}

The Length method above has been implemented using the System.Math.Sqrt method. While the square root operation is accurate, it is also usually a costly one, so developers often replace the square root operation with something more efficient but less accurate. The degree to which we are willing to sacrifice accuracy for an increase in efficiency can be encoded in our unit tests by specifying a tolerance value as shown below.

[Test]
public void VectorLengthTest()
{
    Vector3 vector = new Vector3(221, 132, 40);
    
    float vectorTolerance = 0.00001f;
    float expectedLength = (float)System.Math.Sqrt(result.x*result.x + result.y*result.y + result.z*result.z);
 
    Assert.AreEqual(expectedLength, vector.Length(), vectorTolerance, "Vector Length is not within acceptable tolerance");
}

This allows us to set the boundaries within which to optimize. I used this approach before when writing a custom software version of the Mascot Capsule 3D API while at Upstart Games. I recorded the output of the math routines from Mascot Capsule and set up a series of tests with a specified tolerance. I used these tests to ensure my own pipeline produced the same values within the specified tolerance. This allowed me to emulate and optimize at the same time without breaking anything.

Conclusion

Simple code refactoring and unit testing can be powerful tools to help developers take control of their code no matter what type of software they develop. You can download the full source (including unit tests) for the project and the binaries below. Again, these are not perfect examples but they do demonstrate some of the benefits of using refactoring and unit tests.

JellyVector.zip (54.08 kb) 

JellyVector.bin.zip (11.76 kb)

[Update: The Amiga demo I referred to earlier was called Krest Mass Leftovers by Anarchy. It was released in 1992.]