Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,59 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "WhiteBox_precompiled.h"
#include "EditorWhiteBoxComponentModeCommon.h"
#include <AzCore/Component/ComponentBus.h>
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
#include <WhiteBox/EditorWhiteBoxComponentBus.h>
#include <WhiteBox/WhiteBoxToolApi.h>
namespace WhiteBox
{
using ComponentModeRequestBus = AzToolsFramework::ComponentModeFramework::ComponentModeRequestBus;
void RecordWhiteBoxAction(
WhiteBoxMesh& whiteBox, const AZ::EntityComponentIdPair entityComponentIdPair, const char* undoRedoDesc)
{
// update UVs
Api::CalculatePlanarUVs(whiteBox);
// record an undo step
AzToolsFramework::ScopedUndoBatch undoBatch(undoRedoDesc);
AzToolsFramework::ScopedUndoBatch::MarkEntityDirty(entityComponentIdPair.GetEntityId());
// notify the component things have changed
EditorWhiteBoxComponentRequestBus::Event(
entityComponentIdPair, &EditorWhiteBoxComponentRequests::SerializeWhiteBox);
// notify the white box mesh things have changed
EditorWhiteBoxComponentNotificationBus::Event(
entityComponentIdPair, &EditorWhiteBoxComponentNotifications::OnWhiteBoxMeshModified);
// notify the component mode things have changed
ComponentModeRequestBus::Event(entityComponentIdPair, &ComponentModeRequestBus::Events::Refresh);
}
bool InputFlipEdge(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction)
{
return mouseInteraction.m_mouseInteraction.m_mouseButtons.Right() &&
mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Down;
}
bool InputRestore(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction)
{
return mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Down;
}
} // namespace WhiteBox
@@ -0,0 +1,31 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/ComponentBus.h>
#include <AzToolsFramework/Viewport/ViewportTypes.h>
namespace WhiteBox
{
struct WhiteBoxMesh;
//! Record an undo/redo step and notify the white box mesh
void RecordWhiteBoxAction(
WhiteBoxMesh& whiteBox, const AZ::EntityComponentIdPair entityComponentIdPair, const char* undoRedoDesc);
//! Returns true if user input is for flipping an edge
bool InputFlipEdge(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction);
//! Returns true if user input is for restoring a vertex/edge
bool InputRestore(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction);
} // namespace WhiteBox
@@ -0,0 +1,682 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "WhiteBox_precompiled.h"
#include "EditorWhiteBoxComponentModeCommon.h"
#include "EditorWhiteBoxDefaultMode.h"
#include "Viewport/WhiteBoxEdgeScaleModifier.h"
#include "Viewport/WhiteBoxEdgeTranslationModifier.h"
#include "Viewport/WhiteBoxPolygonScaleModifier.h"
#include "Viewport/WhiteBoxPolygonTranslationModifier.h"
#include "Viewport/WhiteBoxVertexTranslationModifier.h"
#include "Viewport/WhiteBoxViewportConstants.h"
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <QKeySequence>
#include <QLayout>
#include <WhiteBox/EditorWhiteBoxComponentBus.h>
namespace WhiteBox
{
AZ_CVAR(
float, cl_whiteBoxVertexIndicatorLength, 0.1f, nullptr, AZ::ConsoleFunctorFlags::Null,
"The length of each vertex indicator axis");
AZ_CVAR(
float, cl_whiteBoxVertexIndicatorWidth, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null,
"The width/thickness of each vertex indicator axis");
AZ_CVAR(
AZ::Color, cl_whiteBoxVertexIndicatorColor, AZ::Color::CreateFromRgba(0, 0, 0, 102), nullptr,
AZ::ConsoleFunctorFlags::Null, "The color of the vertex indicator");
static const AZ::Crc32 HideEdge = AZ_CRC("com.amazon.action.whitebox.hide_edge", 0x6a60ae23);
static const AZ::Crc32 HideVertex = AZ_CRC("com.amazon.action.whitebox.hide_vertex", 0x4a4bd092);
static const char* const HideEdgeTitle = "Hide Edge";
static const char* const HideEdgeDesc = "Hide the selected edge to merge the two connected polygons";
static const char* const HideVertexTitle = "Hide Vertex";
static const char* const HideVertexDesc = "Hide the selected vertex to merge the two connected edges";
static const char* const HideEdgeUndoRedoDesc = "Hide an edge to merge two connected polygons together";
static const char* const HideVertexUndoRedoDesc = "Hide a vertex to merge two connected edges together";
const QKeySequence HideKey = QKeySequence{Qt::Key_H};
// handle translation and scale modifiers for either polygon or edge - if a translation
// modifier is set (either polygon or edge), update the intersection point so the next time
// mouse down happens the delta offsets of the manipulator are calculated from the correct
// position and also handle clicking off of a selected modifier to clear the selected state
// note: the Intersection type must match the geometry for the translation and scale modifier
template<typename TranslationModifier, typename Intersection, typename DestroyOtherModifierFn>
static void HandleMouseInteractionForModifier(
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
DefaultMode::SelectedTranslationModifier& selectedTranslationModifier,
DestroyOtherModifierFn&& destroyOtherModifierFn, const AZStd::optional<Intersection>& geometryIntersection)
{
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<TranslationModifier>>(&selectedTranslationModifier))
{
// handle clicking off of selected geometry
if (mouseInteraction.m_mouseInteraction.m_mouseButtons.Left() &&
mouseInteraction.m_mouseEvent == AzToolsFramework::ViewportInteraction::MouseEvent::Up &&
!geometryIntersection.has_value())
{
selectedTranslationModifier = AZStd::monostate{};
destroyOtherModifierFn();
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::RefreshActions);
}
}
}
// in this generic context TranslationModifier and OtherTranslationModifier correspond
// to Polygon/Edge or Edge/Polygon depending on the context (which was intersected)
template<typename Intersection, typename TranslationModifier, typename DestroyOtherModifierFn>
static void HandleCreatingDestroyingModifiersOnIntersectionChange(
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
DefaultMode::SelectedTranslationModifier& selectedTranslationModifier,
AZStd::unique_ptr<TranslationModifier>& translationModifier, DestroyOtherModifierFn&& destroyOtherModifierFn,
const AZStd::optional<Intersection>& geometryIntersection,
const AZ::EntityComponentIdPair& entityComponentIdPair)
{
// if we have a valid mouse ray intersection with the geometry (e.g. edge or polygon)
if (geometryIntersection.has_value())
{
// does the geometry the mouse is hovering over match the currently selected geometry
const bool matchesSelected = [&geometryIntersection, &selectedTranslationModifier]()
{
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<TranslationModifier>>(&selectedTranslationModifier))
{
return (*modifier)->GetHandle() == geometryIntersection->GetHandle();
}
return false;
}();
// check if there's currently no modifier or if we need to make a different modifier as
// the geometry is different
const bool shouldCreateTranslationModifier =
!translationModifier || (translationModifier->GetHandle() != geometryIntersection->GetHandle());
if (shouldCreateTranslationModifier && !matchesSelected)
{
// created a modifier for the intersected geometry
translationModifier = AZStd::make_unique<TranslationModifier>(
entityComponentIdPair, geometryIntersection->GetHandle(),
geometryIntersection->m_intersection.m_localIntersectionPoint);
translationModifier->ForwardMouseOverEvent(mouseInteraction.m_mouseInteraction);
destroyOtherModifierFn();
}
}
}
AZ_CLASS_ALLOCATOR_IMPL(DefaultMode, AZ::SystemAllocator, 0)
DefaultMode::DefaultMode(const AZ::EntityComponentIdPair& entityComponentIdPair)
: m_entityComponentIdPair(entityComponentIdPair)
{
EditorWhiteBoxDefaultModeRequestBus::Handler::BusConnect(entityComponentIdPair);
EditorWhiteBoxPolygonModifierNotificationBus::Handler::BusConnect(entityComponentIdPair);
EditorWhiteBoxEdgeModifierNotificationBus::Handler::BusConnect(entityComponentIdPair);
}
DefaultMode::~DefaultMode()
{
EditorWhiteBoxEdgeModifierNotificationBus::Handler::BusDisconnect();
EditorWhiteBoxPolygonModifierNotificationBus::Handler::BusDisconnect();
EditorWhiteBoxDefaultModeRequestBus::Handler::BusDisconnect();
}
void DefaultMode::Refresh()
{
// destroy all active modifiers
m_polygonScaleModifier.reset();
m_edgeScaleModifier.reset();
m_polygonTranslationModifier.reset();
m_edgeTranslationModifier.reset();
m_vertexTranslationModifier.reset();
m_selectedModifier = AZStd::monostate{};
}
AZStd::vector<AzToolsFramework::ActionOverride> DefaultMode::PopulateActions(
const AZ::EntityComponentIdPair& entityComponentIdPair)
{
// edge selection test - ensure an edge is selected before allowing this shortcut
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
{
return AZStd::vector<AzToolsFramework::ActionOverride>{
AzToolsFramework::ActionOverride()
.SetUri(HideEdge)
.SetKeySequence(HideKey)
.SetTitle(HideEdgeTitle)
.SetTip(HideEdgeDesc)
.SetEntityComponentIdPair(entityComponentIdPair)
.SetCallback(
[entityComponentIdPair, modifier]()
{
WhiteBoxMesh* whiteBox = nullptr;
EditorWhiteBoxComponentRequestBus::EventResult(
whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
Api::HideEdge(*whiteBox, (*modifier)->GetEdgeHandle());
(*modifier)->SetEdgeHandle(Api::EdgeHandle{});
RecordWhiteBoxAction(*whiteBox, entityComponentIdPair, HideEdgeUndoRedoDesc);
})};
}
// vertex selection test - ensure a vertex is selected before allowing this shortcut
else if (auto modifier2 = AZStd::get_if<AZStd::unique_ptr<VertexTranslationModifier>>(&m_selectedModifier))
{
return AZStd::vector<AzToolsFramework::ActionOverride>{
AzToolsFramework::ActionOverride()
.SetUri(HideVertex)
.SetKeySequence(HideKey)
.SetTitle(HideVertexTitle)
.SetTip(HideVertexDesc)
.SetEntityComponentIdPair(entityComponentIdPair)
.SetCallback(
[entityComponentIdPair, modifier2]()
{
WhiteBoxMesh* whiteBox = nullptr;
EditorWhiteBoxComponentRequestBus::EventResult(
whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
Api::HideVertex(*whiteBox, (*modifier2)->GetVertexHandle());
(*modifier2)->SetVertexHandle(Api::VertexHandle{});
RecordWhiteBoxAction(*whiteBox, entityComponentIdPair, HideVertexUndoRedoDesc);
})};
}
else
{
return {};
}
}
template<typename ModifierUniquePtr>
static void TryDestroyModifier(ModifierUniquePtr& modifier)
{
// has the mouse moved off of the modifier
if (modifier && !modifier->MouseOver())
{
modifier.reset();
}
}
static void DrawVertices(
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal,
const AzFramework::CameraState& cameraState, const IntersectionAndRenderData& renderData)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
const float vertexIndicatorLength = cl_whiteBoxVertexIndicatorLength;
const float vertexIndicatorWidth = cl_whiteBoxVertexIndicatorWidth;
const AZ::Color vertexIndicatorColor = cl_whiteBoxVertexIndicatorColor;
debugDisplay.SetLineWidth(vertexIndicatorWidth);
debugDisplay.SetColor(vertexIndicatorColor);
const auto drawVertIndicator = [&debugDisplay, &worldFromLocal, &cameraState, vertexIndicatorLength](
const AZ::Vector3& start, const AZ::Vector3& axis, const float length)
{
const auto scale =
AzToolsFramework::CalculateScreenToWorldMultiplier(worldFromLocal.TransformPoint(start), cameraState);
debugDisplay.DrawLine(start, start + axis * AZ::GetMin<float>(length, scale * vertexIndicatorLength));
};
for (const auto& edgeBound : renderData.m_whiteBoxEdgeRenderData.m_bounds.m_user)
{
const auto& start = edgeBound.m_bound.m_start;
const auto& end = edgeBound.m_bound.m_end;
const auto edge = end - start;
const auto length = edge.GetLength();
if (length > 0.0f)
{
const auto axis = edge / length;
drawVertIndicator(start, axis, length);
drawVertIndicator(end, -axis, length);
}
}
debugDisplay.SetLineWidth(1.0f);
}
void DefaultMode::Display(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Transform& worldFromLocal,
const IntersectionAndRenderData& renderData, [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
TryDestroyModifier(m_polygonTranslationModifier);
TryDestroyModifier(m_edgeTranslationModifier);
TryDestroyModifier(m_vertexTranslationModifier);
WhiteBoxMesh* whiteBox = nullptr;
EditorWhiteBoxComponentRequestBus::EventResult(
whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
debugDisplay.PushMatrix(worldFromLocal);
DrawEdges(
debugDisplay, cl_whiteBoxEdgeUserColor, renderData.m_whiteBoxIntersectionData.m_edgeBounds,
FindInteractiveEdgeHandles(*whiteBox));
DrawVertices(
debugDisplay, worldFromLocal, AzToolsFramework::GetCameraState(viewportInfo.m_viewportId), renderData);
debugDisplay.PopMatrix();
}
Api::EdgeHandles DefaultMode::FindInteractiveEdgeHandles(const WhiteBoxMesh& whiteBox)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
// get all edge handles for hovered polygon
const Api::EdgeHandles polygonHoveredEdgeHandles = m_polygonTranslationModifier
? Api::PolygonBorderEdgeHandlesFlattened(whiteBox, m_polygonTranslationModifier->GetPolygonHandle())
: Api::EdgeHandles{};
// find edge handles being used by active modifiers
const Api::EdgeHandles selectedEdgeHandles = [&whiteBox, this]()
{
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<PolygonTranslationModifier>>(&m_selectedModifier))
{
return Api::PolygonBorderEdgeHandlesFlattened(whiteBox, (*modifier)->GetPolygonHandle());
}
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
{
return Api::EdgeHandles{(*modifier)->GetEdgeHandle()};
}
return Api::EdgeHandles{};
}();
// combine all potentially interactive edge handles
Api::EdgeHandles interactiveEdgeHandles{polygonHoveredEdgeHandles};
interactiveEdgeHandles.insert(
interactiveEdgeHandles.end(), selectedEdgeHandles.begin(), selectedEdgeHandles.end());
if (m_edgeTranslationModifier)
{
// get edge handle for hovered edge (and associated group)
interactiveEdgeHandles.insert(
interactiveEdgeHandles.end(), m_edgeTranslationModifier->EdgeHandlesBegin(),
m_edgeTranslationModifier->EdgeHandlesEnd());
}
return interactiveEdgeHandles;
}
// if an edge or polygon scale modifier are selected, their scale manipulators (situated
// at the same position as a vertex) should take priority, so do not attempt to create
// a vertex selection modifier for those vertices that currently have a scale modifier
static bool IgnoreVertexHandle(
const WhiteBoxMesh& whiteBox, const PolygonScaleModifier* polygonScaleModifier,
const EdgeScaleModifier* edgeScaleModifier, const Api::VertexHandle vertexHandle)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
if (Api::VertexIsHidden(whiteBox, vertexHandle))
{
return true;
}
Api::VertexHandles vertexHandlesToIgnore;
if (polygonScaleModifier)
{
const auto polygonVertexHandles =
Api::PolygonVertexHandles(whiteBox, polygonScaleModifier->GetPolygonHandle());
vertexHandlesToIgnore.insert(
vertexHandlesToIgnore.end(), polygonVertexHandles.cbegin(), polygonVertexHandles.cend());
}
if (edgeScaleModifier)
{
const auto edgeVertexHandles = Api::EdgeVertexHandles(whiteBox, edgeScaleModifier->GetEdgeHandle());
vertexHandlesToIgnore.insert(
vertexHandlesToIgnore.end(), edgeVertexHandles.cbegin(), edgeVertexHandles.cend());
}
return AZStd::find(vertexHandlesToIgnore.cbegin(), vertexHandlesToIgnore.cend(), vertexHandle) !=
vertexHandlesToIgnore.cend();
}
// only return a valid optional if the vertex intersection is valid and it is not hidden
static AZStd::optional<VertexIntersection> FilterHiddenVertexIntersection(
const AZStd::optional<VertexIntersection>& vertexIntersection, const WhiteBoxMesh& whiteBox)
{
if (!vertexIntersection.has_value() || Api::VertexIsHidden(whiteBox, vertexIntersection->GetHandle()))
{
return AZStd::nullopt;
}
return vertexIntersection;
}
bool DefaultMode::HandleMouseInteraction(
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
const AZ::EntityComponentIdPair& entityComponentIdPair,
const AZStd::optional<EdgeIntersection>& edgeIntersection,
const AZStd::optional<PolygonIntersection>& polygonIntersection,
const AZStd::optional<VertexIntersection>& vertexIntersection)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
WhiteBoxMesh* whiteBox = nullptr;
EditorWhiteBoxComponentRequestBus::EventResult(
whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
// polygon
HandleMouseInteractionForModifier<PolygonTranslationModifier, PolygonIntersection>(
mouseInteraction, m_selectedModifier,
[this]
{
m_polygonScaleModifier.reset();
},
polygonIntersection);
// edge
HandleMouseInteractionForModifier<EdgeTranslationModifier, EdgeIntersection>(
mouseInteraction, m_selectedModifier,
[this]
{
m_edgeScaleModifier.reset();
},
edgeIntersection);
// do not allow intersections with hidden vertices in the default mode
const auto allowedVertexIntersection = FilterHiddenVertexIntersection(vertexIntersection, *whiteBox);
// vertex
HandleMouseInteractionForModifier<VertexTranslationModifier, VertexIntersection>(
mouseInteraction, m_selectedModifier, [] { /*noop*/ }, allowedVertexIntersection);
switch (FindClosestGeometryIntersection(edgeIntersection, polygonIntersection, allowedVertexIntersection))
{
case GeometryIntersection::Edge:
{
HandleCreatingDestroyingModifiersOnIntersectionChange<EdgeIntersection, EdgeTranslationModifier>(
mouseInteraction, m_selectedModifier, m_edgeTranslationModifier,
[this]
{
m_polygonTranslationModifier.reset();
m_vertexTranslationModifier.reset();
},
edgeIntersection, entityComponentIdPair);
}
break;
case GeometryIntersection::Polygon:
{
HandleCreatingDestroyingModifiersOnIntersectionChange<PolygonIntersection, PolygonTranslationModifier>(
mouseInteraction, m_selectedModifier, m_polygonTranslationModifier,
[this]
{
m_edgeTranslationModifier.reset();
m_vertexTranslationModifier.reset();
},
polygonIntersection, entityComponentIdPair);
}
break;
case GeometryIntersection::Vertex:
{
if (!IgnoreVertexHandle(
*whiteBox, m_polygonScaleModifier.get(), m_edgeScaleModifier.get(),
allowedVertexIntersection->GetHandle()))
{
HandleCreatingDestroyingModifiersOnIntersectionChange<
VertexIntersection, VertexTranslationModifier>(
mouseInteraction, m_selectedModifier, m_vertexTranslationModifier,
[this]
{
m_edgeTranslationModifier.reset();
m_polygonTranslationModifier.reset();
},
allowedVertexIntersection, entityComponentIdPair);
}
}
break;
case GeometryIntersection::None:
// do nothing
break;
default:
// do nothing
break;
}
return false;
}
void DefaultMode::CreatePolygonScaleModifier(const Api::PolygonHandle& polygonHandle)
{
m_polygonScaleModifier = AZStd::make_unique<PolygonScaleModifier>(polygonHandle, m_entityComponentIdPair);
}
void DefaultMode::CreateEdgeScaleModifier(const Api::EdgeHandle edgeHandle)
{
m_edgeScaleModifier = AZStd::make_unique<EdgeScaleModifier>(edgeHandle, m_entityComponentIdPair);
}
void DefaultMode::AssignSelectedPolygonTranslationModifier()
{
if (m_polygonTranslationModifier)
{
m_selectedModifier = AZStd::move(m_polygonTranslationModifier);
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::RefreshActions);
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<PolygonTranslationModifier>>(&m_selectedModifier))
{
(*modifier)->SetColors(
AZ::Color::CreateFromVector3AndFloat(
static_cast<AZ::Color>(cl_whiteBoxSelectedModifierColor).GetAsVector3(), 0.5f),
AZ::Color::CreateFromVector3AndFloat(
static_cast<AZ::Color>(cl_whiteBoxSelectedModifierColor).GetAsVector3(), 1.0f));
(*modifier)->CreateView();
}
m_edgeScaleModifier.reset();
m_vertexTranslationModifier.reset();
m_polygonTranslationModifier = nullptr;
}
}
void DefaultMode::AssignSelectedEdgeTranslationModifier()
{
if (m_edgeTranslationModifier)
{
m_selectedModifier = AZStd::move(m_edgeTranslationModifier);
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::RefreshActions);
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
{
(*modifier)->SetColors(cl_whiteBoxSelectedModifierColor, cl_whiteBoxSelectedModifierColor);
(*modifier)->SetWidths(cl_whiteBoxSelectedEdgeVisualWidth, cl_whiteBoxSelectedEdgeVisualWidth);
(*modifier)->CreateView();
}
m_polygonScaleModifier.reset();
m_vertexTranslationModifier.reset();
m_edgeTranslationModifier = nullptr;
}
}
void DefaultMode::AssignSelectedVertexSelectionModifier()
{
if (m_vertexTranslationModifier)
{
m_selectedModifier = AZStd::move(m_vertexTranslationModifier);
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::RefreshActions);
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<VertexTranslationModifier>>(&m_selectedModifier))
{
(*modifier)->SetColor(cl_whiteBoxVertexSelectedModifierColor);
(*modifier)->CreateView();
}
m_polygonScaleModifier.reset();
m_edgeScaleModifier.reset();
m_vertexTranslationModifier = nullptr;
}
}
void DefaultMode::RefreshPolygonScaleModifier()
{
if (m_polygonScaleModifier)
{
m_polygonScaleModifier->Refresh();
}
}
void DefaultMode::RefreshEdgeScaleModifier()
{
if (m_edgeScaleModifier)
{
m_edgeScaleModifier->Refresh();
}
}
void DefaultMode::RefreshPolygonTranslationModifier()
{
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<PolygonTranslationModifier>>(&m_selectedModifier))
{
if (!(*modifier)->PerformingAction())
{
(*modifier)->Refresh();
}
}
if (m_polygonTranslationModifier && !m_polygonTranslationModifier->PerformingAction())
{
m_polygonTranslationModifier->Refresh();
}
}
void DefaultMode::RefreshEdgeTranslationModifier()
{
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
{
if (!(*modifier)->PerformingAction())
{
(*modifier)->Refresh();
}
}
if (m_edgeTranslationModifier && !m_edgeTranslationModifier->PerformingAction())
{
m_edgeTranslationModifier->Refresh();
}
}
void DefaultMode::RefreshVertexSelectionModifier()
{
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<VertexTranslationModifier>>(&m_selectedModifier))
{
if (!(*modifier)->PerformingAction())
{
(*modifier)->Refresh();
}
}
if (m_vertexTranslationModifier && !m_vertexTranslationModifier->PerformingAction())
{
m_vertexTranslationModifier->Refresh();
}
}
template<typename Modifier>
auto ModifierHandles(const DefaultMode::SelectedTranslationModifier& selectedModifier)
{
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<Modifier>>(&selectedModifier))
{
return AZStd::vector<typename Modifier::HandleType>{(*modifier)->GetHandle()};
}
return AZStd::vector<typename Modifier::HandleType>{};
}
Api::VertexHandles DefaultMode::SelectedVertexHandles() const
{
return ModifierHandles<VertexTranslationModifier>(m_selectedModifier);
}
Api::EdgeHandles DefaultMode::SelectedEdgeHandles() const
{
return ModifierHandles<EdgeTranslationModifier>(m_selectedModifier);
}
Api::PolygonHandles DefaultMode::SelectedPolygonHandles() const
{
return ModifierHandles<PolygonTranslationModifier>(m_selectedModifier);
}
Api::VertexHandle DefaultMode::HoveredVertexHandle() const
{
return m_vertexTranslationModifier ? m_vertexTranslationModifier->GetVertexHandle() : Api::VertexHandle();
}
Api::EdgeHandle DefaultMode::HoveredEdgeHandle() const
{
return m_edgeTranslationModifier ? m_edgeTranslationModifier->GetEdgeHandle() : Api::EdgeHandle();
}
Api::PolygonHandle DefaultMode::HoveredPolygonHandle() const
{
return m_polygonTranslationModifier ? m_polygonTranslationModifier->GetPolygonHandle() : Api::PolygonHandle();
}
void DefaultMode::OnPolygonModifierUpdatedPolygonHandle(
const Api::PolygonHandle& previousPolygonHandle, const Api::PolygonHandle& nextPolygonHandle)
{
// an operation has caused the currently selected polygon handle to update (e.g. an append/extrusion)
// if the previous polygon handle matches the selected polygon translation modifier, we know it caused
// the extrusion and should be updated
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<PolygonTranslationModifier>>(&m_selectedModifier))
{
if ((*modifier)->GetPolygonHandle() == previousPolygonHandle)
{
(*modifier)->SetPolygonHandle(nextPolygonHandle);
m_polygonScaleModifier->SetPolygonHandle(nextPolygonHandle);
}
}
}
void DefaultMode::OnEdgeModifierUpdatedEdgeHandle(
const Api::EdgeHandle previousEdgeHandle, const Api::EdgeHandle nextEdgeHandle)
{
// an operation has caused the currently selected edge handle to update (e.g. an append/extrusion)
// if the previous edge handle matches the selected edge translation modifier, we know it caused
// the extrusion and should be updated
if (auto modifier = AZStd::get_if<AZStd::unique_ptr<EdgeTranslationModifier>>(&m_selectedModifier))
{
if ((*modifier)->GetEdgeHandle() == previousEdgeHandle)
{
m_edgeScaleModifier->SetEdgeHandle(nextEdgeHandle);
}
}
}
} // namespace WhiteBox
@@ -0,0 +1,130 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "EditorWhiteBoxComponentModeTypes.h"
#include "SubComponentModes/EditorWhiteBoxDefaultModeBus.h"
#include <EditorWhiteBoxEdgeModifierBus.h>
#include <EditorWhiteBoxPolygonModifierBus.h>
#include <QScopedPointer>
namespace AZ
{
class EntityComponentIdPair;
}
namespace AzFramework
{
struct ViewportInfo;
}
namespace AzToolsFramework
{
namespace ViewportInteraction
{
struct MouseInteractionEvent;
}
struct ActionOverride;
} // namespace AzToolsFramework
namespace WhiteBox
{
class EdgeTranslationModifier;
class PolygonTranslationModifier;
class PolygonScaleModifier;
class EdgeScaleModifier;
class VertexTranslationModifier;
//! The default mode of the EditorWhiteBoxComponentMode - this state allows immediate
//! interaction of polygons and edges.
class DefaultMode
: private EditorWhiteBoxDefaultModeRequestBus::Handler
, private EditorWhiteBoxPolygonModifierNotificationBus::Handler
, private EditorWhiteBoxEdgeModifierNotificationBus::Handler
{
public:
AZ_CLASS_ALLOCATOR_DECL
//! A variant to hold either a selected polygon translation, edge translation,
//! or a vertex selection modifier - default is empty (monostate).
using SelectedTranslationModifier = AZStd::variant<
AZStd::monostate, AZStd::unique_ptr<PolygonTranslationModifier>, AZStd::unique_ptr<EdgeTranslationModifier>,
AZStd::unique_ptr<VertexTranslationModifier>>;
explicit DefaultMode(const AZ::EntityComponentIdPair& entityComponentIdPair);
DefaultMode(DefaultMode&&) = default;
DefaultMode& operator=(DefaultMode&&) = default;
~DefaultMode();
// Interface
void Refresh();
AZStd::vector<AzToolsFramework::ActionOverride> PopulateActions(
const AZ::EntityComponentIdPair& entityComponentIdPair);
void Display(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Transform& worldFromLocal,
const IntersectionAndRenderData& renderData, const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay);
bool HandleMouseInteraction(
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
const AZ::EntityComponentIdPair& entityComponentIdPair,
const AZStd::optional<EdgeIntersection>& edgeIntersection,
const AZStd::optional<PolygonIntersection>& polygonIntersection,
const AZStd::optional<VertexIntersection>& vertexIntersection);
private:
// EditorWhiteBoxDefaultModeRequestBus ...
void CreatePolygonScaleModifier(const Api::PolygonHandle& polygonHandle) override;
void CreateEdgeScaleModifier(Api::EdgeHandle edgeHandle) override;
void AssignSelectedPolygonTranslationModifier() override;
void AssignSelectedEdgeTranslationModifier() override;
void AssignSelectedVertexSelectionModifier() override;
void RefreshPolygonScaleModifier() override;
void RefreshEdgeScaleModifier() override;
void RefreshPolygonTranslationModifier() override;
void RefreshEdgeTranslationModifier() override;
void RefreshVertexSelectionModifier() override;
Api::VertexHandles SelectedVertexHandles() const override;
Api::EdgeHandles SelectedEdgeHandles() const override;
Api::PolygonHandles SelectedPolygonHandles() const override;
Api::VertexHandle HoveredVertexHandle() const override;
Api::EdgeHandle HoveredEdgeHandle() const override;
Api::PolygonHandle HoveredPolygonHandle() const override;
// EditorWhiteBoxPolygonModifierNotificationBus ...
void OnPolygonModifierUpdatedPolygonHandle(
const Api::PolygonHandle& previousPolygonHandle, const Api::PolygonHandle& nextPolygonHandle) override;
// EditorWhiteBoxEdgeModifierNotificationBus ...
void OnEdgeModifierUpdatedEdgeHandle(
Api::EdgeHandle previousEdgeHandle, Api::EdgeHandle nextEdgeHandle) override;
//! Find all potentially interactive edge handles the user can select and manipulate.
Api::EdgeHandles FindInteractiveEdgeHandles(const WhiteBoxMesh& whiteBox);
//! The entity component id of the component mode this sub-mode is associated with.
AZ::EntityComponentIdPair m_entityComponentIdPair;
AZStd::unique_ptr<PolygonTranslationModifier>
m_polygonTranslationModifier; //!< The hovered polygon translation modifier.
AZStd::unique_ptr<EdgeTranslationModifier>
m_edgeTranslationModifier; //!< The currently instantiated edge translation modifier.
AZStd::unique_ptr<PolygonScaleModifier>
m_polygonScaleModifier; //!< The currently instantiated polygon scale modifier.
AZStd::unique_ptr<EdgeScaleModifier> m_edgeScaleModifier; //!< The currently instantiated edge scale modifier.
AZStd::unique_ptr<VertexTranslationModifier>
m_vertexTranslationModifier; //!< The currently instantiated vertex selection modifier.
SelectedTranslationModifier m_selectedModifier; //!< The type of selected translation modifier.
};
} // namespace WhiteBox
@@ -0,0 +1,73 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/ComponentBus.h>
#include <WhiteBox/WhiteBoxToolApi.h>
namespace WhiteBox
{
//! Request bus for White Box ComponentMode operations while in 'default' mode.
class EditorWhiteBoxDefaultModeRequests : public AZ::EntityComponentBus
{
public:
//! Create a polygon scale modifier for the given polygon handles.
virtual void CreatePolygonScaleModifier(const Api::PolygonHandle& polygonHandle) = 0;
//! Create an edge scale modifier for the given edge handle.
virtual void CreateEdgeScaleModifier(Api::EdgeHandle edgeHandle) = 0;
//! Assign whatever polygon is currently hovered to the selected polygon translation modifier.
virtual void AssignSelectedPolygonTranslationModifier() = 0;
//! Assign whatever edge is currently hovered to the selected edge translation modifier.
virtual void AssignSelectedEdgeTranslationModifier() = 0;
//! Assign whatever vertex is currently hovered to the vertex selection modifier.
virtual void AssignSelectedVertexSelectionModifier() = 0;
//! Refresh (rebuild) the polygon scale modifier.
//! The internal manipulator will be rebuilt from the current white box handles stored in the modifier.
virtual void RefreshPolygonScaleModifier() = 0;
//! Refresh (rebuild) the edge scale modifier.
//! The internal manipulator will be rebuilt from the current white box handles stored in the modifier.
virtual void RefreshEdgeScaleModifier() = 0;
//! Refresh (rebuild) the polygon translation modifier.
//! The internal manipulator will be rebuilt from the current white box handles stored in the modifier.
virtual void RefreshPolygonTranslationModifier() = 0;
//! Refresh (rebuild) the edge translation modifier.
//! The internal manipulator will be rebuilt from the current white box handles stored in the modifier.
virtual void RefreshEdgeTranslationModifier() = 0;
//! Refresh (rebuild) the vertex selection modifier.
//! The internal manipulator will be rebuilt from the current white box handles stored in the modifier.
virtual void RefreshVertexSelectionModifier() = 0;
//! Returns the currently selected vertex handles.
//! @note If no vertex handles are selected an empty vector is returned.
virtual Api::VertexHandles SelectedVertexHandles() const = 0;
//! Returns the currently selected edge handles.
//! @note If no edge handles are selected an empty vector is returned.
virtual Api::EdgeHandles SelectedEdgeHandles() const = 0;
//! Returns the currently selected polygon handles.
//! @note If no polygon handles are selected an empty vector is returned.
virtual Api::PolygonHandles SelectedPolygonHandles() const = 0;
//! Returns the hovered vertex handle.
//! @note If no vertex is currently being hovered then an invalid VertexHandle is returned.
virtual Api::VertexHandle HoveredVertexHandle() const = 0;
//! Returns the hovered edge handle.
//! @note If no edge is currently being hovered then an invalid EdgeHandle is returned.
virtual Api::EdgeHandle HoveredEdgeHandle() const = 0;
//! Returns the hovered polygon handle.
//! @note If no polygon is currently being hovered then an empty PolygonHandle is returned.
virtual Api::PolygonHandle HoveredPolygonHandle() const = 0;
protected:
~EditorWhiteBoxDefaultModeRequests() = default;
};
using EditorWhiteBoxDefaultModeRequestBus = AZ::EBus<EditorWhiteBoxDefaultModeRequests>;
} // namespace WhiteBox
@@ -0,0 +1,224 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "WhiteBox_precompiled.h"
#include "EditorWhiteBoxComponentModeCommon.h"
#include "EditorWhiteBoxEdgeRestoreMode.h"
#include "Viewport/WhiteBoxModifierUtil.h"
#include "Viewport/WhiteBoxViewportConstants.h"
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/std/sort.h>
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
#include <AzToolsFramework/Maths/TransformUtils.h>
#include <AzToolsFramework/Viewport/ViewportTypes.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <WhiteBox/EditorWhiteBoxComponentBus.h>
namespace WhiteBox
{
static const char* const FlipEdgeUndoRedoDesc = "Flip an edge to divide quad across different diagonal";
static const char* const RestoreEdgeUndoRedoDesc = "Restore an edge to split two connected polygons";
static const char* const RestoreVertexUndoRedoDesc = "Restore a vertex to split two connected edges";
AZ_CLASS_ALLOCATOR_IMPL(EdgeRestoreMode, AZ::SystemAllocator, 0)
void EdgeRestoreMode::Refresh()
{
// noop
}
AZStd::vector<AzToolsFramework::ActionOverride> EdgeRestoreMode::PopulateActions(
[[maybe_unused]] const AZ::EntityComponentIdPair& entityComponentIdPair)
{
return {};
}
bool EdgeRestoreMode::HandleMouseInteraction(
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
const AZ::EntityComponentIdPair& entityComponentIdPair,
const AZStd::optional<EdgeIntersection>& edgeIntersection,
[[maybe_unused]] const AZStd::optional<PolygonIntersection>& polygonIntersection,
const AZStd::optional<VertexIntersection>& vertexIntersection)
{
WhiteBoxMesh* whiteBox = nullptr;
EditorWhiteBoxComponentRequestBus::EventResult(
whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
const auto closestIntersection =
FindClosestGeometryIntersection(edgeIntersection, polygonIntersection, vertexIntersection);
// clear for each event/update
m_edgeIntersection.reset();
m_vertexIntersection.reset();
// update stored edge and vertex intersection
switch (closestIntersection)
{
case GeometryIntersection::Edge:
m_edgeIntersection = edgeIntersection;
break;
case GeometryIntersection::Vertex:
m_vertexIntersection = vertexIntersection;
break;
default:
// do nothing
break;
}
if (InputRestore(mouseInteraction))
{
switch (closestIntersection)
{
// ensure we were actually hovering over an edge when clicking
case GeometryIntersection::Edge:
{
// attempt to restore an edge
// (an optional<> is returned potentially containing two split polygons if successful)
if (Api::RestoreEdge(
*whiteBox, edgeIntersection->m_closestEdgeWithHandle.m_handle, m_edgeHandlesBeingRestored))
{
RecordWhiteBoxAction(*whiteBox, entityComponentIdPair, RestoreEdgeUndoRedoDesc);
return true;
}
}
break;
// ensure we were actually hovering over a vertex when clicking
case GeometryIntersection::Vertex:
{
// note: operation may fail if the vertex is isolated
if (Api::TryRestoreVertex(*whiteBox, vertexIntersection->m_closestVertexWithHandle.m_handle))
{
RecordWhiteBoxAction(*whiteBox, entityComponentIdPair, RestoreVertexUndoRedoDesc);
}
return true;
}
break;
default:
return false;
}
}
if (InputFlipEdge(mouseInteraction))
{
switch (closestIntersection)
{
// ensure we were actually hovering over an edge when clicking
case GeometryIntersection::Edge:
{
// attempt to flip an edge
if (Api::FlipEdge(*whiteBox, edgeIntersection->m_closestEdgeWithHandle.m_handle))
{
RecordWhiteBoxAction(*whiteBox, entityComponentIdPair, FlipEdgeUndoRedoDesc);
return true;
}
}
break;
default:
return false;
}
}
return false;
}
void EdgeRestoreMode::Display(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Transform& worldFromLocal,
const IntersectionAndRenderData& renderData, const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay)
{
// clang-format off
const Api::EdgeHandles interactiveEdgeHandles = m_edgeIntersection.has_value()
? Api::EdgeHandles{ m_edgeIntersection->m_closestEdgeWithHandle.m_handle }
: Api::EdgeHandles{};
// clang-format on
debugDisplay.PushMatrix(worldFromLocal);
// draw all 'user' and 'mesh' edges
DrawEdges(
debugDisplay, cl_whiteBoxEdgeUserColor, renderData.m_whiteBoxEdgeRenderData.m_bounds.m_user,
interactiveEdgeHandles);
DrawEdges(
debugDisplay, cl_whiteBoxEdgeMeshColor, renderData.m_whiteBoxEdgeRenderData.m_bounds.m_mesh,
interactiveEdgeHandles);
WhiteBoxMesh* whiteBox = nullptr;
EditorWhiteBoxComponentRequestBus::EventResult(
whiteBox, entityComponentIdPair, &EditorWhiteBoxComponentRequests::GetWhiteBoxMesh);
// special handling for edges in the process of being restored - an edge may be clicked
// and remain 'orphaned' from a polygon until another connection (loop) can be made.
for (const Api::EdgeHandle edgeHandleRestore : m_edgeHandlesBeingRestored)
{
if (AZStd::any_of(
interactiveEdgeHandles.begin(), interactiveEdgeHandles.end(),
[edgeHandleRestore](const Api::EdgeHandle edgeHandle)
{
return edgeHandle == edgeHandleRestore;
}))
{
continue;
}
debugDisplay.SetColor(cl_whiteBoxEdgeHoveredColor);
const auto edgeGeom = Api::EdgeVertexPositions(*whiteBox, edgeHandleRestore);
debugDisplay.DrawLine(edgeGeom[0], edgeGeom[1]);
}
// draw the hovered highlighted edge
if (!interactiveEdgeHandles.empty() && m_edgeIntersection.has_value())
{
debugDisplay.SetColor(cl_whiteBoxSelectedModifierColor);
debugDisplay.DrawLine(
m_edgeIntersection->m_closestEdgeWithHandle.m_bound.m_start,
m_edgeIntersection->m_closestEdgeWithHandle.m_bound.m_end);
}
debugDisplay.PopMatrix();
const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId);
const Api::VertexHandle hoveredVertexHandle =
m_vertexIntersection.value_or(VertexIntersection{}).m_closestVertexWithHandle.m_handle;
for (const auto& vertex : renderData.m_whiteBoxIntersectionData.m_vertexBounds)
{
if (hoveredVertexHandle == vertex.m_handle)
{
debugDisplay.SetColor(cl_whiteBoxVertexSelectedModifierColor);
}
else if (Api::VertexIsHidden(*whiteBox, vertex.m_handle))
{
debugDisplay.SetColor(cl_whiteBoxVertexHiddenRestoreColor);
}
else
{
debugDisplay.SetColor(cl_whiteBoxVertexRestoreColor);
}
// calculate the radius of the manipulator based
// on the distance from the camera
const float radius = cl_whiteBoxVertexManipulatorSize *
AzToolsFramework::CalculateScreenToWorldMultiplier(
worldFromLocal.TransformPoint(vertex.m_bound.m_center), cameraState);
// note: we must manually transform position to world space to avoid the size
// of the sphere being drawn incorrectly when scale is applied
debugDisplay.DrawBall(worldFromLocal.TransformPoint(vertex.m_bound.m_center), radius);
}
}
} // namespace WhiteBox
@@ -0,0 +1,73 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "EditorWhiteBoxComponentModeTypes.h"
namespace AZ
{
class EntityComponentIdPair;
}
namespace AzFramework
{
struct ViewportInfo;
}
namespace AzToolsFramework
{
namespace ViewportInteraction
{
struct MouseInteractionEvent;
}
struct ActionOverride;
} // namespace AzToolsFramework
namespace WhiteBox
{
struct IntersectionAndRenderData;
//! The mode where 'mesh' edges can be promoted/restored to 'user' edges so the user can interact
//! with them again or form new polygons to manipulate.
class EdgeRestoreMode
{
public:
AZ_CLASS_ALLOCATOR_DECL
EdgeRestoreMode() = default;
EdgeRestoreMode(EdgeRestoreMode&&) = default;
EdgeRestoreMode& operator=(EdgeRestoreMode&&) = default;
~EdgeRestoreMode() = default;
// Submode interface
void Refresh();
AZStd::vector<AzToolsFramework::ActionOverride> PopulateActions(
const AZ::EntityComponentIdPair& entityComponentIdPair);
void Display(
const AZ::EntityComponentIdPair& entityComponentIdPair, const AZ::Transform& worldFromLocal,
const IntersectionAndRenderData& renderData, const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay);
bool HandleMouseInteraction(
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteraction,
const AZ::EntityComponentIdPair& entityComponentIdPair,
const AZStd::optional<EdgeIntersection>& edgeIntersection,
const AZStd::optional<PolygonIntersection>& polygonIntersection,
const AZStd::optional<VertexIntersection>& vertexIntersection);
private:
AZStd::optional<EdgeIntersection> m_edgeIntersection; //!< The hovered edge if one exists.
AZStd::optional<VertexIntersection> m_vertexIntersection; //!< The hovered vertex if one exists.
Api::EdgeHandles m_edgeHandlesBeingRestored; //!< The edge handles currently attempting to be restored.
};
} // namespace WhiteBox