engine: sync editor rendering and ui changes

This commit is contained in:
2026-04-08 16:09:15 +08:00
parent 31756847ab
commit 162f1cc12e
153 changed files with 4454 additions and 2990 deletions

View File

@@ -131,6 +131,19 @@ bool DrawDataContainsText(
return false;
}
const XCEngine::UI::UIDrawCommand* FindFirstFilledRectCommand(
const XCEngine::UI::UIDrawData& drawData) {
for (const XCEngine::UI::UIDrawList& drawList : drawData.GetDrawLists()) {
for (const XCEngine::UI::UIDrawCommand& command : drawList.GetCommands()) {
if (command.type == XCEngine::UI::UIDrawCommandType::FilledRect) {
return &command;
}
}
}
return nullptr;
}
const XCEngine::UI::Runtime::UISystemPresentedLayer* FindPresentedLayerById(
const XCEngine::UI::Runtime::UISystemFrameResult& frame,
XCEngine::UI::Runtime::UIScreenLayerId layerId) {
@@ -442,6 +455,97 @@ TEST_F(SceneRuntimeTest, StopClearsUiRuntimeState) {
EXPECT_TRUE(runtime.GetLastUIFrame().layers.empty());
}
TEST_F(SceneRuntimeTest, ClearQueuedUiInputEventsPreventsPendingDelivery) {
Scene* runtimeScene = CreateScene("RuntimeScene");
runtime.Start(runtimeScene);
runtime.SetUIViewportRect(XCEngine::UI::UIRect(0.0f, 0.0f, 800.0f, 480.0f));
runtime.SetUIFocused(true);
TempFileScope menuView("xcui_scene_runtime_clear_input", ".xcui", BuildViewMarkup("Clear Input Menu"));
const auto layerId = runtime.GetUIScreenStackController().PushMenu(
BuildScreenAsset(menuView.Path(), "runtime.clear.input"),
"clear-input");
ASSERT_NE(layerId, 0u);
XCEngine::UI::UIInputEvent textEvent = {};
textEvent.type = XCEngine::UI::UIInputEventType::Character;
textEvent.character = 'A';
runtime.QueueUIInputEvent(textEvent);
XCEngine::UI::UIInputEvent keyEvent = {};
keyEvent.type = XCEngine::UI::UIInputEventType::KeyDown;
keyEvent.keyCode = 13;
runtime.QueueUIInputEvent(keyEvent);
runtime.ClearQueuedUIInputEvents();
runtime.Update(0.016f);
const auto& clearedFrame = runtime.GetLastUIFrame();
ASSERT_EQ(clearedFrame.presentedLayerCount, 1u);
ASSERT_EQ(clearedFrame.layers.size(), 1u);
EXPECT_EQ(clearedFrame.frameIndex, 1u);
EXPECT_EQ(clearedFrame.layers.front().layerId, layerId);
EXPECT_EQ(clearedFrame.layers.front().stats.inputEventCount, 0u);
runtime.QueueUIInputEvent(textEvent);
runtime.Update(0.016f);
const auto& deliveredFrame = runtime.GetLastUIFrame();
ASSERT_EQ(deliveredFrame.presentedLayerCount, 1u);
ASSERT_EQ(deliveredFrame.layers.size(), 1u);
EXPECT_EQ(deliveredFrame.frameIndex, 2u);
EXPECT_EQ(deliveredFrame.layers.front().stats.inputEventCount, 1u);
}
TEST_F(SceneRuntimeTest, ViewportPersistsAcrossFramesAndResetsAfterStop) {
Scene* runtimeScene = CreateScene("RuntimeScene");
runtime.Start(runtimeScene);
runtime.SetUIViewportRect(XCEngine::UI::UIRect(32.0f, 48.0f, 900.0f, 500.0f));
runtime.SetUIFocused(true);
TempFileScope menuView("xcui_scene_runtime_viewport", ".xcui", BuildViewMarkup("Viewport Menu"));
const UIScreenAsset screenAsset = BuildScreenAsset(menuView.Path(), "runtime.viewport.menu");
ASSERT_NE(runtime.GetUIScreenStackController().PushMenu(screenAsset, "viewport-menu"), 0u);
runtime.Update(0.016f);
const auto& firstFrame = runtime.GetLastUIFrame();
const auto* firstBackground = FindFirstFilledRectCommand(firstFrame.drawData);
ASSERT_NE(firstBackground, nullptr);
EXPECT_EQ(firstFrame.frameIndex, 1u);
EXPECT_FLOAT_EQ(firstBackground->rect.x, 32.0f);
EXPECT_FLOAT_EQ(firstBackground->rect.y, 48.0f);
EXPECT_FLOAT_EQ(firstBackground->rect.width, 900.0f);
EXPECT_FLOAT_EQ(firstBackground->rect.height, 500.0f);
runtime.Update(0.016f);
const auto& secondFrame = runtime.GetLastUIFrame();
const auto* secondBackground = FindFirstFilledRectCommand(secondFrame.drawData);
ASSERT_NE(secondBackground, nullptr);
EXPECT_EQ(secondFrame.frameIndex, 2u);
EXPECT_FLOAT_EQ(secondBackground->rect.x, 32.0f);
EXPECT_FLOAT_EQ(secondBackground->rect.y, 48.0f);
EXPECT_FLOAT_EQ(secondBackground->rect.width, 900.0f);
EXPECT_FLOAT_EQ(secondBackground->rect.height, 500.0f);
runtime.Stop();
runtime.Start(runtimeScene);
runtime.SetUIFocused(true);
ASSERT_NE(runtime.GetUIScreenStackController().PushMenu(screenAsset, "viewport-menu-reset"), 0u);
runtime.Update(0.016f);
const auto& restartedFrame = runtime.GetLastUIFrame();
const auto* restartedBackground = FindFirstFilledRectCommand(restartedFrame.drawData);
ASSERT_NE(restartedBackground, nullptr);
EXPECT_EQ(restartedFrame.frameIndex, 1u);
EXPECT_FLOAT_EQ(restartedBackground->rect.x, 0.0f);
EXPECT_FLOAT_EQ(restartedBackground->rect.y, 0.0f);
EXPECT_FLOAT_EQ(restartedBackground->rect.width, 640.0f);
EXPECT_FLOAT_EQ(restartedBackground->rect.height, 360.0f);
}
TEST_F(SceneRuntimeTest, LayeredSceneUiRoutesInputOnlyToTopInteractivePresentedLayer) {
Scene* runtimeScene = CreateScene("RuntimeScene");
runtime.Start(runtimeScene);