Charles Petzold is a man who requires no introduction among MSDN Magazine readers (but if you need one, here’s my column about his 25 years of service to the magazine). Author of the definitive book Programming Windows (now in its sixth edition), he wrote the very first article about Windows programming to appear in MSDN Magazine, way back in December 1986. Charles has never been afraid to get out in front of a platform or technology he felt could make a difference, and he’s proven that once again with his DirectX Factor column, which plumbs the intriguing capabilities of the DirectX stack.
In the March issue, Charles wrote a DirectX column titled “Triangles and Tessellation,” which digs into Direct2D to unearth some surprising functionality that offers a nifty bridge into the complex world of Direct3D. I know Charles had expressed some trepidation about covering Direct3D in the past, in part because this space is so complex and involved that it can be very challenging to present to a broad developer audience. This month’s column offers a nice window into 3D concepts while still working within the 2D world of Direct2D.
I asked Charles about his experience covering DirectX, and what he discovered in his Triangles and Tessellation column. Here’s what he had to say….
I stumbled upon the triangle support in Direct2D while exploring the ID2D1Geometry interface. I was familiar with many of the concepts of geometries from the Windows Presentation Foundation and later XAML-based environments. In particular, the purpose of the Outline and Widen methods was something I had explored years ago in WPF.
But then there was this method named Tessellate that was new to me and just begged for further exploration. Just saying the word “tessellate” sounded so cool that I couldn’t resist.
There’s virtually no documentation about this stuff, but it’s pretty easy to put the pieces together. The Tessellate method requires an object that implements the ID2D1TessellationSink interface. Where do you get one of those? Well, the ID2D1Mesh will provide one. What else can you do with the ID2D1Mesh? Well, the ID2D1RenderGeometry has a method named FillMesh. So there’s the complete trail from geometry to the video display.
The real breakthrough came when I realized I could write my own class that implemented ID2D1TessellationSink, and get access to the triangles and manipulate them.
Of course, I knew how important triangles are in 3D programming, so I suspected that I might be tapping into something more lower-level than geometries. I had also been exploring Direct2D “effects,” which is a way for Direct2D code to use 3D-like shaders, and these effects also involved triangles.
Immediately I realized how useful these triangles might be. Back in the October 2007 issue of MSDN Magazine I presented some code that turned WPF text geometries into WPF 3D objects, and I could have really used the Tessellate method for that!
I had also recently been exploring doing a Windows 8 finger-painting app using Direct2D, and I wanted to implement a couple unusual gradients. I wanted a gradient that would start at the beginning of a finger-painted stroke and end at the end of the stroke. This sounds like it should be trivial, but it’s not. I also wanted a finger-paint stroke with a gradient orthogonal to the stroke direction. I had tried these things in WPF using geometries (check my blog here), but I figured having the stroke decomposed into triangles might make it easier.
I also envisioned a finger-painting program that would draw 3D strokes, and the triangles also seemed ideal for that.
Certainly for some applications, the triangles are more efficient than the geometries. But it’s not clear to me how much Direct2D coding is going on in the real world, and whether programmers are really encountering performance problems with geometries. You have to really push Direct2D to do some weird animating things before you start worrying that Direct2D geometries aren’t giving you the performance you want.
So I began thinking of the triangles from the Tessellate method as forming a bridge between Direct2D and Direct3D. One possible bridge is pedagogical: As I will demonstrate in future columns, it’s possible to move these 2D triangles that you get from the Tessellate method into 3D space, and perform 3D manipulations on them, mimicking 3D entirely within the confines of Direct2D. The Direct2D effects provide even more of a bridge. This pedagogical bridges allow programmers to become more familiar with 3D concepts within the relative comfort of Direct2D without the scary plunge into Direct3D.
For me, this immersion into DirectX has been one of the most challenging exercises of my programming career, and consequently one of the most rewarding. This is a programming environment that allows application code to sneak into odd corners of the graphics pipeline and do tasks that are just inconceivable otherwise.
For example, suppose you wanted to apply a squiggly underline to a word somewhere within a paragraph displayed by your app. In WPF, Silverlight and Windows 8 there’s just no good way to do it without attempting to figure out where that particular word is being displayed on the screen and then drawing a little squiggly line underneath it.
Well, DirectWrite provides a much better way. You can write code that slips into the whole text-rendering pipeline and then do whatever you need to do. Granted, it’s not easy. When I figured it out, I realized it was much too big a job for an MSDN Magazine article so I wrote a long blog entry about it.
On the other hand, DirectX is certainly awkward to use, partly because it’s all COM based (which at this point seems like an antique from the distant past), and partly because you have to code in C++ (or use wrapper library), and not least because of the names. When you’re dealing with names like
ID2D1PathGeometry1, you realize that you’re working in a world completely untouched by marketing amenities.