Formalize scene viewport overlay sprite resource lifecycle
This commit is contained in:
@@ -89,6 +89,7 @@ add_executable(${PROJECT_NAME} WIN32
|
|||||||
src/Viewport/SceneViewportTransformGizmoCoordinator.cpp
|
src/Viewport/SceneViewportTransformGizmoCoordinator.cpp
|
||||||
src/Viewport/SceneViewportOrientationGizmo.cpp
|
src/Viewport/SceneViewportOrientationGizmo.cpp
|
||||||
src/Viewport/SceneViewportOverlayBuilder.cpp
|
src/Viewport/SceneViewportOverlayBuilder.cpp
|
||||||
|
src/Viewport/SceneViewportOverlaySpriteResources.cpp
|
||||||
src/Viewport/SceneViewportOverlayProviders.cpp
|
src/Viewport/SceneViewportOverlayProviders.cpp
|
||||||
src/Viewport/Passes/SceneViewportEditorOverlayPass.cpp
|
src/Viewport/Passes/SceneViewportEditorOverlayPass.cpp
|
||||||
src/Viewport/Passes/SceneViewportGridPass.cpp
|
src/Viewport/Passes/SceneViewportGridPass.cpp
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "Passes/SceneViewportEditorOverlayPass.h"
|
#include "Passes/SceneViewportEditorOverlayPass.h"
|
||||||
|
|
||||||
#include "Viewport/SceneViewportMath.h"
|
#include "Viewport/SceneViewportMath.h"
|
||||||
#include "Viewport/SceneViewportResourcePaths.h"
|
|
||||||
|
|
||||||
#include <XCEngine/RHI/RHIBuffer.h>
|
#include <XCEngine/RHI/RHIBuffer.h>
|
||||||
#include <XCEngine/RHI/RHICommandList.h>
|
#include <XCEngine/RHI/RHICommandList.h>
|
||||||
@@ -18,18 +17,13 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <filesystem>
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <stb_image.h>
|
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr size_t kOverlaySpriteTextureCount = 2u;
|
|
||||||
constexpr uint64_t kMinDynamicVertexBufferBytes = 4096u;
|
constexpr uint64_t kMinDynamicVertexBufferBytes = 4096u;
|
||||||
|
|
||||||
const char kSceneViewportEditorOverlayLineHlsl[] = R"(
|
const char kSceneViewportEditorOverlayLineHlsl[] = R"(
|
||||||
@@ -191,78 +185,6 @@ private:
|
|||||||
SceneViewportOverlayFrameData m_frameData = {};
|
SceneViewportOverlayFrameData m_frameData = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t ToSpriteTextureIndex(SceneViewportOverlaySpriteTextureKind textureKind) {
|
|
||||||
switch (textureKind) {
|
|
||||||
case SceneViewportOverlaySpriteTextureKind::Camera:
|
|
||||||
return 0u;
|
|
||||||
case SceneViewportOverlaySpriteTextureKind::Light:
|
|
||||||
return 1u;
|
|
||||||
default:
|
|
||||||
return 0u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::filesystem::path ResolveOverlaySpriteTexturePath(SceneViewportOverlaySpriteTextureKind textureKind) {
|
|
||||||
switch (textureKind) {
|
|
||||||
case SceneViewportOverlaySpriteTextureKind::Camera:
|
|
||||||
return std::filesystem::path(GetSceneViewportCameraGizmoIconPath().CStr());
|
|
||||||
case SceneViewportOverlaySpriteTextureKind::Light:
|
|
||||||
return std::filesystem::path(GetSceneViewportMainLightGizmoIconPath().CStr());
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::filesystem::path();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReadFileBytes(const std::filesystem::path& filePath, std::vector<stbi_uc>& outBytes) {
|
|
||||||
std::ifstream input(filePath, std::ios::binary | std::ios::ate);
|
|
||||||
if (!input.is_open()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::ifstream::pos_type size = input.tellg();
|
|
||||||
if (size <= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
outBytes.resize(static_cast<size_t>(size));
|
|
||||||
input.seekg(0, std::ios::beg);
|
|
||||||
return input.read(reinterpret_cast<char*>(outBytes.data()), size).good();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DecodeTextureFile(
|
|
||||||
const std::filesystem::path& filePath,
|
|
||||||
std::vector<stbi_uc>& outPixels,
|
|
||||||
int& outWidth,
|
|
||||||
int& outHeight) {
|
|
||||||
std::vector<stbi_uc> fileData = {};
|
|
||||||
if (!ReadFileBytes(filePath, fileData)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int channels = 0;
|
|
||||||
stbi_uc* pixels = stbi_load_from_memory(
|
|
||||||
fileData.data(),
|
|
||||||
static_cast<int>(fileData.size()),
|
|
||||||
&outWidth,
|
|
||||||
&outHeight,
|
|
||||||
&channels,
|
|
||||||
STBI_rgb_alpha);
|
|
||||||
if (pixels == nullptr || outWidth <= 0 || outHeight <= 0) {
|
|
||||||
if (pixels != nullptr) {
|
|
||||||
stbi_image_free(pixels);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
outPixels.assign(
|
|
||||||
pixels,
|
|
||||||
pixels + static_cast<size_t>(outWidth) * static_cast<size_t>(outHeight) * 4u);
|
|
||||||
stbi_image_free(pixels);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RHI::GraphicsPipelineDesc BuildLinePipelineDesc(
|
RHI::GraphicsPipelineDesc BuildLinePipelineDesc(
|
||||||
RHI::RHIPipelineLayout* pipelineLayout,
|
RHI::RHIPipelineLayout* pipelineLayout,
|
||||||
bool depthTestEnabled) {
|
bool depthTestEnabled) {
|
||||||
@@ -550,19 +472,20 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<OverlaySpriteVertex> spriteVertices = {};
|
std::vector<OverlaySpriteVertex> spriteVertices = {};
|
||||||
std::array<OverlaySpriteBatchRange, kOverlaySpriteTextureCount> depthTestedSpriteBatches = {};
|
std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount> depthTestedSpriteBatches = {};
|
||||||
std::array<OverlaySpriteBatchRange, kOverlaySpriteTextureCount> alwaysOnTopSpriteBatches = {};
|
std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount> alwaysOnTopSpriteBatches = {};
|
||||||
if (spriteVertexCount > 0u) {
|
if (spriteVertexCount > 0u) {
|
||||||
spriteVertices.reserve(spriteVertexCount);
|
spriteVertices.reserve(spriteVertexCount);
|
||||||
const auto appendSpriteBatches =
|
const auto appendSpriteBatches =
|
||||||
[&spriteVertices](
|
[&spriteVertices](
|
||||||
const std::vector<const SceneViewportOverlaySpritePrimitive*>& sprites,
|
const std::vector<const SceneViewportOverlaySpritePrimitive*>& sprites,
|
||||||
std::array<OverlaySpriteBatchRange, kOverlaySpriteTextureCount>& outBatches) {
|
std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount>& outBatches) {
|
||||||
for (size_t textureIndex = 0; textureIndex < kOverlaySpriteTextureCount; ++textureIndex) {
|
for (size_t textureIndex = 0; textureIndex < kSceneViewportOverlaySpriteResourceCount; ++textureIndex) {
|
||||||
OverlaySpriteBatchRange range = {};
|
OverlaySpriteBatchRange range = {};
|
||||||
range.firstVertex = static_cast<uint32_t>(spriteVertices.size());
|
range.firstVertex = static_cast<uint32_t>(spriteVertices.size());
|
||||||
for (const SceneViewportOverlaySpritePrimitive* sprite : sprites) {
|
for (const SceneViewportOverlaySpritePrimitive* sprite : sprites) {
|
||||||
if (sprite == nullptr || ToSpriteTextureIndex(sprite->textureKind) != textureIndex) {
|
if (sprite == nullptr ||
|
||||||
|
GetSceneViewportOverlaySpriteResourceIndex(sprite->textureKind) != textureIndex) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -651,21 +574,28 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
|
|||||||
const auto drawSpriteBatchGroup =
|
const auto drawSpriteBatchGroup =
|
||||||
[this, commandList](
|
[this, commandList](
|
||||||
RHI::RHIPipelineState* pipelineState,
|
RHI::RHIPipelineState* pipelineState,
|
||||||
const std::array<OverlaySpriteBatchRange, kOverlaySpriteTextureCount>& batches) {
|
const std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount>& batches) {
|
||||||
if (pipelineState == nullptr) {
|
if (pipelineState == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
commandList->SetPipelineState(pipelineState);
|
commandList->SetPipelineState(pipelineState);
|
||||||
for (size_t textureIndex = 0; textureIndex < kOverlaySpriteTextureCount; ++textureIndex) {
|
for (size_t textureIndex = 0; textureIndex < kSceneViewportOverlaySpriteResourceCount; ++textureIndex) {
|
||||||
const OverlaySpriteBatchRange& batch = batches[textureIndex];
|
const OverlaySpriteBatchRange& batch = batches[textureIndex];
|
||||||
if (!batch.HasVertices()) {
|
if (!batch.HasVertices()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RHI::RHIDescriptorSet* const textureSet =
|
||||||
|
m_overlaySpriteResources.GetTextureSet(
|
||||||
|
GetSceneViewportOverlaySpriteTextureKindByIndex(textureIndex));
|
||||||
|
if (textureSet == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
RHI::RHIDescriptorSet* descriptorSets[] = {
|
RHI::RHIDescriptorSet* descriptorSets[] = {
|
||||||
m_constantSet,
|
m_constantSet,
|
||||||
m_overlaySpriteTextures[textureIndex].textureSet,
|
textureSet,
|
||||||
m_samplerSet
|
m_samplerSet
|
||||||
};
|
};
|
||||||
commandList->SetGraphicsDescriptorSets(0, 3, descriptorSets, m_spritePipelineLayout);
|
commandList->SetGraphicsDescriptorSets(0, 3, descriptorSets, m_spritePipelineLayout);
|
||||||
@@ -814,7 +744,7 @@ bool SceneViewportEditorOverlayPassRenderer::CreateResources(
|
|||||||
|
|
||||||
RHI::DescriptorPoolDesc texturePoolDesc = {};
|
RHI::DescriptorPoolDesc texturePoolDesc = {};
|
||||||
texturePoolDesc.type = RHI::DescriptorHeapType::CBV_SRV_UAV;
|
texturePoolDesc.type = RHI::DescriptorHeapType::CBV_SRV_UAV;
|
||||||
texturePoolDesc.descriptorCount = static_cast<uint32_t>(kOverlaySpriteTextureCount);
|
texturePoolDesc.descriptorCount = static_cast<uint32_t>(kSceneViewportOverlaySpriteResourceCount);
|
||||||
texturePoolDesc.shaderVisible = true;
|
texturePoolDesc.shaderVisible = true;
|
||||||
m_texturePool = m_device->CreateDescriptorPool(texturePoolDesc);
|
m_texturePool = m_device->CreateDescriptorPool(texturePoolDesc);
|
||||||
if (m_texturePool == nullptr) {
|
if (m_texturePool == nullptr) {
|
||||||
@@ -1037,73 +967,7 @@ bool SceneViewportEditorOverlayPassRenderer::EnsureSpriteBufferCapacity(size_t r
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SceneViewportEditorOverlayPassRenderer::EnsureIconTexturesLoaded() {
|
bool SceneViewportEditorOverlayPassRenderer::EnsureIconTexturesLoaded() {
|
||||||
if (m_device == nullptr || m_texturePool == nullptr) {
|
return m_overlaySpriteResources.EnsureResources(m_device, m_texturePool);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RHI::DescriptorSetLayoutBinding textureBinding = {};
|
|
||||||
textureBinding.binding = 0;
|
|
||||||
textureBinding.type = static_cast<uint32_t>(RHI::DescriptorType::SRV);
|
|
||||||
textureBinding.count = 1;
|
|
||||||
RHI::DescriptorSetLayoutDesc textureLayout = {};
|
|
||||||
textureLayout.bindings = &textureBinding;
|
|
||||||
textureLayout.bindingCount = 1;
|
|
||||||
|
|
||||||
for (size_t textureIndex = 0; textureIndex < kOverlaySpriteTextureCount; ++textureIndex) {
|
|
||||||
OverlaySpriteTextureResources& resources = m_overlaySpriteTextures[textureIndex];
|
|
||||||
if (resources.texture != nullptr && resources.shaderView != nullptr && resources.textureSet != nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SceneViewportOverlaySpriteTextureKind textureKind =
|
|
||||||
textureIndex == 0u
|
|
||||||
? SceneViewportOverlaySpriteTextureKind::Camera
|
|
||||||
: SceneViewportOverlaySpriteTextureKind::Light;
|
|
||||||
|
|
||||||
std::vector<stbi_uc> pixels = {};
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
if (!DecodeTextureFile(ResolveOverlaySpriteTexturePath(textureKind), pixels, width, height)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RHI::TextureDesc textureDesc = {};
|
|
||||||
textureDesc.width = static_cast<uint32_t>(width);
|
|
||||||
textureDesc.height = static_cast<uint32_t>(height);
|
|
||||||
textureDesc.depth = 1;
|
|
||||||
textureDesc.mipLevels = 1;
|
|
||||||
textureDesc.arraySize = 1;
|
|
||||||
textureDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
|
|
||||||
textureDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
|
|
||||||
textureDesc.sampleCount = 1;
|
|
||||||
textureDesc.sampleQuality = 0;
|
|
||||||
textureDesc.flags = 0;
|
|
||||||
resources.texture = m_device->CreateTexture(
|
|
||||||
textureDesc,
|
|
||||||
pixels.data(),
|
|
||||||
pixels.size(),
|
|
||||||
static_cast<uint32_t>(width * 4));
|
|
||||||
if (resources.texture == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RHI::ResourceViewDesc viewDesc = {};
|
|
||||||
viewDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
|
|
||||||
viewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
|
|
||||||
viewDesc.mipLevel = 0;
|
|
||||||
resources.shaderView = m_device->CreateShaderResourceView(resources.texture, viewDesc);
|
|
||||||
if (resources.shaderView == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
resources.textureSet = m_texturePool->AllocateSet(textureLayout);
|
|
||||||
if (resources.textureSet == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
resources.textureSet->Update(0, resources.shaderView);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneViewportEditorOverlayPassRenderer::DestroyResources() {
|
void SceneViewportEditorOverlayPassRenderer::DestroyResources() {
|
||||||
@@ -1138,23 +1002,7 @@ void SceneViewportEditorOverlayPassRenderer::DestroyResources() {
|
|||||||
m_spriteVertexBuffer = nullptr;
|
m_spriteVertexBuffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (OverlaySpriteTextureResources& resources : m_overlaySpriteTextures) {
|
m_overlaySpriteResources.Shutdown();
|
||||||
if (resources.textureSet != nullptr) {
|
|
||||||
resources.textureSet->Shutdown();
|
|
||||||
delete resources.textureSet;
|
|
||||||
resources.textureSet = nullptr;
|
|
||||||
}
|
|
||||||
if (resources.shaderView != nullptr) {
|
|
||||||
resources.shaderView->Shutdown();
|
|
||||||
delete resources.shaderView;
|
|
||||||
resources.shaderView = nullptr;
|
|
||||||
}
|
|
||||||
if (resources.texture != nullptr) {
|
|
||||||
resources.texture->Shutdown();
|
|
||||||
delete resources.texture;
|
|
||||||
resources.texture = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_depthTestedLinePipelineState != nullptr) {
|
if (m_depthTestedLinePipelineState != nullptr) {
|
||||||
m_depthTestedLinePipelineState->Shutdown();
|
m_depthTestedLinePipelineState->Shutdown();
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Viewport/SceneViewportEditorOverlayData.h"
|
#include "Viewport/SceneViewportEditorOverlayData.h"
|
||||||
|
#include "Viewport/SceneViewportOverlaySpriteResources.h"
|
||||||
|
|
||||||
#include <XCEngine/Rendering/RenderContext.h>
|
#include <XCEngine/Rendering/RenderContext.h>
|
||||||
#include <XCEngine/Rendering/RenderPass.h>
|
#include <XCEngine/Rendering/RenderPass.h>
|
||||||
#include <XCEngine/Rendering/RenderSurface.h>
|
#include <XCEngine/Rendering/RenderSurface.h>
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -39,12 +39,6 @@ public:
|
|||||||
const SceneViewportOverlayFrameData& frameData);
|
const SceneViewportOverlayFrameData& frameData);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct OverlaySpriteTextureResources {
|
|
||||||
RHI::RHITexture* texture = nullptr;
|
|
||||||
RHI::RHIResourceView* shaderView = nullptr;
|
|
||||||
RHI::RHIDescriptorSet* textureSet = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool EnsureInitialized(const Rendering::RenderContext& renderContext);
|
bool EnsureInitialized(const Rendering::RenderContext& renderContext);
|
||||||
bool CreateResources(const Rendering::RenderContext& renderContext);
|
bool CreateResources(const Rendering::RenderContext& renderContext);
|
||||||
bool EnsureLineBufferCapacity(size_t requiredVertexCount);
|
bool EnsureLineBufferCapacity(size_t requiredVertexCount);
|
||||||
@@ -78,7 +72,7 @@ private:
|
|||||||
uint64_t m_lineVertexBufferCapacity = 0;
|
uint64_t m_lineVertexBufferCapacity = 0;
|
||||||
uint64_t m_screenTriangleVertexBufferCapacity = 0;
|
uint64_t m_screenTriangleVertexBufferCapacity = 0;
|
||||||
uint64_t m_spriteVertexBufferCapacity = 0;
|
uint64_t m_spriteVertexBufferCapacity = 0;
|
||||||
std::array<OverlaySpriteTextureResources, 2> m_overlaySpriteTextures = {};
|
SceneViewportOverlaySpriteResourceCache m_overlaySpriteResources = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Rendering::RenderPass> CreateSceneViewportEditorOverlayPass(
|
std::unique_ptr<Rendering::RenderPass> CreateSceneViewportEditorOverlayPass(
|
||||||
|
|||||||
209
editor/src/Viewport/SceneViewportOverlaySpriteResources.cpp
Normal file
209
editor/src/Viewport/SceneViewportOverlaySpriteResources.cpp
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
#include "Viewport/SceneViewportOverlaySpriteResources.h"
|
||||||
|
|
||||||
|
#include <XCEngine/RHI/RHIDescriptorPool.h>
|
||||||
|
#include <XCEngine/RHI/RHIDescriptorSet.h>
|
||||||
|
#include <XCEngine/RHI/RHIDevice.h>
|
||||||
|
#include <XCEngine/RHI/RHIEnums.h>
|
||||||
|
#include <XCEngine/RHI/RHIResourceView.h>
|
||||||
|
#include <XCEngine/RHI/RHITexture.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <stb_image.h>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace Editor {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool ReadFileBytes(const std::filesystem::path& filePath, std::vector<stbi_uc>& outBytes) {
|
||||||
|
std::ifstream input(filePath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!input.is_open()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::ifstream::pos_type size = input.tellg();
|
||||||
|
if (size <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outBytes.resize(static_cast<size_t>(size));
|
||||||
|
input.seekg(0, std::ios::beg);
|
||||||
|
return input.read(reinterpret_cast<char*>(outBytes.data()), size).good();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecodeTextureFile(
|
||||||
|
const std::filesystem::path& filePath,
|
||||||
|
SceneViewportOverlaySpritePixels& outPixels) {
|
||||||
|
outPixels = {};
|
||||||
|
|
||||||
|
std::vector<stbi_uc> fileData = {};
|
||||||
|
if (!ReadFileBytes(filePath, fileData)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
int channels = 0;
|
||||||
|
stbi_uc* pixels = stbi_load_from_memory(
|
||||||
|
fileData.data(),
|
||||||
|
static_cast<int>(fileData.size()),
|
||||||
|
&width,
|
||||||
|
&height,
|
||||||
|
&channels,
|
||||||
|
STBI_rgb_alpha);
|
||||||
|
if (pixels == nullptr || width <= 0 || height <= 0) {
|
||||||
|
if (pixels != nullptr) {
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outPixels.width = static_cast<uint32_t>(width);
|
||||||
|
outPixels.height = static_cast<uint32_t>(height);
|
||||||
|
outPixels.rgbaPixels.assign(
|
||||||
|
pixels,
|
||||||
|
pixels + static_cast<size_t>(width) * static_cast<size_t>(height) * 4u);
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
return outPixels.IsValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::DescriptorSetLayoutDesc BuildSpriteTextureLayout() {
|
||||||
|
RHI::DescriptorSetLayoutBinding textureBinding = {};
|
||||||
|
textureBinding.binding = 0;
|
||||||
|
textureBinding.type = static_cast<uint32_t>(RHI::DescriptorType::SRV);
|
||||||
|
textureBinding.count = 1;
|
||||||
|
|
||||||
|
RHI::DescriptorSetLayoutDesc textureLayout = {};
|
||||||
|
textureLayout.bindings = &textureBinding;
|
||||||
|
textureLayout.bindingCount = 1;
|
||||||
|
return textureLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool LoadSceneViewportOverlaySpritePixels(
|
||||||
|
SceneViewportOverlaySpriteTextureKind textureKind,
|
||||||
|
SceneViewportOverlaySpritePixels& outPixels) {
|
||||||
|
const SceneViewportOverlaySpriteAssetSpec spec =
|
||||||
|
GetSceneViewportOverlaySpriteAssetSpec(textureKind);
|
||||||
|
if (spec.resourcePath.Empty()) {
|
||||||
|
outPixels = {};
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DecodeTextureFile(std::filesystem::path(spec.resourcePath.CStr()), outPixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneViewportOverlaySpriteResourceCache::Shutdown() {
|
||||||
|
for (ResourceEntry& entry : m_resources) {
|
||||||
|
DestroyResourceEntry(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = nullptr;
|
||||||
|
m_texturePool = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SceneViewportOverlaySpriteResourceCache::EnsureResources(
|
||||||
|
RHI::RHIDevice* device,
|
||||||
|
RHI::RHIDescriptorPool* texturePool) {
|
||||||
|
if (device == nullptr || texturePool == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_device != nullptr && m_device != device) ||
|
||||||
|
(m_texturePool != nullptr && m_texturePool != texturePool)) {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_device = device;
|
||||||
|
m_texturePool = texturePool;
|
||||||
|
const RHI::DescriptorSetLayoutDesc textureLayout = BuildSpriteTextureLayout();
|
||||||
|
|
||||||
|
for (size_t textureIndex = 0u;
|
||||||
|
textureIndex < kSceneViewportOverlaySpriteResourceCount;
|
||||||
|
++textureIndex) {
|
||||||
|
ResourceEntry& entry = m_resources[textureIndex];
|
||||||
|
if (entry.texture != nullptr &&
|
||||||
|
entry.shaderView != nullptr &&
|
||||||
|
entry.textureSet != nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SceneViewportOverlaySpriteTextureKind textureKind =
|
||||||
|
GetSceneViewportOverlaySpriteTextureKindByIndex(textureIndex);
|
||||||
|
SceneViewportOverlaySpritePixels pixels = {};
|
||||||
|
if (!LoadSceneViewportOverlaySpritePixels(textureKind, pixels)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::TextureDesc textureDesc = {};
|
||||||
|
textureDesc.width = pixels.width;
|
||||||
|
textureDesc.height = pixels.height;
|
||||||
|
textureDesc.depth = 1;
|
||||||
|
textureDesc.mipLevels = 1;
|
||||||
|
textureDesc.arraySize = 1;
|
||||||
|
textureDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
textureDesc.textureType = static_cast<uint32_t>(RHI::TextureType::Texture2D);
|
||||||
|
textureDesc.sampleCount = 1;
|
||||||
|
textureDesc.sampleQuality = 0;
|
||||||
|
textureDesc.flags = 0;
|
||||||
|
|
||||||
|
entry.texture = m_device->CreateTexture(
|
||||||
|
textureDesc,
|
||||||
|
pixels.rgbaPixels.data(),
|
||||||
|
pixels.rgbaPixels.size(),
|
||||||
|
pixels.width * 4u);
|
||||||
|
if (entry.texture == nullptr) {
|
||||||
|
DestroyResourceEntry(entry);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::ResourceViewDesc viewDesc = {};
|
||||||
|
viewDesc.format = static_cast<uint32_t>(RHI::Format::R8G8B8A8_UNorm);
|
||||||
|
viewDesc.dimension = RHI::ResourceViewDimension::Texture2D;
|
||||||
|
viewDesc.mipLevel = 0;
|
||||||
|
entry.shaderView = m_device->CreateShaderResourceView(entry.texture, viewDesc);
|
||||||
|
if (entry.shaderView == nullptr) {
|
||||||
|
DestroyResourceEntry(entry);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.textureSet = m_texturePool->AllocateSet(textureLayout);
|
||||||
|
if (entry.textureSet == nullptr) {
|
||||||
|
DestroyResourceEntry(entry);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entry.textureSet->Update(0, entry.shaderView);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHI::RHIDescriptorSet* SceneViewportOverlaySpriteResourceCache::GetTextureSet(
|
||||||
|
SceneViewportOverlaySpriteTextureKind textureKind) const {
|
||||||
|
return m_resources[GetSceneViewportOverlaySpriteResourceIndex(textureKind)].textureSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneViewportOverlaySpriteResourceCache::DestroyResourceEntry(ResourceEntry& entry) {
|
||||||
|
if (entry.textureSet != nullptr) {
|
||||||
|
entry.textureSet->Shutdown();
|
||||||
|
delete entry.textureSet;
|
||||||
|
entry.textureSet = nullptr;
|
||||||
|
}
|
||||||
|
if (entry.shaderView != nullptr) {
|
||||||
|
entry.shaderView->Shutdown();
|
||||||
|
delete entry.shaderView;
|
||||||
|
entry.shaderView = nullptr;
|
||||||
|
}
|
||||||
|
if (entry.texture != nullptr) {
|
||||||
|
entry.texture->Shutdown();
|
||||||
|
delete entry.texture;
|
||||||
|
entry.texture = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Editor
|
||||||
|
} // namespace XCEngine
|
||||||
126
editor/src/Viewport/SceneViewportOverlaySpriteResources.h
Normal file
126
editor/src/Viewport/SceneViewportOverlaySpriteResources.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SceneViewportEditorOverlayData.h"
|
||||||
|
#include "SceneViewportResourcePaths.h"
|
||||||
|
|
||||||
|
#include <XCEngine/Core/Containers/String.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace RHI {
|
||||||
|
class RHIDescriptorPool;
|
||||||
|
class RHIDescriptorSet;
|
||||||
|
class RHIDevice;
|
||||||
|
class RHIResourceView;
|
||||||
|
class RHITexture;
|
||||||
|
} // namespace RHI
|
||||||
|
|
||||||
|
namespace Editor {
|
||||||
|
|
||||||
|
inline constexpr std::array<SceneViewportOverlaySpriteTextureKind, 2> kSceneViewportOverlaySpriteTextureKinds = {
|
||||||
|
SceneViewportOverlaySpriteTextureKind::Camera,
|
||||||
|
SceneViewportOverlaySpriteTextureKind::Light
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr size_t kSceneViewportOverlaySpriteResourceCount =
|
||||||
|
kSceneViewportOverlaySpriteTextureKinds.size();
|
||||||
|
|
||||||
|
inline size_t GetSceneViewportOverlaySpriteResourceIndex(
|
||||||
|
SceneViewportOverlaySpriteTextureKind textureKind) {
|
||||||
|
switch (textureKind) {
|
||||||
|
case SceneViewportOverlaySpriteTextureKind::Camera:
|
||||||
|
return 0u;
|
||||||
|
case SceneViewportOverlaySpriteTextureKind::Light:
|
||||||
|
return 1u;
|
||||||
|
default:
|
||||||
|
return 0u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline SceneViewportOverlaySpriteTextureKind GetSceneViewportOverlaySpriteTextureKindByIndex(
|
||||||
|
size_t textureIndex) {
|
||||||
|
return textureIndex < kSceneViewportOverlaySpriteResourceCount
|
||||||
|
? kSceneViewportOverlaySpriteTextureKinds[textureIndex]
|
||||||
|
: kSceneViewportOverlaySpriteTextureKinds[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SceneViewportOverlaySpriteAssetSpec {
|
||||||
|
SceneViewportOverlaySpriteTextureKind kind = SceneViewportOverlaySpriteTextureKind::Camera;
|
||||||
|
Containers::String resourcePath = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
inline SceneViewportOverlaySpriteAssetSpec GetSceneViewportOverlaySpriteAssetSpec(
|
||||||
|
SceneViewportOverlaySpriteTextureKind textureKind) {
|
||||||
|
SceneViewportOverlaySpriteAssetSpec spec = {};
|
||||||
|
spec.kind = textureKind;
|
||||||
|
|
||||||
|
switch (textureKind) {
|
||||||
|
case SceneViewportOverlaySpriteTextureKind::Camera:
|
||||||
|
spec.resourcePath = GetSceneViewportCameraGizmoIconPath();
|
||||||
|
break;
|
||||||
|
case SceneViewportOverlaySpriteTextureKind::Light:
|
||||||
|
spec.resourcePath = GetSceneViewportMainLightGizmoIconPath();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SceneViewportOverlaySpritePixels {
|
||||||
|
std::vector<uint8_t> rgbaPixels = {};
|
||||||
|
uint32_t width = 0u;
|
||||||
|
uint32_t height = 0u;
|
||||||
|
|
||||||
|
bool IsValid() const {
|
||||||
|
const uint64_t expectedBytes =
|
||||||
|
static_cast<uint64_t>(width) *
|
||||||
|
static_cast<uint64_t>(height) *
|
||||||
|
4u;
|
||||||
|
return width > 0u &&
|
||||||
|
height > 0u &&
|
||||||
|
expectedBytes > 0u &&
|
||||||
|
expectedBytes <= static_cast<uint64_t>((std::numeric_limits<size_t>::max)()) &&
|
||||||
|
rgbaPixels.size() == static_cast<size_t>(expectedBytes);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool LoadSceneViewportOverlaySpritePixels(
|
||||||
|
SceneViewportOverlaySpriteTextureKind textureKind,
|
||||||
|
SceneViewportOverlaySpritePixels& outPixels);
|
||||||
|
|
||||||
|
class SceneViewportOverlaySpriteResourceCache {
|
||||||
|
public:
|
||||||
|
~SceneViewportOverlaySpriteResourceCache() = default;
|
||||||
|
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
bool EnsureResources(
|
||||||
|
RHI::RHIDevice* device,
|
||||||
|
RHI::RHIDescriptorPool* texturePool);
|
||||||
|
|
||||||
|
RHI::RHIDescriptorSet* GetTextureSet(
|
||||||
|
SceneViewportOverlaySpriteTextureKind textureKind) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ResourceEntry {
|
||||||
|
RHI::RHITexture* texture = nullptr;
|
||||||
|
RHI::RHIResourceView* shaderView = nullptr;
|
||||||
|
RHI::RHIDescriptorSet* textureSet = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
void DestroyResourceEntry(ResourceEntry& entry);
|
||||||
|
|
||||||
|
RHI::RHIDevice* m_device = nullptr;
|
||||||
|
RHI::RHIDescriptorPool* m_texturePool = nullptr;
|
||||||
|
std::array<ResourceEntry, kSceneViewportOverlaySpriteResourceCount> m_resources = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Editor
|
||||||
|
} // namespace XCEngine
|
||||||
@@ -36,6 +36,8 @@ private:
|
|||||||
bool m_playModeActive = false;
|
bool m_playModeActive = false;
|
||||||
bool m_playModePaused = false;
|
bool m_playModePaused = false;
|
||||||
bool m_requestSearchFocus = false;
|
bool m_requestSearchFocus = false;
|
||||||
|
bool m_requestedTabSelectionRecovery = false;
|
||||||
|
bool m_requestedLayoutResetForCollapsedContent = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ set(EDITOR_TEST_SOURCES
|
|||||||
test_scene_viewport_chrome.cpp
|
test_scene_viewport_chrome.cpp
|
||||||
test_scene_viewport_transform_gizmo_coordinator.cpp
|
test_scene_viewport_transform_gizmo_coordinator.cpp
|
||||||
test_scene_viewport_shader_paths.cpp
|
test_scene_viewport_shader_paths.cpp
|
||||||
|
test_scene_viewport_overlay_sprite_resources.cpp
|
||||||
test_scene_viewport_overlay_renderer.cpp
|
test_scene_viewport_overlay_renderer.cpp
|
||||||
test_scene_viewport_overlay_providers.cpp
|
test_scene_viewport_overlay_providers.cpp
|
||||||
test_script_component_editor_utils.cpp
|
test_script_component_editor_utils.cpp
|
||||||
@@ -49,6 +50,7 @@ set(EDITOR_TEST_SOURCES
|
|||||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportTransformGizmoCoordinator.cpp
|
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportTransformGizmoCoordinator.cpp
|
||||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOrientationGizmo.cpp
|
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOrientationGizmo.cpp
|
||||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOverlayBuilder.cpp
|
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOverlayBuilder.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOverlaySpriteResources.cpp
|
||||||
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOverlayProviders.cpp
|
${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOverlayProviders.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "Viewport/SceneViewportOverlaySpriteResources.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using XCEngine::Editor::GetSceneViewportOverlaySpriteAssetSpec;
|
||||||
|
using XCEngine::Editor::GetSceneViewportOverlaySpriteResourceIndex;
|
||||||
|
using XCEngine::Editor::GetSceneViewportOverlaySpriteTextureKindByIndex;
|
||||||
|
using XCEngine::Editor::LoadSceneViewportOverlaySpritePixels;
|
||||||
|
using XCEngine::Editor::SceneViewportOverlaySpritePixels;
|
||||||
|
using XCEngine::Editor::SceneViewportOverlaySpriteTextureKind;
|
||||||
|
using XCEngine::Editor::kSceneViewportOverlaySpriteResourceCount;
|
||||||
|
using XCEngine::Editor::kSceneViewportOverlaySpriteTextureKinds;
|
||||||
|
|
||||||
|
TEST(SceneViewportOverlaySpriteResourcesTest, TextureKindIndexMappingIsStable) {
|
||||||
|
EXPECT_EQ(kSceneViewportOverlaySpriteResourceCount, 2u);
|
||||||
|
EXPECT_EQ(GetSceneViewportOverlaySpriteResourceIndex(SceneViewportOverlaySpriteTextureKind::Camera), 0u);
|
||||||
|
EXPECT_EQ(GetSceneViewportOverlaySpriteResourceIndex(SceneViewportOverlaySpriteTextureKind::Light), 1u);
|
||||||
|
EXPECT_EQ(GetSceneViewportOverlaySpriteTextureKindByIndex(0u), SceneViewportOverlaySpriteTextureKind::Camera);
|
||||||
|
EXPECT_EQ(GetSceneViewportOverlaySpriteTextureKindByIndex(1u), SceneViewportOverlaySpriteTextureKind::Light);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SceneViewportOverlaySpriteResourcesTest, AssetSpecsResolveKnownEditorIcons) {
|
||||||
|
for (SceneViewportOverlaySpriteTextureKind textureKind : kSceneViewportOverlaySpriteTextureKinds) {
|
||||||
|
const auto spec = GetSceneViewportOverlaySpriteAssetSpec(textureKind);
|
||||||
|
EXPECT_EQ(spec.kind, textureKind);
|
||||||
|
EXPECT_FALSE(spec.resourcePath.Empty());
|
||||||
|
|
||||||
|
const std::filesystem::path path(spec.resourcePath.CStr());
|
||||||
|
EXPECT_TRUE(path.is_absolute());
|
||||||
|
EXPECT_TRUE(std::filesystem::exists(path));
|
||||||
|
EXPECT_NE(path.generic_string().find("editor/resources/Icons"), std::string::npos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SceneViewportOverlaySpriteResourcesTest, LoadsOverlaySpritePixelsFromEditorResources) {
|
||||||
|
for (SceneViewportOverlaySpriteTextureKind textureKind : kSceneViewportOverlaySpriteTextureKinds) {
|
||||||
|
SceneViewportOverlaySpritePixels pixels = {};
|
||||||
|
EXPECT_TRUE(LoadSceneViewportOverlaySpritePixels(textureKind, pixels));
|
||||||
|
EXPECT_TRUE(pixels.IsValid());
|
||||||
|
EXPECT_GT(pixels.width, 0u);
|
||||||
|
EXPECT_GT(pixels.height, 0u);
|
||||||
|
EXPECT_FALSE(pixels.rgbaPixels.empty());
|
||||||
|
EXPECT_EQ(
|
||||||
|
pixels.rgbaPixels.size(),
|
||||||
|
static_cast<size_t>(pixels.width) * static_cast<size_t>(pixels.height) * 4u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "Viewport/SceneViewportResourcePaths.h"
|
||||||
#include "Viewport/SceneViewportShaderPaths.h"
|
#include "Viewport/SceneViewportShaderPaths.h"
|
||||||
|
|
||||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||||
@@ -10,7 +11,9 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using XCEngine::Editor::GetSceneViewportCameraGizmoIconPath;
|
||||||
using XCEngine::Editor::GetSceneViewportInfiniteGridShaderPath;
|
using XCEngine::Editor::GetSceneViewportInfiniteGridShaderPath;
|
||||||
|
using XCEngine::Editor::GetSceneViewportMainLightGizmoIconPath;
|
||||||
using XCEngine::Editor::GetSceneViewportObjectIdOutlineShaderPath;
|
using XCEngine::Editor::GetSceneViewportObjectIdOutlineShaderPath;
|
||||||
using XCEngine::Resources::LoadResult;
|
using XCEngine::Resources::LoadResult;
|
||||||
using XCEngine::Resources::ResourceHandle;
|
using XCEngine::Resources::ResourceHandle;
|
||||||
@@ -25,13 +28,21 @@ using XCEngine::Resources::ShaderType;
|
|||||||
TEST(SceneViewportShaderPathsTest, ResolvePathsUnderEditorResources) {
|
TEST(SceneViewportShaderPathsTest, ResolvePathsUnderEditorResources) {
|
||||||
const std::filesystem::path gridPath(GetSceneViewportInfiniteGridShaderPath().CStr());
|
const std::filesystem::path gridPath(GetSceneViewportInfiniteGridShaderPath().CStr());
|
||||||
const std::filesystem::path outlinePath(GetSceneViewportObjectIdOutlineShaderPath().CStr());
|
const std::filesystem::path outlinePath(GetSceneViewportObjectIdOutlineShaderPath().CStr());
|
||||||
|
const std::filesystem::path cameraIconPath(GetSceneViewportCameraGizmoIconPath().CStr());
|
||||||
|
const std::filesystem::path lightIconPath(GetSceneViewportMainLightGizmoIconPath().CStr());
|
||||||
|
|
||||||
EXPECT_TRUE(gridPath.is_absolute());
|
EXPECT_TRUE(gridPath.is_absolute());
|
||||||
EXPECT_TRUE(outlinePath.is_absolute());
|
EXPECT_TRUE(outlinePath.is_absolute());
|
||||||
|
EXPECT_TRUE(cameraIconPath.is_absolute());
|
||||||
|
EXPECT_TRUE(lightIconPath.is_absolute());
|
||||||
EXPECT_TRUE(std::filesystem::exists(gridPath));
|
EXPECT_TRUE(std::filesystem::exists(gridPath));
|
||||||
EXPECT_TRUE(std::filesystem::exists(outlinePath));
|
EXPECT_TRUE(std::filesystem::exists(outlinePath));
|
||||||
|
EXPECT_TRUE(std::filesystem::exists(cameraIconPath));
|
||||||
|
EXPECT_TRUE(std::filesystem::exists(lightIconPath));
|
||||||
EXPECT_NE(gridPath.generic_string().find("editor/resources/shaders/scene-viewport"), std::string::npos);
|
EXPECT_NE(gridPath.generic_string().find("editor/resources/shaders/scene-viewport"), std::string::npos);
|
||||||
EXPECT_NE(outlinePath.generic_string().find("editor/resources/shaders/scene-viewport"), std::string::npos);
|
EXPECT_NE(outlinePath.generic_string().find("editor/resources/shaders/scene-viewport"), std::string::npos);
|
||||||
|
EXPECT_NE(cameraIconPath.generic_string().find("editor/resources/Icons"), std::string::npos);
|
||||||
|
EXPECT_NE(lightIconPath.generic_string().find("editor/resources/Icons"), std::string::npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SceneViewportShaderPathsTest, ShaderLoaderLoadsSceneViewportInfiniteGridShader) {
|
TEST(SceneViewportShaderPathsTest, ShaderLoaderLoadsSceneViewportInfiniteGridShader) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using XCEngine::Editor::ApplySceneViewportRenderRequestSetup;
|
|||||||
using XCEngine::Editor::ApplySceneViewportRenderPlan;
|
using XCEngine::Editor::ApplySceneViewportRenderPlan;
|
||||||
using XCEngine::Editor::ApplyViewportFailureStatus;
|
using XCEngine::Editor::ApplyViewportFailureStatus;
|
||||||
using XCEngine::Editor::BuildGameViewportRenderFailurePolicy;
|
using XCEngine::Editor::BuildGameViewportRenderFailurePolicy;
|
||||||
|
using XCEngine::Editor::BuildSceneViewportGridPassData;
|
||||||
using XCEngine::Editor::BuildSceneViewportRenderPlan;
|
using XCEngine::Editor::BuildSceneViewportRenderPlan;
|
||||||
using XCEngine::Editor::BuildSceneViewportRenderFailurePolicy;
|
using XCEngine::Editor::BuildSceneViewportRenderFailurePolicy;
|
||||||
using XCEngine::Editor::BuildSceneViewportSelectionOutlineStyle;
|
using XCEngine::Editor::BuildSceneViewportSelectionOutlineStyle;
|
||||||
@@ -24,7 +25,9 @@ using XCEngine::Editor::SceneViewportOverlayFrameData;
|
|||||||
using XCEngine::Editor::SceneViewportOverlayLinePrimitive;
|
using XCEngine::Editor::SceneViewportOverlayLinePrimitive;
|
||||||
using XCEngine::Editor::SceneViewportRenderFailure;
|
using XCEngine::Editor::SceneViewportRenderFailure;
|
||||||
using XCEngine::Editor::SceneViewportOverlayData;
|
using XCEngine::Editor::SceneViewportOverlayData;
|
||||||
|
using XCEngine::Editor::SceneViewportGridPassData;
|
||||||
using XCEngine::Editor::SceneViewportRenderPlan;
|
using XCEngine::Editor::SceneViewportRenderPlan;
|
||||||
|
using XCEngine::Editor::SceneViewportSelectionOutlineStyle;
|
||||||
using XCEngine::Editor::ViewportRenderTargets;
|
using XCEngine::Editor::ViewportRenderTargets;
|
||||||
using XCEngine::RHI::Format;
|
using XCEngine::RHI::Format;
|
||||||
using XCEngine::RHI::RHIResourceView;
|
using XCEngine::RHI::RHIResourceView;
|
||||||
@@ -163,7 +166,7 @@ TEST(ViewportRenderFlowUtilsTest, ApplyViewportFailureStatusRespectsSetIfEmptyBe
|
|||||||
|
|
||||||
TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportGridPassDataCopiesSceneCameraState) {
|
TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportGridPassDataCopiesSceneCameraState) {
|
||||||
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
const SceneViewportOverlayData overlay = CreateValidOverlay();
|
||||||
const auto gridPassData = XCEngine::Editor::BuildSceneViewportGridPassData(overlay);
|
const auto gridPassData = BuildSceneViewportGridPassData(overlay);
|
||||||
|
|
||||||
EXPECT_TRUE(gridPassData.valid);
|
EXPECT_TRUE(gridPassData.valid);
|
||||||
EXPECT_FLOAT_EQ(gridPassData.cameraPosition.x, overlay.cameraPosition.x);
|
EXPECT_FLOAT_EQ(gridPassData.cameraPosition.x, overlay.cameraPosition.x);
|
||||||
@@ -265,7 +268,7 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanCollectsPostSceneA
|
|||||||
overlay,
|
overlay,
|
||||||
{ 7u, 11u },
|
{ 7u, 11u },
|
||||||
editorOverlayFrameData,
|
editorOverlayFrameData,
|
||||||
[&gridPassFactoryCallCount](const XCEngine::Rendering::Passes::InfiniteGridPassData& data) {
|
[&gridPassFactoryCallCount](const SceneViewportGridPassData& data) {
|
||||||
++gridPassFactoryCallCount;
|
++gridPassFactoryCallCount;
|
||||||
EXPECT_TRUE(data.valid);
|
EXPECT_TRUE(data.valid);
|
||||||
return std::make_unique<NoopRenderPass>();
|
return std::make_unique<NoopRenderPass>();
|
||||||
@@ -273,7 +276,7 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanCollectsPostSceneA
|
|||||||
[&selectionOutlinePassFactoryCallCount](
|
[&selectionOutlinePassFactoryCallCount](
|
||||||
RHIResourceView* objectIdTextureView,
|
RHIResourceView* objectIdTextureView,
|
||||||
const std::vector<uint64_t>& selectedObjectIds,
|
const std::vector<uint64_t>& selectedObjectIds,
|
||||||
const XCEngine::Rendering::Passes::ObjectIdOutlineStyle& style) {
|
const SceneViewportSelectionOutlineStyle& style) {
|
||||||
++selectionOutlinePassFactoryCallCount;
|
++selectionOutlinePassFactoryCallCount;
|
||||||
EXPECT_NE(objectIdTextureView, nullptr);
|
EXPECT_NE(objectIdTextureView, nullptr);
|
||||||
EXPECT_EQ(selectedObjectIds.size(), 2u);
|
EXPECT_EQ(selectedObjectIds.size(), 2u);
|
||||||
@@ -304,13 +307,13 @@ TEST(ViewportRenderFlowUtilsTest, BuildSceneViewportRenderPlanWarnsWhenSelection
|
|||||||
overlay,
|
overlay,
|
||||||
{ 42u },
|
{ 42u },
|
||||||
{},
|
{},
|
||||||
[](const XCEngine::Rendering::Passes::InfiniteGridPassData&) {
|
[](const SceneViewportGridPassData&) {
|
||||||
return std::make_unique<NoopRenderPass>();
|
return std::make_unique<NoopRenderPass>();
|
||||||
},
|
},
|
||||||
[](
|
[](
|
||||||
RHIResourceView*,
|
RHIResourceView*,
|
||||||
const std::vector<uint64_t>&,
|
const std::vector<uint64_t>&,
|
||||||
const XCEngine::Rendering::Passes::ObjectIdOutlineStyle&) {
|
const SceneViewportSelectionOutlineStyle&) {
|
||||||
return std::make_unique<NoopRenderPass>();
|
return std::make_unique<NoopRenderPass>();
|
||||||
},
|
},
|
||||||
[](const SceneViewportOverlayFrameData&) {
|
[](const SceneViewportOverlayFrameData&) {
|
||||||
|
|||||||
Reference in New Issue
Block a user