Today was the last day for me over at Objectware. It was a day I have dreaded somehow for a while. I really loved it at Objectware. Due to the fact that it is about 2 hours by bus or train away from where I live, it got to be too much of a strain on my family. I got an opportunity some months back to join a company called Bouvet and join them on establishing in my town; Sandefjord. So the choice was kind of obvious and at the same time gave me a bit of sadness. On average I've been holding jobs for some 3-4 years before changing, and everytime its been because I wanted to, for personal growth. But family has to come first, even though it was short run (some 8 months). Still, it feels kind of odd, leaving a place I got fond of with great colleagues and very fun projects.
I must take this time to thank Objectware for giving me the opportunity – I've had great personal growth and has had really fun challenges and projects. And the colleagues impresses me with their great knowledge and commitment to the job. Kudos!
15th of June, I'll be starting at Bouvet – looking forward for new challenges.
Until then, I'll be sunbathing in Spain, enjoying some time off with my kids and wife.
UPDATE, July 5th 2009: read about Silverlight 3 optimizations here and the alpha release here.
Ever since I started the Balder project back in 2007, the main goal has always been to get proper texturemapping support in the engine. At one point I had it all up and running by utilizing the Silverlight Matrix transformations for the brush used to make it scale and skew according to the given texture coordinates.
The problem was speed. I never really figured out what the speed issue was, but I guess the architecture of Silverlight was never built with 3D graphics in mind.
With the new software rendering technique in place, it is a lot easier to get different drawing techniques up and running. One drawback we ran into when doing everything with "software", we can't utilize the imaging support, such as the PNG decoder that Silverlight has built in, there is no way to get hold of the pixel data. So, the first thing we needed is to have a C# decoder og image data and we started off with PNG. Looking for an existing PNG decoder entirely written in managed code (C# preferably) turned out to be quite an interesting task. After some time googling, I finally came across a project called PR2 that has something called SharpPNG. After bending the code a bit, I got it running in a more generic way and put it in the Balder repository (with all credits intact – ofcourse).
After getting the image loading in place, it was off to write the texturemapping support. With the generic implementation we have for doing triangle drawings at the moment, the task ended up being quite simple.
A snippet from the SimpleSpanRenderer as an illustration:
public void Texture(IBuffers buffer, Span span, Image image, ImageContext texture)
var spreadCount = span.XEnd – span.XStart;
TextureInterpolator.SetPoint(0, span.ZStart, span.ZEnd);
TextureInterpolator.SetPoint(1, span.UStart, span.UEnd);
TextureInterpolator.SetPoint(2, span.VStart, span.VEnd);
var yOffset = span.Y * buffer.Display.Stride;
var rOffset = buffer.Display.RedPosition;
var gOffset = buffer.Display.GreenPosition;
var bOffset = buffer.Display.BluePosition;
var aOffset = buffer.Display.AlphaPosition;
var bufferOffset = yOffset + (span.XStart * 4);
var depthBufferOffset = (buffer.Width * span.Y) + span.XStart;
for (var index = 0; index < spreadCount; index++)
var z = TextureInterpolator.Points.InterpolatedValues[index];
var bufferZ = (UInt32)(z * (float)UInt32.MaxValue);
var u = TextureInterpolator.Points.InterpolatedValues[index];
var v = TextureInterpolator.Points.InterpolatedValues[index];
var intu = (int)(u*image.Width)&(image.Width-1);
var intv = (int)(v*image.Height)&(image.Height-1);
Finally we had to add support for materials in the ASE file loader, I ended up spending too much time trying to figure out a good way to do it with regular expression, ending up with also adding a project by Joshua Flanagan called Readable Regular Expressions in combination with LINQ to RegEx by Roy Osherove. Both projects are now part of the Balder repository as well. The reason for adding them to the repository is for maintenance purposes, seeing that we're targeting Balder for multiple platforms. The better way would probably be to contribute to the projects so they had the modifications or support we need to have for Balder.
With all this in place, it was texturemania going on:
There is also experimental code in the Balder repository for doing spherical environment mapping. This will be part of the material system, so one does not have to think about it in the code.
UPDATE: 19th of may 2009 – Texture support is now added, read more here.
We've been hard at work the last couple of weeks to bring Balder to a point where it can be useful, not only a proof of concept for prooving that 3D can be done in Silverlight.
Our main challenge is to get a proper framerate in Silverlight. The reason for this is due to the architecture of Silverlight, there is a big cost in marshalling data between the CLR and the rendering/Xaml engine, so one has to try to limit this. Our initial plan was to generate all the polygon data needed in a 3D scene during initialization and then just turn the visibility on and off and modify the coordinates and color/brush information dynamically. Since a polygon is a dependency object and the properties we needed to modify was dependency properties, this sounded like a good plan, and it was.
My previous post showed a version using this technique, and we could get a decent framerate, but it was only flat shaded – no shading nor texturemapping.
Our next goal was then to include what is known as gouraud shading, here we ran in to a bunch of issues. First of all, how could one simulate the effect of gouraud shading in Silverlight 2, when there is no brush that has this implemented. The brushes available in Silverlight are SolidBrush, LinearGradientBrush and RadialGradientBrush. After some experiments, I ended up getting a solution working using the RadialGradientBrush. The technique I used was to have 3 polygons representing every triangle, all with different radial brushes. The brushes hotspot/origin was then set to be on the 3 points representing the triangle and then have some magical calculation for generating the correct color values and alpha values for the gradients. The result was kinda nice, allthough not entirely correct rendering.
I then started to implement it for the engine itself, but never finished it, the result before finishing it was this:
The reason for not finishing it was plain and simply speed. The FPS dropped from a solid 30 FPS to 5.
We decided then that in order for this project to survive, we needed to do something dramatic. I started then to look at how we could draw using "software" – pixeldrawing in C#. In Silverlight 3, this would be a walk in the park, seeing that there is an ImageSource called WritableBitmap, in Silverlight 2, which is still our main goal, it is not all that straight forward to do. I remembered that I had seen samples of water effects, mandelbrot and such for Silverlight 2, and the technique being used is to generate a RAW PNG file on the fly every frame and streaming this into the BitmapImage source. Joe Stegman has an excellent implementation for this here. But, being in a optimization mode, I found there was a couple of things in his solution that generated quite a bit of overhead.
First of all, there is an EditableImage class holding the buffer one can draw to, this is then encoded into a new buffer. Another thing I found to be an overhead, was the usage of two different memorystreams during the encoding. Long story short, during the weekend I decided to create what I called a RawPngStream. It is a somewhat highly optimized stream that holds a buffer one can write to. The listing of the source is to big for this post, and to much details to go into – but you'll find it over at CodePlex in the Balder.Silverlight project.
What we have done now is to introduce a general software rendering component, that is not targetting specifically Silverlight – in fact, we created it for Windows Forms first – seeing that it was easier to get things up and running there first. The last thing we've done is to implement the Silverlight specifics, with the framebuffer handling and all. The result, with a few inaccuracies in the polygon routine for now, is as follows.
I've been busy the last couple of nights doing a complete rewrite of my original SilverlightRunners project.
The reason for this was that the structure of the original project didn't agree with me, hard to write unit tests, bad structure – had the feeling of being rushed. Also, having the implementational details it had, stability was really bad. Another point was that I wanted to rebrand the project.
The new project has been called Odin (yes, I know – what is going on with all this Norse Mythology fetish I seem to have..) and is located on Codeplex.
For the time being there is a 0.4 release, with an MSI file for easier installation. The current version only has limited support for running the unit tests through commandline. I am working hard these days to complete the 0.5 release to have a feature full execution engine for running tests and full commandline support. Then I'll be moving on to recreating the resharper support, targetting R# 4.5.