engine: sync editor rendering and ui changes

This commit is contained in:
2026-04-08 16:09:15 +08:00
parent 31756847ab
commit 162f1cc12e
153 changed files with 4454 additions and 2990 deletions

View File

@@ -72,17 +72,60 @@ inline ::XCEngine::Components::GameObject* CreateLightEntity(
IEditorContext& context,
::XCEngine::Components::GameObject* parent = nullptr,
const std::string& commandLabel = "Create Light",
const std::string& entityName = "Light") {
const std::string& entityName = "Light",
::XCEngine::Components::LightType lightType = ::XCEngine::Components::LightType::Directional) {
return CreateEntity(
context,
commandLabel,
entityName,
parent,
[](::XCEngine::Components::GameObject& entity, ISceneManager&) {
entity.AddComponent<::XCEngine::Components::LightComponent>();
[lightType](::XCEngine::Components::GameObject& entity, ISceneManager&) {
auto* light = entity.AddComponent<::XCEngine::Components::LightComponent>();
if (light != nullptr) {
light->SetLightType(lightType);
}
});
}
inline ::XCEngine::Components::GameObject* CreateDirectionalLightEntity(
IEditorContext& context,
::XCEngine::Components::GameObject* parent = nullptr,
const std::string& commandLabel = "Create Directional Light",
const std::string& entityName = "Directional Light") {
return CreateLightEntity(
context,
parent,
commandLabel,
entityName,
::XCEngine::Components::LightType::Directional);
}
inline ::XCEngine::Components::GameObject* CreatePointLightEntity(
IEditorContext& context,
::XCEngine::Components::GameObject* parent = nullptr,
const std::string& commandLabel = "Create Point Light",
const std::string& entityName = "Point Light") {
return CreateLightEntity(
context,
parent,
commandLabel,
entityName,
::XCEngine::Components::LightType::Point);
}
inline ::XCEngine::Components::GameObject* CreateSpotLightEntity(
IEditorContext& context,
::XCEngine::Components::GameObject* parent = nullptr,
const std::string& commandLabel = "Create Spot Light",
const std::string& entityName = "Spot Light") {
return CreateLightEntity(
context,
parent,
commandLabel,
entityName,
::XCEngine::Components::LightType::Spot);
}
inline ::XCEngine::Components::GameObject* CreatePrimitiveEntity(
IEditorContext& context,
::XCEngine::Resources::BuiltinPrimitiveType primitiveType,

View File

@@ -99,7 +99,9 @@ struct BuiltInIconState {
BuiltInTexture gameObject;
BuiltInTexture scene;
BuiltInTexture cameraGizmo;
BuiltInTexture mainLightGizmo;
BuiltInTexture directionalLightGizmo;
BuiltInTexture pointLightGizmo;
BuiltInTexture spotLightGizmo;
struct CachedAssetPreview {
BuiltInTexture texture;
std::unique_ptr<LoadedTexturePixels> decodedPixels;
@@ -157,9 +159,19 @@ std::filesystem::path ResolveCameraGizmoIconPath() {
return (exeDir / ".." / ".." / "resources" / "Icons" / "camera_gizmo.png").lexically_normal();
}
std::filesystem::path ResolveMainLightGizmoIconPath() {
std::filesystem::path ResolveDirectionalLightGizmoIconPath() {
const std::filesystem::path exeDir(Platform::GetExecutableDirectoryUtf8());
return (exeDir / ".." / ".." / "resources" / "Icons" / "main_light_gizmo.png").lexically_normal();
return (exeDir / ".." / ".." / "resources" / "Icons" / "directional_light_gizmo.png").lexically_normal();
}
std::filesystem::path ResolvePointLightGizmoIconPath() {
const std::filesystem::path exeDir(Platform::GetExecutableDirectoryUtf8());
return (exeDir / ".." / ".." / "resources" / "Icons" / "point_light_gizmo.png").lexically_normal();
}
std::filesystem::path ResolveSpotLightGizmoIconPath() {
const std::filesystem::path exeDir(Platform::GetExecutableDirectoryUtf8());
return (exeDir / ".." / ".." / "resources" / "Icons" / "spot_light_gizmo.png").lexically_normal();
}
std::string NormalizePathKey(const std::filesystem::path& path) {
@@ -975,8 +987,12 @@ BuiltInTexture* ResolveEditorTexture(EditorTextureIconKind kind) {
switch (kind) {
case EditorTextureIconKind::CameraGizmo:
return &g_icons.cameraGizmo;
case EditorTextureIconKind::MainLightGizmo:
return &g_icons.mainLightGizmo;
case EditorTextureIconKind::DirectionalLightGizmo:
return &g_icons.directionalLightGizmo;
case EditorTextureIconKind::PointLightGizmo:
return &g_icons.pointLightGizmo;
case EditorTextureIconKind::SpotLightGizmo:
return &g_icons.spotLightGizmo;
default:
return nullptr;
}
@@ -1025,8 +1041,30 @@ void InitializeBuiltInIcons(
backend,
device,
commandQueue,
ResolveMainLightGizmoIconPath(),
g_icons.mainLightGizmo,
ResolveDirectionalLightGizmoIconPath(),
g_icons.directionalLightGizmo,
pendingUpload)) {
g_icons.pendingIconUploads.push_back(std::move(pendingUpload));
}
pendingUpload.reset();
if (LoadTextureFromFile(
backend,
device,
commandQueue,
ResolvePointLightGizmoIconPath(),
g_icons.pointLightGizmo,
pendingUpload)) {
g_icons.pendingIconUploads.push_back(std::move(pendingUpload));
}
pendingUpload.reset();
if (LoadTextureFromFile(
backend,
device,
commandQueue,
ResolveSpotLightGizmoIconPath(),
g_icons.spotLightGizmo,
pendingUpload)) {
g_icons.pendingIconUploads.push_back(std::move(pendingUpload));
}
@@ -1043,7 +1081,9 @@ void ShutdownBuiltInIcons() {
ResetTexture(g_icons.gameObject);
ResetTexture(g_icons.scene);
ResetTexture(g_icons.cameraGizmo);
ResetTexture(g_icons.mainLightGizmo);
ResetTexture(g_icons.directionalLightGizmo);
ResetTexture(g_icons.pointLightGizmo);
ResetTexture(g_icons.spotLightGizmo);
g_icons.backend = nullptr;
g_icons.device = nullptr;
g_icons.commandQueue = nullptr;

View File

@@ -21,7 +21,10 @@ enum class AssetIconKind {
enum class EditorTextureIconKind {
CameraGizmo,
MainLightGizmo
DirectionalLightGizmo,
PointLightGizmo,
SpotLightGizmo,
MainLightGizmo = DirectionalLightGizmo
};
void InitializeBuiltInIcons(

View File

@@ -14,8 +14,17 @@ namespace XCEngine {
namespace Editor {
namespace UI {
inline bool ShouldTracePopupSubmenuLabel(const char* label) {
if (!label) {
return false;
}
const std::string text(label);
return text == "Create" || text == "3D Object";
}
inline void TracePopupSubmenuIfNeeded(const char* label, const std::string& message) {
if (!label || std::string(label) != "Create") {
if (!ShouldTracePopupSubmenuLabel(label)) {
return;
}
@@ -92,7 +101,7 @@ inline bool DrawMenuScope(const char* label, DrawContentFn&& drawContent) {
}
template <typename DrawContentFn>
inline bool DrawPopupSubmenuScope(const char* label, DrawContentFn&& drawContent) {
inline bool DrawPopupSubmenuScope(const char* label, DrawContentFn&& drawContent, bool enabled = true) {
if (!label || label[0] == '\0') {
return false;
}
@@ -103,18 +112,24 @@ inline bool DrawPopupSubmenuScope(const char* label, DrawContentFn&& drawContent
const ImVec2 rowPos = ImGui::GetCursorScreenPos();
const float rowHeight = labelSize.y;
const float rowWidth = ImMax(ImGui::GetContentRegionAvail().x, 1.0f);
const bool popupOpen = ImGui::IsPopupOpen(popupId);
const bool popupOpen = enabled && ImGui::IsPopupOpen(popupId);
ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_NoAutoClosePopups;
if (!enabled) {
selectableFlags |= ImGuiSelectableFlags_Disabled;
}
if (ImGui::Selectable(
"##PopupSubmenuRow",
popupOpen,
ImGuiSelectableFlags_NoAutoClosePopups,
selectableFlags,
ImVec2(rowWidth, rowHeight))) {
TracePopupSubmenuIfNeeded(label, "Hierarchy create submenu selectable clicked -> OpenPopup");
ImGui::OpenPopup(popupId);
if (enabled) {
TracePopupSubmenuIfNeeded(label, "Hierarchy create submenu selectable clicked -> OpenPopup");
ImGui::OpenPopup(popupId);
}
}
const bool hovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
const bool hovered = enabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
if (hovered && !popupOpen) {
TracePopupSubmenuIfNeeded(label, "Hierarchy create submenu hovered -> OpenPopup");
ImGui::OpenPopup(popupId);
@@ -127,9 +142,10 @@ inline bool DrawPopupSubmenuScope(const char* label, DrawContentFn&& drawContent
const float parentWindowRight = parentWindowPos.x + parentWindowSize.x;
const float itemHeight = itemMax.y - itemMin.y;
ImDrawList* drawList = ImGui::GetWindowDrawList();
const ImU32 textColor = ImGui::GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled);
drawList->AddText(
ImVec2(itemMin.x + ImGui::GetStyle().FramePadding.x, itemMin.y + (itemHeight - labelSize.y) * 0.5f),
ImGui::GetColorU32(ImGuiCol_Text),
textColor,
label);
const float arrowExtent = PopupSubmenuArrowExtent();
@@ -139,7 +155,12 @@ inline bool DrawPopupSubmenuScope(const char* label, DrawContentFn&& drawContent
ImVec2(arrowCenterX - arrowExtent * 0.30f, arrowCenterY - arrowExtent * 0.50f),
ImVec2(arrowCenterX - arrowExtent * 0.30f, arrowCenterY + arrowExtent * 0.50f),
ImVec2(arrowCenterX + arrowExtent * 0.50f, arrowCenterY),
ImGui::GetColorU32(ImGuiCol_Text));
textColor);
if (!enabled) {
ImGui::PopID();
return false;
}
ImGui::SetNextWindowPos(
ImVec2(parentWindowRight + PopupSubmenuOpenOffsetX(), rowPos.y - PopupWindowPadding().y),
@@ -149,7 +170,7 @@ inline bool DrawPopupSubmenuScope(const char* label, DrawContentFn&& drawContent
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoSavedSettings);
if (std::string(label) == "Create") {
if (ShouldTracePopupSubmenuLabel(label)) {
static bool s_lastCreateOpen = false;
if (open != s_lastCreateOpen) {
TracePopupSubmenuIfNeeded(

View File

@@ -1,9 +1,5 @@
#include <XCEngine/Core/Asset/ResourceManager.h>
#include "Passes/SceneViewportSelectionOutlinePass.h"
#include "Viewport/SceneViewportShaderPaths.h"
namespace XCEngine {
namespace Editor {
@@ -45,7 +41,7 @@ private:
} // namespace
SceneViewportSelectionOutlinePassRenderer::SceneViewportSelectionOutlinePassRenderer()
: m_outlinePass(GetSceneViewportObjectIdOutlineShaderPath()) {
: m_outlinePass() {
}
void SceneViewportSelectionOutlinePassRenderer::Shutdown() {

View File

@@ -20,7 +20,10 @@ enum class SceneViewportOverlayDepthMode : uint8_t {
enum class SceneViewportOverlaySpriteTextureKind : uint8_t {
Camera = 0,
Light = 1
DirectionalLight = 1,
PointLight = 2,
SpotLight = 3,
Light = DirectionalLight
};
enum class SceneViewportOverlayHandleKind : uint8_t {

View File

@@ -29,12 +29,24 @@ bool DrawSceneViewportSpriteIcon(
min,
max,
UI::EditorTextureIconKind::CameraGizmo);
case SceneViewportOverlaySpriteTextureKind::Light:
case SceneViewportOverlaySpriteTextureKind::DirectionalLight:
return UI::DrawEditorTextureIcon(
drawList,
min,
max,
UI::EditorTextureIconKind::MainLightGizmo);
UI::EditorTextureIconKind::DirectionalLightGizmo);
case SceneViewportOverlaySpriteTextureKind::PointLight:
return UI::DrawEditorTextureIcon(
drawList,
min,
max,
UI::EditorTextureIconKind::PointLightGizmo);
case SceneViewportOverlaySpriteTextureKind::SpotLight:
return UI::DrawEditorTextureIcon(
drawList,
min,
max,
UI::EditorTextureIconKind::SpotLightGizmo);
default:
return false;
}

View File

@@ -105,6 +105,16 @@ inline bool ShouldBeginSceneViewportNavigationDrag(
return hasInteractiveViewport && hovered && !activeDrag && !otherDrag && !gizmoActive && clicked;
}
inline bool ShouldBeginSceneViewportHeldNavigationDrag(
bool hasInteractiveViewport,
bool hovered,
bool activeDrag,
bool otherDrag,
bool gizmoActive,
bool buttonDown) {
return hasInteractiveViewport && hovered && !activeDrag && !otherDrag && !gizmoActive && buttonDown;
}
inline bool IsSceneViewportPanDragButtonDown(
const SceneViewportNavigationRequest& request,
int button) {
@@ -139,13 +149,21 @@ inline SceneViewportNavigationUpdate UpdateSceneViewportNavigationState(
request.state.panDragging,
request.gizmoActive,
request.clickedRight);
update.beginMiddlePanDrag = ShouldBeginSceneViewportNavigationDrag(
request.hasInteractiveViewport,
request.viewportHovered,
request.state.panDragging,
request.state.lookDragging,
request.gizmoActive,
request.clickedMiddle);
update.beginMiddlePanDrag =
ShouldBeginSceneViewportNavigationDrag(
request.hasInteractiveViewport,
request.viewportHovered,
request.state.panDragging,
request.state.lookDragging,
request.gizmoActive,
request.clickedMiddle) ||
ShouldBeginSceneViewportHeldNavigationDrag(
request.hasInteractiveViewport,
request.viewportHovered,
request.state.panDragging,
request.state.lookDragging,
request.gizmoActive,
request.middleMouseDown);
update.beginPanDrag = update.beginLeftPanDrag || update.beginMiddlePanDrag;
if (update.beginLookDrag) {

View File

@@ -73,6 +73,42 @@ void AppendWorldLine(
line.depthMode = depthMode;
}
constexpr Math::Color kSelectedLightHelperColor(1.0f, 0.92f, 0.24f, 1.0f);
constexpr float kSelectedLightHelperLineThickness = 1.8f;
constexpr size_t kSelectedLightHelperSegmentCount = 32u;
void AppendWireCircle(
SceneViewportOverlayFrameData& frameData,
const Math::Vector3& center,
const Math::Vector3& basisA,
const Math::Vector3& basisB,
float radius,
const Math::Color& color,
float thicknessPixels,
SceneViewportOverlayDepthMode depthMode) {
const Math::Vector3 axisA = basisA.Normalized();
const Math::Vector3 axisB = basisB.Normalized();
if (radius <= Math::EPSILON ||
axisA.SqrMagnitude() <= Math::EPSILON ||
axisB.SqrMagnitude() <= Math::EPSILON) {
return;
}
for (size_t segmentIndex = 0; segmentIndex < kSelectedLightHelperSegmentCount; ++segmentIndex) {
const float angle0 =
static_cast<float>(segmentIndex) / static_cast<float>(kSelectedLightHelperSegmentCount) *
Math::PI * 2.0f;
const float angle1 =
static_cast<float>(segmentIndex + 1u) / static_cast<float>(kSelectedLightHelperSegmentCount) *
Math::PI * 2.0f;
const Math::Vector3 p0 =
center + axisA * std::cos(angle0) * radius + axisB * std::sin(angle0) * radius;
const Math::Vector3 p1 =
center + axisA * std::cos(angle1) * radius + axisB * std::sin(angle1) * radius;
AppendWorldLine(frameData, p0, p1, color, thicknessPixels, depthMode);
}
}
void AppendWorldSprite(
SceneViewportOverlayFrameData& frameData,
const Math::Vector3& worldPosition,
@@ -164,6 +200,20 @@ void AppendSceneIconOverlay(
projectedPoint.ndcDepth);
}
SceneViewportOverlaySpriteTextureKind ResolveLightSceneIconTextureKind(
const Components::LightComponent& light) {
switch (light.GetLightType()) {
case Components::LightType::Directional:
return SceneViewportOverlaySpriteTextureKind::DirectionalLight;
case Components::LightType::Point:
return SceneViewportOverlaySpriteTextureKind::PointLight;
case Components::LightType::Spot:
return SceneViewportOverlaySpriteTextureKind::SpotLight;
default:
return SceneViewportOverlaySpriteTextureKind::DirectionalLight;
}
}
void AppendCameraFrustumOverlay(
SceneViewportOverlayFrameData& frameData,
const Components::CameraComponent& camera,
@@ -251,10 +301,10 @@ void AppendDirectionalLightOverlay(
}
const Math::Vector3 position = transform->GetPosition();
const Math::Vector3 lightDirection = (transform->GetForward() * -1.0f).Normalized();
const Math::Vector3 lightRayDirection = transform->GetForward().Normalized();
const Math::Vector3 right = transform->GetRight().Normalized();
const Math::Vector3 up = transform->GetUp().Normalized();
if (lightDirection.SqrMagnitude() <= Math::EPSILON ||
if (lightRayDirection.SqrMagnitude() <= Math::EPSILON ||
right.SqrMagnitude() <= Math::EPSILON ||
up.SqrMagnitude() <= Math::EPSILON) {
return;
@@ -265,8 +315,6 @@ void AppendDirectionalLightOverlay(
return;
}
constexpr Math::Color kDirectionalLightColor(1.0f, 0.92f, 0.24f, 1.0f);
constexpr float kLineThickness = 1.8f;
constexpr size_t kRingSegmentCount = 32u;
constexpr std::array<float, 6> kRayAngles = {{
0.0f,
@@ -281,7 +329,7 @@ void AppendDirectionalLightOverlay(
const float ringOffset = worldUnitsPerPixel * 54.0f;
const float innerRayRadius = ringRadius * 0.52f;
const float rayLength = worldUnitsPerPixel * 96.0f;
const Math::Vector3 ringCenter = position + lightDirection * ringOffset;
const Math::Vector3 ringCenter = position + lightRayDirection * ringOffset;
for (size_t segmentIndex = 0; segmentIndex < kRingSegmentCount; ++segmentIndex) {
const float angle0 =
@@ -296,8 +344,8 @@ void AppendDirectionalLightOverlay(
frameData,
p0,
p1,
kDirectionalLightColor,
kLineThickness,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
}
@@ -305,15 +353,15 @@ void AppendDirectionalLightOverlay(
frameData,
position,
ringCenter,
kDirectionalLightColor,
kLineThickness,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
AppendWorldLine(
frameData,
ringCenter,
ringCenter + lightDirection * rayLength,
kDirectionalLightColor,
kLineThickness,
ringCenter + lightRayDirection * rayLength,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
for (float angle : kRayAngles) {
@@ -322,9 +370,119 @@ void AppendDirectionalLightOverlay(
AppendWorldLine(
frameData,
rayStart,
rayStart + lightDirection * rayLength,
kDirectionalLightColor,
kLineThickness,
rayStart + lightRayDirection * rayLength,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
}
}
void AppendPointLightOverlay(
SceneViewportOverlayFrameData& frameData,
const Components::GameObject& gameObject,
const Components::LightComponent& light) {
const Components::TransformComponent* transform = gameObject.GetTransform();
if (transform == nullptr) {
return;
}
const Math::Vector3 position = transform->GetPosition();
const Math::Vector3 right = transform->GetRight().Normalized();
const Math::Vector3 up = transform->GetUp().Normalized();
const Math::Vector3 forward = transform->GetForward().Normalized();
if (right.SqrMagnitude() <= Math::EPSILON ||
up.SqrMagnitude() <= Math::EPSILON ||
forward.SqrMagnitude() <= Math::EPSILON) {
return;
}
const float range = (std::max)(light.GetRange(), 0.001f);
AppendWireCircle(
frameData,
position,
right,
up,
range,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
AppendWireCircle(
frameData,
position,
right,
forward,
range,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
AppendWireCircle(
frameData,
position,
up,
forward,
range,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
}
void AppendSpotLightOverlay(
SceneViewportOverlayFrameData& frameData,
const Components::GameObject& gameObject,
const Components::LightComponent& light) {
const Components::TransformComponent* transform = gameObject.GetTransform();
if (transform == nullptr) {
return;
}
const Math::Vector3 position = transform->GetPosition();
const Math::Vector3 forward = transform->GetForward().Normalized();
const Math::Vector3 right = transform->GetRight().Normalized();
const Math::Vector3 up = transform->GetUp().Normalized();
if (forward.SqrMagnitude() <= Math::EPSILON ||
right.SqrMagnitude() <= Math::EPSILON ||
up.SqrMagnitude() <= Math::EPSILON) {
return;
}
const float range = (std::max)(light.GetRange(), 0.001f);
const float halfAngleRadians =
std::clamp(light.GetSpotAngle(), 1.0f, 179.0f) * Math::DEG_TO_RAD * 0.5f;
const float coneRadius = std::tan(halfAngleRadians) * range;
const Math::Vector3 coneBaseCenter = position + forward * range;
AppendWorldLine(
frameData,
position,
coneBaseCenter,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
AppendWireCircle(
frameData,
coneBaseCenter,
right,
up,
coneRadius,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
static constexpr std::array<float, 4> kConeEdgeAngles = {{
0.0f,
Math::PI * 0.5f,
Math::PI,
Math::PI * 1.5f
}};
for (float angle : kConeEdgeAngles) {
const Math::Vector3 coneEdgePoint =
coneBaseCenter + right * std::cos(angle) * coneRadius + up * std::sin(angle) * coneRadius;
AppendWorldLine(
frameData,
position,
coneEdgePoint,
kSelectedLightHelperColor,
kSelectedLightHelperLineThickness,
SceneViewportOverlayDepthMode::AlwaysOnTop);
}
}
@@ -421,7 +579,7 @@ public:
context.viewportHeight,
*gameObject,
kLightIconSize,
SceneViewportOverlaySpriteTextureKind::Light);
ResolveLightSceneIconTextureKind(*light));
}
for (uint64_t entityId : *context.selectedObjectIds) {
@@ -435,17 +593,25 @@ public:
}
Components::LightComponent* light = gameObject->GetComponent<Components::LightComponent>();
if (light == nullptr ||
!light->IsEnabled() ||
light->GetLightType() != Components::LightType::Directional) {
if (light == nullptr || !light->IsEnabled()) {
continue;
}
AppendDirectionalLightOverlay(
frameData,
*gameObject,
*context.overlay,
context.viewportHeight);
switch (light->GetLightType()) {
case Components::LightType::Directional:
AppendDirectionalLightOverlay(
frameData,
*gameObject,
*context.overlay,
context.viewportHeight);
break;
case Components::LightType::Point:
AppendPointLightOverlay(frameData, *gameObject, *light);
break;
case Components::LightType::Spot:
AppendSpotLightOverlay(frameData, *gameObject, *light);
break;
}
}
}
};

View File

@@ -22,9 +22,11 @@ class RHITexture;
namespace Editor {
inline constexpr std::array<SceneViewportOverlaySpriteTextureKind, 2> kSceneViewportOverlaySpriteTextureKinds = {
inline constexpr std::array<SceneViewportOverlaySpriteTextureKind, 4> kSceneViewportOverlaySpriteTextureKinds = {
SceneViewportOverlaySpriteTextureKind::Camera,
SceneViewportOverlaySpriteTextureKind::Light
SceneViewportOverlaySpriteTextureKind::DirectionalLight,
SceneViewportOverlaySpriteTextureKind::PointLight,
SceneViewportOverlaySpriteTextureKind::SpotLight
};
inline constexpr size_t kSceneViewportOverlaySpriteResourceCount =
@@ -35,8 +37,12 @@ inline size_t GetSceneViewportOverlaySpriteResourceIndex(
switch (textureKind) {
case SceneViewportOverlaySpriteTextureKind::Camera:
return 0u;
case SceneViewportOverlaySpriteTextureKind::Light:
case SceneViewportOverlaySpriteTextureKind::DirectionalLight:
return 1u;
case SceneViewportOverlaySpriteTextureKind::PointLight:
return 2u;
case SceneViewportOverlaySpriteTextureKind::SpotLight:
return 3u;
default:
return 0u;
}
@@ -63,8 +69,14 @@ inline SceneViewportOverlaySpriteAssetSpec GetSceneViewportOverlaySpriteAssetSpe
case SceneViewportOverlaySpriteTextureKind::Camera:
spec.resourcePath = GetSceneViewportCameraGizmoIconPath();
break;
case SceneViewportOverlaySpriteTextureKind::Light:
spec.resourcePath = GetSceneViewportMainLightGizmoIconPath();
case SceneViewportOverlaySpriteTextureKind::DirectionalLight:
spec.resourcePath = GetSceneViewportDirectionalLightGizmoIconPath();
break;
case SceneViewportOverlaySpriteTextureKind::PointLight:
spec.resourcePath = GetSceneViewportPointLightGizmoIconPath();
break;
case SceneViewportOverlaySpriteTextureKind::SpotLight:
spec.resourcePath = GetSceneViewportSpotLightGizmoIconPath();
break;
default:
break;

View File

@@ -39,22 +39,28 @@ inline Containers::String GetSceneViewportInfiniteGridShaderPath() {
"infinite-grid.shader");
}
inline Containers::String GetSceneViewportObjectIdOutlineShaderPath() {
return Detail::BuildSceneViewportEditorResourcePath(
std::filesystem::path("shaders") /
"scene-viewport" /
"object-id-outline" /
"object-id-outline.shader");
}
inline Containers::String GetSceneViewportCameraGizmoIconPath() {
return Detail::BuildSceneViewportEditorResourcePath(
std::filesystem::path("Icons") / "camera_gizmo.png");
}
inline Containers::String GetSceneViewportMainLightGizmoIconPath() {
inline Containers::String GetSceneViewportDirectionalLightGizmoIconPath() {
return Detail::BuildSceneViewportEditorResourcePath(
std::filesystem::path("Icons") / "main_light_gizmo.png");
std::filesystem::path("Icons") / "directional_light_gizmo.png");
}
inline Containers::String GetSceneViewportPointLightGizmoIconPath() {
return Detail::BuildSceneViewportEditorResourcePath(
std::filesystem::path("Icons") / "point_light_gizmo.png");
}
inline Containers::String GetSceneViewportSpotLightGizmoIconPath() {
return Detail::BuildSceneViewportEditorResourcePath(
std::filesystem::path("Icons") / "spot_light_gizmo.png");
}
inline Containers::String GetSceneViewportMainLightGizmoIconPath() {
return GetSceneViewportDirectionalLightGizmoIconPath();
}
} // namespace Editor

View File

@@ -77,10 +77,15 @@ inline void RenderViewportInteractionSurface(
result.itemMin = ImGui::GetItemRectMin();
result.itemMax = ImGui::GetItemRectMax();
result.hovered = ImGui::IsItemHovered();
result.clickedLeft = result.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left, false);
result.clickedRight = result.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right, false);
result.clickedMiddle = result.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Middle, false);
// Use explicit viewport-rect hit testing instead of ImGui item hover state. Dear ImGui ties
// hovered items to click ownership, so a middle-button press that arrives before the panel
// has established hover can fail to start panning in the live docked editor even though the
// cursor is inside the viewport.
const bool hoveredForInput = ImGui::IsMouseHoveringRect(result.itemMin, result.itemMax, false);
result.hovered = hoveredForInput;
result.clickedLeft = hoveredForInput && ImGui::IsMouseClicked(ImGuiMouseButton_Left);
result.clickedRight = hoveredForInput && ImGui::IsMouseClicked(ImGuiMouseButton_Right);
result.clickedMiddle = hoveredForInput && ImGui::IsMouseClicked(ImGuiMouseButton_Middle);
}
inline ViewportPanelContentResult RenderViewportPanelContent(