// // Editor:docking 编辑器骨架。 // // 职责: // - 顶栏菜单(File/View)+ 全屏 DockSpace + 首帧默认布局(DockBuilder) // - 实体选中状态(entt::entity,Hierarchy 写 / Inspector 读) // - 退出确认模态框(窗口关闭 → RequestQuit → Yes 时 Close) // // 面板窗口名(Outliner/Details/Viewport/Stats/Content Browser)即 // docking 身份,imgui.ini 持久化布局;默认布局只在 dock node 为空时 // 构建一次(旧名 ini 由 Init 一次性迁移删除,见 Editor.cpp)。 // #ifndef HELLOVULKAN_EDITOR_H #define HELLOVULKAN_EDITOR_H #include "EditorContext.h" #include "panels/ViewportPanel.h" // ViewportInputState(成员按值持有) #include // u32(SelectEntity 位模式转换) #include // PIE 状态权威(IsPlaying 直查) #include #include #include class HierarchyPanel; class InspectorPanel; class ViewportPanel; class StatsPanel; class AssetBrowserPanel; class MaterialEditorPanel; class ControllerEditorPanel; class Editor { public: Editor(); ~Editor(); Editor(const Editor&) = delete; Editor& operator=(const Editor&) = delete; // 注入上下文(OnInit 阶段,指针必须全部有效) void Init(const EditorContext& ctx); // 每帧 UI 构建(OnImGuiRender 唯一入口) void Draw(); // ---- 输入归属判定(Window 层输入捕获谓词;UE/Unity 的 // "viewport 持焦才拥有输入" 语义,ImGui 侧经自身后端 // 链式回调永远正常收输入)---- // 键盘:编辑器形态 = Viewport 持焦且不在文本输入中;游戏形态 // (Fullscreen)只在文本输入中让位(打字不触发快捷键) bool BlockingKeyboard() const; // 鼠标:编辑器形态 = 悬停 Viewport 才放行;Gizmo 拖拽中一律拦截 // (抓杆时相机不能吃鼠标);游戏形态沿用 WantCaptureMouse bool BlockingMouse() const; // 请求退出(弹确认框;窗口关闭事件走这里) void RequestQuit() { m_ShowQuitConfirm = true; } // ---- PIE(Play-In-Editor,UE 主工具栏语义)---- // 状态权威 = GameFlow(EditorContext::flow);编辑器只是转换的 // 发起者(Request*)与监听器(快照/恢复挂在 →Loading/→Stopped) bool IsPlaying() const { return m_Ctx.flow && (m_Ctx.flow->IsIn(Engine::GameFlowState::Running) || m_Ctx.flow->IsIn(Engine::GameFlowState::Paused)); } bool IsPaused() const { return m_Ctx.flow && m_Ctx.flow->IsIn(Engine::GameFlowState::Paused); } // Play:RequestStart → →Loading 监听器做快照 + 切 gameView(Viewport // 内嵌 primary 相机渲染,UE PIE 语义;不切全屏)→ 同步加载完成 // CompleteLoading → Running 解冻;Stop:RequestStop → →Stopped 监听器 // 快照原子换血恢复 → 回编辑器渲染。编辑器态默认冻结(GameFlow 构造 // 即 timeScale=0),Play 解冻由 GameFlow 权威处理 void TogglePlay(); // PIE 暂停切换(UE Pause 语义):Running ↔ Paused(timeScale 由 // GameFlow 权威处理)。运行态才有意义(编辑器态本来就冻结, // Pause 按钮不出现) void TogglePause(); private: // GameFlow 监听器(Init 注册):编辑器快照/恢复挂在此处—— // GameFlow 不知场景,转换的副作用由消费端自己挂 void OnFlowEnterLoading(); // →Loading:快照 + 切 gameView + 同步完成加载 void OnFlowEnterStopped(); // →Stopped:快照换血恢复 + 回编辑器渲染 // ---- 选中状态 ---- // 同步描边:Renderer 落帧后 SelectionMask/Outline 只画选中实体。 // nullopt = 清选中——实体 0 号(场景首个创建)位模式 = 0, // 不能拿位值兼作哨兵("第一个模型无描边"的根因) void SelectEntity(entt::entity e) { m_Selected = e; if (m_Ctx.renderer) { m_Ctx.renderer->SetSelectedEntity( e == entt::null ? std::optional{} : std::optional( static_cast(entt::to_integral(e)))); } } entt::entity GetSelected() const { return m_Selected; } private: void DrawMenuBar(); // host 窗口内顶栏(File/View 菜单) void DrawToolbar(); // 菜单栏下方主工具栏(Play/Pause/Stop 居中) void DrawDockSpace(); // 全屏 host + dockspace + 默认布局 void DrawQuitModal(); // 退出确认模态框 void DrawSceneModals(); // 保存/加载路径模态框(共用一个路径输入) void DoSaveScene(); // 模态确认动作:目录创建 + 序列化落盘 void DoLoadScene(); // 模态确认动作:反序列化 + 选中清空 + 环境恢复 + 回调 EditorContext m_Ctx{}; ViewportInputState m_VpInput{}; // Viewport 面板 hover/focus(每帧刷新) GizmoState m_Gizmo{}; // 视口操纵杆状态(op/拖拽中) std::unique_ptr m_Hierarchy; std::unique_ptr m_Inspector; std::unique_ptr m_Viewport; std::unique_ptr m_Stats; std::unique_ptr m_AssetBrowser; std::unique_ptr m_MaterialEditor; std::unique_ptr m_ControllerEditor; entt::entity m_Selected{entt::null}; // 面板显隐(View 菜单) bool m_ShowHierarchy = true; bool m_ShowInspector = true; bool m_ShowViewport = true; bool m_ShowStats = true; bool m_ShowAssetBrowser = true; bool m_ShowMaterialEditor = true; // 默认布局只建一次(imgui.ini 已有布局则跳过) bool m_LayoutBuilt = false; // 退出确认链 bool m_ShowQuitConfirm = false; bool m_QuitConfirmed = false; // 场景保存/加载(File 菜单 → 路径模态框;无文件对话框库,InputText 手输) bool m_ShowSaveModal = false; bool m_ShowLoadModal = false; char m_ScenePathBuf[256] = "scenes/sandbox.scene"; // PIE 镜像态(面板只读指针消费;权威 = GameFlow,Draw 开头同步) bool m_PlayingMirror = false; bool m_PausedMirror = false; std::string m_PlaySnapshot; }; #endif //HELLOVULKAN_EDITOR_H