Getting Started with CNA
This guide targets CNA 0.1.0-alpha.1, the first tagged pre-release. Start with a single renderer and the default SDL3 platform/audio implementations; multi-renderer selection, SDL2/Headless/Terminal platforms, non-default audio-device selection and compiled Effect Framework bytecode are opt-in topics covered by their dedicated guides. Only CNA_AUDIO_PLATFORM=SDL3 enables the tag's real XNA mixer/playback path. The tag also contains an experimental C API source layer, but its final library target is compile-blocked and is not a usable getting-started path. APIs may change before 1.0, so pin v0.1.0-alpha.1 when following these commands.
What you are getting
CNA is a C++ framework that mirrors the XNA 4.0 programming model. You write game code against Microsoft::Xna::Framework. The default build uses SDL3 for host and audio services, but CNA_PLATFORM, CNA_AUDIO_PLATFORM and graphics-renderer selection are independent.
If you have XNA or MonoGame experience, the patterns will feel familiar. The main difference is C++ instead of C#.
Prerequisites
Linux
- CMake 3.20 or newer
- C++23-capable compiler: GCC 12+ or Clang 15+
../sharp-runtimedirectory (sibling to the CNA repo) - no external dependencies../easy-gldirectory - only needed for theOPENGLES3renderer- SDL3, SDL3_image, and SDL3_mixer are built from vendored submodules - no system packages required
Windows
- CMake 3.20 or newer
- One of: MSVC 2022 (v17.8+), clang-cl, or MinGW-w64
..\sharp-runtimedirectory (sibling to the CNA repo)- SDL3 built from vendored submodules - no pre-built binaries or
CMAKE_PREFIX_PATHneeded
System requirements
| Component | Requirement |
|---|---|
| Compiler | GCC 12+, Clang 15+, or MSVC 2022 v17.8+ (C++23 required) |
| Build system | CMake 3.20+ |
| Git | Any recent version (for submodules) |
| OpenGL (OPENGLES3 renderer) | OpenGL ES 3.0 or OpenGL 3.0+ desktop; GPU driver installed |
| Vulkan (VULKAN renderer) | Vulkan-capable GPU; vulkan-headers / libvulkan-dev |
| Disk space | ~500 MB (source + build artifacts) |
| RAM | 4 GB minimum for compilation |
| Sibling repos | sharp-runtime and (for OPENGLES3) easy-gl cloned alongside cna/ |
Clone & initialise
git clone https://github.com/openeggbert/cna.git
cd cna
git submodule update --init --recursive
This populates third_party/SDL, third_party/SDL_image, and third_party/SDL_mixer. After this step no system SDL packages are required.
Quick start build (Linux - EasyGL renderer)
git submodule update --init --recursive
cmake -S . -B build -DCNA_GRAPHICS_RENDERER=OPENGLES3
cmake --build build --target CnaTests
ctest --test-dir build --output-on-failure
Quick start build (Linux - SDL_Renderer renderer)
cmake -S . -B build-sdlrenderer -DCNA_GRAPHICS_RENDERER=SDL_RENDERER
cmake --build build-sdlrenderer --target CnaTests
Verify the build
# Run the test suite
ctest --test-dir build --output-on-failure
# Run the hello-triangle verification demo
cmake --build build --target hello-triangle-sdl
Minimal game skeleton
Here is the smallest possible CNA game - a window that clears to cornflower blue, the traditional XNA default clear colour.
#include <memory>
#include "Microsoft/Xna/Framework/Game.hpp"
#include "Microsoft/Xna/Framework/Color.hpp"
#include "Microsoft/Xna/Framework/Graphics/GraphicsDeviceManager.hpp"
#include "Microsoft/Xna/Framework/Graphics/SpriteBatch.hpp"
#include "Microsoft/Xna/Framework/Graphics/Texture2D.hpp"
using namespace Microsoft::Xna::Framework;
using namespace Microsoft::Xna::Framework::Graphics;
class MyGame final : public Game {
public:
MyGame() : graphics_(this) {}
protected:
void LoadContent() override {
spriteBatch_ = std::make_unique<SpriteBatch>(getGraphicsDeviceProperty());
logo_ = std::make_unique<Texture2D>("assets/logo.png", getGraphicsDeviceProperty());
}
void Update(GameTime& gameTime) override {
(void)gameTime;
// Update game state here.
}
void Draw(const GameTime& gameTime) override {
(void)gameTime;
auto& device = getGraphicsDeviceProperty();
device.Clear(CornflowerBlue);
spriteBatch_->Begin();
spriteBatch_->Draw(*logo_, 100.0f, 80.0f);
spriteBatch_->End();
device.Present();
}
private:
GraphicsDeviceManager graphics_;
std::unique_ptr<SpriteBatch> spriteBatch_;
std::unique_ptr<Texture2D> logo_;
};
int main() {
MyGame game;
game.Run();
return 0;
}
Testing your build
CNA's tag contains 568 C++ test source files and 8,263 static GoogleTest-family definitions covering the framework and configuration-specific modules.
# Run all tests
ctest --test-dir build --output-on-failure
# Or build and run directly
cmake --build build --target CnaTests
./build/CnaTests
This runs what the configured build registered. Parameterized tests, platform/renderer selection, optional layers and dependencies change the executable and CTest inventory; run ctest --test-dir build -N to inspect it. See Verification & Known Issues.
3D rendering example
The following example draws a coloured triangle using the EasyGL or Vulkan renderer. It demonstrates VertexBuffer, BasicEffect, and the DrawPrimitives call.
#include "Microsoft/Xna/Framework/Game.hpp"
#include "Microsoft/Xna/Framework/Graphics/GraphicsDeviceManager.hpp"
#include "Microsoft/Xna/Framework/Graphics/BasicEffect.hpp"
#include "Microsoft/Xna/Framework/Graphics/VertexBuffer.hpp"
#include "Microsoft/Xna/Framework/Graphics/VertexPositionColor.hpp"
using namespace Microsoft::Xna::Framework;
using namespace Microsoft::Xna::Framework::Graphics;
class TriangleGame final : public Game {
public:
TriangleGame() : graphics_(this) {
graphics_.setPreferredBackBufferWidthProperty(800);
graphics_.setPreferredBackBufferHeightProperty(600);
}
protected:
void LoadContent() override {
effect_ = std::make_unique<BasicEffect>(getGraphicsDeviceProperty());
effect_->VertexColorEnabled = true;
VertexPositionColor vertices[] = {
{ Vector3( 0.0f, 0.5f, 0.0f), Color::Red },
{ Vector3( 0.5f, -0.5f, 0.0f), Color::Green },
{ Vector3(-0.5f, -0.5f, 0.0f), Color::Blue },
};
vb_ = std::make_unique<VertexBuffer>(
getGraphicsDeviceProperty(),
VertexPositionColor::VertexDeclaration,
3, BufferUsage::None);
vb_->SetData(vertices, 3);
}
void Update(GameTime&) override {}
void Draw(const GameTime&) override {
auto& gd = getGraphicsDeviceProperty();
gd.Clear(Color::CornflowerBlue);
effect_->setWorldProperty(Matrix::Identity);
effect_->setViewProperty(Matrix::CreateLookAt(
Vector3(0, 0, 2), Vector3::Zero, Vector3::Up));
effect_->setProjectionProperty(Matrix::CreatePerspectiveFieldOfView(
MathHelper::PiOver4, 800.0f / 600.0f, 0.1f, 100.0f));
gd.SetVertexBuffer(*vb_);
for (auto& pass : effect_->getCurrentTechniqueProperty().Passes) {
pass.Apply();
gd.DrawPrimitives(PrimitiveType::TriangleList, 0, 1);
}
gd.Present();
}
private:
GraphicsDeviceManager graphics_;
std::unique_ptr<BasicEffect> effect_;
std::unique_ptr<VertexBuffer> vb_;
};
int main() { TriangleGame game; game.Run(); }
Build with the OPENGLES3 or VULKAN renderer — 3D rendering is not available on SDL_RENDERER. See the 3D Rendering guide for the full API.
Next steps
- Full build instructions - all platforms and renderers
- Renderers - which renderer to choose and why
- Platform support - Linux, Windows, Android, web
- XNA compatibility - what is implemented
- FAQ - common questions
External references
CNA targets the XNA 4.0 API surface. These references document the target API: