Files
HelloVulkan/App/main.cpp
T
atdunbg beba491bcb 阶段性合并:动画重定向、碎裂共享库、第三人称玩法、编辑器面板与 vendored ufbx
- 动画:HumanoidRig 三层架构(standard 标准槽 / dialects 方言映射 / mapper 配对),
  指/趾统一走世界增量两遍式烘焙;AnimationAttach 拆为纯算法 + facade;修正 HumanoidBasis
  行走基朝向与跨骨架去重、根运动通道
- 物理:CharacterController 角色互碰撞 / shapeOffset / 接触事件;PhysicsWorld 接触合成与
  字符冲量判定
- 渲染与材质:Model 多材质按材质拆子 mesh 与贴图路径解析、DDS 直传、GLB 内嵌纹理落盘、
  不透明通道 alpha 固定 1.0、glTF FlipUVs 对齐;SceneSerializer 支持 meshIndex 与材质覆盖
- 脚本:FractureLib 抽为共享库(HostView 桥接)、WallFracture 参数直绑、新增
  ThirdPersonCamera / Follower / WASDMove 玩法;移除 GameDirector / PlayerController / Target
- 编辑器:新增 GamepadPanel、LogPanel(LogRing),改进 Inspector / 材质 / 统计 / 视口面板
- 依赖:vendored ufbx(FBX 5.x/6.x/7.x 全版本解析,替代 assimp 对 FBX 6.1 的拒读)
2026-10-11 22:22:19 +08:00

213 lines
7.2 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.
//
// 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/Renderer/Renderer.h>
#include <Engine/Renderer/EditorCamera.h>
#include <Engine/Serialization/SceneSerializer.h>
#include <Engine/Core/Input.h>
#include <filesystem>
// 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。
// 游戏流:Stopped → Loading(OnUpdate 泵场景加载)→ Running
GetGameFlow().RequestStart();
#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
// Loading 泵(同步示例):场景文件存在则加载,不存在 =
// 空场景照常进 Running(引擎冒烟路径)。加载完成后必须
// CompleteLoading,否则物理/脚本门控永远跳过(卡死 Loading)
if (GetGameFlow().IsIn(GameFlowState::Loading))
{
if (std::filesystem::exists(m_ScenePath))
{
if (Serialization::SceneSerializer::Deserialize(
GetScene(), GetAssets(), m_ScenePath))
{
ENGINE_INFO("Game: scene loaded from {}", m_ScenePath);
}
else
{
ENGINE_ERROR("Game: scene load failed: {}",
m_ScenePath);
}
}
else
{
ENGINE_WARN("Game: scene file not found ({}), "
"starting empty", m_ScenePath);
}
GetGameFlow().CompleteLoading();
}
#endif
}
// ---- UI(全部委托 docking Editor;本文件零 ImGui 控件)----
void OnImGuiRender() override
{
#ifdef HELLO_EDITOR
m_Editor->Draw();
#endif
}
// ---- 事件 ----
#ifdef HELLO_EDITOR
void OnWindowClose(const Event& event) override
{
// 退出确认走 Editor 的模态框(ImGui 必须可见才有 UI)
SetImGuiEnabled(true);
m_Editor->RequestQuit();
}
#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
}
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.flow = &GetGameFlow();
ctx.editorCamera = &GetRenderer().GetEditorCamera();
// 编辑器态默认冻结:GameFlow 构造即 timeScale=0(Stopped 语义),
// timeScale 权威在 GameFlow,此处不再手设
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>();
#else
// game 形态:启动场景路径(CWD = bin;编辑器 Save 的产物位置)
const char* m_ScenePath = "assets/scenes/sandbox.scene";
#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;
}