extract WorldRenderer
This commit is contained in:
183
src/ui/WorldRenderer.h
Normal file
183
src/ui/WorldRenderer.h
Normal file
@@ -0,0 +1,183 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QColor>
|
||||
#include <QPoint>
|
||||
#include <QPointF>
|
||||
#include <QRectF>
|
||||
#include <QVector2D>
|
||||
|
||||
#include "BeamFiredEvent.h"
|
||||
#include "BuildModeController.h"
|
||||
#include "BuildingConfig.h"
|
||||
#include "BuildingId.h"
|
||||
#include "BuildingType.h"
|
||||
#include "Rotation.h"
|
||||
#include "SelectionController.h"
|
||||
#include "VisualsConfig.h"
|
||||
#include "WorldCoordinates.h"
|
||||
|
||||
class ItemIconCache;
|
||||
class Simulation;
|
||||
class QPainter;
|
||||
class QSvgRenderer;
|
||||
|
||||
// A beam still being drawn. Lifetime is counted in game ticks so beams freeze with
|
||||
// the simulation when it is paused or slowed (REQ-SHP-FIRING-BEAM); the view owns
|
||||
// the ageing, the renderer only draws what it is given.
|
||||
struct ActiveBeam
|
||||
{
|
||||
BeamFiredEvent event;
|
||||
QVector2D targetOffset;
|
||||
};
|
||||
|
||||
// Brief outline flash shown on a building when settings are copied from it or
|
||||
// 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;
|
||||
};
|
||||
|
||||
// Everything the renderer draws that the simulation does not know about: what the
|
||||
// player has selected, which build mode is active, and the other transient bits of
|
||||
// interaction state the view owns. Assembled fresh each frame and passed by
|
||||
// reference, so the renderer holds no copy that could go stale.
|
||||
struct WorldRenderFrame
|
||||
{
|
||||
const SelectionController& selection;
|
||||
const BuildModeController& buildMode;
|
||||
const std::vector<ActiveBeam>& beams;
|
||||
const std::optional<BuildingConfig>& copiedConfig;
|
||||
const std::vector<CopyConfigFlash>& copyConfigFlashes;
|
||||
bool isBoxSelecting;
|
||||
QPoint boxStartTile;
|
||||
QPoint boxCurrentTile;
|
||||
bool isDebugDrawEnabled;
|
||||
};
|
||||
|
||||
// Draws the game world: terrain, buildings, items, ships, effects and the build
|
||||
// overlays, in back-to-front order (see the Layer Order section of
|
||||
// docs/architecture.md).
|
||||
//
|
||||
// Reads the simulation and never writes it, and knows nothing about input — the
|
||||
// view resolves clicks and owns the interaction state, and hands the parts the
|
||||
// renderer needs over in a WorldRenderFrame. Screen-anchored chrome that is not
|
||||
// part of the world (the pause and deconstruct vignettes, the replay overlay)
|
||||
// stays with the view, which is also why those never took a WorldCoordinates.
|
||||
class WorldRenderer
|
||||
{
|
||||
// Not a QObject, but drawDebugOverlay puts text on screen, so it still needs
|
||||
// tr() for translation (REQ-UI-...): this declares the tr() overloads without
|
||||
// dragging in the meta-object system.
|
||||
Q_DECLARE_TR_FUNCTIONS(WorldRenderer)
|
||||
|
||||
public:
|
||||
// `itemIcons` is the window-wide per-item icon cache (REQ-UI-ITEM-ICON); not
|
||||
// owned, must outlive this renderer. `configDir` is used once, to load the
|
||||
// per-building world icons.
|
||||
WorldRenderer(Simulation& sim, const VisualsConfig& visuals,
|
||||
ItemIconCache* itemIcons, const std::string& configDir);
|
||||
~WorldRenderer();
|
||||
|
||||
void render(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
|
||||
private:
|
||||
void drawTiles(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawBuildings(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawSelectionHighlights(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawCopyConfigFeedback(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawPortItems(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawStations(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawBeltItems(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawDebris(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawShips(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawDebugSensorRanges(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawDebugTargetLines(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawBeams(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawSelectedTunnelConnections(QPainter& painter,
|
||||
const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
void drawOverlays(QPainter& painter, const WorldCoordinates& coordinates,
|
||||
const WorldRenderFrame& frame);
|
||||
// Screen-anchored, but drawn mid-world so ships and effects still paint over
|
||||
// it, as they always have.
|
||||
void drawDebugOverlay(QPainter& painter);
|
||||
|
||||
// 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 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;
|
||||
|
||||
// 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;
|
||||
|
||||
std::optional<QVector2D> entityPosition(entt::entity entity) const;
|
||||
|
||||
// Non-const only because EntityAdmin's component accessors are; the renderer
|
||||
// reads the simulation and never writes it.
|
||||
Simulation& m_sim;
|
||||
const VisualsConfig& m_visuals;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
};
|
||||
Reference in New Issue
Block a user