- .animctrl state machine asset (params/transitions/blend trees, 1D+2D directional blending) with Unity Animator-style editor panel: state list, transitions, params, directional pad preview driving live CrossFade on the selected entity - Split animation evaluation out of SceneRenderer into AnimationSystem/AnimationEvaluator; skin palettes with rest-pose fallback and blend-weight epsilon filtering - MaterialAsset (.material) with reload-safe preview tile pool (DropMaterial clears dirty refs before instance destruction) - EditorGizmoPass skeleton wires + viewport joint overlay; camera projection rework (baked Vulkan Y-flip, ortho support) - Editor/game build split via HELLOVULKAN_EDITOR option
187 lines
5.9 KiB
C++
187 lines
5.9 KiB
C++
//
|
||
// 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 <Engine/Core/Application.h>
|
||
#include <Engine/Core/Time.h>
|
||
#include <Engine/Core/Window.h> // SetInputCapture(Application.h 只前置声明)
|
||
#include <Engine/Core/Log.h>
|
||
#include <Engine/Core/Stats.h>
|
||
#include <Engine/Renderer/Renderer.h>
|
||
#include <Engine/Renderer/EditorCamera.h>
|
||
|
||
#include <Engine/Core/Input.h>
|
||
|
||
// editor/game 编译期分离(HELLOVULKAN_EDITOR CMake option):editor 形态
|
||
// 挂接 docking Editor;game 形态 = Direct 直渲 + primary 相机,零编辑器代码
|
||
#ifdef HELLO_EDITOR
|
||
#include "Editor.h"
|
||
#include "EditorContext.h"
|
||
#endif
|
||
|
||
using namespace Engine;
|
||
|
||
namespace
|
||
{
|
||
class SandboxApp final : public Application
|
||
{
|
||
public:
|
||
SandboxApp()
|
||
: Application("HelloVulkan", 1920, 1080)
|
||
{
|
||
}
|
||
|
||
~SandboxApp() override
|
||
{
|
||
}
|
||
|
||
protected:
|
||
// ---- 生命周期 ----
|
||
|
||
void OnInit() override
|
||
{
|
||
Renderer& renderer = GetRenderer();
|
||
#ifdef HELLO_EDITOR
|
||
renderer.SetDisplayMode(kDisplayViewport);
|
||
|
||
|
||
// ImGui 叠加层(框架只做管线桥接;UI 内容 = docking Editor)
|
||
EnableImGui();
|
||
|
||
// Editor 注入:引擎门面 + 沙盒能力回调(环境异步切换等)
|
||
InitEditor();
|
||
#else
|
||
// game 形态:全窗口 Direct 直渲(Renderer 默认即 kDisplayDirect),
|
||
// 相机由场景 primary camera 提供,无 UI
|
||
#endif
|
||
}
|
||
|
||
void OnUpdate(const FrameTime& frameTime) override
|
||
{
|
||
#ifdef HELLO_EDITOR
|
||
// 编辑器形态:驱动编辑器相机(RMB 飞行 / MMB 焦点环绕 /
|
||
// 滚轮推拉)。暂停(timeScale=0)时仍可飞行——unscaled dt。
|
||
// PIE 内嵌播放:渲染源已切 primary 相机,编辑器相机停驱
|
||
//(否则与游戏脚本抢 WASD,Stop 后视角也被偷跑)。
|
||
// 游戏形态:相机实体由游戏逻辑驱动(本沙盒无逻辑 = 静止)
|
||
if (GetRenderer().GetDisplayMode() == kDisplayViewport &&
|
||
!m_Editor->IsPlaying())
|
||
{
|
||
GetRenderer().GetEditorCamera().Update(frameTime.UnscaledDt());
|
||
}
|
||
#else
|
||
(void)frameTime; // game 形态:本沙盒无游戏逻辑
|
||
#endif
|
||
}
|
||
|
||
// ---- UI(全部委托 docking Editor;本文件零 ImGui 控件)----
|
||
|
||
void OnImGuiRender() override
|
||
{
|
||
#ifdef HELLO_EDITOR
|
||
m_Editor->Draw();
|
||
#endif
|
||
}
|
||
|
||
// ---- 事件 ----
|
||
|
||
void OnWindowClose(const Event& event) override
|
||
{
|
||
#ifdef HELLO_EDITOR
|
||
// 退出确认走 Editor 的模态框(ImGui 必须可见才有 UI)
|
||
SetImGuiEnabled(true);
|
||
m_Editor->RequestQuit();
|
||
#else
|
||
(void)event;
|
||
#endif
|
||
}
|
||
|
||
void OnKeyPress(const Event& event) override
|
||
{
|
||
// 键码统一走 Input::Key(App 层零 GLFW 依赖)
|
||
#ifdef HELLO_EDITOR
|
||
if (event.key == static_cast<int>(Input::Key::GraveAccent))
|
||
{
|
||
SetImGuiEnabled(!GetImGuiEnabled());
|
||
}
|
||
#endif
|
||
if (event.key == static_cast<int>(Input::Key::F1))
|
||
{
|
||
STATS.PrintComparison();
|
||
}
|
||
}
|
||
|
||
|
||
void OnWindowResize(const Event& event) override
|
||
{
|
||
ENGINE_INFO("App: window resized to {}x{}", event.width, event.height);
|
||
}
|
||
|
||
private:
|
||
#ifdef HELLO_EDITOR
|
||
// Editor 注入:门面指针 + 反向能力回调(面板 → 沙盒)
|
||
void InitEditor()
|
||
{
|
||
EditorContext ctx;
|
||
ctx.renderer = &GetRenderer();
|
||
ctx.scene = &GetScene();
|
||
ctx.assets = &GetAssets();
|
||
ctx.app = this;
|
||
ctx.editorCamera = &GetRenderer().GetEditorCamera();
|
||
// 继承原沙盒默认:初始暂停(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<Editor> m_Editor = std::make_unique<Editor>();
|
||
#endif
|
||
};
|
||
}
|
||
|
||
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;
|
||
}
|