docs: Update RHI test refactoring status

- Mark P0-1 (Shader) and P0-2 (PipelineState) as completed
- Update test coverage matrix
- Add changelog v1.1
This commit is contained in:
2026-03-25 12:30:05 +08:00
parent f808f8d197
commit 0948e0fdbe
13 changed files with 273 additions and 49 deletions

View File

@@ -1,5 +1,8 @@
#include "Application.h"
#include "Layers/EditorLayer.h"
#include <XCEngine/Debug/Logger.h>
#include <XCEngine/Debug/FileLogSink.h>
#include <XCEngine/Debug/ConsoleLogSink.h>
#include <imgui_impl_win32.h>
#include <imgui_impl_dx12.h>
#include <imgui_internal.h>
@@ -16,6 +19,28 @@ Application& Application::Get() {
}
bool Application::Initialize(HWND hwnd) {
// Initialize logging first
Debug::Logger::Get().AddSink(std::make_unique<Debug::ConsoleLogSink>());
// Get exe directory for log file path
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(nullptr, exePath, MAX_PATH);
std::wstring exeDirW(exePath);
size_t pos = exeDirW.find_last_of(L"\\/");
if (pos != std::wstring::npos) {
exeDirW = exeDirW.substr(0, pos);
}
std::string exeDir;
int len = WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, nullptr, 0, nullptr, nullptr);
if (len > 0) {
exeDir.resize(len - 1);
WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, &exeDir[0], len, nullptr, nullptr);
}
std::string logPath = exeDir + "\\editor.log";
Debug::Logger::Get().AddSink(std::make_unique<Debug::FileLogSink>(logPath.c_str()));
Debug::Logger::Get().Info(Debug::LogCategory::General, "Editor Application starting...");
Debug::Logger::Get().Info(Debug::LogCategory::General, ("Log file: " + logPath).c_str());
m_hwnd = hwnd;
if (!CreateDevice()) {
@@ -46,20 +71,6 @@ bool Application::Initialize(HWND hwnd) {
m_srvHeap->GetCPUDescriptorHandleForHeapStart(),
m_srvHeap->GetGPUDescriptorHandleForHeapStart());
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(nullptr, exePath, MAX_PATH);
std::wstring exeDirW(exePath);
size_t pos = exeDirW.find_last_of(L"\\/");
if (pos != std::wstring::npos) {
exeDirW = exeDirW.substr(0, pos);
}
std::string exeDir;
int len = WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, nullptr, 0, nullptr, nullptr);
if (len > 0) {
exeDir.resize(len - 1);
WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, &exeDir[0], len, nullptr, nullptr);
}
m_editorLayer = new EditorLayer();
m_editorLayer->SetProjectPath(exeDir);
m_layerStack.pushLayer(std::unique_ptr<Core::Layer>(m_editorLayer));

View File

@@ -39,6 +39,17 @@ void EditorLayer::onUpdate(float dt) {
}
void EditorLayer::onEvent(void* event) {
ImGuiIO& io = ImGui::GetIO();
if (ImGui::IsKeyPressed(ImGuiKey_F5)) {
TogglePlay();
}
if (ImGui::IsKeyPressed(ImGuiKey_F6)) {
if (GetEditorMode() != EditorMode::Edit) {
TogglePause();
}
}
}
void EditorLayer::onImGuiRender() {

View File

@@ -21,6 +21,103 @@ void ConsolePanel::Render() {
LogSystem::Get().Clear();
}
ImGui::SameLine();
ImGui::SeparatorText("Filter");
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
ImGui::PushStyleColor(ImGuiCol_Button, m_showInfo ? ImVec4(0.2f, 0.6f, 0.2f, 1.0f) : ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
if (ImGui::Button("Info")) {
m_showInfo = !m_showInfo;
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, m_showWarning ? ImVec4(0.8f, 0.6f, 0.0f, 1.0f) : ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
if (ImGui::Button("Warn")) {
m_showWarning = !m_showWarning;
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, m_showError ? ImVec4(0.8f, 0.2f, 0.2f, 1.0f) : ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
if (ImGui::Button("Error")) {
m_showError = !m_showError;
}
ImGui::PopStyleColor();
ImGui::PopStyleVar();
ImGui::Separator();
ImGui::BeginChild("LogScroll", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
size_t logIndex = 0;
for (const auto& log : LogSystem::Get().GetLogs()) {
bool shouldShow = false;
switch (log.level) {
case ::XCEngine::Debug::LogLevel::Info:
shouldShow = m_showInfo;
break;
case ::XCEngine::Debug::LogLevel::Warning:
shouldShow = m_showWarning;
break;
case ::XCEngine::Debug::LogLevel::Error:
shouldShow = m_showError;
break;
}
if (!shouldShow) {
continue;
}
ImVec4 color;
const char* prefix;
switch (log.level) {
case ::XCEngine::Debug::LogLevel::Info:
color = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
prefix = "[INFO] ";
break;
case ::XCEngine::Debug::LogLevel::Warning:
color = ImVec4(1.0f, 0.8f, 0.0f, 1.0f);
prefix = "[WARN] ";
break;
case ::XCEngine::Debug::LogLevel::Error:
color = ImVec4(1.0f, 0.3f, 0.3f, 1.0f);
prefix = "[ERROR]";
break;
}
ImGui::PushID(static_cast<int>(logIndex));
std::string timestampStr = "[" + log.timestamp + "] ";
ImGui::TextColored(ImVec4(0.4f, 0.4f, 0.4f, 1.0f), "%s", timestampStr.c_str());
ImGui::SameLine();
std::string fullMessage = std::string(prefix) + log.message;
ImGui::TextColored(color, "%s", fullMessage.c_str());
if (ImGui::IsItemClicked()) {
ImGui::SetClipboardText(fullMessage.c_str());
}
ImGui::PopID();
logIndex++;
}
if (m_scrollToBottom && !LogSystem::Get().GetLogs().empty()) {
ImGui::SetScrollHereY(1.0f);
m_scrollToBottom = false;
}
ImGui::EndChild();
ImGui::End();
}
ImGui::SameLine();
if (ImGui::Button("Info")) {
LogSystem::Get().AddLog(::XCEngine::Debug::LogLevel::Info, "Test info message");
}

View File

@@ -11,6 +11,9 @@ public:
void Render() override;
private:
bool m_showInfo = true;
bool m_showWarning = true;
bool m_showError = true;
bool m_scrollToBottom = false;
};

View File

@@ -33,7 +33,10 @@ void HierarchyPanel::Render() {
ImGui::BeginChild("EntityList");
for (auto* gameObject : EditorSceneManager::Get().GetRootEntities()) {
auto rootEntities = EditorSceneManager::Get().GetRootEntities();
SortEntities(const_cast<std::vector<::XCEngine::Components::GameObject*>&>(rootEntities));
for (auto* gameObject : rootEntities) {
RenderEntity(gameObject, filter);
}
@@ -65,6 +68,13 @@ void HierarchyPanel::Render() {
}
void HierarchyPanel::RenderSearchBar() {
ImGui::SetNextItemWidth(120);
const char* sortLabels[] = { "Name", "Components", "Transform First" };
int currentSort = static_cast<int>(m_sortMode);
if (ImGui::Combo("##Sort", &currentSort, sortLabels, 3)) {
m_sortMode = static_cast<SortMode>(currentSort);
}
ImGui::SameLine();
ImGui::SetNextItemWidth(-1);
ImGui::InputTextWithHint("##Search", "Search...", m_searchBuffer, sizeof(m_searchBuffer));
}
@@ -346,5 +356,30 @@ bool HierarchyPanel::PassesFilter(::XCEngine::Components::GameObject* gameObject
return false;
}
void HierarchyPanel::SortEntities(std::vector<::XCEngine::Components::GameObject*>& entities) {
switch (m_sortMode) {
case SortMode::Name:
std::sort(entities.begin(), entities.end(), [](::XCEngine::Components::GameObject* a, ::XCEngine::Components::GameObject* b) {
return a->GetName() < b->GetName();
});
break;
case SortMode::ComponentCount:
std::sort(entities.begin(), entities.end(), [](::XCEngine::Components::GameObject* a, ::XCEngine::Components::GameObject* b) {
return a->GetComponents<::XCEngine::Components::Component>().size() > b->GetComponents<::XCEngine::Components::Component>().size();
});
break;
case SortMode::TransformFirst:
std::sort(entities.begin(), entities.end(), [](::XCEngine::Components::GameObject* a, ::XCEngine::Components::GameObject* b) {
bool aHasTransform = a->GetComponent<::XCEngine::Components::TransformComponent>() != nullptr;
bool bHasTransform = b->GetComponent<::XCEngine::Components::TransformComponent>() != nullptr;
if (aHasTransform != bHasTransform) {
return aHasTransform;
}
return a->GetName() < b->GetName();
});
break;
}
}
}
}

View File

@@ -6,6 +6,8 @@
namespace XCEngine {
namespace Editor {
enum class SortMode { Name, ComponentCount, TransformFirst };
class HierarchyPanel : public Panel {
public:
HierarchyPanel();
@@ -21,6 +23,7 @@ private:
void HandleDragDrop(::XCEngine::Components::GameObject* gameObject);
void HandleKeyboardShortcuts();
bool PassesFilter(::XCEngine::Components::GameObject* gameObject, const std::string& filter);
void SortEntities(std::vector<::XCEngine::Components::GameObject*>& entities);
uint64_t m_selectionHandlerId = 0;
@@ -29,6 +32,7 @@ private:
::XCEngine::Components::GameObject* m_renamingEntity = nullptr;
char m_renameBuffer[256] = "";
bool m_renameJustStarted = false;
SortMode m_sortMode = SortMode::Name;
};
}

View File

@@ -2,6 +2,7 @@
#include "Managers/SceneManager.h"
#include "Managers/SelectionManager.h"
#include "UI/UI.h"
#include <XCEngine/Debug/Logger.h>
#include <imgui.h>
#include <string>
@@ -9,6 +10,7 @@ namespace XCEngine {
namespace Editor {
InspectorPanel::InspectorPanel() : Panel("Inspector") {
Debug::Logger::Get().Debug(Debug::LogCategory::General, "InspectorPanel constructed");
m_selectionHandlerId = SelectionManager::Get().OnSelectionChanged.Subscribe([this](uint64_t) {
m_selectedGameObject = SelectionManager::Get().GetSelectedEntity();
});
@@ -19,6 +21,7 @@ InspectorPanel::~InspectorPanel() {
}
void InspectorPanel::Render() {
Debug::Logger::Get().Debug(Debug::LogCategory::General, "InspectorPanel::Render START");
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
m_selectedGameObject = SelectionManager::Get().GetSelectedEntity();
@@ -31,9 +34,11 @@ void InspectorPanel::Render() {
}
ImGui::End();
Debug::Logger::Get().Debug(Debug::LogCategory::General, "InspectorPanel::Render END");
}
void InspectorPanel::RenderGameObject(::XCEngine::Components::GameObject* gameObject) {
Debug::Logger::Get().Debug(Debug::LogCategory::General, "RenderGameObject START");
char nameBuffer[256];
strcpy_s(nameBuffer, gameObject->GetName().c_str());
ImGui::InputText("##Name", nameBuffer, sizeof(nameBuffer));
@@ -43,6 +48,7 @@ void InspectorPanel::RenderGameObject(::XCEngine::Components::GameObject* gameOb
ImGui::SameLine();
if (ImGui::Button("Add Component")) {
Debug::Logger::Get().Debug(Debug::LogCategory::General, "Add Component BUTTON CLICKED");
ImGui::OpenPopup("AddComponent");
}
@@ -52,27 +58,47 @@ void InspectorPanel::RenderGameObject(::XCEngine::Components::GameObject* gameOb
for (auto* component : components) {
RenderComponent(component, gameObject);
}
Debug::Logger::Get().Debug(Debug::LogCategory::General, "RenderGameObject END");
}
void InspectorPanel::RenderAddComponentPopup(::XCEngine::Components::GameObject* gameObject) {
if (!ImGui::BeginPopup("AddComponent")) {
Debug::Logger::Get().Debug(Debug::LogCategory::General, "RenderAddComponentPopup called");
if (!gameObject) {
Debug::Logger::Get().Error(Debug::LogCategory::General, "ERROR: gameObject is nullptr!");
return;
}
if (!ImGui::BeginPopup("AddComponent")) {
Debug::Logger::Get().Debug(Debug::LogCategory::General, "BeginPopup returned false");
return;
}
Debug::Logger::Get().Debug(Debug::LogCategory::General, "BeginPopup succeeded");
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12.0f, 10.0f));
ImGui::SeparatorText("Components");
if (ImGui::MenuItem("Transform", nullptr, false, !gameObject->GetComponent<::XCEngine::Components::TransformComponent>())) {
gameObject->AddComponent<::XCEngine::Components::TransformComponent>();
bool hasTransform = gameObject->GetComponent<::XCEngine::Components::TransformComponent>() != nullptr;
Debug::Logger::Get().Debug(Debug::LogCategory::General, hasTransform ? "Has Transform: yes" : "Has Transform: no");
Debug::Logger::Get().Debug(Debug::LogCategory::General, "About to check MenuItem condition");
if (ImGui::MenuItem("Transform", nullptr, false, !hasTransform)) {
Debug::Logger::Get().Debug(Debug::LogCategory::General, "MenuItem CLICKED! Before AddComponent");
auto* newComp = gameObject->AddComponent<::XCEngine::Components::TransformComponent>();
Debug::Logger::Get().Debug(Debug::LogCategory::General, newComp ? "AddComponent SUCCEEDED" : "AddComponent FAILED");
ImGui::CloseCurrentPopup();
} else {
Debug::Logger::Get().Debug(Debug::LogCategory::General, "MenuItem not clicked (disabled or condition false)");
}
ImGui::SeparatorText("Other");
ImGui::TextDisabled("No more components available");
ImGui::PopStyleVar();
Debug::Logger::Get().Debug(Debug::LogCategory::General, "About to EndPopup");
ImGui::EndPopup();
ImGui::PopStyleVar();
Debug::Logger::Get().Debug(Debug::LogCategory::General, "Popup closed");
}
void InspectorPanel::RenderComponent(::XCEngine::Components::Component* component, ::XCEngine::Components::GameObject* gameObject) {