How CNA is structured
CNA is organised into four clear, strictly separated layers — from high-level game code down to hardware-specific rendering backends.
Layer overview
┌─────────────────────────────────────────────────────────────────┐
│ Game / Application Code │
│ Uses: Microsoft::Xna::Framework API │
│ Example: MyGame extends Game, calls SpriteBatch::Draw() │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ XNA-Compatible Public API Layer │
│ include/Microsoft/Xna/Framework/... │
│ Game · GraphicsDevice · SpriteBatch · Texture2D · Color │
│ Vector2/3/4 · Matrix · Rectangle · GameTime · Input │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ CNA Internal Abstraction Layer (sharp-runtime support) │
│ include/CNA/Internal/Backends/... │
│ IGraphicsBackend · ISpriteBatchBackend · ITextureBackend │
│ Factory: CreateGraphicsBackend(backend_type) │
└──────────┬───────────────┬──────────────┬───────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌────────────────────────────┐
│ SDL_Renderer │ │ EasyGL │ │ bgfx | Vulkan (stub) │
│ Backend │ │ (OpenGL) │ │ Backend │
│ │ │ Backend │ │ │
└──────┬───────┘ └──────┬───────┘ └──────────────┬─────────────┘
│ │ │
└─────────────────┴──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ SDL3 Platform Layer │
│ Windowing · Input · Audio (SDL3_mixer) · Image (SDL3_image) │
│ OpenGL context · Vulkan surface · bgfx platform init │
└─────────────────────────────────────────────────────────────────┘
Layer descriptions
Game / Application Code
Your game logic. Subclasses Game, overrides LoadContent(), Update(), Draw(). Calls XNA-style APIs exclusively. Has zero knowledge of which backend is in use — this is the contract CNA enforces. Games written against this layer are portable across backends.
XNA-Compatible API Layer
Lives under include/Microsoft/Xna/Framework/. This is the surface that game code touches. Class names, namespaces, and method signatures mirror the original XNA 4.0 API as faithfully as practical in C++. No backend-specific code leaks into this layer. Includes: Game, GraphicsDevice, GraphicsDeviceManager, SpriteBatch, Texture2D, Color, all math types, input surfaces, GameTime, GameComponent, etc.
CNA Internal Layer & sharp-runtime Support
Lives under include/CNA/Internal/Backends/ and src/CNA/Internal/Backends/. Defines pure virtual backend interfaces: IGraphicsBackend, ISpriteBatchBackend, ITextureBackend. The factory function CreateGraphicsBackend() selects the correct implementation at compile time based on the CNA_GRAPHICS_BACKEND CMake variable. Also integrates the sharp-runtime utility layer for runtime support primitives.
Backend Implementations & SDL3
Concrete backend implementations live under src/CNA/Internal/Backends/{SdlRenderer,EasyGL,Vulkan,Bgfx}/. Each backend implements the interfaces from Layer 3 using the relevant low-level API. SDL3 (vendored at third_party/SDL) provides the platform abstraction: window management, input events, audio (SDL3_mixer), and image loading (SDL3_image).
Key architectural decisions
Interface/Implementation separation
Public API headers (include/Microsoft/...) never include backend headers. Backend code never bleeds into game-facing APIs. This boundary is enforced by directory and include structure.
Build-time backend selection
Only one backend is compiled per build. No runtime dispatch overhead. Backend is selected with -DCNA_GRAPHICS_BACKEND=<BACKEND>. This keeps the hot rendering path backend-specific and optimised.
Vendored dependencies
SDL3, SDL3_image, and SDL3_mixer are vendored as Git submodules. No system SDL packages needed. bgfx is fetched via CMake FetchContent. This ensures reproducible builds across environments.
XNA namespace mirroring
C++ namespaces mirror XNA's hierarchy: Microsoft::Xna::Framework, Microsoft::Xna::Framework::Graphics, Microsoft::Xna::Framework::Input, etc. Reduces conceptual migration cost from XNA/MonoGame experience.
sharp-runtime support layer
The sharp-runtime library provides utility and runtime support primitives that CNA's internals depend on. It builds cleanly on all supported platforms with no external dependencies of its own.
Nova-3D composability
The strict layering makes it straightforward to build higher-level engines on top. Nova-3D will depend on the public CNA API layer only — not on backend internals — preserving its portability.
Directory structure
cna/
├── include/
│ ├── Microsoft/Xna/Framework/ ← Public XNA-compatible API
│ │ ├── Game.hpp
│ │ ├── Color.hpp
│ │ ├── GameTime.hpp
│ │ ├── Graphics/
│ │ │ ├── GraphicsDevice.hpp
│ │ │ ├── SpriteBatch.hpp
│ │ │ └── Texture2D.hpp
│ │ └── ...
│ └── CNA/Internal/Backends/ ← Backend interfaces
│ ├── IGraphicsBackend.hpp
│ ├── ISpriteBatchBackend.hpp
│ └── ITextureBackend.hpp
│
├── src/
│ ├── Microsoft/Xna/Framework/ ← Public API implementations
│ └── CNA/Internal/Backends/
│ ├── SdlRenderer/ ← SDL_Renderer backend
│ ├── EasyGL/ ← OpenGL backend
│ ├── Bgfx/ ← bgfx backend
│ └── Vulkan/ ← Vulkan backend (stub)
│
├── third_party/
│ ├── SDL/ ← SDL3 submodule
│ ├── SDL_image/ ← SDL3_image submodule
│ └── SDL_mixer/ ← SDL3_mixer submodule
│
├── cmake/ ← CMake helpers
├── examples/ ← Demo/example programs
├── tests/ ← GoogleTest suite
└── CMakeLists.txt