// // Created by atdunbg on 2026/9/20. // // SandboxApp:基于 Application 框架的编辑器宿主程序。 // // main 的职责边界: // - 定义 Application 派生类并运行它 // - 编辑器形态驱动 EditorCamera(Scene view 专用相机,非场景对象) // - 异步环境加载、全局热键、输入归属门控 // - UI 全部委托 App/editor/ 的 docking Editor(本文件不再出现 // 任何 ImGui 控件) // // 场景内容(实体/组件)由编辑器 File 菜单 Save/Load 场景文件管理, // 相机实体属于场景数据、只在游戏形态参与渲染(UE 语义)。 // // 窗口、渲染器、事件泵、帧计时、场景容器全部由框架管理。 // #include #include #include // SetInputCapture(Application.h 只前置声明) #include #include #include #include #include #include "Editor.h" #include "EditorContext.h" // kEnvPaths / kDefaultEnv(与 StatsPanel 共用) using namespace Engine; namespace { class SandboxApp final : public Application { public: SandboxApp() : Application("HelloVulkan", 1920, 1080) { } ~SandboxApp() override { } protected: // ---- 生命周期 ---- void OnInit() override { Renderer& renderer = GetRenderer(); renderer.SetDisplayMode(kDisplayViewport); // ImGui 叠加层(框架只做管线桥接;UI 内容 = docking Editor) EnableImGui(); // Editor 注入:引擎门面 + 沙盒能力回调(环境异步切换等) InitEditor(); } void OnUpdate(const FrameTime& frameTime) override { // 编辑器形态:驱动编辑器相机(RMB 飞行 / MMB 焦点环绕 / // 滚轮推拉)。暂停(timeScale=0)时仍可飞行——unscaled dt。 // 游戏形态:相机实体由游戏逻辑驱动(本沙盒无逻辑 = 静止) if (GetRenderer().GetDisplayMode() == kDisplayViewport) { GetRenderer().GetEditorCamera().Update(GetWindow(), frameTime.UnscaledDt()); } } // ---- UI(全部委托 docking Editor;本文件零 ImGui 控件)---- void OnImGuiRender() override { m_Editor->Draw(); } // ---- 事件 ---- void OnWindowClose(const Event& event) override { // 退出确认走 Editor 的模态框(ImGui 必须可见才有 UI) SetImGuiEnabled(true); m_Editor->RequestQuit(); } void OnKeyPress(const Event& event) override { if (event.key == GLFW_KEY_GRAVE_ACCENT) { SetImGuiEnabled(!GetImGuiEnabled()); } if (event.key == GLFW_KEY_F1) { STATS.PrintComparison(); } } void OnWindowResize(const Event& event) override { ENGINE_INFO("App: window resized to {}x{}", event.width, event.height); } private: // Editor 注入:门面指针 + 反向能力回调(面板 → 沙盒) void InitEditor() { EditorContext ctx; ctx.renderer = &GetRenderer(); ctx.scene = &GetScene(); ctx.assets = &GetAssets(); ctx.app = this; ctx.editorCamera = &GetRenderer().GetEditorCamera(); ctx.getEnvIndex = [this] { return m_EnvIndex; }; ctx.setEnvIndex = [this](int index) { m_EnvIndex = index; }; // 继承原沙盒默认:初始暂停(StatsPanel 的 Pause Simulation 开关恢复) Time::SetTimeScale(0.0f); m_Editor->Init(ctx); // 输入归属:覆盖 EnableImGui 的全局 WantCapture* 谓词 //(全屏 dock host 让它恒真,输入全死)。改为 Editor 按帧 // 判定——Viewport hover/focus 拥有输入(Hazel/UE 语义); // UI 隐藏(反引号)时 Draw 不再执行,直接全放行 GetWindow().SetInputCapture( [this] { return GetImGuiEnabled() && m_Editor->BlockingKeyboard(); }, [this] { return GetImGuiEnabled() && m_Editor->BlockingMouse(); }); } private: std::unique_ptr m_Editor = std::make_unique(); int m_EnvIndex = kDefaultEnv; }; } int main() { Logger::Initialize(); { SandboxApp app; try { app.Run(); } catch (const std::exception& e) { ENGINE_FATAL("Exception: {}", e.what()); Logger::Shutdown(); return -1; } } // app 析构:成员(Device/Renderer/Window…)全部销毁完毕 Logger::Shutdown(); return 0; }