Tutorial 01: Introduction to CNA
What is CNA?
CNA is a C++23 reimplementation of the Microsoft XNA 4.0 game framework. It exposes the same Microsoft::Xna::Framework API that XNA developers know, but compiles to native code using modern C++23 and runs on Linux, Windows, Android, and the web through SDL3.
The name "CNA" is a deliberate reversal of "XNA" — it signals that you are writing C++ instead of C#, but the programming model is the same. If you have ever written an XNA or MonoGame game you will find CNA immediately familiar.
CNA implements 227 of the 245 public types in the XNA 4.0 API, measured against FNA. That includes full 2D and 3D rendering, audio, input, the math types, and content loading — verified by 4,373 unit tests and 490 GPU pixel-readback tests across four rendering backends. Two things are deliberately missing and worth knowing up front: CNA cannot read .xnb content files, and it cannot load compiled .fx shaders.
CNA is research and demo quality, not yet recommended for shipping commercial games. It is ideal for learning game development, porting XNA/MonoGame projects to C++, building demos, and experimenting with game engine design.
The four rendering backends
CNA supports four interchangeable graphics backends selected at CMake configure time:
| Backend | CMake flag | Use case |
|---|---|---|
SDL_RENDERER | -DCNA_GRAPHICS_BACKEND=SDL_RENDERER | Portable 2D only, no shaders |
EASYGL | -DCNA_GRAPHICS_BACKEND=EASYGL | OpenGL ES 3.0 / OpenGL 3.0+, full 2D and 3D |
VULKAN | -DCNA_GRAPHICS_BACKEND=VULKAN | Vulkan, low-level control |
BGFX | -DCNA_GRAPHICS_BACKEND=BGFX | Cross-backend abstraction layer |
For these tutorials we will use EASYGL as the primary backend because it supports both 2D and 3D rendering and runs on any machine with a modern GPU driver.
sharp-runtime
CNA depends on sharp-runtime, a companion C++ library that provides C#-compatible primitive types. This gives you types like intcs (equivalent to C# int), bytecs, Single, floatcs, boolcs, and C# string/array semantics. These types make the CNA source code mirror the original XNA C# code as closely as possible and help when porting existing XNA games.
You will see sharp-runtime types in CNA API signatures. In practice you can often pass plain C++ values (int, float, bool) directly because the types are implicitly convertible. The sharp-runtime repository must be cloned as a sibling directory to the cna directory.
The NOXNA marker
Some CNA APIs that have no XNA equivalent are annotated with a NOXNA marker in the source. This helps you distinguish CNA extensions from XNA-faithful APIs when porting code.
CNA vs XNA vs MonoGame
| Property | XNA 4.0 | MonoGame | CNA |
|---|---|---|---|
| Language | C# | C# | C++23 |
| Runtime | .NET Framework | .NET / Mono | Native (no runtime) |
| Status | Discontinued 2013 | Active | Active (research) |
| Platforms | Windows / Xbox 360 | Many | Linux, Windows, Android, Web |
| Rendering | DirectX | DirectX / OpenGL / Metal / Vulkan | SDL3 + pluggable backend |
| API compatibility | Reference | ~100% | 227 / 245 types |
| GC overhead | Yes (.NET GC) | Yes (.NET GC) | None — RAII/smart pointers |
If you already know XNA or MonoGame, porting to CNA is mostly a matter of translating C# idioms to C++ idioms. The class names, method names, and overall structure stay the same.
Key Differences: C++ vs C#
The biggest adjustment when coming from XNA/MonoGame is moving from C# to C++. Here are the most common differences you will encounter throughout these tutorials:
Memory management
C# uses garbage collection — you can allocate objects freely and forget about them. C++ requires explicit memory management. CNA games use smart pointers to handle this safely:
// C# (XNA/MonoGame)
SpriteBatch spriteBatch;
spriteBatch = new SpriteBatch(GraphicsDevice);
// C++ (CNA) — use unique_ptr for exclusive ownership
std::unique_ptr<SpriteBatch> spriteBatch_;
spriteBatch_ = std::make_unique<SpriteBatch>(getGraphicsDeviceProperty());
Properties become getter/setter methods
C# properties like GraphicsDevice.Viewport become getViewport() / setViewport() in CNA's C++ API:
// C# (XNA)
var vp = GraphicsDevice.Viewport;
// C++ (CNA)
auto vp = getGraphicsDeviceProperty().getViewport();
Namespaces and includes
Every CNA class lives in the Microsoft::Xna::Framework namespace hierarchy and requires a corresponding include:
#include "Microsoft/Xna/Framework/Game.hpp"
#include "Microsoft/Xna/Framework/Color.hpp"
#include "Microsoft/Xna/Framework/Graphics/SpriteBatch.hpp"
using namespace Microsoft::Xna::Framework;
using namespace Microsoft::Xna::Framework::Graphics;
sharp-runtime types
CNA function signatures use sharp-runtime types. In practice you can usually pass standard C++ types and they will implicitly convert:
// These are equivalent — intcs is implicitly constructible from int
intcs width = 800;
int height = 600;
graphics_.setPreferredBackBufferWidth(width);
graphics_.setPreferredBackBufferHeight(height);
No LINQ or delegates
Where XNA C# code uses delegates or LINQ, CNA uses C++ lambdas and standard algorithms. You will see this most in audio and effects APIs.
What You Can Build
CNA has enough of the XNA API implemented to build a wide variety of game types today:
- 2D games — platformers, shoot-em-ups, puzzle games, visual novels. SpriteBatch, Texture2D, SpriteFont, and full input handling are all working.
- 3D games — BasicEffect, VertexBuffer, IndexBuffer, Model loading, and draw primitives work on the EASYGL and VULKAN backends.
- Tech demos — The CNA House 3D demo runs in the browser via WebAssembly.
- Ports of XNA/MonoGame games — If you have an existing XNA or MonoGame project, CNA provides a migration path to C++ without rewriting your entire game.
Audio (SDL3_mixer backend), touch input, and some advanced effect types are partially implemented. The roadmap lists what is planned.
How These Tutorials Are Structured
This tutorial series builds a complete knowledge base in a linear sequence. Each tutorial adds one concept and provides working, compilable code examples.
- Tutorials 01-02 — Introduction and environment setup. No code yet.
- Tutorials 03-05 — Getting a window open, understanding the game class and game loop.
- Tutorials 06-09 — Rendering: shapes, colors, textures, and text.
- Tutorials 10-11 — Input: keyboard and mouse.
- Tutorials 12-13 — Movement and animation.
Each tutorial assumes you have completed the previous ones. If you have XNA experience you may skim the early tutorials quickly — the C++ patterns will be the main new thing.
Code examples use the following conventions:
- Member variables end with
_(e.g.,spriteBatch_) using namespace Microsoft::Xna::Framework;is assumed in all code examples- Headers are abbreviated — full include lists are shown only in tutorial 03
Prerequisites
These tutorials assume:
- C++ basics — you are comfortable with classes, inheritance, pointers, and the standard library. You do not need to be a C++ expert, but you should know what
std::unique_ptris. - Game development concepts — you understand what a game loop is at a high level (update state, render frame, repeat).
- Command line — you can run CMake and build commands in a terminal.
- XNA/MonoGame familiarity is helpful but not required — the tutorials explain every concept from first principles.
You do not need to know C# or have used XNA before. Tutorial 02 walks you through installing every dependency from scratch.
Ready to get started? Head to Tutorial 02: Setting Up Your Dev Environment.