Tutorial 01: Introduction to CNA
What you’ll learn
- What CNA is, and how it differs from XNA 4.0, MonoGame and FNA.
- How C++ changes the API shape you knew from C#: property getters/setters, namespaces, manual memory.
- Why
sharp-runtimetypes turn up in almost every CNA signature. - What the
CNAEXTmarker means when you meet it in a header.
Before you start — None — this tutorial stands alone. It is the entry point to the series; read it before anything else.
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 covers the public Microsoft::Xna::Framework namespaces except the Windows Forms-specific Framework.Design. That includes real 2D and 3D rendering, audio, input, math, and read-side content loading. Rather than publish a blended "percent complete" figure, CNA pins its public API with compile-time signature-freeze tests and a CNA_STRICT_XNA_API purity mode. At the alpha.1 tag the test tree contains 568 C++ test sources and 8,263 statically discoverable GoogleTest-family definitions; the executable and CTest totals remain configuration-dependent.
Reading .xnb content files is supported: CNA implements the XNB container, LZX decompression, and 50 built-in type readers (49 without FFmpeg, which drops the video reader). They are not registered automatically — call CNA::Internal::Xnb::RegisterAllBuiltInXnbReaders() once at startup. CNA is an XNB loader, not an authoring pipeline. Its EffectReader can load XNA/FNA D3D9 Effect Framework bytecode only on a renderer build advertising CompiledEffects; HLSL .fx source, DXBC and MGFX are different unsupported inputs.
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.
Renderers
CNA exposes 50 renderer identities across 46 implementation families. A normal build compiles one renderer; an opt-in CNA_GRAPHICS_RENDERERS build can include several and choose one before the first graphics device is created. The identities are not equally complete: some are full 2D+3D paths, others are deliberately 2D-only, no-output, historical, or experimental targets. The Graphics Renderers page has the per-renderer detail; the ones you are most likely to pick are:
| Renderer | CMake flag | Use case |
|---|---|---|
SDL_RENDERER | -DCNA_GRAPHICS_RENDERER=SDL_RENDERER | Portable 2D only, no shaders. The default when nothing more specific applies |
OPENGLES3 | -DCNA_GRAPHICS_RENDERER=OPENGLES3 | OpenGL ES 3.0 / OpenGL 3.0+, full 2D and 3D. The Linux default |
VULKAN | -DCNA_GRAPHICS_RENDERER=VULKAN | Vulkan, low-level control, 2D and 3D |
BGFX | -DCNA_GRAPHICS_RENDERER=BGFX | Cross-platform rendering library as the underlying layer |
SDL_GPU | -DCNA_GRAPHICS_RENDERER=SDL_GPU | SDL3's GPU API, 2D and 3D |
WEBGL2 | -DCNA_GRAPHICS_RENDERER=WEBGL2 | WebGL 2 in the browser. The Emscripten default; Emscripten builds only |
SOFTWARE | -DCNA_GRAPHICS_RENDERER=SOFTWARE | CPU rasterizer, deterministic pixel tests, no GPU needed. Never presents to a window — read pixels back with GetBackBufferData() |
HEADLESS | -DCNA_GRAPHICS_RENDERER=HEADLESS | CI logic testing, no GPU/window, no pixel output at all |
DIRECTX9 | -DCNA_GRAPHICS_RENDERER=DIRECTX9 | Windows only. 2D and 3D, and the one renderer that matches the 39-scene XNA oracle corpus 39/39 at tolerance 0, since real XNA ran on Direct3D 9 |
DIRECTX11 | -DCNA_GRAPHICS_RENDERER=DIRECTX11 | Windows only. Native Direct3D 11 |
DIRECTX12 | -DCNA_GRAPHICS_RENDERER=DIRECTX12 | Windows only. Native Direct3D 12 |
FREEDIRECT | -DCNA_GRAPHICS_RENDERER=FREEDIRECT | 2D only, via the free-direct library — a DirectX 3 shaped 2D subset reimplemented on SDL3 |
CANVAS | -DCNA_GRAPHICS_RENDERER=CANVAS | 2D only, HTML5 Canvas. Emscripten builds only |
The default is chosen for you if you do not pass the flag: WEBGL2 under Emscripten, OPENGLES3 on Linux, and SDL_RENDERER otherwise. Two equivalent single-renderer forms exist and must not be mixed: -DCNA_GRAPHICS_RENDERER=<NAME>, or -DCNA_RENDERER_<NAME>=ON with exactly one turned on. Passing a name that is not one of the 50 is a hard CMake FATAL_ERROR, not a silent fallback.
Two more things worth knowing early. The five GL-profile identities — OPENGLES2, OPENGLES3, OPENGL33, WEBGL1 and WEBGL2 — share one internal implementation called EasyGL, which lives in the ../easy-gl sibling repository. The profiles are not cosmetic: OPENGLES2 and WEBGL1 genuinely lose multiple render targets, occlusion queries, Texture3D, instancing and multi-stream vertex input. The tag also provides manual Wine/DXVK and vkd3d-proton paths for its Windows-gated renderers, but no automatic Wine workflow.
For these tutorials we will use OPENGLES3 as the primary renderer because it supports both 2D and 3D rendering and runs on any machine with a modern GPU driver. See Tutorial 72 for a fuller comparison.
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 CNAEXT marker
Some CNA APIs that have no XNA equivalent are annotated with a CNAEXT 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 | One of 50 identities by default, or a compatible runtime-selectable set; host platform is independent |
| API compatibility | Reference | Broad | XNA-facing signatures pinned by compile-time freeze tests |
| 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 getViewportProperty() / setViewportProperty() in CNA's C++ API:
// C# (XNA)
var vp = GraphicsDevice.Viewport;
// C++ (CNA)
auto vp = getGraphicsDeviceProperty().getViewportProperty();
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_.setPreferredBackBufferWidthProperty(width);
graphics_.setPreferredBackBufferHeightProperty(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 OPENGLES3 and VULKAN renderers. glTF 2.0 files load at runtime through
Content.Load<Model>()with no tooling step. - 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 (through SDL3_mixer, including a real XACT parser and player) and touch input (all 10 XNA gesture types detected) are largely functional. XNA/FNA D3D9 Effect Framework binaries now load on FNA3D and on explicitly enabled SDL_GPU, EasyGL-family and Vulkan builds; HLSL .fx source, DXBC and MGFX remain unsupported inputs, while custom renderer-native shaders use ShaderEffect. Two platform caveats are worth flagging up front: on the web there is no save persistence and no video playback, and video is also absent on Windows and Android. The roadmap tracks current status.
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.