#include #include "Viewport/ViewportObjectIdPicker.h" #include namespace { using XCEngine::Editor::BuildViewportObjectIdReadbackRequest; using XCEngine::Editor::CanPickViewportObjectId; using XCEngine::Editor::PickViewportObjectIdEntity; using XCEngine::Editor::TryPickViewportObjectIdEntity; using XCEngine::Editor::ViewportObjectIdPickContext; using XCEngine::Editor::ViewportObjectIdPickResult; using XCEngine::Editor::ViewportObjectIdPickStatus; using XCEngine::Editor::ViewportObjectIdReadbackRequest; using XCEngine::RHI::RHICommandQueue; using XCEngine::RHI::RHITexture; using XCEngine::RHI::ResourceStates; using XCEngine::UI::UIPoint; using XCEngine::UI::UISize; RHICommandQueue* MakeDummyQueue() { return reinterpret_cast(static_cast(0x1)); } RHITexture* MakeDummyTexture() { return reinterpret_cast(static_cast(0x2)); } ViewportObjectIdPickContext CreateValidContext() { ViewportObjectIdPickContext context = {}; context.commandQueue = MakeDummyQueue(); context.texture = MakeDummyTexture(); context.textureState = ResourceStates::PixelShaderResource; context.textureWidth = 1280; context.textureHeight = 720; context.hasValidFrame = true; context.viewportSize = UISize(1280.0f, 720.0f); context.viewportMousePosition = UIPoint(640.0f, 360.0f); return context; } TEST(ViewportObjectIdPickerTest, CanPickRejectsMissingOrOutOfBoundsInputs) { ViewportObjectIdPickContext context = CreateValidContext(); EXPECT_TRUE(CanPickViewportObjectId(context)); context.commandQueue = nullptr; EXPECT_FALSE(CanPickViewportObjectId(context)); context = CreateValidContext(); context.texture = nullptr; EXPECT_FALSE(CanPickViewportObjectId(context)); context = CreateValidContext(); context.hasValidFrame = false; EXPECT_FALSE(CanPickViewportObjectId(context)); context = CreateValidContext(); context.textureWidth = 0; EXPECT_FALSE(CanPickViewportObjectId(context)); context = CreateValidContext(); context.viewportMousePosition = UIPoint(-1.0f, 10.0f); EXPECT_FALSE(CanPickViewportObjectId(context)); context = CreateValidContext(); context.viewportMousePosition = UIPoint(10.0f, 721.0f); EXPECT_FALSE(CanPickViewportObjectId(context)); } TEST(ViewportObjectIdPickerTest, BuildReadbackRequestMapsViewportCoordinatesToTexturePixels) { ViewportObjectIdPickContext context = CreateValidContext(); context.viewportMousePosition = UIPoint(1280.0f, 720.0f); ViewportObjectIdReadbackRequest request = {}; ASSERT_TRUE(BuildViewportObjectIdReadbackRequest(context, request)); EXPECT_EQ(request.commandQueue, context.commandQueue); EXPECT_EQ(request.texture, context.texture); EXPECT_EQ(request.textureState, ResourceStates::PixelShaderResource); EXPECT_EQ(request.pixelX, 1279u); EXPECT_EQ(request.pixelY, 719u); } TEST(ViewportObjectIdPickerTest, TryPickViewportObjectIdEntityDecodesReadbackColor) { const ViewportObjectIdPickContext context = CreateValidContext(); uint64_t entityId = 0; ViewportObjectIdReadbackRequest capturedRequest = {}; const bool picked = TryPickViewportObjectIdEntity( context, [&capturedRequest](const ViewportObjectIdReadbackRequest& request, std::array& outRgba) { capturedRequest = request; outRgba = { 0x78, 0x56, 0x34, 0x12 }; return true; }, entityId); EXPECT_TRUE(picked); EXPECT_EQ(entityId, 0x12345678ull); EXPECT_EQ(capturedRequest.pixelX, 640u); EXPECT_EQ(capturedRequest.pixelY, 360u); } TEST(ViewportObjectIdPickerTest, PickViewportObjectIdEntityReturnsSuccessForZeroObjectId) { const ViewportObjectIdPickContext context = CreateValidContext(); const ViewportObjectIdPickResult result = PickViewportObjectIdEntity( context, [](const ViewportObjectIdReadbackRequest&, std::array& outRgba) { outRgba = { 0u, 0u, 0u, 0u }; return true; }); EXPECT_EQ(result.status, ViewportObjectIdPickStatus::Success); EXPECT_EQ(result.entityId, 0u); EXPECT_TRUE(result.HasResolvedSample()); } TEST(ViewportObjectIdPickerTest, PickViewportObjectIdEntityReturnsUnavailableWhenContextIsInvalid) { ViewportObjectIdPickContext context = CreateValidContext(); context.hasValidFrame = false; const ViewportObjectIdPickResult result = PickViewportObjectIdEntity( context, [](const ViewportObjectIdReadbackRequest&, std::array&) { return true; }); EXPECT_EQ(result.status, ViewportObjectIdPickStatus::Unavailable); EXPECT_EQ(result.entityId, 0u); EXPECT_FALSE(result.HasResolvedSample()); } TEST(ViewportObjectIdPickerTest, TryPickViewportObjectIdEntityFailsWhenReadbackFails) { const ViewportObjectIdPickContext context = CreateValidContext(); uint64_t entityId = 99; const bool picked = TryPickViewportObjectIdEntity( context, [](const ViewportObjectIdReadbackRequest&, std::array&) { return false; }, entityId); EXPECT_FALSE(picked); EXPECT_EQ(entityId, 0u); } TEST(ViewportObjectIdPickerTest, PickViewportObjectIdEntityReportsReadbackFailure) { const ViewportObjectIdPickContext context = CreateValidContext(); const ViewportObjectIdPickResult result = PickViewportObjectIdEntity( context, [](const ViewportObjectIdReadbackRequest&, std::array&) { return false; }); EXPECT_EQ(result.status, ViewportObjectIdPickStatus::ReadbackFailed); EXPECT_EQ(result.entityId, 0u); EXPECT_FALSE(result.HasResolvedSample()); } } // namespace