Skip to content
libcnaPublic

About

CNA is a cross-platform multi-language XNA 4.0 API ecosystem powered by a high-performance C++ core, featuring 10 renders and 10,000+ pixel-perfect integration tests

Topics

Resources

Stars

106 stars

Watchers

1 watching

Forks

Latest commit

 

History

10,699 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CNA

1. 🚀 Overview

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.

Quick Start

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 desktop

Current state, known bugs and the maintained build/test commands: handoff.md.

Version

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.md for 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 in plans/README.md.

Project Status

  • Microsoft::Xna::Framework::Graphics: every major Graphics class is present, implemented and tested; what each renderer supports is in docs/graphics-renderer-feature-matrix.md, and the remaining known defects are in handoff.md §5. docs/graphics-compatibility-report.md is 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 XNB EffectReader execute XNA/FNA Direct3D 9 Effect Framework bytecode on FNA3D unconditionally, and behind opt-in CNA_<RENDERER>_COMPILED_EFFECTS build options on SDL_GPU, the EasyGL family, WEBGPU, SOFTWARE and DIRECTX9. The shared public contract covers reflection, parameter mutation, techniques/passes, pass states, cloning, 3D draws, and SpriteBatch. Unsupported renderers reject the constructor explicitly; MGFX and runtime .fx source compilation remain separate formats/projects. See docs/shader-effect-vs-fx-bytecode.md.
  • OPENGLES3/OPENGL33/WEBGL2 renderers: the most mature GL-family public renderers overall — one shared internal implementation (EasyGL, on top of easy-gl) driven by a GL profile choice, not three separate implementations. OPENGLES3 (desktop/mobile GLES 3.0) and WEBGL2 (Emscripten, GLES 3.0 → WebGL 2.0) have full 2D+3D pixel-verified coverage — this is what was previously the single EASYGL public 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 in docs/renderer-registry.md and docs/graphics-renderer-feature-matrix.md.
  • SDL_GPU renderer: 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: ShaderEffect is compiled out on Windows, Apple and Emscripten, and there are no occlusion queries.
  • WEBGPU renderer: Supported renderer (GraphicsRendererMaturity::Supported, the class SDL_GPU is in) using native wgpu-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 WGSL SpriteBatch, full 3D with every stock effect (BasicEffect incl. per-pixel/per-vertex lighting, AlphaTestEffect, DualTextureEffect, SkinnedEffect 72-bone palette, EnvironmentMapEffect — all with FNA fog parity, WEBGPU-145–148; plus PbrEffect/SkinnedPbrEffect), real instancing, RenderTarget2D/RenderTargetCube, MSAA, GPU occlusion queries, MRT (2-4 targets), custom WGSL ShaderEffects (3D and SpriteBatch), full stencil state, and GPU-native block-compressed textures (DXT/BC7). The one open item is WEBGPU-1, verification of the Windows, macOS and linux-aarch64 wgpu-native packages — see the status summary in plans/plan_webgpu.md and docs/webgpu-renderer.md.
  • DIRECTX9 renderer: 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/.HiDef enforcement is real (the only CNA renderer where it is). Validation on real Windows hardware is still open. See docs/directx9-renderer.md, docs/d3d9-divergence-report.md, and plans/plan_dx9.md.
  • Verification methodology: differential testing against a real, running FNA.dll reference implementation (tools/fna-reference/), disputed behavior settled against genuine XNA 4.0 on a Windows 7 VM, and a compile-time CNAEXT purity check (a dedicated CMake build option that turns every non-XNA-tagged declaration into a [[deprecated]] warning under -Werror) — see CHECKLIST.md's "CNAEXT markers" section and CMakeLists.txt.
  • Automatic CI is partial (see .github/workflows/): general-tests-ci.yml runs 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 with SOFTWARE and runs the portable platform suites plus a bundle smoke app; a separate manual-dispatch Windows MSVC workflow builds and runs the DIRECTX9 CTest suite. There is no automatic Windows or Android gate.

2. 🎯 Goals

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

3. ✨ Features

XNA API Compatibility (Incremental)

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

Diagnostics and Inspector

  • CNA_DIAGNOSTICS=OFF|STATS|FULL provides the bounded renderer-independent profiler and resource metadata foundation; OFF remains the default and compiles instrumentation out.
  • CNA_BUILD_INSPECTOR=ON optionally builds a separately linked, explicitly started application agent and the standalone cna-inspector local browser bridge. It is authenticated, demand-driven, localhost-only by default, and never embeds HTTP/JSON work in the game loop.
  • See docs/diagnostics.md and docs/inspector.md for activation, security, protocol, supported views, performance measurements, and limitations.

Input

  • Keyboard, Mouse (incl. MouseCursor), GamePad (up to 4 players), TouchPanel/TouchCollection, and the GestureDetector gesture recognizer (Tap/DoubleTap/Hold/Drag/Flick/Pinch) — all under Microsoft::Xna::Framework::Input, matching FNA/XNA 4.0 behavior member-for-member. See plans/plan_input.md for the full FNA-parity audit record.
  • CNAEXT extensions beyond stock XNA: TextInputEXT (IME composition), rumble/trigger-rumble/light-bar/ gyro/accelerometer on GamePad, raw CNA::Input::Joysticks (distinct from GamePad's mapped view), device-level CNA::Input::Sensors/Power, and CNA::Input::Haptics for 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; the CnaTests input suite verifies the shared state path.

Rendering

  • GraphicsDevice abstraction with renderer delegation.
  • SpriteBatch API with Begin(...) / Draw(...) / End() workflow.
  • Texture2D abstraction with renderer-owned texture resources.

Content pipeline — .gltf / .glb / .cnj

  • 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.md before 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 older misc/CNAEXT.md design is historical; use the current glTF limitations document.

Standalone CNA graphics extensions (CNA_CNAEXT)

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.

Cross-Platform Direction

  • 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-only TERMINAL. See docs/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) and SOFTWARE are cross-compiled with MinGW-w64 and verified under Wine; a manual MSVC workflow builds and runs the DIRECTX9 suite. Validation on real Windows hardware is not current.
  • Linux: OPENGLES3/OPENGL33, SDL_GPU (Vulkan), WEBGPU, FNA3D, and the CPU/no-GPU renderers SOFTWARE, HEADLESS and STUB.
  • Web (Emscripten) and Android (NDK) targets are implemented and verified, not just architecturally planned — see section 7 (Networking, Services & Avatar) below for what Net does 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 .app for device and simulator and launches a one-frame SOFTWARE Game smoke application in the simulator. There is still no physical-device, pixel, touch, audio, storage or performance evidence. The boundary is stated per claim in docs/apple-platforms.md.

Performance / C++ Advantages

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

4. 🏗 Architecture

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         |
+-----------------------------------------------------------+

Interface vs Implementation Separation

  • Public API lives under modules/<module>/include/Microsoft/... and stays framework-facing.
  • Renderer contracts live under CNA::Internal::Renderers interfaces (modules/graphics/include/CNA/Internal/Renderers/Common/).
  • Renderer implementations live under modules/renderers/<family>/.
  • GraphicsDevice constructs renderers via factory (CreateGraphicsRenderer(...)) based on build-time renderer selection.

5. 🎮 Rendering System

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.

6. 🔌 Renderer System

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_GPU
  • OPENGLES3 (internal implementation: EasyGL)
  • OPENGL33 (internal implementation: EasyGL)
  • WEBGL2 (Emscripten only; internal implementation: EasyGL)
  • WEBGPU
  • HEADLESS
  • SOFTWARE
  • STUB
  • DIRECTX9 (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 — see docs/fna3d-renderer.md)

Tradeoffs

  • 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.
    • ShaderEffect is compiled out on Windows, Apple and Emscripten; no occlusion queries.

7. 🌐 Networking, Services & Avatar

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

GamerServices

  • 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.md and, 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.

Net (Microsoft::Xna::Framework::Net)

  • Complete NetworkSession API surface (5 enums + 18 classes).
  • SystemLink runs over ENet (reliable UDP, vendored under third_party/enet): hosting, joining, LAN discovery with measured QoS, data relay, host migration, disconnect handling and StartGame/EndGame state broadcast.
  • PlayerMatch and Ranked run through the CNA service's session directory, with every datagram carried by its authenticated TLS/WSS relay: create, find, join, invitations, online host migration, AddLocalGamer and Ranked arbitration. Local and LocalWithLeaderboards need 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.

Avatar

  • AvatarAnimation, AvatarDescription and AvatarRenderer work 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 and AvatarDescription.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. See docs/avatars.md.

8. 🧰 Technology Stack

  • 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 the OPENGLES3/OPENGL33/WEBGL2 renderers), resolved from the canonical ../easy-gl sibling; EasyGL in turn resolves ../meta-gl
  • Networking: ENet (vendored directly at third_party/enet) — the realtime transport of every Microsoft::Xna::Framework::Net session (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 (CnaTests target)

9. ⚡ Getting Started

Prerequisites (Linux)

  • CMake 3.20+
  • C++23-capable compiler (GCC 12+ or Clang 15+)
  • Dependency directories available to CMake:
    • ../sharp-runtime
    • ../easy-gl and ../meta-gl (needed for the OPENGLES3/OPENGL33/WEBGL2 renderers)
  • 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 when libavcodec, libavformat, libavutil and libswresample development packages are present; use OFF for a game that does not need video, or ON to require them. The XNA video types remain available in all three modes; see docs/video-backend.md.

Prerequisites (Windows)

  • 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_PATH configuration required.

Initialise Submodules

Before the first build, initialise the vendored submodules:

git submodule update --init

This 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/SDL will be empty and CMake aborts with a clear error (Missing vendored 'SDL' … Run: git submodule update --init, from cmake/ThirdPartySDL.cmake). Either clone with Git and run the command above, or set -DCNA_USE_SYSTEM_SDL=ON to use system-installed SDL3 packages.

Build (Linux — OPENGLES3 renderer, default)

git submodule update --init
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=OPENGLES3
cmake --build build --target CnaTests

Build (Windows — SDL_GPU renderer, vendored SDL)

On 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 CnaTests

Build (Linux → Windows cross-compilation with MinGW-w64)

GamerServices 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 CnaTests

The resulting .exes run under Wine; SDL_GPU's Direct3D 12 backend needs vkd3d-proton (scripts/run-wine-vkd3d.sh).

Build (macOS)

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 --parallel

CI builds macOS with SOFTWARE; SDL_GPU (Metal backend) is not currently re-qualified on macOS.

Build (macOS → iOS / iPadOS cross-compilation)

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>

Optional: use system-installed SDL

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 CnaTests

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

Other renderers

cmake -S . -B build -DCNA_GRAPHICS_RENDERER=OPENGL33
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=SDL_GPU

Build (Windows cross-compilation — DIRECTX9 renderer)

A 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 --parallel

Running 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-failure

Run Demo / Verification

This 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

Tested Compilers

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

10. 📖 Usage Example

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;
}

11. 🧠 Design & Engineering Highlights

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

12. 🛣 Direction

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.

13. 📜 License

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

About

CNA is a cross-platform multi-language XNA 4.0 API ecosystem powered by a high-performance C++ core, featuring 10 renders and 10,000+ pixel-perfect integration tests

Topics

Resources

Stars

106 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages