- 动画: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 的拒读)
153 lines
5.5 KiB
C++
153 lines
5.5 KiB
C++
//
|
||
// LogPanel.cpp:运行时日志面板实现。
|
||
//
|
||
// 数据源 = Engine::Debug::LogRing(spdlog ring sink 落的整行)。
|
||
// 级别着色(trace 灰 / debug 青 / info 浅白 / warn 黄 / error 红 /
|
||
// fatal 亮红带背景条)+ 级别过滤 + 文本过滤 + Auto-scroll(滚动条
|
||
// 贴底才自动拉,上翻看历史不被拽回)。
|
||
//
|
||
|
||
#include "LogPanel.h"
|
||
|
||
#include <Engine/Core/LogRing.h>
|
||
|
||
#include <imgui.h>
|
||
|
||
#include <cctype>
|
||
#include <cstring>
|
||
#include <string>
|
||
|
||
void LogPanel::Draw(const EditorContext& ctx)
|
||
{
|
||
(void)ctx;
|
||
if (!ImGui::Begin("Log"))
|
||
{
|
||
ImGui::End();
|
||
return;
|
||
}
|
||
|
||
// ---- 工具栏:清空 / 自动滚动 / 文本过滤 / 级别过滤 ----
|
||
if (ImGui::Button("Clear"))
|
||
{
|
||
Engine::Debug::LogRing().Clear();
|
||
}
|
||
ImGui::SameLine();
|
||
ImGui::Checkbox("Auto-scroll", &m_AutoScroll);
|
||
ImGui::SameLine();
|
||
ImGui::SetNextItemWidth(160.0f);
|
||
ImGui::InputTextWithHint("##filter", "filter...", m_Filter, sizeof(m_Filter));
|
||
ImGui::SameLine();
|
||
ImGui::Checkbox("Trace", &m_ShowTrace);
|
||
ImGui::SameLine();
|
||
ImGui::Checkbox("Info", &m_ShowInfo);
|
||
ImGui::SameLine();
|
||
ImGui::Checkbox("Warn", &m_ShowWarn);
|
||
ImGui::SameLine();
|
||
ImGui::Checkbox("Error", &m_ShowError);
|
||
ImGui::Separator();
|
||
|
||
// ---- 版本感知:有新日志且滚动条贴底 → 拉底(上翻历史不拽回)----
|
||
const Engine::u64 ver = Engine::Debug::LogRing().Version();
|
||
bool scrollToBottom = false;
|
||
if (ver != m_LastVersion)
|
||
{
|
||
m_LastVersion = ver;
|
||
if (m_AutoScroll)
|
||
{
|
||
scrollToBottom = ImGui::GetScrollY() >=
|
||
ImGui::GetScrollMaxY() - 24.0f;
|
||
}
|
||
}
|
||
|
||
if (ImGui::BeginChild("loglist", {0.0f, 0.0f}, false,
|
||
ImGuiWindowFlags_HorizontalScrollbar))
|
||
{
|
||
const auto entries = Engine::Debug::LogRing().Snapshot();
|
||
for (const auto& e : entries)
|
||
{
|
||
using lv = spdlog::level::level_enum;
|
||
bool show = false;
|
||
switch (e.level)
|
||
{
|
||
case lv::trace:
|
||
case lv::debug: show = m_ShowTrace; break;
|
||
case lv::info: show = m_ShowInfo; break;
|
||
case lv::warn: show = m_ShowWarn; break;
|
||
case lv::err:
|
||
case lv::critical: show = m_ShowError; break;
|
||
default: show = m_ShowInfo; break;
|
||
}
|
||
if (!show) continue;
|
||
if (m_Filter[0] != '\0')
|
||
{
|
||
// 简单子串过滤(大小写不敏感)
|
||
std::string lower;
|
||
lower.reserve(e.msg.size());
|
||
for (char c : e.msg)
|
||
{
|
||
lower.push_back(static_cast<char>(
|
||
std::tolower(static_cast<unsigned char>(c))));
|
||
}
|
||
std::string needle;
|
||
needle.reserve(strlen(m_Filter));
|
||
for (const char* p = m_Filter; *p; ++p)
|
||
{
|
||
needle.push_back(static_cast<char>(
|
||
std::tolower(static_cast<unsigned char>(*p))));
|
||
}
|
||
if (lower.find(needle) == std::string::npos)
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// ---- 渲染:级别徽标(恒彩色,固定列)+ 消息本体 ----
|
||
// 消息色只有 warn/error/fatal 染色(info 白是惯例),颜色
|
||
// 辨识主要靠徽标列——UE Output Log 的 Verbosity 列同位
|
||
ImVec4 tagCol, msgCol;
|
||
const char* tag = "INFO";
|
||
bool bg = false;
|
||
switch (e.level)
|
||
{
|
||
case lv::trace:
|
||
tag = "TRACE"; tagCol = {0.55f, 0.55f, 0.55f, 1.0f};
|
||
msgCol = {0.55f, 0.55f, 0.55f, 1.0f}; break;
|
||
case lv::debug:
|
||
tag = "DEBUG"; tagCol = {0.40f, 0.80f, 0.90f, 1.0f};
|
||
msgCol = {0.70f, 0.70f, 0.70f, 1.0f}; break;
|
||
case lv::info:
|
||
tag = "INFO"; tagCol = {0.45f, 0.72f, 0.95f, 1.0f};
|
||
msgCol = {0.90f, 0.90f, 0.90f, 1.0f}; break;
|
||
case lv::warn:
|
||
tag = "WARN"; tagCol = {1.00f, 0.78f, 0.20f, 1.0f};
|
||
msgCol = {1.00f, 0.78f, 0.20f, 1.0f}; break;
|
||
case lv::err:
|
||
tag = "ERROR"; tagCol = {1.00f, 0.35f, 0.35f, 1.0f};
|
||
msgCol = {1.00f, 0.35f, 0.35f, 1.0f}; break;
|
||
default:
|
||
tag = "FATAL"; tagCol = {1.00f, 0.15f, 0.15f, 1.0f};
|
||
msgCol = {1.00f, 0.15f, 0.15f, 1.0f};
|
||
bg = true; break;
|
||
}
|
||
if (bg)
|
||
{
|
||
// fatal:整行暗红背景条提级(先画背景再画文本)
|
||
const ImVec2 p0 = ImGui::GetCursorScreenPos();
|
||
const ImVec2 p1(p0.x + ImGui::GetContentRegionAvail().x,
|
||
p0.y + ImGui::GetTextLineHeight());
|
||
ImGui::GetWindowDrawList()->AddRectFilled(
|
||
p0, p1, IM_COL32(90, 10, 10, 160));
|
||
}
|
||
ImGui::TextColored(tagCol, "%s", tag);
|
||
ImGui::SameLine(40.0f); // 徽标固定列宽,消息对齐成两列
|
||
ImGui::TextColored(msgCol, "%s", e.msg.c_str());
|
||
}
|
||
if (scrollToBottom)
|
||
{
|
||
ImGui::SetScrollHereY(1.0f);
|
||
}
|
||
}
|
||
ImGui::EndChild();
|
||
ImGui::End();
|
||
}
|