CubeMeshRenderer requires CNA link

Easy3D / Data & Batching / CubeMeshRenderer

Easy3D::CubeMeshRenderer is Easy3D's first Roadmap Phase 4 CNA renderer adapter: it uploads a CubeMesh's vertex/index arrays to real GPU buffers once, then Draw() issues indexed TriangleList draw calls on demand. It knows nothing about tiles, gameplay, or cameras — the caller owns and configures the BasicEffect (World/View/Projection/Texture) before calling Draw().

#include <Easy3D/CubeMeshRenderer.hpp>

namespace Easy3D { class CubeMeshRenderer; }
This is real, rendering, GPU-touching code — the first place in Easy3D that actually calls GraphicsDevice::DrawIndexedPrimitives. Everything upstream of it (CubeBatch, CubeMesh) is still plain CPU data.

The draw-path decision

Easy3D issues cube/billboard draws with raw VertexBuffer + IndexBuffer + BasicEffect + GraphicsDevice::DrawIndexedPrimitives — the same pattern CNA's own examples/house3d_demo.cpp already proves works (build GPU buffers once, SetVertexBuffer/Indices/DrawIndexedPrimitives per frame inside a pass.Apply() loop). SpriteBatch was considered and rejected: it is 2D-only, not usable for cube/billboard geometry.

Constructor — uploads once

CubeMeshRenderer(GraphicsDevice& device,
                   const std::vector<CubeVertex>& vertices,
                   const std::vector<std::uint32_t>& indices)
Uploads vertices/indices to new GPU VertexBuffer/IndexBuffer objects immediately. indices.size() must be a multiple of 3 (whole triangles); otherwise throws std::invalid_argument.

Internally, each CubeVertex{Position, Uv} converts 1:1 to CNA's VertexPositionTexture{Position, TextureCoordinate} — the field layouts match exactly, so there is no reordering or reinterpretation, just a straight copy. The index buffer always uses 32-bit indices (IndexElementSize::ThirtyTwoBits), matching CubeMesh's std::uint32_t output.

Draw

void Draw(GraphicsDevice& device, BasicEffect& effect) const
Draws the uploaded mesh once per pass of effect's current technique: for each pass, calls pass.Apply(), binds the renderer's vertex/index buffers, and issues one DrawIndexedPrimitives(TriangleList, ...) call covering the whole mesh. effect's World/View/Projection and, if texturing is wanted, TextureEnabled/Texture must already be set by the caller before calling Draw().
[[nodiscard]] int VertexCount() const noexcept
[[nodiscard]] int PrimitiveCount() const noexcept
The uploaded vertex count and triangle count (indices.size() / 3) — handy for stats/debug overlays.

Lifecycle — build once, draw many times

Unlike BillboardMeshRenderer, a CubeMeshRenderer's geometry is camera-independent — cube positions don't change when the camera moves. Build it once (on load, or whenever the level's cube batch actually changes) and call Draw() every frame against it:

// On load / level change:
std::vector<Easy3D::CubeVertex> vertices;
std::vector<std::uint32_t>      indices;
Easy3D::BuildCubeMesh(terrain, vertices, indices);
Easy3D::CubeMeshRenderer terrainRenderer(graphicsDevice, vertices, indices);

// Each frame:
effect.World      = Matrix::Identity;
effect.View        = camera.GetViewMatrix();
effect.Projection  = camera.GetProjectionMatrix();
effect.TextureEnabled = true;
effect.Texture         = tilesTexture;   // the CNA texture your TextureAtlas describes

terrainRenderer.Draw(graphicsDevice, effect);

Verification

CubeMeshRenderer's constructor needs a live GraphicsDevice&, which only exists once a real CNA Game has opened a window — something a plain test main() cannot produce. So Easy3D's own test suite only compile-checks it (see Testing); the real runtime verification was done end-to-end against Galaxy Eggbert's actual windowed binary, with a center-screen pixel readback confirming real, non-background pixels were drawn.

See CubeMesh for how to produce the vertices/indices this class consumes, and BillboardMeshRenderer for the equivalent adapter for camera-facing quads.