Merge branch 'development' of https://github.com/o3de/o3de into daimini/FocusMode/breadcrumbs

This commit is contained in:
Danilo Aimini
2021-09-30 08:16:11 -07:00
136 changed files with 3530 additions and 3882 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ enum
{
// in milliseconds
GameModeIdleFrequency = 0,
EditorModeIdleFrequency = 0,
EditorModeIdleFrequency = 1,
InactiveModeFrequency = 10,
UninitializedFrequency = 9999,
};
@@ -175,27 +175,15 @@ namespace SandboxEditor
m_pivotCamera = AZStd::make_shared<AzFramework::PivotCameraInput>(SandboxEditor::CameraPivotChannelId());
m_pivotCamera->SetPivotFn(
[viewportId = m_viewportId]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction)
[]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction)
{
AZStd::optional<AZ::Vector3> lookAtAfterInterpolation;
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
lookAtAfterInterpolation, viewportId,
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookAtAfterInterpolation);
// initially attempt to use the last set look at point after an interpolation has finished
// note: ignore this if it is the same location as the camera (e.g. after go to position)
if (lookAtAfterInterpolation.has_value() && !lookAtAfterInterpolation->IsClose(position))
{
return *lookAtAfterInterpolation;
}
// otherwise fall back to the selected entity pivot
// use the manipulator transform as the pivot point
AZStd::optional<AZ::Transform> entityPivot;
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
entityPivot, AzToolsFramework::GetEntityContextId(),
&AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
// finally just use the identity
// otherwise just use the identity
return entityPivot.value_or(AZ::Transform::CreateIdentity()).GetTranslation();
});
+1 -1
View File
@@ -48,7 +48,7 @@ namespace SandboxEditor
{
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
viewportContext->GetId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
AZ::Transform::CreateFromQuaternionAndTranslation(CameraRotation(pitch, yaw), position), 0.0f);
AZ::Transform::CreateFromQuaternionAndTranslation(CameraRotation(pitch, yaw), position));
}
}
@@ -167,7 +167,7 @@ namespace UnitTest
AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(20.0f, 40.0f, 60.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
transformToInterpolateTo, 0.0f);
transformToInterpolateTo);
// simulate interpolation
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
@@ -193,7 +193,7 @@ namespace UnitTest
// When
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
transformToInterpolateTo, 0.0f);
transformToInterpolateTo);
// simulate interpolation
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
@@ -1739,8 +1739,7 @@ void SandboxIntegrationManager::GoToEntitiesInViewports(const AzToolsFramework::
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
viewportContext->GetId(),
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform,
distanceToLookAt);
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform);
}
}
}
@@ -36,9 +36,6 @@
#include "CryEdit.h"
#include "Viewport.h"
// Atom Renderer
#include <Atom/RPI.Public/RPISystemInterface.h>
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include <TrackView/ui_SequenceBatchRenderDialog.h>
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
@@ -1237,13 +1234,6 @@ void CSequenceBatchRenderDialog::OnKickIdleTimout()
{
componentApplication->TickSystem();
}
// Directly tick the renderer, as it's no longer part of the system tick
if (auto rpiSystem = AZ::RPI::RPISystemInterface::Get())
{
rpiSystem->SimulationTick();
rpiSystem->RenderTick();
}
}
}
@@ -74,8 +74,6 @@
#include <AzCore/Module/Environment.h>
#include <AzCore/std/string/conversions.h>
AZ_CVAR(float, g_simulation_tick_rate, 0, nullptr, AZ::ConsoleFunctorFlags::Null, "The rate at which the game simulation tick loop runs, or 0 for as fast as possible");
static void PrintEntityName(const AZ::ConsoleCommandContainer& arguments)
{
if (arguments.empty())
@@ -1396,23 +1394,6 @@ namespace AZ
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick");
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
}
// If tick rate limiting is on, ensure (1 / g_simulation_tick_rate) ms has elapsed since the last frame,
// sleeping if there's still time remaining.
if (g_simulation_tick_rate > 0.f)
{
now = AZStd::chrono::system_clock::now();
// Work in microsecond durations here as that's the native measurement time for time_point
constexpr float microsecondsPerSecond = 1000.f * 1000.f;
const AZStd::chrono::microseconds timeBudgetPerTick(static_cast<int>(microsecondsPerSecond / g_simulation_tick_rate));
AZStd::chrono::microseconds timeUntilNextTick = m_currentTime + timeBudgetPerTick - now;
if (timeUntilNextTick.count() > 0)
{
AZStd::this_thread::sleep_for(timeUntilNextTick);
}
}
}
}
@@ -46,8 +46,6 @@ namespace AZ
TICK_PRE_RENDER = 750, ///< Suggested tick handler position to update render-related data.
TICK_RENDER = 800, ///< Suggested tick handler position for rendering.
TICK_DEFAULT = 1000, ///< Default tick handler position when the handler is constructed.
TICK_UI = 2000, ///< Suggested tick handler position for UI components.
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M16.9,16.7c0,0.7-0.6,1.3-1.3,1.3h-7c-0.7,0-1.3-0.6-1.3-1.3v-0.5h-2v0.5c0,1.8,1.5,3.3,3.3,3.3h2
c-0.2,0.5-0.1,1.2,0.3,1.6c0.6,0.6,1.5,0.6,2.1,0c0.4-0.4,0.5-1,0.3-1.6h2.3c1.8,0,3.3-1.5,3.3-3.3v-0.5l-2,0V16.7z M12.3,20.9
c-0.2,0.2-0.6,0.2-0.8,0c-0.2-0.2-0.2-0.5,0-0.8c0.2-0.2,0.5-0.2,0.8,0c0,0,0,0,0,0C12.5,20.3,12.5,20.7,12.3,20.9z"/>
<rect x="6.5" y="8" transform="matrix(0.9939 -0.1101 0.1101 0.9939 -0.8771 1.3776)" class="st0" width="11" height="1.4"/>
<rect x="6.5" y="10.6" transform="matrix(0.9939 -0.1101 0.1101 0.9939 -1.1681 1.3937)" class="st0" width="11" height="1.4"/>
<rect x="6.5" y="13.2" transform="matrix(0.9939 -0.1101 0.1101 0.9939 -1.4588 1.4055)" class="st0" width="11" height="1.4"/>
<path class="st0" d="M13.3,4c0.1-0.2,0.1-0.3,0.1-0.5c0-0.8-0.6-1.4-1.4-1.4s-1.4,0.6-1.4,1.4c0,0.2,0,0.4,0.1,0.5H5.2v2.3h13.6V4
H13.3z M12,4c-0.3,0-0.6-0.3-0.6-0.6c0-0.3,0.3-0.6,0.6-0.6s0.6,0.3,0.6,0.6C12.6,3.7,12.3,4,12,4z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M3,17.9v1.3c5.9,1.2,12.1,1.2,18,0v-1.3C15.1,19.1,8.9,19.1,3,17.9z"/>
<path class="st0" d="M3,15.9v1.3c5.9,1.2,12.1,1.2,18,0v-1.3C15.1,17.2,8.9,17.2,3,15.9z"/>
<path class="st0" d="M3,14v1.3c5.9,1.2,12.1,1.2,18-0.1v-1.3C15.1,15.2,8.9,15.3,3,14z"/>
<path class="st0" d="M6.5,11.5c0.1,0.1,0.2,0.2,0.4,0.2c0.1,0,0.3-0.1,0.4-0.2l2-2.1c0.2-0.2,0.2-0.5,0-0.8c-0.2-0.2-0.5-0.2-0.7,0
c0,0,0,0,0,0L7.4,9.9V3.3C7.4,3.2,7.3,3,7.2,3c0,0,0,0,0,0H6.7C6.5,3,6.4,3.1,6.4,3.3v0.2v6.4L5.3,8.7C5,8.5,4.7,8.5,4.5,8.7
C4.4,8.8,4.4,8.9,4.3,9.1c0,0.1,0.1,0.3,0.2,0.4L6.5,11.5z"/>
<path class="st0" d="M16.7,11.5c0.1,0.1,0.2,0.2,0.4,0.2c0.1,0,0.3-0.1,0.4-0.2l2-2.1c0.2-0.2,0.2-0.5,0-0.8
c-0.2-0.2-0.5-0.2-0.7,0c0,0,0,0,0,0l-1.1,1.1V3.3c0-0.2-0.1-0.3-0.2-0.3c0,0,0,0,0,0h-0.5c-0.2,0-0.3,0.1-0.3,0.3v0.2v6.4
l-1.1-1.2c-0.2-0.2-0.6-0.2-0.8,0c-0.1,0.1-0.1,0.2-0.1,0.4c0,0.1,0.1,0.3,0.1,0.4L16.7,11.5z"/>
<path class="st0" d="M9.6,11.3l2,2.1c0.1,0.1,0.2,0.2,0.4,0.2c0.1,0,0.3-0.1,0.4-0.2l2-2.1c0.2-0.2,0.2-0.5,0-0.8c0,0,0,0,0,0
c-0.2-0.2-0.5-0.2-0.7,0c0,0,0,0,0,0l-1.1,1.1V5.1c0-0.2-0.1-0.3-0.3-0.3c0,0,0,0,0,0h-0.5c-0.2,0-0.3,0.1-0.3,0.3v0.1v6.4
l-1.1-1.1c-0.2-0.2-0.5-0.2-0.7,0c0,0,0,0,0,0c-0.1,0.1-0.2,0.2-0.2,0.4C9.4,11,9.5,11.2,9.6,11.3z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<path class="st0" d="M12,12.2c-5.9,0-7-1.6-7-1.6v7.2c0.1,1,3,1.9,6.7,1.9V21c0,0.2,0.1,0.3,0.3,0.3s0.3-0.1,0.3-0.3v-1.3
c3.6,0,6.5-0.9,6.7-1.9v-7.2C19,10.6,17.9,12.2,12,12.2z"/>
<path class="st0" d="M12.3,7.6V6.9l0.8,0.4V6.6c2.7-0.1,5.2-0.7,5.2-1.4c0-0.8-2.7-1.2-6-1.2V3c0-0.2-0.1-0.3-0.3-0.3
c-0.2,0-0.3,0.1-0.3,0.3v1c-3.3,0-6,0.4-6,1.2c0,0.2,0.5,0.4,0.8,0.5C7.2,5.9,8,6.1,8.8,6.1c0.3,0,0.5,0,0.8,0C9.4,6,9.2,6,9,6
C7.6,5.9,7.2,5.5,7.2,5.2c0-0.5,1.8-0.7,4.4-0.7v1.1l-1,0.5l1,0.5v1.1C8,7.7,5,8.5,5,9.6c0,1.1,3.1,2,7,2s7-0.9,7-2
C19,8.5,16,7.7,12.3,7.6z M12.3,4.6c2.6,0,4.5,0.2,4.5,0.7c0,0.5-1.7,0.6-3.6,0.7v-1l-0.9,0.4V4.6z M8.4,9.6c0-0.5,1.4-0.9,3.2-1v2
C9.8,10.6,8.4,10.1,8.4,9.6z M12.3,10.6v-2c1.8,0,3.2,0.5,3.2,1C15.6,10.1,14.2,10.6,12.3,10.6z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M19.6,11.7l-2.2-2.2l0,0l-1.7-1.7l0,0h0l0,0l0,0h0l0,0L13.4,10l-0.1,0.1l0,0l0,0l1.7,1.7l0,0l1.6,1.6
c1,0.8,1.1,2.2,0.4,3.2c-0.3,0.3-0.8,0.5-1.2,0.5c-0.7,0-1.5-0.3-2-0.8l-1.6-1.6l0,0L10.5,13l-0.7,0.7l-1.7,1.7l3.9,3.9
c2.2,2,5.6,1.7,7.6-0.5C21.3,16.7,21.3,13.7,19.6,11.7z M18.4,18.5c-1.6,1.4-4.1,1.4-5.7,0l-2.2-2.2l0.9-0.9L13,17
c0.7,0.7,1.7,1.1,2.7,1.1c0.7,0,1.5-0.3,2-0.8c1.2-1.4,1-3.5-0.3-4.7l-1.6-1.6l0.9-0.9l2.2,2.2C20.4,14.2,20.2,16.9,18.4,18.5z"/>
<polygon class="st0" points="6.1,7.5 5.1,7.5 5.1,5.9 3,8 5.1,10.1 5.1,8.5 6.1,8.5 "/>
<polygon class="st0" points="7.5,6.1 8.5,6.1 8.5,5.1 10.1,5.1 8,3 5.9,5.1 7.5,5.1 "/>
<polygon class="st0" points="8.5,11 8.5,10 7.5,10 7.5,10.9 5.9,10.9 8,13 10.1,11 "/>
<polygon class="st0" points="10,7.5 10,8.5 10.9,8.5 10.9,10.1 13,8 10.9,5.9 11,7.5 "/>
<rect x="6.5" y="6.5" class="st0" width="3" height="3"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M19.6,11.7l-2.2-2.2l0,0l-1.7-1.7l0,0h0l0,0l0,0h0l0,0L13.4,10l-0.1,0.1l0,0l0,0l1.7,1.7l0,0l1.6,1.6
c1,0.8,1.1,2.2,0.4,3.2c-0.3,0.3-0.8,0.5-1.2,0.5c-0.7,0-1.5-0.3-2-0.8l-1.6-1.6l0,0L10.5,13l-0.7,0.7l-1.7,1.7l3.9,3.9
c2.2,2,5.6,1.7,7.6-0.5C21.3,16.7,21.3,13.7,19.6,11.7z M18.4,18.5c-1.6,1.4-4.1,1.4-5.7,0l-2.2-2.2l0.9-0.9L13,17
c0.7,0.7,1.7,1.1,2.7,1.1c0.7,0,1.5-0.3,2-0.8c1.2-1.4,1-3.5-0.3-4.7l-1.6-1.6l0.9-0.9l2.2,2.2C20.4,14.2,20.2,16.9,18.4,18.5z"/>
<path class="st0" d="M7.1,9.5l2.1,2.1v-1.2c2.3-0.3,4-1.4,4-3.4c0-2.3-2.2-3.5-5-3.5s-5,1.2-5,3.5c0,0.5,0.2,1.1,0.6,1.5
C4.3,9,5,9.4,5.8,9.5c0.4,0.1,0.6,0.2,0.6,0.1S6.2,9.4,5.9,9.2C5,8.9,4.4,8,4.5,7c0-1.4,1.5-2,3.7-2S12,5.6,12,7
c0,1.2-1.1,2-2.8,2.2V7.4L7.1,9.5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M14.5,11.3L14.5,11.3c-0.1,0-0.2,0-0.3,0.1c-0.2,0.1-0.4,0.2-0.6,0.4c-0.5,0.4-1,0.6-1.6,0.7
c-0.6-0.1-1.2-0.4-1.6-0.7c-0.2-0.1-0.4-0.3-0.6-0.4c-0.1,0-0.2-0.1-0.3-0.1H9.5c-2.4,0-3,1-3,1c-0.1,0.2-0.2,0.3-0.3,0.5v1.5
c0,0.4,0.5,0.8,0.5,0.8l1.6,1.6c0.5,0.5,0.8,1.3,0.9,2V21c0,0.4,0.3,0.7,0.7,0.7c0,0,0,0,0,0h4.1c0.4,0,0.7-0.3,0.7-0.7
c0,0,0,0,0,0v-2.3c0-0.7,0.3-1.5,0.9-2l1.6-1.6c0,0,0.5-0.4,0.5-0.8v-1.5c-0.1-0.2-0.2-0.4-0.3-0.5C17.5,12.3,16.9,11.3,14.5,11.3z
"/>
<path class="st0" d="M9.5,10.3c0.2,0,0.3,0.1,0.5,0.1c0.6,0.3,1.3,1.1,2.1,1.1s1.5-0.8,2.1-1.1c0.1-0.1,0.3-0.1,0.5-0.1
c2.7,0,3.3,1.1,3.3,1.1V11c0-0.6-0.3-1.2-0.7-1.7l-1.5-1.6c-0.5-0.7-0.7-1.5-0.7-2.4V3c0-0.6-0.4-1-1-1h-3.8c-0.6,0-1,0.4-1,1v2.3
C9.1,6.2,8.9,7,8.4,7.7L6.9,9.3C6.5,9.7,6.2,10.4,6.2,11v0.5C6.2,11.5,6.8,10.3,9.5,10.3z"/>
<path class="st0" d="M19.6,7.8c-0.1-0.2-0.3-0.2-0.5-0.1C19,7.7,18.9,7.9,19,8.1c1.4,2.5,1.4,5.4,0,7.9c0,0,0,0,0,0
c-0.1,0.2,0,0.4,0.1,0.4c0.1,0,0.1,0,0.2,0c0.1,0,0.2,0,0.3-0.1C21.1,13.7,21.1,10.4,19.6,7.8z"/>
<path class="st0" d="M4.1,11.7c0-1.2,0.3-2.4,0.8-3.4c0.1-0.2,0-0.4-0.2-0.4C4.5,7.8,4.3,7.8,4.3,8c-1.2,2.5-1.1,5.4,0.2,7.8
C4.5,15.9,4.6,16,4.7,16c0,0,0.1,0,0.1,0c0,0,0,0,0,0C5,15.9,5.1,15.7,5,15.5C4.4,14.3,4.1,13,4.1,11.7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M19.3,10.7l0.1-2.5c0-0.2-0.2-0.4-0.4-0.4c-0.3,0-0.5,0.2-0.5,0.5l-0.1,1.6L18,9.5l0,0
c-0.1-0.1-0.2-0.2-0.2-0.2c-0.4-0.4-0.9-0.7-1.3-0.9L17,6.7c0.1-0.3,0-0.6-0.3-0.7c0,0-0.1,0-0.1,0l-3.1-0.6
c-0.3-0.1-0.6,0.1-0.7,0.4c0,0,0,0.1,0,0.1l-0.1,1.4C10.3,7,7.9,7.8,6,9.5l0,0L5.6,9.8V8.2c0-0.3-0.2-0.5-0.5-0.5c0,0,0,0,0,0
c-0.2,0-0.5,0.2-0.5,0.4c0,0,0,0,0,0v2.5c0,0.3,0.2,0.5,0.5,0.5l2.5,0.1c0.3,0,0.5-0.2,0.5-0.5c0-0.3-0.2-0.5-0.5-0.5l-1.5-0.1
C6.3,10,6.4,9.8,6.6,9.7c1.8-1.5,4-2.1,6.1-1.9l-0.1,1.9c0,0.4,0.3,0.7,0.6,0.8l0.3,0.1l-1.8,9.2c-0.6,0.1-1.1,0.6-1.1,1.2
c0,0.7,0.6,1.3,1.3,1.3s1.3-0.6,1.3-1.3c0-0.4-0.2-0.8-0.6-1l1.8-9.2l0.3,0.1c0.4,0.1,0.7-0.1,0.9-0.5l0.5-1.4
c0.6,0.3,1.1,0.7,1.6,1.2l0.1,0.1c0,0,0.1,0.1,0.1,0.1h-1.6c-0.1,0-0.3,0-0.3,0.1c-0.1,0.1-0.1,0.2-0.2,0.3c0,0.2,0.2,0.4,0.4,0.5
c0,0,0,0,0,0h2.5C19.1,11.2,19.3,11,19.3,10.7z"/>
<path class="st0" d="M2.8,10.1c-0.1-0.1-0.3-0.1-0.4,0c-0.1,0.1-0.1,0.3,0,0.4l2.9,2.7c0.1,0,0.1,0.1,0.2,0.1c0.1,0,0.2,0,0.2-0.1
c0.1-0.1,0.1-0.3,0-0.4L2.8,10.1z"/>
<path class="st0" d="M21.5,10c-0.1-0.1-0.3-0.1-0.4,0l-2.7,2.9c0,0.1-0.1,0.1-0.1,0.2c0,0.1,0,0.1,0.1,0.2c0.1,0.1,0.3,0.1,0.4,0
l2.6-2.9C21.6,10.3,21.6,10.1,21.5,10z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M17.5,18.1c-0.1,0-0.1,0-0.2,0H6.9l7.4-7.3c0.3-0.2,0.3-0.6,0-0.9c0,0,0,0,0,0c-0.1-0.1-0.3-0.2-0.5-0.2
c-0.2,0-0.3,0.1-0.5,0.2L6,17.2V6.9c0-0.4-0.3-0.7-0.7-0.7C5,6.2,4.7,6.5,4.7,6.9c0,0,0,0,0,0L4.6,17.1c0,0,0,0,0,0
c-1.3,0-2.3,1-2.3,2.3s1,2.3,2.3,2.3s2.3-1,2.3-2.3h10.4c0.4,0,0.7-0.2,0.7-0.6C18.1,18.5,17.9,18.1,17.5,18.1z"/>
<path class="st0" d="M21.8,13.2c-0.2-0.2-0.6-0.2-0.9,0l-1.3,1.3V14c-0.1-5.2-4.3-9.4-9.5-9.4H9.6l1.3-1.2c0.2-0.2,0.2-0.6,0-0.9
c-0.1-0.1-0.3-0.2-0.4-0.2c-0.2,0-0.3,0.1-0.4,0.2L7.7,4.8C7.6,4.9,7.5,5.1,7.5,5.2c0,0.2,0.1,0.3,0.2,0.4l2.3,2.3
c0.2,0.2,0.6,0.2,0.9,0c0.2-0.2,0.2-0.6,0-0.8L9.6,5.8h0.5c4.6,0,8.3,3.6,8.3,8.2c0,0,0,0,0,0v0.5l-1.3-1.3
c-0.1-0.1-0.3-0.2-0.4-0.2c-0.2,0-0.3,0.1-0.4,0.2c-0.2,0.2-0.2,0.6,0,0.8c0,0,0,0,0,0l2.4,2.3c0.2,0.2,0.6,0.2,0.9,0l2.3-2.3
C22.1,13.8,22.1,13.4,21.8,13.2z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -390,6 +390,14 @@
<file>img/UI20/toolbar/Y_axis.svg</file>
<file>img/UI20/toolbar/Z_axis.svg</file>
<file>img/UI20/toolbar/XY2_copy.svg</file>
<file>img/UI20/toolbar/joints/Damping.svg</file>
<file>img/UI20/toolbar/joints/MaxForce.svg</file>
<file>img/UI20/toolbar/joints/MaxTorque.svg</file>
<file>img/UI20/toolbar/joints/SnapPosition.svg</file>
<file>img/UI20/toolbar/joints/SnapRotation.svg</file>
<file>img/UI20/toolbar/joints/Stiffness.svg</file>
<file>img/UI20/toolbar/joints/SwingLimits.svg</file>
<file>img/UI20/toolbar/joints/TwistLimits.svg</file>
<file>img/triangle0.png</file>
<file>img/triangle0_highlighted.png</file>
<file>img/line.png</file>
@@ -20,7 +20,7 @@ AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option")
AZ_POP_DISABLE_WARNING
AZ_CVAR(
bool, ed_useNewAssetBrowserTableView, false, nullptr, AZ::ConsoleFunctorFlags::Null,
bool, ed_useNewAssetBrowserTableView, true, nullptr, AZ::ConsoleFunctorFlags::Null,
"Use the new AssetBrowser TableView for searching assets.");
namespace AzToolsFramework
{
@@ -29,7 +29,7 @@ AZ_PUSH_DISABLE_WARNING(4251 4244, "-Wunknown-warning-option") // disable warnin
AZ_POP_DISABLE_WARNING
AZ_CVAR(
bool, ed_hideAssetPickerPathColumn, false, nullptr, AZ::ConsoleFunctorFlags::Null,
bool, ed_hideAssetPickerPathColumn, true, nullptr, AZ::ConsoleFunctorFlags::Null,
"Hide AssetPicker path column for a clearer view.");
AZ_CVAR_EXTERNED(bool, ed_useNewAssetBrowserTableView);
@@ -8,8 +8,9 @@
#include "ComponentModeCollection.h"
#include <AzToolsFramework/Commands/ComponentModeCommand.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
#include <AzToolsFramework/Commands/ComponentModeCommand.h>
namespace AzToolsFramework
{
@@ -17,7 +18,7 @@ namespace AzToolsFramework
{
AZ_CLASS_ALLOCATOR_IMPL(ComponentModeCollection, AZ::SystemAllocator, 0)
static const char* const s_nextActiveComponentModeTitle = "Edit Next";
static const char* const s_nextActiveComponentModeTitle = "Edit Next";
static const char* const s_previousActiveComponentModeTitle = "Edit Previous";
static const char* const s_nextActiveComponentModeDesc = "Move to the next component";
static const char* const s_prevActiveComponentModeDesc = "Move to the previous component";
@@ -119,6 +120,11 @@ namespace AzToolsFramework
}
};
ComponentModeCollection::ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
: m_viewportEditorModeTracker(viewportEditorModeTracker)
{
}
void ComponentModeCollection::AddComponentMode(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid componentType,
const ComponentModeFactoryFunction& componentModeBuilder)
@@ -209,6 +215,11 @@ namespace AzToolsFramework
GetEntityContextId(), &EditorComponentModeNotifications::EnteredComponentMode,
m_activeComponentTypes);
// this call to activate the component mode editor state should eventually replace the bus call in
// ComponentModeCollection::BeginComponentMode() to EditorComponentModeNotifications::EnteredComponentMode
// such that all of the notifications for activating/deactivating the different editor modes are in a central location
m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component);
// enable actions for the first/primary ComponentMode
// note: if multiple ComponentModes are activated at the same time, actions
// are not available together, the 'active' mode will bind its actions one at a time
@@ -282,6 +293,10 @@ namespace AzToolsFramework
&EditorComponentModeNotifications::LeftComponentMode,
m_activeComponentTypes);
// this call to deactivate the component mode editor state should eventually replace the bus call in
// ComponentModeCollection::EndComponentMode() to EditorComponentModeNotifications::LeftComponentMode
// such that all of the notifications for activating/deactivating the different editor modes are in a central location
m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Component);
// clear stored modes and builders for this ComponentMode
// TLDR: avoid 'use after free' error
@@ -15,6 +15,7 @@
namespace AzToolsFramework
{
class EditorMetricsEventsBusTraits;
class ViewportEditorModeTrackerInterface;
namespace ComponentModeFramework
{
@@ -25,7 +26,7 @@ namespace AzToolsFramework
AZ_CLASS_ALLOCATOR_DECL
/// @cond
ComponentModeCollection() = default;
explicit ComponentModeCollection(ViewportEditorModeTrackerInterface* viewportEditorModeTracker);
~ComponentModeCollection() = default;
ComponentModeCollection(const ComponentModeCollection&) = delete;
ComponentModeCollection& operator=(const ComponentModeCollection&) = delete;
@@ -101,6 +102,7 @@ namespace AzToolsFramework
size_t m_selectedComponentModeIndex = 0; ///< Index into the array of active ComponentModes, current index is 'selected' ComponentMode.
bool m_adding = false; ///< Are we currently adding individual ComponentModes to the Editor wide ComponentMode.
bool m_componentMode = false; ///< Editor (global) ComponentMode flag - is ComponentMode active or not.
ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes.
};
} // namespace ComponentModeFramework
} // namespace AzToolsFramework
@@ -119,11 +119,12 @@ namespace AzToolsFramework
// replace the default input handler with one specific for dealing with
// entity selection in the viewport
EditorInteractionSystemViewportSelectionRequestBus::Event(
GetEntityContextId(), &EditorInteractionSystemViewportSelection::SetHandler,
[](const EditorVisibleEntityDataCache* entityDataCache)
[](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<EditorPickEntitySelection>(entityDataCache);
return AZStd::make_unique<EditorPickEntitySelection>(entityDataCache, viewportEditorModeTracker);
});
if (!pickModeEntityContextId.IsNull())
@@ -22,6 +22,7 @@
#include <AZTestShared/Math/MathTestHelpers.h>
#include <AZTestShared/Utils/Utils.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Entity/EditorEntityTransformBus.h>
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
@@ -166,11 +167,12 @@ namespace UnitTest
m_editorActions.Connect();
const auto viewportHandlerBuilder =
[this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache)
[this](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
// create the default viewport (handles ComponentMode)
AZStd::unique_ptr<AzToolsFramework::EditorDefaultSelection> defaultSelection =
AZStd::make_unique<AzToolsFramework::EditorDefaultSelection>(entityDataCache);
AZStd::make_unique<AzToolsFramework::EditorDefaultSelection>(entityDataCache, viewportEditorModeTracker);
// override the phantom widget so we can use out custom test widget
defaultSelection->SetOverridePhantomWidget(&m_editorActions.m_componentModeWidget);
@@ -9,6 +9,7 @@
#include "EditorDefaultSelection.h"
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
@@ -19,21 +20,26 @@ namespace AzToolsFramework
{
AZ_CLASS_ALLOCATOR_IMPL(EditorDefaultSelection, AZ::SystemAllocator, 0)
EditorDefaultSelection::EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache)
EditorDefaultSelection::EditorDefaultSelection(
const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
: m_phantomWidget(nullptr)
, m_entityDataCache(entityDataCache)
, m_viewportEditorModeTracker(viewportEditorModeTracker)
, m_componentModeCollection(viewportEditorModeTracker)
{
ActionOverrideRequestBus::Handler::BusConnect(GetEntityContextId());
ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusConnect();
m_manipulatorManager = AZStd::make_shared<AzToolsFramework::ManipulatorManager>(AzToolsFramework::g_mainManipulatorManagerId);
m_transformComponentSelection = AZStd::make_unique<EditorTransformComponentSelection>(entityDataCache);
m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default);
}
EditorDefaultSelection::~EditorDefaultSelection()
{
ComponentModeFramework::ComponentModeSystemRequestBus::Handler::BusDisconnect();
ActionOverrideRequestBus::Handler::BusDisconnect();
m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Default);
}
void EditorDefaultSelection::SetOverridePhantomWidget(QWidget* phantomOverrideWidget)
@@ -15,6 +15,8 @@
namespace AzToolsFramework
{
class ViewportEditorModeTrackerInterface;
//! The default selection/input handler for the editor (includes handling ComponentMode).
class EditorDefaultSelection
: public ViewportInteraction::InternalViewportSelectionRequests
@@ -25,7 +27,7 @@ namespace AzToolsFramework
AZ_CLASS_ALLOCATOR_DECL
//! @cond
explicit EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache);
EditorDefaultSelection(const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker);
EditorDefaultSelection(const EditorDefaultSelection&) = delete;
EditorDefaultSelection& operator=(const EditorDefaultSelection&) = delete;
virtual ~EditorDefaultSelection();
@@ -110,5 +112,7 @@ namespace AzToolsFramework
AZStd::shared_ptr<AzToolsFramework::ManipulatorManager> m_manipulatorManager; //!< The default manipulator manager.
ViewportInteraction::MouseInteraction m_currentInteraction; //!< Current mouse interaction to be used for drawing manipulators.
ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes.
};
} // namespace AzToolsFramework
@@ -10,9 +10,24 @@
#include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
#include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
#include <AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h>
namespace AzToolsFramework
{
EditorInteractionSystemComponent::EditorInteractionSystemComponent()
: m_viewportEditorMode(AZStd::make_unique<ViewportEditorModeTracker>())
{
AZ_Assert(AZ::Interface<ViewportEditorModeTrackerInterface>::Get() == nullptr, "Unexpected registration of viewport editor mode tracker.")
AZ::Interface<ViewportEditorModeTrackerInterface>::Register(m_viewportEditorMode.get());
}
EditorInteractionSystemComponent::~EditorInteractionSystemComponent()
{
m_interactionRequests.reset();
AZ_Assert(AZ::Interface<ViewportEditorModeTrackerInterface>::Get() != nullptr, "Unexpected unregistration of viewport editor mode tracker.")
AZ::Interface<ViewportEditorModeTrackerInterface>::Unregister(m_viewportEditorMode.get());
}
void EditorInteractionSystemComponent::Activate()
{
EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId());
@@ -41,7 +56,8 @@ namespace AzToolsFramework
return m_interactionRequests->InternalHandleMouseManipulatorInteraction(mouseInteraction);
}
void EditorInteractionSystemComponent::SetHandler(const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder)
void EditorInteractionSystemComponent::SetHandler(
const ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder)
{
// when setting a handler, make sure we're connected to the ViewportDebugDisplayEventBus so we
// can forward calls to the specific type implementing ViewportSelectionRequests
@@ -59,7 +75,7 @@ namespace AzToolsFramework
m_entityDataCache = AZStd::make_unique<EditorVisibleEntityDataCache>();
m_interactionRequests.reset(); // BusConnect/Disconnect in constructor/destructor,
// so have to reset before assigning the new one
m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get());
m_interactionRequests = interactionRequestsBuilder(m_entityDataCache.get(), m_viewportEditorMode.get());
}
EditorInteractionSystemViewportSelectionRequestBus::Handler::BusConnect(GetEntityContextId());
@@ -68,9 +84,9 @@ namespace AzToolsFramework
void EditorInteractionSystemComponent::SetDefaultHandler()
{
SetHandler(
[](const EditorVisibleEntityDataCache* entityDataCache)
[](const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<EditorDefaultSelection>(entityDataCache);
return AZStd::make_unique<EditorDefaultSelection>(entityDataCache, viewportEditorModeTracker);
});
}
@@ -14,6 +14,8 @@
namespace AzToolsFramework
{
class ViewportEditorModeTracker;
//! System Component to wrap active input handler.
//! EditorInteractionSystemComponent is notified of viewport mouse events from RenderViewport
//! and forwards them to a concrete implementation of ViewportSelectionRequests.
@@ -26,6 +28,9 @@ namespace AzToolsFramework
public:
AZ_COMPONENT(EditorInteractionSystemComponent, "{146D0317-AF42-45AB-A953-F54198525DD5}")
EditorInteractionSystemComponent();
~EditorInteractionSystemComponent();
static void Reflect(AZ::ReflectContext* context);
// EditorInteractionSystemViewportSelectionRequestBus
@@ -54,5 +59,7 @@ namespace AzToolsFramework
AZStd::unique_ptr<InternalViewportSelectionRequests> m_interactionRequests; //!< Hold a concrete implementation of
//!< ViewportSelectionRequests to handle viewport
//!< input and drawing for the Editor.
AZStd::unique_ptr<ViewportEditorModeTracker> m_viewportEditorMode; //!< Editor mode tracker for each viewport.
};
} // namespace AzToolsFramework
@@ -17,6 +17,7 @@
namespace AzToolsFramework
{
class EditorVisibleEntityDataCache;
class ViewportEditorModeTrackerInterface;
//! Bus to handle all mouse events originating from the viewport.
//! Coordinated by the EditorInteractionSystemComponent
@@ -32,8 +33,8 @@ namespace AzToolsFramework
};
//! Alias for factory function to create a new type implementing the ViewportSelectionRequests interface.
using ViewportSelectionRequestsBuilderFn =
AZStd::function<AZStd::unique_ptr<ViewportInteraction::InternalViewportSelectionRequests>(const EditorVisibleEntityDataCache*)>;
using ViewportSelectionRequestsBuilderFn = AZStd::function<AZStd::unique_ptr<ViewportInteraction::InternalViewportSelectionRequests>(
const EditorVisibleEntityDataCache*, ViewportEditorModeTrackerInterface*)>;
//! Interface for system component implementing the ViewportSelectionRequests interface.
//! This interface also includes a setter to set a custom handler also implementing
@@ -8,6 +8,7 @@
#include "EditorPickEntitySelection.h"
#include <AzToolsFramework/API/ViewportEditorModeTrackerInterface.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <QApplication>
@@ -15,9 +16,12 @@ namespace AzToolsFramework
{
AZ_CLASS_ALLOCATOR_IMPL(EditorPickEntitySelection, AZ::SystemAllocator, 0)
EditorPickEntitySelection::EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache)
EditorPickEntitySelection::EditorPickEntitySelection(
const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
: m_editorHelpers(AZStd::make_unique<EditorHelpers>(entityDataCache))
, m_viewportEditorModeTracker(viewportEditorModeTracker)
{
m_viewportEditorModeTracker->ActivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick);
}
EditorPickEntitySelection::~EditorPickEntitySelection()
@@ -26,6 +30,8 @@ namespace AzToolsFramework
{
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetEntityHighlighted, m_hoveredEntityId, false);
}
m_viewportEditorModeTracker->DeactivateMode({ /* DefaultViewportId */ }, ViewportEditorMode::Pick);
}
// note: entityIdUnderCursor is the authoritative entityId we get each frame by querying
@@ -13,6 +13,8 @@
namespace AzToolsFramework
{
class ViewportEditorModeTrackerInterface;
//! Viewport interaction that will handle assigning an entity in the viewport to
//! an entity field in the entity inspector.
class EditorPickEntitySelection : public ViewportInteraction::InternalViewportSelectionRequests
@@ -20,7 +22,8 @@ namespace AzToolsFramework
public:
AZ_CLASS_ALLOCATOR_DECL
EditorPickEntitySelection(const EditorVisibleEntityDataCache* entityDataCache);
EditorPickEntitySelection(
const EditorVisibleEntityDataCache* entityDataCache, ViewportEditorModeTrackerInterface* viewportEditorModeTracker);
~EditorPickEntitySelection();
private:
@@ -32,5 +35,6 @@ namespace AzToolsFramework
AZStd::unique_ptr<EditorHelpers> m_editorHelpers; //!< Editor visualization of entities (icons, shapes, debug visuals etc).
AZ::EntityId m_hoveredEntityId; //!< What EntityId is the mouse currently hovering over (if any).
AZ::EntityId m_cachedEntityIdUnderCursor; //!< Store the EntityId on each mouse move for use in Display.
ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr; //!< Tracker for activating/deactivating viewport editor modes.
};
} // namespace AzToolsFramework
@@ -45,22 +45,6 @@ namespace AzToolsFramework
return m_editorModes[static_cast<AZ::u32>(mode)];
}
void ViewportEditorModeTracker::RegisterInterface()
{
if (AZ::Interface<ViewportEditorModeTrackerInterface>::Get() == nullptr)
{
AZ::Interface<ViewportEditorModeTrackerInterface>::Register(this);
}
}
void ViewportEditorModeTracker::UnregisterInterface()
{
if (AZ::Interface<ViewportEditorModeTrackerInterface>::Get() != nullptr)
{
AZ::Interface<ViewportEditorModeTrackerInterface>::Unregister(this);
}
}
AZ::Outcome<void, AZStd::string> ViewportEditorModeTracker::ActivateMode(
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode)
{
@@ -41,12 +41,6 @@ namespace AzToolsFramework
: public ViewportEditorModeTrackerInterface
{
public:
//! Registers this object with the AZ::Interface.
void RegisterInterface();
//! Unregisters this object with the AZ::Interface.
void UnregisterInterface();
// ViewportEditorModeTrackerInterface overrides ...
AZ::Outcome<void, AZStd::string> ActivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override;
AZ::Outcome<void, AZStd::string> DeactivateMode(const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) override;
@@ -29,13 +29,29 @@ namespace AzToolsFramework::ViewportUi::Internal
void ButtonGroup::SetHighlightedButton(ButtonId buttonId)
{
if (buttonId == m_highlightedButtonId) // the requested button is highlighted, so do nothing.
{
return;
}
if (auto buttonEntry = m_buttons.find(buttonId); buttonEntry != m_buttons.end())
{
for (auto& button : m_buttons)
{
button.second->m_state = Button::State::Deselected;
}
ClearHighlightedButton();
buttonEntry->second->m_state = Button::State::Selected;
m_highlightedButtonId = buttonId;
}
}
void ButtonGroup::ClearHighlightedButton()
{
if (m_highlightedButtonId == InvalidButtonId)
{
return;
}
if (auto buttonEntry = m_buttons.find(m_highlightedButtonId); buttonEntry != m_buttons.end())
{
buttonEntry->second->m_state = Button::State::Deselected;
m_highlightedButtonId = InvalidButtonId;
}
}
@@ -25,6 +25,7 @@ namespace AzToolsFramework::ViewportUi::Internal
~ButtonGroup() = default;
void SetHighlightedButton(ButtonId buttonId);
void ClearHighlightedButton();
void SetViewportUiElementId(ViewportUiElementId id);
ViewportUiElementId GetViewportUiElementId() const;
@@ -40,5 +41,6 @@ namespace AzToolsFramework::ViewportUi::Internal
AZ::Event<ButtonId> m_buttonTriggeredEvent;
ViewportUiElementId m_viewportUiId;
AZStd::unordered_map<ButtonId, AZStd::unique_ptr<Button>> m_buttons;
ButtonId m_highlightedButtonId = InvalidButtonId;
};
} // namespace AzToolsFramework::ViewportUi::Internal
@@ -50,6 +50,16 @@ namespace AzToolsFramework::ViewportUi
}
}
void ViewportUiManager::ClearClusterActiveButton(ClusterId clusterId)
{
if (auto clusterIt = m_clusterButtonGroups.find(clusterId); clusterIt != m_clusterButtonGroups.end())
{
auto cluster = clusterIt->second;
cluster->ClearHighlightedButton();
UpdateButtonGroupUi(cluster.get());
}
}
void ViewportUiManager::SetSwitcherActiveButton(const SwitcherId switcherId, const ButtonId buttonId)
{
if (auto switcherIt = m_switcherButtonGroups.find(switcherId); switcherIt != m_switcherButtonGroups.end())
@@ -30,6 +30,7 @@ namespace AzToolsFramework::ViewportUi
const ClusterId CreateCluster(Alignment align) override;
const SwitcherId CreateSwitcher(Alignment align) override;
void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) override;
void ClearClusterActiveButton(ClusterId clusterId) override;
void SetSwitcherActiveButton(SwitcherId switcherId, ButtonId buttonId) override;
void SetClusterButtonLocked(ClusterId clusterId, ButtonId buttonId, bool isLocked) override;
void SetClusterButtonTooltip(ClusterId clusterId, ButtonId buttonId, const AZStd::string& tooltip) override;
@@ -59,6 +59,8 @@ namespace AzToolsFramework::ViewportUi
virtual const SwitcherId CreateSwitcher(Alignment align) = 0;
//! Sets the active button of the cluster. This is the button which will display as highlighted.
virtual void SetClusterActiveButton(ClusterId clusterId, ButtonId buttonId) = 0;
//! Clears the active button of the cluster if one is active. The button will no longer display as highlighted.
virtual void ClearClusterActiveButton(ClusterId clusterId) = 0;
//! Sets the active button of the switcher. This is the button which has a text label.
virtual void SetSwitcherActiveButton(SwitcherId clusterId, ButtonId buttonId) = 0;
//! Adds a locked overlay to the cluster button's icon.
@@ -344,9 +344,10 @@ namespace UnitTest
using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler,
[](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache)
[](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<AzToolsFramework::EditorPickEntitySelection>(entityDataCache);
return AZStd::make_unique<AzToolsFramework::EditorPickEntitySelection>(entityDataCache, viewportEditorModeTracker);
});
// When
@@ -7,7 +7,9 @@
*/
#include <AzTest/AzTest.h>
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorPickEntitySelection.h>
#include <AzToolsFramework/ViewportSelection/ViewportEditorModeTracker.h>
namespace UnitTest
@@ -18,6 +20,7 @@ namespace UnitTest
using ViewportEditorModeInfo = AzToolsFramework::ViewportEditorModeInfo;
using ViewportId = ViewportEditorModeInfo::IdType;
using ViewportEditorModesInterface = AzToolsFramework::ViewportEditorModesInterface;
using ViewportEditorModeTrackerInterface = AzToolsFramework::ViewportEditorModeTrackerInterface;
void ActivateModeAndExpectSuccess(ViewportEditorModes& editorModeState, ViewportEditorMode mode)
{
@@ -47,6 +50,26 @@ namespace UnitTest
}
}
void ExpectOnlyModeActive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode)
{
for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++)
{
const auto currentMode = static_cast<ViewportEditorMode>(modeIndex);
const bool expectedActive = (mode == currentMode);
EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive);
}
}
void ExpectOnlyModeInactive(const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode)
{
for (auto modeIndex = 0; modeIndex < ViewportEditorModes::NumEditorModes; modeIndex++)
{
const auto currentMode = static_cast<ViewportEditorMode>(modeIndex);
const bool expectedActive = (mode != currentMode);
EXPECT_EQ(editorModeState.IsModeActive(currentMode), expectedActive);
}
}
// Fixture for testing editor mode states
class ViewportEditorModesTestsFixture
: public ::testing::Test
@@ -116,7 +139,7 @@ namespace UnitTest
m_editorModes[mode].m_onEnter = true;
}
virtual void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override
void OnEditorModeDeactivated([[maybe_unused]] const ViewportEditorModesInterface& editorModeState, ViewportEditorMode mode) override
{
m_editorModes[mode].m_onExit = true;
}
@@ -152,6 +175,22 @@ namespace UnitTest
AZStd::array<AZStd::unique_ptr<ViewportEditorModeNotificationsBusHandler>, ViewportEditorModes::NumEditorModes> m_editorModeHandlers;
};
// Fixture for testing the integration of viewport editor mode state tracker
class ViewportEditorModeTrackerIntegrationTestFixture
: public ToolsApplicationFixture
{
public:
void SetUpEditorFixtureImpl() override
{
m_viewportEditorModeTracker = AZ::Interface<ViewportEditorModeTrackerInterface>::Get();
ASSERT_NE(m_viewportEditorModeTracker, nullptr);
m_viewportEditorModes = m_viewportEditorModeTracker->GetViewportEditorModes({});
}
ViewportEditorModeTrackerInterface* m_viewportEditorModeTracker = nullptr;
const ViewportEditorModesInterface* m_viewportEditorModes = nullptr;
};
TEST_F(ViewportEditorModesTestsFixture, NumberOfEditorModesIsEqualTo4)
{
EXPECT_EQ(ViewportEditorModes::NumEditorModes, 4);
@@ -168,38 +207,14 @@ namespace UnitTest
TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeActiveActivatesOnlyThatMode)
{
ActivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode);
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
{
const auto editorMode = static_cast<ViewportEditorMode>(mode);
if (editorMode == m_selectedEditorMode)
{
EXPECT_TRUE(m_editorModes.IsModeActive(static_cast<ViewportEditorMode>(editorMode)));
}
else
{
EXPECT_FALSE(m_editorModes.IsModeActive(static_cast<ViewportEditorMode>(editorMode)));
}
}
ExpectOnlyModeActive(m_editorModes, m_selectedEditorMode);
}
TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingModeInactiveInactivatesOnlyThatMode)
{
SetAllModesActive(m_editorModes);
DeactivateModeAndExpectSuccess(m_editorModes, m_selectedEditorMode);
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
{
const auto editorMode = static_cast<ViewportEditorMode>(mode);
if (editorMode == m_selectedEditorMode)
{
EXPECT_FALSE(m_editorModes.IsModeActive(editorMode));
}
else
{
EXPECT_TRUE(m_editorModes.IsModeActive(editorMode));
}
}
ExpectOnlyModeInactive(m_editorModes, m_selectedEditorMode);
}
TEST_P(ViewportEditorModesTestsFixtureWithParams, SettingMultipleModesActiveActivatesAllThoseModesNonMutuallyExclusively)
@@ -298,7 +313,7 @@ namespace UnitTest
EXPECT_EQ(m_viewportEditorModeTracker.GetTrackedViewportCount(), 0);
}
TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId)
TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatId)
{
// Given a viewport not currently being tracked
const ViewportId viewportid = 0;
@@ -318,7 +333,7 @@ namespace UnitTest
EXPECT_TRUE(viewportEditorModeState->IsModeActive(editorMode));
}
TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError)
TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModeForNonExistentIdCreatesViewportEditorModesForThatIdButReturnsError)
{
// Given a viewport not currently being tracked
const ViewportId viewportid = 0;
@@ -351,7 +366,7 @@ namespace UnitTest
EXPECT_EQ(m_viewportEditorModeTracker.GetViewportEditorModes({ viewportid }), nullptr);
}
TEST_F(ViewportEditorModeTrackerTestFixture, RegisteringViewportEditorModesForExistingIdInThatStateReturnsError)
TEST_F(ViewportEditorModeTrackerTestFixture, ActivatingViewportEditorModesForExistingIdInThatStateReturnsError)
{
// Given a viewport not currently tracked
const ViewportId viewportid = 0;
@@ -390,7 +405,7 @@ namespace UnitTest
}
}
TEST_F(ViewportEditorModeTrackerTestFixture, UnregisteringViewportEditorModesForExistingIdNotInThatStateReturnssError)
TEST_F(ViewportEditorModeTrackerTestFixture, DeactivatingViewportEditorModesForExistingIdNotInThatStateReturnssError)
{
// Given a viewport not currently tracked
const ViewportId viewportid = 0;
@@ -432,7 +447,7 @@ namespace UnitTest
TEST_F(
ViewportEditorModePublisherTestFixture,
RegisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeRegisterEventForAllSubscribers)
ActivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeActivateEventForAllSubscribers)
{
// Given a set of subscribers tracking the editor modes for their exclusive viewport
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
@@ -465,7 +480,7 @@ namespace UnitTest
TEST_F(
ViewportEditorModePublisherTestFixture,
UnregisteringViewportEditorModesForExistingIdPublishesOnViewportEditorModeUnregisterEventForAllSubscribers)
DeactivatingViewportEditorModesForExistingIdPublishesOnViewportEditorModeDeactivatingEventForAllSubscribers)
{
// Given a set of subscribers tracking the editor modes for their exclusive viewport
for (auto mode = 0; mode < ViewportEditorModes::NumEditorModes; mode++)
@@ -495,4 +510,54 @@ namespace UnitTest
EXPECT_TRUE(expectedEditorModeSet->second.m_onExit);
}
}
TEST_F(ViewportEditorModeTrackerIntegrationTestFixture, InitialViewportEditorModeIsDefault)
{
ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Default);
}
TEST_F(
ViewportEditorModeTrackerIntegrationTestFixture, EnteringComponentModeAfterInitialStateHasViewportEditorModesDefaultAndComponentModeActive)
{
// When component mode is entered
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::BeginComponentMode,
AZStd::vector<AzToolsFramework::ComponentModeFramework::EntityAndComponentModeBuilders>{});
bool inComponentMode = false;
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::BroadcastResult(
inComponentMode, &AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::InComponentMode);
// Expect to be in component mode
EXPECT_TRUE(inComponentMode);
// Expect the default and component viewport editor modes to be active
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Default));
EXPECT_TRUE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Component));
// Do not expect the pick and focus viewport editor modes to be active
EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Pick));
EXPECT_FALSE(m_viewportEditorModes->IsModeActive(ViewportEditorMode::Focus));
}
TEST_F(
ViewportEditorModeTrackerIntegrationTestFixture,
EnteringEditorPickEntitySelectionAfterInitialStateHasOnlyViewportEditorModePickModeActive)
{
// When entering pick mode
using AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus;
EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(), &EditorInteractionSystemViewportSelectionRequestBus::Events::SetHandler,
[](const AzToolsFramework::EditorVisibleEntityDataCache* entityDataCache,
[[maybe_unused]] AzToolsFramework::ViewportEditorModeTrackerInterface* viewportEditorModeTracker)
{
return AZStd::make_unique<AzToolsFramework::EditorPickEntitySelection>(entityDataCache, viewportEditorModeTracker);
});
// Expect only the pick viewport editor mode to be active
ExpectOnlyModeActive(*m_viewportEditorModes, ViewportEditorMode::Pick);
}
// FocusMode integration tests will follow (LYN-6995)
} // namespace UnitTest
@@ -127,6 +127,25 @@ namespace UnitTest
EXPECT_TRUE(button->m_state == AzToolsFramework::ViewportUi::Internal::Button::State::Selected);
}
TEST_F(ViewportUiManagerTestFixture, ClearClusterActiveButtonSetsButtonStateToDeselected)
{
// setup
auto clusterId = m_viewportManagerWrapper.GetViewportManager()->CreateCluster(AzToolsFramework::ViewportUi::Alignment::TopLeft);
auto buttonId = m_viewportManagerWrapper.GetViewportManager()->CreateClusterButton(clusterId, "");
auto clusterEntry = m_viewportManagerWrapper.GetViewportManager()->GetClusterMap().find(clusterId);
auto button = clusterEntry->second->GetButton(buttonId);
// first set a button to active
m_viewportManagerWrapper.GetViewportManager()->SetClusterActiveButton(clusterId, buttonId);
EXPECT_TRUE(button->m_state == AzToolsFramework::ViewportUi::Internal::Button::State::Selected);
// clear the active button on the cluster
m_viewportManagerWrapper.GetViewportManager()->ClearClusterActiveButton(clusterId);
// the button should now be deselected
EXPECT_TRUE(button->m_state == AzToolsFramework::ViewportUi::Internal::Button::State::Deselected);
}
TEST_F(ViewportUiManagerTestFixture, RegisterClusterEventHandlerConnectsHandlerToClusterEvent)
{
auto clusterId = m_viewportManagerWrapper.GetViewportManager()->CreateCluster(AzToolsFramework::ViewportUi::Alignment::TopLeft);
@@ -56,8 +56,7 @@ namespace AZ
//////////////////////////////////////////////////////////////////////////
virtual void OnBootstrapSceneReady([[maybe_unused]]AZ::RPI::Scene* bootstrapScene){}
virtual void OnFrameRateLimitChanged([[maybe_unused]]float fpsLimit){}
virtual void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) = 0;
};
using NotificationBus = AZ::EBus<Notification>;
} // namespace Bootstrap
@@ -23,8 +23,6 @@ namespace AZ::Render::Bootstrap
virtual AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) = 0;
virtual bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) = 0;
virtual float GetFrameRateLimit() const = 0;
virtual void SetFrameRateLimit(float fpsLimit) = 0;
protected:
~Request() = default;
@@ -42,14 +42,7 @@
#include <AzCore/Console/IConsole.h>
#include <BootstrapSystemComponent_Traits_Platform.h>
static void OnFrameRateLimitChanged(const float& fpsLimit)
{
AZ::Render::Bootstrap::RequestBus::Broadcast(
&AZ::Render::Bootstrap::RequestBus::Events::SetFrameRateLimit, fpsLimit);
}
AZ_CVAR(AZ::CVarFixedString, r_default_pipeline_name, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default Render pipeline name");
AZ_CVAR(float, r_fps_limit, 0, OnFrameRateLimitChanged, AZ::ConsoleFunctorFlags::Null, "The maximum framerate to render at, or 0 for unlimited");
namespace AZ
{
@@ -358,22 +351,6 @@ namespace AZ
return true;
}
float BootstrapSystemComponent::GetFrameRateLimit() const
{
return r_fps_limit;
}
void BootstrapSystemComponent::SetFrameRateLimit(float fpsLimit)
{
r_fps_limit = fpsLimit;
if (m_viewportContext)
{
m_viewportContext->SetFpsLimit(r_fps_limit);
}
Render::Bootstrap::NotificationBus::Broadcast(
&Render::Bootstrap::NotificationBus::Events::OnFrameRateLimitChanged, fpsLimit);
}
void BootstrapSystemComponent::CreateDefaultRenderPipeline()
{
EnsureDefaultRenderPipelineInstalledForScene(m_defaultScene, m_viewportContext);
@@ -413,11 +390,23 @@ namespace AZ
}
void BootstrapSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
{ }
{
// Temp: When running in the launcher without the legacy renderer
// we need to call RenderTick on the viewport context each frame.
if (m_viewportContext)
{
AZ::ApplicationTypeQuery appType;
ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
if (appType.IsGame())
{
m_viewportContext->RenderTick();
}
}
}
int BootstrapSystemComponent::GetTickOrder()
{
return TICK_PRE_RENDER;
return TICK_LAST;
}
void BootstrapSystemComponent::OnWindowClosed()
@@ -69,8 +69,6 @@ namespace AZ
// Render::Bootstrap::RequestBus::Handler overrides ...
AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) override;
bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) override;
float GetFrameRateLimit() const override;
void SetFrameRateLimit(float fpsLimit) override;
protected:
// Component overrides ...
@@ -39,13 +39,24 @@ namespace AZ
//! Otherwise an attempt will be made to find or create a shared instance.
void RebuildInstance();
//! Release asset and instance references
void Release();
//! Return true if contained assets have not been loaded
bool RequiresLoading() const;
//! Applies property overrides to material instance
bool ApplyProperties();
//! Returns a string composed of the asset path.
AZStd::string ToString() const;
Data::Asset<RPI::MaterialAsset> m_materialAsset;
Data::Asset<RPI::MaterialAsset> m_defaultMaterialAsset;
Data::Instance<RPI::Material> m_materialInstance;
MaterialPropertyOverrideMap m_propertyOverrides;
RPI::MaterialModelUvOverrideMap m_matModUvOverrides;
bool m_materialInstancePreCreated = false;
};
using MaterialAssignmentMap = AZStd::unordered_map<MaterialAssignmentId, MaterialAssignment>;
@@ -71,9 +71,9 @@ namespace AZ
}
MaterialAssignment::MaterialAssignment(const AZ::Data::AssetId& materialAssetId)
: m_materialInstance()
: m_materialAsset(materialAssetId, AZ::AzTypeInfo<AZ::RPI::MaterialAsset>::Uuid())
, m_materialInstance()
{
m_materialAsset.Create(materialAssetId);
}
MaterialAssignment::MaterialAssignment(const Data::Asset<RPI::MaterialAsset>& asset)
@@ -90,12 +90,70 @@ namespace AZ
void MaterialAssignment::RebuildInstance()
{
if (m_materialInstancePreCreated)
{
return;
}
if (m_materialAsset.IsReady())
{
m_materialInstance =
m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset);
m_materialInstance = m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset);
AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized");
}
else if (m_defaultMaterialAsset.IsReady())
{
m_materialInstance = m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_defaultMaterialAsset) : RPI::Material::Create(m_defaultMaterialAsset);
AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized");
}
}
void MaterialAssignment::Release()
{
if (!m_materialInstancePreCreated)
{
m_materialInstance = nullptr;
}
m_materialAsset.Release();
m_defaultMaterialAsset.Release();
}
bool MaterialAssignment::RequiresLoading() const
{
return
!m_materialInstancePreCreated &&
!m_materialAsset.IsReady() &&
!m_materialAsset.IsLoading() &&
!m_defaultMaterialAsset.IsReady() &&
!m_defaultMaterialAsset.IsLoading();
}
bool MaterialAssignment::ApplyProperties()
{
// if there is no instance or no properties there's nothing to apply
if (!m_materialInstance || m_propertyOverrides.empty())
{
return true;
}
if (m_materialInstance->CanCompile())
{
for (const auto& propertyPair : m_propertyOverrides)
{
if (!propertyPair.second.empty())
{
const auto& materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyPair.first);
if (!materialPropertyIndex.IsNull())
{
m_materialInstance->SetPropertyValue(
materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second));
}
}
}
return m_materialInstance->Compile();
}
return false;
}
AZStd::string MaterialAssignment::ToString() const
@@ -161,25 +161,19 @@ namespace AZ
//! Add this RenderPipeline to RPI system's RenderTick and it will be rendered whenever
//! the RPI system's RenderTick is called.
//! The RenderPipeline is rendered per RenderTick by default.
//! The RenderPipeline is rendered per RenderTick by default unless AddToRenderTickOnce() was called.
void AddToRenderTick();
//! Add this RenderPipeline to RPI system's RenderTick and it will be rendered every RenderTick
//! after the specified interval has elapsed since the last rendered frame.
//! @param renderInterval The desired time between rendered frames, in seconds.
void AddToRenderTickAtInterval(AZStd::chrono::duration<float> renderInterval);
//! Disable render for this RenderPipeline
void RemoveFromRenderTick();
~RenderPipeline();
enum class RenderMode : uint8_t
{
RenderEveryTick, //!< Render at each RPI system render tick.
RenderAtTargetRate, //!< Render on RPI system render tick after a target refresh rate interval has passed.
RenderOnce, //!< Render once in next RPI system render tick.
NoRender //!< Render disabled.
RenderEveryTick, // Render at each RPI system render tick
RenderOnce, // Render once in next RPI system render tick
NoRender // Render disabled.
};
//! Get current render mode
@@ -191,12 +185,6 @@ namespace AZ
//! Get draw filter mask
RHI::DrawFilterMask GetDrawFilterMask() const;
using FrameNotificationEvent = AZ::Event<>;
//! Notifies a listener when a frame is about to be prepared for render, before SRGs are bound.
void ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler);
//! Notifies a listener when the rendering of a frame has finished
void ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler);
private:
RenderPipeline() = default;
@@ -214,11 +202,8 @@ namespace AZ
void OnAddedToScene(Scene* scene);
void OnRemovedFromScene(Scene* scene);
// Called before this pipeline is about to be rendered and before SRGs are bound.
void OnPrepareFrame();
// Called when this pipeline is about to be rendered
void OnStartFrame();
void OnStartFrame(const TickTimeInfo& tick);
// Called when the rendering of current frame is finished.
void OnFrameEnd();
@@ -243,14 +228,8 @@ namespace AZ
PipelineViewMap m_pipelineViewsByTag;
// The system time when the last time this pipeline render was started
AZStd::chrono::system_clock::time_point m_lastRenderStartTime;
// The current system time, as of OnPrepareFrame's execution.
AZStd::chrono::system_clock::time_point m_lastRenderRequestTime;
// The target time between renders when m_renderMode is RenderMode::RenderAtTargetRate
AZStd::chrono::duration<float> m_targetRefreshRate;
/// The system time when the last time this pipeline render was started
float m_lastRenderStartTime = 0;
// RenderPipeline's name id, it will be used to identify the render pipeline when it's added to a Scene
RenderPipelineId m_nameId;
@@ -280,11 +259,7 @@ namespace AZ
RHI::DrawFilterTag m_drawFilterTag;
// A mask to filter draw items submitted by passes of this render pipeline.
// This mask is created from the value of m_drawFilterTag.
RHI::DrawFilterMask m_drawFilterMask = 0;
// Events for notification on render state
FrameNotificationEvent m_prepareFrameEvent;
FrameNotificationEvent m_endFrameEvent;
RHI::DrawFilterMask m_drawFilterMask = 0;
};
} // namespace RPI
@@ -67,9 +67,6 @@ namespace AZ
//! Notifies when the PrepareRender phase is ending
virtual void OnEndPrepareRender() {}
//! Notifies when the render tick for a given frame has finished.
virtual void OnFrameEnd() {}
};
using SceneNotificationBus = AZ::EBus<SceneNotification>;
@@ -51,21 +51,9 @@ namespace AZ
//! Sets the root scene associated with this viewport.
//! This does not provide a default render pipeline, one must be provided to enable rendering.
void SetRenderScene(ScenePtr scene);
//! Gets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited.
//! The target framerate for the pipeline will be determined by this frame limit and the
//! vsync settings for the current window.
float GetFpsLimit() const;
//! Sets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited.
//! The target framerate for the pipeline will be determined by this frame limit and the
//! vsync settings for the current window.
void SetFpsLimit(float fpsLimit);
//! Gets the target frame rate for this viewport context.
//! This returns the lowest of either the current VSync refresh rate
//! or 0 for an unlimited frame rate (if there's no FPS limit and vsync is off).
float GetTargetFrameRate() const;
//! Runs one simulation and render tick and renders a frame to this viewport's window.
//! @note This is likely to be replaced by a tick management system in the RPI.
void RenderTick();
//! Gets the current name of this ViewportContext.
//! This name is used to tie this ViewportContext to its View stack, and ViewportContexts may be
@@ -86,28 +74,19 @@ namespace AZ
//! \see AzFramework::WindowRequests::GetDpiScaleFactor
float GetDpiScalingFactor() const;
//! Gets the current vsync interval, as a divisor of the current refresh rate.
//! A value of 0 indicates that vsync is disabled.
uint32_t GetVsyncInterval() const;
//! Gets the current display refresh rate, in frames per second.
uint32_t GetRefreshRate() const;
// SceneNotificationBus interface overrides...
//! Ensures our default view remains set when our scene's render pipelines are modified.
void OnRenderPipelineAdded(RenderPipelinePtr pipeline) override;
//! Ensures our default view remains set when our scene's render pipelines are modified.
void OnRenderPipelineRemoved(RenderPipeline* pipeline) override;
//! OnBeginPrepareRender is forwarded to our RenderTick notification to allow subscribers to do rendering.
void OnBeginPrepareRender() override;
// WindowNotificationBus interface overrides...
//! Used to fire a notification when our window resizes.
void OnWindowResized(uint32_t width, uint32_t height) override;
//! Used to fire a notification when our window DPI changes.
void OnDpiScaleFactorChanged(float dpiScaleFactor) override;
//! Used to fire a notification when our vsync interval changes.
void OnVsyncIntervalChanged(uint32_t interval) override;
//! Used to fire a notification when our refresh rate changes.
void OnRefreshRateChanged(uint32_t refreshRate) override;
using SizeChangedEvent = AZ::Event<AzFramework::WindowSize>;
//! Notifies consumers when the viewport size has changed.
@@ -119,12 +98,6 @@ namespace AZ
//! Alternatively, connect to ViewportContextNotificationsBus and listen to ViewportContextNotifications::OnViewportDpiScalingChanged.
void ConnectDpiScalingFactorChangedHandler(ScalarChangedEvent::Handler& handler);
using UintChangedEvent = AZ::Event<uint32_t>;
//! Notifies consumers when the vsync interval has changed.
void ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler);
//! Notifies consumers when the refresh rate has changed.
void ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler);
using MatrixChangedEvent = AZ::Event<const AZ::Matrix4x4&>;
//! Notifies consumers when the view matrix has changed.
void ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler);
@@ -166,24 +139,15 @@ namespace AZ
void SetDefaultView(ViewPtr view);
// Ensures our render pipeline's default camera matches ours.
void UpdatePipelineView();
// Ensures our render pipeline refresh rate matches our refresh rate.
void UpdatePipelineRefreshRate();
// Resets the current pipeline reference and ensures pipeline events are disconnected.
void ResetCurrentPipeline();
ScenePtr m_rootScene;
WindowContextSharedPtr m_windowContext;
ViewPtr m_defaultView;
AzFramework::WindowSize m_viewportSize;
float m_viewportDpiScaleFactor = 1.0f;
uint32_t m_vsyncInterval = 1;
uint32_t m_refreshRate = 60;
float m_fpsLimit = 0.f;
SizeChangedEvent m_sizeChangedEvent;
ScalarChangedEvent m_dpiScalingFactorChangedEvent;
UintChangedEvent m_vsyncIntervalChangedEvent;
UintChangedEvent m_refreshRateChangedEvent;
MatrixChangedEvent m_viewMatrixChangedEvent;
MatrixChangedEvent::Handler m_onViewMatrixChangedHandler;
MatrixChangedEvent m_projectionMatrixChangedEvent;
@@ -193,9 +157,6 @@ namespace AZ
ViewChangedEvent m_defaultViewChangedEvent;
ViewportIdEvent m_aboutToBeDestroyedEvent;
AZ::Event<>::Handler m_prepareFrameHandler;
AZ::Event<>::Handler m_endFrameHandler;
ViewportContextManager* m_manager;
RenderPipelinePtr m_currentPipeline;
Name m_name;
@@ -110,13 +110,11 @@ namespace AZ
virtual void OnViewportSizeChanged(AzFramework::WindowSize size){AZ_UNUSED(size);}
//! Called when the window DPI scaling changes for a given viewport context.
virtual void OnViewportDpiScalingChanged(float dpiScale){AZ_UNUSED(dpiScale);}
//! Called when the active view changes for a given viewport context.
//! Called when the active view for a given viewport context name changes.
virtual void OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view){AZ_UNUSED(view);}
//! Called when the viewport is to be rendered.
//! Add draws to this function if they only need to be rendered to this viewport.
virtual void OnRenderTick(){}
//! Called when the viewport finishes rendering a frame.
virtual void OnFrameEnd(){}
//! Add draws to this functions if they only need to be rendered to this viewport.
virtual void OnRenderTick(){};
protected:
~ViewportContextNotifications() = default;
@@ -14,9 +14,6 @@
#include <RPI.Private/RPISystemComponent.h>
#include <Atom/RHI/Factory.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/IO/IOUtils.h>
@@ -96,29 +93,20 @@ namespace AZ
}
m_rpiSystem.Initialize(m_rpiDescriptor);
AZ::TickBus::Handler::BusConnect();
AZ::SystemTickBus::Handler::BusConnect();
}
void RPISystemComponent::Deactivate()
{
AZ::TickBus::Handler::BusDisconnect();
AZ::SystemTickBus::Handler::BusDisconnect();
m_rpiSystem.Shutdown();
}
void RPISystemComponent::OnTick([[maybe_unused]]float deltaTime, [[maybe_unused]]ScriptTimePoint time)
void RPISystemComponent::OnSystemTick()
{
if (deltaTime == 0.f)
{
return;
}
m_rpiSystem.SimulationTick();
m_rpiSystem.RenderTick();
}
int RPISystemComponent::GetTickOrder()
{
return AZ::ComponentTickBus::TICK_RENDER;
}
} // namespace RPI
} // namespace AZ
@@ -32,7 +32,7 @@ namespace AZ
*/
class RPISystemComponent final
: public AZ::Component
, private AZ::TickBus::Handler
, public AZ::SystemTickBus::Handler
{
public:
AZ_COMPONENT(RPISystemComponent, "{83E301F3-7A0C-4099-B530-9342B91B1BC0}");
@@ -50,9 +50,8 @@ namespace AZ
private:
RPISystemComponent(const RPISystemComponent&) = delete;
// TickBus overrides...
void OnTick(float deltaTime, ScriptTimePoint time) override;
int GetTickOrder() override;
// SystemTickBus overrides...
void OnSystemTick() override;
RPISystem m_rpiSystem;
@@ -93,11 +93,8 @@ namespace AZ
void Pass::SetEnabled(bool enabled)
{
if (m_flags.m_enabled != enabled)
{
m_flags.m_enabled = enabled;
OnHierarchyChange();
}
m_flags.m_enabled = enabled;
OnHierarchyChange();
}
bool Pass::IsEnabled() const
@@ -301,26 +301,6 @@ namespace AZ
m_drawFilterMask = 0;
}
void RenderPipeline::OnPrepareFrame()
{
m_lastRenderRequestTime = AZStd::chrono::system_clock::now();
// If we're attempting to render at a target interval, check to see if we're within
// 1ms of that interval, enabling rendering only if we are.
if (m_renderMode == RenderMode::RenderAtTargetRate)
{
constexpr AZStd::chrono::duration<float> updateThresholdMs(0.001f);
const bool shouldRender =
m_lastRenderRequestTime - m_lastRenderStartTime + updateThresholdMs >= m_targetRefreshRate;
m_rootPass->SetEnabled(shouldRender);
}
if (NeedsRender())
{
m_prepareFrameEvent.Signal();
}
}
void RenderPipeline::OnPassModified()
{
if (m_needsPassRecreate)
@@ -395,11 +375,11 @@ namespace AZ
m_scene->RemoveRenderPipeline(m_nameId);
}
void RenderPipeline::OnStartFrame()
void RenderPipeline::OnStartFrame(const TickTimeInfo& tick)
{
AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame");
m_lastRenderStartTime = m_lastRenderRequestTime;
m_lastRenderStartTime = tick.m_currentGameTime;
OnPassModified();
@@ -427,7 +407,6 @@ namespace AZ
{
RemoveFromRenderTick();
}
m_endFrameEvent.Signal();
}
void RenderPipeline::CollectPersistentViews(AZStd::map<ViewPtr, RHI::DrawListMask>& outViewMasks) const
@@ -510,13 +489,6 @@ namespace AZ
m_renderMode = RenderMode::RenderEveryTick;
}
void RenderPipeline::AddToRenderTickAtInterval(AZStd::chrono::duration<float> renderInterval)
{
m_rootPass->SetEnabled(false);
m_renderMode = RenderMode::RenderAtTargetRate;
m_targetRefreshRate = renderInterval;
}
void RenderPipeline::RemoveFromRenderTick()
{
m_renderMode = RenderMode::NoRender;
@@ -530,7 +502,7 @@ namespace AZ
bool RenderPipeline::NeedsRender() const
{
return m_rootPass->IsEnabled();
return m_renderMode != RenderMode::NoRender;
}
RHI::DrawFilterTag RenderPipeline::GetDrawFilterTag() const
@@ -543,16 +515,6 @@ namespace AZ
return m_drawFilterMask;
}
void RenderPipeline::ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler)
{
handler.Connect(m_prepareFrameEvent);
}
void RenderPipeline::ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler)
{
handler.Connect(m_endFrameEvent);
}
void RenderPipeline::SetDrawFilterTag(RHI::DrawFilterTag tag)
{
m_drawFilterTag = tag;
+4 -17
View File
@@ -418,7 +418,7 @@ namespace AZ
}
}
void Scene::PrepareRender([[maybe_unused]]const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
{
AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender");
@@ -429,27 +429,20 @@ namespace AZ
SceneNotificationBus::Event(GetId(), &SceneNotification::OnBeginPrepareRender);
// Get active pipelines which need to be rendered and notify them of an impending frame.
// Get active pipelines which need to be rendered and notify them frame started
AZStd::vector<RenderPipelinePtr> activePipelines;
{
AZ_PROFILE_SCOPE(RPI, "Scene: OnPrepareFrame");
AZ_PROFILE_SCOPE(RPI, "Scene: OnStartFrame");
for (auto& pipeline : m_pipelines)
{
pipeline->OnPrepareFrame();
if (pipeline->NeedsRender())
{
activePipelines.push_back(pipeline);
pipeline->OnStartFrame(tickInfo);
}
}
}
// Get active pipelines which need to be rendered and notify them frame started
for (const auto& pipeline : activePipelines)
{
AZ_PROFILE_SCOPE(RPI, "Scene: OnStartFrame");
pipeline->OnStartFrame();
}
// Return if there is no active render pipeline
if (activePipelines.empty())
{
@@ -589,12 +582,10 @@ namespace AZ
void Scene::OnFrameEnd()
{
AZ_PROFILE_SCOPE(RPI, "Scene: OnFrameEnd");
bool didRender = false;
for (auto& pipeline : m_pipelines)
{
if (pipeline->NeedsRender())
{
didRender = true;
pipeline->OnFrameEnd();
}
}
@@ -602,10 +593,6 @@ namespace AZ
{
fp->OnRenderEnd();
}
if (didRender)
{
SceneNotificationBus::Event(GetId(), &SceneNotification::OnFrameEnd);
}
}
void Scene::UpdateSrgs()
@@ -241,10 +241,7 @@ namespace AZ
{
AZ_PROFILE_SCOPE(RPI, "View: FinalizeDrawLists");
m_drawListContext.FinalizeLists();
if (m_passesByDrawList)
{
SortFinalizedDrawLists();
}
SortFinalizedDrawLists();
}
void View::SortFinalizedDrawLists()
@@ -25,13 +25,14 @@ namespace AZ
, m_viewportSize(1, 1)
{
m_windowContext->Initialize(device, nativeWindow);
AzFramework::WindowRequestBus::Event(nativeWindow, [this](AzFramework::WindowRequestBus::Events* window)
{
m_viewportSize = window->GetClientAreaSize();
m_viewportDpiScaleFactor = window->GetDpiScaleFactor();
m_vsyncInterval = window->GetSyncInterval();
m_refreshRate = window->GetDisplayRefreshRate();
});
AzFramework::WindowRequestBus::EventResult(
m_viewportSize,
nativeWindow,
&AzFramework::WindowRequestBus::Events::GetClientAreaSize);
AzFramework::WindowRequestBus::EventResult(
m_viewportDpiScaleFactor,
nativeWindow,
&AzFramework::WindowRequestBus::Events::GetDpiScaleFactor);
AzFramework::WindowNotificationBus::Handler::BusConnect(nativeWindow);
AzFramework::ViewportRequestBus::Handler::BusConnect(id);
@@ -45,20 +46,6 @@ namespace AZ
m_viewMatrixChangedEvent.Signal(matrix);
});
m_prepareFrameHandler = RenderPipeline::FrameNotificationEvent::Handler(
[this]()
{
ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick);
ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick);
});
m_endFrameHandler = RenderPipeline::FrameNotificationEvent::Handler(
[this]()
{
ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnFrameEnd);
ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnFrameEnd);
});
SetRenderScene(renderScene);
}
@@ -124,38 +111,26 @@ namespace AZ
{
SceneNotificationBus::Handler::BusConnect(m_rootScene->GetId());
}
ResetCurrentPipeline();
m_currentPipeline.reset();
UpdatePipelineView();
UpdatePipelineRefreshRate();
}
m_sceneChangedEvent.Signal(scene);
}
float ViewportContext::GetFpsLimit() const
void ViewportContext::RenderTick()
{
return m_fpsLimit;
}
void ViewportContext::SetFpsLimit(float fpsLimit)
{
m_fpsLimit = fpsLimit;
UpdatePipelineRefreshRate();
}
float ViewportContext::GetTargetFrameRate() const
{
float targetFrameRate = GetFpsLimit();
const AZ::u32 vsyncInterval = GetVsyncInterval();
if (vsyncInterval != 0)
// add the current pipeline to next render tick if it's not already added.
if (m_currentPipeline && m_currentPipeline->GetRenderMode() != RenderPipeline::RenderMode::RenderOnce)
{
const float vsyncFrameRate = static_cast<float>(GetRefreshRate()) / static_cast<float>(vsyncInterval);
if (targetFrameRate == 0.f || vsyncFrameRate < targetFrameRate)
{
targetFrameRate = vsyncFrameRate;
}
m_currentPipeline->AddToRenderTickOnce();
}
return targetFrameRate;
}
void ViewportContext::OnBeginPrepareRender()
{
ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick);
ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick);
}
AZ::Name ViewportContext::GetName() const
@@ -183,16 +158,6 @@ namespace AZ
return m_viewportDpiScaleFactor;
}
uint32_t ViewportContext::GetVsyncInterval() const
{
return m_vsyncInterval;
}
uint32_t ViewportContext::GetRefreshRate() const
{
return m_refreshRate;
}
void ViewportContext::ConnectSizeChangedHandler(SizeChangedEvent::Handler& handler)
{
handler.Connect(m_sizeChangedEvent);
@@ -203,16 +168,6 @@ namespace AZ
handler.Connect(m_dpiScalingFactorChangedEvent);
}
void ViewportContext::ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler)
{
handler.Connect(m_vsyncIntervalChangedEvent);
}
void ViewportContext::ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler)
{
handler.Connect(m_refreshRateChangedEvent);
}
void ViewportContext::ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler)
{
handler.Connect(m_viewMatrixChangedEvent);
@@ -308,43 +263,12 @@ namespace AZ
m_currentPipelineChangedEvent.Signal(m_currentPipeline);
}
if (m_currentPipeline)
if (auto pipeline = GetCurrentPipeline())
{
if (!m_prepareFrameHandler.IsConnected())
{
m_currentPipeline->ConnectPrepareFrameHandler(m_prepareFrameHandler);
m_currentPipeline->ConnectEndFrameHandler(m_endFrameHandler);
}
m_currentPipeline->SetDefaultView(m_defaultView);
pipeline->SetDefaultView(m_defaultView);
}
}
void ViewportContext::UpdatePipelineRefreshRate()
{
if (!m_currentPipeline)
{
return;
}
const float refreshRate = GetTargetFrameRate();
// If we have a truly unlimited framerate, just render every tick
if (refreshRate == 0.f)
{
m_currentPipeline->AddToRenderTick();
}
else
{
m_currentPipeline->AddToRenderTickAtInterval(AZStd::chrono::duration<float>(1.f / refreshRate));
}
}
void ViewportContext::ResetCurrentPipeline()
{
m_prepareFrameHandler.Disconnect();
m_endFrameHandler.Disconnect();
m_currentPipeline.reset();
}
RenderPipelinePtr ViewportContext::GetCurrentPipeline()
{
return m_currentPipeline;
@@ -357,9 +281,8 @@ namespace AZ
// in the event prioritization is added later
if (pipeline->GetWindowHandle() == m_windowContext->GetWindowHandle())
{
ResetCurrentPipeline();
m_currentPipeline.reset();
UpdatePipelineView();
UpdatePipelineRefreshRate();
}
}
@@ -367,9 +290,8 @@ namespace AZ
{
if (m_currentPipeline.get() == pipeline)
{
ResetCurrentPipeline();
m_currentPipeline.reset();
UpdatePipelineView();
UpdatePipelineRefreshRate();
}
}
@@ -383,30 +305,10 @@ namespace AZ
}
}
void ViewportContext::OnRefreshRateChanged(uint32_t refreshRate)
{
if (m_refreshRate != refreshRate)
{
m_refreshRate = refreshRate;
m_refreshRateChangedEvent.Signal(m_refreshRate);
UpdatePipelineRefreshRate();
}
}
void ViewportContext::OnDpiScaleFactorChanged(float dpiScaleFactor)
{
m_viewportDpiScaleFactor = dpiScaleFactor;
m_dpiScalingFactorChangedEvent.Signal(dpiScaleFactor);
}
void ViewportContext::OnVsyncIntervalChanged(uint32_t interval)
{
if (m_vsyncInterval != interval)
{
m_vsyncInterval = interval;
m_vsyncIntervalChangedEvent.Signal(m_vsyncInterval);
UpdatePipelineRefreshRate();
}
}
} // namespace RPI
} // namespace AZ
@@ -112,8 +112,7 @@ namespace AtomToolsFramework
void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
// ModularViewportCameraControllerRequestBus overrides ...
void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) override;
AZStd::optional<AZ::Vector3> LookAtAfterInterpolation() const override;
void InterpolateToTransform(const AZ::Transform& worldFromLocal) override;
AZ::Transform GetReferenceFrame() const override;
void SetReferenceFrame(const AZ::Transform& worldFromLocal) override;
void ClearReferenceFrame() override;
@@ -149,9 +148,8 @@ namespace AtomToolsFramework
CameraAnimation m_cameraAnimation; //!< Camera animation state (used during CameraMode::Animation).
CameraMode m_cameraMode = CameraMode::Control; //!< The current mode the camera is operating in.
AZStd::optional<AZ::Vector3> m_lookAtAfterInterpolation; //!< The look at point after an interpolation has finished.
//!< Will be cleared when the view changes (camera looks away).
AZ::Transform m_referenceFrameOverride = AZ::Transform::CreateIdentity(); //!<
//! An additional reference frame the camera can operate in (identity has no effect).
AZ::Transform m_referenceFrameOverride = AZ::Transform::CreateIdentity();
//! Flag to prevent circular updates of the camera transform (while the viewport transform is being updated internally).
bool m_updatingTransformInternally = false;
//! Listen for camera view changes outside of the camera controller.
@@ -29,11 +29,7 @@ namespace AtomToolsFramework
//! Begin a smooth transition of the camera to the requested transform.
//! @param worldFromLocal The transform of where the camera should end up.
//! @param lookAtDistance The distance between the camera transform and the imagined look at point.
virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) = 0;
//! Look at point after an interpolation has finished and no translation has occurred.
virtual AZStd::optional<AZ::Vector3> LookAtAfterInterpolation() const = 0;
virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0;
//! Return the current reference frame.
//! @note If a reference frame has not been set or a frame has been cleared, this is just the identity.
@@ -10,7 +10,6 @@
#include <QWidget>
#include <QElapsedTimer>
#include <QPointer>
#include <Atom/RPI.Public/Base.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/Input/QtEventToAzInputManager.h>
@@ -22,8 +21,6 @@
#include <AzFramework/Windowing/WindowBus.h>
#include <AzCore/Component/TickBus.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h>
namespace AtomToolsFramework
{
@@ -38,8 +35,6 @@ namespace AtomToolsFramework
, public AzFramework::WindowRequestBus::Handler
, protected AzFramework::InputChannelEventListener
, protected AZ::TickBus::Handler
, protected AZ::Render::Bootstrap::NotificationBus::Handler
, protected AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler
{
public:
//! Creates a RenderViewportWidget.
@@ -126,7 +121,6 @@ namespace AtomToolsFramework
// AZ::TickBus::Handler ...
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
int GetTickOrder() override;
// QWidget ...
void resizeEvent(QResizeEvent *event) override;
@@ -134,21 +128,9 @@ namespace AtomToolsFramework
void enterEvent(QEvent* event) override;
void leaveEvent(QEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void focusInEvent(QFocusEvent* event) override;
// AZ::Render::Bootstrap::NotificationBus::Handler ...
void OnFrameRateLimitChanged(float fpsLimit) override;
// AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler ...
void OnInactiveViewportFrameRateChanged(float fpsLimit) override;
private:
AzFramework::NativeWindowHandle GetNativeWindowHandle() const;
void UpdateFrameRate();
void SetScreen(QScreen* screen);
void SendWindowResizeEvent();
void NotifyUpdateRefreshRate();
// The underlying ViewportContext, our entry-point to the Atom RPI.
AZ::RPI::ViewportContextPtr m_viewportContext;
@@ -169,11 +151,5 @@ namespace AtomToolsFramework
AZ::ScriptTimePoint m_time;
// Maps our internal Qt events into AzFramework InputChannels for our ViewportControllerList.
AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr;
// Stores our current screen, used for tracking the current refresh rate.
QScreen* m_screen = nullptr;
// Stores the last RenderViewportWidget that has received user focus.
// This is used for optional framerate throtting for "inactive" viewports via the
// ed_inactive_viewport_fps_limit CVAR.
AZ::EnvironmentVariable<RenderViewportWidget*> m_lastFocusedViewport;
};
} //namespace AtomToolsFramework
@@ -1,35 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
namespace AtomToolsFramework
{
//! Provides an interface for providing notifications specific to RenderViewportWidget.
//! @note Most behaviors in RenderViewportWidget are handled by its underyling
//! ViewportContext, this bus is specifically for functionality exclusive to the
//! Qt layer provided by RenderViewportWidget.
class RenderViewportWidgetNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
//! Triggered when the idle frame rate limit for inactive viewports changed.
//! Controlled by the ed_inactive_viewport_fps_limit CVAR.
//! Active viewports are controlled by the r_fps_limit CVAR.
virtual void OnInactiveViewportFrameRateChanged([[maybe_unused]]float fpsLimit){}
protected:
~RenderViewportWidgetNotifications() = default;
};
using RenderViewportWidgetNotificationBus = AZ::EBus<RenderViewportWidgetNotifications>;
} // namespace AtomToolsFramework
@@ -227,19 +227,6 @@ namespace AtomToolsFramework
{
m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count());
m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, m_cameraProps, event.m_deltaTime.count());
// if there has been an interpolation, only clear the look at point if it is no longer
// centered in the view (the camera has looked away from it)
if (m_lookAtAfterInterpolation.has_value())
{
if (const float lookDirection =
(*m_lookAtAfterInterpolation - m_camera.Translation()).GetNormalized().Dot(m_camera.Transform().GetBasisY());
!AZ::IsCloseMag(lookDirection, 1.0f, 0.001f))
{
m_lookAtAfterInterpolation = {};
}
}
m_modularCameraViewportContext->SetCameraTransform(m_referenceFrameOverride * m_camera.Transform());
}
else if (m_cameraMode == CameraMode::Animation)
@@ -277,16 +264,10 @@ namespace AtomToolsFramework
m_updatingTransformInternally = false;
}
void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance)
void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal)
{
m_cameraMode = CameraMode::Animation;
m_cameraAnimation = CameraAnimation{ m_referenceFrameOverride * m_camera.Transform(), worldFromLocal, 0.0f };
m_lookAtAfterInterpolation = worldFromLocal.GetTranslation() + worldFromLocal.GetBasisY() * lookAtDistance;
}
AZStd::optional<AZ::Vector3> ModularViewportCameraControllerInstance::LookAtAfterInterpolation() const
{
return m_lookAtAfterInterpolation;
}
AZ::Transform ModularViewportCameraControllerInstance::GetReferenceFrame() const
@@ -6,42 +6,23 @@
*
*/
#include <Atom/Bootstrap/BootstrapRequestBus.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/View.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <AzCore/Console/Console.h>
#include <AzCore/Math/MathUtils.h>
#include <Atom/RPI.Public/View.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Viewport/ViewportControllerList.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzToolsFramework/Viewport/ViewportTypes.h>
#include <AzCore/Math/MathUtils.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/Bootstrap/BootstrapRequestBus.h>
#include <QApplication>
#include <QBoxLayout>
#include <QCursor>
#include <QMouseEvent>
#include <QScreen>
#include <QTimer>
#include <QBoxLayout>
#include <QWindow>
static void OnInactiveViewportFrameRateChanged(const float& fpsLimit)
{
AtomToolsFramework::RenderViewportWidgetNotificationBus::Broadcast(
&AtomToolsFramework::RenderViewportWidgetNotificationBus::Events::OnInactiveViewportFrameRateChanged, fpsLimit);
}
AZ_CVAR(
float,
ed_inactive_viewport_fps_limit,
0,
OnInactiveViewportFrameRateChanged,
AZ::ConsoleFunctorFlags::Null,
"The maximum framerate to render viewports that don't have focus at");
static constexpr const char* LastFocusedViewportVariableName = "AtomToolsFramework::RenderViewportWidget::LastFocusedViewport";
#include <QMouseEvent>
namespace AtomToolsFramework
{
@@ -49,12 +30,6 @@ namespace AtomToolsFramework
: QWidget(parent)
, AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDefault())
{
m_lastFocusedViewport = AZ::Environment::FindVariable<RenderViewportWidget*>(LastFocusedViewportVariableName);
if (!m_lastFocusedViewport)
{
m_lastFocusedViewport = AZ::Environment::CreateVariable<RenderViewportWidget*>(LastFocusedViewportVariableName, nullptr);
}
if (shouldInitializeViewportContext)
{
InitializeViewportContext();
@@ -63,24 +38,13 @@ namespace AtomToolsFramework
setUpdatesEnabled(false);
setFocusPolicy(Qt::FocusPolicy::WheelFocus);
setMouseTracking(true);
// Wait a frame for our window handle to be constructed, then wire up our screen change signals.
QTimer::singleShot(
0,
[this]()
{
QObject::connect(windowHandle(), &QWindow::screenChanged, this, &RenderViewportWidget::SetScreen);
});
SetScreen(screen());
}
bool RenderViewportWidget::InitializeViewportContext(AzFramework::ViewportId id)
{
if (m_viewportContext != nullptr)
{
AZ_Assert(
id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id,
"Attempted to reinitialize RenderViewportWidget with a different ID");
AZ_Assert(id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id, "Attempted to reinitialize RenderViewportWidget with a different ID");
return true;
}
@@ -95,7 +59,7 @@ namespace AtomToolsFramework
// Before we do anything else, we must create a ViewportContext which will give us a ViewportId if we didn't manually specify one.
AZ::RPI::ViewportContextRequestsInterface::CreationParameters params;
params.device = AZ::RHI::RHISystemInterface::Get()->GetDevice();
params.windowHandle = GetNativeWindowHandle();
params.windowHandle = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
params.id = id;
AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle);
m_viewportContext = viewportContextManager->CreateViewportContext(AZ::Name(), params);
@@ -116,46 +80,29 @@ namespace AtomToolsFramework
AzFramework::InputChannelEventListener::Connect();
AZ::TickBus::Handler::BusConnect();
AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle);
AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler::BusConnect();
m_inputChannelMapper = new AzToolsFramework::QtEventToAzInputMapper(this, id);
// Forward input events to our controller list.
QObject::connect(
m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this,
QObject::connect(m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this,
[this](const AzFramework::InputChannel* inputChannel, QEvent* event)
{
const AzFramework::NativeWindowHandle windowId = GetNativeWindowHandle();
if (m_controllerList->HandleInputChannelEvent(
AzFramework::ViewportControllerInputEvent{ GetId(), windowId, *inputChannel }))
{
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
if (event)
{
event->setAccepted(true);
}
}
});
// Update our target frame rate. If we're the only viewport, become active.
if (m_lastFocusedViewport.Get() == nullptr)
{
m_lastFocusedViewport.Set(this);
}
UpdateFrameRate();
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
if (m_controllerList->HandleInputChannelEvent(AzFramework::ViewportControllerInputEvent{GetId(), windowId, *inputChannel}))
{
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
if (event)
{
event->setAccepted(true);
}
}
});
return true;
}
RenderViewportWidget::~RenderViewportWidget()
{
if (m_lastFocusedViewport.Get() == this)
{
m_lastFocusedViewport.Set(nullptr);
}
AzFramework::WindowRequestBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AzFramework::InputChannelEventListener::Disconnect();
@@ -234,22 +181,17 @@ namespace AtomToolsFramework
bool shouldConsumeEvent = true;
const bool eventHandled = m_controllerList->HandleInputChannelEvent({ GetId(), GetNativeWindowHandle(), inputChannel });
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
const bool eventHandled = m_controllerList->HandleInputChannelEvent({GetId(), windowId, inputChannel});
// If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might
// need), consume it.
// If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might need), consume it.
return eventHandled && shouldConsumeEvent;
}
void RenderViewportWidget::OnTick([[maybe_unused]] float deltaTime, AZ::ScriptTimePoint time)
void RenderViewportWidget::OnTick([[maybe_unused]]float deltaTime, AZ::ScriptTimePoint time)
{
m_time = time;
m_controllerList->UpdateViewport({ GetId(), AzFramework::FloatSeconds(deltaTime), m_time });
}
int RenderViewportWidget::GetTickOrder()
{
return AZ::ComponentTickBus::TICK_PRE_RENDER;
m_controllerList->UpdateViewport({GetId(), AzFramework::FloatSeconds(deltaTime), m_time});
}
void RenderViewportWidget::resizeEvent([[maybe_unused]] QResizeEvent* event)
@@ -277,75 +219,6 @@ namespace AtomToolsFramework
m_mousePosition = event->localPos();
}
void RenderViewportWidget::focusInEvent([[maybe_unused]] QFocusEvent* event)
{
RenderViewportWidget* lastFocusedViewport = m_lastFocusedViewport.Get();
if (lastFocusedViewport == this)
{
return;
}
RenderViewportWidget* previousFocusWidget = lastFocusedViewport;
m_lastFocusedViewport.Set(this);
// Ensure this viewport and whatever viewport last had focus (if any) respect
// the active / inactive viewport frame rate settings.
UpdateFrameRate();
if (previousFocusWidget != nullptr)
{
previousFocusWidget->UpdateFrameRate();
}
}
void RenderViewportWidget::OnFrameRateLimitChanged([[maybe_unused]] float fpsLimit)
{
UpdateFrameRate();
}
void RenderViewportWidget::OnInactiveViewportFrameRateChanged([[maybe_unused]] float fpsLimit)
{
UpdateFrameRate();
}
AzFramework::NativeWindowHandle RenderViewportWidget::GetNativeWindowHandle() const
{
return reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
}
void RenderViewportWidget::UpdateFrameRate()
{
if (ed_inactive_viewport_fps_limit > 0.f && m_lastFocusedViewport.Get() != this)
{
m_viewportContext->SetFpsLimit(ed_inactive_viewport_fps_limit);
}
else
{
float fpsLimit = 0.f;
AZ::Render::Bootstrap::RequestBus::BroadcastResult(fpsLimit, &AZ::Render::Bootstrap::RequestBus::Events::GetFrameRateLimit);
m_viewportContext->SetFpsLimit(fpsLimit);
}
}
void RenderViewportWidget::SetScreen(QScreen* screen)
{
if (m_screen != screen)
{
if (m_screen)
{
QObject::disconnect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate);
}
if (screen)
{
QObject::connect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate);
}
NotifyUpdateRefreshRate();
m_screen = screen;
}
}
void RenderViewportWidget::SendWindowResizeEvent()
{
// Scale the size by the DPI of the platform to
@@ -353,14 +226,8 @@ namespace AtomToolsFramework
const QSize uiWindowSize = size();
const QSize windowSize = uiWindowSize * devicePixelRatioF();
AzFramework::WindowNotificationBus::Event(
GetNativeWindowHandle(), &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height());
}
void RenderViewportWidget::NotifyUpdateRefreshRate()
{
AzFramework::WindowNotificationBus::Event(
GetNativeWindowHandle(), &AzFramework::WindowNotificationBus::Events::OnRefreshRateChanged, GetDisplayRefreshRate());
const AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
AzFramework::WindowNotificationBus::Event(windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height());
}
AZ::Name RenderViewportWidget::GetCurrentContextName() const
@@ -418,7 +285,9 @@ namespace AtomToolsFramework
// Build camera state from Atom camera transforms
AzFramework::CameraState cameraState = AzFramework::CreateCameraFromWorldFromViewMatrix(
currentView->GetViewToWorldMatrix(), AZ::Vector2{ aznumeric_cast<float>(width()), aznumeric_cast<float>(height()) });
currentView->GetViewToWorldMatrix(),
AZ::Vector2{aznumeric_cast<float>(width()), aznumeric_cast<float>(height())}
);
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, currentView->GetViewToClipMatrix());
// Convert from Z-up
@@ -430,7 +299,8 @@ namespace AtomToolsFramework
AzFramework::ScreenPoint RenderViewportWidget::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
{
if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView(); currentView == nullptr)
if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView();
currentView == nullptr)
{
return AzFramework::ScreenPoint(0, 0);
}
@@ -443,10 +313,12 @@ namespace AtomToolsFramework
const auto& cameraProjection = m_viewportContext->GetCameraProjectionMatrix();
const auto& cameraView = m_viewportContext->GetCameraViewMatrix();
const AZ::Vector4 normalizedScreenPosition{ screenPosition.m_x * 2.f / width() - 1.0f,
(height() - screenPosition.m_y) * 2.f / height() - 1.0f,
1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
1.f };
const AZ::Vector4 normalizedScreenPosition {
screenPosition.m_x * 2.f / width() - 1.0f,
(height() - screenPosition.m_y) * 2.f / height() - 1.0f,
1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
1.f
};
AZ::Matrix4x4 worldFromScreen = cameraProjection * cameraView;
worldFromScreen.InvertFull();
@@ -475,7 +347,7 @@ namespace AtomToolsFramework
AZ::Vector3 rayDirection = pos1.value() - pos0.value();
rayDirection.Normalize();
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{ rayOrigin, rayDirection };
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection};
}
float RenderViewportWidget::DeviceScalingFactor()
@@ -505,12 +377,12 @@ namespace AtomToolsFramework
AzFramework::WindowSize RenderViewportWidget::GetClientAreaSize() const
{
return AzFramework::WindowSize{ aznumeric_cast<uint32_t>(width()), aznumeric_cast<uint32_t>(height()) };
return AzFramework::WindowSize{aznumeric_cast<uint32_t>(width()), aznumeric_cast<uint32_t>(height())};
}
void RenderViewportWidget::ResizeClientArea(AzFramework::WindowSize clientAreaSize)
{
const QSize targetSize = QSize{ aznumeric_cast<int>(clientAreaSize.m_width), aznumeric_cast<int>(clientAreaSize.m_height) };
const QSize targetSize = QSize{aznumeric_cast<int>(clientAreaSize.m_width), aznumeric_cast<int>(clientAreaSize.m_height)};
resize(targetSize);
}
@@ -520,7 +392,7 @@ namespace AtomToolsFramework
return false;
}
void RenderViewportWidget::SetFullScreenState([[maybe_unused]] bool fullScreenState)
void RenderViewportWidget::SetFullScreenState([[maybe_unused]]bool fullScreenState)
{
// The RenderViewportWidget does not currently support full screen.
}
@@ -543,20 +415,11 @@ namespace AtomToolsFramework
uint32_t RenderViewportWidget::GetDisplayRefreshRate() const
{
return static_cast<uint32_t>(screen()->refreshRate());
return 60;
}
uint32_t RenderViewportWidget::GetSyncInterval() const
{
uint32_t interval = 1;
// Get vsync_interval from AzFramework::NativeWindow, which owns it.
// NativeWindow also handles broadcasting OnVsyncIntervalChanged to all
// WindowNotificationBus listeners.
if (auto console = AZ::Interface<AZ::IConsole>::Get())
{
console->GetCvarValue<uint32_t>("vsync_interval", interval);
}
return interval;
return 1;
}
} // namespace AtomToolsFramework
} //namespace AtomToolsFramework
@@ -28,7 +28,6 @@ set(FILES
Include/AtomToolsFramework/Util/MaterialPropertyUtil.h
Include/AtomToolsFramework/Util/Util.h
Include/AtomToolsFramework/Viewport/RenderViewportWidget.h
Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h
Include/AtomToolsFramework/Window/AtomToolsMainWindow.h
@@ -182,7 +182,9 @@ namespace MaterialEditor
AZ_Error("MaterialViewportRenderer", m_shadowCatcherMaterial != nullptr, "Could not create shadow catcher material.");
AZ::Render::MaterialAssignmentMap shadowCatcherMaterials;
shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId].m_materialInstance = m_shadowCatcherMaterial;
auto& shadowCatcherMaterialAssignment = shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId];
shadowCatcherMaterialAssignment.m_materialInstance = m_shadowCatcherMaterial;
shadowCatcherMaterialAssignment.m_materialInstancePreCreated = true;
AZ::Render::MaterialComponentRequestBus::Event(m_shadowCatcherEntity->GetId(),
&AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, shadowCatcherMaterials);
@@ -291,7 +293,9 @@ namespace MaterialEditor
MaterialDocumentRequestBus::EventResult(materialInstance, documentId, &MaterialDocumentRequestBus::Events::GetInstance);
AZ::Render::MaterialAssignmentMap materials;
materials[AZ::Render::DefaultMaterialAssignmentId].m_materialInstance = materialInstance;
auto& materialAssignment = materials[AZ::Render::DefaultMaterialAssignmentId];
materialAssignment.m_materialInstance = materialInstance;
materialAssignment.m_materialInstancePreCreated = true;
AZ::Render::MaterialComponentRequestBus::Event(m_modelEntity->GetId(),
&AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, materials);
@@ -183,15 +183,6 @@ namespace AZ::Render
DrawFramerate();
}
void AtomViewportDisplayInfoSystemComponent::OnFrameEnd()
{
auto currentTime = AZStd::chrono::system_clock::now();
if (!m_fpsHistory.empty())
{
m_fpsHistory.back().m_endFrameTime = currentTime;
}
}
AtomBridge::ViewportInfoDisplayState AtomViewportDisplayInfoSystemComponent::GetDisplayState() const
{
return aznumeric_cast<AtomBridge::ViewportInfoDisplayState>(r_displayInfo.operator int());
@@ -257,11 +248,11 @@ namespace AZ::Render
void AtomViewportDisplayInfoSystemComponent::UpdateFramerate()
{
auto currentTime = AZStd::chrono::system_clock::now();
while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front().m_beginFrameTime) > m_fpsInterval)
while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front()) > m_fpsInterval)
{
m_fpsHistory.pop_front();
}
m_fpsHistory.push_back(FrameTimingInfo(currentTime));
m_fpsHistory.push_back(currentTime);
}
void AtomViewportDisplayInfoSystemComponent::DrawFramerate()
@@ -270,31 +261,25 @@ namespace AZ::Render
double minFPS = DBL_MAX;
double maxFPS = 0;
AZStd::chrono::duration<double> deltaTime;
AZStd::chrono::milliseconds totalFrameMS(0);
for (const auto& time : m_fpsHistory)
{
if (lastTime.has_value())
{
deltaTime = time.m_beginFrameTime - lastTime.value();
deltaTime = time - lastTime.value();
double fps = AZStd::chrono::seconds(1) / deltaTime;
minFPS = AZStd::min(minFPS, fps);
maxFPS = AZStd::max(maxFPS, fps);
}
lastTime = time.m_beginFrameTime;
if (time.m_endFrameTime.has_value())
{
totalFrameMS += time.m_endFrameTime.value() - time.m_beginFrameTime;
}
lastTime = time;
}
double averageFPS = 0;
double averageFrameMs = 0;
if (m_fpsHistory.size() > 1)
{
deltaTime = m_fpsHistory.back().m_beginFrameTime - m_fpsHistory.front().m_beginFrameTime;
averageFPS = AZStd::chrono::seconds(m_fpsHistory.size() - 1) / deltaTime;
averageFrameMs = aznumeric_cast<double>(totalFrameMS.count()) / (m_fpsHistory.size() - 1);
deltaTime = m_fpsHistory.back() - m_fpsHistory.front();
averageFPS = AZStd::chrono::seconds(m_fpsHistory.size()) / deltaTime;
averageFrameMs = 1000.0f/averageFPS;
}
const double frameIntervalSeconds = m_fpsInterval.count();
@@ -303,7 +288,7 @@ namespace AZ::Render
AZStd::string::format(
"FPS %.1f [%.0f..%.0f], %.1fms/frame, avg over %.1fs",
averageFPS,
minFPS == DBL_MAX ? 0.0 : minFPS,
minFPS,
maxFPS,
averageFrameMs,
frameIntervalSeconds),
@@ -45,7 +45,6 @@ namespace AZ
// AZ::RPI::ViewportContextNotificationBus::Handler overrides...
void OnRenderTick() override;
void OnFrameEnd() override;
// AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler overrides...
AtomBridge::ViewportInfoDisplayState GetDisplayState() const override;
@@ -62,8 +61,6 @@ namespace AZ
void DrawPassInfo();
void DrawFramerate();
void UpdateScene(AZ::RPI::ScenePtr scene);
static constexpr float BaseFontSize = 0.7f;
AZStd::string m_rendererDescription;
@@ -71,17 +68,7 @@ namespace AZ
AzFramework::FontDrawInterface* m_fontDrawInterface = nullptr;
float m_lineSpacing;
AZStd::chrono::duration<double> m_fpsInterval = AZStd::chrono::seconds(1);
struct FrameTimingInfo
{
AZStd::chrono::system_clock::time_point m_beginFrameTime;
AZStd::optional<AZStd::chrono::system_clock::time_point> m_endFrameTime;
explicit FrameTimingInfo(AZStd::chrono::system_clock::time_point beginFrameTime)
: m_beginFrameTime(beginFrameTime)
{
}
};
AZStd::deque<FrameTimingInfo> m_fpsHistory;
AZStd::deque<AZStd::chrono::system_clock::time_point> m_fpsHistory;
AZStd::optional<AZStd::chrono::system_clock::time_point> m_lastMemoryUpdate;
bool m_updateRootPassQuery = true;
};
@@ -151,7 +151,9 @@ namespace AZ
//! Returns the list of all ModelMaterialSlot's for the model, across all LODs.
virtual RPI::ModelMaterialSlotMap GetModelMaterialSlots() const = 0;
//! Returns the available, overridable material slots and the default assigned materials
virtual MaterialAssignmentMap GetMaterialAssignments() const = 0;
virtual AZStd::unordered_set<AZ::Name> GetModelUvNames() const = 0;
};
using MaterialReceiverRequestBus = EBus<MaterialReceiverRequests>;
@@ -161,6 +163,7 @@ namespace AZ
: public ComponentBus
{
public:
//! Notification that overridable material slots are available or have changed
virtual void OnMaterialAssignmentsChanged() = 0;
};
using MaterialReceiverNotificationBus = EBus<MaterialReceiverNotifications>;
@@ -88,6 +88,12 @@ namespace AZ
AZ::Data::AssetId materialAssetId = {};
MaterialComponentRequestBus::EventResult(
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
if (!materialAssetId.IsValid())
{
MaterialComponentRequestBus::EventResult(
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId,
m_materialAssignmentId);
}
if (!materialAssetId.IsValid())
{
@@ -728,11 +734,16 @@ namespace AZ
void MaterialPropertyInspector::UpdateUI()
{
AZ::Data::AssetId assetId;
AZ::Data::AssetId materialAssetId = {};
MaterialComponentRequestBus::EventResult(
assetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetMaterialOverride, m_materialAssignmentId);
if (!materialAssetId.IsValid())
{
MaterialComponentRequestBus::EventResult(
materialAssetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_materialAssignmentId);
}
if (IsLoaded() && m_editData.m_materialAssetId == assetId)
if (IsLoaded() && m_editData.m_materialAssetId == materialAssetId)
{
LoadOverridesFromEntity();
}
@@ -118,10 +118,16 @@ namespace AZ
}
};
AZ::Data::AssetId EditorMaterialComponentSlot::GetActiveAssetId() const
{
return m_materialAsset.GetId().IsValid() ? m_materialAsset.GetId() : GetDefaultAssetId();
}
AZ::Data::AssetId EditorMaterialComponentSlot::GetDefaultAssetId() const
{
AZ::Data::AssetId assetId;
MaterialComponentRequestBus::EventResult(assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id);
MaterialComponentRequestBus::EventResult(
assetId, m_entityId, &MaterialComponentRequestBus::Events::GetDefaultMaterialAssetId, m_id);
return assetId;
}
@@ -135,7 +141,7 @@ namespace AZ
bool EditorMaterialComponentSlot::HasSourceData() const
{
// The slot only has valid source data if the source path is valid and the file has the correct extension
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId());
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId());
return !sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension);
}
@@ -220,7 +226,7 @@ namespace AZ
void EditorMaterialComponentSlot::OpenMaterialEditor() const
{
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(m_materialAsset.GetId());
const AZStd::string& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(GetActiveAssetId());
if (!sourcePath.empty() && AZ::StringFunc::Path::IsExtension(sourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension))
{
EditorMaterialSystemComponentRequestBus::Broadcast(
@@ -236,7 +242,7 @@ namespace AZ
void EditorMaterialComponentSlot::OpenUvNameMapInspector()
{
if (m_materialAsset.GetId().IsValid())
if (GetActiveAssetId().IsValid())
{
AZStd::unordered_set<AZ::Name> modelUvNames;
MaterialReceiverRequestBus::EventResult(modelUvNames, m_entityId, &MaterialReceiverRequestBus::Events::GetModelUvNames);
@@ -252,7 +258,7 @@ namespace AZ
};
if (EditorMaterialComponentInspector::OpenInspectorDialog(
m_materialAsset.GetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback))
GetActiveAssetId(), matModUvOverrides, modelUvNames, applyMatModUvOverrideChangedCallback))
{
OnDataChanged();
}
@@ -274,10 +280,10 @@ namespace AZ
action->setEnabled(HasSourceData());
action = menu.addAction("Edit Material Instance...", [this]() { OpenMaterialInspector(); });
action->setEnabled(m_materialAsset.GetId().IsValid());
action->setEnabled(GetActiveAssetId().IsValid());
action = menu.addAction("Edit Material Instance UV Map...", [this]() { OpenUvNameMapInspector(); });
action->setEnabled(m_materialAsset.GetId().IsValid());
action->setEnabled(GetActiveAssetId().IsValid());
menu.addSeparator();
@@ -30,6 +30,7 @@ namespace AZ
static void Reflect(ReflectContext* context);
static bool ConvertVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
AZ::Data::AssetId GetActiveAssetId() const;
AZ::Data::AssetId GetDefaultAssetId() const;
AZStd::string GetLabel() const;
bool HasSourceData() const;
@@ -111,12 +111,14 @@ namespace AZ
m_queuedMaterialUpdateNotification = false;
MaterialComponentRequestBus::Handler::BusConnect(m_entityId);
MaterialReceiverNotificationBus::Handler::BusConnect(m_entityId);
LoadMaterials();
}
void MaterialComponentController::Deactivate()
{
MaterialComponentRequestBus::Handler::BusDisconnect();
MaterialReceiverNotificationBus::Handler::BusDisconnect();
TickBus::Handler::BusDisconnect();
ReleaseMaterials();
@@ -146,56 +148,26 @@ namespace AZ
void MaterialComponentController::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
AZStd::unordered_set<MaterialAssignmentId> propertyOverrides;
AZStd::swap(m_queuedPropertyOverrides, propertyOverrides);
AZStd::unordered_set<MaterialAssignmentId> materialsWithDirtyProperties;
AZStd::swap(m_materialsWithDirtyProperties, materialsWithDirtyProperties);
// Iterate through all MaterialAssignmentId's that have property overrides and attempt to apply them
// if material instance is already compiling, delay application of property overrides until next frame
for (const auto& materialAssignmentId : propertyOverrides)
for (const auto& materialAssignmentId : materialsWithDirtyProperties)
{
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
if (materialIt != m_configuration.m_materials.end())
{
//Skip materials that do not exist in the map
continue;
}
auto materialInstance = materialIt->second.m_materialInstance;
if (!materialInstance)
{
//Skip materials with an invalid instances
continue;
}
if (!materialInstance->CanCompile())
{
//If a material cannot currently be compiled then it must be queued again
m_queuedPropertyOverrides.emplace(materialAssignmentId);
continue;
}
const auto& propertyOverrides2 = materialIt->second.m_propertyOverrides;
for (auto& propertyPair : propertyOverrides2)
{
if (propertyPair.second.empty())
if (!materialIt->second.ApplyProperties())
{
continue;
// If a material cannot currently be compiled then it must be queued again
m_materialsWithDirtyProperties.emplace(materialAssignmentId);
}
const auto& materialPropertyIndex = materialInstance->FindPropertyIndex(propertyPair.first);
if (materialPropertyIndex.IsNull())
{
continue;
}
materialInstance->SetPropertyValue(materialPropertyIndex, AZ::RPI::MaterialPropertyValue::FromAny(propertyPair.second));
}
materialInstance->Compile();
}
// Only disconnect from tick bus and send notification after all pending properties have been applied
if (m_queuedPropertyOverrides.empty())
if (m_materialsWithDirtyProperties.empty())
{
if (m_queuedMaterialUpdateNotification)
{
@@ -213,15 +185,35 @@ namespace AZ
Data::AssetBus::MultiHandler::BusDisconnect();
bool anyQueued = false;
for (auto& materialPair : m_configuration.m_materials)
auto queueAsset = [&anyQueued, this](AZ::Data::Asset<AZ::RPI::MaterialAsset>& materialAsset) -> bool
{
auto& materialAsset = materialPair.second.m_materialAsset;
if (materialAsset.GetId().IsValid() && !Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId()))
if (materialAsset.GetId().IsValid() && !this->Data::AssetBus::MultiHandler::BusIsConnectedId(materialAsset.GetId()))
{
anyQueued = true;
materialAsset.QueueLoad();
Data::AssetBus::MultiHandler::BusConnect(materialAsset.GetId());
this->Data::AssetBus::MultiHandler::BusConnect(materialAsset.GetId());
return true;
}
return false;
};
for (auto& materialPair : m_configuration.m_materials)
{
if (materialPair.second.m_materialInstancePreCreated)
{
continue;
}
materialPair.second.m_defaultMaterialAsset = {};
if (!queueAsset(materialPair.second.m_materialAsset))
{
// Only assign and load the default material if there was no material override and there are propoerties to apply
if (!materialPair.second.m_propertyOverrides.empty() || !materialPair.second.m_matModUvOverrides.empty())
{
materialPair.second.m_defaultMaterialAsset = AZ::Data::Asset<AZ::RPI::MaterialAsset>(
GetDefaultMaterialAssetId(materialPair.first), AZ::AzTypeInfo<AZ::RPI::MaterialAsset>::Uuid());
queueAsset(materialPair.second.m_defaultMaterialAsset);
}
}
}
@@ -234,10 +226,8 @@ namespace AZ
void MaterialComponentController::InitializeMaterialInstance(const Data::Asset<Data::AssetData>& asset)
{
bool allReady = true;
for (auto& materialPair : m_configuration.m_materials)
auto updateAsset = [&](AZ::Data::Asset<AZ::RPI::MaterialAsset>& materialAsset)
{
auto& materialAsset = materialPair.second.m_materialAsset;
if (materialAsset.GetId() == asset.GetId())
{
materialAsset = asset;
@@ -247,6 +237,12 @@ namespace AZ
{
allReady = false;
}
};
for (auto& materialPair : m_configuration.m_materials)
{
updateAsset(materialPair.second.m_materialAsset);
updateAsset(materialPair.second.m_defaultMaterialAsset);
}
if (allReady)
@@ -269,11 +265,7 @@ namespace AZ
for (auto& materialPair : m_configuration.m_materials)
{
if (materialPair.second.m_materialAsset.GetId().IsValid())
{
materialPair.second.m_materialAsset.Release();
materialPair.second.m_materialInstance = nullptr;
}
materialPair.second.Release();
}
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialsUpdated, m_configuration.m_materials);
@@ -441,12 +433,7 @@ namespace AZ
AZ::Data::AssetId MaterialComponentController::GetMaterialOverride(const MaterialAssignmentId& materialAssignmentId) const
{
auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
{
return {};
}
return materialIt->second.m_materialAsset.GetId();
return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_materialAsset.GetId() : AZ::Data::AssetId();
}
void MaterialComponentController::ClearMaterialOverride(const MaterialAssignmentId& materialAssignmentId)
@@ -460,18 +447,21 @@ namespace AZ
void MaterialComponentController::SetPropertyOverride(const MaterialAssignmentId& materialAssignmentId, const AZStd::string& propertyName, const AZStd::any& value)
{
auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value;
// When applying property overrides for the first time, new instance needs to be created in case the current instance is already used somewhere else to keep overrides local
if (materialAssignment.m_propertyOverrides.empty())
if (materialAssignment.RequiresLoading())
{
materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value;
materialAssignment.RebuildInstance();
MaterialComponentNotificationBus::Event(m_entityId, &MaterialComponentNotifications::OnMaterialInstanceCreated, materialAssignment);
QueueMaterialUpdateNotification();
LoadMaterials();
return;
}
else
if (wasEmpty != materialAssignment.m_propertyOverrides.empty())
{
materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value;
materialAssignment.RebuildInstance();
MaterialComponentNotificationBus::Event(
m_entityId, &MaterialComponentNotifications::OnMaterialInstanceCreated, materialAssignment);
QueueMaterialUpdateNotification();
}
QueuePropertyChanges(materialAssignmentId);
@@ -704,6 +694,12 @@ namespace AZ
const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
materialAssignment.m_propertyOverrides = propertyOverrides;
if (materialAssignment.RequiresLoading())
{
LoadMaterials();
return;
}
if (wasEmpty != materialAssignment.m_propertyOverrides.empty())
{
materialAssignment.RebuildInstance();
@@ -713,14 +709,11 @@ namespace AZ
QueuePropertyChanges(materialAssignmentId);
}
MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides(const MaterialAssignmentId& materialAssignmentId) const
MaterialPropertyOverrideMap MaterialComponentController::GetPropertyOverrides(
const MaterialAssignmentId& materialAssignmentId) const
{
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
{
return {};
}
return materialIt->second.m_propertyOverrides;
return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_propertyOverrides : MaterialPropertyOverrideMap();
}
void MaterialComponentController::SetModelUvOverrides(
@@ -730,6 +723,12 @@ namespace AZ
const bool wasEmpty = materialAssignment.m_matModUvOverrides.empty();
materialAssignment.m_matModUvOverrides = modelUvOverrides;
if (materialAssignment.RequiresLoading())
{
LoadMaterials();
return;
}
if (wasEmpty != materialAssignment.m_matModUvOverrides.empty())
{
materialAssignment.RebuildInstance();
@@ -743,16 +742,24 @@ namespace AZ
const MaterialAssignmentId& materialAssignmentId) const
{
const auto materialIt = m_configuration.m_materials.find(materialAssignmentId);
if (materialIt == m_configuration.m_materials.end())
return materialIt != m_configuration.m_materials.end() ? materialIt->second.m_matModUvOverrides : AZ::RPI::MaterialModelUvOverrideMap();
}
void MaterialComponentController::OnMaterialAssignmentsChanged()
{
for (const auto& materialPair : m_configuration.m_materials)
{
return {};
if (materialPair.second.RequiresLoading())
{
LoadMaterials();
return;
}
}
return materialIt->second.m_matModUvOverrides;
}
void MaterialComponentController::QueuePropertyChanges(const MaterialAssignmentId& materialAssignmentId)
{
m_queuedPropertyOverrides.emplace(materialAssignmentId);
m_materialsWithDirtyProperties.emplace(materialAssignmentId);
if (!TickBus::Handler::BusIsConnected())
{
TickBus::Handler::BusConnect();
@@ -22,6 +22,7 @@ namespace AZ
//! to provide material overrides on a per-entity basis.
class MaterialComponentController final
: MaterialComponentRequestBus::Handler
, MaterialReceiverNotificationBus::Handler
, Data::AssetBus::MultiHandler
, TickBus::Handler
{
@@ -100,6 +101,9 @@ namespace AZ
const MaterialAssignmentId& materialAssignmentId, const AZ::RPI::MaterialModelUvOverrideMap& modelUvOverrides) override;
AZ::RPI::MaterialModelUvOverrideMap GetModelUvOverrides(const MaterialAssignmentId& materialAssignmentId) const override;
//! MaterialReceiverNotificationBus::Handler overrides...
void OnMaterialAssignmentsChanged() override;
private:
AZ_DISABLE_COPY(MaterialComponentController);
@@ -121,7 +125,7 @@ namespace AZ
EntityId m_entityId;
MaterialComponentConfig m_configuration;
AZStd::unordered_set<MaterialAssignmentId> m_queuedPropertyOverrides;
AZStd::unordered_set<MaterialAssignmentId> m_materialsWithDirtyProperties;
bool m_queuedMaterialUpdateNotification = false;
};
} // namespace Render
@@ -726,10 +726,12 @@ namespace EMotionFX
{
MCore::LockGuardRecursive lock(m_mutex);
return AZStd::accumulate(begin(m_childSets), end(m_childSets), size_t{0}, [](size_t total, const MotionSet* motionSet)
size_t result = 0;
for (const MotionSet* motionSet : m_childSets)
{
return total + motionSet->GetIsOwnedByRuntime();
});
result += !motionSet->GetIsOwnedByRuntime();
}
return result;
}
@@ -8,21 +8,20 @@
#pragma once
#include "ColliderSubComponentMode.h"
#include <Editor/Source/ComponentModes/PhysXSubComponentModeBase.h>
#include <AzToolsFramework/Manipulators/ScaleManipulators.h>
namespace PhysX
{
/// Sub component mode for modifying the asset scale on a collider in the viewport.
class ColliderAssetScaleMode
: public PhysX::ColliderSubComponentMode
class ColliderAssetScaleMode : public PhysXSubComponentModeBase
{
public:
AZ_CLASS_ALLOCATOR_DECL
ColliderAssetScaleMode();
// ColliderSubComponentMode ...
// PhysXSubComponentModeBase ...
void Setup(const AZ::EntityComponentIdPair& idPair) override;
void Refresh(const AZ::EntityComponentIdPair& idPair) override;
void Teardown(const AZ::EntityComponentIdPair& idPair) override;
+3 -4
View File
@@ -8,19 +8,18 @@
#pragma once
#include "ColliderSubComponentMode.h"
#include <Editor/Source/ComponentModes/PhysXSubComponentModeBase.h>
#include <AzToolsFramework/ComponentModes/BoxViewportEdit.h>
namespace PhysX
{
/// Sub component mode for modifying the box dimensions on a collider.
class ColliderBoxMode
: public PhysX::ColliderSubComponentMode
class ColliderBoxMode : public PhysXSubComponentModeBase
{
public:
AZ_CLASS_ALLOCATOR_DECL
// ColliderSubComponentMode ...
// PhysXSubComponentModeBase ...
void Setup(const AZ::EntityComponentIdPair& idPair) override;
void Refresh(const AZ::EntityComponentIdPair& idPair) override;
void Teardown(const AZ::EntityComponentIdPair& idPair) override;
+3 -3
View File
@@ -8,7 +8,7 @@
#pragma once
#include "ColliderSubComponentMode.h"
#include <Editor/Source/ComponentModes/PhysXSubComponentModeBase.h>
#include <AzToolsFramework/ComponentModes/BoxViewportEdit.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
@@ -16,13 +16,13 @@ namespace PhysX
{
/// Sub component mode for modifying the height and radius on a capsule collider.
class ColliderCapsuleMode
: public PhysX::ColliderSubComponentMode
: public PhysXSubComponentModeBase
, private AzFramework::EntityDebugDisplayEventBus::Handler
{
public:
AZ_CLASS_ALLOCATOR_DECL
// ColliderSubComponentMode ...
// PhysXSubComponentModeBase ...
void Setup(const AZ::EntityComponentIdPair& idPair) override;
void Refresh(const AZ::EntityComponentIdPair& idPair) override;
void Teardown(const AZ::EntityComponentIdPair& idPair) override;
@@ -7,7 +7,6 @@
*/
#include "ColliderComponentMode.h"
#include "ColliderSubComponentMode.h"
#include "ColliderOffsetMode.h"
#include "ColliderRotationMode.h"
#include "ColliderBoxMode.h"
@@ -15,6 +14,7 @@
#include "ColliderCapsuleMode.h"
#include "ColliderAssetScaleMode.h"
#include <Editor/Source/ComponentModes/PhysXSubComponentModeBase.h>
#include <PhysX/EditorColliderComponentRequestBus.h>
#include <AzFramework/Physics/ShapeConfiguration.h>
@@ -15,7 +15,7 @@
namespace PhysX
{
class ColliderSubComponentMode;
class PhysXSubComponentModeBase;
//! ComponentMode for the Collider Component - Manages a list of Sub-Component Modes and
//! is responsible for switching between and activating them.
@@ -53,7 +53,7 @@ namespace PhysX
void CreateSubModes();
void ResetCurrentMode();
AZStd::unordered_map<SubMode, AZStd::unique_ptr<ColliderSubComponentMode>> m_subModes;
AZStd::unordered_map<SubMode, AZStd::unique_ptr<PhysXSubComponentModeBase>> m_subModes;
SubMode m_subMode = SubMode::Dimensions;
//! Create the Viewport UI cluster for sub mode selection.
+3 -4
View File
@@ -8,21 +8,20 @@
#pragma once
#include "ColliderSubComponentMode.h"
#include <Editor/Source/ComponentModes/PhysXSubComponentModeBase.h>
#include <AzToolsFramework/Manipulators/TranslationManipulators.h>
namespace PhysX
{
/// Sub component mode for modifying offset on a collider in the viewport.
class ColliderOffsetMode
: public PhysX::ColliderSubComponentMode
class ColliderOffsetMode : public PhysXSubComponentModeBase
{
public:
AZ_CLASS_ALLOCATOR_DECL
ColliderOffsetMode();
// ColliderSubComponentMode ...
// PhysXSubComponentModeBase ...
void Setup(const AZ::EntityComponentIdPair& idPair) override;
void Refresh(const AZ::EntityComponentIdPair& idPair) override;
void Teardown(const AZ::EntityComponentIdPair& idPair) override;
@@ -8,7 +8,7 @@
#pragma once
#include "ColliderSubComponentMode.h"
#include <Editor/Source/ComponentModes/PhysXSubComponentModeBase.h>
#include <AzToolsFramework/Manipulators/RotationManipulators.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
@@ -16,7 +16,7 @@ namespace PhysX
{
/// Sub component mode for modifying the rotation on a collider in the viewport.
class ColliderRotationMode
: public PhysX::ColliderSubComponentMode
: public PhysXSubComponentModeBase
, private AzFramework::EntityDebugDisplayEventBus::Handler
{
public:
@@ -24,7 +24,7 @@ namespace PhysX
ColliderRotationMode();
// ColliderSubComponentMode ...
// PhysXSubComponentModeBase ...
void Setup(const AZ::EntityComponentIdPair& idPair) override;
void Refresh(const AZ::EntityComponentIdPair& idPair) override;
void Teardown(const AZ::EntityComponentIdPair& idPair) override;
+3 -3
View File
@@ -8,7 +8,7 @@
#pragma once
#include "ColliderSubComponentMode.h"
#include <Editor/Source/ComponentModes/PhysXSubComponentModeBase.h>
#include <AzToolsFramework/ComponentModes/BoxViewportEdit.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
@@ -16,13 +16,13 @@ namespace PhysX
{
/// Sub component mode for modifying the box dimensions on a collider.
class ColliderSphereMode
: public PhysX::ColliderSubComponentMode
: public PhysXSubComponentModeBase
, private AzFramework::EntityDebugDisplayEventBus::Handler
{
public:
AZ_CLASS_ALLOCATOR_DECL
// ColliderSubComponentMode ...
// PhysXSubComponentModeBase ...
void Setup(const AZ::EntityComponentIdPair& idPair) override;
void Refresh(const AZ::EntityComponentIdPair& idPair) override;
void Teardown(const AZ::EntityComponentIdPair& idPair) override;
@@ -1,42 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
namespace AZ
{
class EntityComponentIdPair;
}
namespace PhysX
{
/// Interface to implement when adding a new editing mode
/// for collider component mode.
class ColliderSubComponentMode
{
public:
virtual ~ColliderSubComponentMode() {};
/// Called when the mode is entered to initialise the mode.
/// @param idPair The entity/component id pair.
virtual void Setup(const AZ::EntityComponentIdPair& idPair) = 0;
/// Called when the mode needs to refresh it's values.
/// @param idPair The entity/component id pair.
virtual void Refresh(const AZ::EntityComponentIdPair& idPair) = 0;
/// Called when the mode exits to perform cleanup.
/// @param idPair The entity/component id pair.
virtual void Teardown(const AZ::EntityComponentIdPair& idPair) = 0;
/// Called when reset hotkey is pressed.
/// Should reset values in the sub component mode to sensible defaults.
/// @param idPair The entity/component id pair.
virtual void ResetValues(const AZ::EntityComponentIdPair& idPair) = 0;
};
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/utils.h>
namespace PhysX
{
//! Pair of floating point values for angular limits.
using AngleLimitsFloatPair = AZStd::pair<float, float>;
} // namespace PhysX
@@ -1,577 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Editor/EditorJointConfiguration.h>
#include <Editor/EditorJointComponentMode.h>
#include <Editor/EditorSubComponentModeAngleCone.h>
#include <Editor/EditorSubComponentModeAnglePair.h>
#include <Editor/EditorSubComponentModeLinear.h>
#include <Editor/EditorSubComponentModeRotation.h>
#include <Editor/EditorSubComponentModeSnapPosition.h>
#include <Editor/EditorSubComponentModeSnapRotation.h>
#include <Editor/EditorSubComponentModeVec3.h>
#include <PhysX/EditorJointBus.h>
namespace PhysX
{
namespace
{
//! Uri's for shortcut actions.
const AZ::Crc32 GoToNextModeActionUri = AZ_CRC("com.o3de.action.physx.joint.nextmode", 0xe9cf4ed6);
const AZ::Crc32 GoToPrevModeActionUri = AZ_CRC("com.o3de.action.physx.joint.prevmode", 0xe70f8daa);
}
const AZStd::string EditorJointComponentMode::s_parameterAngularPair = "Twist Limits";
const AZStd::string EditorJointComponentMode::s_parameterDamping = "Damping";
const AZStd::string EditorJointComponentMode::s_parameterMaxForce = "Maximum Force";
const AZStd::string EditorJointComponentMode::s_parameterMaxTorque = "Maximum Torque";
const AZStd::string EditorJointComponentMode::s_parameterPosition = "Position";
const AZStd::string EditorJointComponentMode::s_parameterRotation = "Rotation";
const AZStd::string EditorJointComponentMode::s_parameterSnapPosition = "Snap Position";
const AZStd::string EditorJointComponentMode::s_parameterSnapRotation = "Snap Rotation";
const AZStd::string EditorJointComponentMode::s_parameterStiffness = "Stiffness";
const AZStd::string EditorJointComponentMode::s_parameterSwingLimit = "Swing Limits";
const AZStd::string EditorJointComponentMode::s_parameterTolerance = "Tolerance";
const AZStd::string EditorJointComponentMode::s_parameterTransform = "Transform";
const AZStd::string EditorJointComponentMode::s_parameterComponentMode = "Component Mode";
const AZStd::string EditorJointComponentMode::s_parameterLeadEntity = "Lead Entity";
const AZStd::string EditorJointComponentMode::s_parameterSelectOnSnap = "Select on Snap";
EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name
, EditorSubComponentModeType type)
: m_name(name), m_type(type)
{
}
EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name
, EditorSubComponentModeType type
, float exponent
, float max
, float min)
: m_name(name), m_type(type), m_exponent(exponent), m_max(max), m_min(min)
{
}
EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name
, EditorSubComponentModeType type
, const AZ::Vector3& axis
, float max
, float min)
: m_name(name), m_type(type), m_axis(axis), m_max(max), m_min(min)
{
}
EditorSubComponentModeConfig::EditorSubComponentModeConfig(const AZStd::string& name
, EditorSubComponentModeType type
, float max
, float min)
: m_name(name), m_type(type), m_max(max), m_min(min)
{
}
EditorJointComponentMode::EditorJointComponentMode(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType)
: EditorBaseComponentMode(entityComponentIdPair, componentType)
, m_entityComponentIdPair(entityComponentIdPair)
, m_componentType(componentType)
{
EditorJointRequestBus::Event(
m_entityComponentIdPair
, &EditorJointRequests::SetBoolValue
, EditorJointComponentMode::s_parameterComponentMode
, true);
}
EditorJointComponentMode::~EditorJointComponentMode()
{
EditorJointRequestBus::Event(
m_entityComponentIdPair
, &EditorJointRequests::SetBoolValue
, EditorJointComponentMode::s_parameterComponentMode
, false);
}
bool EditorJointComponentMode::HandleMouseInteraction(
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction)
{
if (mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Wheel &&
mouseInteraction.m_mouseInteraction.m_keyboardModifiers.Ctrl())
{
NextMode();
return true;
}
// Propagate mouse interaction to sub-component mode.
if (m_currentSubComponentMode)
{
m_currentSubComponentMode->HandleMouseInteraction(mouseInteraction);
}
return false;
}
AZStd::vector<AzToolsFramework::ActionOverride> EditorJointComponentMode::PopulateActionsImpl()
{
AzToolsFramework::ActionOverride goToNextMode;
goToNextMode.SetUri(GoToNextModeActionUri);
goToNextMode.SetKeySequence(QKeySequence(Qt::Key_Tab));
goToNextMode.SetTitle("Next Mode");
goToNextMode.SetTip("Go to next mode");
goToNextMode.SetEntityComponentIdPair(GetEntityComponentIdPair());
goToNextMode.SetCallback([this]()
{
NextMode();
});
AzToolsFramework::ActionOverride goToPrevMode;
goToPrevMode.SetUri(GoToPrevModeActionUri);
goToPrevMode.SetKeySequence(QKeySequence(Qt::SHIFT + Qt::Key_Tab));
goToPrevMode.SetTitle("Previous Mode");
goToPrevMode.SetTip("Go to previous mode");
goToPrevMode.SetEntityComponentIdPair(GetEntityComponentIdPair());
goToPrevMode.SetCallback([this]()
{
PreviousMode();
});
return {goToNextMode, goToPrevMode};
}
void EditorJointComponentMode::NextMode()
{
const bool isForwardChange = true;
ChangeMode(isForwardChange);
}
void EditorJointComponentMode::PreviousMode()
{
const bool isForwardChange = false;
ChangeMode(isForwardChange);
}
void EditorJointComponentMode::ChangeMode(bool forwardChange)
{
if (m_configMap.empty())
{
return;
}
AZStd::string previousModeName;
if (m_currentSubComponentMode)
{
previousModeName = m_currentSubComponentMode->m_name;
m_currentSubComponentMode.reset();
}
ConfigMapIter configIter = m_configMap.begin();
if (!previousModeName.empty())
{
configIter = m_configMap.find(previousModeName);
}
AZ::u32 iterCount = 0;
do
{
if (forwardChange)
{
++configIter;
if (configIter == m_configMap.end())
{
configIter = m_configMap.begin();
}
}
else
{
if (configIter == m_configMap.begin())
{
configIter = m_configMap.end();
}
--configIter;
}
++iterCount;
} while (!IsSubComponentModeUsed(configIter->second.m_name) && iterCount != m_configMap.size());
if (iterCount == m_configMap.size()) // All sub component modes are not in use.
{
return;
}
SetCurrentSubComponentMode(configIter->second.m_name);
}
void EditorJointComponentMode::SetCurrentSubComponentMode(const AZStd::string& subComponentModeName)
{
ConfigMapIter configIter = m_configMap.find(subComponentModeName);
if (configIter == m_configMap.end())
{
AZ_Warning("EditorJointComponentMode"
, false
, "Attempt to set sub component mode which does not exist: %s"
, subComponentModeName.c_str());
return;
}
EditorSubComponentModeConfig config = configIter->second;
EditorJointRequestBus::EventResult(
config.m_selectLeadOnSnap, m_entityComponentIdPair
, &EditorJointRequests::GetBoolValue
, s_parameterSelectOnSnap);
m_currentSubComponentMode.reset();
switch (config.m_type)
{
case EditorSubComponentModeType::Linear:
SetSubComponentModeLinear(config);
break;
case EditorSubComponentModeType::AnglePair:
SetSubComponentModeAnglePair(config);
break;
case EditorSubComponentModeType::AngleCone:
SetSubComponentModeAngleCone(config);
break;
case EditorSubComponentModeType::Vec3:
SetSubComponentModeVec3(config);
break;
case EditorSubComponentModeType::Rotation:
SetSubComponentModeRotation(config);
break;
case EditorSubComponentModeType::SnapPosition:
SetSubComponentModeSnapPosition(config);
break;
case EditorSubComponentModeType::SnapRotation:
SetSubComponentModeSnapRotation(config);
break;
default:
AZ_Error("EditorJointComponentMode::SetCurrentSubComponentMode"
, false
, "Unsupported sub-component mode type.");
}
}
bool EditorJointComponentMode::IsSubComponentModeUsed(const AZStd::string& subComponentModeName)
{
bool isUsed = false;
EditorJointRequestBus::EventResult(
isUsed, m_entityComponentIdPair
, &EditorJointRequests::IsParameterUsed
, subComponentModeName);
return isUsed;
}
void EditorJointComponentMode::SetSubComponentModeAngleCone(const EditorSubComponentModeConfig& config)
{
m_currentSubComponentMode = AZStd::make_shared<EditorSubComponentModeAngleCone>(m_entityComponentIdPair
, m_componentType
, config.m_name
, config.m_max
, config.m_min);
}
void EditorJointComponentMode::SetSubComponentModeAnglePair(const EditorSubComponentModeConfig& config)
{
m_currentSubComponentMode = AZStd::make_shared<EditorSubComponentModeAnglePair>(m_entityComponentIdPair
, m_componentType
, config.m_name
, config.m_axis
, config.m_max
, config.m_min
, config.m_min
, -config.m_max);
}
void EditorJointComponentMode::SetSubComponentModeLinear(const EditorSubComponentModeConfig& config)
{
m_currentSubComponentMode = AZStd::make_shared<EditorSubComponentModeLinear>(m_entityComponentIdPair
, m_componentType
, config.m_name
, config.m_exponent
, config.m_max
, config.m_min);
}
void EditorJointComponentMode::SetSubComponentModeVec3(const EditorSubComponentModeConfig& config)
{
m_currentSubComponentMode = AZStd::make_shared<EditorSubComponentModeVec3>(m_entityComponentIdPair
, m_componentType
, config.m_name);
}
void EditorJointComponentMode::SetSubComponentModeRotation(const EditorSubComponentModeConfig& config)
{
m_currentSubComponentMode = AZStd::make_shared<EditorSubComponentModeRotation>(m_entityComponentIdPair
, m_componentType
, config.m_name);
}
void EditorJointComponentMode::SetSubComponentModeSnapPosition(const EditorSubComponentModeConfig& config)
{
m_currentSubComponentMode = AZStd::make_shared<EditorSubComponentModeSnapPosition>(m_entityComponentIdPair
, m_componentType
, config.m_name
, config.m_selectLeadOnSnap);
}
void EditorJointComponentMode::SetSubComponentModeSnapRotation(const EditorSubComponentModeConfig& config)
{
m_currentSubComponentMode = AZStd::make_shared<EditorSubComponentModeSnapRotation>(m_entityComponentIdPair
, m_componentType
, config.m_name);
}
EditorBallJointComponentMode::EditorBallJointComponentMode(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType)
: EditorJointComponentMode(entityComponentIdPair, componentType)
{
m_configMap = Configure();
NextMode();
}
EditorBallJointComponentMode::~EditorBallJointComponentMode()
{
if (m_currentSubComponentMode)
{
m_currentSubComponentMode.reset();
}
}
void EditorJointComponentMode::Refresh()
{
if (m_currentSubComponentMode)
{
m_currentSubComponentMode->Refresh();
}
}
AZStd::map<AZStd::string, EditorSubComponentModeConfig> EditorBallJointComponentMode::Configure()
{
AZStd::map<AZStd::string, EditorSubComponentModeConfig> configMap;
configMap.emplace(
EditorJointComponentMode::s_parameterPosition
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterPosition
, EditorSubComponentModeType::Vec3)
);
configMap.emplace(
EditorJointComponentMode::s_parameterRotation
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterRotation
, EditorSubComponentModeType::Rotation)
);
configMap.emplace(
EditorJointComponentMode::s_parameterSnapPosition
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSnapPosition
, EditorSubComponentModeType::SnapPosition)
);
configMap.emplace(
EditorJointComponentMode::s_parameterSnapRotation
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSnapRotation
, EditorSubComponentModeType::SnapRotation)
);
const float exponentBreakage = 1.0f;
configMap.emplace(
EditorJointComponentMode::s_parameterMaxForce
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxForce
, EditorSubComponentModeType::Linear
, exponentBreakage
, PhysX::EditorJointConfig::s_breakageMax
, PhysX::EditorJointConfig::s_breakageMin)
);
configMap.emplace(
EditorJointComponentMode::s_parameterMaxTorque
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxTorque
, EditorSubComponentModeType::Linear
, exponentBreakage
, PhysX::EditorJointConfig::s_breakageMax
, PhysX::EditorJointConfig::s_breakageMin)
);
const float exponentSpring = 2.0f;
configMap.emplace(
EditorJointComponentMode::s_parameterDamping
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterDamping
, EditorSubComponentModeType::Linear
, exponentSpring
, PhysX::EditorJointLimitConeConfig::s_springMax
, PhysX::EditorJointLimitConeConfig::s_springMin)
);
configMap.emplace(
EditorJointComponentMode::s_parameterStiffness
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterStiffness
, EditorSubComponentModeType::Linear
, exponentSpring
, PhysX::EditorJointLimitConeConfig::s_springMax
, PhysX::EditorJointLimitConeConfig::s_springMin)
);
// Cone tip to base is always X-axis.
//The angle cone defines the limitations for rotation about the Y and Z axes.
configMap.emplace(
EditorJointComponentMode::s_parameterSwingLimit
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSwingLimit
, EditorSubComponentModeType::AngleCone
, PhysX::EditorJointLimitConeConfig::s_angleMax
, PhysX::EditorJointLimitConeConfig::s_angleMin)
);
return configMap;
}
EditorFixedJointComponentMode::EditorFixedJointComponentMode(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType)
: EditorJointComponentMode(entityComponentIdPair, componentType)
{
m_configMap = Configure();
NextMode();
}
EditorFixedJointComponentMode::~EditorFixedJointComponentMode()
{
if (m_currentSubComponentMode)
{
m_currentSubComponentMode.reset();
}
}
AZStd::map<AZStd::string, EditorSubComponentModeConfig> EditorFixedJointComponentMode::Configure()
{
AZStd::map<AZStd::string, EditorSubComponentModeConfig> configMap;
configMap.emplace(
EditorJointComponentMode::s_parameterPosition
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterPosition
, EditorSubComponentModeType::Vec3)
);
configMap.emplace(
EditorJointComponentMode::s_parameterRotation
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterRotation
, EditorSubComponentModeType::Rotation)
);
const float exponentBreakage = 1.0f;
configMap.emplace(
EditorJointComponentMode::s_parameterMaxForce
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxForce
, EditorSubComponentModeType::Linear
, exponentBreakage
, PhysX::EditorJointConfig::s_breakageMax
, PhysX::EditorJointConfig::s_breakageMin)
);
configMap.emplace(
EditorJointComponentMode::s_parameterMaxTorque
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxTorque
, EditorSubComponentModeType::Linear
, exponentBreakage
, PhysX::EditorJointConfig::s_breakageMax
, PhysX::EditorJointConfig::s_breakageMin)
);
return configMap;
}
EditorHingeJointComponentMode::EditorHingeJointComponentMode(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType)
: EditorJointComponentMode(entityComponentIdPair, componentType)
{
m_configMap = Configure();
NextMode();
}
EditorHingeJointComponentMode::~EditorHingeJointComponentMode()
{
if (m_currentSubComponentMode)
{
m_currentSubComponentMode.reset();
}
}
AZStd::map<AZStd::string, EditorSubComponentModeConfig> EditorHingeJointComponentMode::Configure()
{
AZStd::map<AZStd::string, EditorSubComponentModeConfig> configMap;
configMap.emplace(
EditorJointComponentMode::s_parameterPosition
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterPosition
, EditorSubComponentModeType::Vec3)
);
configMap.emplace(
EditorJointComponentMode::s_parameterRotation
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterRotation
, EditorSubComponentModeType::Rotation)
);
const float exponentBreakage = 1.0f;
configMap.emplace(
EditorJointComponentMode::s_parameterMaxForce
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxForce
, EditorSubComponentModeType::Linear
, exponentBreakage
, PhysX::EditorJointConfig::s_breakageMax
, PhysX::EditorJointConfig::s_breakageMin)
);
configMap.emplace(
EditorJointComponentMode::s_parameterMaxTorque
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterMaxTorque
, EditorSubComponentModeType::Linear
, exponentBreakage
, PhysX::EditorJointConfig::s_breakageMax
, PhysX::EditorJointConfig::s_breakageMin)
);
const float exponentSpring = 2.0f;
configMap.emplace(
EditorJointComponentMode::s_parameterDamping
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterDamping
, EditorSubComponentModeType::Linear
, exponentSpring
, PhysX::EditorJointLimitPairConfig::s_springMax
, PhysX::EditorJointLimitPairConfig::s_springMin)
);
configMap.emplace(
EditorJointComponentMode::s_parameterStiffness
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterStiffness
, EditorSubComponentModeType::Linear
, exponentSpring
, PhysX::EditorJointLimitPairConfig::s_springMax
, PhysX::EditorJointLimitPairConfig::s_springMin)
);
AZ::Vector3 axis = AZ::Vector3::CreateAxisX(); // PhysX revolute joints uses the x-axis by default
configMap.emplace(
EditorJointComponentMode::s_parameterAngularPair
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterAngularPair
, EditorSubComponentModeType::AnglePair
, axis
, PhysX::EditorJointLimitPairConfig::s_angleMax
, PhysX::EditorJointLimitPairConfig::s_angleMin)
);
configMap.emplace(
EditorJointComponentMode::s_parameterSnapPosition
, EditorSubComponentModeConfig(EditorJointComponentMode::s_parameterSnapPosition
, EditorSubComponentModeType::SnapPosition)
);
return configMap;
}
} // namespace LmbrCentral
@@ -1,173 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/containers/map.h>
#include <AzToolsFramework/ComponentMode/EditorBaseComponentMode.h>
#include <Editor/EditorSubComponentModeBase.h>
namespace PhysX
{
enum class EditorSubComponentModeType : AZ::u8
{
Linear, /// sub-component mode to modify a single linear value, e.g. a float value.
AnglePair, /// sub-component mode to modify a pair of float values representing angles.
AngleCone, /// sub-component mode to modify a constraint's swing limits and local transformation.
Rotation, /// sub-component mode to modify local transformation.
SnapPosition, /// sub-component mode to modify local position using a point-and-snap feature in the viewport.
SnapRotation, /// sub-component mode to modify local rotation using a point-and-snap feature in the viewport.
Vec3 /// sub-component mode to modify a Vector3 value.
};
/// Contains configuration of a sub-component mode. Shared by different types of sub-component mode.
/// Alternative implementation of this struct using AZStd::Variant is pending the development of the rest of the joint types.
struct EditorSubComponentModeConfig
{
EditorSubComponentModeConfig() = default;
EditorSubComponentModeConfig(const AZStd::string& name
, EditorSubComponentModeType type);
EditorSubComponentModeConfig(const AZStd::string& name
, EditorSubComponentModeType type
, float exponent
, float max
, float min);
EditorSubComponentModeConfig(const AZStd::string& name
, EditorSubComponentModeType type
, const AZ::Vector3& axis
, float max
, float min);
EditorSubComponentModeConfig(const AZStd::string& name
, EditorSubComponentModeType type
, float max
, float min);
AZStd::string m_name;
EditorSubComponentModeType m_type;
AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX();
float m_exponent = 1.0f;
float m_max = FLT_MAX;
float m_min = -FLT_MAX;
bool m_selectLeadOnSnap = true; ///< A user may use the snap-to-position component mode to snap the position of a joint to an entity. This flag indicates if the snapped-to entity would be selected as a joint's lead when that happens.
};
/// Generic component mode that supports multiple sub-component modes.
class EditorJointComponentMode
: public AzToolsFramework::ComponentModeFramework::EditorBaseComponentMode
{
public:
static const AZStd::string s_parameterAngularPair;
static const AZStd::string s_parameterDamping;
static const AZStd::string s_parameterMaxForce;
static const AZStd::string s_parameterMaxTorque;
static const AZStd::string s_parameterPosition;
static const AZStd::string s_parameterRotation;
static const AZStd::string s_parameterSnapPosition;
static const AZStd::string s_parameterSnapRotation;
static const AZStd::string s_parameterStiffness;
static const AZStd::string s_parameterSwingLimit;
static const AZStd::string s_parameterTolerance;
static const AZStd::string s_parameterTransform;
static const AZStd::string s_parameterComponentMode;
static const AZStd::string s_parameterLeadEntity;
static const AZStd::string s_parameterSelectOnSnap;
EditorJointComponentMode(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType);
~EditorJointComponentMode();
// EditorBaseComponentMode
void Refresh() override;
/// Returns map of sub-component mode configurations required by this component mode.
virtual AZStd::map<AZStd::string, EditorSubComponentModeConfig> Configure() = 0;
protected:
/// AzToolsFramework::ViewportInteraction::MouseViewportRequests
bool HandleMouseInteraction(
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) override;
/// EditorBaseComponentMode
AZStd::vector<AzToolsFramework::ActionOverride> PopulateActionsImpl() override;
/// Changes to the next sub-component mode found in m_configMap.
void NextMode();
/// Changes to the previous sub-component mode found in m_configMap.
void PreviousMode();
/// Changes to the next or previous sub-component mode found in m_configMap.
void ChangeMode(bool forwardChange);
/// Replaces m_currentSubComponentMode with a new one instantiated using the configuration identified by the input subComponentModeName.
void SetCurrentSubComponentMode(const AZStd::string& subComponentModeName);
AZStd::shared_ptr<EditorSubComponentModeBase> m_currentSubComponentMode = nullptr; ///< The active sub-component mode in this component mode.
AZ::Uuid m_componentType = AZ::Uuid::CreateNull();
AZStd::map<AZStd::string, EditorSubComponentModeConfig> m_configMap; ///< Contains sub-component mode configurations supported by this component mode.
AZ::EntityComponentIdPair m_entityComponentIdPair;
private:
bool IsSubComponentModeUsed(const AZStd::string& subComponentModeName);
void SetSubComponentModeAngleCone(const EditorSubComponentModeConfig& config);
void SetSubComponentModeAnglePair(const EditorSubComponentModeConfig& config);
void SetSubComponentModeLinear(const EditorSubComponentModeConfig& config);
void SetSubComponentModeVec3(const EditorSubComponentModeConfig& config);
void SetSubComponentModeRotation(const EditorSubComponentModeConfig& config);
void SetSubComponentModeSnapPosition(const EditorSubComponentModeConfig& config);
void SetSubComponentModeSnapRotation(const EditorSubComponentModeConfig& config);
};
/// Ball joint specific component mode. Configure() is overriden to set up the required sub-component modes.
class EditorBallJointComponentMode
: public EditorJointComponentMode
{
public:
EditorBallJointComponentMode(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType);
~EditorBallJointComponentMode();
// EditorJointComponentMode
AZStd::map<AZStd::string, EditorSubComponentModeConfig> Configure() override;
};
/// Fixed joint specific component mode. Configure() is overriden to set up the required sub-component modes.
class EditorFixedJointComponentMode
: public EditorJointComponentMode
{
public:
EditorFixedJointComponentMode(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType);
~EditorFixedJointComponentMode();
// EditorJointComponentMode
AZStd::map<AZStd::string, EditorSubComponentModeConfig> Configure() override;
};
/// Hinge joint specific component mode. Configure() is overriden to set up the required sub-component modes.
class EditorHingeJointComponentMode
: public EditorJointComponentMode
{
public:
EditorHingeJointComponentMode(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Uuid& componentType);
~EditorHingeJointComponentMode();
// EditorJointComponentMode
AZStd::map<AZStd::string, EditorSubComponentModeConfig> Configure() override;
};
using ConfigMap = AZStd::map<AZStd::string, EditorSubComponentModeConfig>;
using ConfigMapIter = ConfigMap::iterator;
using ConfigMapReverseIter = ConfigMap::reverse_iterator;
} // namespace PhysX
@@ -1,68 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <Editor/EditorJointTypeDrawer.h>
namespace PhysX
{
EditorJointTypeDrawer::EditorJointTypeDrawer(EditorJointType jointType,
AzFramework::EntityContextId entityContextId,
const AZStd::string& subComponentModeName):
m_subComponentModeName(subComponentModeName)
{
AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(entityContextId);
EditorJointTypeDrawerBus::Handler::BusConnect(EditorJointTypeDrawerId(jointType,
EditorSubComponentModeNameCrc(subComponentModeName)));
}
EditorJointTypeDrawer::~EditorJointTypeDrawer()
{
EditorJointTypeDrawerBus::Handler::BusDisconnect();
AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect();
}
void EditorJointTypeDrawer::DisplayViewport2d(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay)
{
const AZ::u32 stateBefore = debugDisplay.GetState();
const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId);
const float xOffsetCurrentMode = 125.0f;
const float yOffsetCurrentMode = 55.0f;
const float xOffsetHotKeys = 125.0f;
const float yOffsetHotKeys = 30.0f;
const float viewportWidthHalf = cameraState.m_viewportSize.GetX() / 2.0f;
const float viewportHeight = cameraState.m_viewportSize.GetY();
debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, 1.0f));
AZStd::string screenTextCurrentMode = "Edit mode: " + m_subComponentModeName;
float xPos = viewportWidthHalf - xOffsetCurrentMode;
float yPos = viewportHeight - yOffsetCurrentMode;
float textSize = 2.0f;
debugDisplay.Draw2dTextLabel(xPos, yPos, textSize, screenTextCurrentMode.c_str());
AZStd::string screenTextHotKeys = "<Tab> or <Shift+Tab> to change modes";
xPos = viewportWidthHalf - xOffsetHotKeys;
yPos = viewportHeight - yOffsetHotKeys;
textSize = 1.2f;
debugDisplay.Draw2dTextLabel(xPos, yPos, textSize, screenTextHotKeys.c_str());
debugDisplay.SetState(stateBefore);
}
AZStd::shared_ptr<EditorJointTypeDrawer> EditorJointTypeDrawer::GetEditorJointTypeDrawer()
{
return shared_from_this();
}
} // namespace PhysX
@@ -1,41 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/std/smart_ptr/enable_shared_from_this.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <Editor/EditorJointTypeDrawerBus.h>
namespace PhysX
{
/// This class enables drawing in the viewport once for the component modes of multiple components in one entity.
/// Until the component mode framework allows a way to do this, a work-around like this class is necessary.
/// An instance of this class is created for each pair of component type and sub-component mode.
class EditorJointTypeDrawer
: public EditorJointTypeDrawerBus::Handler
, public AZStd::enable_shared_from_this<EditorJointTypeDrawer>
, private AzFramework::ViewportDebugDisplayEventBus::Handler
{
public:
EditorJointTypeDrawer(EditorJointType id,
AzFramework::EntityContextId entityContextId,
const AZStd::string& subComponentModeName);
~EditorJointTypeDrawer();
private:
// AzFramework::ViewportDebugDisplayEventBus
void DisplayViewport2d(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
// PhysX::EditorJointTypeDrawerBus
AZStd::shared_ptr<EditorJointTypeDrawer> GetEditorJointTypeDrawer() override;
AZStd::string m_subComponentModeName;///< Name of the sub component mode. E.g. Position, Rotation, Snap Position, etc.
};
} // namespace PhysX
@@ -1,31 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
namespace PhysX
{
class EditorJointTypeDrawer;
using EditorJointType = AZ::Uuid;
using EditorSubComponentModeNameCrc = AZ::Crc32;
using EditorJointTypeDrawerId = AZStd::pair<EditorJointType, EditorSubComponentModeNameCrc>;
/// The sub-component mode of a component type uses this bus (by invoking GetEditorJointTypeDrawer) to retrieve a drawer.
/// If nothing is returned, it creates an instance of the drawer that will be shared by other instances of the same component type.
class EditorJointTypeDrawerRequests : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = EditorJointTypeDrawerId;
virtual AZStd::shared_ptr<EditorJointTypeDrawer> GetEditorJointTypeDrawer() = 0;
};
using EditorJointTypeDrawerBus = AZ::EBus<EditorJointTypeDrawerRequests>;
} // namespace PhysX
@@ -1,453 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Component/TransformBus.h>
#include <AzToolsFramework/Manipulators/AngularManipulator.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzToolsFramework/Manipulators/PlanarManipulator.h>
#include <Editor/EditorJointComponentMode.h>
#include <Editor/EditorSubComponentModeAngleCone.h>
#include <PhysX/EditorJointBus.h>
#include <Source/Utils.h>
namespace
{
const float ArrowLength = 2.0f;
const float ConeHeight = 3.0f;
const float XRotationManipulatorRadius = 2.0f;
const float XRotationManipulatorWidth = 0.05f;
}
namespace PhysX
{
struct SharedRotationState
{
AZ::Vector3 m_axis;
AZ::Quaternion m_savedOrientation = AZ::Quaternion::CreateIdentity();
AngleLimitsFloatPair m_valuePair;
};
EditorSubComponentModeAngleCone::EditorSubComponentModeAngleCone(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name
, float max
, float min)
: EditorSubComponentModeBase(entityComponentIdPair, componentType, name)
, m_max(max)
, m_min(min)
{
AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId());
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
const AZ::Quaternion localRotation = localTransform.GetRotation();
// Initialize manipulators used to resize the base of the cone.
m_yLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform);
m_yLinearManipulator->AddEntityComponentIdPair(m_entityComponentId);
m_yLinearManipulator->SetAxis(AZ::Vector3::CreateAxisZ());
m_zLinearManipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform);
m_zLinearManipulator->AddEntityComponentIdPair(m_entityComponentId);
m_zLinearManipulator->SetAxis(AZ::Vector3::CreateAxisY());
m_yzPlanarManipulator = AzToolsFramework::PlanarManipulator::MakeShared(worldTransform);
m_yzPlanarManipulator->AddEntityComponentIdPair(m_entityComponentId);
m_yzPlanarManipulator->SetAxes(AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
ConfigureLinearView(ArrowLength
, AZ::Color(1.0f, 0.0f, 0.0f, 1.0f)
, AZ::Color(0.0f, 1.0f, 0.0f, 1.0f)
, AZ::Color(0.0f, 0.0f, 1.0f, 1.0f));
ConfigurePlanarView(AZ::Color(0.0f, 1.0f, 0.0f, 1.0f)
, AZ::Color(0.0f, 0.0f, 1.0f, 1.0f));
// Position and orientate manipulators
AZ::Transform displacementTransform = localTransform;
AZ::Vector3 displacementTranslate = localRotation.TransformVector(AZ::Vector3(ConeHeight, 0.0f, 0.0f));
displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate);
m_yLinearManipulator->SetLocalTransform(displacementTransform);
m_zLinearManipulator->SetLocalTransform(displacementTransform);
m_yzPlanarManipulator->SetLocalTransform(displacementTransform);
// Initialize rotation manipulator for rotating cone
m_xRotationManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform);
m_xRotationManipulator->AddEntityComponentIdPair(m_entityComponentId);
m_xRotationManipulator->SetAxis(AZ::Vector3::CreateAxisX());
m_xRotationManipulator->SetLocalTransform(localTransform);
const AZ::Color xRotationManipulatorColor = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
m_xRotationManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle(
*m_xRotationManipulator, xRotationManipulatorColor,
XRotationManipulatorRadius, XRotationManipulatorWidth, AzToolsFramework::DrawHalfDottedCircle));
AZStd::shared_ptr<SharedRotationState> sharedRotationState =
AZStd::make_shared<SharedRotationState>();
struct SharedState
{
AngleLimitsFloatPair m_startValues;
};
auto sharedState = AZStd::make_shared<SharedState>();
m_yLinearManipulator->InstallLeftMouseDownCallback(
[this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable
{
AngleLimitsFloatPair currentValue;
EditorJointRequestBus::EventResult(
currentValue, m_entityComponentId
, &EditorJointRequests::GetLinearValuePair
, m_name);
sharedState->m_startValues = currentValue;
});
m_yLinearManipulator->InstallMouseMoveCallback(
[this, sharedState](const AzToolsFramework::LinearManipulator::Action& action)
{
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
const AZ::Quaternion localRotation = localTransform.GetRotation();
const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis));
const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * ConeHeight;
const float newBaseY = originalBaseY + axisDisplacement;
const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / ConeHeight)), m_min, m_max);
EditorJointRequestBus::Event(
m_entityComponentId
, &EditorJointRequests::SetLinearValuePair
, m_name
, AngleLimitsFloatPair(newAngle, sharedState->m_startValues.second));
m_yLinearManipulator->SetBoundsDirty();
});
m_zLinearManipulator->InstallLeftMouseDownCallback(
[this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable
{
AngleLimitsFloatPair currentValue;
EditorJointRequestBus::EventResult(
currentValue, m_entityComponentId
, &EditorJointRequests::GetLinearValuePair
, m_name);
sharedState->m_startValues = currentValue;
});
m_zLinearManipulator->InstallMouseMoveCallback(
[this, sharedState](const AzToolsFramework::LinearManipulator::Action& action)
{
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
const AZ::Quaternion localRotation = localTransform.GetRotation();
const float axisDisplacement = action.LocalPositionOffset().Dot(localRotation.TransformVector(action.m_fixed.m_axis));
const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * ConeHeight;
const float newBaseZ = originalBaseZ + axisDisplacement;
const float newAngle = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / ConeHeight)), m_min, m_max);
EditorJointRequestBus::Event(
m_entityComponentId
, &EditorJointRequests::SetLinearValuePair
, m_name
, AngleLimitsFloatPair(sharedState->m_startValues.first, newAngle));
m_zLinearManipulator->SetBoundsDirty();
});
m_yzPlanarManipulator->InstallLeftMouseDownCallback(
[this, sharedState](const AzToolsFramework::PlanarManipulator::Action& /*action*/) mutable
{
AngleLimitsFloatPair currentValue;
EditorJointRequestBus::EventResult(
currentValue, m_entityComponentId
, &EditorJointRequests::GetLinearValuePair
, m_name);
sharedState->m_startValues = currentValue;
});
m_yzPlanarManipulator->InstallMouseMoveCallback(
[this, sharedState](const AzToolsFramework::PlanarManipulator::Action& action)
{
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
const AZ::Quaternion localRotation = localTransform.GetRotation();
const float axisDisplacementY = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisY()));
const float axisDisplacementZ = action.LocalPositionOffset().Dot(localRotation.TransformVector(AZ::Vector3::CreateAxisZ()));
const float axisDisplacement = axisDisplacementZ > axisDisplacementY? axisDisplacementZ : axisDisplacementY;
const float originalBaseY = tan(AZ::DegToRad(sharedState->m_startValues.first)) * ConeHeight;
const float newBaseY = originalBaseY + axisDisplacement;
const float newAngleY = AZ::GetClamp(AZ::RadToDeg(atan(newBaseY / ConeHeight)), m_min, m_max);
const float originalBaseZ = tan(AZ::DegToRad(sharedState->m_startValues.second)) * ConeHeight;
const float newBaseZ = originalBaseZ + axisDisplacement;
const float newAngleZ = AZ::GetClamp(AZ::RadToDeg(atan(newBaseZ / ConeHeight)), m_min, m_max);
EditorJointRequestBus::Event(
m_entityComponentId
, &EditorJointRequests::SetLinearValuePair
, m_name
, AngleLimitsFloatPair(newAngleY, newAngleZ));
m_yzPlanarManipulator->SetBoundsDirty();
});
struct SharedStateXRotate
{
AZ::Transform m_startTM;
};
auto sharedStateXRotate = AZStd::make_shared<SharedStateXRotate>();
auto mouseDownCallback = [this, sharedRotationState](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void
{
AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized();
sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ());
sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity();
AngleLimitsFloatPair currentValue;
EditorJointRequestBus::EventResult(
currentValue, m_entityComponentId
, &EditorJointRequests::GetLinearValuePair
, m_name);
sharedRotationState->m_valuePair = currentValue;
};
auto mouseDownRotateXCallback = [this, sharedStateXRotate]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void
{
PhysX::EditorJointRequestBus::EventResult(sharedStateXRotate->m_startTM
, m_entityComponentId
, &PhysX::EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
};
m_xRotationManipulator->InstallLeftMouseDownCallback(mouseDownRotateXCallback);
m_xRotationManipulator->InstallMouseMoveCallback(
[this, sharedStateXRotate]
(const AzToolsFramework::AngularManipulator::Action& action) mutable -> void
{
const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta;
AZ::Transform newTransform = AZ::Transform::CreateIdentity();
newTransform = sharedStateXRotate->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta);
PhysX::EditorJointRequestBus::Event(m_entityComponentId
, &PhysX::EditorJointRequests::SetVector3Value
, PhysX::EditorJointComponentMode::s_parameterPosition
, newTransform.GetTranslation());
PhysX::EditorJointRequestBus::Event(m_entityComponentId
, &PhysX::EditorJointRequests::SetVector3Value
, PhysX::EditorJointComponentMode::s_parameterRotation
, newTransform.GetRotation().GetEulerDegrees());
m_yLinearManipulator->SetLocalOrientation(manipulatorOrientation);
m_zLinearManipulator->SetLocalOrientation(manipulatorOrientation);
m_yLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisY()));
m_zLinearManipulator->SetAxis(action.m_current.m_delta.TransformVector(AZ::Vector3::CreateAxisZ()));
m_xRotationManipulator->SetLocalOrientation(manipulatorOrientation);
m_yLinearManipulator->SetBoundsDirty();
m_zLinearManipulator->SetBoundsDirty();
m_xRotationManipulator->SetBoundsDirty();
});
m_xRotationManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
m_yLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
m_zLinearManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
m_yzPlanarManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId());
Refresh();
}
EditorSubComponentModeAngleCone::~EditorSubComponentModeAngleCone()
{
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
m_xRotationManipulator->Unregister();
m_yLinearManipulator->Unregister();
m_zLinearManipulator->Unregister();
m_yzPlanarManipulator->Unregister();
}
void EditorSubComponentModeAngleCone::Refresh()
{
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
float coneHeight = ConeHeight;
AngleLimitsFloatPair yzSwingAngleLimits;
EditorJointRequestBus::EventResult(
yzSwingAngleLimits, m_entityComponentId
, &EditorJointRequests::GetLinearValuePair
, m_name);
// Draw inverted cone (negative cone height) if angles are larger than 90 deg.
if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f)
{
coneHeight = -ConeHeight;
}
// reposition manipulators
const AZ::Quaternion localRotation = localTransform.GetRotation();
const AZ::Vector3 linearManipulatorOffset = localTransform.GetTranslation() + localRotation.TransformVector(AZ::Vector3(coneHeight, 0.0f, 0.0f));
m_xRotationManipulator->SetLocalTransform(localTransform);
m_xRotationManipulator->SetBoundsDirty();
localTransform.SetTranslation(linearManipulatorOffset);
m_yLinearManipulator->SetLocalTransform(localTransform);
m_zLinearManipulator->SetLocalTransform(localTransform);
m_yzPlanarManipulator->SetLocalTransform(localTransform);
m_yLinearManipulator->SetBoundsDirty();
m_zLinearManipulator->SetBoundsDirty();
m_yzPlanarManipulator->SetBoundsDirty();
}
void EditorSubComponentModeAngleCone::ConfigureLinearView(
float axisLength, [[maybe_unused]] const AZ::Color& axis1Color, const AZ::Color& axis2Color,
const AZ::Color& axis3Color)
{
const float coneLength = 0.28f;
const float coneRadius = 0.07f;
const auto configureLinearView = [coneLength, axisLength, coneRadius](
AzToolsFramework::LinearManipulator* linearManipulator, const AZ::Color& color)
{
AzToolsFramework::ManipulatorViews views;
views.emplace_back(CreateManipulatorViewLine(
*linearManipulator, color, axisLength, AzToolsFramework::ManipulatorLineBoundWidth()));
views.emplace_back(CreateManipulatorViewCone(
*linearManipulator, color, linearManipulator->GetAxis() * (axisLength - coneLength),
coneLength, coneRadius));
linearManipulator->SetViews(AZStd::move(views));
};
configureLinearView(m_yLinearManipulator.get(), axis2Color);
configureLinearView(m_zLinearManipulator.get(), axis3Color);
}
void EditorSubComponentModeAngleCone::ConfigurePlanarView(const AZ::Color& planeColor,
const AZ::Color& plane2Color)
{
const float planeSize = 0.6f;
AzToolsFramework::ManipulatorViews views;
views.emplace_back(CreateManipulatorViewQuad(
*m_yzPlanarManipulator
, planeColor
, plane2Color
, planeSize));
m_yzPlanarManipulator->SetViews(AZStd::move(views));
}
void EditorSubComponentModeAngleCone::DisplayEntityViewport(
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay)
{
AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId());
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
AZ::u32 stateBefore = debugDisplay.GetState();
debugDisplay.CullOff();
debugDisplay.PushMatrix(worldTransform);
debugDisplay.PushMatrix(localTransform);
const float xAxisArrowLength = 2.0f;
debugDisplay.SetColor(AZ::Color(1.0f, 0.0f, 0.0f, 1.0f));
debugDisplay.DrawArrow(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(xAxisArrowLength, 0.0f, 0.0f));
AngleLimitsFloatPair yzSwingAngleLimits;
EditorJointRequestBus::EventResult(
yzSwingAngleLimits, m_entityComponentId
, &EditorJointRequests::GetLinearValuePair
, m_name);
const AZ::u32 numEllipseSamples = 16;
AZ::Vector3 ellipseSamples[numEllipseSamples];
float coneHeight = ConeHeight;
// Draw inverted cone if angles are larger than 90 deg.
if (yzSwingAngleLimits.first > 90.0f || yzSwingAngleLimits.second > 90.0f)
{
coneHeight = -ConeHeight;
}
// Compute points along perimeter of cone base
const float coney = tanf(AZ::DegToRad(yzSwingAngleLimits.first)) * coneHeight;
const float conez = tanf(AZ::DegToRad(yzSwingAngleLimits.second)) * coneHeight;
const float step = AZ::Constants::TwoPi / numEllipseSamples;
for (size_t i = 0; i < numEllipseSamples; ++i)
{
const float angleStep = step * i;
ellipseSamples[i].SetX(coneHeight);
ellipseSamples[i].SetY(conez * sin(angleStep));
ellipseSamples[i].SetZ(coney * cos(angleStep));
}
// draw cone
for (size_t i = 0; i < numEllipseSamples; ++i)
{
size_t nextIndex = i + 1;
if (i == numEllipseSamples - 1)
{
nextIndex = 0;
}
// draw cone sides
debugDisplay.SetColor(AZ::Color(1.0f, 1.0f, 1.0f, 0.2f));
debugDisplay.DrawTri(AZ::Vector3(0.0f, 0.0f, 0.0f), ellipseSamples[i], ellipseSamples[nextIndex]);
// draw parameter of cone base
debugDisplay.SetColor(AZ::Color(0.4f, 0.4f, 0.4f, 0.4f));
debugDisplay.DrawLine(ellipseSamples[i], ellipseSamples[nextIndex]);
}
// draw axis lines at base of cone, and from tip to base.
debugDisplay.SetColor(AZ::Color(0.5f, 0.5f, 0.5f, 0.6f));
debugDisplay.DrawLine(ellipseSamples[0], ellipseSamples[numEllipseSamples/2]);
debugDisplay.DrawLine(ellipseSamples[numEllipseSamples*3/4], ellipseSamples[numEllipseSamples/4]);
debugDisplay.DrawLine(AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3(coneHeight, 0.0f, 0.0f));
debugDisplay.PopMatrix();//pop local transform
debugDisplay.PopMatrix();//pop world transform
debugDisplay.SetState(stateBefore);
// reposition and reorientate manipulators
Refresh();
}
} // namespace PhysX
@@ -1,63 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Editor/EditorSubComponentModeBase.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/Viewport/ViewportTypes.h>
namespace AzToolsFramework
{
class AngularManipulator;
class LinearManipulator;
class PlanarManipulator;
}
namespace PhysX
{
class EditorSubComponentModeAngleCone
: public PhysX::EditorSubComponentModeBase
, private AzFramework::EntityDebugDisplayEventBus::Handler
{
public:
EditorSubComponentModeAngleCone(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name
, float max
, float min);
~EditorSubComponentModeAngleCone();
// PhysX::EditorSubComponentModeBase
void Refresh() override;
private:
// AzFramework::EntityDebugDisplayEventBus
void DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
void ConfigureLinearView(
float axisLength,
const AZ::Color& axis1Color, const AZ::Color& axis2Color,
const AZ::Color& axis3Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f));
void ConfigurePlanarView(const AZ::Color& planeColor = AZ::Color(0.0f, 1.0f, 0.0f, 0.5f)
, const AZ::Color& plane2Color = AZ::Color(0.0f, 0.0f, 1.0f, 0.5f));
AZStd::shared_ptr<AzToolsFramework::AngularManipulator> m_xRotationManipulator;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> m_yLinearManipulator;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> m_zLinearManipulator;
AZStd::shared_ptr<AzToolsFramework::PlanarManipulator> m_yzPlanarManipulator;
float m_max = FLT_MAX;
float m_min = 0.0f;
};
} // namespace PhysX
@@ -1,318 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Component/TransformBus.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <Editor/EditorJointComponentMode.h>
#include <Editor/EditorSubComponentModeAnglePair.h>
#include <Source/Utils.h>
namespace
{
const float Alpha = 0.6f;
const AZ::Color ColorDefault = AZ::Color(1.0f, 1.0f, 1.0f, Alpha);
const AZ::Color ColorFirst = AZ::Color(1.0f, 0.0f, 0.0f, Alpha);
const AZ::Color ColorSecond = AZ::Color(0.0f, 1.0f, 0.0f, Alpha);
const AZ::Color ColorSweepArc = AZ::Color(1.0f, 1.0f, 1.0f, Alpha);
const float SweepLineDisplaceFactor = 0.5f;
const float SweepLineThickness = 1.0f;
const float SweepLineGranularity = 1.0f;
}
namespace PhysX
{
EditorSubComponentModeAnglePair::EditorSubComponentModeAnglePair(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name
, const AZ::Vector3& axis
, float firstMax
, float firstMin
, float secondMax
, float secondMin)
: EditorSubComponentModeBase(entityComponentIdPair, componentType, name)
, m_axis(axis)
, m_firstMax(firstMax)
, m_firstMin(firstMin)
, m_secondMax(secondMax)
, m_secondMin(secondMin)
{
AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId());
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
const AZ::Quaternion localRotation = localTransform.GetRotation();
AZ::Vector3 displacement = m_axis;
AZ::Transform displacementTransform = localTransform;
AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement);
displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate);
m_firstManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform);
m_firstManipulator->AddEntityComponentIdPair(m_entityComponentId);
m_firstManipulator->SetAxis(m_axis);
m_firstManipulator->SetLocalTransform(displacementTransform);
displacement = -m_axis;
displacementTranslate = localRotation.TransformVector(displacement);
displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate);
m_secondManipulator = AzToolsFramework::AngularManipulator::MakeShared(worldTransform);
m_secondManipulator->AddEntityComponentIdPair(m_entityComponentId);
m_secondManipulator->SetAxis(m_axis);
m_secondManipulator->SetLocalTransform(displacementTransform);
const float manipulatorRadius = 2.0f;
const float manipulatorWidth = 0.05f;
m_firstManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle(
*m_firstManipulator, ColorFirst,
manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle));
m_secondManipulator->SetView(AzToolsFramework::CreateManipulatorViewCircle(
*m_secondManipulator, ColorSecond,
manipulatorRadius, manipulatorWidth, AzToolsFramework::DrawHalfDottedCircle));
Refresh();
AZStd::shared_ptr<SharedRotationState> sharedRotationState =
AZStd::make_shared<SharedRotationState>();
auto mouseDownCallback = [this, sharedRotationState](const AzToolsFramework::AngularManipulator::Action& action) mutable -> void
{
const AZ::Quaternion normalizedStart = action.m_start.m_rotation.GetNormalized();
sharedRotationState->m_axis = AZ::Vector3(normalizedStart.GetX(), normalizedStart.GetY(), normalizedStart.GetZ());
sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity();
AngleLimitsFloatPair currentValue;
EditorJointRequestBus::EventResult(
currentValue, m_entityComponentId
, &EditorJointRequests::GetLinearValuePair
, m_name);
sharedRotationState->m_valuePair = currentValue;
};
m_firstManipulator->InstallLeftMouseDownCallback(mouseDownCallback);
m_secondManipulator->InstallLeftMouseDownCallback(mouseDownCallback);
m_firstManipulator->InstallMouseMoveCallback(
[this, sharedRotationState]
(const AzToolsFramework::AngularManipulator::Action& action) mutable -> void
{
float angleDelta;
AZ::Quaternion manipulatorOrientation;
const float newValue = MouseMove(sharedRotationState, action, true, angleDelta, manipulatorOrientation);
if (newValue > m_firstMax || newValue < m_firstMin)
{
return;
}
m_firstManipulator->SetLocalOrientation(manipulatorOrientation);
const float newFirstValue = AZ::GetClamp(sharedRotationState->m_valuePair.first + angleDelta, m_firstMin, m_firstMax);
EditorJointRequestBus::Event(
m_entityComponentId
, &EditorJointRequests::SetLinearValuePair
, m_name
, AngleLimitsFloatPair(newFirstValue, sharedRotationState->m_valuePair.second));
m_firstManipulator->SetBoundsDirty();
});
m_secondManipulator->InstallMouseMoveCallback(
[this, sharedRotationState]
(const AzToolsFramework::AngularManipulator::Action& action) mutable -> void
{
float angleDelta;
AZ::Quaternion manipulatorOrientation;
const float newValue = MouseMove(sharedRotationState, action, false, angleDelta, manipulatorOrientation);
if (newValue > m_secondMax || newValue < m_secondMin)
{
return; //Not handling values exceeding limits
}
m_secondManipulator->SetLocalOrientation(manipulatorOrientation);
float newSecondValue = AZ::GetClamp(sharedRotationState->m_valuePair.second + angleDelta, m_secondMin, m_secondMax);
EditorJointRequestBus::Event(
m_entityComponentId
, &EditorJointRequests::SetLinearValuePair
, m_name
, AngleLimitsFloatPair(sharedRotationState->m_valuePair.first, newSecondValue));
m_secondManipulator->SetBoundsDirty();
});
m_firstManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
m_secondManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId());
}
EditorSubComponentModeAnglePair::~EditorSubComponentModeAnglePair()
{
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
m_firstManipulator->Unregister();
m_secondManipulator->Unregister();
}
void EditorSubComponentModeAnglePair::Refresh()
{
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
const AZ::Quaternion localRotation = localTransform.GetRotation();
AZ::Transform displacementTransform = localTransform;
AZ::Vector3 displacement = m_axis;
AZ::Vector3 displacementTranslate = localRotation.TransformVector(displacement);
displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate);
m_firstManipulator->SetLocalTransform(displacementTransform);
displacement = -m_axis;
displacementTranslate = localRotation.TransformVector(displacement);
displacementTransform.SetTranslation(localTransform.GetTranslation() + displacementTranslate);
m_secondManipulator->SetLocalTransform(displacementTransform);
m_firstManipulator->SetBoundsDirty();
m_secondManipulator->SetBoundsDirty();
}
void EditorSubComponentModeAnglePair::DisplayEntityViewport(
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay)
{
AngleLimitsFloatPair currentValue;
EditorJointRequestBus::EventResult(
currentValue, m_entityComponentId
, &EditorJointRequests::GetLinearValuePair
, m_name);
const float size = 2.0f;
AZ::Vector3 axisPoint = m_axis * size * 0.5f;
AZStd::array<AZ::Vector3, 4> points = {
-axisPoint
, axisPoint
, axisPoint
, -axisPoint
};
if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON)
{
points[2].SetZ(size);
points[3].SetZ(size);
}
else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON)
{
points[2].SetX(size);
points[3].SetX(size);
}
else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON)
{
points[2].SetX(size);
points[3].SetX(size);
}
AZ::u32 stateBefore = debugDisplay.GetState();
debugDisplay.CullOff();
debugDisplay.SetAlpha(Alpha);
AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId());
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
debugDisplay.PushMatrix(worldTransform);
debugDisplay.PushMatrix(localTransform);
debugDisplay.SetColor(ColorSweepArc);
const AZ::Vector3 zeroVector = AZ::Vector3::CreateZero();
const AZ::Vector3 posPosition = m_axis * SweepLineDisplaceFactor;
const AZ::Vector3 negPosition = -posPosition;
debugDisplay.DrawArc(posPosition, SweepLineThickness, -currentValue.first, currentValue.first, SweepLineGranularity, -m_axis);
debugDisplay.DrawArc(zeroVector, SweepLineThickness, -currentValue.first, currentValue.first, SweepLineGranularity, -m_axis);
debugDisplay.DrawArc(negPosition, SweepLineThickness, -currentValue.first, currentValue.first, SweepLineGranularity, -m_axis);
debugDisplay.DrawArc(posPosition, SweepLineThickness, 0.0f, abs(currentValue.second), SweepLineGranularity, -m_axis);
debugDisplay.DrawArc(zeroVector, SweepLineThickness, 0.0f, abs(currentValue.second), SweepLineGranularity, -m_axis);
debugDisplay.DrawArc(negPosition, SweepLineThickness, 0.0f, abs(currentValue.second), SweepLineGranularity, -m_axis);
AZ::Quaternion firstRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.first));
AZ::Transform firstTM = AZ::Transform::CreateFromQuaternion(firstRotate);
debugDisplay.PushMatrix(firstTM);
debugDisplay.SetColor(ColorFirst);
debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]);
debugDisplay.PopMatrix();
AZ::Quaternion secondRotate = AZ::Quaternion::CreateFromAxisAngle(m_axis, AZ::DegToRad(currentValue.second));
AZ::Transform secondTM = AZ::Transform::CreateFromQuaternion(secondRotate);
debugDisplay.PushMatrix(secondTM);
debugDisplay.SetColor(ColorSecond);
debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]);
debugDisplay.PopMatrix();
debugDisplay.SetColor(ColorDefault);
debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]);
debugDisplay.PopMatrix(); // pop local transform
debugDisplay.PopMatrix(); // pop global transform
debugDisplay.SetState(stateBefore);
// reposition and reorientate manipulators
Refresh();
}
float EditorSubComponentModeAnglePair::MouseMove(AZStd::shared_ptr<SharedRotationState>& sharedRotationState
, const AzToolsFramework::AngularManipulator::Action& action
, bool isFirstValue
, float& angleDelta
, AZ::Quaternion& manipulatorOrientation)
{
sharedRotationState->m_savedOrientation = action.m_current.m_delta.GetInverseFull();
angleDelta = 0.0f;
AZ::Vector3 axis = m_axis;
sharedRotationState->m_savedOrientation.ConvertToAxisAngle(axis, angleDelta);
// Polarity of axis is switched by ConvertToAxisAngle call depending on direction of rotation
if (abs(m_axis.GetX() - 1.0f) < FLT_EPSILON)
{
angleDelta = AZ::RadToDeg(angleDelta) * axis.GetX();
}
else if (abs(m_axis.GetY() - 1.0f) < FLT_EPSILON)
{
angleDelta = AZ::RadToDeg(angleDelta) * axis.GetY();
}
else if (abs(m_axis.GetZ() - 1.0f) < FLT_EPSILON)
{
angleDelta = AZ::RadToDeg(angleDelta) * axis.GetZ();
}
manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta;
if (isFirstValue)
{
return sharedRotationState->m_valuePair.first + angleDelta;
}
else
{
return sharedRotationState->m_valuePair.second + angleDelta;
}
}
} // namespace PhysX
@@ -1,66 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Editor/EditorSubComponentModeBase.h>
#include <PhysX/EditorJointBus.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/Manipulators/AngularManipulator.h>
namespace PhysX
{
class EditorSubComponentModeAnglePair
: public PhysX::EditorSubComponentModeBase
, private AzFramework::EntityDebugDisplayEventBus::Handler
{
public:
EditorSubComponentModeAnglePair(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name
, const AZ::Vector3& axis
, float firstMax
, float firstMin
, float secondMax
, float secondMin);
~EditorSubComponentModeAnglePair();
// PhysX::EditorSubComponentModeBase
void Refresh() override;
private:
struct SharedRotationState
{
AZ::Vector3 m_axis;
AZ::Quaternion m_savedOrientation = AZ::Quaternion::CreateIdentity();
AngleLimitsFloatPair m_valuePair;
};
// AzFramework::EntityDebugDisplayEventBus
void DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
float MouseMove(AZStd::shared_ptr<SharedRotationState>& sharedRotationState
, const AzToolsFramework::AngularManipulator::Action& action
, bool isFirstValue
, float& angleDelta
, AZ::Quaternion& manipulatorOrientation);
AZStd::shared_ptr<AzToolsFramework::AngularManipulator> m_firstManipulator;
AZStd::shared_ptr<AzToolsFramework::AngularManipulator> m_secondManipulator;
AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX();
float m_firstMax = FLT_MAX;
float m_firstMin = -FLT_MAX;
float m_secondMax = FLT_MAX;
float m_secondMin = -FLT_MAX;
};
} // namespace PhysX
@@ -1,37 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <Editor/EditorJointTypeDrawer.h>
#include <Editor/EditorSubComponentModeBase.h>
#include <AzCore/std/smart_ptr/make_shared.h>
namespace PhysX
{
EditorSubComponentModeBase::EditorSubComponentModeBase(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name)
: m_entityComponentId(entityComponentIdPair),
m_name(name)
{
// The first time this is called, no object will respond to this bus call as no object is connected at the address,
// and m_jointTypeDrawer will remain as a nullptr.
EditorJointTypeDrawerBus::EventResult(m_jointTypeDrawer,
EditorJointTypeDrawerId(componentType, EditorSubComponentModeNameCrc(name)),
&EditorJointTypeDrawerBus::Events::GetEditorJointTypeDrawer);
if (!m_jointTypeDrawer)
{
// Once this is called, the bus call to GetEditorJointTypeDrawer above will no longer get a null response, until m_jointTypeDrawer is destroyed.
m_jointTypeDrawer = AZStd::make_shared<EditorJointTypeDrawer>(componentType,
AzToolsFramework::GetEntityContextId(),
m_name);
}
}
} // namespace PhysX
@@ -1,55 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/ComponentBus.h>
namespace AzFramework
{
class DebugDisplayRequests;
struct ViewportInfo;
}
namespace AzToolsFramework
{
namespace ViewportInteraction
{
struct MouseInteractionEvent;
}
}
namespace PhysX
{
class EditorJointTypeDrawer;
/// Base class for (joints) sub-component modes.
class EditorSubComponentModeBase
{
public:
EditorSubComponentModeBase(
const AZ::EntityComponentIdPair& entityComponentIdPair,
const AZ::Uuid& componentType,
const AZStd::string& name);
virtual ~EditorSubComponentModeBase() = default;
/// Additional mouse handling by sub-component mode. Does not absorb mouse event.
virtual void HandleMouseInteraction(
[[maybe_unused]] const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction) {};
virtual void Refresh() = 0;
AZStd::string m_name;///< Name of sub-component mode.
protected:
AZ::EntityComponentIdPair m_entityComponentId;///< Entity Id and component pair.
private:
AZStd::shared_ptr<EditorJointTypeDrawer> m_jointTypeDrawer;///< Drawer that draws component type specific objects in the viewport.
};
} // namespace PhysX
@@ -1,133 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Component/TransformBus.h>
#include <AzCore/std/smart_ptr/intrusive_ptr.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <Editor/EditorJointComponentMode.h>
#include <Editor/EditorSubComponentModeLinear.h>
#include <PhysX/EditorJointBus.h>
#include <Source/Utils.h>
namespace PhysX
{
EditorSubComponentModeLinear::EditorSubComponentModeLinear(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name
, float exponent
, float max
, float min)
: EditorSubComponentModeBase(entityComponentIdPair, componentType, name)
, m_exponent(exponent)
, m_inverseExponent(1.0f/exponent)
, m_max(max)
, m_min(min)
{
AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId());
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
m_manipulator = AzToolsFramework::LinearManipulator::MakeShared(worldTransform);
m_manipulator->AddEntityComponentIdPair(m_entityComponentId);
m_manipulator->SetAxis(AZ::Vector3::CreateAxisX());
m_manipulator->SetLocalTransform(localTransform);
Refresh();
const AZ::Color manipulatorColor(0.3f, 0.3f, 0.3f, 1.0f);
const float manipulatorSize = 0.05f;
AzToolsFramework::ManipulatorViews views;
views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(manipulatorColor
, manipulatorSize));
m_manipulator->SetViews(AZStd::move(views));
struct SharedState
{
float m_startingValue = 0.0f;
};
auto sharedState = AZStd::make_shared<SharedState>();
m_manipulator->InstallLeftMouseDownCallback(
[this, sharedState](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable
{
float currentValue = 0.0f;
EditorJointRequestBus::EventResult(
currentValue, m_entityComponentId
, &EditorJointRequests::GetLinearValue
, m_name);
sharedState->m_startingValue = currentValue;
});
m_manipulator->InstallMouseMoveCallback(
[this, sharedState](const AzToolsFramework::LinearManipulator::Action& action)
{
const float axisDisplacement = action.LocalPositionOffset().Dot(action.m_fixed.m_axis);
float newValue = AZ::GetClamp(sharedState->m_startingValue + DisplacementToDeltaValue(axisDisplacement), m_min, m_max);
EditorJointRequestBus::Event(
m_entityComponentId
, &EditorJointRequests::SetLinearValue
, m_name
, newValue);
const AZ::Vector3 localPosition = action.LocalPosition().GetMax(AZ::Vector3(0.01f, 0.0f, 0.0f));
m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(localPosition));
m_manipulator->SetBoundsDirty();
});
m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
}
EditorSubComponentModeLinear::~EditorSubComponentModeLinear()
{
m_manipulator->Unregister();
}
void EditorSubComponentModeLinear::Refresh()
{
float currentValue = 0.0f;
EditorJointRequestBus::EventResult(
currentValue, m_entityComponentId
, &EditorJointRequests::GetLinearValue
, m_name);
m_manipulator->SetLocalTransform(AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisX() * ValueToDisplacement(currentValue)));
}
float EditorSubComponentModeLinear::DisplacementToDeltaValue(float displacement) const
{
if (displacement > 0.0f)
{
return powf(displacement, m_exponent);
}
else if (displacement < 0.0f)
{
return -powf(fabsf(displacement), m_exponent);
}
else
{
return 0.0f;
}
}
float EditorSubComponentModeLinear::ValueToDisplacement(float value) const
{
return powf(value, m_inverseExponent);
}
} // namespace PhysX
@@ -1,46 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Editor/EditorSubComponentModeBase.h>
namespace AzToolsFramework
{
class LinearManipulator;
}
namespace PhysX
{
class EditorSubComponentModeLinear
: public PhysX::EditorSubComponentModeBase
{
public:
EditorSubComponentModeLinear(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name
, float exponent
, float max
, float min);
~EditorSubComponentModeLinear();
// PhysX::EditorSubComponentModeBase
void Refresh() override;
private:
float DisplacementToDeltaValue(float displacement) const;
float ValueToDisplacement(float value) const;
float m_exponent = 1.0f;
float m_inverseExponent = 1.0f;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> m_manipulator;
float m_max = FLT_MAX;
float m_min = -FLT_MAX;
};
} // namespace PhysX
@@ -1,151 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Component/TransformBus.h>
#include <AzToolsFramework/Manipulators/AngularManipulator.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <Editor/EditorJointComponentMode.h>
#include <PhysX/EditorJointBus.h>
#include <Editor/EditorSubComponentModeRotation.h>
#include <Source/Utils.h>
namespace PhysX
{
EditorSubComponentModeRotation::EditorSubComponentModeRotation(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name)
: EditorSubComponentModeBase(entityComponentIdPair, componentType, name)
{
CreateManipulators();
RegisterManipulators();
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId());
}
EditorSubComponentModeRotation::~EditorSubComponentModeRotation()
{
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
UnregisterManipulators();
}
void EditorSubComponentModeRotation::Refresh()
{
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
for (auto rotationManipulator : m_rotationManipulators)
{
rotationManipulator->SetLocalTransform(localTransform);
rotationManipulator->SetBoundsDirty();
}
}
void EditorSubComponentModeRotation::DisplayEntityViewport(
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
[[maybe_unused]] AzFramework::DebugDisplayRequests& debugDisplay)
{
Refresh(); //Update position and orientation of manipulators.
}
void EditorSubComponentModeRotation::CreateManipulators()
{
AZ::Transform worldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(m_entityComponentId.GetEntityId());
const AZ::Quaternion worldRotation = worldTransform.GetRotation();
AZ::Transform localTransform = AZ::Transform::CreateIdentity();
EditorJointRequestBus::EventResult(
localTransform, m_entityComponentId
, &EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
const AZStd::array<AZ::Vector3, 3> axes = { AZ::Vector3::CreateAxisX()
, AZ::Vector3::CreateAxisY()
, AZ::Vector3::CreateAxisZ()};
const AZStd::array <AZ::Color, 3> colors = { AZ::Color(1.0f, 0.0f, 0.0f, 1.0f)
, AZ::Color(0.0f, 1.0f, 0.0f, 1.0f)
, AZ::Color(0.0f, 0.0f, 1.0f, 1.0f)};
for (AZ::u32 i = 0; i < 3; ++i)
{
m_rotationManipulators[i] = AzToolsFramework::AngularManipulator::MakeShared(worldTransform);
m_rotationManipulators[i]->AddEntityComponentIdPair(m_entityComponentId);
m_rotationManipulators[i]->SetAxis(axes[i]);
m_rotationManipulators[i]->SetLocalTransform(localTransform);
const float manipulatorRadius = 2.0f;
m_rotationManipulators[i]->SetView(AzToolsFramework::CreateManipulatorViewCircle(
*m_rotationManipulators[i], colors[i], manipulatorRadius,
AzToolsFramework::ManipulatorCicleBoundWidth(), AzToolsFramework::DrawHalfDottedCircle));
}
Refresh();
InstallManipulatorMouseCallbacks();
}
void EditorSubComponentModeRotation::InstallManipulatorMouseCallbacks()
{
struct SharedState
{
AZ::Transform m_startTM;
};
auto sharedState = AZStd::make_shared<SharedState>();
auto mouseDownRotateXCallback = [this, sharedState]([[maybe_unused]] const AzToolsFramework::AngularManipulator::Action& action) mutable -> void
{
PhysX::EditorJointRequestBus::EventResult(sharedState->m_startTM
, m_entityComponentId
, &PhysX::EditorJointRequests::GetTransformValue
, PhysX::EditorJointComponentMode::s_parameterTransform);
};
for (AZ::u32 index = 0; index < 3; ++index)
{
m_rotationManipulators[index]->InstallLeftMouseDownCallback(mouseDownRotateXCallback);
m_rotationManipulators[index]->InstallMouseMoveCallback(
[this, index, sharedState]
(const AzToolsFramework::AngularManipulator::Action& action) mutable -> void
{
const AZ::Quaternion manipulatorOrientation = action.m_start.m_rotation * action.m_current.m_delta;
AZ::Transform newTransform = AZ::Transform::CreateIdentity();
newTransform = sharedState->m_startTM * AZ::Transform::CreateFromQuaternion(action.m_current.m_delta);
PhysX::EditorJointRequestBus::Event(m_entityComponentId
, &PhysX::EditorJointRequests::SetVector3Value
, PhysX::EditorJointComponentMode::s_parameterRotation
, newTransform.GetRotation().GetEulerDegrees());
m_rotationManipulators[index]->SetLocalOrientation(manipulatorOrientation);
m_rotationManipulators[index]->SetBoundsDirty();
});
}
}
void EditorSubComponentModeRotation::RegisterManipulators()
{
for (auto rotationManipulator : m_rotationManipulators)
{
rotationManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
}
}
void EditorSubComponentModeRotation::UnregisterManipulators()
{
for (auto rotationManipulator : m_rotationManipulators)
{
rotationManipulator->Unregister();
}
}
}
@@ -1,48 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Editor/EditorSubComponentModeBase.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
namespace AzToolsFramework
{
class AngularManipulator;
}
namespace PhysX
{
class EditorSubComponentModeRotation
: public PhysX::EditorSubComponentModeBase
, private AzFramework::EntityDebugDisplayEventBus::Handler
{
public:
EditorSubComponentModeRotation(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name);
~EditorSubComponentModeRotation();
// PhysX::EditorSubComponentModeBase
void Refresh() override;
private:
// AzFramework::EntityDebugDisplayEventBus
void DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
void CreateManipulators();
void InstallManipulatorMouseCallbacks();
void RegisterManipulators();
void UnregisterManipulators();
AZStd::array<AZStd::shared_ptr<AzToolsFramework::AngularManipulator>, 3> m_rotationManipulators;
};
} // namespace PhysX
@@ -1,97 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Math/Color.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <Editor/EditorJointComponentMode.h>
#include <Editor/EditorSubComponentModeSnapPosition.h>
#include <PhysX/EditorJointBus.h>
#include <Source/Utils.h>
namespace PhysX
{
EditorSubComponentModeSnapPosition::EditorSubComponentModeSnapPosition(
const AZ::EntityComponentIdPair& entityComponentIdPair
, const AZ::Uuid& componentType
, const AZStd::string& name
, bool selectLeadOnSnap)
: EditorSubComponentModeSnap(entityComponentIdPair, componentType, name)
, m_selectLeadOnSnap(selectLeadOnSnap)
{
InitMouseDownCallBack();
m_manipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(m_entityComponentId.GetEntityId());
}
EditorSubComponentModeSnapPosition::~EditorSubComponentModeSnapPosition()
{
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
m_manipulator->Unregister();
}
void EditorSubComponentModeSnapPosition::DisplaySpecificSnapType(
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay,
const AZ::Vector3& jointPosition,
const AZ::Vector3& snapDirection,
const float snapLength)
{
const float arrowLength = 1.0f;
const float iconGap = 1.0f;
const AZ::Vector3 iconPosition = jointPosition +
(snapDirection * (snapLength + arrowLength + iconGap));
debugDisplay.SetColor(AZ::Colors::Red);
debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(arrowLength, 0.0f, 0.0f));
debugDisplay.SetColor(AZ::Colors::Green);
debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.2f, arrowLength, 0.2f));
debugDisplay.SetColor(AZ::Colors::Blue);
debugDisplay.DrawArrow(iconPosition, iconPosition + AZ::Vector3(0.0f, 0.0f, arrowLength));
}
void EditorSubComponentModeSnapPosition::InitMouseDownCallBack()
{
m_manipulator->InstallLeftMouseDownCallback(
[this](const AzToolsFramework::LinearManipulator::Action& /*action*/) mutable
{
if (!m_pickedEntity.IsValid())
{
return;
}
const AZ::Vector3 newLocalPosition = PhysX::Utils::ComputeJointLocalTransform(
PhysX::Utils::GetEntityWorldTransformWithScale(m_pickedEntity),
PhysX::Utils::GetEntityWorldTransformWithScale(m_entityComponentId.GetEntityId())).GetTranslation();
PhysX::EditorJointRequestBus::Event(m_entityComponentId
, &PhysX::EditorJointRequests::SetVector3Value
, PhysX::EditorJointComponentMode::s_parameterPosition
, newLocalPosition);
const bool selectedEntityIsNotJointEntity = m_pickedEntity != m_entityComponentId.GetEntityId();
AZ_Error("EditorSubComponentModeSnapPosition",
selectedEntityIsNotJointEntity,
"Joint's lead entity cannot be the same as the entity in which the joint resides. Select lead entity on snap failed.");
if (m_selectLeadOnSnap &&
selectedEntityIsNotJointEntity)
{
PhysX::EditorJointRequestBus::Event(m_entityComponentId
, &PhysX::EditorJointRequests::SetEntityIdValue
, PhysX::EditorJointComponentMode::s_parameterLeadEntity
, m_pickedEntity);
}
m_manipulator->SetBoundsDirty();
});
}
} // namespace PhysX

Some files were not shown because too many files have changed in this diff Show More