2026-04-03 15:43:21 +08:00
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
2026-04-04 17:10:15 +08:00
|
|
|
#include "Viewport/SceneViewportResourcePaths.h"
|
2026-04-03 15:43:21 +08:00
|
|
|
#include "Viewport/SceneViewportShaderPaths.h"
|
|
|
|
|
|
|
|
|
|
#include <XCEngine/Core/Asset/ResourceManager.h>
|
2026-04-08 16:09:15 +08:00
|
|
|
#include <XCEngine/Resources/BuiltinResources.h>
|
2026-04-03 15:43:21 +08:00
|
|
|
#include <XCEngine/Resources/Shader/ShaderLoader.h>
|
|
|
|
|
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
2026-04-04 17:10:15 +08:00
|
|
|
using XCEngine::Editor::GetSceneViewportCameraGizmoIconPath;
|
2026-04-08 16:09:15 +08:00
|
|
|
using XCEngine::Editor::GetSceneViewportDirectionalLightGizmoIconPath;
|
2026-04-03 15:43:21 +08:00
|
|
|
using XCEngine::Editor::GetSceneViewportInfiniteGridShaderPath;
|
2026-04-08 16:09:15 +08:00
|
|
|
using XCEngine::Editor::GetSceneViewportPointLightGizmoIconPath;
|
|
|
|
|
using XCEngine::Editor::GetSceneViewportSpotLightGizmoIconPath;
|
|
|
|
|
using XCEngine::Resources::GetBuiltinObjectIdOutlineShaderPath;
|
2026-04-09 05:16:04 +08:00
|
|
|
using XCEngine::Resources::GetBuiltinSelectionMaskShaderPath;
|
|
|
|
|
using XCEngine::Resources::GetBuiltinSelectionOutlineShaderPath;
|
2026-04-03 15:43:21 +08:00
|
|
|
using XCEngine::Resources::LoadResult;
|
|
|
|
|
using XCEngine::Resources::ResourceHandle;
|
|
|
|
|
using XCEngine::Resources::ResourceManager;
|
|
|
|
|
using XCEngine::Resources::Shader;
|
|
|
|
|
using XCEngine::Resources::ShaderBackend;
|
2026-04-09 05:16:04 +08:00
|
|
|
using XCEngine::Resources::ShaderKeywordDeclarationType;
|
|
|
|
|
using XCEngine::Resources::ShaderKeywordSet;
|
2026-04-03 15:43:21 +08:00
|
|
|
using XCEngine::Resources::ShaderLoader;
|
|
|
|
|
using XCEngine::Resources::ShaderPass;
|
|
|
|
|
using XCEngine::Resources::ShaderStageVariant;
|
|
|
|
|
using XCEngine::Resources::ShaderType;
|
|
|
|
|
|
|
|
|
|
TEST(SceneViewportShaderPathsTest, ResolvePathsUnderEditorResources) {
|
|
|
|
|
const std::filesystem::path gridPath(GetSceneViewportInfiniteGridShaderPath().CStr());
|
2026-04-04 17:10:15 +08:00
|
|
|
const std::filesystem::path cameraIconPath(GetSceneViewportCameraGizmoIconPath().CStr());
|
2026-04-08 16:09:15 +08:00
|
|
|
const std::filesystem::path directionalLightIconPath(GetSceneViewportDirectionalLightGizmoIconPath().CStr());
|
|
|
|
|
const std::filesystem::path pointLightIconPath(GetSceneViewportPointLightGizmoIconPath().CStr());
|
|
|
|
|
const std::filesystem::path spotLightIconPath(GetSceneViewportSpotLightGizmoIconPath().CStr());
|
2026-04-03 15:43:21 +08:00
|
|
|
|
|
|
|
|
EXPECT_TRUE(gridPath.is_absolute());
|
2026-04-04 17:10:15 +08:00
|
|
|
EXPECT_TRUE(cameraIconPath.is_absolute());
|
2026-04-08 16:09:15 +08:00
|
|
|
EXPECT_TRUE(directionalLightIconPath.is_absolute());
|
|
|
|
|
EXPECT_TRUE(pointLightIconPath.is_absolute());
|
|
|
|
|
EXPECT_TRUE(spotLightIconPath.is_absolute());
|
2026-04-03 15:43:21 +08:00
|
|
|
EXPECT_TRUE(std::filesystem::exists(gridPath));
|
2026-04-04 17:10:15 +08:00
|
|
|
EXPECT_TRUE(std::filesystem::exists(cameraIconPath));
|
2026-04-08 16:09:15 +08:00
|
|
|
EXPECT_TRUE(std::filesystem::exists(directionalLightIconPath));
|
|
|
|
|
EXPECT_TRUE(std::filesystem::exists(pointLightIconPath));
|
|
|
|
|
EXPECT_TRUE(std::filesystem::exists(spotLightIconPath));
|
2026-04-03 15:43:21 +08:00
|
|
|
EXPECT_NE(gridPath.generic_string().find("editor/resources/shaders/scene-viewport"), std::string::npos);
|
2026-04-04 17:10:15 +08:00
|
|
|
EXPECT_NE(cameraIconPath.generic_string().find("editor/resources/Icons"), std::string::npos);
|
2026-04-08 16:09:15 +08:00
|
|
|
EXPECT_NE(directionalLightIconPath.generic_string().find("editor/resources/Icons"), std::string::npos);
|
|
|
|
|
EXPECT_NE(pointLightIconPath.generic_string().find("editor/resources/Icons"), std::string::npos);
|
|
|
|
|
EXPECT_NE(spotLightIconPath.generic_string().find("editor/resources/Icons"), std::string::npos);
|
|
|
|
|
EXPECT_EQ(directionalLightIconPath.filename().generic_string(), "directional_light_gizmo.png");
|
|
|
|
|
EXPECT_EQ(pointLightIconPath.filename().generic_string(), "point_light_gizmo.png");
|
|
|
|
|
EXPECT_EQ(spotLightIconPath.filename().generic_string(), "spot_light_gizmo.png");
|
2026-04-03 15:43:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SceneViewportShaderPathsTest, ShaderLoaderLoadsSceneViewportInfiniteGridShader) {
|
|
|
|
|
ShaderLoader loader;
|
|
|
|
|
const auto shaderPath = GetSceneViewportInfiniteGridShaderPath();
|
|
|
|
|
EXPECT_TRUE(loader.CanLoad(shaderPath));
|
|
|
|
|
|
|
|
|
|
LoadResult result = loader.Load(shaderPath);
|
|
|
|
|
ASSERT_TRUE(result);
|
|
|
|
|
ASSERT_NE(result.resource, nullptr);
|
|
|
|
|
|
|
|
|
|
auto* shader = static_cast<Shader*>(result.resource);
|
|
|
|
|
ASSERT_NE(shader, nullptr);
|
|
|
|
|
ASSERT_TRUE(shader->IsValid());
|
|
|
|
|
|
|
|
|
|
const ShaderPass* pass = shader->FindPass("InfiniteGrid");
|
|
|
|
|
ASSERT_NE(pass, nullptr);
|
|
|
|
|
ASSERT_EQ(pass->variants.Size(), 2u);
|
|
|
|
|
ASSERT_EQ(pass->tags.Size(), 1u);
|
|
|
|
|
EXPECT_EQ(pass->tags[0].name, "LightMode");
|
|
|
|
|
EXPECT_EQ(pass->tags[0].value, "InfiniteGrid");
|
|
|
|
|
|
|
|
|
|
const ShaderStageVariant* fragment = shader->FindVariant(
|
|
|
|
|
"InfiniteGrid",
|
|
|
|
|
ShaderType::Fragment,
|
|
|
|
|
ShaderBackend::D3D12);
|
|
|
|
|
ASSERT_NE(fragment, nullptr);
|
|
|
|
|
EXPECT_NE(
|
|
|
|
|
std::string(fragment->sourceCode.CStr()).find("XC_EDITOR_SCENE_VIEW_INFINITE_GRID_D3D12_PS"),
|
|
|
|
|
std::string::npos);
|
|
|
|
|
|
|
|
|
|
delete shader;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(SceneViewportShaderPathsTest, ResourceManagerLoadsSceneViewportOutlineShaderByResolvedPath) {
|
|
|
|
|
ResourceManager& manager = ResourceManager::Get();
|
|
|
|
|
manager.Shutdown();
|
|
|
|
|
|
2026-04-08 16:09:15 +08:00
|
|
|
const ResourceHandle<Shader> shaderHandle = manager.Load<Shader>(GetBuiltinObjectIdOutlineShaderPath());
|
2026-04-03 15:43:21 +08:00
|
|
|
ASSERT_TRUE(shaderHandle.IsValid());
|
|
|
|
|
|
|
|
|
|
const ShaderPass* pass = shaderHandle->FindPass("ObjectIdOutline");
|
|
|
|
|
ASSERT_NE(pass, nullptr);
|
|
|
|
|
ASSERT_EQ(pass->variants.Size(), 2u);
|
|
|
|
|
|
|
|
|
|
const ShaderStageVariant* fragment = shaderHandle->FindVariant(
|
|
|
|
|
"ObjectIdOutline",
|
|
|
|
|
ShaderType::Fragment,
|
|
|
|
|
ShaderBackend::D3D12);
|
|
|
|
|
ASSERT_NE(fragment, nullptr);
|
|
|
|
|
EXPECT_NE(
|
2026-04-08 16:09:15 +08:00
|
|
|
std::string(fragment->sourceCode.CStr()).find("XC_BUILTIN_OBJECT_ID_OUTLINE_D3D12_PS"),
|
2026-04-03 15:43:21 +08:00
|
|
|
std::string::npos);
|
|
|
|
|
|
|
|
|
|
manager.Shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 05:16:04 +08:00
|
|
|
TEST(SceneViewportShaderPathsTest, ResourceManagerLoadsSelectionOutlineShadersByResolvedPath) {
|
|
|
|
|
ResourceManager& manager = ResourceManager::Get();
|
|
|
|
|
manager.Shutdown();
|
|
|
|
|
|
|
|
|
|
const ResourceHandle<Shader> maskShaderHandle = manager.Load<Shader>(GetBuiltinSelectionMaskShaderPath());
|
|
|
|
|
ASSERT_TRUE(maskShaderHandle.IsValid());
|
|
|
|
|
|
|
|
|
|
const ShaderPass* maskPass = maskShaderHandle->FindPass("SelectionMask");
|
|
|
|
|
ASSERT_NE(maskPass, nullptr);
|
|
|
|
|
ASSERT_EQ(maskPass->variants.Size(), 4u);
|
|
|
|
|
ASSERT_EQ(maskPass->keywordDeclarations.Size(), 1u);
|
|
|
|
|
EXPECT_EQ(maskPass->keywordDeclarations[0].type, ShaderKeywordDeclarationType::ShaderFeatureLocal);
|
|
|
|
|
ASSERT_EQ(maskPass->keywordDeclarations[0].options.Size(), 2u);
|
|
|
|
|
EXPECT_EQ(maskPass->keywordDeclarations[0].options[0], "_");
|
|
|
|
|
EXPECT_EQ(maskPass->keywordDeclarations[0].options[1], "XC_ALPHA_TEST");
|
|
|
|
|
EXPECT_TRUE(maskShaderHandle->PassDeclaresKeyword("SelectionMask", "XC_ALPHA_TEST"));
|
|
|
|
|
|
|
|
|
|
const ShaderStageVariant* maskFragment = maskShaderHandle->FindVariant(
|
|
|
|
|
"SelectionMask",
|
|
|
|
|
ShaderType::Fragment,
|
|
|
|
|
ShaderBackend::D3D12);
|
|
|
|
|
ASSERT_NE(maskFragment, nullptr);
|
|
|
|
|
EXPECT_NE(
|
|
|
|
|
std::string(maskFragment->sourceCode.CStr()).find("XC_BUILTIN_SELECTION_MASK_D3D12_PS"),
|
|
|
|
|
std::string::npos);
|
|
|
|
|
|
|
|
|
|
ShaderKeywordSet alphaKeywords = {};
|
|
|
|
|
alphaKeywords.enabledKeywords.PushBack("XC_ALPHA_TEST");
|
|
|
|
|
const ShaderStageVariant* alphaMaskFragment = maskShaderHandle->FindVariant(
|
|
|
|
|
"SelectionMask",
|
|
|
|
|
ShaderType::Fragment,
|
|
|
|
|
ShaderBackend::D3D12,
|
|
|
|
|
alphaKeywords);
|
|
|
|
|
ASSERT_NE(alphaMaskFragment, nullptr);
|
|
|
|
|
EXPECT_NE(
|
|
|
|
|
std::string(alphaMaskFragment->sourceCode.CStr()).find("#define XC_ALPHA_TEST 1"),
|
|
|
|
|
std::string::npos);
|
|
|
|
|
|
|
|
|
|
const ResourceHandle<Shader> outlineShaderHandle = manager.Load<Shader>(GetBuiltinSelectionOutlineShaderPath());
|
|
|
|
|
ASSERT_TRUE(outlineShaderHandle.IsValid());
|
|
|
|
|
|
|
|
|
|
const ShaderPass* outlinePass = outlineShaderHandle->FindPass("SelectionOutline");
|
|
|
|
|
ASSERT_NE(outlinePass, nullptr);
|
|
|
|
|
ASSERT_EQ(outlinePass->variants.Size(), 2u);
|
|
|
|
|
|
|
|
|
|
const ShaderStageVariant* outlineFragment = outlineShaderHandle->FindVariant(
|
|
|
|
|
"SelectionOutline",
|
|
|
|
|
ShaderType::Fragment,
|
|
|
|
|
ShaderBackend::D3D12);
|
|
|
|
|
ASSERT_NE(outlineFragment, nullptr);
|
|
|
|
|
EXPECT_NE(
|
|
|
|
|
std::string(outlineFragment->sourceCode.CStr()).find("XC_BUILTIN_SELECTION_OUTLINE_D3D12_PS"),
|
|
|
|
|
std::string::npos);
|
|
|
|
|
|
|
|
|
|
manager.Shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-03 15:43:21 +08:00
|
|
|
} // namespace
|