Tutorial 01: Introduction to CNA

CNA Tutorial Series  ·  Beginner

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-runtime types turn up in almost every CNA signature.
  • What the CNAEXT marker 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:

RendererCMake flagUse case
SDL_RENDERER-DCNA_GRAPHICS_RENDERER=SDL_RENDERERPortable 2D only, no shaders. The default when nothing more specific applies
OPENGLES3-DCNA_GRAPHICS_RENDERER=OPENGLES3OpenGL ES 3.0 / OpenGL 3.0+, full 2D and 3D. The Linux default
VULKAN-DCNA_GRAPHICS_RENDERER=VULKANVulkan, low-level control, 2D and 3D
BGFX-DCNA_GRAPHICS_RENDERER=BGFXCross-platform rendering library as the underlying layer
SDL_GPU-DCNA_GRAPHICS_RENDERER=SDL_GPUSDL3's GPU API, 2D and 3D
WEBGL2-DCNA_GRAPHICS_RENDERER=WEBGL2WebGL 2 in the browser. The Emscripten default; Emscripten builds only
SOFTWARE-DCNA_GRAPHICS_RENDERER=SOFTWARECPU rasterizer, deterministic pixel tests, no GPU needed. Never presents to a window — read pixels back with GetBackBufferData()
HEADLESS-DCNA_GRAPHICS_RENDERER=HEADLESSCI logic testing, no GPU/window, no pixel output at all
DIRECTX9-DCNA_GRAPHICS_RENDERER=DIRECTX9Windows 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=DIRECTX11Windows only. Native Direct3D 11
DIRECTX12-DCNA_GRAPHICS_RENDERER=DIRECTX12Windows only. Native Direct3D 12
FREEDIRECT-DCNA_GRAPHICS_RENDERER=FREEDIRECT2D only, via the free-direct library — a DirectX 3 shaped 2D subset reimplemented on SDL3
CANVAS-DCNA_GRAPHICS_RENDERER=CANVAS2D 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

PropertyXNA 4.0MonoGameCNA
LanguageC#C#C++23
Runtime.NET Framework.NET / MonoNative (no runtime)
StatusDiscontinued 2013ActiveActive (research)
PlatformsWindows / Xbox 360ManyLinux, Windows, Android, Web
RenderingDirectXDirectX / OpenGL / Metal / VulkanOne of 50 identities by default, or a compatible runtime-selectable set; host platform is independent
API compatibilityReferenceBroadXNA-facing signatures pinned by compile-time freeze tests
GC overheadYes (.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_ptr is.
  • 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.