Add semantic pixel asserts for lighting scenes
This commit is contained in:
@@ -42,6 +42,10 @@ Old `editor` replacement is explicitly out of scope for this phase.
|
||||
- ImGui factory entry points now live only in `LegacyImGuiHostInterop.h`
|
||||
- `XCUIEditorFontSetup.h` no longer exposes `ImFont` / `ImFontAtlas`; the public API is now a current-context font bootstrap helper
|
||||
- `XCUIStandaloneTextAtlasProvider.h` no longer depends on the ImGui-oriented font bootstrap header
|
||||
- The generic shell command/state boundary is now narrower as well:
|
||||
- `XCUIShellChromeState` no longer carries the legacy host demo-window toggle or command id on the generic shell-state surface
|
||||
- `Application.h` no longer exposes that legacy demo command through generic `ShellCommandIds`, `ShellCommandBindings`, or `RegisterShellViewCommands(...)`
|
||||
- the legacy demo window toggle now lives as a compatibility-only command inside `ApplicationLegacyImGui.cpp`
|
||||
- Old `editor` replacement remains deferred; all active execution still stays inside XCUI shared code and `new_editor`.
|
||||
|
||||
## Three-Layer Status
|
||||
@@ -120,7 +124,7 @@ Current gap:
|
||||
- `XCUIDemoRuntime` now bridges pointer activation, text-edit commands, and shortcut-triggered commands through a unified command path, and `DrainPendingCommandIds()` now preserves mixed pointer/text/shortcut ordering.
|
||||
- `new_editor` now also has a pure `XCUIShellChromeState` model covering panel visibility, hosted-preview mode, and shell-level view toggles without depending on ImGui, `Application`, or the old editor.
|
||||
- `XCUIShellChromeState` hosted-preview mode naming is now backend-neutral (`HostedPresenter` / `NativeOffscreen`) instead of encoding `ImGui` into the XCUI shell model.
|
||||
- The shell chrome view-toggle model no longer encodes the legacy Dear ImGui demo window as a generic `ImGuiDemoWindow` concept; that compatibility-only toggle is now named `LegacyHostDemoWindow` / `new_editor.view.legacy_host_demo` at the editor-layer seam.
|
||||
- The shell chrome view-toggle model no longer carries the legacy host demo window at all on the generic XCUI seam; that command now lives only inside the compatibility-only legacy host implementation.
|
||||
- `new_editor` now also has a concrete `NativeWindowUICompositor` path and native-focused compositor tests, so the window compositor seam is no longer ImGui-only.
|
||||
- `Application` now also has a native XCUI shell path that:
|
||||
- becomes the default `new_editor` startup path
|
||||
|
||||
@@ -607,7 +607,9 @@ if(MSVC)
|
||||
target_compile_options(XCEngine PRIVATE
|
||||
/FS
|
||||
$<$<CONFIG:Debug,RelWithDebInfo>:/Z7>)
|
||||
target_link_libraries(XCEngine PUBLIC delayimp)
|
||||
target_link_libraries(XCEngine PUBLIC
|
||||
delayimp
|
||||
d3dcompiler)
|
||||
target_link_options(XCEngine INTERFACE "/DELAYLOAD:assimp-vc143-mt.dll")
|
||||
set_target_properties(XCEngine PROPERTIES
|
||||
MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>"
|
||||
|
||||
@@ -60,8 +60,6 @@ public:
|
||||
::XCEngine::Editor::XCUIBackend::XCUIShellChromeCommandIds::ToggleXCUIDemoPanel;
|
||||
static constexpr const char* ToggleXCUILayoutLabPanel =
|
||||
::XCEngine::Editor::XCUIBackend::XCUIShellChromeCommandIds::ToggleXCUILayoutLabPanel;
|
||||
static constexpr const char* ToggleLegacyHostDemoWindow =
|
||||
::XCEngine::Editor::XCUIBackend::XCUIShellChromeCommandIds::ToggleLegacyHostDemoWindow;
|
||||
static constexpr const char* ToggleNativeBackdrop =
|
||||
::XCEngine::Editor::XCUIBackend::XCUIShellChromeCommandIds::ToggleNativeBackdrop;
|
||||
static constexpr const char* TogglePulseAccent =
|
||||
@@ -81,8 +79,6 @@ public:
|
||||
std::function<void(bool)> setXCUIDemoPanelVisible = {};
|
||||
std::function<bool()> getXCUILayoutLabPanelVisible = {};
|
||||
std::function<void(bool)> setXCUILayoutLabPanelVisible = {};
|
||||
std::function<bool()> getLegacyHostDemoWindowVisible = {};
|
||||
std::function<void(bool)> setLegacyHostDemoWindowVisible = {};
|
||||
std::function<bool()> getNativeBackdropVisible = {};
|
||||
std::function<void(bool)> setNativeBackdropVisible = {};
|
||||
std::function<bool()> getPulseAccentEnabled = {};
|
||||
@@ -213,15 +209,6 @@ public:
|
||||
ctrlOnly,
|
||||
true,
|
||||
false } });
|
||||
bindToggleCommand(
|
||||
ShellCommandIds::ToggleLegacyHostDemoWindow,
|
||||
bindings.getLegacyHostDemoWindowVisible,
|
||||
bindings.setLegacyHostDemoWindowVisible,
|
||||
{ XCUIEditorCommandAccelerator{
|
||||
static_cast<std::int32_t>(KeyCode::Three),
|
||||
ctrlOnly,
|
||||
true,
|
||||
false } });
|
||||
bindToggleCommand(
|
||||
ShellCommandIds::ToggleNativeBackdrop,
|
||||
bindings.getNativeBackdropVisible,
|
||||
@@ -469,6 +456,7 @@ private:
|
||||
::XCEngine::Editor::XCUIBackend::NativeXCUIPanelCanvasHost m_nativeDemoCanvasHost;
|
||||
::XCEngine::Editor::XCUIBackend::NativeXCUIPanelCanvasHost m_nativeLayoutCanvasHost;
|
||||
ShellPanelId m_nativeActivePanel = ShellPanelId::XCUIDemo;
|
||||
bool m_legacyHostDemoWindowVisible = false;
|
||||
bool m_nativeDemoReloadSucceeded = false;
|
||||
bool m_nativeLayoutReloadSucceeded = false;
|
||||
::XCEngine::Editor::XCUIBackend::XCUILayoutLabRuntime m_nativeOverlayRuntime;
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace NewEditor {
|
||||
namespace {
|
||||
|
||||
constexpr float kLegacyHostClearColor[4] = { 0.08f, 0.09f, 0.11f, 1.0f };
|
||||
constexpr const char* kLegacyHostDemoWindowCommandId = "new_editor.view.legacy_host_demo";
|
||||
|
||||
std::uint64_t MakeLegacyHostFrameTimestampNanoseconds() {
|
||||
return static_cast<std::uint64_t>(
|
||||
@@ -65,6 +66,37 @@ const char* GetHostedPreviewStateLabel(
|
||||
return "idle";
|
||||
}
|
||||
|
||||
void RegisterLegacyHostDemoWindowCommand(
|
||||
::XCEngine::Editor::XCUIBackend::XCUIEditorCommandRouter& router,
|
||||
const std::function<bool()>& getter,
|
||||
const std::function<void(bool)>& setter) {
|
||||
if (!getter || !setter) {
|
||||
return;
|
||||
}
|
||||
|
||||
using ::XCEngine::Editor::XCUIBackend::XCUIEditorCommandAccelerator;
|
||||
using ::XCEngine::Editor::XCUIBackend::XCUIEditorCommandDefinition;
|
||||
using ::XCEngine::Input::KeyCode;
|
||||
|
||||
XCUIEditorCommandDefinition definition = {};
|
||||
definition.commandId = kLegacyHostDemoWindowCommandId;
|
||||
definition.isEnabled = [getter, setter]() {
|
||||
return static_cast<bool>(getter) && static_cast<bool>(setter);
|
||||
};
|
||||
definition.invoke = [getter, setter]() {
|
||||
setter(!getter());
|
||||
};
|
||||
definition.accelerators = {
|
||||
XCUIEditorCommandAccelerator{
|
||||
static_cast<std::int32_t>(KeyCode::Three),
|
||||
{ false, true, false, false },
|
||||
true,
|
||||
false,
|
||||
},
|
||||
};
|
||||
router.RegisterCommand(definition);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Application::Application() = default;
|
||||
@@ -155,12 +187,6 @@ void Application::ConfigureShellCommandRouter() {
|
||||
m_layoutLabPanel->SetVisible(visible);
|
||||
}
|
||||
};
|
||||
bindings.getLegacyHostDemoWindowVisible = [this]() {
|
||||
return IsShellViewToggleEnabled(ShellViewToggleId::LegacyHostDemoWindow);
|
||||
};
|
||||
bindings.setLegacyHostDemoWindowVisible = [this](bool visible) {
|
||||
SetShellViewToggleEnabled(ShellViewToggleId::LegacyHostDemoWindow, visible);
|
||||
};
|
||||
bindings.getNativeBackdropVisible = [this]() {
|
||||
return IsShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop);
|
||||
};
|
||||
@@ -204,6 +230,10 @@ void Application::ConfigureShellCommandRouter() {
|
||||
bindings.onHostedPreviewModeChanged = [this]() { ConfigureHostedPreviewPresenters(); };
|
||||
|
||||
Application::RegisterShellViewCommands(m_shellCommandRouter, bindings);
|
||||
RegisterLegacyHostDemoWindowCommand(
|
||||
m_shellCommandRouter,
|
||||
[this]() { return m_legacyHostDemoWindowVisible; },
|
||||
[this](bool visible) { m_legacyHostDemoWindowVisible = visible; });
|
||||
}
|
||||
|
||||
::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta
|
||||
@@ -308,9 +338,9 @@ void Application::RenderLegacyImGuiUiFrame() {
|
||||
m_layoutLabPanel->RenderIfVisible();
|
||||
}
|
||||
|
||||
bool showLegacyHostDemoWindow = IsShellViewToggleEnabled(ShellViewToggleId::LegacyHostDemoWindow);
|
||||
bool showLegacyHostDemoWindow = m_legacyHostDemoWindowVisible;
|
||||
if (::XCEngine::Editor::XCUIBackend::RenderLegacyImGuiDemoWindow(showLegacyHostDemoWindow)) {
|
||||
SetShellViewToggleEnabled(ShellViewToggleId::LegacyHostDemoWindow, showLegacyHostDemoWindow);
|
||||
m_legacyHostDemoWindowVisible = showLegacyHostDemoWindow;
|
||||
}
|
||||
|
||||
SyncShellChromePanelStateFromPanels();
|
||||
@@ -371,8 +401,8 @@ void Application::RenderShellChrome() {
|
||||
drawCommandMenuItem(
|
||||
"Legacy Host Demo",
|
||||
"Ctrl+3",
|
||||
IsShellViewToggleEnabled(ShellViewToggleId::LegacyHostDemoWindow),
|
||||
ShellCommandIds::ToggleLegacyHostDemoWindow);
|
||||
m_legacyHostDemoWindowVisible,
|
||||
kLegacyHostDemoWindowCommandId);
|
||||
ImGui::Separator();
|
||||
drawCommandMenuItem(
|
||||
"Native Backdrop",
|
||||
|
||||
@@ -13,7 +13,6 @@ constexpr std::size_t ToIndex(XCUIShellPanelId panelId) {
|
||||
constexpr std::string_view kViewMenuLabel = "View";
|
||||
constexpr std::string_view kXCUIDemoShortcut = "Ctrl+1";
|
||||
constexpr std::string_view kXCUILayoutLabShortcut = "Ctrl+2";
|
||||
constexpr std::string_view kLegacyHostDemoShortcut = "Ctrl+3";
|
||||
constexpr std::string_view kNativeBackdropShortcut = "Ctrl+Shift+B";
|
||||
constexpr std::string_view kPulseAccentShortcut = "Ctrl+Shift+P";
|
||||
constexpr std::string_view kNativeXCUIOverlayShortcut = "Ctrl+Shift+O";
|
||||
@@ -164,8 +163,6 @@ bool XCUIShellChromeState::ToggleHostedPreviewMode(XCUIShellPanelId panelId) {
|
||||
|
||||
bool XCUIShellChromeState::GetViewToggle(XCUIShellViewToggleId toggleId) const {
|
||||
switch (toggleId) {
|
||||
case XCUIShellViewToggleId::LegacyHostDemoWindow:
|
||||
return m_viewToggles.legacyHostDemoWindowVisible;
|
||||
case XCUIShellViewToggleId::NativeBackdrop:
|
||||
return m_viewToggles.nativeBackdropVisible;
|
||||
case XCUIShellViewToggleId::PulseAccent:
|
||||
@@ -183,9 +180,6 @@ bool XCUIShellChromeState::GetViewToggle(XCUIShellViewToggleId toggleId) const {
|
||||
bool XCUIShellChromeState::SetViewToggle(XCUIShellViewToggleId toggleId, bool enabled) {
|
||||
bool* target = nullptr;
|
||||
switch (toggleId) {
|
||||
case XCUIShellViewToggleId::LegacyHostDemoWindow:
|
||||
target = &m_viewToggles.legacyHostDemoWindowVisible;
|
||||
break;
|
||||
case XCUIShellViewToggleId::NativeBackdrop:
|
||||
target = &m_viewToggles.nativeBackdropVisible;
|
||||
break;
|
||||
@@ -227,9 +221,6 @@ bool XCUIShellChromeState::InvokeCommand(std::string_view commandId) {
|
||||
if (commandId == XCUIShellChromeCommandIds::ToggleXCUILayoutLabPanel) {
|
||||
return TogglePanelVisible(XCUIShellPanelId::XCUILayoutLab);
|
||||
}
|
||||
if (commandId == XCUIShellChromeCommandIds::ToggleLegacyHostDemoWindow) {
|
||||
return ToggleViewToggle(XCUIShellViewToggleId::LegacyHostDemoWindow);
|
||||
}
|
||||
if (commandId == XCUIShellChromeCommandIds::ToggleNativeBackdrop) {
|
||||
return ToggleViewToggle(XCUIShellViewToggleId::NativeBackdrop);
|
||||
}
|
||||
@@ -288,15 +279,6 @@ bool XCUIShellChromeState::TryGetCommandDescriptor(
|
||||
return true;
|
||||
}
|
||||
|
||||
if (commandId == GetViewToggleCommandId(XCUIShellViewToggleId::LegacyHostDemoWindow)) {
|
||||
outDescriptor.label = "Legacy Host Demo";
|
||||
outDescriptor.shortcut = kLegacyHostDemoShortcut;
|
||||
outDescriptor.commandId = commandId;
|
||||
outDescriptor.checkable = true;
|
||||
outDescriptor.checked = GetViewToggle(XCUIShellViewToggleId::LegacyHostDemoWindow);
|
||||
outDescriptor.enabled = true;
|
||||
return true;
|
||||
}
|
||||
if (commandId == GetViewToggleCommandId(XCUIShellViewToggleId::NativeBackdrop)) {
|
||||
outDescriptor.label = "Native Backdrop";
|
||||
outDescriptor.shortcut = kNativeBackdropShortcut;
|
||||
@@ -358,7 +340,7 @@ bool XCUIShellChromeState::TryGetCommandDescriptor(
|
||||
XCUIShellMenuDescriptor XCUIShellChromeState::BuildViewMenuDescriptor() const {
|
||||
XCUIShellMenuDescriptor descriptor = {};
|
||||
descriptor.label = kViewMenuLabel;
|
||||
descriptor.items.reserve(10u);
|
||||
descriptor.items.reserve(9u);
|
||||
|
||||
const auto appendCommandItem = [this, &descriptor](std::string_view commandId) {
|
||||
XCUIShellCommandDescriptor commandDescriptor = {};
|
||||
@@ -374,7 +356,6 @@ XCUIShellMenuDescriptor XCUIShellChromeState::BuildViewMenuDescriptor() const {
|
||||
|
||||
appendCommandItem(GetPanelVisibilityCommandId(XCUIShellPanelId::XCUIDemo));
|
||||
appendCommandItem(GetPanelVisibilityCommandId(XCUIShellPanelId::XCUILayoutLab));
|
||||
appendCommandItem(GetViewToggleCommandId(XCUIShellViewToggleId::LegacyHostDemoWindow));
|
||||
|
||||
descriptor.items.push_back({ XCUIShellMenuItemKind::Separator, {} });
|
||||
|
||||
@@ -414,8 +395,6 @@ std::string_view XCUIShellChromeState::GetPanelPreviewModeCommandId(XCUIShellPan
|
||||
|
||||
std::string_view XCUIShellChromeState::GetViewToggleCommandId(XCUIShellViewToggleId toggleId) {
|
||||
switch (toggleId) {
|
||||
case XCUIShellViewToggleId::LegacyHostDemoWindow:
|
||||
return XCUIShellChromeCommandIds::ToggleLegacyHostDemoWindow;
|
||||
case XCUIShellViewToggleId::NativeBackdrop:
|
||||
return XCUIShellChromeCommandIds::ToggleNativeBackdrop;
|
||||
case XCUIShellViewToggleId::PulseAccent:
|
||||
|
||||
@@ -16,8 +16,7 @@ enum class XCUIShellPanelId : std::uint8_t {
|
||||
};
|
||||
|
||||
enum class XCUIShellViewToggleId : std::uint8_t {
|
||||
LegacyHostDemoWindow = 0,
|
||||
NativeBackdrop,
|
||||
NativeBackdrop = 0,
|
||||
PulseAccent,
|
||||
NativeXCUIOverlay,
|
||||
HostedPreviewHud,
|
||||
@@ -46,7 +45,6 @@ struct XCUIShellPanelChromeState {
|
||||
};
|
||||
|
||||
struct XCUIShellViewToggleState {
|
||||
bool legacyHostDemoWindowVisible = false;
|
||||
bool nativeBackdropVisible = true;
|
||||
bool pulseAccentEnabled = true;
|
||||
bool nativeXCUIOverlayVisible = true;
|
||||
@@ -56,7 +54,6 @@ struct XCUIShellViewToggleState {
|
||||
struct XCUIShellChromeCommandIds {
|
||||
static constexpr const char* ToggleXCUIDemoPanel = "new_editor.view.xcui_demo";
|
||||
static constexpr const char* ToggleXCUILayoutLabPanel = "new_editor.view.xcui_layout_lab";
|
||||
static constexpr const char* ToggleLegacyHostDemoWindow = "new_editor.view.legacy_host_demo";
|
||||
static constexpr const char* ToggleNativeBackdrop = "new_editor.view.native_backdrop";
|
||||
static constexpr const char* TogglePulseAccent = "new_editor.view.pulse_accent";
|
||||
static constexpr const char* ToggleNativeXCUIOverlay = "new_editor.view.native_xcui_overlay";
|
||||
|
||||
@@ -71,12 +71,6 @@ struct ShellCommandHarness {
|
||||
bindings.setXCUILayoutLabPanelVisible = [this](bool visible) {
|
||||
panels[ToPanelIndex(Application::ShellPanelId::XCUILayoutLab)].visible = visible;
|
||||
};
|
||||
bindings.getLegacyHostDemoWindowVisible = [this]() {
|
||||
return viewToggles.legacyHostDemoWindowVisible;
|
||||
};
|
||||
bindings.setLegacyHostDemoWindowVisible = [this](bool visible) {
|
||||
viewToggles.legacyHostDemoWindowVisible = visible;
|
||||
};
|
||||
bindings.getNativeBackdropVisible = [this]() {
|
||||
return viewToggles.nativeBackdropVisible;
|
||||
};
|
||||
@@ -134,7 +128,6 @@ TEST(ApplicationShellCommandBindingsTest, RegisterShellViewCommandsInvokesBoundT
|
||||
|
||||
EXPECT_TRUE(router.HasCommand(Application::ShellCommandIds::ToggleXCUIDemoPanel));
|
||||
EXPECT_TRUE(router.HasCommand(Application::ShellCommandIds::ToggleXCUILayoutLabPanel));
|
||||
EXPECT_TRUE(router.HasCommand(Application::ShellCommandIds::ToggleLegacyHostDemoWindow));
|
||||
EXPECT_TRUE(router.HasCommand(Application::ShellCommandIds::ToggleNativeBackdrop));
|
||||
EXPECT_TRUE(router.HasCommand(Application::ShellCommandIds::TogglePulseAccent));
|
||||
EXPECT_TRUE(router.HasCommand(Application::ShellCommandIds::ToggleNativeXCUIOverlay));
|
||||
@@ -144,8 +137,6 @@ TEST(ApplicationShellCommandBindingsTest, RegisterShellViewCommandsInvokesBoundT
|
||||
|
||||
EXPECT_TRUE(router.InvokeCommand(Application::ShellCommandIds::ToggleXCUIDemoPanel));
|
||||
EXPECT_FALSE(harness.Panel(Application::ShellPanelId::XCUIDemo).visible);
|
||||
EXPECT_TRUE(router.InvokeCommand(Application::ShellCommandIds::ToggleLegacyHostDemoWindow));
|
||||
EXPECT_TRUE(harness.viewToggles.legacyHostDemoWindowVisible);
|
||||
EXPECT_TRUE(router.InvokeCommand(Application::ShellCommandIds::ToggleNativeBackdrop));
|
||||
EXPECT_FALSE(harness.viewToggles.nativeBackdropVisible);
|
||||
EXPECT_TRUE(router.InvokeCommand(Application::ShellCommandIds::ToggleNativeXCUIOverlay));
|
||||
|
||||
@@ -17,7 +17,6 @@ TEST(XCUIShellChromeStateTest, DefaultsMatchCurrentShellChromeConfiguration) {
|
||||
XCUIShellChromeState state = {};
|
||||
|
||||
const auto& viewToggles = state.GetViewToggles();
|
||||
EXPECT_FALSE(viewToggles.legacyHostDemoWindowVisible);
|
||||
EXPECT_TRUE(viewToggles.nativeBackdropVisible);
|
||||
EXPECT_TRUE(viewToggles.pulseAccentEnabled);
|
||||
EXPECT_TRUE(viewToggles.nativeXCUIOverlayVisible);
|
||||
@@ -118,10 +117,6 @@ TEST(XCUIShellChromeStateTest, HostedPreviewStateSeparatesEnablementFromRequeste
|
||||
TEST(XCUIShellChromeStateTest, ViewToggleMutatorsOnlyFlipRequestedFlags) {
|
||||
XCUIShellChromeState state = {};
|
||||
|
||||
EXPECT_TRUE(state.SetViewToggle(XCUIShellViewToggleId::LegacyHostDemoWindow, true));
|
||||
EXPECT_TRUE(state.GetViewToggle(XCUIShellViewToggleId::LegacyHostDemoWindow));
|
||||
EXPECT_FALSE(state.SetViewToggle(XCUIShellViewToggleId::LegacyHostDemoWindow, true));
|
||||
|
||||
EXPECT_TRUE(state.ToggleViewToggle(XCUIShellViewToggleId::HostedPreviewHud));
|
||||
EXPECT_FALSE(state.GetViewToggle(XCUIShellViewToggleId::HostedPreviewHud));
|
||||
EXPECT_TRUE(state.GetViewToggle(XCUIShellViewToggleId::NativeBackdrop));
|
||||
@@ -190,7 +185,7 @@ TEST(XCUIShellChromeStateTest, ViewMenuDescriptorMatchesCurrentApplicationOrderi
|
||||
|
||||
const auto menu = state.BuildViewMenuDescriptor();
|
||||
ASSERT_EQ(menu.label, "View");
|
||||
ASSERT_EQ(menu.items.size(), 10u);
|
||||
ASSERT_EQ(menu.items.size(), 9u);
|
||||
|
||||
ASSERT_EQ(menu.items[0].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[0].command.label, "XCUI Demo");
|
||||
@@ -203,42 +198,37 @@ TEST(XCUIShellChromeStateTest, ViewMenuDescriptorMatchesCurrentApplicationOrderi
|
||||
EXPECT_EQ(menu.items[1].command.shortcut, "Ctrl+2");
|
||||
EXPECT_EQ(menu.items[1].command.commandId, XCUIShellChromeCommandIds::ToggleXCUILayoutLabPanel);
|
||||
|
||||
ASSERT_EQ(menu.items[2].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[2].command.label, "Legacy Host Demo");
|
||||
EXPECT_EQ(menu.items[2].command.shortcut, "Ctrl+3");
|
||||
EXPECT_EQ(menu.items[2].command.commandId, XCUIShellChromeCommandIds::ToggleLegacyHostDemoWindow);
|
||||
EXPECT_EQ(menu.items[2].kind, XCUIShellMenuItemKind::Separator);
|
||||
|
||||
EXPECT_EQ(menu.items[3].kind, XCUIShellMenuItemKind::Separator);
|
||||
ASSERT_EQ(menu.items[3].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[3].command.label, "Native Backdrop");
|
||||
EXPECT_EQ(menu.items[3].command.shortcut, "Ctrl+Shift+B");
|
||||
EXPECT_EQ(menu.items[3].command.commandId, XCUIShellChromeCommandIds::ToggleNativeBackdrop);
|
||||
|
||||
ASSERT_EQ(menu.items[4].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[4].command.label, "Native Backdrop");
|
||||
EXPECT_EQ(menu.items[4].command.shortcut, "Ctrl+Shift+B");
|
||||
EXPECT_EQ(menu.items[4].command.commandId, XCUIShellChromeCommandIds::ToggleNativeBackdrop);
|
||||
EXPECT_EQ(menu.items[4].command.label, "Pulse Accent");
|
||||
EXPECT_EQ(menu.items[4].command.shortcut, "Ctrl+Shift+P");
|
||||
EXPECT_EQ(menu.items[4].command.commandId, XCUIShellChromeCommandIds::TogglePulseAccent);
|
||||
|
||||
ASSERT_EQ(menu.items[5].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[5].command.label, "Pulse Accent");
|
||||
EXPECT_EQ(menu.items[5].command.shortcut, "Ctrl+Shift+P");
|
||||
EXPECT_EQ(menu.items[5].command.commandId, XCUIShellChromeCommandIds::TogglePulseAccent);
|
||||
EXPECT_EQ(menu.items[5].command.label, "Native XCUI Overlay");
|
||||
EXPECT_EQ(menu.items[5].command.shortcut, "Ctrl+Shift+O");
|
||||
EXPECT_EQ(menu.items[5].command.commandId, XCUIShellChromeCommandIds::ToggleNativeXCUIOverlay);
|
||||
|
||||
ASSERT_EQ(menu.items[6].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[6].command.label, "Native XCUI Overlay");
|
||||
EXPECT_EQ(menu.items[6].command.shortcut, "Ctrl+Shift+O");
|
||||
EXPECT_EQ(menu.items[6].command.commandId, XCUIShellChromeCommandIds::ToggleNativeXCUIOverlay);
|
||||
EXPECT_EQ(menu.items[6].command.label, "Hosted Preview HUD");
|
||||
EXPECT_EQ(menu.items[6].command.shortcut, "Ctrl+Shift+H");
|
||||
EXPECT_EQ(menu.items[6].command.commandId, XCUIShellChromeCommandIds::ToggleHostedPreviewHud);
|
||||
|
||||
ASSERT_EQ(menu.items[7].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[7].command.label, "Hosted Preview HUD");
|
||||
EXPECT_EQ(menu.items[7].command.shortcut, "Ctrl+Shift+H");
|
||||
EXPECT_EQ(menu.items[7].command.commandId, XCUIShellChromeCommandIds::ToggleHostedPreviewHud);
|
||||
EXPECT_EQ(menu.items[7].command.label, "Native Demo Panel Preview");
|
||||
EXPECT_EQ(menu.items[7].command.shortcut, "Ctrl+Alt+1");
|
||||
EXPECT_EQ(menu.items[7].command.commandId, XCUIShellChromeCommandIds::ToggleNativeDemoPanelPreview);
|
||||
|
||||
ASSERT_EQ(menu.items[8].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[8].command.label, "Native Demo Panel Preview");
|
||||
EXPECT_EQ(menu.items[8].command.shortcut, "Ctrl+Alt+1");
|
||||
EXPECT_EQ(menu.items[8].command.commandId, XCUIShellChromeCommandIds::ToggleNativeDemoPanelPreview);
|
||||
|
||||
ASSERT_EQ(menu.items[9].kind, XCUIShellMenuItemKind::Command);
|
||||
EXPECT_EQ(menu.items[9].command.label, "Native Layout Lab Preview");
|
||||
EXPECT_EQ(menu.items[9].command.shortcut, "Ctrl+Alt+2");
|
||||
EXPECT_EQ(menu.items[9].command.commandId, XCUIShellChromeCommandIds::ToggleNativeLayoutLabPreview);
|
||||
EXPECT_EQ(menu.items[8].command.label, "Native Layout Lab Preview");
|
||||
EXPECT_EQ(menu.items[8].command.shortcut, "Ctrl+Alt+2");
|
||||
EXPECT_EQ(menu.items[8].command.commandId, XCUIShellChromeCommandIds::ToggleNativeLayoutLabPreview);
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, ViewMenuDescriptorCheckedStateTracksShellStateChanges) {
|
||||
@@ -254,9 +244,9 @@ TEST(XCUIShellChromeStateTest, ViewMenuDescriptorCheckedStateTracksShellStateCha
|
||||
const auto menu = state.BuildViewMenuDescriptor();
|
||||
|
||||
EXPECT_FALSE(menu.items[0].command.checked);
|
||||
EXPECT_FALSE(menu.items[6].command.checked);
|
||||
EXPECT_FALSE(menu.items[7].command.checked);
|
||||
EXPECT_FALSE(menu.items[8].command.checked);
|
||||
EXPECT_TRUE(menu.items[9].command.checked);
|
||||
EXPECT_TRUE(menu.items[8].command.checked);
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, PanelCommandIdHelpersMatchCurrentShellCommands) {
|
||||
@@ -275,9 +265,6 @@ TEST(XCUIShellChromeStateTest, PanelCommandIdHelpersMatchCurrentShellCommands) {
|
||||
}
|
||||
|
||||
TEST(XCUIShellChromeStateTest, ViewToggleCommandIdHelpersMatchCurrentShellCommands) {
|
||||
EXPECT_EQ(
|
||||
XCUIShellChromeState::GetViewToggleCommandId(XCUIShellViewToggleId::LegacyHostDemoWindow),
|
||||
XCUIShellChromeCommandIds::ToggleLegacyHostDemoWindow);
|
||||
EXPECT_EQ(
|
||||
XCUIShellChromeState::GetViewToggleCommandId(XCUIShellViewToggleId::NativeBackdrop),
|
||||
XCUIShellChromeCommandIds::ToggleNativeBackdrop);
|
||||
|
||||
176
tests/Rendering/integration/RenderingIntegrationImageAssert.h
Normal file
176
tests/Rendering/integration/RenderingIntegrationImageAssert.h
Normal file
@@ -0,0 +1,176 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
namespace RenderingIntegrationTestUtils {
|
||||
|
||||
struct PpmImage {
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
std::vector<uint8_t> rgb;
|
||||
|
||||
std::array<uint8_t, 3> GetPixel(uint32_t x, uint32_t y) const {
|
||||
const size_t index = (static_cast<size_t>(y) * width + x) * 3u;
|
||||
return { rgb[index + 0], rgb[index + 1], rgb[index + 2] };
|
||||
}
|
||||
};
|
||||
|
||||
inline std::filesystem::path GetExecutableDirectory() {
|
||||
char exePath[MAX_PATH] = {};
|
||||
const DWORD length = GetModuleFileNameA(nullptr, exePath, MAX_PATH);
|
||||
if (length == 0 || length >= MAX_PATH) {
|
||||
return std::filesystem::current_path();
|
||||
}
|
||||
|
||||
return std::filesystem::path(exePath).parent_path();
|
||||
}
|
||||
|
||||
inline std::filesystem::path ResolveRuntimePath(const char* path) {
|
||||
std::filesystem::path resolved(path);
|
||||
if (resolved.is_absolute()) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
return GetExecutableDirectory() / resolved;
|
||||
}
|
||||
|
||||
inline std::string ReadNextPpmToken(std::istream& stream) {
|
||||
std::string token;
|
||||
while (stream >> token) {
|
||||
if (!token.empty() && token[0] == '#') {
|
||||
std::string ignored;
|
||||
std::getline(stream, ignored);
|
||||
continue;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
inline PpmImage LoadPpmImage(const char* path) {
|
||||
const std::filesystem::path resolvedPath = ResolveRuntimePath(path);
|
||||
std::ifstream file(resolvedPath, std::ios::binary);
|
||||
EXPECT_TRUE(file.is_open()) << resolvedPath.string();
|
||||
|
||||
PpmImage image;
|
||||
if (!file.is_open()) {
|
||||
return image;
|
||||
}
|
||||
|
||||
const std::string magic = ReadNextPpmToken(file);
|
||||
EXPECT_EQ(magic, "P6");
|
||||
if (magic != "P6") {
|
||||
return image;
|
||||
}
|
||||
|
||||
const std::string widthToken = ReadNextPpmToken(file);
|
||||
const std::string heightToken = ReadNextPpmToken(file);
|
||||
const std::string maxValueToken = ReadNextPpmToken(file);
|
||||
EXPECT_FALSE(widthToken.empty());
|
||||
EXPECT_FALSE(heightToken.empty());
|
||||
EXPECT_FALSE(maxValueToken.empty());
|
||||
if (widthToken.empty() || heightToken.empty() || maxValueToken.empty()) {
|
||||
return image;
|
||||
}
|
||||
|
||||
image.width = static_cast<uint32_t>(std::stoul(widthToken));
|
||||
image.height = static_cast<uint32_t>(std::stoul(heightToken));
|
||||
EXPECT_EQ(std::stoul(maxValueToken), 255u);
|
||||
|
||||
file.get();
|
||||
image.rgb.resize(static_cast<size_t>(image.width) * image.height * 3u);
|
||||
file.read(reinterpret_cast<char*>(image.rgb.data()), static_cast<std::streamsize>(image.rgb.size()));
|
||||
EXPECT_EQ(file.gcount(), static_cast<std::streamsize>(image.rgb.size()));
|
||||
return image;
|
||||
}
|
||||
|
||||
inline int PixelLuminance(const std::array<uint8_t, 3>& pixel) {
|
||||
return static_cast<int>(pixel[0]) + static_cast<int>(pixel[1]) + static_cast<int>(pixel[2]);
|
||||
}
|
||||
|
||||
inline void AssertPixelInBounds(const PpmImage& image, uint32_t x, uint32_t y, const char* label) {
|
||||
ASSERT_LT(x, image.width) << label;
|
||||
ASSERT_LT(y, image.height) << label;
|
||||
}
|
||||
|
||||
inline void ExpectPixelNear(
|
||||
const PpmImage& image,
|
||||
uint32_t x,
|
||||
uint32_t y,
|
||||
const std::array<uint8_t, 3>& expected,
|
||||
uint8_t tolerance,
|
||||
const char* label) {
|
||||
AssertPixelInBounds(image, x, y, label);
|
||||
|
||||
const std::array<uint8_t, 3> actual = image.GetPixel(x, y);
|
||||
for (size_t channel = 0; channel < actual.size(); ++channel) {
|
||||
const int delta = std::abs(static_cast<int>(actual[channel]) - static_cast<int>(expected[channel]));
|
||||
EXPECT_LE(delta, static_cast<int>(tolerance))
|
||||
<< label << " @ (" << x << ", " << y << ") channel=" << channel;
|
||||
}
|
||||
}
|
||||
|
||||
inline void ExpectPixelLuminanceAtLeast(
|
||||
const PpmImage& image,
|
||||
uint32_t x,
|
||||
uint32_t y,
|
||||
int minLuminance,
|
||||
const char* label) {
|
||||
AssertPixelInBounds(image, x, y, label);
|
||||
|
||||
const std::array<uint8_t, 3> actual = image.GetPixel(x, y);
|
||||
EXPECT_GE(PixelLuminance(actual), minLuminance) << label << " @ (" << x << ", " << y << ")";
|
||||
}
|
||||
|
||||
inline void ExpectPixelLuminanceAtMost(
|
||||
const PpmImage& image,
|
||||
uint32_t x,
|
||||
uint32_t y,
|
||||
int maxLuminance,
|
||||
const char* label) {
|
||||
AssertPixelInBounds(image, x, y, label);
|
||||
|
||||
const std::array<uint8_t, 3> actual = image.GetPixel(x, y);
|
||||
EXPECT_LE(PixelLuminance(actual), maxLuminance) << label << " @ (" << x << ", " << y << ")";
|
||||
}
|
||||
|
||||
inline void ExpectPixelChannelDominates(
|
||||
const PpmImage& image,
|
||||
uint32_t x,
|
||||
uint32_t y,
|
||||
size_t dominantChannel,
|
||||
int minMargin,
|
||||
const char* label) {
|
||||
AssertPixelInBounds(image, x, y, label);
|
||||
ASSERT_LT(dominantChannel, static_cast<size_t>(3)) << label;
|
||||
|
||||
const std::array<uint8_t, 3> actual = image.GetPixel(x, y);
|
||||
int maxOtherChannel = 0;
|
||||
for (size_t channel = 0; channel < actual.size(); ++channel) {
|
||||
if (channel == dominantChannel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
maxOtherChannel = std::max(maxOtherChannel, static_cast<int>(actual[channel]));
|
||||
}
|
||||
|
||||
EXPECT_GE(static_cast<int>(actual[dominantChannel]) - maxOtherChannel, minMargin)
|
||||
<< label << " @ (" << x << ", " << y << ")";
|
||||
}
|
||||
|
||||
} // namespace RenderingIntegrationTestUtils
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../RenderingIntegrationImageAssert.h"
|
||||
#include "../RenderingIntegrationMain.h"
|
||||
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
@@ -45,6 +46,18 @@ constexpr const char* kVulkanScreenshot = "multi_light_scene_vulkan.ppm";
|
||||
constexpr uint32_t kFrameWidth = 1280;
|
||||
constexpr uint32_t kFrameHeight = 720;
|
||||
|
||||
void ExpectMultiLightKeyPixels(const RenderingIntegrationTestUtils::PpmImage& image) {
|
||||
using namespace RenderingIntegrationTestUtils;
|
||||
|
||||
ExpectPixelLuminanceAtMost(image, 320, 320, 24, "background remains dark");
|
||||
ExpectPixelLuminanceAtLeast(image, 625, 285, 540, "left point-light highlight");
|
||||
ExpectPixelChannelDominates(image, 625, 285, 0, 80, "left point-light highlight stays warm");
|
||||
ExpectPixelLuminanceAtLeast(image, 640, 315, 470, "center cube receives main light");
|
||||
ExpectPixelChannelDominates(image, 640, 315, 0, 40, "center cube keeps warm directional tint");
|
||||
ExpectPixelLuminanceAtLeast(image, 758, 311, 300, "right cube receives cool fill");
|
||||
ExpectPixelChannelDominates(image, 758, 311, 2, 20, "right cube keeps cool fill tint");
|
||||
}
|
||||
|
||||
void AppendQuadFace(
|
||||
std::vector<StaticMeshVertex>& vertices,
|
||||
std::vector<uint32_t>& indices,
|
||||
@@ -459,6 +472,8 @@ TEST_P(MultiLightSceneTest, RenderMultiLightScene) {
|
||||
if (frameCount >= targetFrameCount) {
|
||||
commandQueue->WaitForIdle();
|
||||
ASSERT_TRUE(TakeScreenshot(screenshotFilename));
|
||||
const auto screenshotImage = RenderingIntegrationTestUtils::LoadPpmImage(screenshotFilename);
|
||||
ExpectMultiLightKeyPixels(screenshotImage);
|
||||
ASSERT_TRUE(CompareWithGoldenTemplate(screenshotFilename, "GT.ppm", static_cast<float>(comparisonThreshold)));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../RenderingIntegrationImageAssert.h"
|
||||
#include "../RenderingIntegrationMain.h"
|
||||
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
@@ -45,6 +46,20 @@ constexpr const char* kVulkanScreenshot = "spot_light_scene_vulkan.ppm";
|
||||
constexpr uint32_t kFrameWidth = 1280;
|
||||
constexpr uint32_t kFrameHeight = 720;
|
||||
|
||||
void ExpectSpotLightKeyPixels(const RenderingIntegrationTestUtils::PpmImage& image) {
|
||||
using namespace RenderingIntegrationTestUtils;
|
||||
|
||||
ExpectPixelLuminanceAtMost(image, 320, 320, 18, "background remains unlit");
|
||||
ExpectPixelLuminanceAtLeast(image, 640, 320, 700, "spot hot area stays bright");
|
||||
ExpectPixelNear(image, 640, 320, { 255, 255, 203 }, 2, "spot hot area color");
|
||||
ExpectPixelLuminanceAtLeast(image, 676, 289, 560, "upper cone receives spotlight");
|
||||
ExpectPixelChannelDominates(image, 676, 289, 0, 40, "upper cone keeps warm tint");
|
||||
ExpectPixelLuminanceAtLeast(image, 700, 376, 540, "ground inside cone stays lit");
|
||||
ExpectPixelChannelDominates(image, 700, 376, 0, 30, "ground inside cone stays warm");
|
||||
ExpectPixelLuminanceAtMost(image, 760, 320, 210, "edge cube outside cone stays dark");
|
||||
ExpectPixelLuminanceAtMost(image, 640, 406, 160, "ground outside cone stays dark");
|
||||
}
|
||||
|
||||
void AppendQuadFace(
|
||||
std::vector<StaticMeshVertex>& vertices,
|
||||
std::vector<uint32_t>& indices,
|
||||
@@ -420,6 +435,8 @@ TEST_P(SpotLightSceneTest, RenderSpotLightScene) {
|
||||
if (frameCount >= targetFrameCount) {
|
||||
commandQueue->WaitForIdle();
|
||||
ASSERT_TRUE(TakeScreenshot(screenshotFilename));
|
||||
const auto screenshotImage = RenderingIntegrationTestUtils::LoadPpmImage(screenshotFilename);
|
||||
ExpectSpotLightKeyPixels(screenshotImage);
|
||||
ASSERT_TRUE(CompareWithGoldenTemplate(screenshotFilename, "GT.ppm", static_cast<float>(comparisonThreshold)));
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user