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 (Adv.)    │
  │  Backend     │  │  (OpenGL)    │  │  Backend                   │
  │              │  │  Backend     │  │                            │
  └──────┬───────┘  └──────┬───────┘  └──────────────┬─────────────┘
         │                 │                         │
         └─────────────────┴──────────────────────────┘
                               │
                               ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │          SDL3 Platform Layer                                    │
  │   Windowing · Input · Audio (SDL3_mixer) · Image (SDL3_image)   │
  │   OpenGL context · Vulkan surface · bgfx platform init          │
  └─────────────────────────────────────────────────────────────────┘

Detailed architecture diagram

CNA detailed architecture diagram

Layer descriptions

Layer 1 - Highest

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.

Layer 2 - Public API

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.

Layer 3 - Internal Abstractions

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.

Layer 4 - Lowest

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).

SDL3 — important notes

CNA uses SDL3 (not SDL2). The SDL3 API is substantially different from SDL2 — migration between them is not backwards compatible. Key SDL3 specifics used in CNA:

  • SDL3_mixer uses the MIX_Mixer model with track-based, per-mixer channels — unlike SDL2_mixer's global audio system.
  • SDL3_image is used for texture/image loading.
  • All three libraries (SDL, SDL_image, SDL_mixer) are vendored as Git submodules under third_party/. No system SDL install is required by default; pass -DCNA_USE_SYSTEM_SDL=ON to use system packages instead.

SDL3 serves as the foundation for:

  • WindowingSDL_Window creation and management
  • Event loop — cross-platform event pumping
  • InputSDL_Keyboard, SDL_Mouse, SDL_Gamepad, SDL_Touch
  • Audio initialisation — SDL3_mixer setup
  • OpenGL context creation — used by the EasyGL backend
  • Vulkan surface creation — used by the VULKAN backend
  • Android JNI Activity layer — Android platform integration
  • Emscripten main loop — WebAssembly/browser event scheduling

Required sibling repositories

CNA depends on two sibling C++ libraries that must be cloned adjacent to the CNA repository. They are not vendored inside CNA — they live at predictable relative paths and are discovered by CMake automatically.

Sibling — clone at ../sharp-runtime/

sharp-runtime

sharp-runtime is a C++ library that provides .NET-style type primitives for C++23. It allows CNA code to closely mirror XNA C# code structure without a managed runtime. Clone it at ../sharp-runtime/ relative to the CNA repo root.

Integer aliases:

  • bytecs — alias for uint8_t
  • shortcs — alias for int16_t
  • intcs — alias for int32_t
  • longcs — alias for int64_t
  • ushortcs, uintcs, ulongcs — unsigned variants

Other primitives:

  • Single — alias for float
  • Stringstd::string wrapper
  • IDisposable — virtual Dispose() interface
  • IEquatable<T>Equals method interface
  • IComparable<T> — comparison interface
  • EventHandler<TArgs> — multicast delegate-style callbacks
  • List<T>, Dictionary<K,V> — collection wrappers
  • I/O primitives
Sibling — clone at ../easy-gl/ (EASYGL backend only)

easy-gl

easy-gl wraps OpenGL ES 3.0/3.2 for CNA's EASYGL rendering backend. Clone it at ../easy-gl/ relative to the CNA repo root. It is required only for the EASYGL backend — not needed for SDL_RENDERER, VULKAN, or BGFX.

  • Abstracts GLSL shader compilation, linking, and uniform binding
  • Manages VAOs, VBOs, FBOs, textures, and renderbuffers
  • Provides the OpenGL context for both Linux desktop (OpenGL 3.0+ with ES emulation) and WebGL 2 (via Emscripten)

Which backend should I choose?

Select your rendering backend at configure time with -DCNA_GRAPHICS_BACKEND=<BACKEND>. Use the table below to pick the best fit for your target platform and requirements.

Backend Best for 2D 3D WASM Android Status
SDL_RENDERER Portability, simple 2D Stable
EASYGL Linux, Web, full 3D Stable
VULKAN High-performance 3D, Linux Advanced
BGFX Multi-API (Metal, DX) Advanced

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.

Key C++23 features used in CNA

CNA targets C++23 and uses several modern standard library features to mirror XNA's C# semantics cleanly without a managed runtime.

Standard Library & Language Features
  • std::optional<T> — replaces XNA nullable types (Nullable<T>) for missing or unset values.
  • std::span<T> — provides buffer views in GetData()/SetData() without copying data.
  • std::string_view — zero-copy string parameters wherever a string is read but not owned.
  • std::unique_ptr<T> / std::shared_ptr<T> — RAII resource management, replacing C# using blocks and IDisposable patterns.
  • Ranges and concepts (where available) — type-safe template constraints replacing unconstrained templates.
  • [[nodiscard]] attributes — applied to Load<T>(), Begin(), and similar factory/guard calls to catch accidentally discarded return values.
  • Structured bindings — used for returning multiple values from internal helpers without heavyweight output-parameter patterns.
  • if constexpr — compile-time template branching in PackedVector implementations and format-dispatch helpers.
  • Inline variables — for static constants defined directly in header-only types without requiring a separate .cpp definition.

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 (2D + 3D, second-most mature; BlendState and OcclusionQuery are the remaining named gaps)
│
├── 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