CNA is a C++ reimplementation of the XNA 4.0 programming model, built on SDL3 and a pluggable graphics renderer layer.
It is a framework/runtime and abstraction layer—not a game—designed to preserve XNA-style APIs (Microsoft::Xna::Framework) while using modern C++ internals.
CNA demonstrates engine-level C++ architecture, graphics abstraction design, and renderer-oriented systems engineering.
git submodule update --init
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=OPENGLES3
cmake --build build
tools/platform/run_gpu_tests_private.sh build --output-on-failure # private display, never the desktopCurrent state, known bugs and the maintained build/test commands: handoff.md.
Current release: 0.2.0 (pre-1.0 — a minor release may still change the public API; see
CHANGELOG.md for what the release contains and
docs/releasing.md for how versions are managed). Compiled code reads its
own version from CNA::getVersionString() in CNA/Version.hpp.
CNA 0.2.0 requires the sibling checkouts sharp-runtime 0.2.0, easy-gl 0.1.1 and
meta-gl 0.4.1 (or a later patch release of each). They are not submodules, so check out
those tags next to this repository; configuration stops with instructions when a checkout
declares an incompatible version (cmake/DependencyVersions.cmake).
For binary C++ consumers, opt in to CNA_INSTALL_CXX=ON and install the configured
SDK; it exports CNA:: and SharpRuntime:: modules for find_package(CNA CONFIG).
See the installed SDK guide for prerequisites, install
components, relocation, version semantics and tested platform coverage.
Looking for a specific doc? See
docs/README.mdfor an index of what's current vs. historical. Current state, known bugs and limitations:handoff.md(§5 is the one authoritative bug list). Implementation roadmaps and retained task logs are indexed separately inplans/README.md.
Microsoft::Xna::Framework::Graphics: every major Graphics class is present, implemented and tested; what each renderer supports is indocs/graphics-renderer-feature-matrix.md, and the remaining known defects are inhandoff.md§5.docs/graphics-compatibility-report.mdis a dated 2026-07-09 snapshot kept for its methodology, not current status.- Documented XNA 4.0 runtime API surface: every public type and every documented member of the Microsoft reference corpus is represented in CNA. The member audit holds the current counts and classifications; its JSON report records every reference member. Run
python3 tools/audit_xna_runtime_surface.py --write-reports. API representation does not establish behavioral compatibility; the Content Pipeline is measured separately. - Compiled XNA effects:
Effect(GraphicsDevice&, byte[])and the canonical XNBEffectReaderexecute XNA/FNA Direct3D 9 Effect Framework bytecode onFNA3Dunconditionally, and behind opt-inCNA_<RENDERER>_COMPILED_EFFECTSbuild options onSDL_GPU, the EasyGL family,WEBGPU,SOFTWAREandDIRECTX9. The shared public contract covers reflection, parameter mutation, techniques/passes, pass states, cloning, 3D draws, andSpriteBatch. Unsupported renderers reject the constructor explicitly; MGFX and runtime.fxsource compilation remain separate formats/projects. Seedocs/shader-effect-vs-fx-bytecode.md. OPENGLES3/OPENGL33/WEBGL2renderers: the most mature GL-family public renderers overall — one shared internal implementation (EasyGL, on top ofeasy-gl) driven by a GL profile choice, not three separate implementations.OPENGLES3(desktop/mobile GLES 3.0) andWEBGL2(Emscripten, GLES 3.0 → WebGL 2.0) have full 2D+3D pixel-verified coverage — this is what was previously the singleEASYGLpublic renderer, split into its real public identities.OPENGL33(desktop GL 3.3 core) is the desktop-GL profile of the same implementation; per-profile limits are indocs/renderer-registry.mdanddocs/graphics-renderer-feature-matrix.md.SDL_GPUrenderer: CNA's modern native cross-platform path and the default on Windows, macOS and iOS; CNA maps XNA 4.0 onto SDL_GPU, and SDL owns its Vulkan, Direct3D 12 and Metal backends. Fully exercised on Linux (Vulkan); its Direct3D 12 backend runs under Wine through vkd3d-proton. Open gaps:ShaderEffectis compiled out on Windows, Apple and Emscripten, and there are no occlusion queries.WEBGPUrenderer: Supported renderer (GraphicsRendererMaturity::Supported, the classSDL_GPUis in) using nativewgpu-native(v29.0.1.1) and, since 2026-08-26, Emscripten's emdawnwebgpu port for a real in-browser path. Well past a 2D baseline: device/surface setup, clear/present,Texture2D/TextureCube/Texture3D, vertex/index uploads, a pixel-verified WGSLSpriteBatch, full 3D with every stock effect (BasicEffectincl. per-pixel/per-vertex lighting,AlphaTestEffect,DualTextureEffect,SkinnedEffect72-bone palette,EnvironmentMapEffect— all with FNA fog parity,WEBGPU-145–148; plusPbrEffect/SkinnedPbrEffect), real instancing,RenderTarget2D/RenderTargetCube, MSAA, GPU occlusion queries, MRT (2-4 targets), custom WGSLShaderEffects (3D andSpriteBatch), full stencil state, and GPU-native block-compressed textures (DXT/BC7). The one open item isWEBGPU-1, verification of the Windows, macOS and linux-aarch64 wgpu-native packages — see the status summary inplans/plan_webgpu.mdanddocs/webgpu-renderer.md.DIRECTX9renderer: Windows-only native Direct3D 9 renderer targeting real XNA 4.0 pixel authenticity, not just feature parity — it runs Microsoft's own vendored Stock Effects HLSL bytecode, cross-compiled via MinGW-w64 and verified through Wine+DXVK on a real GPU. A checked-in 31-scene oracle corpus diffs CNA's render against the real XNA 4.0 runtime's own render of the same scene at--tolerance 0: 0/31 scenes currently diverge.GraphicsProfile.Reach/.HiDefenforcement is real (the only CNA renderer where it is). Validation on real Windows hardware is still open. Seedocs/directx9-renderer.md,docs/d3d9-divergence-report.md, andplans/plan_dx9.md.- Verification methodology: differential testing against a real, running
FNA.dllreference implementation (tools/fna-reference/), disputed behavior settled against genuine XNA 4.0 on a Windows 7 VM, and a compile-timeCNAEXTpurity check (a dedicated CMake build option that turns every non-XNA-tagged declaration into a[[deprecated]]warning under-Werror) — seeCHECKLIST.md's "CNAEXT markers" section andCMakeLists.txt. - Automatic CI is partial (see
.github/workflows/):general-tests-ci.ymlruns the full unfiltered suite on Linux for one renderer (OPENGLES3) under Xvfb and fails if the run left the checkout dirty; other Linux workflows cover narrower subsystems. There is no automatic full GPU pixel matrix across renderers. The Apple workflow builds macOS withSOFTWAREand runs the portable platform suites plus a bundle smoke app; a separate manual-dispatch Windows MSVC workflow builds and runs theDIRECTX9CTest suite. There is no automatic Windows or Android gate.
- Recreate the XNA developer experience in native C++.
- Provide a native C++ path for teams that like the XNA/MonoGame model but need non-managed runtime/toolchain control.
- Mirror core XNA namespaces and API patterns while implementing them incrementally.
- Decouple gameplay-facing API from rendering renderer implementation details.
- Enable one high-level API surface across different rendering technologies.
- Keep SDL- and graphics-API-level concerns behind framework abstractions.
- Public API uses XNA-style namespaces, especially under
Microsoft::Xna::Framework. - Core game loop and framework primitives are available (
Game,GameTime, graphics types, input/audio surfaces). - Compatibility is partial and evolving; implementation status is tracked progressively in source.
CNA_DIAGNOSTICS=OFF|STATS|FULLprovides the bounded renderer-independent profiler and resource metadata foundation;OFFremains the default and compiles instrumentation out.CNA_BUILD_INSPECTOR=ONoptionally builds a separately linked, explicitly started application agent and the standalonecna-inspectorlocal browser bridge. It is authenticated, demand-driven, localhost-only by default, and never embeds HTTP/JSON work in the game loop.- See
docs/diagnostics.mdanddocs/inspector.mdfor activation, security, protocol, supported views, performance measurements, and limitations.
Keyboard,Mouse(incl.MouseCursor),GamePad(up to 4 players),TouchPanel/TouchCollection, and theGestureDetectorgesture recognizer (Tap/DoubleTap/Hold/Drag/Flick/Pinch) — all underMicrosoft::Xna::Framework::Input, matching FNA/XNA 4.0 behavior member-for-member. Seeplans/plan_input.mdfor the full FNA-parity audit record.- CNAEXT extensions beyond stock XNA:
TextInputEXT(IME composition), rumble/trigger-rumble/light-bar/ gyro/accelerometer onGamePad, rawCNA::Input::Joysticks(distinct fromGamePad's mapped view), device-levelCNA::Input::Sensors/Power, andCNA::Input::Hapticsfor standalone haptic devices. - Single platform-event funnel (
IPlatform::PollEvents→PlatformInputBridge::ProcessEvent), renderer-agnostic and independent of the selected native event source. SDL3 translation stays inside its platform implementation; theCnaTestsinput suite verifies the shared state path.
GraphicsDeviceabstraction with renderer delegation.SpriteBatchAPI withBegin(...)/Draw(...)/End()workflow.Texture2Dabstraction with renderer-owned texture resources.
- glTF 2.0 loads directly:
Content.Load<Model>("character.glb")— no offline step. An offline converter (tools/gltf_to_cnj) produces.cnj+ binary sidecars for the same asset, and the two loaders are held to identical output by a per-fixture parity sweep. - Geometry, PBR materials, skinning, animation (LINEAR/STEP/CUBICSPLINE), morph targets, cameras and punctual lights all import. What that costs is stated rather than implied: XNA's model is four joint influences and three directional lights, two sampled UV channels, and one colour channel — glTF data beyond those is counted and reported, never silently dropped.
- Correctness is held by a generated 145-asset conformance corpus: the exact L0–L6 numerical ladder covers container, accessor, semantic mesh, world geometry, packed GPU bytes and bound effect parameters per commit (including ASan + UBSan), then the production OPENGLES3 viewer supplies the final deterministic L7 image/disposition gate.
- Read
docs/gltf-limitations.mdbefore choosing CNA for a glTF pipeline. It lists every approximation and every unsupported feature next to the report field that names the loss at run time. The oldermisc/CNAEXT.mddesign is historical; use the current glTF limitations document.
CNA_CNAEXT=ON enables the small modules/graphics-ext surface: AsciiPostProcessEffect,
CRTEffect, DepthEffect (colour-depth and palette reduction), and DebugDraw. CRT and Depth
are ordinary ShaderEffect descendants usable with render targets and SpriteBatch; ASCII has a
direct draw API. DebugDraw batches wireframe lines, bounds, spheres and frusta using BasicEffect.
The option is off by default. See graphics extension guide.
The XNA-compatible graphics core, renderer backends, custom shaders, PbrEffect and
SkinnedPbrEffect, glTF loading, and CNB/CNJ content pipeline do not depend on this option.
- Platform layer (
CNA_PLATFORM):SDL3(default; Windows, X11, Wayland, macOS, iOS, Android and the browser are all reached through SDL3's own drivers),HEADLESS, and POSIX-onlyTERMINAL. Seedocs/platform-abstraction.md. - Renderer abstraction supports targeting multiple rendering paths from one API layer.
- Windows:
DIRECTX9(through DXVK),SDL_GPU(its Direct3D 12 backend through vkd3d-proton) andSOFTWAREare cross-compiled with MinGW-w64 and verified under Wine; a manual MSVC workflow builds and runs theDIRECTX9suite. Validation on real Windows hardware is not current. - Linux:
OPENGLES3/OPENGL33,SDL_GPU(Vulkan),WEBGPU,FNA3D, and the CPU/no-GPU renderersSOFTWARE,HEADLESSandSTUB. - Web (Emscripten) and Android (NDK) targets are implemented and verified, not just
architecturally planned — see section 7 (Networking, Services & Avatar) below for what
Netdoes on each (browsers have no multiplayer through the XNA API). - macOS has a native CI build/test gate (
SOFTWARE);SDL_GPU's Metal backend passed the full test tree on a Mac mini M4 once and has not been re-qualified since. iOS/iPadOS is experimental platform support. The Apple workflow final-links an actual.appfor device and simulator and launches a one-frameSOFTWAREGamesmoke application in the simulator. There is still no physical-device, pixel, touch, audio, storage or performance evidence. The boundary is stated per claim indocs/apple-platforms.md.
- Native C++23 codebase and explicit control over memory/lifetime.
- Interface-driven renderer boundaries to keep hot rendering paths renderer-specific.
- Lightweight gameplay-facing API over renderer-specific implementations.
CNA is organized into clear layers with strict responsibility boundaries:
+-----------------------------------------------------------+
| Game / Application Code |
| (uses Microsoft::Xna::Framework API) |
+------------------------------+----------------------------+
|
v
+-----------------------------------------------------------+
| API Layer (XNA-style public surface) |
| modules/<module>/include/Microsoft/Xna/Framework/... |
| - Game, GraphicsDevice, SpriteBatch, Texture2D, ... |
+------------------------------+----------------------------+
|
v
+-----------------------------------------------------------+
| CNA Internal Layer (abstractions/factories) |
| modules/graphics/include/CNA/Internal/Renderers/Common/... |
| - IGraphicsRenderer, ISpriteBatchRenderer, ITextureRenderer |
+------------------------------+----------------------------+
|
v
+-----------------------------------------------------------+
| Renderer Implementations |
| modules/renderers/{easygl,sdl-gpu,webgpu,...}/src |
+-----------------------------------------------------------+
- Public API lives under
modules/<module>/include/Microsoft/...and stays framework-facing. - Renderer contracts live under
CNA::Internal::Renderersinterfaces (modules/graphics/include/CNA/Internal/Renderers/Common/). - Renderer implementations live under
modules/renderers/<family>/. GraphicsDeviceconstructs renderers via factory (CreateGraphicsRenderer(...)) based on build-time renderer selection.
SpriteBatch is the primary 2D rendering abstraction.
- You create it against a
GraphicsDevice. - Call
Begin(...)to start a draw pass. - Issue
Draw(...)calls for textures/sprites. - Call
End()to close the batch.
The API surface is renderer-agnostic, while rendering behavior is executed by renderer-specific ISpriteBatchRenderer implementations.
This keeps game code stable while allowing renderer-specific optimizations in EasyGL, SDL_GPU, WebGPU and the other renderers.
CNA exposes 10 public renderer identities through CNA_GRAPHICS_RENDERER (choose one per build
configuration; when none is named the default is WEBGL2 under Emscripten, SDL_GPU on Windows,
macOS and iOS, and OPENGLES3 everywhere else). The set is curated: a renderer is added only when
it provides meaningful platform coverage, compatibility value, architectural value, or a capability
the existing set does not reasonably cover, and forty-one identities have been retired
(docs/removed-renderers.md). The canonical registration, implementation-sharing, capability, and platform-gate
inventory is docs/renderer-registry.md.
Renderers are normally chosen at compile time, one per build. CNA can also be built with several renderers and the concrete one chosen at runtime, before the game starts:
#include "CNA/GraphicsRendererSelection.hpp"
CNA::GraphicsRendererSelection::SetPreferred(CNA::GraphicsRendererType::SdlGpu);A renderer that is unavailable or fails to start is an error by default — CNA never silently substitutes another. An opt-in fallback chain is available when a game wants one. See docs/runtime-renderer-selection.md.
The former ASCII renderer identity was removed 2026-08 in favor of a renderer-neutral post-process
effect, CNA::Graphics::AsciiPostProcessEffect (modules/graphics-ext/), usable with any renderer's
RenderTarget2D output — see docs/ascii-post-process-effect.md.
SDL_GPUOPENGLES3(internal implementation: EasyGL)OPENGL33(internal implementation: EasyGL)WEBGL2(Emscripten only; internal implementation: EasyGL)WEBGPUHEADLESSSOFTWARESTUBDIRECTX9(Windows-only; native Direct3D 9 running Microsoft's own vendored Stock Effects HLSL bytecode)FNA3D(FNA's own XNA-shaped graphics library; picks SDL_GPU/Direct3D 11/OpenGL at runtime, executes XNA's stock effects and CNA's compiled punctual/PBR extensions — seedocs/fna3d-renderer.md)
-
EasyGL renderer (OpenGL-based path through
easy-gl)- Custom shader-driven rendering path across GL ES 3.0, GL 3.3 core and WebGL 2.
-
SDL_GPU renderer
- One native path to SDL's Vulkan, Direct3D 12 and Metal backends.
ShaderEffectis compiled out on Windows, Apple and Emscripten; no occlusion queries.
Beyond graphics, CNA ports the XNA 4.0 GamerServices and Net namespaces (and, within
GamerServices, the Avatar subsystem), backed by CNA's own account service
(cna-gamer-services-server).
- The XNA gamer services API with real behaviour: with a configured CNA service, accounts and Guide sign-in, profiles, friends and presence, messages and player reviews, achievements, leaderboards (including Ranked arbitration), invitations, parties and social notifications; without one, local offline profiles, as on a console without Xbox LIVE. An Xbox 360-inspired Guide (sign-in picker, gamer cards, friends, party, avatar editor) is drawn by CNA over the game, in CNA's own look.
- A CNA-owned, XNA/Xbox-like implementation with its own protocol, accounts and backend
policies — not Xbox LIVE compatible. See
docs/gamer-services-server.mdand, for everything that is not done or done differently,docs/gamer-services-known-limitations.md. - What "Xbox-like" does and does not claim: the public API is XNA-compatible (names, types, exceptions and event order read from the XNA 4.0 assemblies and documentation); the workflow is Xbox-like (sign in, Guide, friends, invitations, parties, as XNA games expected); how the backend decides what XNA only reports -- the Reputation formula, host election, party rules, presence timeouts, invitation lifetime, Ranked arbitration, privilege policy -- is CNA policy, not a claim about Xbox LIVE; console behaviour was never traced on an Xbox 360, so exact historical equivalence is claimed nowhere; and the Guide and avatars resemble the Xbox 360 era in original CNA art only.
- Complete
NetworkSessionAPI surface (5 enums + 18 classes). SystemLinkruns over ENet (reliable UDP, vendored underthird_party/enet): hosting, joining, LAN discovery with measured QoS, data relay, host migration, disconnect handling andStartGame/EndGamestate broadcast.PlayerMatchandRankedrun through the CNA service's session directory, with every datagram carried by its authenticated TLS/WSS relay: create, find, join, invitations, online host migration,AddLocalGamerand Ranked arbitration.LocalandLocalWithLeaderboardsneed no transport.- Voice is routed automatically in SystemLink and online sessions (microphone capture, Opus,
realtime session packets, playback) where libopus is available (
CNA_ENABLE_VOICE). - Networking by platform:
- Linux — native ENet/UDP, including a genuine two-OS-process loopback test.
- Windows — native ENet/UDP via WinSock2; cross-compiled with MinGW-w64 and verified running under Wine.
- Web (Emscripten) — ENet runs over Emscripten's WebSocket-emulated sockets as a client of a
Node.js-run host, but a browser has no LAN discovery, no service transport and no relay, so a
browser game cannot find or join sessions through the XNA API: browser multiplayer is outside
the current scope (
docs/browser-network-readiness.md). - Android (NDK) — native ENet/UDP via bionic libc's genuine POSIX sockets, verified on a real x86_64 emulator — no platform-specific transport workarounds needed at all, unlike Web.
AvatarAnimation,AvatarDescriptionandAvatarRendererwork as XNA's documentation describes them on the Xbox 360 (the Windows assembly only stubbed them): real rendering on XNA's 71-bone skeleton, the 31 animation presets, expressions andAvatarDescription.Changed, drawn from original CNA avatar catalogs compiled into the runtime. The service stores each account's description; a catalog a client lacks is installed as a verified pack. Seedocs/avatars.md.
- Language: C++23
- Core platform/runtime library: SDL3 (vendored via Git submodule at
third_party/SDL) - Media integration:
SDL3_mixer(vendored via Git submodule) - Graphics dependency:
easy-gl(for theOPENGLES3/OPENGL33/WEBGL2renderers), resolved from the canonical../easy-glsibling; EasyGL in turn resolves../meta-gl - Networking: ENet (vendored directly at
third_party/enet) — the realtime transport of everyMicrosoft::Xna::Framework::Netsession (UDP on the LAN, carried through the service relay online); libcurl (TLS HTTPS and WebSockets to the CNA service); optional libopus for network voice - Utility/runtime layer:
sharp-runtime - Build system: CMake
- Tests: GoogleTest (
CnaTeststarget)
- CMake 3.20+
- C++23-capable compiler (GCC 12+ or Clang 15+)
- Dependency directories available to CMake:
../sharp-runtime../easy-gland../meta-gl(needed for theOPENGLES3/OPENGL33/WEBGL2renderers)
- libcurl and nlohmann-json development packages (GamerServices and Net, both on by default)
- SDL3 and SDL3_mixer are built from vendored submodules by default — no system SDL packages required, but building them needs the X11, OpenGL and audio development headers.
- The Debian 13 package list for all of the above, the test environment and the optional features is docs/development-environment.md.
- FFmpeg is optional.
CNA_ENABLE_VIDEO=AUTO(the default) enables video decoding whenlibavcodec,libavformat,libavutilandlibswresampledevelopment packages are present; useOFFfor a game that does not need video, orONto require them. The XNA video types remain available in all three modes; see docs/video-backend.md.
- CMake 3.20+
- One of:
- MSVC 2022 (Visual Studio 2022, v17.8+, with C++20/23 support)
- clang-cl (LLVM for Windows, targeting MSVC ABI)
- MinGW-w64 (either natively on Windows or cross-compiled from Linux)
- Dependency directories:
../sharp-runtime(no external dependencies — builds cleanly on Windows)
- SDL3 and SDL3_mixer are built from vendored submodules by default — no pre-built SDL binaries or
CMAKE_PREFIX_PATHconfiguration required.
Before the first build, initialise the vendored submodules:
git submodule update --initThis populates third_party/SDL, third_party/SDL_mixer, third_party/draco and
vendor/googletest. --recursive is not needed: it only adds SDL_mixer's and Draco's nested
submodules, which CNA's configuration does not build.
After that, no system SDL packages are required.
Building from a source zip/tarball instead of a Git clone? GitHub's "Download ZIP" and release archives do not include submodule contents, so
third_party/SDLwill be empty and CMake aborts with a clear error (Missing vendored 'SDL' … Run: git submodule update --init, fromcmake/ThirdPartySDL.cmake). Either clone with Git and run the command above, or set-DCNA_USE_SYSTEM_SDL=ONto use system-installed SDL3 packages.
git submodule update --init
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=OPENGLES3
cmake --build build --target CnaTestsOn Windows SDL_GPU is selected automatically when no renderer is named (native Windows
qualification of it is still open). SDL is built from the vendored submodule — no pre-built SDL
binaries or CMAKE_PREFIX_PATH needed.
git submodule update --init
cmake -S . -B build-win -DCNA_GRAPHICS_RENDERER=SDL_GPU
cmake --build build-win --target CnaTestsGamerServices and Net, both on by default, need a libcurl built for Windows, which Debian does not
package. Point CURL_INCLUDE_DIR and CURL_LIBRARY at a MinGW build of curl, or add
-DCNA_ENABLE_NET=OFF -DCNA_ENABLE_GAMER_SERVICES=OFF to the configure below. Details:
docs/development-environment.md, Windows cross-development.
# Install cross toolchain
sudo apt install mingw-w64
git submodule update --init
cmake -S . -B build-windows \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/mingw-w64.cmake \
-DCNA_GRAPHICS_RENDERER=SDL_GPU
cmake --build build-windows --target CnaTestsThe resulting .exes run under Wine; SDL_GPU's Direct3D 12 backend needs vkd3d-proton
(scripts/run-wine-vkd3d.sh).
brew install ccache ffmpeg
git submodule update --init
cmake -S . -B cmake-build-macos -DCNA_GRAPHICS_RENDERER=SDL_GPU
cmake --build cmake-build-macos --target CnaTests --parallelCI builds macOS with SOFTWARE; SDL_GPU (Metal backend) is not currently re-qualified on macOS.
Requires a macOS host with Xcode. This produces a final-linked cna_ios_smoke.app for a device
or simulator; the Apple workflow also launches its one-frame Game path in the simulator. This
is not evidence for a physical device or correct pixels/input/audio/storage — see
docs/apple-platforms.md for the exact boundary. iOS accepts SOFTWARE
and SDL_GPU; SDL_GPU has never been built for iOS.
cmake -S . -B cmake-build-ios \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/ios.cmake \
-DCNA_GRAPHICS_RENDERER=SOFTWARE \
-DCNA_BUILD_TESTS=OFF -DCNA_BUILD_EXAMPLES=OFF
cmake --build cmake-build-ios --parallel
# Simulator: add -DCNA_IOS_SIMULATOR=ON (use a separate build directory).
# Device deployment needs the Xcode generator and a team id:
# -G Xcode -DCNA_APPLE_DEVELOPMENT_TEAM=<TEAMID>If you prefer to link against system-installed SDL3 packages instead of the
vendored submodules, pass -DCNA_USE_SYSTEM_SDL=ON:
cmake -S . -B build -DCNA_USE_SYSTEM_SDL=ON -DCNA_GRAPHICS_RENDERER=OPENGLES3
cmake --build build --target CnaTestsThis calls find_package(SDL3 REQUIRED) and find_package(SDL3_mixer REQUIRED) and requires
those packages to be present on the system (e.g. installed via your package manager).
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=OPENGL33
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=SDL_GPUA native Direct3D 9 renderer, Windows-only (hard-FATAL_ERROR-gated at configure time on any other
CMAKE_SYSTEM_NAME), targeting real XNA 4.0 pixel authenticity rather than just feature parity —
see docs/directx9-renderer.md for what that means and why. Developed and
verified on this repo's own Debian dev machine via the MinGW-w64 cross toolchain, tested locally
through Wine + DXVK (scripts/run-wine-dxvk9.sh). See
docs/directx9-renderer.md and plans/plan_dx9.md for full detail.
The Windows libcurl note of the MinGW SDL_GPU build above applies here too.
# Install cross toolchain
sudo apt install mingw-w64
git submodule update --init
cmake -S . -B cmake-build-d3d9 \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/mingw-w64.cmake \
-DCNA_GRAPHICS_RENDERER=DIRECTX9 \
-DCNA_BUILD_TESTS=ON
cmake --build cmake-build-d3d9 --target CnaTests --parallelRunning the resulting .exes needs a Wine + DXVK dev-loop
(docs/directx9-renderer.md has full setup steps); CTest wires this in automatically:
ctest --test-dir cmake-build-d3d9 -L DIRECTX9 --output-on-failureThis repository intentionally prioritizes framework/runtime development over shipping a bundled game demo executable.
Use these commands for quick environment and rendering-path verification. Tests that open a window run on a private headless compositor, never on the desktop:
cmake --build build
tools/platform/run_gpu_tests_private.sh build --output-on-failure
scripts/check_clean_checkout.sh -- tools/platform/run_gpu_tests_private.sh build # also proves the run left the checkout clean| Platform | Compiler | Renderer | Status |
|---|---|---|---|
| Linux x86_64 | GCC 12+ | OPENGLES3, SDL_GPU | ✅ |
| Linux x86_64 | Clang 15+ | OPENGLES3 | ✅ |
| Windows x86_64 | MSVC 2022 | DIRECTX9, HEADLESS | covered by the Windows MSVC workflows (d3d-windows-ci.yml, content-pipeline-windows-ci.yml); not run locally |
| Linux → Windows (cross) | MinGW-w64 | SDL_GPU, SOFTWARE | ✅ verified building + running under Wine (SDL_GPU's Direct3D 12 backend through vkd3d-proton) |
| Linux → Windows (cross) | MinGW-w64 | DIRECTX9 | ✅ verified building + DIRECTX9-labelled CTest suite under Wine+DXVK on a real GPU — 0/31 oracle scenes diverge from real XNA 4.0 at --tolerance 0; real Windows hardware verification still open, see docs/directx9-renderer.md |
| Web (Emscripten) | emcc/Clang (emsdk) | WEBGL2, WEBGPU | ✅ verified building + running in Chrome; limits in docs/web-emscripten-graphics-limitations.md |
| Android (NDK) | Clang (NDK 29/30) | OPENGLES3 | ✅ verified building + running on an x86_64 emulator; limits in docs/android-graphics-limitations.md |
Minimal XNA-style game skeleton in CNA (Game presents the frame itself, exactly as in XNA):
#include <memory>
#include "Microsoft/Xna/Framework/Color.hpp"
#include "Microsoft/Xna/Framework/Game.hpp"
#include "Microsoft/Xna/Framework/GraphicsDeviceManager.hpp"
#include "Microsoft/Xna/Framework/Graphics/SpriteBatch.hpp"
#include "Microsoft/Xna/Framework/Graphics/Texture2D.hpp"
#include "Microsoft/Xna/Framework/Vector2.hpp"
using namespace Microsoft::Xna::Framework;
using namespace Microsoft::Xna::Framework::Graphics;
class MyGame final : public Game {
public:
MyGame()
: graphics_(this)
{
getContentProperty().setRootDirectoryProperty("Content");
}
protected:
void LoadContent() override
{
spriteBatch_ = std::make_unique<SpriteBatch>(getGraphicsDeviceProperty());
logo_ = std::make_unique<Texture2D>(getContentProperty().Load<Texture2D>("logo"));
}
void Update(GameTime& gameTime) override
{
// Update game state here.
Game::Update(gameTime);
}
void Draw(const GameTime& gameTime) override
{
getGraphicsDeviceProperty().Clear(Color::CornflowerBlue);
spriteBatch_->Begin();
spriteBatch_->Draw(*logo_, Vector2(100.0f, 80.0f), Color::White);
spriteBatch_->End();
Game::Draw(gameTime);
}
private:
GraphicsDeviceManager graphics_;
std::unique_ptr<SpriteBatch> spriteBatch_;
std::unique_ptr<Texture2D> logo_;
};
int main()
{
MyGame game;
game.Run();
return 0;
}- API mirroring strategy: Public classes follow XNA naming and namespace conventions to reduce conceptual migration cost from XNA/MonoGame-style code.
- Abstraction design: Gameplay-facing rendering APIs (
GraphicsDevice,SpriteBatch,Texture2D) delegate to renderer interfaces instead of exposing low-level renderer objects. - Separation of concerns: Public framework API, internal contracts, and renderer implementations are physically separated in directory structure and ownership.
- Renderer-oriented architecture: Renderer can be swapped at build-time with a single CMake option while keeping high-level game code stable.
- Performance-minded C++ implementation: Native code path enables tighter control over memory, lifetime, and rendering behavior than managed runtime abstractions.
CNA is moving from feature expansion to long-term maintenance by a human C++ developer. The work
ahead is fixing the defects listed in handoff.md §5, keeping behaviour faithful to XNA
4.0, and keeping validation deterministic. The renderer set (10 identities), the platform layer and
the content formats are deliberately kept as they are; new renderers, asset formats or subsystems
are not planned.
CNA is licensed under the Microsoft Public License (Ms-PL). See the LICENSE file for details.
Portions of CNA are derived from or based on FNA, which is also licensed under the Microsoft Public License (Ms-PL).