Formalize editor skybox wiring and debug presets
This commit is contained in:
35
CMakePresets.json
Normal file
35
CMakePresets.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 21,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "vs2022-x64",
|
||||||
|
"displayName": "Visual Studio 2022 x64",
|
||||||
|
"generator": "Visual Studio 17 2022",
|
||||||
|
"binaryDir": "${sourceDir}/build"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buildPresets": [
|
||||||
|
{
|
||||||
|
"name": "debug",
|
||||||
|
"displayName": "Build Debug",
|
||||||
|
"configurePreset": "vs2022-x64",
|
||||||
|
"configuration": "Debug"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"testPresets": [
|
||||||
|
{
|
||||||
|
"name": "debug",
|
||||||
|
"displayName": "Test Debug",
|
||||||
|
"configurePreset": "vs2022-x64",
|
||||||
|
"configuration": "Debug",
|
||||||
|
"output": {
|
||||||
|
"outputOnFailure": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "AssetReferenceEditorUtils.h"
|
||||||
#include "IComponentEditor.h"
|
#include "IComponentEditor.h"
|
||||||
#include "Core/IUndoManager.h"
|
#include "Core/IUndoManager.h"
|
||||||
#include "UI/UI.h"
|
#include "UI/UI.h"
|
||||||
|
|
||||||
#include <XCEngine/Components/CameraComponent.h>
|
#include <XCEngine/Components/CameraComponent.h>
|
||||||
|
#include <XCEngine/Core/Math/Color.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
@@ -95,6 +99,87 @@ public:
|
|||||||
camera->SetPrimary(primary);
|
camera->SetPrimary(primary);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bool skyboxEnabled = camera->IsSkyboxEnabled();
|
||||||
|
changed |= UI::ApplyPropertyChange(
|
||||||
|
UI::DrawPropertyBool("Skybox", skyboxEnabled),
|
||||||
|
undoManager,
|
||||||
|
kUndoLabel,
|
||||||
|
[&]() {
|
||||||
|
camera->SetSkyboxEnabled(skyboxEnabled);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (skyboxEnabled) {
|
||||||
|
const ComponentEditorAssetUI::AssetReferenceInteraction skyboxMaterialInteraction =
|
||||||
|
ComponentEditorAssetUI::DrawAssetReferenceProperty(
|
||||||
|
"Skybox Material",
|
||||||
|
camera->GetSkyboxMaterialPath(),
|
||||||
|
"Drop Skybox Material",
|
||||||
|
{ ".mat" });
|
||||||
|
|
||||||
|
changed |= UI::ApplyPropertyChange(
|
||||||
|
skyboxMaterialInteraction.clearRequested && !camera->GetSkyboxMaterialPath().empty(),
|
||||||
|
undoManager,
|
||||||
|
kUndoLabel,
|
||||||
|
[camera]() {
|
||||||
|
camera->SetSkyboxMaterialPath(std::string());
|
||||||
|
});
|
||||||
|
changed |= UI::ApplyPropertyChange(
|
||||||
|
!skyboxMaterialInteraction.assignedPath.empty() &&
|
||||||
|
skyboxMaterialInteraction.assignedPath != camera->GetSkyboxMaterialPath(),
|
||||||
|
undoManager,
|
||||||
|
kUndoLabel,
|
||||||
|
[camera, assignedPath = skyboxMaterialInteraction.assignedPath]() {
|
||||||
|
camera->SetSkyboxMaterialPath(assignedPath);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (camera->GetSkyboxMaterialPath().empty()) {
|
||||||
|
float topColor[4] = {
|
||||||
|
camera->GetSkyboxTopColor().r,
|
||||||
|
camera->GetSkyboxTopColor().g,
|
||||||
|
camera->GetSkyboxTopColor().b,
|
||||||
|
camera->GetSkyboxTopColor().a
|
||||||
|
};
|
||||||
|
changed |= UI::ApplyPropertyChange(
|
||||||
|
UI::DrawPropertyColor4("Skybox Top", topColor),
|
||||||
|
undoManager,
|
||||||
|
kUndoLabel,
|
||||||
|
[&]() {
|
||||||
|
camera->SetSkyboxTopColor(::XCEngine::Math::Color(
|
||||||
|
topColor[0], topColor[1], topColor[2], topColor[3]));
|
||||||
|
});
|
||||||
|
|
||||||
|
float horizonColor[4] = {
|
||||||
|
camera->GetSkyboxHorizonColor().r,
|
||||||
|
camera->GetSkyboxHorizonColor().g,
|
||||||
|
camera->GetSkyboxHorizonColor().b,
|
||||||
|
camera->GetSkyboxHorizonColor().a
|
||||||
|
};
|
||||||
|
changed |= UI::ApplyPropertyChange(
|
||||||
|
UI::DrawPropertyColor4("Skybox Horizon", horizonColor),
|
||||||
|
undoManager,
|
||||||
|
kUndoLabel,
|
||||||
|
[&]() {
|
||||||
|
camera->SetSkyboxHorizonColor(::XCEngine::Math::Color(
|
||||||
|
horizonColor[0], horizonColor[1], horizonColor[2], horizonColor[3]));
|
||||||
|
});
|
||||||
|
|
||||||
|
float bottomColor[4] = {
|
||||||
|
camera->GetSkyboxBottomColor().r,
|
||||||
|
camera->GetSkyboxBottomColor().g,
|
||||||
|
camera->GetSkyboxBottomColor().b,
|
||||||
|
camera->GetSkyboxBottomColor().a
|
||||||
|
};
|
||||||
|
changed |= UI::ApplyPropertyChange(
|
||||||
|
UI::DrawPropertyColor4("Skybox Bottom", bottomColor),
|
||||||
|
undoManager,
|
||||||
|
kUndoLabel,
|
||||||
|
[&]() {
|
||||||
|
camera->SetSkyboxBottomColor(::XCEngine::Math::Color(
|
||||||
|
bottomColor[0], bottomColor[1], bottomColor[2], bottomColor[3]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float clearColor[4] = {
|
float clearColor[4] = {
|
||||||
camera->GetClearColor().r,
|
camera->GetClearColor().r,
|
||||||
camera->GetClearColor().g,
|
camera->GetClearColor().g,
|
||||||
|
|||||||
@@ -471,7 +471,9 @@ void SceneManager::CreateDemoScene() {
|
|||||||
ClearSceneLoadProgress();
|
ClearSceneLoadProgress();
|
||||||
|
|
||||||
::XCEngine::Components::GameObject* camera = CreateEntity("Main Camera", nullptr);
|
::XCEngine::Components::GameObject* camera = CreateEntity("Main Camera", nullptr);
|
||||||
camera->AddComponent<::XCEngine::Components::CameraComponent>();
|
if (auto* cameraComponent = camera->AddComponent<::XCEngine::Components::CameraComponent>()) {
|
||||||
|
cameraComponent->SetSkyboxEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
::XCEngine::Components::GameObject* light = CreateEntity("Directional Light", nullptr);
|
::XCEngine::Components::GameObject* light = CreateEntity("Directional Light", nullptr);
|
||||||
light->AddComponent<::XCEngine::Components::LightComponent>();
|
light->AddComponent<::XCEngine::Components::LightComponent>();
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ struct BuiltInIconState {
|
|||||||
BuiltInTexture folder;
|
BuiltInTexture folder;
|
||||||
BuiltInTexture gameObject;
|
BuiltInTexture gameObject;
|
||||||
BuiltInTexture scene;
|
BuiltInTexture scene;
|
||||||
|
BuiltInTexture cameraGizmo;
|
||||||
|
BuiltInTexture mainLightGizmo;
|
||||||
struct CachedAssetPreview {
|
struct CachedAssetPreview {
|
||||||
BuiltInTexture texture;
|
BuiltInTexture texture;
|
||||||
std::unique_ptr<LoadedTexturePixels> decodedPixels;
|
std::unique_ptr<LoadedTexturePixels> decodedPixels;
|
||||||
@@ -150,6 +152,16 @@ std::filesystem::path ResolveSceneIconPath() {
|
|||||||
return (exeDir / ".." / ".." / "resources" / "Icons" / "scene_icon.png").lexically_normal();
|
return (exeDir / ".." / ".." / "resources" / "Icons" / "scene_icon.png").lexically_normal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path ResolveCameraGizmoIconPath() {
|
||||||
|
const std::filesystem::path exeDir(Platform::GetExecutableDirectoryUtf8());
|
||||||
|
return (exeDir / ".." / ".." / "resources" / "Icons" / "camera_gizmo.png").lexically_normal();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path ResolveMainLightGizmoIconPath() {
|
||||||
|
const std::filesystem::path exeDir(Platform::GetExecutableDirectoryUtf8());
|
||||||
|
return (exeDir / ".." / ".." / "resources" / "Icons" / "main_light_gizmo.png").lexically_normal();
|
||||||
|
}
|
||||||
|
|
||||||
std::string NormalizePathKey(const std::filesystem::path& path) {
|
std::string NormalizePathKey(const std::filesystem::path& path) {
|
||||||
std::wstring key = path.lexically_normal().generic_wstring();
|
std::wstring key = path.lexically_normal().generic_wstring();
|
||||||
std::transform(key.begin(), key.end(), key.begin(), ::towlower);
|
std::transform(key.begin(), key.end(), key.begin(), ::towlower);
|
||||||
@@ -959,6 +971,17 @@ void PruneAssetPreviewCache() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BuiltInTexture* ResolveEditorTexture(EditorTextureIconKind kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case EditorTextureIconKind::CameraGizmo:
|
||||||
|
return &g_icons.cameraGizmo;
|
||||||
|
case EditorTextureIconKind::MainLightGizmo:
|
||||||
|
return &g_icons.mainLightGizmo;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void InitializeBuiltInIcons(
|
void InitializeBuiltInIcons(
|
||||||
@@ -985,6 +1008,28 @@ void InitializeBuiltInIcons(
|
|||||||
if (LoadTextureFromFile(backend, device, commandQueue, ResolveSceneIconPath(), g_icons.scene, pendingUpload)) {
|
if (LoadTextureFromFile(backend, device, commandQueue, ResolveSceneIconPath(), g_icons.scene, pendingUpload)) {
|
||||||
g_icons.pendingIconUploads.push_back(std::move(pendingUpload));
|
g_icons.pendingIconUploads.push_back(std::move(pendingUpload));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pendingUpload.reset();
|
||||||
|
if (LoadTextureFromFile(
|
||||||
|
backend,
|
||||||
|
device,
|
||||||
|
commandQueue,
|
||||||
|
ResolveCameraGizmoIconPath(),
|
||||||
|
g_icons.cameraGizmo,
|
||||||
|
pendingUpload)) {
|
||||||
|
g_icons.pendingIconUploads.push_back(std::move(pendingUpload));
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingUpload.reset();
|
||||||
|
if (LoadTextureFromFile(
|
||||||
|
backend,
|
||||||
|
device,
|
||||||
|
commandQueue,
|
||||||
|
ResolveMainLightGizmoIconPath(),
|
||||||
|
g_icons.mainLightGizmo,
|
||||||
|
pendingUpload)) {
|
||||||
|
g_icons.pendingIconUploads.push_back(std::move(pendingUpload));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShutdownBuiltInIcons() {
|
void ShutdownBuiltInIcons() {
|
||||||
@@ -997,6 +1042,8 @@ void ShutdownBuiltInIcons() {
|
|||||||
ResetTexture(g_icons.folder);
|
ResetTexture(g_icons.folder);
|
||||||
ResetTexture(g_icons.gameObject);
|
ResetTexture(g_icons.gameObject);
|
||||||
ResetTexture(g_icons.scene);
|
ResetTexture(g_icons.scene);
|
||||||
|
ResetTexture(g_icons.cameraGizmo);
|
||||||
|
ResetTexture(g_icons.mainLightGizmo);
|
||||||
g_icons.backend = nullptr;
|
g_icons.backend = nullptr;
|
||||||
g_icons.device = nullptr;
|
g_icons.device = nullptr;
|
||||||
g_icons.commandQueue = nullptr;
|
g_icons.commandQueue = nullptr;
|
||||||
@@ -1041,6 +1088,22 @@ void DrawAssetIcon(ImDrawList* drawList, const ImVec2& min, const ImVec2& max, A
|
|||||||
DrawBuiltInFileIcon(drawList, min, max);
|
DrawBuiltInFileIcon(drawList, min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DrawEditorTextureIcon(
|
||||||
|
ImDrawList* drawList,
|
||||||
|
const ImVec2& min,
|
||||||
|
const ImVec2& max,
|
||||||
|
EditorTextureIconKind kind) {
|
||||||
|
MaintainIconRuntimeState();
|
||||||
|
|
||||||
|
const BuiltInTexture* texture = ResolveEditorTexture(kind);
|
||||||
|
if (texture == nullptr || !texture->IsValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawTextureIcon(drawList, *texture, min, max);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool DrawTextureAssetPreview(
|
bool DrawTextureAssetPreview(
|
||||||
ImDrawList* drawList,
|
ImDrawList* drawList,
|
||||||
const ImVec2& min,
|
const ImVec2& min,
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ enum class AssetIconKind {
|
|||||||
Scene
|
Scene
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class EditorTextureIconKind {
|
||||||
|
CameraGizmo,
|
||||||
|
MainLightGizmo
|
||||||
|
};
|
||||||
|
|
||||||
void InitializeBuiltInIcons(
|
void InitializeBuiltInIcons(
|
||||||
ImGuiBackendBridge& backend,
|
ImGuiBackendBridge& backend,
|
||||||
ID3D12Device* device,
|
ID3D12Device* device,
|
||||||
@@ -27,6 +32,11 @@ void InitializeBuiltInIcons(
|
|||||||
void ShutdownBuiltInIcons();
|
void ShutdownBuiltInIcons();
|
||||||
|
|
||||||
void DrawAssetIcon(ImDrawList* drawList, const ImVec2& min, const ImVec2& max, AssetIconKind kind);
|
void DrawAssetIcon(ImDrawList* drawList, const ImVec2& min, const ImVec2& max, AssetIconKind kind);
|
||||||
|
bool DrawEditorTextureIcon(
|
||||||
|
ImDrawList* drawList,
|
||||||
|
const ImVec2& min,
|
||||||
|
const ImVec2& max,
|
||||||
|
EditorTextureIconKind kind);
|
||||||
bool DrawTextureAssetPreview(
|
bool DrawTextureAssetPreview(
|
||||||
ImDrawList* drawList,
|
ImDrawList* drawList,
|
||||||
const ImVec2& min,
|
const ImVec2& min,
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
|
|||||||
const Rendering::RenderContext& renderContext,
|
const Rendering::RenderContext& renderContext,
|
||||||
const Rendering::RenderSurface& surface,
|
const Rendering::RenderSurface& surface,
|
||||||
const SceneViewportOverlayFrameData& frameData) {
|
const SceneViewportOverlayFrameData& frameData) {
|
||||||
if (!frameData.HasOverlayPrimitives() || !renderContext.IsValid() || renderContext.commandList == nullptr) {
|
if (!frameData.HasRenderPassPrimitives() || !renderContext.IsValid() || renderContext.commandList == nullptr) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,33 +411,10 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
|
|||||||
AppendScreenTriangleVertices(targetVertices, triangle);
|
AppendScreenTriangleVertices(targetVertices, triangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const SceneViewportOverlaySpritePrimitive*> depthTestedSprites = {};
|
|
||||||
std::vector<const SceneViewportOverlaySpritePrimitive*> alwaysOnTopSprites = {};
|
|
||||||
depthTestedSprites.reserve(frameData.worldSprites.size());
|
|
||||||
alwaysOnTopSprites.reserve(frameData.worldSprites.size());
|
|
||||||
for (const SceneViewportOverlaySpritePrimitive& sprite : frameData.worldSprites) {
|
|
||||||
if (sprite.sizePixels.x <= Math::EPSILON || sprite.sizePixels.y <= Math::EPSILON) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sprite.depthMode == SceneViewportOverlayDepthMode::DepthTested) {
|
|
||||||
depthTestedSprites.push_back(&sprite);
|
|
||||||
} else {
|
|
||||||
alwaysOnTopSprites.push_back(&sprite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto sortBackToFront =
|
|
||||||
[](const SceneViewportOverlaySpritePrimitive* lhs, const SceneViewportOverlaySpritePrimitive* rhs) {
|
|
||||||
return lhs->sortDepth > rhs->sortDepth;
|
|
||||||
};
|
|
||||||
std::sort(depthTestedSprites.begin(), depthTestedSprites.end(), sortBackToFront);
|
|
||||||
std::sort(alwaysOnTopSprites.begin(), alwaysOnTopSprites.end(), sortBackToFront);
|
|
||||||
|
|
||||||
const size_t lineVertexCount = depthTestedLineVertices.size() + alwaysOnTopLineVertices.size();
|
const size_t lineVertexCount = depthTestedLineVertices.size() + alwaysOnTopLineVertices.size();
|
||||||
const size_t screenTriangleVertexCount =
|
const size_t screenTriangleVertexCount =
|
||||||
depthTestedScreenTriangleVertices.size() + alwaysOnTopScreenTriangleVertices.size();
|
depthTestedScreenTriangleVertices.size() + alwaysOnTopScreenTriangleVertices.size();
|
||||||
const size_t spriteVertexCount = (depthTestedSprites.size() + alwaysOnTopSprites.size()) * 6u;
|
const size_t spriteVertexCount = 0u;
|
||||||
if (lineVertexCount == 0u && screenTriangleVertexCount == 0u && spriteVertexCount == 0u) {
|
if (lineVertexCount == 0u && screenTriangleVertexCount == 0u && spriteVertexCount == 0u) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -471,35 +448,6 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
|
|||||||
screenTriangleVertices.size() * sizeof(OverlayScreenTriangleVertex));
|
screenTriangleVertices.size() * sizeof(OverlayScreenTriangleVertex));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<OverlaySpriteVertex> spriteVertices = {};
|
|
||||||
std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount> depthTestedSpriteBatches = {};
|
|
||||||
std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount> alwaysOnTopSpriteBatches = {};
|
|
||||||
if (spriteVertexCount > 0u) {
|
|
||||||
spriteVertices.reserve(spriteVertexCount);
|
|
||||||
const auto appendSpriteBatches =
|
|
||||||
[&spriteVertices](
|
|
||||||
const std::vector<const SceneViewportOverlaySpritePrimitive*>& sprites,
|
|
||||||
std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount>& outBatches) {
|
|
||||||
for (size_t textureIndex = 0; textureIndex < kSceneViewportOverlaySpriteResourceCount; ++textureIndex) {
|
|
||||||
OverlaySpriteBatchRange range = {};
|
|
||||||
range.firstVertex = static_cast<uint32_t>(spriteVertices.size());
|
|
||||||
for (const SceneViewportOverlaySpritePrimitive* sprite : sprites) {
|
|
||||||
if (sprite == nullptr ||
|
|
||||||
GetSceneViewportOverlaySpriteResourceIndex(sprite->textureKind) != textureIndex) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppendSpriteVertices(spriteVertices, *sprite);
|
|
||||||
}
|
|
||||||
range.vertexCount = static_cast<uint32_t>(spriteVertices.size()) - range.firstVertex;
|
|
||||||
outBatches[textureIndex] = range;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
appendSpriteBatches(depthTestedSprites, depthTestedSpriteBatches);
|
|
||||||
appendSpriteBatches(alwaysOnTopSprites, alwaysOnTopSpriteBatches);
|
|
||||||
m_spriteVertexBuffer->SetData(spriteVertices.data(), spriteVertices.size() * sizeof(OverlaySpriteVertex));
|
|
||||||
}
|
|
||||||
|
|
||||||
OverlayConstants constants = {};
|
OverlayConstants constants = {};
|
||||||
constants.viewProjection = BuildSceneViewportViewProjectionMatrix(
|
constants.viewProjection = BuildSceneViewportViewProjectionMatrix(
|
||||||
frameData.overlay,
|
frameData.overlay,
|
||||||
@@ -564,49 +512,6 @@ bool SceneViewportEditorOverlayPassRenderer::Render(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spriteVertexCount > 0u) {
|
|
||||||
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
|
|
||||||
RHI::RHIResourceView* vertexBuffers[] = { m_spriteVertexBufferView };
|
|
||||||
const uint64_t offsets[] = { 0u };
|
|
||||||
const uint32_t strides[] = { static_cast<uint32_t>(sizeof(OverlaySpriteVertex)) };
|
|
||||||
commandList->SetVertexBuffers(0, 1, vertexBuffers, offsets, strides);
|
|
||||||
|
|
||||||
const auto drawSpriteBatchGroup =
|
|
||||||
[this, commandList](
|
|
||||||
RHI::RHIPipelineState* pipelineState,
|
|
||||||
const std::array<OverlaySpriteBatchRange, kSceneViewportOverlaySpriteResourceCount>& batches) {
|
|
||||||
if (pipelineState == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
commandList->SetPipelineState(pipelineState);
|
|
||||||
for (size_t textureIndex = 0; textureIndex < kSceneViewportOverlaySpriteResourceCount; ++textureIndex) {
|
|
||||||
const OverlaySpriteBatchRange& batch = batches[textureIndex];
|
|
||||||
if (!batch.HasVertices()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
RHI::RHIDescriptorSet* const textureSet =
|
|
||||||
m_overlaySpriteResources.GetTextureSet(
|
|
||||||
GetSceneViewportOverlaySpriteTextureKindByIndex(textureIndex));
|
|
||||||
if (textureSet == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
RHI::RHIDescriptorSet* descriptorSets[] = {
|
|
||||||
m_constantSet,
|
|
||||||
textureSet,
|
|
||||||
m_samplerSet
|
|
||||||
};
|
|
||||||
commandList->SetGraphicsDescriptorSets(0, 3, descriptorSets, m_spritePipelineLayout);
|
|
||||||
commandList->Draw(batch.vertexCount, 1, batch.firstVertex, 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
drawSpriteBatchGroup(m_depthTestedSpritePipelineState, depthTestedSpriteBatches);
|
|
||||||
drawSpriteBatchGroup(m_alwaysOnTopSpritePipelineState, alwaysOnTopSpriteBatches);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screenTriangleVertexCount > 0u) {
|
if (screenTriangleVertexCount > 0u) {
|
||||||
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
|
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
|
||||||
RHI::RHIResourceView* vertexBuffers[] = { m_screenTriangleVertexBufferView };
|
RHI::RHIResourceView* vertexBuffers[] = { m_screenTriangleVertexBufferView };
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ struct SceneViewportOverlayFrameData {
|
|||||||
return overlay.valid && (!worldLines.empty() || !worldSprites.empty() || !screenTriangles.empty());
|
return overlay.valid && (!worldLines.empty() || !worldSprites.empty() || !screenTriangles.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasRenderPassPrimitives() const {
|
||||||
|
return overlay.valid && (!worldLines.empty() || !screenTriangles.empty());
|
||||||
|
}
|
||||||
|
|
||||||
bool HasWorldOverlay() const {
|
bool HasWorldOverlay() const {
|
||||||
return HasOverlayPrimitives();
|
return HasOverlayPrimitives();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
#include "SceneViewportHudOverlay.h"
|
#include "SceneViewportHudOverlay.h"
|
||||||
|
|
||||||
#include "SceneViewportOrientationGizmo.h"
|
#include "SceneViewportOrientationGizmo.h"
|
||||||
|
#include "SceneViewportMath.h"
|
||||||
|
|
||||||
|
#include "UI/BuiltInIcons.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace Editor {
|
namespace Editor {
|
||||||
@@ -11,6 +17,97 @@ bool IsViewportRectValid(const ImVec2& viewportMin, const ImVec2& viewportMax) {
|
|||||||
viewportMax.y - viewportMin.y > 1.0f;
|
viewportMax.y - viewportMin.y > 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DrawSceneViewportSpriteIcon(
|
||||||
|
ImDrawList* drawList,
|
||||||
|
const ImVec2& min,
|
||||||
|
const ImVec2& max,
|
||||||
|
SceneViewportOverlaySpriteTextureKind textureKind) {
|
||||||
|
switch (textureKind) {
|
||||||
|
case SceneViewportOverlaySpriteTextureKind::Camera:
|
||||||
|
return UI::DrawEditorTextureIcon(
|
||||||
|
drawList,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
UI::EditorTextureIconKind::CameraGizmo);
|
||||||
|
case SceneViewportOverlaySpriteTextureKind::Light:
|
||||||
|
return UI::DrawEditorTextureIcon(
|
||||||
|
drawList,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
UI::EditorTextureIconKind::MainLightGizmo);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawSceneViewportSceneIcons(
|
||||||
|
ImDrawList* drawList,
|
||||||
|
const SceneViewportHudOverlayData& overlay,
|
||||||
|
const ImVec2& viewportMin,
|
||||||
|
const ImVec2& viewportMax) {
|
||||||
|
if (drawList == nullptr ||
|
||||||
|
!overlay.showSceneIcons ||
|
||||||
|
overlay.overlayFrameData == nullptr ||
|
||||||
|
overlay.overlayFrameData->worldSprites.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float viewportWidth = viewportMax.x - viewportMin.x;
|
||||||
|
const float viewportHeight = viewportMax.y - viewportMin.y;
|
||||||
|
if (viewportWidth <= 1.0f || viewportHeight <= 1.0f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const SceneViewportOverlaySpritePrimitive*> sortedSprites = {};
|
||||||
|
sortedSprites.reserve(overlay.overlayFrameData->worldSprites.size());
|
||||||
|
for (const SceneViewportOverlaySpritePrimitive& sprite : overlay.overlayFrameData->worldSprites) {
|
||||||
|
sortedSprites.push_back(&sprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(
|
||||||
|
sortedSprites.begin(),
|
||||||
|
sortedSprites.end(),
|
||||||
|
[](const SceneViewportOverlaySpritePrimitive* lhs, const SceneViewportOverlaySpritePrimitive* rhs) {
|
||||||
|
if (lhs == rhs) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (lhs == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (rhs == nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return lhs->sortDepth > rhs->sortDepth;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const SceneViewportOverlaySpritePrimitive* sprite : sortedSprites) {
|
||||||
|
if (sprite == nullptr ||
|
||||||
|
sprite->sizePixels.x <= Math::EPSILON ||
|
||||||
|
sprite->sizePixels.y <= Math::EPSILON) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SceneViewportProjectedPoint projectedPoint = ProjectSceneViewportWorldPoint(
|
||||||
|
overlay.sceneOverlay,
|
||||||
|
viewportWidth,
|
||||||
|
viewportHeight,
|
||||||
|
sprite->worldPosition);
|
||||||
|
if (!projectedPoint.visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImVec2 halfSize(sprite->sizePixels.x * 0.5f, sprite->sizePixels.y * 0.5f);
|
||||||
|
const ImVec2 center(
|
||||||
|
viewportMin.x + projectedPoint.screenPosition.x,
|
||||||
|
viewportMin.y + projectedPoint.screenPosition.y);
|
||||||
|
DrawSceneViewportSpriteIcon(
|
||||||
|
drawList,
|
||||||
|
ImVec2(center.x - halfSize.x, center.y - halfSize.y),
|
||||||
|
ImVec2(center.x + halfSize.x, center.y + halfSize.y),
|
||||||
|
sprite->textureKind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void DrawSceneViewportHudOverlay(
|
void DrawSceneViewportHudOverlay(
|
||||||
@@ -25,6 +122,11 @@ void DrawSceneViewportHudOverlay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawList->PushClipRect(viewportMin, viewportMax, true);
|
drawList->PushClipRect(viewportMin, viewportMax, true);
|
||||||
|
DrawSceneViewportSceneIcons(
|
||||||
|
drawList,
|
||||||
|
overlay,
|
||||||
|
viewportMin,
|
||||||
|
viewportMax);
|
||||||
if (overlay.showOrientationGizmo) {
|
if (overlay.showOrientationGizmo) {
|
||||||
DrawSceneViewportOrientationGizmo(
|
DrawSceneViewportOrientationGizmo(
|
||||||
drawList,
|
drawList,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "IViewportHostService.h"
|
#include "SceneViewportEditorOverlayData.h"
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
@@ -26,18 +26,28 @@ struct SceneViewportHudOverlayHitResult {
|
|||||||
struct SceneViewportHudOverlayData {
|
struct SceneViewportHudOverlayData {
|
||||||
SceneViewportOverlayData sceneOverlay = {};
|
SceneViewportOverlayData sceneOverlay = {};
|
||||||
bool showOrientationGizmo = true;
|
bool showOrientationGizmo = true;
|
||||||
|
bool showSceneIcons = true;
|
||||||
|
const SceneViewportOverlayFrameData* overlayFrameData = nullptr;
|
||||||
|
|
||||||
bool HasVisibleElements() const {
|
bool HasVisibleElements() const {
|
||||||
return sceneOverlay.valid && showOrientationGizmo;
|
return sceneOverlay.valid &&
|
||||||
|
(showOrientationGizmo ||
|
||||||
|
(showSceneIcons &&
|
||||||
|
overlayFrameData != nullptr &&
|
||||||
|
!overlayFrameData->worldSprites.empty()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline SceneViewportHudOverlayData BuildSceneViewportHudOverlayData(
|
inline SceneViewportHudOverlayData BuildSceneViewportHudOverlayData(
|
||||||
const SceneViewportOverlayData& sceneOverlay,
|
const SceneViewportOverlayData& sceneOverlay,
|
||||||
bool showOrientationGizmo = true) {
|
bool showOrientationGizmo = true,
|
||||||
|
const SceneViewportOverlayFrameData* overlayFrameData = nullptr,
|
||||||
|
bool showSceneIcons = true) {
|
||||||
SceneViewportHudOverlayData data = {};
|
SceneViewportHudOverlayData data = {};
|
||||||
data.sceneOverlay = sceneOverlay;
|
data.sceneOverlay = sceneOverlay;
|
||||||
data.showOrientationGizmo = showOrientationGizmo;
|
data.showOrientationGizmo = showOrientationGizmo;
|
||||||
|
data.showSceneIcons = showSceneIcons;
|
||||||
|
data.overlayFrameData = overlayFrameData;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ inline bool ShouldFocusSceneViewportAfterInteraction(
|
|||||||
struct SceneViewportPresentationRequest {
|
struct SceneViewportPresentationRequest {
|
||||||
IEditorContext* context = nullptr;
|
IEditorContext* context = nullptr;
|
||||||
IViewportHostService* viewportHostService = nullptr;
|
IViewportHostService* viewportHostService = nullptr;
|
||||||
|
const SceneViewportOverlayFrameData* overlayFrameData = nullptr;
|
||||||
bool hasInteractiveViewport = false;
|
bool hasInteractiveViewport = false;
|
||||||
SceneViewportFrameGeometry geometry = {};
|
SceneViewportFrameGeometry geometry = {};
|
||||||
SceneViewportTransformGizmoFrameOptions gizmoFrameOptions = {};
|
SceneViewportTransformGizmoFrameOptions gizmoFrameOptions = {};
|
||||||
@@ -182,7 +183,10 @@ inline void RefreshAndDrawSceneViewportPresentation(const SceneViewportPresentat
|
|||||||
|
|
||||||
DrawSceneViewportHudOverlay(
|
DrawSceneViewportHudOverlay(
|
||||||
request.drawList,
|
request.drawList,
|
||||||
BuildSceneViewportHudOverlayData(overlay),
|
BuildSceneViewportHudOverlayData(
|
||||||
|
overlay,
|
||||||
|
true,
|
||||||
|
request.overlayFrameData),
|
||||||
request.viewportMin,
|
request.viewportMin,
|
||||||
request.viewportMax);
|
request.viewportMax);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ inline SceneViewportRenderPlanBuildResult BuildSceneViewportRenderPlan(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editorOverlayFrameData.HasOverlayPrimitives() &&
|
if (editorOverlayFrameData.HasRenderPassPrimitives() &&
|
||||||
overlayPassFactory != nullptr) {
|
overlayPassFactory != nullptr) {
|
||||||
std::unique_ptr<Rendering::RenderPass> overlayPass = overlayPassFactory(editorOverlayFrameData);
|
std::unique_ptr<Rendering::RenderPass> overlayPass = overlayPassFactory(editorOverlayFrameData);
|
||||||
if (overlayPass != nullptr) {
|
if (overlayPass != nullptr) {
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ void SceneViewPanel::Render() {
|
|||||||
SceneViewportPresentationRequest presentationRequest = {};
|
SceneViewportPresentationRequest presentationRequest = {};
|
||||||
presentationRequest.context = m_context;
|
presentationRequest.context = m_context;
|
||||||
presentationRequest.viewportHostService = viewportHostService;
|
presentationRequest.viewportHostService = viewportHostService;
|
||||||
|
presentationRequest.overlayFrameData = interactionFrameState.overlayFrameData;
|
||||||
presentationRequest.hasInteractiveViewport = hasInteractiveViewport;
|
presentationRequest.hasInteractiveViewport = hasInteractiveViewport;
|
||||||
presentationRequest.geometry = frameGeometry;
|
presentationRequest.geometry = frameGeometry;
|
||||||
presentationRequest.gizmoFrameOptions = toolState.gizmoFrameOptions;
|
presentationRequest.gizmoFrameOptions = toolState.gizmoFrameOptions;
|
||||||
|
|||||||
Reference in New Issue
Block a user