One thing that can be off-putting when migrating from XNA to Direct3D on Windows Phone 8 is the empty default project template. In XNA projects, an empty project simply contained the Game1.cs class, with all it’s overriding methods that you could place code in and start working on the game. The rest of the code was hidden inside the framework’s bowels.
When creating a new ‘Windows Phone Direct3D App’, you get no less than 10 code files. At the beginning, you can get away with not looking into most of these and just start modifying the CubeRenderer.h and CubeRenderer.cpp files (as I suggested in my Getting Started post), but eventually you will need to understand what goes on in the other files and add code to them, which is what this short dissection is for.
ProjectName.cpp and ProjectName.h
These two will have whatever name you chose for the project. These contain the code that contains instantiate the application and glues everything together.
Looking at the .h file, you’ll see two classes defined.
The first is named identical to the project and it implements the IFrameworkView interface. This means it can be used as a ‘view provider’ for the application. It is the rough equivalent of having a Game class without any GraphicsDevice or ContentManager objects. The interface defines 5 methods which the class has to implement:
- Initialize – first method called in the lifetime of the app. The default code subscribes to three lifetime events here: Activated, Suspended and Resuming
- SetWindow – When the window of the app is created, this method is called, allowing us to subscribe to any window-related events (visibility, input, etc), and also to initialize the renderer (the equivalent of XNA’s GraphicsDevice) to use the current window
- Load – Called between Initialize and Run, here you can load any external resources you might need.
- Uninitialize – Called when closing the app. Here you should unload any resources loaded in the Load function.
- Run – Here is the code that actually runs the game. While the window is visible, it listens to any events that the window might receive and calls Update and Render on the renderer class.
You’ll also notice quite a few Event Handlers defined here, used to respond to events related to the application’s lifecycle and input.
The second class defined in this file is the Direct3DApplicationSource, implementing the IFrameworkViewSource interface, whose sole purpose is to create an instance of the ProjectName class.
In the ProjectName.cpp file, you can see all the code for the 5 methods above, as well as all the empty event handlers. As you write your game, you’ll probably need to add code to all of these in time, unless you want a non-interactive game
At the end of this file is the entry point of the application, in the main function. Here, the Direct3DApplicationSource class is instantiated, and used to start up the application.
Direct3DBase.h and Direct3DBase.cpp
These define a helper class that contains the DirectX initialization code. The methods of this class initialize the Direct3D device, connect it to the Window of the app, create the swap chain, depth and stencil buffer. The code here is very well commented, so go ahead and take a look at it.
If you’re developing and testing using the emulator, here’s the place you should make the changes Shawn Hargreaves talked about in a recent post of his, to avoid being tricked by Feature Level 11 emulation.
CubeRenderer.h and CubeRenderer.cpp
This is the class that you’ll almost always remove, and replace with your own renderer that inherits from Direct3DBase. At this point, all code that is common between different projects was abstracted away into the other classes, leaving CubeRenderer as a simple demo on how to draw a spinning cube.
In the CreateDeviceResources method, it loads the pixel and vertex shaders and creates the vertex and index buffers describing a cube.
In the CreateWindowSizeDependentResources method it computes the projection matrix, which depends on the width and height of the window, so it will be recomputed anytime the size of the windows changes.
Update creates the Model and View matrices.
Lastly, in the Render function, the shaders are set on the device, and the cube is drawn.
This file provides two methods that will often be useful in your code. ThrowIfFailed convert failed result handles into exceptions, and ReadDataAsync reads asynchronously from a binary file
A basic class to keep track of timing. It uses the same low level timing functions as the GameTime class in XNA ( QueryPerformanceCounter ), so you can rely on the same precision. After each update, it can give the total time in seconds from the start of the game, and the elapsed time in seconds since the last frame, just like using gameTime.TotalGameTime.TotalSeconds and gameTime.ElapsedGameTime.TotalSeconds.
The shaders used by the default CubeRenderer files are loaded from SimpleVertexShader.hlsl and SimplePixelShader.hlsl. The vertex shader simply multiplies the vertices by the Model, View and Projection matrices, and passes the new position and the vertex color forward towards the pixel shader. The pixel shader simply outputs that colors.
This is the simplest shader possible, and it’s very likely that you will never use it. But it is here to demonstrate how .hlsl files are compiled into .cso (compiled shader object) at build time, which you can than load at runtime.
To use something else than the default simple shaders, you can:
- Change the code in these files directly
- Use the DirectXTK built in shader effects, similar to the build-in Effects available in XNA for WP7
- Add new .hlsl files to the project, and write your own shaders
- Use the visual shader designer to make new shaders
This serves the same purpose it did in Windows Phone 7: to configure metadata for your application, including Name, Tile Icons, Requirements, Supported Resolutions, etc. But this time, besides being able to manually edit the .xml, we also have a visual UI to edit all the settings. Make sure you check this part out.
This is the precompiled header file, used to speed up compilation of big header files you might use.
For further reading, you can check the whole How to set up your DirectX Windows Store app to display a view guide on MSDN, which explains this for Windows 8 Store apps. Fortunately, the architecture of a Win8Store Direct3D app and of a Windows Phone Direct3D app are 90% identical, and the linked article should be just as useful. Just ignore everything you see related to Orientation and DXGI’s SetRotation functions, since things don’t work the same in Windows Phone 8. But I’ll get back to this subject in a different article.
I hope this small article can help clear some light in what the various code in the default template does, or at least let’s you know what you can safely ignore at the beginning. Next time, we’ll look at what changes need to be done to support Landscape orientation for Direct3D Windows Phone games.