extract WorldRenderer
The last seam of the decomposition, and the one the earlier ones were groundwork for: every draw method already took a WorldCoordinates, read mode state through BuildModeController and selection through SelectionController, and used the shared shapes in WorldPrimitives, so the move needed almost no rewriting. paintGL is now a call sequence. The split is the world-space / screen-space line already drawn by the WorldCoordinates work: the renderer draws everything positioned in tiles, while the pause and deconstruct vignettes and the replay overlay - which never took a WorldCoordinates because they are anchored to the viewport - stay with the widget. WorldRenderFrame is what keeps the renderer independent of the widget. It reads the simulation directly, but the rest of what it draws is interaction state the widget owns: the selection, the active build mode, live beams, the copy-settings feedback, the box-select rectangle. Those are gathered per frame and passed by reference, so the renderer holds no copy a later click could invalidate, and it knows nothing about input. Three more queries had to stop belonging to the view first, because the renderer and the click path both need them: buildingsInBox and collectTunnelTiles move to FactoryQueries, and makeTunnelLookup with the TunnelTileMap and QPointCompare it needs move to TunnelCompletion, which already owned that concept. Two small things fell out of leaving QWidget. The port-item clip region used QWidget::rect() and now takes the painter's own viewport. drawDebugOverlay puts translated text on screen, so the renderer declares tr() via Q_DECLARE_TR_FUNCTIONS rather than becoming a QObject. drawDebugOverlay stays in the renderer despite being screen-anchored: it is drawn mid-sequence, so moving it out would put it on top of the ships instead of under them. The simulation reference is non-const only because EntityAdmin's component accessors are; the renderer never writes it. Draw order is unchanged, and so is behaviour. GameWorldView.cpp is 1431 lines, from 3265 when this branch started. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JcReq7hVk4KUPhTDKWAG7K
This commit is contained in:
@@ -61,6 +61,7 @@
|
||||
#include "VisualsConfig.h"
|
||||
#include "WorldCamera.h"
|
||||
#include "WorldCoordinates.h"
|
||||
#include "WorldRenderer.h"
|
||||
|
||||
struct Command;
|
||||
struct ParsedReplay;
|
||||
@@ -68,19 +69,6 @@ class ItemIconCache;
|
||||
class ReplayPlayer;
|
||||
class Simulation;
|
||||
class QPainter;
|
||||
class QSvgRenderer;
|
||||
|
||||
struct QPointCompare
|
||||
{
|
||||
bool operator()(const QPoint& a, const QPoint& b) const
|
||||
{
|
||||
if (a.x() != b.x()) { return a.x() < b.x(); }
|
||||
return a.y() < b.y();
|
||||
}
|
||||
};
|
||||
|
||||
// Tunnel entries/exits indexed by their single-cell tile (REQ-BLD-TUNNEL-MODE).
|
||||
using TunnelTileMap = std::map<QPoint, TunnelTileInfo, QPointCompare>;
|
||||
|
||||
class GameWorldView : public QOpenGLWidget,
|
||||
public CombinedEventHandler<BeamFiredEvent,
|
||||
@@ -159,29 +147,8 @@ private:
|
||||
// Used to pre-validate placements whose UI follow-up depends on success.
|
||||
bool canAfford(BuildingType type) const;
|
||||
|
||||
// World-space drawing takes the frame's transform (see getCoordinates()) rather
|
||||
// than reaching for the scroll position and viewport size itself; the
|
||||
// screen-space draws below need neither.
|
||||
void drawTiles(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawPortItems(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawBuildings(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawSelectionHighlights(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawCopyConfigFeedback(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawStations(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawBeltItems(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
// Draws a single item centered at widget-space `center`, spanning `halfPx` in
|
||||
// each direction (a half-tile). Uses the item's icon when one exists
|
||||
// (REQ-UI-ITEM-ICON), otherwise falls back to the colored square from
|
||||
// visuals.toml. Shared by drawBeltItems and drawPortItems.
|
||||
void drawWorldItem(QPainter& painter, const std::string& itemId,
|
||||
QPointF center, float halfPx);
|
||||
void drawDebris(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawShips(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawDebugSensorRanges(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawDebugTargetLines(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawDebugOverlay(QPainter& painter);
|
||||
void drawBeams(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
void drawOverlays(QPainter& painter, const WorldCoordinates& coordinates);
|
||||
// Screen-anchored chrome, drawn after the world (see WorldRenderer): these
|
||||
// need no world transform, which is exactly why they stayed here.
|
||||
void drawScreenSpace(QPainter& painter);
|
||||
// Vignette-style border shown while the game is paused (speed 0x, REQ-UI-PAUSE-BORDER)
|
||||
// to make the paused state hard to miss: a black frame whose alpha fades from 50% at
|
||||
@@ -197,17 +164,14 @@ private:
|
||||
void drawVignetteBorder(QPainter& painter, const QColor& edgeColor);
|
||||
void drawReplayOverlay(QPainter& painter);
|
||||
|
||||
// Gathers the interaction state the renderer needs for this frame.
|
||||
WorldRenderFrame makeRenderFrame() const;
|
||||
|
||||
// The world <-> widget transform for the current viewport size and scroll
|
||||
// position. Cheap to build and deliberately not cached: it is a snapshot that
|
||||
// a resize or a scroll invalidates, so every user takes a fresh one.
|
||||
WorldCoordinates getCoordinates() const;
|
||||
|
||||
// Widget-space rectangle covering a building or construction site's footprint,
|
||||
// or nullopt if the id resolves to neither. Shared by the selection highlight
|
||||
// and the copy-settings feedback (REQ-BLD-COPY-CONFIG-FEEDBACK).
|
||||
std::optional<QRectF> footprintWidgetRect(const WorldCoordinates& coordinates,
|
||||
BuildingId id) const;
|
||||
|
||||
float getAsteroidLeftEdge() const;
|
||||
float getEnemyStationRightEdge() const;
|
||||
// The camera's current pan limits, read fresh from the simulation each frame:
|
||||
@@ -218,36 +182,9 @@ private:
|
||||
bool canPlaceBuildingHere(BuildingType type, QPoint anchor, Rotation rot) const;
|
||||
std::optional<BuildingId> buildingAtTile(QPoint tile) const;
|
||||
std::optional<BuildingId> siteAtTile(QPoint tile) const;
|
||||
// Ids of all buildings and construction sites whose footprint intersects
|
||||
// the tile box spanned by the two (unordered) corner tiles.
|
||||
std::vector<BuildingId> buildingsInBox(QPoint cornerA, QPoint cornerB) const;
|
||||
|
||||
void drawPortGlyph(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
QPoint tile, Rotation direction, const QColor& color,
|
||||
bool centered);
|
||||
|
||||
void drawBuildingGhost(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
BuildingType type,
|
||||
QPoint anchorTile, Rotation rotation, bool valid,
|
||||
bool showPortTargetGlyphs);
|
||||
|
||||
// Loads the per-building world icons (REQ-UI-WORLD-ICON) from
|
||||
// <configDir>/../icons/buildings once at construction. Only the building
|
||||
// types with a world icon are loaded (production buildings, HQ, stations);
|
||||
// belts, splitters, and tunnels are deliberately excluded so their
|
||||
// orientation stays readable. The SVG's chip background is stripped; the
|
||||
// glyph is pre-rendered in both white and dark ink for auto-contrast.
|
||||
void loadBuildingIcons(const std::string& configDir);
|
||||
// Draws a building's world icon glyph centered in box, choosing the white or
|
||||
// dark pre-rendered variant by fill luminance so it stays legible. Returns
|
||||
// false if the type has no world icon (caller falls back to the text glyph).
|
||||
bool drawBuildingIcon(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
BuildingType type,
|
||||
const QRectF& box, const QColor& fill) const;
|
||||
|
||||
void placeBlueprintAtTile(QPoint center);
|
||||
|
||||
std::optional<QVector2D> entityPosition(entt::entity entity) const;
|
||||
// Drops despawned or fully-collected debris from the selection
|
||||
// (REQ-UI-DEBRIS-CLICK-SELECT). Called each frame from onFrame().
|
||||
void pruneDespawnedDebris();
|
||||
@@ -266,17 +203,6 @@ private:
|
||||
// ghost tile, rotation, and sub-tile cursor position, storing both on the build
|
||||
// mode controller. Only meaningful in tunnel mode (REQ-BLD-TUNNEL-MODE).
|
||||
void updateTunnelGhost();
|
||||
// Indexes every tunnel entry/exit — built or still a construction site — by its
|
||||
// single-cell tile. Shared by the placement preview and the selection highlight.
|
||||
TunnelTileMap collectTunnelTiles() const;
|
||||
// Wraps a tunnel tile index in the lookup functor the TunnelCompletion helpers
|
||||
// take. The returned functor references `tunnels`, which must outlive it.
|
||||
static TunnelLookup makeTunnelLookup(const TunnelTileMap& tunnels);
|
||||
// Draws the green connection highlight for every selected tunnel end that has a
|
||||
// matching end (REQ-BLD-TUNNEL-SELECT-HIGHLIGHT).
|
||||
void drawSelectedTunnelConnections(QPainter& painter,
|
||||
const WorldCoordinates& coordinates);
|
||||
|
||||
// Belt drag placement (REQ-BLD-BELT-DRAG).
|
||||
// Recomputes the drag path from its anchor to cursorTile using the current ghost
|
||||
// orientation, and stores it on the build mode controller.
|
||||
@@ -297,12 +223,6 @@ private:
|
||||
// The mode transitions themselves live on m_buildMode.
|
||||
void rotateGhost(bool clockwise);
|
||||
|
||||
struct ActiveBeam
|
||||
{
|
||||
BeamFiredEvent event;
|
||||
QVector2D targetOffset;
|
||||
};
|
||||
|
||||
// Beam lifetime in game ticks so beams freeze with the simulation when
|
||||
// paused or slowed, instead of fading on wall-clock time (REQ-SHP-FIRING-BEAM).
|
||||
static constexpr Tick kBeamLifetimeTicks = secondsToTicks(0.3);
|
||||
@@ -311,22 +231,6 @@ private:
|
||||
const GameConfig* m_config;
|
||||
const VisualsConfig* m_visuals;
|
||||
|
||||
// World icon glyph renderers per building type (REQ-UI-WORLD-ICON), in a
|
||||
// white and a dark variant so drawBuildingIcon can auto-contrast against the
|
||||
// building's fill. Rendered as vector at the view scale each draw so they
|
||||
// stay crisp. Populated once by loadBuildingIcons().
|
||||
struct BuildingIconRenderers
|
||||
{
|
||||
std::unique_ptr<QSvgRenderer> white;
|
||||
std::unique_ptr<QSvgRenderer> dark;
|
||||
};
|
||||
std::map<BuildingType, BuildingIconRenderers> m_buildingIcons;
|
||||
|
||||
// Per-item icon cache (REQ-UI-ITEM-ICON), shared window-wide and owned by
|
||||
// MainWindow. Shared draw path for belt and port items; pixmaps are cached
|
||||
// per target size.
|
||||
ItemIconCache* m_itemIcons;
|
||||
|
||||
// Funnels all player input into the single Simulation::apply chokepoint.
|
||||
CommandManager m_commandManager;
|
||||
// A Reset command was enqueued; reset the view after the next drain applies it.
|
||||
@@ -335,6 +239,10 @@ private:
|
||||
// live input is ignored (the CommandManager is in replay mode).
|
||||
std::unique_ptr<ReplayPlayer> m_replayPlayer;
|
||||
|
||||
// Draws the world; this widget supplies the interaction state each frame and
|
||||
// keeps only the screen-anchored chrome for itself.
|
||||
std::unique_ptr<WorldRenderer> m_renderer;
|
||||
|
||||
TickDriver m_tickDriver;
|
||||
QElapsedTimer m_frameTimer;
|
||||
std::mt19937 m_rng;
|
||||
@@ -366,11 +274,6 @@ private:
|
||||
// pasted onto it (REQ-BLD-COPY-CONFIG-FEEDBACK). remainingMs counts down in
|
||||
// wall-clock time so the flash plays at a fixed length regardless of game speed
|
||||
// (and while paused).
|
||||
struct CopyConfigFlash
|
||||
{
|
||||
BuildingId id;
|
||||
qint64 remainingMs;
|
||||
};
|
||||
std::vector<CopyConfigFlash> m_copyConfigFlashes;
|
||||
static constexpr qint64 kCopyFlashDurationMs = 300;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user