Introduction
In this post, I present a sample animation framework that demonstrates how Direct2D and DirectWrite can be used in a wide variety of applications. This post is targeted at game developers and demoscene coders who want to take advantage of modern hardware-accelerated components.
Direct2D was designed for applications that need graphics intensive operations and yet demand high performance and reliability; these applications include internet browsers, office applications, and graphics editors. But Direct2D’s applicability extends beyond these problem domains and well into the realms of games and art.
Graphics sell games. Therefore, they need to be very fast and look great. Even though the majority of games are heavily 3D, there is also a large chunk of 2D graphics in games, particularly UI components and textures. Also games from some genres, such as puzzle, strategy, and educational games, mostly use 2D graphics.
Then there is the “demoscene,” a competitive, computer arts subculture, where teams of amateur coders, musicians and graphics artists create demos, programs that include hard-to-code visual effects with graphics and synchronized music, much like music videos. 2D graphics in particular is a rising trend in demos in the last few years (see Masagin by Farbraush & Neuro or Metamorphosis by ASD for example)
While differences remain among a graphical editor application such as Adobe Illustrator, a real time strategy game and a demoscene demo, they present some of the same challenges:
Direct2D is really great for addressing these issues. All drawings in Direct2D happen in a continuous float space, with the ability to apply transformation matrices with a few lines of code. Direct2D also gives you a lot of power for rich animation by providing very fast animation methods for transforms and by minimizing graphics bus traffic with the use of mesh and mask capabilities. Direct2D is further designed to interoperate well with Direct3D. By using Direct2D, you can directly render into Direct3D textures and use those textures to wrap your 3D models. For more information about Direct2D, see http://msdn.microsoft.com/en-us/library/dd370990(VS.85).aspx.
The Graphimation Framework Basics
During the development of Direct2D, I had the opportunity to actually apply some of these ideas to a prototype scenario. Once I recognized the value Direct2D has for the mentioned application spaces, I decided to design an animated 2D graphics framework in native C++, called the Graphimation Framework. I then used the framework to create three applications to showcase what you can do with the framework.
With the ease of use and direct applicability that Direct2D possesses, I was able to implement these applications in about 4 weeks.
Disclaimer: All the code and documentation for Graphimation Framework is provided to the developer community as an example and is not an official Microsoft product. You can access the download at: http://code.msdn.microsoft.com/graphimation
Let’s take a closer look at what the Graphimation Framework provides. It provides an interface called IGraphimation. This interface encapsulates a graphics object that can be rendered and includes some animations. It can also provide some named variables that its client can set to customize certain aspects of the graphimation object. You can also hit test against a graphimation.
A graphimation object is defined and initialized by an external file (a .d2g file). Once a graphimation object is initialized, you need to call render() on it from your render function, and update() it with time passed between each invocation of the main loop.
Each graphimation object (for example, a soldier in the RTS game) defines one or more animations. Through the render + update mechanics, each animation automatically keeps playing. Animations can also loop or tie into other animations. All this is automatically handled by the Graphimation Framework. The client can switch any animation. For example, to make a soldier walk, the application calls PlayAnimation(“walk”).
If you want to see more information about how to create and use graphimations, see the GraphimationFrameworkManual.docx file in the Doc folder in the sources. It provides information about the internal workings of the framework.
All the graphics and animations are defined in the d2g files. A d2g file defines the following:
In a d2g file, you can put a variable name almost anywhere that you can write a constant number. These variables can then either be set from outside the framework by the SetVariable interface or internally controlled by a controller.
A graphimation object can also contain other graphimation objects as resources and render or update them. Therefore whole hierarchies of graphimation objects can be built and easily controlled. In fact, the entire Direct2D Demo is a single graphimation object that includes many others (like the fish, the plants, and the butterfly). Check out the manual for advanced techniques in using graphimations. Also please refer to the manual for further info on the d2g file syntax.
Implementing this framework was very easy with Direct2D and took only about two-dev weeks. A large portion of the code is for parsing the d2g files. Since Direct2D maps to this problem so well, the rest of the code is just simple wrapper classes around Direct2D classes with ten – twenty lines of code each.
Library Dependencies
Graphimation Framework depends pretty heavily on STL and Boost. The Graphimation Framework only needs the headers from the Boost libraries, so you only need to download Boost—you don’t have to build it. You do need to add the Boost path to your include path in Visual Studio.
You also need the Windows 7 SDK, which is available at http://msdn.microsoft.com/en-us/windows/bb980924.aspx.
As Graphimation is provided as a Visual C++2008 project, you also need a version of Visual Studio 2008. The free express one from http://www.microsoft.com/exPress/ will do.
Throughout the framework the RAII concept is used to control all the resources, so the framework satisfies the “basic exception safety” guarantee that no resources will be leaked on the face of exceptions (which may happen due to STL, Boost, or new -- GXM also converts D2D errors into exceptions too). However, the framework does NOT provide “strong exception safety,” meaning that, in the case of an exception, the object may not be in a usable state. Finally, any exceptions thrown from Boost or STL are caught at the module boundary and converted to error codes. Therefore, the client code does not see any exceptions.
The following diagram shows a group of main classes and their relationships.
Samples Using the Graphimation Framework
Here I describe three samples that use the Graphimation Framework:
The Direct2D Demo
By using the framework, I implemented a simple player that can play a .d2g file, and then created a set of nested .d2g files that made up a demoscene style demo. You can see what is shown in the following screen shot by running the demo.bat file in the GxmPlayer sources.
Carousel Widget Library
By using this framework, I implemented an animated UI framework prototype called Carousel with only a few hundred lines of code. Simply each widget has a corresponding Graphimation object that can be animated in different ways. For example, the following screen shot shows several parent and child widgets,
When a parent widget is clicked, child widget graphimations simply play an animation (they “open up” around their parent). The idea was providing menu navigation with minimum distance of mouse movement. All options in a menu are at a small distance from where your mouse is, thanks to the circular structure of the menus. Another interesting point is that, since Direct2D provides hit testing with arbitrary geometries, your widgets do not have to be rectangular. The Graphimation Framework provides hit testing for any sub resources it contains.
Writing a simple RTS game became a lot easier with the Graphimation Framework. As mentioned before, the soldiers are instances of the same graphimation type (i.e. the same .d2g file). They support a set of animations (stand, walk, fight, die etc.) and once all the graphical concerns are handled by the Graphimation Framework, the remaining game code is greatly simplified. In the example shown in the following screen shot, all I did was to implement a few classes for the game world, soldier and AI, and it only took a few hundred lines!
Conclusions
Of course a real UI framework, a real game, or a real demoscene demo will need to be more complex, but these examples help show how easy it can be to build a 2D graphic animation framework with Direct2D and be able to reuse it in a variety of cool applications.
In summary, this blog post provided a perspective on the applicability of Direct2D on certain sets of applications. A set that is not necessarily the one that comes to mind when speaking of Direct2D. Irrespective of which industry you develop software for, if your problem domain includes issues like “animated 2D graphics” and “a continuous 2D float coordinate space”, then you might enjoy a number of benefits from using Direct2D.
Bilgem Cakir, Direct2D Team