Targeting Win32 and WinRT/Metro at the Same Time

I’ve seen some developers assume that if you write an App for WinRT/Metro, you have to
write it exclusively in C++/CX, a variant of C++ with lots of
Microsoft-specific extensions. In reality, you only really need C++/CX to interface with
WinRT, but everything under that layer can be clean ISO C++! In this post I’ll explain
how I’m designing my Ogre game to run inside Windows’ Metro UI while still
supporting other platforms such as Win32, Android and iPhone on the same code base.

A good start is to look at what’s different between a normal desktop application
and a Metro application and then develop a design concept where these differences
are abstracted or wrapped so the core game code does not need to know about them.

WinRT vs. Win32

Action

Differences

Creating the game’s window

In a Metro app, you cannot create any kind of windows. Instead,
your app provides an IFrameworkView which will be handed
a system-created window via IFrameworkView.SetWindow().

I’ll move the window creation part into the platform-specific code
and my core game code will just manage Ogre’s scene graph, assuming that
a window is already there.

Querying Input Devices

Metro apps are given notifications when the user presses a key, moves
a pointer (mouse, pen or finger) and so on. Being WinRT events, these
notifications can only be subscribed to from a C++/CX class.

There’s already an input library for Ogre called OIS that abstracts
input devices and Ogre’s WinRT sample browser has some adapter classes
to feed the OIS input devices from WinRT callbacks. In this case,
however, I decided to port my Nuclex.Input library to C++ because its
design takes care of several other porting issues.

Running the game loop

Metro apps need a game loop, too, but the message pump looks a bit
different and there are additional exit signals.

Here, I’ll simply follow the scheme that has already served me well
in XNA: instead of running its own game loop, the game class will simply
provide two methods, Update() and Draw() that
it expects to be called. The platform specific code can then execute
whatever game loop is appropriate and call these methods.

Exiting your game

Metro apps can be closed at any instant. The application is immediately
put in the background and may ask for up to 5 seconds additional time to
save its state before it is forcibly terminated.

This concept cannot be isolated from the game, but it can be embraced:
I’ll design my game so that it can be closed at any moment and will save
its state. It’ll be a nice feature for casual players on the desktop.

Accessing the file system

Metro apps may not access the system’s local files at all. There are
two locations you do have access to: you can read from the app’s install
directory and all subdirectories thereof and you are given another
directory where your app can store its state and other data.

Not too troublesome – my game just needs to be told where to put its
saves and where it is installed.

Consequences

Given the window creation and main loop differences, it’s clear that I need
a shell around my core game that deals with the platform-specific code for
starting up and shutting down the app. This shell can also set up and provide
abstractions for querying input devices, accessing files and any other things
that might still come up.

As a way to enforce these abstractions, I will put my actual game code into
a DLL and load it from the wrapper applications. That reduces the risk of
accidentally mixing platform dependent code with the core game code that should
stay platform independent. I’ll also try to most development on WinRT,
the more restrictred of the two platforms.