feat: move editor to project / add post processing etc

This commit is contained in:
2026-10-23 20:54:12 +02:00
parent f7e7c56392
commit a3d3da4a67
104 changed files with 11750 additions and 2675 deletions
+32
View File
@@ -0,0 +1,32 @@
#ifndef EDITOR_ASSETBROWSER_H
#define EDITOR_ASSETBROWSER_H
#include <filesystem>
#include <optional>
#include <string>
#include <vector>
class AssetBrowser final {
public:
std::optional<std::string> Draw(bool* open = nullptr);
private:
struct Entry {
std::string name;
bool directory{false};
};
void Refresh();
void Navigate(const std::string& scheme, const std::filesystem::path& folder);
[[nodiscard]] std::string VirtualPath(const std::string& name) const;
void DrawEntry(const Entry& entry, std::optional<std::string>& opened, bool& navigated);
void DrawFolderMenu();
std::string m_Scheme;
std::filesystem::path m_Folder;
std::vector<Entry> m_Entries;
std::string m_Filter;
bool m_Dirty{true};
};
#endif // EDITOR_ASSETBROWSER_H
+141
View File
@@ -0,0 +1,141 @@
#ifndef EDITOR_EDITOR_H
#define EDITOR_EDITOR_H
#include <filesystem>
#include <optional>
#include <string>
#include <string_view>
#include <glm/vec2.hpp>
#include <destrum/AppLayer.h>
#include <editor/AssetBrowser.h>
#include <editor/EditorCamera.h>
#include <editor/PlayMode.h>
#include <editor/RectGizmo.h>
#include <editor/ResourcesInspector.h>
#include <editor/SceneInspector.h>
#include <editor/ShaderHotReload.h>
#include <editor/TransformGizmo.h>
#include <editor/UndoStack.h>
class App;
class Scene;
struct EditorSettings {
std::filesystem::path gameAssetsSource;
std::string scenePath;
bool startInEditMode{true};
};
class Editor final : public AppLayer {
public:
Editor(App& app, EditorSettings settings);
void onAttach() override;
void onBeginFrame() override;
void onImGuiBegin(float dt) override;
void onImGui(float dt) override;
void onEndFrame() override;
void onRender(GameRenderer& renderer) override;
[[nodiscard]] Camera* viewCamera() override;
[[nodiscard]] bool hostsViewport() const override { return true; }
[[nodiscard]] InputFocus gameInputFocus() const override;
bool OpenScene(std::string_view path);
bool SaveScene();
bool SaveSceneAs(std::string_view path);
void NewScene();
[[nodiscard]] UndoStack& GetUndoStack() { return m_UndoStack; }
[[nodiscard]] PlayMode& GetPlayMode() { return m_PlayMode; }
private:
struct Panels {
bool inspector{true};
bool assets{true};
bool stats{true};
bool physics{false};
bool imageCache{false};
};
struct ViewOptions {
bool colliders{false};
bool gizmos{true};
};
struct Viewport {
glm::vec2 min{0.0f};
glm::vec2 size{1.0f};
glm::ivec2 desiredSize{0};
bool hovered{false};
bool focused{false};
bool mouseClaimed{false};
bool pickSelectsParent{false};
std::optional<glm::ivec2> hoverPixel;
};
// Editor.cpp
[[nodiscard]] Scene* CurrentScene() const;
[[nodiscard]] bool UsesEditorCamera();
void HandleShortcuts();
void Undo();
void Redo();
void RecordEdits();
void AfterSceneReplaced(bool resetHistory);
void DeleteSelection();
void DuplicateSelection();
void FocusSelection();
void SetStatus(std::string status);
bool WriteScene(Scene& scene, std::string_view path);
// EditorViewport.cpp
void ApplyViewportResize();
void DrawViewport();
void DrawGizmos(Scene& scene);
void RequestPick();
void ApplyPick();
void OnAssetDropped(std::string_view path);
void SubmitColliderLines(Scene& scene) const;
// EditorMenus.cpp
void DrawDockSpace();
void DrawMainMenuBar();
void DrawFileMenu();
void DrawEditMenu();
void DrawViewMenu();
void DrawDisplayMenu();
void DrawPlayControls();
void DrawSceneDialogs();
void DrawStatsPanel();
void DrawPhysicsPanel();
App& m_App;
EditorSettings m_Settings;
EditorCamera m_Camera;
PlayMode m_PlayMode;
UndoStack m_UndoStack;
SceneInspector m_Inspector;
AssetBrowser m_AssetBrowser;
ResourcesInspector m_ResourcesInspector;
TransformGizmo m_TransformGizmo;
RectGizmo m_RectGizmo;
ShaderHotReload m_ShaderHotReload;
Panels m_Panels;
ViewOptions m_View;
Viewport m_Viewport;
std::string m_ScenePath;
std::string m_Status;
std::string m_SaveAsPath;
bool m_OpenSceneDialog{false};
bool m_SaveAsDialog{false};
bool m_ItemWasActive{false};
bool m_EditPending{false};
};
#endif // EDITOR_EDITOR_H
+36
View File
@@ -0,0 +1,36 @@
#ifndef EDITOR_EDITORCAMERA_H
#define EDITOR_EDITORCAMERA_H
#include <optional>
#include <glm/vec3.hpp>
#include <destrum/Graphics/Camera.h>
class GameObject;
class RenderResources;
struct WorldBounds {
glm::vec3 center{0.0f};
float radius{1.0f};
};
[[nodiscard]] WorldBounds ComputeWorldBounds(GameObject& object, const RenderResources& resources);
class EditorCamera final {
public:
EditorCamera();
void Update(float dt, bool hasInput);
void Focus(const WorldBounds& bounds);
[[nodiscard]] Camera& GetCamera() { return m_Camera; }
[[nodiscard]] bool IsLooking() const { return m_Looking; }
private:
Camera m_Camera;
std::optional<glm::vec3> m_FocusTarget;
bool m_Looking{false};
};
#endif // EDITOR_EDITORCAMERA_H
+39
View File
@@ -0,0 +1,39 @@
#ifndef EDITOR_PLAYMODE_H
#define EDITOR_PLAYMODE_H
#include <memory>
#include <optional>
#include <nlohmann/json.hpp>
class App;
class Scene;
class PlayMode final {
public:
explicit PlayMode(App& app);
void EnterEditMode();
void RequestToggle() { m_ToggleRequested = true; }
void SetPaused(bool paused);
[[nodiscard]] bool ApplyPendingToggle();
[[nodiscard]] bool IsPlaying() const { return m_Playing; }
[[nodiscard]] bool IsPaused() const { return m_Paused; }
[[nodiscard]] bool IsEditing() const { return !m_Playing; }
private:
bool Enter();
void Exit();
App& m_App;
bool m_Playing{true};
bool m_Paused{false};
bool m_ToggleRequested{false};
bool m_MouseCapturedBeforePause{false};
std::optional<nlohmann::json> m_EditSnapshot;
std::weak_ptr<Scene> m_EditScene;
};
#endif // EDITOR_PLAYMODE_H
+28
View File
@@ -0,0 +1,28 @@
#ifndef EDITOR_RECTGIZMO_H
#define EDITOR_RECTGIZMO_H
#include <glm/glm.hpp>
class GameObject;
class RectGizmo final {
public:
[[nodiscard]] static bool CanManipulate(GameObject& object);
bool Manipulate(GameObject& object, const glm::vec2& drawImageSize, const glm::vec2& viewMin, const glm::vec2& viewSize);
[[nodiscard]] bool IsUsing() const { return m_ActiveHandle >= 0; }
[[nodiscard]] bool IsInteracting() const { return m_ActiveHandle >= 0 || m_Hovered; }
bool snap{false};
float snapStep{5.0f};
private:
int m_ActiveHandle{-1};
bool m_Hovered{false};
glm::vec2 m_DragStartMouse{0.0f};
glm::vec2 m_DragStartPosition{0.0f};
glm::vec2 m_DragStartSize{0.0f};
};
#endif // EDITOR_RECTGIZMO_H
@@ -0,0 +1,35 @@
#ifndef EDITOR_RESOURCESINSPECTOR_H
#define EDITOR_RESOURCESINSPECTOR_H
#include <destrum/Graphics/ids.h>
struct GPUImage;
class ImguiPass;
class RenderResources;
// ImGui windows for looking into the render resource caches
class ResourcesInspector final
{
public:
void drawImageCacheWindow(bool* open, const RenderResources& resources, ImguiPass& imguiPass);
private:
struct PreviewInfo
{
bool previewable{false};
const char* reason{""};
};
[[nodiscard]] static PreviewInfo getPreviewInfo(const GPUImage& image);
void drawImagePreview(const GPUImage& image, float maxSize, ImguiPass& imguiPass) const;
void drawImageDetails(ImageID id, const RenderResources& resources) const;
[[nodiscard]] bool matchesFilter(ImageID id, const RenderResources& resources) const;
char filter[128]{};
float thumbnailSize{48.0f};
bool onlyPreviewable{false};
ImageID selectedImageId{NULL_IMAGE_ID};
};
#endif //EDITOR_RESOURCESINSPECTOR_H
+60
View File
@@ -0,0 +1,60 @@
#ifndef EDITOR_SCENEINSPECTOR_H
#define EDITOR_SCENEINSPECTOR_H
#include <functional>
#include <string>
#include <unordered_set>
#include <nlohmann/json.hpp>
#include <destrum/ObjectModel/ObjectId.h>
class Component;
class GameObject;
class Scene;
class SceneInspector final {
public:
void Draw(Scene& scene, ObjectId& selectedObjectId, const std::function<void()>& drawSceneSettings, bool* open);
private:
struct PendingMove {
ObjectId object{InvalidObjectId};
ObjectId parent{InvalidObjectId};
ObjectId anchor{InvalidObjectId};
bool after{false};
};
void DrawHierarchy(Scene& scene, ObjectId& selectedObjectId);
void DrawNode(Scene& scene, GameObject& object, ObjectId& selectedObjectId, std::unordered_set<const GameObject*>& visited);
void DrawRenameField(GameObject& object);
void DrawNodeDragDrop(GameObject& object);
void DrawObjectMenu(Scene& scene, GameObject* object, ObjectId& selectedObjectId);
void HandleShortcuts(Scene& scene, ObjectId& selectedObjectId);
void ApplyPendingActions(Scene& scene, ObjectId& selectedObjectId);
void DrawObject(GameObject& object);
void DrawTransform(GameObject& object);
void DrawComponents(GameObject& object);
void DrawComponentMenu(GameObject& object, Component& component, std::size_t index, bool removable);
void DrawAddComponent(GameObject& object);
void BeginRename(const GameObject& object);
std::string m_Filter;
std::string m_ComponentFilter;
ObjectId m_RenamingId{InvalidObjectId};
std::string m_RenameBuffer;
bool m_FocusRename{false};
ObjectId m_OpenNextFrame{InvalidObjectId};
PendingMove m_PendingMove;
ObjectId m_PendingDelete{InvalidObjectId};
ObjectId m_PendingDuplicate{InvalidObjectId};
std::string m_ClipboardType;
nlohmann::json m_Clipboard;
};
#endif // EDITOR_SCENEINSPECTOR_H
+33
View File
@@ -0,0 +1,33 @@
#ifndef EDITOR_SHADERHOTRELOAD_H
#define EDITOR_SHADERHOTRELOAD_H
#include <filesystem>
#include <future>
#include <string>
#include <unordered_map>
class ShaderHotReload final {
public:
void Configure(std::filesystem::path cooker, std::filesystem::path sourceRoot, std::filesystem::path runtimeRoot);
[[nodiscard]] bool IsConfigured() const { return !m_Cooker.empty(); }
void RequestCook() { m_CookRequested = true; }
[[nodiscard]] bool Poll(float dt);
[[nodiscard]] bool IsCooking() const { return m_Cook.valid(); }
[[nodiscard]] const std::string& GetLastResult() const { return m_LastResult; }
private:
[[nodiscard]] bool SourcesChanged();
void StartCook();
std::filesystem::path m_Cooker;
std::filesystem::path m_SourceRoot;
std::filesystem::path m_RuntimeRoot;
std::unordered_map<std::string, std::filesystem::file_time_type> m_Stamps;
std::future<int> m_Cook;
std::string m_LastResult;
float m_PollTimer{0.0f};
bool m_CookRequested{false};
};
#endif // EDITOR_SHADERHOTRELOAD_H
+37
View File
@@ -0,0 +1,37 @@
#ifndef EDITOR_TRANSFORMGIZMO_H
#define EDITOR_TRANSFORMGIZMO_H
#include <glm/glm.hpp>
class Camera;
class GameObject;
enum class GizmoOperation {
Translate,
Rotate,
Scale,
};
enum class GizmoSpace {
World,
Local,
};
class TransformGizmo final {
public:
void HandleShortcuts();
void DrawToolbar();
bool Manipulate(GameObject& object, const Camera& camera, const glm::vec2& viewMin, const glm::vec2& viewSize);
[[nodiscard]] bool IsUsing() const;
[[nodiscard]] bool IsOver() const;
GizmoOperation operation{GizmoOperation::Translate};
GizmoSpace space{GizmoSpace::World};
bool snap{false};
float translationSnap{0.5f};
float rotationSnapDegrees{15.0f};
float scaleSnap{0.1f};
};
#endif // EDITOR_TRANSFORMGIZMO_H
+42
View File
@@ -0,0 +1,42 @@
#ifndef EDITOR_UNDOSTACK_H
#define EDITOR_UNDOSTACK_H
#include <cstddef>
#include <deque>
#include <optional>
#include <string>
#include <vector>
#include <destrum/ObjectModel/ObjectId.h>
class Scene;
class UndoStack final {
public:
static constexpr std::size_t MaxSteps = 64;
void Reset(Scene& scene);
void Rebase(Scene& scene);
bool Record(Scene& scene);
bool Undo(Scene& scene);
bool Redo(Scene& scene);
[[nodiscard]] bool CanUndo() const { return !m_Undo.empty(); }
[[nodiscard]] bool CanRedo() const { return !m_Redo.empty(); }
[[nodiscard]] std::size_t UndoCount() const { return m_Undo.size(); }
private:
struct Snapshot {
std::string scene;
ObjectId selected{InvalidObjectId};
};
[[nodiscard]] static std::optional<Snapshot> Capture(Scene& scene);
bool Restore(Scene& scene, const Snapshot& snapshot);
std::deque<Snapshot> m_Undo;
std::vector<Snapshot> m_Redo;
std::optional<Snapshot> m_Current;
};
#endif // EDITOR_UNDOSTACK_H