Polyphase Game Engine
Loading...
Searching...
No Matches
TilePaintManager.h
Go to the documentation of this file.
1#pragma once
2
3#if EDITOR
4
5#include <vector>
6#include <set>
7#include <string>
8#include <cstdint>
9#include "Maths.h"
10#include "Assets/TileMap.h"
11
12class TileMap2D;
13class Node;
14
15enum class TileSculptMode : uint8_t
16{
17 Pencil = 0,
18 Eraser,
19 Picker,
20 RectFill,
21 FloodFill,
22 Line,
23 NineBox,
24 Select,
25 Autotile,
26
27 Count
28};
29
30// One mutated cell in a stroke. Captured both for forward application and
31// for reverse-undo.
32struct TilePaintChange
33{
34 int32_t mCellX = 0;
35 int32_t mCellY = 0;
36 int32_t mLayer = 0;
37 TileCell mOldCell;
38 TileCell mNewCell;
39};
40
41struct TileSculptOptions
42{
43 TileSculptMode mMode = TileSculptMode::Pencil;
44 int32_t mSelectedTileIndex = 0;
45 int32_t mActiveLayer = 0;
46
47 // Index into TileSet::mNineBoxBrushes; -1 means none chosen.
48 int32_t mActiveNineBoxIndex = -1;
49
50 // Index into TileSet::mAutotileSets; -1 means none chosen.
51 int32_t mActiveAutotileIndex = -1;
52
53 // View toggles
54 bool mShowCollisionOverlay = false;
55 bool mShowTagOverlay = false;
56 bool mShowCellGrid = false;
57 std::string mTagOverlayName = "";
58};
59
60// Snapshot of a rectangular region of tiles, used by Copy/Cut/Paste/Transform.
61struct TileClipboard
62{
63 int32_t mWidth = 0;
64 int32_t mHeight = 0;
65 std::vector<TileCell> mCells; // row-major, mWidth * mHeight entries
66
67 bool IsValid() const { return mWidth > 0 && mHeight > 0 && !mCells.empty(); }
68 void Clear() { mWidth = 0; mHeight = 0; mCells.clear(); }
69};
70
71class TilePaintManager
72{
73public:
74
75 TilePaintManager();
76 ~TilePaintManager();
77
78 void Update();
79 void HandleNodeDestroy(Node* node);
80
81 TileSculptOptions mOptions;
82
83 // Hover state — read by the paint panel UI.
84 bool mHoverValid = false;
85 glm::ivec2 mHoverCell = { 0, 0 };
86
87 // Preview state for drag-based tools (RectFill, Line, NineBox, Select).
88 bool mPreviewActive = false;
89 glm::ivec2 mDragStartCell = { 0, 0 };
90
91 // Per-frame interpolation state for free-stroke pencil/eraser drags.
92 // Reset when a new stroke starts, updated each tick the user holds the
93 // mouse and moves between cells. The panel uses this to ghost-preview
94 // the cells the pencil is filling in along the way.
95 bool mStrokeActive = false;
96 bool mLastStrokeCellValid = false;
97 glm::ivec2 mLastStrokeCell = { 0, 0 };
98
99 // Active marquee / freeform selection. mSelectedCells is the source of
100 // truth — it stores every cell coordinate currently selected, packed as
101 // (uint32_t(x) | (uint64_t(uint32_t(y)) << 32)). The min/max bounding
102 // rect is recomputed from the set whenever it changes so the existing
103 // copy/cut/paste paths and the 4-corner outline still work.
104 bool mHasSelection = false;
105 glm::ivec2 mSelectionMin = { 0, 0 };
106 glm::ivec2 mSelectionMax = { 0, 0 };
107 std::set<int64_t> mSelectedCells;
108
109 static int64_t SelectionCellKey(int32_t cellX, int32_t cellY)
110 {
111 return int64_t(uint32_t(cellX)) | (int64_t(uint32_t(cellY)) << 32);
112 }
113 static void DecodeSelectionCellKey(int64_t key, int32_t& outX, int32_t& outY)
114 {
115 outX = int32_t(uint32_t(key & 0xFFFFFFFFu));
116 outY = int32_t(uint32_t((key >> 32) & 0xFFFFFFFFu));
117 }
118 bool IsCellSelected(int32_t cellX, int32_t cellY) const
119 {
120 return mSelectedCells.count(SelectionCellKey(cellX, cellY)) > 0;
121 }
122 void RecomputeSelectionBounds();
123
124 // Public API the panel calls for clipboard / transform operations.
125 void DoCopy();
126 void DoCut();
127 void DoPaste(glm::ivec2 destOrigin); // origin = bottom-left cell
128 void DoPasteAtCursor();
129 void DoFlipClipboardX();
130 void DoFlipClipboardY();
131 void DoRotateClipboard90();
132 // Apply the active 9-box brush to the current marquee selection — every
133 // cell in the selection gets the appropriate corner/edge/center tile.
134 void DoApply9BoxToSelection();
135 bool HasClipboard() const { return mClipboard.IsValid(); }
136 bool HasSelection() const { return mHasSelection; }
137 glm::ivec2 GetSelectionMin() const { return mSelectionMin; }
138 glm::ivec2 GetSelectionMax() const { return mSelectionMax; }
139 void ClearSelection() { mHasSelection = false; mSelectedCells.clear(); }
140
141private:
142
143 void UpdateHover();
144 void UpdateStroke();
145 void CommitStroke();
146 void CancelStroke();
147 void DrawCursor();
148 void DrawOverlays();
149 void DrawGridOverlay();
150 void DrawSelectionOutline();
151 void ApplyPencilOrEraser(TileMap2D* node, glm::ivec2 cell);
152 void StrokePencilOrEraserInterp(TileMap2D* node, glm::ivec2 from, glm::ivec2 to);
153 void CommitRectFill(TileMap2D* node, glm::ivec2 a, glm::ivec2 b);
154 void CommitLine(TileMap2D* node, glm::ivec2 a, glm::ivec2 b);
155 void CommitFloodFill(TileMap2D* node, glm::ivec2 origin);
156 void CommitNineBox(TileMap2D* node, glm::ivec2 a, glm::ivec2 b);
157 void CommitAutotileAt(TileMap2D* node, glm::ivec2 cell);
158 void StageCellChange(int32_t cellX, int32_t cellY, int32_t layer,
159 const TileCell& oldCell, const TileCell& newCell);
160 TileCell BuildBrushCell(const TileCell& existing) const;
161 int32_t PickNineBoxSlot(int32_t cx, int32_t cy,
162 int32_t minX, int32_t maxX,
163 int32_t minY, int32_t maxY) const;
164 // Compute the 8-neighbor "self mask" for the given cell. The pendingPaint
165 // map lets the caller pretend a set of cells are already members (used by
166 // autotile so the painted cell counts as self before the asset has it).
167 uint8_t ComputeAutotileSelfMask(TileMap2D* node, int32_t cellX, int32_t cellY,
168 int32_t layer, int32_t autotileIdx,
169 const std::set<int64_t>& pendingSelfCells) const;
170
171 static int64_t CellKey(int32_t cellX, int32_t cellY, int32_t layer);
172
173 TileMap2D* mPendingTarget = nullptr;
174 std::vector<TilePaintChange> mPendingChanges;
175 std::set<int64_t> mModifiedSet;
176
177 TileClipboard mClipboard;
178};
179
180#endif
bool Update()
Definition Engine.cpp:710
Definition Node.h:67
Definition TileMap2d.h:23
Definition Line.h:6
Definition TileMap.h:30