image

DirectCanvas is a hardware accelerated, 2D drawing API for .NET.  It’s goals are to use Direct3D10, Direct2D, DirectWrite, DirectShow, Windows Animation Manager and WIC to create a single API for high performance drawing.  By leveraging these APIs it is possible to create anti-alias vector graphics, high quality text, multimedia, extensible pixel-shaders, animation and imaging.

You can watch some of the demo videos here.

Background

When IE9 platform preview was first released, they mentioned they would be leveraging Direct2D for high performance, hardware acceleration of web pages.  I was always curious about Direct2D, but never bothered to getting around to learning it.  This was a great time to see what Direct2D could do.

Running a few of the IE9 test drive applications, I was totally convinced.  I was convinced Direct2D is very fast.  I was convinced IE9 is going to be a fantastic product.  And beyond everything, I was convinced that HTML5 Canvas is going to be huge!

If you aren’t familiar with HTML5 Canvas, it’s an immediate mode, 2D drawing API.  It provides no notion of buttons, click events, mouse moves, etc.  It just lets you draw vectors, video and images.  So what good is it for developers?  For making painting programs?  This is what many developers ask when first exposed to the HTML5 Canvas.  They are used to having a premade UI framework ready to go.  HTML5 Canvas is powerful in the respect that it’s a least-common-denominator for user-interface.  This will allow the web community to build their own UI frameworks to fit their needs.  No longer will web applications be confined to the rules of the DOM to build UI.

As IE9 platform preview progressed, I started seeing amazing demos popup.  Some of which were very immersive, but also very fast…and in many cases, the UI was either impossible to make in Silverlight/WPF or just wouldn’t be able to run with the same performance.  Doing a lot of reflecting on this,  I started thinking, “Why don’t .NET developers have an API like this?  Why do I have to use JavaScript to get high performance?  The irony.”  This is where I decided there was a need something like this, and because we aren’t restricted by Javascript, we can get an even better result.

Why DirectCanvas?  Why not XNA?

XNA is a very good framework around Direct3D9 (and D3D11 if you consider WP7).  It’s mainly used for prototyping and indie game creation.  Because it does not use a WDDM version of D3D, it is impossible to get good performance out of using Direct2D.  It also is pretty high level, so it does not allow for the flexibility we want for building DirectCanvas.

Why not just use something like SlimDX?

Actually, I am using SlimDX and maybe SharpDX in the future.  There is a difference between having access to a .NET wrapper for a native API and creating a higher level library that attempts to unify five or six lower level subsystems.  Direct2D by itself is moderately easy, but limited.  Once you need to do more than Direct2D allows, you have to get involved in the low level Direct3D nitty-gritty.  DirectCanvas aims to hide that all away.

The DirectCanvas Library

Development of DirectCanvas started with reading tons of Direct3D books and countless blog posts and SDK samples.  There was also a lot of research into Direct2D, but knowledge of this subject was restricted to PDC videos, blog posts and SDK samples.  The first real piece I invested in was something I call the “Compositor”.

The DirectCanvas Compositor

The compositor is really just a glorified sprite batcher.  I like to think of it more than just that because it’s extremely optimized for GPU usage and allows for simple 3D transforms like Silverlight has.  To give an example, XNA has a sprite batcher, and you may get 10k or 20k sprites at 60FPS.  The compositor should give you 5 – 10x the performance (110k sprites @ 40fps on my machine).  This is because we offload all matrix operations to the GPU, only sending primitive uncalculated transforms.  We also can use up to 16 textures (artificial limit) as inputs before causing a flush on the compositor.  There are a few other advantages to the compositor, but mostly forward thinking stuff, such as allowing for simple lighting, which will come for “free”

The DirectCanvas Factory

The DirectCanvas factory is your “root” object for creating many resources, such as brushes, media players, drawing layers, geometry, etc.  All resources created by the factory can be used with any drawing layer created by the factory.

The DrawingLayer

A drawing layer is simply a bitmap, but it exists on your GPU.  The drawing layer is where you draw vector graphics and images, video and effects.

The Presenters

A presenter is technically a subclass of a DrawingLayer.  But it is kind of special because it allows “presenting” your DirectCanvas to a given technology.  Right now there is  WindowsFormsPresenter and a WPFPresenter.

Primitives, Geometry and Transforms

Primitives and Geometry are almost directly analogous to Primitives and Geometry in Direct2D.  A primitive is essentially most of the “drawingLayer.Draw/FillShape” methods.  Geometry can use the GeneralTransform class.  This is a rip-off of WPF’s transformations.  So you have a RotateTransform, ScaleTransform, TranslateTransform and a TransfromGroup.  The primitives can accept a GeneralTransform as a parameter.

Brushes

Right now DirectCanvas supports a solid color, linear gradient, radial gradient, bitmap and video brush.

In Direct2D, all brush coordinates are aligned to the render target in which you are drawing to.  This is good, but that leaves us doing a lot of tedious and redundant code to transform our brush to match the transform of our geometry.  I wanted to make things a little easier (hopefully).

The “Brush” base class has an Alignment property of the BrushAlignment enum:

public enum BrushAlignment
{
    DrawingLayerAbsolute,
    DrawingLayerRelative,
    GeometryAbsolute,
    GeometryRelative
}

DrawingLayerAbsolute – The Brush is aligned to the drawing layer axis and is not scaled to match the drawing layer bounds.  This is basically the D2D default.

GeometryAbsolute – The Brush is aligned to the geometry axis being drawn and is not scaled to match the geometry bounds.

DrawingLayerRelative – The brush is aligned to the drawing layer axis and scaled to match the drawing layer bounds.

GeometryRelative – The brush is aligned to the geometry axis being drawn and scaled to match the geometry bounds.

VERY IMPORTANT:  When using DrawingLayerRelative or GeometryRelative on a brush, the values given to your GeneralTransform (Brush.Transform, which would be rotate, scale, translate or transfrom group) are RELATIVE also.  So a rotate transform with a CenterX of 0.5 and CenterY of 0.5 will be the center of the drawn geometry or drawing layer.  Same goes for scale, translate, etc.

 image

Multimedia

DirectCanvas supports video playback and will use hardware accelerated decoding if available.  To use it, simply create a media player from the DirectCanvasFactory, give it a media file path and tell it to play.  Once playing you can paint it directly onto a DrawingLayer or create a VideoBrush and use it as a brush.  In the future I aim to make this API extensible and add webcam support.

Text

Work in progress Smile.  But it will use the awesome, high quality DirectWrite API!

Closing

I still consider the DirectCanvas library experimental and do not recommend building anything off it just yet.  But if you are curious of what your computer is really capable of, give it a spin.  You can find it on codeplex here:  http://directcanvas.codeplex.com

-Jeremiah