Files
HelloVulkan/App/editor/Editor.h
T
atdunbg 1a278d5945 PIE: viewport-embedded playback with UE-style main toolbar
Play no longer switches to fullscreen direct rendering: PIE now keeps
the editor UI alive and renders the primary camera into the Viewport
panel (new SceneRenderer::SetGameView flag; kDisplayDirect stays a
manual fullscreen preview for later release form). Editor camera stops
being driven during PIE, and viewport click-pick is gated off while
playing (clicks are game input now).

The Play/Stop buttons move out of the menu bar into a dedicated main
toolbar row below it (centered, UE Main Toolbar semantics): green Play
when idle; Pause (yellow, highlighted while paused) + Stop (orange)
while playing. Ctrl+P hotkey kept. Stats "Pause Simulation" merged
into the toolbar Pause; viewport overlay shows PAUSED accordingly.
2026-10-05 11:14:24 +08:00

140 lines
5.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// 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 "ViewportPanel.h" // ViewportInputState(成员按值持有)
#include <Engine/Core/Types.h> // u32(SelectEntity 位模式转换)
#include <entt/entt.hpp>
#include <memory>
#include <optional>
class HierarchyPanel;
class InspectorPanel;
class ViewportPanel;
class StatsPanel;
class AssetBrowserPanel;
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 主工具栏语义)----
bool IsPlaying() const { return m_Playing; }
bool IsPaused() const { return m_Paused; }
// Play:内存快照当前场景 → 切 gameView(Viewport 内嵌 primary 相机
// 渲染,UE PIE 语义;不切全屏)→ 解冻时间;
// Stop:快照原子换血恢复 → 回编辑器渲染 → 冻结时间。
// 编辑器态默认 timeScale=0(物理冻结 = UE 语义),Play 解冻
void TogglePlay();
// PIE 暂停切换(UE Pause 语义):timeScale 0 ↔ 1
void TogglePause();
private:
void DoPlay(); // TogglePlay 的 Play 半程(快照 + 切渲染 + 解冻)
void DoStop(); // TogglePlay 的 Stop 半程(恢复 + 回编辑器 + 冻结)
// ---- 选中状态 ----
// 同步描边: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<Engine::u32>{}
: std::optional<Engine::u32>(
static_cast<Engine::u32>(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<HierarchyPanel> m_Hierarchy;
std::unique_ptr<InspectorPanel> m_Inspector;
std::unique_ptr<ViewportPanel> m_Viewport;
std::unique_ptr<StatsPanel> m_Stats;
std::unique_ptr<AssetBrowserPanel> m_AssetBrowser;
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;
// 默认布局只建一次(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 状态:Play 时场景 YAML 内存快照,Stop 时原子换血恢复
bool m_Playing = false;
bool m_Paused = false; // PIE 暂停(timeScale=0;Stop 时复位)
std::string m_PlaySnapshot;
};
#endif //HELLOVULKAN_EDITOR_H