WorldRenderer
Draws the 3D world from a SceneFrame: the draw list says what, WorldRenderer says how.
| Header | src/GalaxyEggbert/Game/WorldRenderer.hpp |
|---|---|
| Source | src/GalaxyEggbert/Game/WorldRenderer.cpp; the effects' parts in src/GalaxyEggbert/Game/WorldEffects.cpp |
| Namespace | GalaxyEggbert::Game |
| Since | 2026-11-09 (extracted from the game's draw code; frames byte-equal to before) |
Purpose
WorldRenderer is the drawing half of the seam between simulation and rendering. The host builds a
SceneFrame (src/GalaxyEggbert/Game/SceneFrame.hpp) from the game's state in
src/GalaxyEggbertCNA/GalaxyEggbertGameScene.cpp; WorldRenderer reads only that list and the assets it is lent,
and sets all device state itself. It owns only what drawing needs from frame to frame: per-frame GPU meshes for the
background, cubes, billboards, shadows and particles, a decal effect, a tint texture, the effects' shaders
(SceneShaders, SurfaceShaders) and Ultra's smoothed model parts. The content it draws with — effects, textures,
models, the TerrainRenderer — belongs to the game and arrives each frame as a
WorldRenderAssets; any of it may be null, and then that part is left out.
Collaborators
SceneFrameand its parts (SceneCamera,SceneModel,SceneQuad,SceneBillboardBatch,SceneEffects).- TerrainRenderer:
UpdateRelief,DrawOpaque,DrawGrass,DrawTransparent, shadow and geometry passes. SceneShaders(shadow map, occlusion, point lights, Ultra's lighting),SurfaceShaders(water, lava),ModelSubdivision.hpp(Ultra's smoother models),BlockModels.hpp(which saw and teleporter parts show).- CNA:
BasicEffect,SkinnedEffect,SkinnedModelEXT,GraphicsDevice; cna-engine:MeshBuilder,GpuMesh. - GalaxyEggbertGame: owns one
worldRenderer_, builds the frame, lends the assets (SceneAssets()), runsPostProcessorUltraFinisharound it.
Public API
| Member | What it does |
|---|---|
using TerrainDrawnHook = std::function<void(GraphicsDevice&)> | Called once the terrain, every model and decal are drawn, before the billboards. |
void Draw(GraphicsDevice& device, const SceneFrame& frame, const WorldRenderAssets& assets, const TerrainDrawnHook& terrainDrawn = {}) | Draws the world: fog, background, terrain pass (with cubes, grass, models, decals, water last), billboards, particles. Nothing when frame.world is false. |
void RenderShadowMap(device, frame, assets) | The effects' sun shadow map; call before Draw() and before anything is drawn into the frame's target. Leaves the screen bound; does nothing without the effects or where the device cannot. |
bool DrawGeometry(device, frame, assets) | Ultra's geometry pass (normal, depth, mirror per pixel) into the bound target; false when there is none. |
bool DrawSmoothPart(device, part) | Ultra's subdivided version of a model part, made on first request; false where it cannot be. |
const SceneShaders& Scene() const | The effects' shading, e.g. the shadow map's cascades for Ultra's fog. |
bool TerrainShadersReady(device) | Whether the effects' terrain shader compiles here; decides if the terrain is built with ambient occlusion. |
const WorldRenderStatistics& Statistics() const, void ResetStatistics() | Model draws, triangles and culled models, for the performance output. |
WorldRenderAssets fields: background, terrain, grass, cubes (BasicEffect*),
models (SkinnedEffect*), one effect per sprite sheet (element, objectM, explo,
blupi, blupi1, bigDecor), terrainRenderer and ultra.
WorldRenderStatistics: modelDraws, modelTriangles, modelsCulled.
How it is used
From src/GalaxyEggbertCNA/GalaxyEggbertGameDraw.cpp:
BuildSceneFrame(sceneFrame_, soulDrawnIn3D);
...
const auto assets = SceneAssets();
worldRenderer_.RenderShadowMap(device, sceneFrame_, assets);
...
worldRenderer_.ResetStatistics();
worldRenderer_.Draw(device, sceneFrame_, assets,
[this](Microsoft::Xna::Framework::Graphics::GraphicsDevice& drawn) { CheckTerrainVisibility(drawn); });
- Keep the frame's list order. What is drawn first stays first, so blending and depth come out the same as before the refactor; water must stay after the models (OR-0052).
- To show something new in the world, add it to
SceneFramein the scene builder and draw it here. Do not letWorldRendererread the simulation directly. - With the effects off, every frame must stay byte-equal to the classic look; the golden frames check that.
- Billboards are blended with
NonPremultipliedbecause the sprite sheets are loaded with straight alpha.
Tests
No CTest drives WorldRenderer itself: it needs a GPU. Its output is locked by the golden frames
(tools/verify_golden_frames.sh: tests/golden/, effects-medium/, effects-high/) and the lava depth
regression (tools/verify_lava_depth.py), both run by hand under Xvfb. The effects' decisions are tested without a GPU:
VerifySceneEffects (shadows, lights, occlusion; SceneEffectsLogic.hpp), VerifyUltra and
VerifyEffectParticles.
Related pages
- Rendering — the whole frame, the effect levels, the HUD.
- TerrainRenderer, TileAtlas, GalaxyEggbertGame.
- 3D Effects & Graphics — the settings as a player sees them.