Chapter 2 Ecosystem and Vocabulary
CNA does not sit alone in the openeggbert GitHub organization. It sits at the center of a small, deliberately layered set of sibling repositories, most of which expect to be checked out as literal sibling directories on disk — ../sharp-runtime, ../easy-gl, ../cna-samples, and so on — because CNake’s own build system looks for them there. This chapter is the map; later chapters (Part VIII for sharp-runtime, Part IX for easy-gl and free-direct) are the territory.
2.1 The dependency graph
| Repository | Role | Consumed by |
|---|---|---|
| sharp-runtime | C++ subset of the .NET BCL | CNA (foundation layer) |
| easy-gl | Toolkit-independent OpenGL/ES wrapper | CNA’s five EasyGL-backed profiles |
| free-direct | DirectDraw/DirectSound/DirectPlay subset | CNA’s FREEDIRECT renderer |
| xna4-spec | Machine-readable XNA 4.0 API spec (XML) | Compatibility audits of CNA |
| cna-samples | Ports of official XNA 4.0 samples | Exercises CNA end-to-end |
| cna-examples | In-app demo catalog for CNA | Exercises CNA end-to-end |
Every one of these is a genuinely independent, separately buildable, separately tested project — none of them is a vendored copy or a submodule of CNA. sharp-runtime in particular describes itself as serving “as a foundation for higher-level frameworks (e.g. CNA)” and lists CNA as its own downstream consumer, not the other way around; you could, in principle, use sharp-runtime or easy-gl in a project that has nothing to do with XNA at all.
2.2 The sibling build graph
The dependency graph above is not just a narrative claim — it is exactly what CNA’s own CMakeLists.txt and cmake/RendererSelection.cmake do at configure time, checked directly rather than assumed. Every sibling dependency follows the identical pattern: an if(NOT EXISTS …/CMakeLists.txt) guard that fails configuration outright, with a real, copy-pasteable fix in the error message itself, rather than failing confusingly deep in a missing-header compile error later:
sharp-runtime is unconditionally required (add_subdirectory(../sharp-runtime SHARP_RUNTIME) runs regardless of renderer choice); easy-gl and free-direct are each pulled in only when a matching -DCNA_GRAPHICS_RENDERER value is selected, so a plain SDL_RENDERER or VULKAN build never even checks whether those two sibling directories exist.
A real, second-level dependency this book’s dependency-graph table doesn’t show. free-direct is not a leaf in this graph — its own CMakeLists.txt pulls in a third sibling repository, free-api, an experimental, small WinAPI-compatibility-subset project (targeting roughly the Win32 API surface as it existed around 1998) built on SDL3 the same way every other project in this ecosystem is, per free-api’s own README. RendererSelection.cmake’s own comment explains why this does not need a separate SDL configuration flag: free-direct resolves SDL3::SDL3 / SDL3_image::SDL3_image / SDL3_mixer::SDL3_mixer from CNA’s own already-vendored targets, set up before renderer selection runs, so the whole three-level chain (CNA free-direct free-api) shares one SDL3 build rather than each level vendoring its own. The same comment names two real, independent consumers of free-direct beyond CNA itself — free-eggbert and planetblupi — confirming this sibling chain is genuinely reused ecosystem infrastructure, not machinery built only for CNA’s own FREEDIRECT renderer.
2.3 sharp-runtime: the floor CNA stands on
XNA’s public API vocabulary assumes .NET underneath it: byte, TimeSpan, events, IDisposable, System.Object.GetType(). A C++ reimplementation of XNA has two choices — invent ad-hoc C++ substitutes for all of that inline, scattered through the XNA porting work itself, or build the .NET-shaped foundation once, as its own project, and depend on it. CNA’s own CLAUDE.md porting rules choose the second option explicitly: “If CNA needs anything from .NET that is not yet in sharp-runtime — a type alias, a class, an interface, an exception type, a utility — add it to sharp-runtime first, then use it from CNA. Do not inline .NET concepts directly into CNA headers as raw C++ types or ad-hoc workarounds.”
sharp-runtime is explicit that it is not attempting a CLR: no reflection, no GC, no delegates beyond std::function, no serialization infrastructure, no P/Invoke, no full cryptography/TLS stack. What it does provide is documented as a “pragmatic subset designed for use in native C++ applications,” tracked class-by-class in a SQLite database (plan.sqlite3) whose exact blob exists in the pinned commit despite also matching a current ignore rule, with an honest, small state machine per .NET type: todo, ported, ignore / ignored, or tobedecided for genuinely ambiguous cases that need a human architecture call rather than a guess. Chapter 53 and Chapter 56 cover sharp-runtime’s own architecture, its System::* namespace layout, and its component-isolated test apparatus in depth; Chapter 57 covers the specific question of how strictly CNA insists on that .NET shape versus where it deliberately diverges.
2.4 easy-gl: OpenGL without a windowing opinion
The EasyGL renderer family — five public OpenGL/OpenGL ES profiles sharing one implementation factory — is built on easy-gl, a small, toolkit-independent C++20 wrapper over OpenGL and OpenGLES. Its defining architectural choice is what it refuses to own: no window creation, no GL context creation, no event loop. The host application (CNA, in this case) owns the window, creates and activates the GL context, and hands easy-gl a GetProcAddress-style loader callback; easy-gl owns everything from there down — shader compilation and linking, buffers, vertex arrays, textures, draw calls, and capability queries that let calling code gate OpenGL-only features (like polygon-mode fill flags) away from OpenGLES targets at runtime via device.supports(...) / device.require(...). As of the snapshot this book draws from, easy-gl’s own README describes its scope as still a deliberately compact, evolving vertical slice — initialization, capability detection, and basic draw flow, exercised by its own hello-triangle-sdl example and two dedicated smoke-test suites (easy-gl-smoke-tests, easy-gl-resource-smoke-tests) — with CNA’s own EasyGL implementation having grown well beyond that slice on top of it, per Chapter 22. Chapter 59 covers easy-gl’s public API surface (easygl::Device, easygl::Shader, easygl::Program, easygl::Buffer, easygl::VertexArray, easygl::Texture, easygl::Feature) in full.
A live instance of this book’s own recurring pattern, caught in a sibling repo rather than in CNA itself. easy-gl carries its own MIGRATION.md (added 2026-07-19, alongside a new 845-line PLAN.md), a nine-row “breaking change summary” table framed entirely in future tense — Framebuffer::attach_texture_2d “now takes const Texture&”, Program::uniform_block_index “returns std::optional<unsigned int>”, and six more signature changes, each described as “planned for the next release”. Reading the real, current headers directly instead of trusting that framing shows every single one of the nine has already landed: checking a sample of five directly against five real include/easygl/ headers — Framebuffer.hpp, Program.hpp, and three others — finds attach_texture_2d is already taking const Texture&, uniform_block_index already returning the optional, and the remaining three checked signatures (ProgramPipeline’s two Program-typed parameters, TransformFeedback::set_varyings, Sync::native_handle()’s GLsync return type) all already in their described post-migration form. MIGRATION.md is not wrong about what changed — it is simply stale about when, describing already-shipped API surface as still upcoming. This is the identical shape of finding this book has made repeatedly about CNA’s own tracked documents (a snapshot that outlived the moment it was accurate), just observed here in a sibling repository this book does not otherwise audit — worth naming because it is independent confirmation that the failure mode is a property of fast-moving source-controlled documentation generally, not something specific to this project’s own writing habits.
2.5 free-direct: DirectX 3 scoped to two legacy games
Where easy-gl is a general-purpose OpenGL wrapper, free-direct is the opposite kind of project: a deliberately narrow, game-driven reimplementation of a subset of DirectX 3 (2D) — DirectDraw, DirectSound, and DirectPlay — built on SDL3 internally, whose explicit goal is not DirectX compatibility in general but running two specific legacy Windows games (Speedy Blupi and Planet Blupi) without their original OS dependencies. Its own README states the non-goals as plainly as the goals: no full DirectX 3 compatibility, no hardware-accurate emulation, no Direct3D pipeline, and no expansion of APIs the target games do not actually call. This project backs CNA’s FREEDIRECT graphics renderer (Chapter 26) and is covered as a project in its own right, including its real (not stubbed) ENet-backed DirectPlay networking, in Chapter 60 and in the Speedy Blupi/Planet Blupi porting case study in Chapter 75. free-direct’s own test suite is deliberately split by transport: the default ctest run (no label filter) exercises LoopbackDirectPlayTransport’s synchronous semantics and is not expected to pass directplay_tests unmodified against a real, asynchronous ENet build (1 of 8 tests fails that way, by design, not as a regression); a separate -L enet label opts into the ENet-backed transport tests specifically, verified 1/1 passing.
2.6 xna4-spec: a ground truth to audit against
A recurring failure mode for any reimplementation project is drift between what the README claims and what the code actually does — and a subtler one is drift between what the README claims and what the original API actually specified, from memory rather than from a real reference. xna4-spec exists to remove the second failure mode. It is a complete, machine-readable XML transcription of the official XNA 4.0 documentation — every class, struct, enum, interface, and delegate across all 19 XNA namespaces, 544 types in total, with their original property/method/constructor/field/event descriptions — converted from Microsoft’s own learn.microsoft.com XNA 4.0 reference pages. Its own README states its purpose directly: “Auditing C++ reimplementations of XNA 4.0 (comparing what is implemented vs. what is missing).” CNA’s release prose repeats a dated 227-of-245 public-FNA-type presence audit (92.7%). That denominator came from diffing FNA’s public type list against CNA headers, not from xna4-spec, and alpha.1 does not ship a generator that re-derives it as a tag invariant. Treat it as a historically recorded, methodology-limited presence snapshot—not behavioral coverage and not a fresh count made by this edition. Chapter 76 walks through using xna4-spec to run this kind of audit yourself, worked through in full against a real class (Ray) rather than described only in the abstract.
2.7 cna-samples and cna-examples: two different kinds of proof
Two sibling repositories exist purely to give CNA something real to run, and they answer two different questions.
cna-samples is a C++ porting catalog for the official Microsoft XNA Game Studio 4.0 sample archives, licensed Ms-PL to match its Microsoft-derived origin. Its question is: does CNA run real, historical XNA sample code? At the pinned revision its plan accounts for 153 archive entries: 63 completed ports, 23 tracked placeholders, and 67 deliberate exclusions. Those are catalog statuses, not fresh execution results; Chapter 77 explains why each dated placeholder must be re-audited before it is counted as a current CNA gap.
cna-examples is original, MIT-licensed CNA-specific work — explicitly not a port of Microsoft’s sample collection, precisely so it can carry a permissive license cna-samples cannot. Conceptually inspired by JavaFX’s Ensemble sample browser, it is a single cross-platform application (desktop, Web, mobile) that lets a reader navigate Area Category Demo (Input, Audio, Devices, Net, Media, 2D/3D Graphics, …) and run a live demonstration of each area, all inside one binary. Its question is: does CNA have a coherent, in-app way to show off everything it can do? As of the snapshot this book draws from it is an early skeleton — the application boots and navigates Area Category, but individual demo screens are not yet implemented, and only the EasyGL-backed renderer family is targeted so far.
2.8 Repositories mentioned but out of this book’s scope
The openeggbert organization hosts a considerably larger set of repositories beyond the six above — additional CNA-adjacent projects (cna-template, cna-extended, cna-craft), other graphics libraries (meta-gl, easy-3d), actual shipped games and tools built on this stack (mesh-craft, galaxy-eggbert, free-eggbert, planetblupi, mobile-eggbert), and a long tail of per-project marketing/documentation sites (the *.openeggbert.com repositories). This book’s scope is deliberately the six repositories in the table above, because they are the ones CNA’s own build system, README, and CLAUDE.md porting rules directly name as dependencies or verification partners. Appendix D gives a fuller repository map for readers who want to go further.