Easy3D is a small C++ helper library for CNA. It is a companion library that lives next to CNA — not on top of it, and not in front of it.
Easy3D provides a handful of boring, practical helpers (cameras, billboard/cube batching, a texture atlas, debug drawing) so that small 3D projects can be written against CNA without re-inventing the same glue code every time.
Its first concrete purpose is to support Galaxy Eggbert, a planned 3D remake of Mobile Eggbert / Speedy Blupi, without dragging in Urho3D, Nova-3D, Simple3D, MeshCraft, or Mesh World.
- A small helper library for CNA.
- A collection of minimal, testable utility classes.
- Used beside CNA: a game uses CNA directly and uses Easy3D where it helps.
- Free to accept and return CNA / XNA-style types (
Vector3,Matrix, …) wherever that is convenient.
- It is not a replacement for CNA. CNA remains the runtime.
- It does not hide CNA. CNA types stay fully visible in Easy3D APIs.
- It is not Simple3D, and must not grow back into Simple3D.
- It is not Nova-3D or a Urho3D-style abstraction.
- It is not a general game engine.
- It has no entity/component framework, physics, navigation, networking, editor, asset database, resource cache, model importer, or plugin system.
If you find yourself building any of the above, it does not belong in Easy3D.
- Cameras exist (
Camera3D,OrbitCamera,FollowCamera). TextureAtlassupports named rects and grid spritesheet insertion (AddGrid), plus a non-throwing lookup (GetUvOrDefault).BillboardBatch,CubeBatch, andDebugDrawstore queued data (BillboardItem/CubeItem/DebugLine+DebugBox) for later use.CubeMesh(AppendCubeMesh/BuildCubeMesh) turns queuedCubeBatchitems into plain CPU-side vertex/index arrays (24 vertices + 36 indices per cube, one UV per face) — still no GPU work. Billboard/debug-line vertex builders are not implemented yet.CubeMeshRendererdoes issue real CNA draw calls: uploads aCubeMeshto GPUVertexBuffer/IndexBufferonce, then draws it via a caller-configuredBasicEffectandGraphicsDevice::DrawIndexedPrimitives. Billboard/debug-line renderer adapters are not implemented yet — seedocs/ROADMAP.md.
Galaxy Eggbert
-> uses CNA directly
-> uses Easy3D helpers for convenience
-> may reuse Mobile Eggbert as an existing reference / data source
Easy3D
-> depends on CNA
-> does NOT hide CNA
-> contains helper classes only
CNA
-> XNA 4.0-style runtime + optional CNA/NOXNA extensions
A bad design (Easy3D hiding everything):
Easy3D::Game game;
game.RunEverything(); // NO — this is not what Easy3D is forThe intended design (CNA stays in charge, Easy3D just helps):
// The game still uses CNA directly for the Game loop, devices, input, etc.
// Easy3D only helps with cameras, billboard/cube drawing, atlases, debug draw.
Easy3D::Camera3D camera;
Easy3D::OrbitCamera orbit;
Easy3D::TextureAtlas atlas;Easy3D expects the sibling repositories to sit next to it:
.../openeggbert/
├── cna/ <- required: the CNA runtime (headers under cna/include)
├── sharp-runtime/ <- optional: used by CNA; Easy3D does NOT depend on it (yet)
└── easy-3d/ <- this repository
- CNA is expected at
../cna. Its public headers live in../cna/include(namespaceMicrosoft::Xna::Framework), and its CMake target is namedCNA. - sharp-runtime may exist at
../sharp-runtime, but Easy3D does not depend on it directly in this initial version.
Requirements: a C++23 compiler and CMake ≥ 3.20.
cmake -S . -B build
cmake --build build
ctest --test-dir buildBy default this builds:
- the
easy3dstatic library (compiled against CNA's headers), and - a small, self-contained test that exercises the CNA-free helpers.
CNA's math types (Vector3, Matrix, …) are declared in headers but
implemented in CNA's compiled .cpp files. The easy3d library compiles
fine against the headers alone, but anything that actually runs camera math
(e.g. Camera3D::GetViewMatrix()) must link the CNA library.
Because building full CNA pulls in heavy dependencies (SHARP_RUNTIME, SDL3, ffmpeg, a graphics backend), easy3d figures out CNA linkage in one of three ways:
-
A parent project already provides the
CNAtarget (a game that doesadd_subdirectory(../cna)beforeadd_subdirectory(../easy-3d)). easy3d detects the existingCNAtarget and links it automatically — no option needed. This is the path games use (see below). -
Standalone, with
-DEASY3D_LINK_CNA=ON. easy3d builds CNA itself fromEASY3D_CNA_DIR(default../cna), selecting a graphics backend viaEASY3D_CNA_BACKEND(defaultEASY_GL) and disabling CNA's own demos/tests:cmake -S . -B build -DEASY3D_LINK_CNA=ON # backend defaults to EASY_GL cmake --build build ctest --test-dir build # runs basics + camera tests
-
Otherwise (default): headers only. easy3d compiles against CNA's headers and leaves linking to the consuming application. The default build stays light and self-contained.
When CNA is linked (case 1 or 2), easy3d defines EASY3D_HAS_CNA_LINK and the
camera example and camera test are built.
A game (e.g. Galaxy Eggbert) uses CNA directly and Easy3D for convenience. Pull both in as subdirectories — add CNA first, then Easy3D auto-links it:
add_subdirectory(../cna cna) # defines the CNA target (+ chosen backend)
add_subdirectory(../easy-3d easy-3d) # detects CNA, links it automatically
add_executable(galaxy_eggbert src/main.cpp ...)
target_link_libraries(galaxy_eggbert PRIVATE CNA easy3d)
# ^^^ the game still uses CNA directly
# ^^^^^^ and Easy3D helpers beside itBecause the game already selects CNA's backend and options, easy3d does not need
EASY3D_LINK_CNA here — it simply links the CNA target the game created.
| Option | Default | Meaning |
|---|---|---|
EASY3D_BUILD_EXAMPLES |
ON |
Build the examples/ targets (camera example needs CNA linked). |
EASY3D_BUILD_TESTS |
ON |
Build the tests/ targets and register them with CTest. |
EASY3D_LINK_CNA |
OFF |
Standalone only: build CNA from EASY3D_CNA_DIR and link it. |
EASY3D_CNA_DIR |
../cna |
Path to the CNA repository. |
EASY3D_CNA_BACKEND |
EASY_GL |
CNA backend to enable when easy3d builds CNA itself (SDL_RENDERER/EASY_GL/BGFX/VULKAN). |
- Lua is intentionally not part of this version. It may later be discussed
as an optional, separate module (e.g.
easy3d-lua), but no Lua code will be added without explicit approval. Seedocs/ROADMAP.md. - Eggbert-specific logic does not live here. Anything specific to Galaxy Eggbert / Mobile Eggbert belongs in those projects, not in Easy3D.
- Mobile Eggbert is not refactored because of Easy3D or Galaxy Eggbert.
See docs/ARCHITECTURE.md and
docs/ROADMAP.md for details, and
CLAUDE.md for rules that future automated contributions must
follow.
Easy3D is licensed under the MIT License.
Note: CNA itself is licensed under the Microsoft Public License (Ms-PL). Easy3D only uses CNA's public headers; it does not copy CNA source.