Polyphase Game Engine
Loading...
Searching...
No Matches
EditorState.h
Go to the documentation of this file.
1#pragma once
2
3#if EDITOR
4
5#include <array>
6#include <string>
7#include <set>
8#include <unordered_map>
9#include <vector>
10#include "Maths.h"
11#include "AssetRef.h"
12#include "SmartPointer.h"
13#include "Property.h"
14#include "Enums.h"
15#include "EditorTypes.h"
16#include "Nodes/Widgets/Text.h"
17#include "imgui.h"
18#include "./ImGuizmo/ImGuizmo.h"
19
20class Node;
21class Scene;
22class Timeline;
24class Widget;
25class Text;
26class Asset;
27struct AssetStub;
28class AssetDir;
29class ActionList;
30class Canvas;
31class Camera3D;
32class Viewport3D;
33class Viewport2D;
34class PaintManager;
35class VoxelSculptManager;
36class TilePaintManager;
37struct SubSceneOverride;
38
39enum class ControlMode
40{
41 Default,
42 Pilot,
44 Rotate,
45 Scale,
46 Pan,
47 Orbit
48};
49
50enum class TransformLock
51{
52 None,
53 AxisX,
54 AxisY,
55 AxisZ,
56 PlaneYZ,
57 PlaneXZ,
58 PlaneXY,
59 Count
60};
61
62enum class EditorMode
63{
64 Scene,
65 Scene2D,
66 Scene3D,
67
68 Count
69};
70
71enum class PaintMode
72{
73 None,
74 Color,
75 Instance,
76 Voxel,
77 Terrain,
78 TilePaint,
79
80 Count
81};
82
83enum class AssetBrowserTab
84{
85 Project = 0,
86 Addons = 1,
87 Count
88};
89
90struct LinkedSceneProps
91{
92 Node* mNode = nullptr;
93 std::vector<Property> mProps;
94 std::vector<SubSceneOverride> mSubSceneOverrides;
95};
96
97struct EditScene
98{
99 SceneRef mSceneAsset;
100 NodePtr mRootNode;
101 glm::mat4 mCameraTransform;
102 std::vector<LinkedSceneProps> mLinkedSceneProps;
103};
104
105struct RecentScene
106{
107 std::string mSceneName;
108 uint64_t mTimestamp = 0;
109};
110
111// Editor 3D viewport camera bookmark. One of 10 per-scene slots driven by the
112// `View_SaveBookmark*` / `View_GotoBookmark*` editor actions. Persisted in
113// EditorProject.sav, keyed by scene name.
114constexpr int32_t kEditorCameraBookmarkSlotCount = 10;
115
116struct EditorCameraBookmark
117{
118 bool mValid = false;
119 glm::vec3 mPosition = { 0.0f, 0.0f, 0.0f };
120 glm::quat mRotation = { 1.0f, 0.0f, 0.0f, 0.0f };
122 float mPerspectiveNearZ = 0.25f;
123 float mPerspectiveFarZ = 4096.0f;
124 float mPerspectiveFov = 70.0f;
125 float mOrthoNearZ = -2048.0f;
126 float mOrthoFarZ = 2048.0f;
127 float mOrthoWidth = 12.8f;
128 float mFocalDistance = 10.0f;
129};
130
131using EditorCameraBookmarkArray = std::array<EditorCameraBookmark, kEditorCameraBookmarkSlotCount>;
132
133// Per-asset state captured at BeginPlayInEditor and re-applied at
134// EndPlayInEditor so script mutations during play don't leak into the editor.
135struct PieAssetSnapshot
136{
137 std::vector<uint8_t> mBytes;
138 bool mWasDirty = false;
139};
140
141struct EditorState
142{
143 // Data
144 EditorMode mMode;
145 std::vector<Node*> mSelectedNodes;
146 Node* mShiftSelectAnchor = nullptr;
147 int32_t mSelectedInstance = -1;
148 std::vector<EditScene> mEditScenes;
149 AssetStub* mSelectedAssetStub = nullptr;
150 std::vector<AssetStub*> mSelectedAssetStubs;
151 ControlMode mControlMode = ControlMode::Default;
152 TransformLock mTransformLock = TransformLock::None;
153 SharedPtr<Camera3D> mEditorCamera;
154 float mPerspectiveNearZ = 0.25f;
155 float mPerspectiveFarZ = 4096.0f;
156 float mPerspectiveFov = 70.0f;
157 float mOrthoNearZ = -2048.0f;
158 float mOrthoFarZ = 2048.0f;
159 float mOrthoWidth = 12.8f;
160 bool mMouseNeedsRecenter = false;
161 bool mUiEnabled = true;
162 bool mPlayInEditor = false;
163 bool mPlayInGameWindow = false;
164 bool mEjected = false;
165 bool mPaused = false;
166 bool mHasEjectedOnce = false;
167 bool mSavedGridEnabled = false;
168
169 // One-frame latch consumed by Viewport3D's left-click selection path.
170 // Set true to make the next left-click release inside the viewport NOT
171 // change the selection. Plugin tools that handle their own clicks
172 // (Level Builder placement etc.) set this every frame they're armed
173 // via EditorUIHooks::Viewport_SuppressNextSelectionClick. Read-and-
174 // cleared in Viewport3D::HandleDefaultControls, so a stale flag never
175 // survives a real click.
176 bool mSuppressNextSelectionClick = false;
177 glm::vec4 mSavedEditorClearColor = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
178 int32_t mSavedWindowRect[4] = {}; // x, y, w, h — saved before Play Full Screen resize
179 bool mSavedWindowMaximized = false; // saved before Play Full Screen resize
180 bool mSavedFullscreenForPie = false; // true if BeginPlayInEditor put us in fullscreen
181 int32_t mEditSceneIndex = -1;
182 int32_t mPieEditSceneIdx = -1;
183 std::unordered_map<Asset*, PieAssetSnapshot> mPieAssetSnapshots;
184 // Lazy cache of instantiated default trees for sub-scene source assets,
185 // used by the inspector to detect overridden properties and revert them.
186 // Keyed by source Scene*. Invalidated when an EditScene closes, on
187 // editor shutdown, and whenever a source Scene is reimported/saved.
188 std::unordered_map<Scene*, NodePtr> mInspectorDefaultCache;
189 // Deferred dispatch for long-running editor operations: the click/hotkey
190 // handler sets the appropriate *AtEndOfFrame flag, and EditorMain.cpp
191 // picks them up *after* EditorImguiDraw has returned and runs the work
192 // synchronously. The EditorProgress modal pumps additional ImGui frames
193 // during the work so the user sees animated progress instead of a freeze.
194 bool mBeginPieAtEndOfFrame = false;
195 bool mEndPieAtEndOfFrame = false;
196 bool mSaveSceneAtEndOfFrame = false;
197 bool mSaveSelectedAssetAtEndOfFrame = false;
198 bool mResaveAllAtEndOfFrame = false;
199 bool mReloadScriptsAtEndOfFrame = false;
200 bool mOpenProjectAtEndOfFrame = false;
201 std::string mPendingOpenProjectPath;
202 // Deferred "close current project" — used by File > Close Project and as
203 // a precondition for Tier-2 recovery. Drained by EditorMain's per-frame
204 // dispatcher alongside the open/save deferreds.
205 bool mCloseProjectAtEndOfFrame = false;
206 // Deferred Tier-2 recovery: drop addon DLLs, kill mspdbsrv, wipe
207 // Intermediate/Plugins, reopen project. mPendingAddonRecoveryReason is
208 // surfaced in logs.
209 bool mAddonRecoveryAtEndOfFrame = false;
210 std::string mPendingAddonRecoveryReason;
211 // Deferred Tier-3 recovery: spawn a fresh editor with --addon-recovery
212 // and quit the current one. The new instance does the wipe + reopen.
213 bool mEditorRestartAtEndOfFrame = false;
214 std::string mPendingEditorRestartReason;
215 // Deferred OpenScene. Either a stub (preferred -- path is captured at
216 // request time so a later directory rename doesn't break it) or empty
217 // to trigger the OS file dialog inside the worker. Scene* is held as
218 // a raw pointer; the asset map owns the lifetime and the dispatcher
219 // runs same-tick so dangling is not realistic.
220 bool mOpenSceneAtEndOfFrame = false;
221 AssetStub* mPendingOpenSceneStub = nullptr;
222
223 // Generic progress modal state, consumed by DrawProgressModal and driven
224 // by the EditorProgress::* API. Negative fraction = indeterminate sine
225 // marquee; non-negative = determinate 0..1 fill.
226 bool mProgressActive = false;
227 // True only while EditorProgress is rendering one of its pumped frames.
228 // Everything drawn during that frame is running nested inside whatever
229 // long operation asked for the pump, so handlers that must not reenter
230 // that work check this. See IsInsideProgressPump() in EditorState.cpp.
231 bool mProgressPumping = false;
232 bool mProgressCancellable = false;
233 bool mProgressCancelRequested = false;
234 std::string mProgressTitle;
235 std::string mProgressStatus;
236 float mProgressFraction = -1.0f;
237 double mProgressLastPumpTime = 0.0;
238 AssetBrowserTab mActiveAssetTab = AssetBrowserTab::Project;
239 AssetDir* mTabCurrentDir[(int)AssetBrowserTab::Count] = {};
240 std::vector<AssetDir*> mTabDirPast[(int)AssetBrowserTab::Count];
241 std::vector<AssetDir*> mTabDirFuture[(int)AssetBrowserTab::Count];
242 std::string mTabFilterStr[(int)AssetBrowserTab::Count];
243 std::vector<AssetStub*> mTabFilteredStubs[(int)AssetBrowserTab::Count];
244 std::vector<Object*> mInspectPast;
245 std::vector<Object*> mInspectFuture;
246 Object* mInspectedObject;
247 Object* mPrevInspectedObject;
248 AssetRef mInspectedAsset;
249 bool mInspectLocked = false;
250 Viewport3D* mViewport3D = nullptr;
251 Viewport2D* mViewport2D = nullptr;
252 std::string mIOAssetPath;
253 bool mRequestSaveSceneAs = false;
254 bool mTrackSelectedAsset = false;
255 bool mTrackSelectedNode = false;
256 // Pending Scripts-panel reveal request. Exactly one of these is set at a
257 // time; the panel consumes and clears both on the next frame it draws.
258 std::string mRevealScriptName = "";
259 std::string mRevealScriptPath = "";
260 std::set<AssetDir*> mRevealAssetExpandDirs;
261 uint32_t mViewportX = 0;
262 uint32_t mViewportY = 0;
263 uint32_t mViewportWidth = 100;
264 uint32_t mViewportHeight = 100;
265 glm::uvec4 mPrevViewport = {};
266 bool mShowLeftPane = true;
267 bool mShowRightPane = true;
268 bool mShowInterface = true;
269 bool mPreviewLighting = true;
270 SharedPtr<Text> mOverlayText = nullptr;
271 std::vector<std::string> mFavoritedDirs;
272 std::vector<std::string> mRecentProjects;
273 std::vector<RecentScene> mRecentScenes;
274
275 // Per-scene camera bookmark slots, keyed by Scene asset name. Saved
276 // and restored from EditorProject.sav (kEditorProjectSaveVersion >= 4).
277 // Unsaved / untitled scenes use the empty-string key — those bookmarks
278 // work within the session but never persist.
279 std::unordered_map<std::string, EditorCameraBookmarkArray> mCameraBookmarks;
280 PaintMode mPaintMode = PaintMode::None;
281 PaintManager* mPaintManager = nullptr;
282 VoxelSculptManager* mVoxelSculptManager = nullptr;
283 class TerrainSculptManager* mTerrainSculptManager = nullptr;
284 TilePaintManager* mTilePaintManager = nullptr;
285
286 // ID of the currently-active addon viewport mode (Batch 15), empty when
287 // no addon mode is active. Activation is mutually exclusive with the
288 // built-in PaintMode: selecting an addon mode forces mMode=Scene3D and
289 // mPaintMode=None; selecting any built-in entry clears this string.
290 // Cross-reference: EditorUIHookManager owns the mode registrations
291 // (RegisteredViewportMode) — this struct only holds the active id and
292 // fires activate/deactivate callbacks via the manager on transition.
293 std::string mActiveAddonViewportModeId;
294
295 // Tile-paint mode stashes the editor camera's previous projection AND
296 // transform so it can switch to a top-down orthographic view of the
297 // currently-selected TileMap2D and restore the original camera on exit.
298 bool mTilePaintProjectionStashed = false;
299 bool mTilePaintPrevWasPerspective = true;
300 bool mTilePaintTransformStashed = false;
301 glm::vec3 mTilePaintPrevCameraPosition = { 0.0f, 0.0f, 0.0f };
302 glm::quat mTilePaintPrevCameraRotation = { 1.0f, 0.0f, 0.0f, 0.0f };
303 bool mNodePropertySelect = false;
304 int32_t mNodePropertySelectIndex = 0;
305 std::string mNodePropertySelectName = "";
306 std::string mPendingSceneImportPath = "";
307 std::vector<std::string> mPendingMeshImportPaths;
308 std::vector<std::string> mPendingSceneImportQueue;
309
310 // AssetDir row the mouse is over in the asset browser this frame. Reset
311 // at the top of EditorImguiDraw, set whenever a dir TreeNodeEx / Selectable
312 // reports IsItemHovered. Used by the OS file-drop modal so dropping onto
313 // a specific folder lands the files there instead of the active folder.
314 AssetDir* mMouseHoveredAssetDir = nullptr;
315
316 // Import-time name-clash queue. Filled by ActionManager::ImportAsset when
317 // the source file's basename collides with an existing asset of a different
318 // type (e.g. importing `tent.glb` as StaticMesh while `tent.oct` is already
319 // a Texture). Drained by the "Asset Name Clash" modal in EditorImgui, which
320 // lets the user rename or cancel before any pointers get rebound.
321 struct PendingImportClash
322 {
323 std::string mSourcePath; // file the user dropped / picked
324 std::string mOriginalBaseName; // basename derived from the source file (what would have been used)
325 std::string mProposedName; // user-editable; pre-filled with first free `name_N`
326 std::string mExistingTypeName;
327 std::string mImportTypeName;
328 bool mCombined = false; // true if it came in via ImportAssetCombined
329 MeshImportOptions mMeshOpts; // forwarded from the "Import Mesh Asset" modal so the re-driven import keeps Place-in-subdir / Import Materials / Shading Model / etc.
330 bool mHasMeshOpts = false; // true when mMeshOpts was populated from a mesh-import flow
331 };
332 std::vector<PendingImportClash> mPendingImportClashes;
333 AssetStub* mPendingReimportSceneStub = nullptr;
334 std::string mPendingReimportScenePath = "";
335 bool mShutdownUnsavedCheck = false;
336 bool mDevMode = false;
337 bool mShowBottomPane = true;
338 float mBottomPaneHeight = 180.0f;
339 bool mShowProjectUpgradeModal = false;
340 bool mProjectUpgradeInProgress = false;
341 std::vector<AssetStub*> mAssetsNeedingUpgrade;
342
343 // 3DS Preview Panel state
344 bool mShow3DSPreview = false;
345 int32_t mSceneScreenFilter = -1; // -1 = All Screens, 0 = Top Screen, 1 = Bottom Screen
346
347 // Game Preview Panel state
348 bool mShowGamePreview = false;
349 bool mGamePreviewCaptured = false;
350
351 // Play target (shared between viewport toolbar and Game Preview)
352 int32_t mPlayTarget = 0; // 0=PlayInEditor, 1=PlayFullScreen, 2=Dolphin, 3=Azahar, 4=Standalone, 5=Send3dsLink
353
354 // Node Graph Panel state
355 bool mShowNodeGraphPanel = false;
356
357 // Timeline Panel state
358 bool mShowTimelinePanel = false;
359
360 // Profiling Panel state
361 bool mShowProfilingPanel = false;
362
363 // Input Tester Panel state
364 bool mShowInputTesterPanel = false;
365
366 // Texture Atlas Viewer state
367 bool mShowTextureAtlasViewer = false;
368
369 // Git Panel state
370 bool mShowGitPanel = false;
371
372 // Animation Browser Panel state
373 bool mShowAnimationBrowser = false;
374 // Bone Mask Editor Panel state
375 bool mShowBoneMaskEditor = false;
376 TimelineRef mEditedTimelineRef;
377 TimelineInstance* mTimelinePreviewInstance = nullptr;
378 float mTimelinePlayheadTime = 0.0f;
379 bool mTimelinePreviewing = false;
380 float mTimelineZoom = 100.0f;
381 float mTimelineScrollX = 0.0f;
382 float mTimelineSnapInterval = 0.1f;
383 int32_t mTimelineSelectedTrack = -1;
384 int32_t mTimelineSelectedClip = -1;
385 int32_t mTimelineSelectedKeyframe = -1;
386
387 // ImGuizmo state
388 ImGuizmo::OPERATION mGizmoOperation = ImGuizmo::TRANSLATE;
389 ImGuizmo::MODE mGizmoMode = ImGuizmo::WORLD;
390 bool mGizmoBlockedBySelection = false;
391
392 // Methods
393 void Init();
394 void Shutdown();
395 void Update(float deltaTime);
396
397 void GatherProperties(std::vector<Property>& props);
398
399 void SetEditorMode(EditorMode mode);
400 EditorMode GetEditorMode();
401
402 void SetPaintMode(PaintMode paintMode);
403 PaintMode GetPaintMode();
404
405 // ===== Batch 15: Addon viewport mode helpers =====
406
421 void SetActiveAddonViewportMode(const std::string& modeId);
422
429 void ClearActiveAddonViewportMode();
430
432 bool HasActiveAddonViewportMode() const { return !mActiveAddonViewportModeId.empty(); }
433
435 const std::string& GetActiveAddonViewportModeId() const { return mActiveAddonViewportModeId; }
436
437 void ReadEditorSave();
438 void WriteEditorSave();
439
440 void ReadEditorProjectSave();
441 void WriteEditorProjectSave();
442
443 void HandleNodeDestroy(Node* node);
444
445 void SetSelectedNode(Node* newNode);
446 void AddSelectedNode(Node* node, bool addAllChildren);
447 void SelectNodesInRange(Node* rootNode, Node* endNode);
448 void RemoveSelectedNode(Node* node);
449 void SetSelectedAssetStub(AssetStub* newStub);
450 void AddSelectedAssetStub(AssetStub* stub);
451 void RemoveSelectedAssetStub(AssetStub* stub);
452 void ClearSelectedAssetStubs();
453 const std::vector<AssetStub*>& GetSelectedAssetStubs();
454 bool IsAssetStubSelected(AssetStub* stub);
455 void SetControlMode(ControlMode newMode);
456
457 void BeginPlayInEditor();
458 void EndPlayInEditor();
459 // Defer the start/stop by one frame so the loading modal can render
460 // before the (potentially slow) snapshot/clone or restore work runs.
461 void RequestBeginPlayInEditor();
462 void RequestEndPlayInEditor();
463 // Defer a Lua "Reload All Scripts" until end-of-frame so the progress
464 // modal can render before the script reload loop blocks. The worker is
465 // the global ::ReloadAllScripts() in Engine.cpp.
466 void RequestReloadAllScripts();
467 void EjectPlayInEditor();
468 void InjectPlayInEditor();
469 void SnapshotAssetsForPie();
470 void RestoreAssetsFromPie();
471
472 // Sub-scene override inspector helpers. The cache holds an instantiated
473 // copy of each source Scene asset that's currently being inspected; the
474 // inspector compares the live node's property values against the
475 // corresponding default node in the cached tree to detect overrides.
476 // Pass nullptr to InvalidateSubSceneDefaultCache to clear everything.
477 Node* GetSubSceneDefaultTree(Scene* src);
478 void InvalidateSubSceneDefaultCache(Scene* src = nullptr);
479 bool IsPropertyOverridden(Node* node, const std::string& propName);
480 void RevertPropertyToSource(Node* node, const std::string& propName);
481 void SetPlayInEditorPaused(bool paused);
482 bool IsPlayInEditorPaused();
483
484 void SetNodePropertySelect(bool enable, int32_t index, const std::string& propName);
485 void ClearNodePropertySelect();
486 void AssignNodePropertySelect(Node* targetNode);
487
488 POLYPHASE_API Camera3D* GetEditorCamera();
489 void ToggleEditorCameraProjection();
490 void ApplyEditorCameraSettings();
491
492 // Camera bookmarks. Slots are 0..kEditorCameraBookmarkSlotCount-1; the
493 // hotkey labels (1..0) correspond to slots 0..9. Save captures the editor
494 // camera's transform / projection / focal distance, Restore re-applies
495 // them, and Has reports whether a slot has been populated. Restore is
496 // intentionally NOT undoable — it changes editor view state, not scene
497 // content.
498 void SaveCameraBookmark(int32_t slot);
499 void RestoreCameraBookmark(int32_t slot);
500 bool HasCameraBookmark(int32_t slot) const;
501 const EditorCameraBookmarkArray* GetActiveSceneCameraBookmarks() const;
502 EditorCameraBookmarkArray* GetOrCreateActiveSceneCameraBookmarks();
503
504 void LoadStartupScene();
505
506 Node* GetSelectedNode();
507 Widget* GetSelectedWidget();
508 const std::vector<Node*>& GetSelectedNodes();
509 bool IsNodeSelected(Node* node);
510 void DeselectNode(Node* node);
511 int32_t GetSelectedInstance();
512 void SetSelectedInstance(int32_t instance);
513 //void ShowTextPrompt(const char* title, TextFieldHandlerFP confirmHandler, const char* defaultText = nullptr);
514
515 POLYPHASE_API void OpenEditScene(Scene* scene);
516 void OpenEditScene(int32_t idx);
517 void CloseEditScene(int32_t idx);
518 void ShelveEditScene();
519 EditScene* GetEditScene(int32_t idx = -1);
520 void CloseAllEditScenes();
521 void EnsureActiveScene();
522
523 void ShowEditorUi(bool show);
524
525 Asset* GetSelectedAsset();
526 AssetStub* GetSelectedAssetStub();
527 ControlMode GetControlMode();
528 glm::vec3 GetTransformLockVector(TransformLock lock);
529 void SetTransformLock(TransformLock lock);
530
531 Object* GetInspectedObject();
532 Node* GetInspectedNode();
533 Asset* GetInspectedAsset();
534 void InspectObject(Object* obj, bool force = false, bool recordHistory = true);
535 void LockInspect(bool lock);
536 bool IsInspectLocked();
537 void RecordInspectHistory();
538 void ClearInspectHistory();
539 void RemoveFromInspectHistory(Object* obj);
540 void ProgressInspectFuture();
541 void RegressInspectPast();
542 void ClearAssetDirHistory();
543 POLYPHASE_API void SetAssetDirectory(AssetDir* assetDir, bool recordHistory);
544 POLYPHASE_API AssetDir* GetAssetDirectory();
545 void BrowseToAsset(const std::string& name);
546 void BrowseToScript(const std::string& scriptName);
547 void BrowseToScriptPath(const std::string& fullPath);
548
549 void CaptureAndSaveScene(AssetStub* stub, Node* rootNode);
550 void DuplicateAsset(AssetStub* srcStub, const char* overrideName = nullptr);
551
552 void ProgressDirFuture();
553 void RegressDirPast();
554
555 void RemoveFilteredAssetStub(AssetStub* stub);
556 int ActiveTab() const { return (int)mActiveAssetTab; }
557
558 Viewport3D* GetViewport3D();
559 Viewport2D* GetViewport2D();
560
561 bool IsDirFavorited(const std::string& dirPath);
562 void AddFavoriteDir(const std::string& dirPath);
563 void RemoveFavoriteDir(const std::string& dirPath);
564
565 void AddRecentProject(const std::string& projPath);
566 void AddRecentScene(const std::string& sceneName);
567};
568
569POLYPHASE_API EditorState* GetEditorState();
570
571#endif
bool Update()
Definition Engine.cpp:897
void Shutdown()
Definition Engine.cpp:1147
ProjectionMode
Definition Enums.h:27
#define POLYPHASE_API
Definition PolyphaseAPI.h:31
Definition AssetDir.h:11
Definition AssetRef.h:18
Definition Asset.h:120
Definition Camera3d.h:12
Definition Canvas.h:9
Definition Node.h:67
Definition Object.h:13
Definition Scene.h:36
Definition Text.h:24
Definition TimelineInstance.h:32
Definition Timeline.h:10
Definition Viewport2d.h:33
Definition Viewport3d.h:7
Definition Widget.h:57
Definition Asset.h:89
Definition Scene.h:13