Merge branch 'development' of https://github.com/o3de/o3de into daimini/FocusMode/breadcrumbs
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||