Introduce scene viewport overlay providers
This commit is contained in:
210
tests/editor/test_scene_viewport_overlay_providers.cpp
Normal file
210
tests/editor/test_scene_viewport_overlay_providers.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "Core/EditorContext.h"
|
||||
#include "Viewport/SceneViewportOverlayBuilder.h"
|
||||
#include "Viewport/SceneViewportOverlayProviders.h"
|
||||
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
#include <XCEngine/Components/LightComponent.h>
|
||||
#include <XCEngine/Core/Math/Color.h>
|
||||
#include <XCEngine/Core/Math/Vector3.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine::Editor {
|
||||
namespace {
|
||||
|
||||
class MarkerOverlayProvider final : public ISceneViewportOverlayProvider {
|
||||
public:
|
||||
explicit MarkerOverlayProvider(float marker)
|
||||
: m_marker(marker) {
|
||||
}
|
||||
|
||||
const char* GetName() const override {
|
||||
return "MarkerOverlayProvider";
|
||||
}
|
||||
|
||||
void AppendOverlay(
|
||||
const SceneViewportOverlayBuildContext& context,
|
||||
SceneViewportOverlayFrameData& frameData) const override {
|
||||
if (!context.IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SceneViewportOverlayLinePrimitive& line = frameData.worldLines.emplace_back();
|
||||
line.startWorld = Math::Vector3(m_marker, 0.0f, 0.0f);
|
||||
line.endWorld = Math::Vector3(m_marker, 1.0f, 0.0f);
|
||||
line.color = Math::Color::White();
|
||||
}
|
||||
|
||||
private:
|
||||
float m_marker = 0.0f;
|
||||
};
|
||||
|
||||
SceneViewportOverlayData CreateValidOverlay() {
|
||||
SceneViewportOverlayData overlay = {};
|
||||
overlay.valid = true;
|
||||
overlay.cameraPosition = Math::Vector3::Zero();
|
||||
overlay.cameraForward = Math::Vector3::Forward();
|
||||
overlay.cameraRight = Math::Vector3::Right();
|
||||
overlay.cameraUp = Math::Vector3::Up();
|
||||
overlay.verticalFovDegrees = 60.0f;
|
||||
overlay.nearClipPlane = 0.1f;
|
||||
overlay.farClipPlane = 1000.0f;
|
||||
overlay.orbitDistance = 6.0f;
|
||||
return overlay;
|
||||
}
|
||||
|
||||
SceneViewportOverlayBuildContext CreateBuildContext(
|
||||
EditorContext& context,
|
||||
const SceneViewportOverlayData& overlay,
|
||||
const std::vector<uint64_t>& selectedObjectIds,
|
||||
uint32_t viewportWidth = 1280u,
|
||||
uint32_t viewportHeight = 720u) {
|
||||
return {
|
||||
&context,
|
||||
context.GetSceneManager().GetScene(),
|
||||
&overlay,
|
||||
viewportWidth,
|
||||
viewportHeight,
|
||||
&selectedObjectIds
|
||||
};
|
||||
}
|
||||
|
||||
bool ContainsSpriteKind(
|
||||
const SceneViewportOverlayFrameData& frameData,
|
||||
SceneViewportOverlaySpriteTextureKind textureKind) {
|
||||
return std::any_of(
|
||||
frameData.worldSprites.begin(),
|
||||
frameData.worldSprites.end(),
|
||||
[textureKind](const SceneViewportOverlaySpritePrimitive& sprite) {
|
||||
return sprite.textureKind == textureKind;
|
||||
});
|
||||
}
|
||||
|
||||
TEST(SceneViewportOverlayProviderRegistryTest, AppendsProvidersInRegistrationOrder) {
|
||||
EditorContext context;
|
||||
context.GetSceneManager().NewScene("Overlay Provider Registry");
|
||||
|
||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||
const std::vector<uint64_t> selectedObjectIds = {};
|
||||
const SceneViewportOverlayBuildContext buildContext =
|
||||
CreateBuildContext(context, overlay, selectedObjectIds);
|
||||
|
||||
SceneViewportOverlayProviderRegistry registry;
|
||||
registry.AddProvider(std::make_unique<MarkerOverlayProvider>(1.0f));
|
||||
registry.AddProvider(std::make_unique<MarkerOverlayProvider>(2.0f));
|
||||
|
||||
ASSERT_EQ(registry.GetProviderCount(), 2u);
|
||||
ASSERT_NE(registry.GetProvider(0u), nullptr);
|
||||
ASSERT_NE(registry.GetProvider(1u), nullptr);
|
||||
|
||||
SceneViewportOverlayFrameData frameData = {};
|
||||
frameData.overlay = overlay;
|
||||
registry.AppendOverlay(buildContext, frameData);
|
||||
|
||||
ASSERT_EQ(frameData.worldLines.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(frameData.worldLines[0].startWorld.x, 1.0f);
|
||||
EXPECT_FLOAT_EQ(frameData.worldLines[1].startWorld.x, 2.0f);
|
||||
}
|
||||
|
||||
TEST(SceneViewportOverlayProviderRegistryTest, CameraProviderBuildsSceneIconAndSelectedFrustum) {
|
||||
EditorContext context;
|
||||
context.GetSceneManager().NewScene("Camera Overlay Provider");
|
||||
|
||||
auto* cameraEntity = context.GetSceneManager().CreateEntity("SceneCamera");
|
||||
ASSERT_NE(cameraEntity, nullptr);
|
||||
cameraEntity->GetTransform()->SetPosition(Math::Vector3(0.0f, 0.0f, 5.0f));
|
||||
|
||||
auto* camera = cameraEntity->AddComponent<Components::CameraComponent>();
|
||||
ASSERT_NE(camera, nullptr);
|
||||
camera->SetNearClipPlane(0.3f);
|
||||
camera->SetFarClipPlane(20.0f);
|
||||
|
||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||
const std::vector<uint64_t> selectedObjectIds = { cameraEntity->GetID() };
|
||||
const SceneViewportOverlayBuildContext buildContext =
|
||||
CreateBuildContext(context, overlay, selectedObjectIds);
|
||||
|
||||
auto provider = CreateSceneViewportCameraOverlayProvider();
|
||||
ASSERT_NE(provider, nullptr);
|
||||
|
||||
SceneViewportOverlayFrameData frameData = {};
|
||||
frameData.overlay = overlay;
|
||||
provider->AppendOverlay(buildContext, frameData);
|
||||
|
||||
ASSERT_EQ(frameData.worldSprites.size(), 1u);
|
||||
EXPECT_EQ(frameData.worldSprites[0].textureKind, SceneViewportOverlaySpriteTextureKind::Camera);
|
||||
ASSERT_EQ(frameData.handleRecords.size(), 1u);
|
||||
EXPECT_EQ(frameData.handleRecords[0].entityId, cameraEntity->GetID());
|
||||
EXPECT_EQ(frameData.worldLines.size(), 12u);
|
||||
}
|
||||
|
||||
TEST(SceneViewportOverlayProviderRegistryTest, LightProviderBuildsSceneIconAndSelectedDirectionalHelper) {
|
||||
EditorContext context;
|
||||
context.GetSceneManager().NewScene("Light Overlay Provider");
|
||||
|
||||
auto* lightEntity = context.GetSceneManager().CreateEntity("DirectionalLight");
|
||||
ASSERT_NE(lightEntity, nullptr);
|
||||
lightEntity->GetTransform()->SetPosition(Math::Vector3(0.0f, 0.0f, 5.0f));
|
||||
|
||||
auto* light = lightEntity->AddComponent<Components::LightComponent>();
|
||||
ASSERT_NE(light, nullptr);
|
||||
light->SetLightType(Components::LightType::Directional);
|
||||
|
||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||
const std::vector<uint64_t> selectedObjectIds = { lightEntity->GetID() };
|
||||
const SceneViewportOverlayBuildContext buildContext =
|
||||
CreateBuildContext(context, overlay, selectedObjectIds);
|
||||
|
||||
auto provider = CreateSceneViewportLightOverlayProvider();
|
||||
ASSERT_NE(provider, nullptr);
|
||||
|
||||
SceneViewportOverlayFrameData frameData = {};
|
||||
frameData.overlay = overlay;
|
||||
provider->AppendOverlay(buildContext, frameData);
|
||||
|
||||
ASSERT_EQ(frameData.worldSprites.size(), 1u);
|
||||
EXPECT_EQ(frameData.worldSprites[0].textureKind, SceneViewportOverlaySpriteTextureKind::Light);
|
||||
ASSERT_EQ(frameData.handleRecords.size(), 1u);
|
||||
EXPECT_EQ(frameData.handleRecords[0].entityId, lightEntity->GetID());
|
||||
EXPECT_GT(frameData.worldLines.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(
|
||||
SceneViewportOverlayProviderRegistryTest,
|
||||
OverlayBuilderUsesDefaultRegistryToAggregateCameraAndLightProviders) {
|
||||
EditorContext context;
|
||||
context.GetSceneManager().NewScene("Overlay Builder");
|
||||
|
||||
auto* cameraEntity = context.GetSceneManager().CreateEntity("SceneCamera");
|
||||
ASSERT_NE(cameraEntity, nullptr);
|
||||
cameraEntity->GetTransform()->SetPosition(Math::Vector3(-0.5f, 0.0f, 5.0f));
|
||||
ASSERT_NE(cameraEntity->AddComponent<Components::CameraComponent>(), nullptr);
|
||||
|
||||
auto* lightEntity = context.GetSceneManager().CreateEntity("DirectionalLight");
|
||||
ASSERT_NE(lightEntity, nullptr);
|
||||
lightEntity->GetTransform()->SetPosition(Math::Vector3(0.5f, 0.0f, 5.0f));
|
||||
auto* light = lightEntity->AddComponent<Components::LightComponent>();
|
||||
ASSERT_NE(light, nullptr);
|
||||
light->SetLightType(Components::LightType::Directional);
|
||||
|
||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||
const std::vector<uint64_t> selectedObjectIds = { cameraEntity->GetID(), lightEntity->GetID() };
|
||||
|
||||
SceneViewportOverlayBuilder builder;
|
||||
const SceneViewportOverlayFrameData frameData =
|
||||
builder.Build(context, overlay, 1280u, 720u, selectedObjectIds);
|
||||
|
||||
EXPECT_TRUE(frameData.overlay.valid);
|
||||
EXPECT_EQ(frameData.worldSprites.size(), 2u);
|
||||
EXPECT_EQ(frameData.handleRecords.size(), 2u);
|
||||
EXPECT_TRUE(ContainsSpriteKind(frameData, SceneViewportOverlaySpriteTextureKind::Camera));
|
||||
EXPECT_TRUE(ContainsSpriteKind(frameData, SceneViewportOverlaySpriteTextureKind::Light));
|
||||
EXPECT_GT(frameData.worldLines.size(), 12u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace XCEngine::Editor
|
||||
Reference in New Issue
Block a user