entt entity 0's integral bits are 0, colliding with the "no selection"
sentinel: u32 selected == 0 meant "clear selection", so the scene's
first-created entity could never be outlined. Replaced with
std::optional<u32> + FrameSceneData::selectedEntityValid.
Also restore per-batch instance contiguity broken by the batchMats
flattening (e038cb3): entities sharing a mesh scatter across the flat
instance array in collection order. ViewScratch now tracks per-batch
singly-linked lists and appendView aggregates each batch into a
contiguous range, preserving the flat-array performance intent.
Hierarchy click selection now routes through SelectEntity so outline
stays in sync when picking from the panel.
133 lines
4.9 KiB
C++
133 lines
4.9 KiB
C++
//
|
||
// Editor:docking 编辑器骨架。
|
||
//
|
||
// 职责:
|
||
// - 顶栏菜单(File/View)+ 全屏 DockSpace + 首帧默认布局(DockBuilder)
|
||
// - 实体选中状态(entt::entity,Hierarchy 写 / Inspector 读)
|
||
// - 退出确认模态框(窗口关闭 → RequestQuit → Yes 时 Close)
|
||
//
|
||
// 面板窗口名(Hierarchy/Inspector/Viewport/Stats)即 docking 身份,
|
||
// imgui.ini 持久化布局;默认布局只在 dock node 为空时构建一次。
|
||
//
|
||
|
||
#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; }
|
||
// Play:内存快照当前场景 → 切游戏渲染(primary 相机)→ 解冻时间;
|
||
// Stop:快照原子换血恢复 → 回编辑器渲染 → 冻结时间。
|
||
// 编辑器态默认 timeScale=0(物理冻结 = UE 语义),Play 解冻
|
||
void TogglePlay();
|
||
|
||
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 窗口内顶栏
|
||
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;
|
||
std::string m_PlaySnapshot;
|
||
};
|
||
|
||
#endif //HELLOVULKAN_EDITOR_H
|