Merge branch 'o3de:development' into rapidjson-natvis
This commit is contained in:
@@ -20,7 +20,7 @@ set(ENABLED_GEMS
|
||||
QtForPython
|
||||
PythonAssetBuilder
|
||||
Metastream
|
||||
AudioSystem
|
||||
|
||||
Camera
|
||||
EMotionFX
|
||||
PhysX
|
||||
@@ -51,4 +51,9 @@ set(ENABLED_GEMS
|
||||
AWSCore
|
||||
AWSClientAuth
|
||||
AWSMetrics
|
||||
|
||||
|
||||
|
||||
|
||||
AudioSystem
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
OutlinerWidget #m_display_options
|
||||
{
|
||||
qproperty-icon: url(:/stylesheet/img/UI20/menu-centered.svg);
|
||||
qproperty-icon: url(:/Menu/menu.svg);
|
||||
qproperty-iconSize: 16px 16px;
|
||||
qproperty-flat: true;
|
||||
}
|
||||
|
||||
@@ -868,7 +868,16 @@ void CViewportTitleDlg::OnBnClickedMuteAudio()
|
||||
|
||||
void CViewportTitleDlg::UpdateMuteActionText()
|
||||
{
|
||||
m_audioMuteAction->setText(gSettings.bMuteAudio ? tr("Un-mute Audio") : tr("Mute Audio"));
|
||||
if (!Audio::AudioSystemRequestBus::HasHandlers())
|
||||
{
|
||||
m_audioMuteAction->setEnabled(false);
|
||||
m_audioMuteAction->setText(tr("Mute Audio: Enable Audio Gem"));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_audioMuteAction->setEnabled(true);
|
||||
m_audioMuteAction->setText(gSettings.bMuteAudio ? tr("Un-mute Audio") : tr("Mute Audio"));
|
||||
}
|
||||
}
|
||||
|
||||
void CViewportTitleDlg::OnHMDInitialized()
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace AZ
|
||||
#define AZ_TraceFmtCompileTimeCheck(expression, isVaArgs, baseMsg, msg, msgVargs) \
|
||||
{ \
|
||||
using namespace AZ::TraceInternal; \
|
||||
const auto& rTraceFmtCompileTimeCheckExpressionHelper = (expression); /* This is needed for edge cases for expressions containing lambdas, that were unsupported before C++20 */ \
|
||||
[[maybe_unused]] const auto& rTraceFmtCompileTimeCheckExpressionHelper = (expression); /* This is needed for edge cases for expressions containing lambdas, that were unsupported before C++20 */ \
|
||||
constexpr ExpressionValidResult isValidTraceFmtResult = ExpressionIsValid<decltype(rTraceFmtCompileTimeCheckExpressionHelper)>::value; \
|
||||
/* Assert different message depending whether it's const char array or if we have extra arguments */ \
|
||||
static_assert(!(isVaArgs) ? isValidTraceFmtResult != ExpressionValidResult::Invalid_ConstCharArray : true, baseMsg " " msg); \
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="component-header" transform="translate(-426.000000, -6.000000)" fill="#FFFFFF">
|
||||
<g id="Buttons-/-Dropdown-button-with-Icon-/-Default" transform="translate(424.000000, 4.000000)">
|
||||
<polygon id="Triangle" transform="translate(19.000000, 8.500000) scale(1, -1) translate(-19.000000, -8.500000) " points="19 7 22 10 16 10"></polygon>
|
||||
<polygon id="Triangle" transform="translate(19.000000, 8.500000) scale(1, -1) translate(-19.000000, -8.500000) " points="20 9 23 12 17 12"></polygon>
|
||||
<g id="Sky-Icon-/-System-/-Menu">
|
||||
<rect id="Rectangle-11" x="2" y="2" width="12" height="2"></rect>
|
||||
<rect id="Rectangle-11" x="2" y="7" width="12" height="2"></rect>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -3,9 +3,9 @@
|
||||
<title>Buttons / Dropdown button with Icon / no arrow</title>
|
||||
<g id="Buttons-/-Dropdown-button-with-Icon-/-no-arrow" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Icons-/-System-/-Menu" fill="#FFFFFF">
|
||||
<rect id="Rectangle-11" x="1.33333333" y="2.66666667" width="13.3333333" height="1.33333333"></rect>
|
||||
<rect id="Rectangle-11" x="1.33333333" y="7.33333333" width="13.3333333" height="1.33333333"></rect>
|
||||
<rect id="Rectangle-11" x="1.33333333" y="12" width="13.3333333" height="1.33333333"></rect>
|
||||
<rect id="Rectangle-11" x="4" y="2.66666667" width="12" height="2"></rect>
|
||||
<rect id="Rectangle-11" x="4" y="7.33333333" width="12" height="2"></rect>
|
||||
<rect id="Rectangle-11" x="4" y="12" width="12" height="2"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 786 B After Width: | Height: | Size: 708 B |
+6
@@ -1145,6 +1145,12 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (interaction.m_keyboardModifiers.Alt())
|
||||
{
|
||||
if (!CanDeleteSelection<Vertex>(entityComponentIdPair.GetEntityId(), /*selectedCount=*/1))
|
||||
{
|
||||
ShowVertexDeletionWarning();
|
||||
return;
|
||||
}
|
||||
|
||||
SafeRemoveVertex<Vertex>(entityComponentIdPair, vertexIndex);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -27,6 +27,8 @@ using namespace AzToolsFramework;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
const auto TestComponentId = AZ::ComponentId(1234);
|
||||
|
||||
// test implementation of variable/fixed vertex request buses
|
||||
// (to be used in place of spline/polygon prism etc)
|
||||
class TestVariableVerticesVertexContainer
|
||||
@@ -86,6 +88,9 @@ namespace UnitTest
|
||||
|
||||
void TearDownEditorFixtureImpl() override
|
||||
{
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorEntityContextRequestBus::Events::DestroyEditorEntity, m_entityId);
|
||||
|
||||
m_vertexContainer.Disconnect();
|
||||
m_vertexSelection.Destroy();
|
||||
}
|
||||
@@ -106,7 +111,7 @@ namespace UnitTest
|
||||
void EditorVertexSelectionFixture::RecreateVertexSelection()
|
||||
{
|
||||
m_vertexSelection.Create(
|
||||
AZ::EntityComponentIdPair(m_entityId, AZ::InvalidComponentId),
|
||||
AZ::EntityComponentIdPair(m_entityId, TestComponentId),
|
||||
g_mainManipulatorManagerId, AZStd::make_unique<NullHoverSelection>(),
|
||||
TranslationManipulators::Dimensions::Three, ConfigureTranslationManipulatorAppearance3d);
|
||||
}
|
||||
@@ -116,7 +121,7 @@ namespace UnitTest
|
||||
for (size_t vertIndex = 0; vertIndex < EditorVertexSelectionFixture::VertexCount; ++vertIndex)
|
||||
{
|
||||
InsertVertexAfter(
|
||||
AZ::EntityComponentIdPair(m_entityId, AZ::InvalidComponentId), 0, AZ::Vector3::CreateZero());
|
||||
AZ::EntityComponentIdPair(m_entityId, TestComponentId), 0, AZ::Vector3::CreateZero());
|
||||
}
|
||||
}
|
||||
void EditorVertexSelectionFixture::ClearVertices()
|
||||
@@ -124,7 +129,7 @@ namespace UnitTest
|
||||
for (size_t vertIndex = 0; vertIndex < EditorVertexSelectionFixture::VertexCount; ++vertIndex)
|
||||
{
|
||||
SafeRemoveVertex<AZ::Vector3>(
|
||||
AZ::EntityComponentIdPair(m_entityId, AZ::InvalidComponentId), 0);
|
||||
AZ::EntityComponentIdPair(m_entityId, TestComponentId), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +202,7 @@ namespace UnitTest
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
const auto entityComponentIdPair = AZ::EntityComponentIdPair(m_entityId, AZ::InvalidComponentId);
|
||||
const auto entityComponentIdPair = AZ::EntityComponentIdPair(m_entityId, TestComponentId);
|
||||
|
||||
const float horizontalPositions[] = {-1.5f, -0.5f, 0.5f, 1.5f};
|
||||
for (size_t vertIndex = 0; vertIndex < std::size(horizontalPositions); ++vertIndex)
|
||||
@@ -252,4 +257,45 @@ namespace UnitTest
|
||||
// deleting all vertices is disallowed - size should remain the same
|
||||
EXPECT_THAT(vertexCountAfter, Eq(EditorVertexSelectionFixture::VertexCount));
|
||||
}
|
||||
|
||||
TEST_F(EditorVertexSelectionManipulatorFixture, CannotDeleteLastVertexWithManipulator)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
const auto entityComponentIdPair = AZ::EntityComponentIdPair(m_entityId, TestComponentId);
|
||||
|
||||
// add a single vertex (in front of the camera)
|
||||
InsertVertexAfter(entityComponentIdPair, 0, AZ::Vector3::CreateAxisY(5.0f));
|
||||
|
||||
// rebuild the vertex selection after adding the new verts
|
||||
RecreateVertexSelection();
|
||||
|
||||
AzFramework::ScreenPoint vertexScreenPosition;
|
||||
{
|
||||
AZ::Vector3 localVertex;
|
||||
bool found = false;
|
||||
AZ::FixedVerticesRequestBus<AZ::Vector3>::EventResult(
|
||||
found, m_entityId, &AZ::FixedVerticesRequestBus<AZ::Vector3>::Handler::GetVertex, 0, localVertex);
|
||||
|
||||
if (found)
|
||||
{
|
||||
// note: entity position is at the origin so localVertex position is equivalent to world
|
||||
vertexScreenPosition = AzFramework::WorldToScreen(localVertex, m_cameraState);
|
||||
}
|
||||
}
|
||||
|
||||
// attempt to delete the vertex by clicking with Alt held
|
||||
m_actionDispatcher->CameraState(m_cameraState)
|
||||
->MousePosition(vertexScreenPosition)
|
||||
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Alt)
|
||||
->MouseLButtonDown()
|
||||
->MouseLButtonUp();
|
||||
|
||||
size_t vertexCountAfter = 0;
|
||||
AZ::VariableVerticesRequestBus<AZ::Vector3>::EventResult(
|
||||
vertexCountAfter, m_entityId, &AZ::VariableVerticesRequestBus<AZ::Vector3>::Events::Size);
|
||||
|
||||
// deleting the last vertex through a manipulator is disallowed - size should remain the same
|
||||
EXPECT_THAT(vertexCountAfter, Eq(1));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
|
||||
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBoneData.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/GraphData/IAnimationData.h>
|
||||
#include <SceneAPI/SceneData/Rules/CoordinateSystemRule.h>
|
||||
|
||||
@@ -166,6 +165,34 @@ namespace EMotionFX
|
||||
return finalMotionData;
|
||||
}
|
||||
|
||||
AZ::SceneAPI::DataTypes::MatrixType MotionDataBuilder::GetLocalSpaceBindPose(const SceneContainers::SceneGraph& sceneGraph,
|
||||
const SceneContainers::SceneGraph::NodeIndex rootBoneNodeIndex,
|
||||
const SceneContainers::SceneGraph::NodeIndex nodeIndex,
|
||||
const SceneDataTypes::ITransform* transform,
|
||||
const SceneDataTypes::IBoneData* bone) const
|
||||
{
|
||||
if (nodeIndex != rootBoneNodeIndex)
|
||||
{
|
||||
const SceneContainers::SceneGraph::NodeIndex parentNodeIndex = sceneGraph.GetNodeParent(nodeIndex);
|
||||
const SceneDataTypes::IGraphObject* parentNode = sceneGraph.GetNodeContent(parentNodeIndex).get();
|
||||
if (const SceneDataTypes::IBoneData* parentBone = azrtti_cast<const SceneDataTypes::IBoneData*>(parentNode))
|
||||
{
|
||||
return parentBone->GetWorldTransform().GetInverseFull() * bone->GetWorldTransform();
|
||||
}
|
||||
}
|
||||
|
||||
if (bone)
|
||||
{
|
||||
return bone->GetWorldTransform();
|
||||
}
|
||||
else if (transform)
|
||||
{
|
||||
return transform->GetMatrix();
|
||||
}
|
||||
|
||||
return AZ::SceneAPI::DataTypes::MatrixType::CreateIdentity();
|
||||
}
|
||||
|
||||
AZ::SceneAPI::Events::ProcessingResult MotionDataBuilder::BuildMotionData(MotionDataBuilderContext& context)
|
||||
{
|
||||
if (context.m_phase != AZ::RC::Phase::Filling)
|
||||
@@ -220,8 +247,10 @@ namespace EMotionFX
|
||||
continue;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<const SceneDataTypes::IBoneData> nodeBone = azrtti_cast<const SceneDataTypes::IBoneData*>(it->second);
|
||||
if (!nodeBone)
|
||||
// Check if we are dealing with a transform node or a bone and only recurse down the node hierarchy in this case.
|
||||
const SceneDataTypes::IBoneData* nodeBone = azrtti_cast<const SceneDataTypes::IBoneData*>(it->second.get());
|
||||
const SceneDataTypes::ITransform* nodeTransform = azrtti_cast<const SceneDataTypes::ITransform*>(it->second.get());
|
||||
if (!nodeBone && !nodeTransform)
|
||||
{
|
||||
it.IgnoreNodeDescendants();
|
||||
continue;
|
||||
@@ -289,24 +318,13 @@ namespace EMotionFX
|
||||
|
||||
// Get the bind pose transform in local space.
|
||||
using SceneAPIMatrixType = AZ::SceneAPI::DataTypes::MatrixType;
|
||||
SceneAPIMatrixType bindSpaceLocalTransform;
|
||||
const SceneContainers::SceneGraph::NodeIndex parentIndex = graph.GetNodeParent(boneNodeIndex);
|
||||
if (boneNodeIndex != rootBoneNodeIndex)
|
||||
{
|
||||
auto parentNode = graph.GetNodeContent(parentIndex);
|
||||
AZStd::shared_ptr<const SceneDataTypes::IBoneData> parentNodeBone = azrtti_cast<const SceneDataTypes::IBoneData*>(parentNode);
|
||||
bindSpaceLocalTransform = parentNodeBone->GetWorldTransform().GetInverseFull() * nodeBone->GetWorldTransform();
|
||||
}
|
||||
else
|
||||
{
|
||||
bindSpaceLocalTransform = nodeBone->GetWorldTransform();
|
||||
}
|
||||
const SceneAPIMatrixType bindSpaceLocalTransform = GetLocalSpaceBindPose(graph, rootBoneNodeIndex, boneNodeIndex, nodeTransform, nodeBone);
|
||||
|
||||
// Get the time step and make sure it didn't change compared to other joint animations.
|
||||
const double timeStep = animation->GetTimeStepBetweenFrames();
|
||||
lowestTimeStep = AZ::GetMin<double>(timeStep, lowestTimeStep);
|
||||
|
||||
SceneAPIMatrixType sampleFrameTransformInverse;
|
||||
AZ::SceneAPI::DataTypes::MatrixType sampleFrameTransformInverse;
|
||||
if (additiveRule)
|
||||
{
|
||||
size_t sampleFrameIndex = additiveRule->GetSampleFrameIndex();
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
#include <SceneAPI/SceneCore/Components/ExportingComponent.h>
|
||||
#include <SceneAPI/SceneCore/Containers/Scene.h>
|
||||
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBoneData.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/GraphData/ITransform.h>
|
||||
|
||||
namespace EMotionFX
|
||||
{
|
||||
@@ -28,6 +31,14 @@ namespace EMotionFX
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZ::SceneAPI::Events::ProcessingResult BuildMotionData(MotionDataBuilderContext& context);
|
||||
|
||||
private:
|
||||
//! Get the bind pose transform in local space.
|
||||
AZ::SceneAPI::DataTypes::MatrixType GetLocalSpaceBindPose(const AZ::SceneAPI::Containers::SceneGraph& sceneGraph,
|
||||
const AZ::SceneAPI::Containers::SceneGraph::NodeIndex rootBoneNodeIndex,
|
||||
const AZ::SceneAPI::Containers::SceneGraph::NodeIndex nodeIndex,
|
||||
const AZ::SceneAPI::DataTypes::ITransform* transform,
|
||||
const AZ::SceneAPI::DataTypes::IBoneData* bone) const;
|
||||
};
|
||||
} // namespace Pipeline
|
||||
} // namespace EMotionFX
|
||||
|
||||
@@ -143,6 +143,7 @@ namespace EMotionFX
|
||||
|
||||
Group::ActorGroup* group = azrtti_cast<Group::ActorGroup*>(&target);
|
||||
group->SetName(AZ::SceneAPI::DataTypes::Utilities::CreateUniqueName<Group::IActorGroup>(scene.GetName(), scene.GetManifest()));
|
||||
group->SetBestMatchingRootBone(scene.GetGraph());
|
||||
|
||||
// LOD Rule need to be built first in the actor, so we know which mesh and bone belongs to LOD.
|
||||
// After this call, LOD rule will be populated with all the LOD bones
|
||||
|
||||
@@ -9,10 +9,14 @@
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
|
||||
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
|
||||
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/Rules/IRule.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBoneData.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshData.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/Groups/ISceneNodeGroup.h>
|
||||
#include <SceneAPI/SceneData/GraphData/RootBoneData.h>
|
||||
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
|
||||
#include <SceneAPI/SceneData/Rules/CoordinateSystemRule.h>
|
||||
#include <SceneAPIExt/Groups/ActorGroup.h>
|
||||
@@ -76,6 +80,22 @@ namespace EMotionFX
|
||||
m_selectedRootBone = selectedRootBone;
|
||||
}
|
||||
|
||||
void ActorGroup::SetBestMatchingRootBone(const AZ::SceneAPI::Containers::SceneGraph& sceneGraph)
|
||||
{
|
||||
auto nameContentView = AZ::SceneAPI::Containers::Views::MakePairView(sceneGraph.GetNameStorage(), sceneGraph.GetContentStorage());
|
||||
auto graphDownwardsView = AZ::SceneAPI::Containers::Views::MakeSceneGraphDownwardsView<AZ::SceneAPI::Containers::Views::BreadthFirst>(
|
||||
sceneGraph, sceneGraph.GetRoot(), nameContentView.begin(), true);
|
||||
|
||||
for (auto it = graphDownwardsView.begin(); it != graphDownwardsView.end(); ++it)
|
||||
{
|
||||
if (it->second && it->second->RTTI_IsTypeOf(AZ::SceneData::GraphData::RootBoneData::TYPEINFO_Uuid()))
|
||||
{
|
||||
SetSelectedRootBone(it->first.GetPath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActorGroup::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
|
||||
@@ -45,8 +45,8 @@ namespace EMotionFX
|
||||
|
||||
// IActorGroup overrides
|
||||
const AZStd::string& GetSelectedRootBone() const override;
|
||||
|
||||
void SetSelectedRootBone(const AZStd::string& selectedRootBone) override;
|
||||
void SetBestMatchingRootBone(const AZ::SceneAPI::Containers::SceneGraph& sceneGraph) override;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
static bool IActorGroupVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
|
||||
|
||||
namespace AZ::SceneAPI::Containers
|
||||
{
|
||||
class SceneGraph;
|
||||
}
|
||||
|
||||
namespace EMotionFX
|
||||
{
|
||||
namespace Pipeline
|
||||
@@ -26,6 +31,7 @@ namespace EMotionFX
|
||||
|
||||
virtual const AZStd::string& GetSelectedRootBone() const = 0;
|
||||
virtual void SetSelectedRootBone(const AZStd::string& selectedRootBone) = 0;
|
||||
virtual void SetBestMatchingRootBone(const AZ::SceneAPI::Containers::SceneGraph& sceneGraph) = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,28 +268,6 @@ namespace LmbrCentral
|
||||
ContainerChanged();
|
||||
}
|
||||
|
||||
AZStd::vector<EditorTubeShapeComponentMode::TubeManipulatorState> EditorTubeShapeComponentMode::GenerateTubeManipulatorStates(
|
||||
const AZ::Spline& spline)
|
||||
{
|
||||
const AZ::u64 startVertex = spline.GetAddressByFraction(0.0f).m_segmentIndex;
|
||||
const AZ::u64 endVertex = startVertex + spline.GetSegmentCount() + (spline.IsClosed() ? 0 : 1);
|
||||
|
||||
AZStd::vector<TubeManipulatorState> splineAddresses;
|
||||
for (AZ::u64 vertIndex = startVertex; vertIndex < endVertex; ++vertIndex)
|
||||
{
|
||||
if (vertIndex + 1 == endVertex)
|
||||
{
|
||||
splineAddresses.push_back({ AZ::SplineAddress(vertIndex - 1, 1.0f), vertIndex });
|
||||
}
|
||||
else
|
||||
{
|
||||
splineAddresses.push_back({ AZ::SplineAddress(vertIndex), vertIndex });
|
||||
}
|
||||
}
|
||||
|
||||
return splineAddresses;
|
||||
}
|
||||
|
||||
void EditorTubeShapeComponentMode::RefreshManipulatorsLocal(const AZ::EntityId entityId)
|
||||
{
|
||||
AZ::SplinePtr spline;
|
||||
@@ -318,4 +296,37 @@ namespace LmbrCentral
|
||||
m_radiusManipulators[manipulatorIndex]->SetBoundsDirty();
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::vector<EditorTubeShapeComponentMode::TubeManipulatorState> GenerateTubeManipulatorStates(const AZ::Spline& spline)
|
||||
{
|
||||
if (spline.GetVertexCount() == 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto segmentCount = spline.GetSegmentCount();
|
||||
if (segmentCount == 0)
|
||||
{
|
||||
return { { AZ::SplineAddress(0), 0 } };
|
||||
}
|
||||
|
||||
const AZ::u64 startVertex = spline.GetAddressByFraction(0.0f).m_segmentIndex;
|
||||
const AZ::u64 endVertex = startVertex + segmentCount + (spline.IsClosed() ? 0 : 1);
|
||||
|
||||
AZStd::vector<EditorTubeShapeComponentMode::TubeManipulatorState> splineAddresses;
|
||||
for (AZ::u64 vertIndex = startVertex; vertIndex < endVertex; ++vertIndex)
|
||||
{
|
||||
if (vertIndex + 1 == endVertex)
|
||||
{
|
||||
AZ_Assert(vertIndex > 0, "vertexIndex is 0 and not safe to subtract from")
|
||||
splineAddresses.push_back({ AZ::SplineAddress(vertIndex - 1, 1.0f), vertIndex });
|
||||
}
|
||||
else
|
||||
{
|
||||
splineAddresses.push_back({ AZ::SplineAddress(vertIndex), vertIndex });
|
||||
}
|
||||
}
|
||||
|
||||
return splineAddresses;
|
||||
}
|
||||
} // namespace LmbrCentral
|
||||
|
||||
@@ -31,6 +31,13 @@ namespace LmbrCentral
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR_DECL
|
||||
|
||||
/// Data required per TubeShape manipulator.
|
||||
struct TubeManipulatorState
|
||||
{
|
||||
AZ::SplineAddress m_splineAddress;
|
||||
AZ::u64 m_vertIndex;
|
||||
};
|
||||
|
||||
EditorTubeShapeComponentMode(
|
||||
const AZ::EntityComponentIdPair& entityComponentIdPair, AZ::Uuid componentType);
|
||||
~EditorTubeShapeComponentMode();
|
||||
@@ -64,18 +71,11 @@ namespace LmbrCentral
|
||||
|
||||
void RefreshManipulatorsLocal(AZ::EntityId entityId);
|
||||
|
||||
/// Data required per TubeShape manipulator.
|
||||
struct TubeManipulatorState
|
||||
{
|
||||
AZ::SplineAddress m_splineAddress;
|
||||
AZ::u64 m_vertIndex;
|
||||
};
|
||||
|
||||
/// For a given Tube + Spline combo, generate data required for each manipulator at
|
||||
/// each vertex required for modifying the tube.
|
||||
AZStd::vector<TubeManipulatorState> GenerateTubeManipulatorStates(const AZ::Spline& spline);
|
||||
|
||||
AZ::Transform m_currentTransform; ///< The current localToWorld transform of the TubeShape.
|
||||
AZStd::vector<AZStd::shared_ptr<AzToolsFramework::LinearManipulator>> m_radiusManipulators; ///< Manipulators to control the radius (volume) of the tube at each vertex.
|
||||
};
|
||||
|
||||
/// For a given Tube + Spline combo, generate data required for each manipulator at
|
||||
/// each vertex required for modifying the tube.
|
||||
AZStd::vector<EditorTubeShapeComponentMode::TubeManipulatorState> GenerateTubeManipulatorStates(const AZ::Spline& spline);
|
||||
} // namespace LmbrCentral
|
||||
|
||||
@@ -31,22 +31,20 @@ namespace LmbrCentral
|
||||
return vertices + 1;
|
||||
}
|
||||
|
||||
void DrawShape(
|
||||
AzFramework::DebugDisplayRequests& debugDisplay,
|
||||
const ShapeDrawParams& shapeDrawParams, const ShapeMesh& shapeMesh)
|
||||
void DrawShape(AzFramework::DebugDisplayRequests& debugDisplay, const ShapeDrawParams& shapeDrawParams, const ShapeMesh& shapeMesh)
|
||||
{
|
||||
if (shapeDrawParams.m_filled)
|
||||
{
|
||||
debugDisplay.DrawTrianglesIndexed(
|
||||
shapeMesh.m_vertexBuffer,
|
||||
shapeMesh.m_indexBuffer,
|
||||
shapeDrawParams.m_shapeColor
|
||||
);
|
||||
if (!shapeMesh.m_vertexBuffer.empty() && !shapeMesh.m_indexBuffer.empty())
|
||||
{
|
||||
debugDisplay.DrawTrianglesIndexed(shapeMesh.m_vertexBuffer, shapeMesh.m_indexBuffer, shapeDrawParams.m_shapeColor);
|
||||
}
|
||||
}
|
||||
|
||||
debugDisplay.DrawLines(
|
||||
shapeMesh.m_lineBuffer,
|
||||
shapeDrawParams.m_wireColor);
|
||||
if (!shapeMesh.m_lineBuffer.empty())
|
||||
{
|
||||
debugDisplay.DrawLines(shapeMesh.m_lineBuffer, shapeDrawParams.m_wireColor);
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine if a list of vertices constitute a simple polygon
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
@@ -131,7 +131,7 @@ namespace LmbrCentral
|
||||
m_variableRadius.SetElement(vertIndex, radius);
|
||||
ValidateVariableRadius(vertIndex);
|
||||
}
|
||||
|
||||
|
||||
ShapeComponentNotificationsBus::Event(
|
||||
m_entityId, &ShapeComponentNotificationsBus::Events::OnShapeChanged,
|
||||
ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged);
|
||||
@@ -379,6 +379,14 @@ namespace LmbrCentral
|
||||
const float radius, const AZ::u32 capSegments, const AZ::u32 sides,
|
||||
AZStd::vector<AZ::Vector3>& vertexBufferOut)
|
||||
{
|
||||
const size_t segmentCount = spline->GetSegmentCount();
|
||||
if (segmentCount == 0)
|
||||
{
|
||||
// clear the buffer so we no longer draw anything
|
||||
vertexBufferOut.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// notes on vert buffer size
|
||||
// total end segments
|
||||
// 2 verts for each segment
|
||||
@@ -393,7 +401,7 @@ namespace LmbrCentral
|
||||
// 2 verts for each segment
|
||||
// loops == sides
|
||||
// 2 loops per segment
|
||||
const AZ::u32 segments = spline->GetSegmentCount() * spline->GetSegmentGranularity();
|
||||
const AZ::u32 segments = segmentCount * spline->GetSegmentGranularity();
|
||||
const AZ::u32 totalEndSegments = capSegments * 2 * 2 * 2 * 2;
|
||||
const AZ::u32 totalSegments = segments * 2 * 2 * 2;
|
||||
const AZ::u32 totalLoops = 2 * sides * segments * 2;
|
||||
@@ -401,7 +409,7 @@ namespace LmbrCentral
|
||||
const size_t numVerts = totalEndSegments + totalSegments + totalLoops;
|
||||
vertexBufferOut.resize(numVerts);
|
||||
|
||||
AZ::Vector3* vertices = vertexBufferOut.begin();
|
||||
AZ::Vector3* vertices = vertexBufferOut.data();
|
||||
|
||||
// start cap
|
||||
auto address = spline->GetAddressByFraction(0.0f);
|
||||
@@ -422,7 +430,7 @@ namespace LmbrCentral
|
||||
// body
|
||||
const float stepDelta = 1.0f / static_cast<float>(spline->GetSegmentGranularity());
|
||||
auto nextAddress = address;
|
||||
const auto endIndex = address.m_segmentIndex + spline->GetSegmentCount();
|
||||
const auto endIndex = address.m_segmentIndex + segmentCount;
|
||||
while (address.m_segmentIndex < endIndex)
|
||||
{
|
||||
address.m_segmentFraction = 0.f;
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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/UnitTest/TestTypes.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <Source/Shape/EditorTubeShapeComponentMode.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
void PrintTo(const AZ::SplineAddress& splineAddress, std::ostream* os)
|
||||
{
|
||||
*os << "SplineAddress { segmentIndex: " << splineAddress.m_segmentIndex << ", segmentFraction: " << splineAddress.m_segmentFraction
|
||||
<< " }";
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class EditorTubeShapeFixture
|
||||
: public AllocatorsFixture
|
||||
, public ::testing::WithParamInterface<bool>
|
||||
{
|
||||
};
|
||||
|
||||
// test both open and closed versions of the spline
|
||||
INSTANTIATE_TEST_CASE_P(GenerateTubeManipulatorStates, EditorTubeShapeFixture, ::testing::Values(true, false));
|
||||
|
||||
TEST_P(EditorTubeShapeFixture, GenerateTubeManipulatorStates_returns_no_TubeManipulatorStates_when_spline_is_empty)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
// given (an empty spline)
|
||||
AZ::BezierSpline spline;
|
||||
spline.SetClosed(GetParam());
|
||||
|
||||
// when (tube manipulator states are attempted to be created)
|
||||
const auto tubeManipulatorStates = LmbrCentral::GenerateTubeManipulatorStates(spline);
|
||||
|
||||
// then (none are returned)
|
||||
EXPECT_THAT(tubeManipulatorStates.empty(), Eq(true));
|
||||
}
|
||||
|
||||
TEST_P(EditorTubeShapeFixture, GenerateTubeManipulatorStates_returns_one_TubeManipulatorStates_when_spline_has_one_vertex)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
// given (an empty spline)
|
||||
AZ::BezierSpline spline;
|
||||
spline.SetClosed(GetParam());
|
||||
spline.m_vertexContainer.AddVertex(AZ::Vector3::CreateZero());
|
||||
|
||||
// when (tube manipulator states are attempted to be created)
|
||||
const auto tubeManipulatorStates = LmbrCentral::GenerateTubeManipulatorStates(spline);
|
||||
|
||||
// then (one is returned)
|
||||
EXPECT_THAT(tubeManipulatorStates.size(), Eq(1));
|
||||
EXPECT_THAT(tubeManipulatorStates[0].m_splineAddress, Eq(AZ::SplineAddress(0, 0.0f)));
|
||||
EXPECT_THAT(tubeManipulatorStates[0].m_vertIndex, Eq(0));
|
||||
}
|
||||
|
||||
TEST_P(EditorTubeShapeFixture, GenerateTubeManipulatorStates_returns_two_TubeManipulatorStates_when_spline_has_two_vertices)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
// given (an empty spline)
|
||||
AZ::BezierSpline spline;
|
||||
spline.SetClosed(GetParam());
|
||||
|
||||
spline.m_vertexContainer.AddVertex(AZ::Vector3::CreateZero());
|
||||
spline.m_vertexContainer.AddVertex(AZ::Vector3::CreateAxisX(1.0f));
|
||||
|
||||
// when (tube manipulator states are attempted to be created)
|
||||
const auto tubeManipulatorStates = LmbrCentral::GenerateTubeManipulatorStates(spline);
|
||||
|
||||
// then (two are returned)
|
||||
EXPECT_THAT(tubeManipulatorStates.size(), Eq(2));
|
||||
|
||||
EXPECT_THAT(tubeManipulatorStates[0].m_splineAddress, Eq(AZ::SplineAddress(0, 0.0f)));
|
||||
EXPECT_THAT(tubeManipulatorStates[0].m_vertIndex, Eq(0));
|
||||
|
||||
EXPECT_THAT(tubeManipulatorStates[1].m_splineAddress, Eq(AZ::SplineAddress(0, 1.0f)));
|
||||
EXPECT_THAT(tubeManipulatorStates[1].m_vertIndex, Eq(1));
|
||||
}
|
||||
|
||||
TEST_P(EditorTubeShapeFixture, GenerateTubeManipulatorStates_returns_three_TubeManipulatorStates_when_spline_has_three_vertices)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
// given (an empty spline)
|
||||
AZ::BezierSpline spline;
|
||||
spline.SetClosed(GetParam());
|
||||
|
||||
spline.m_vertexContainer.AddVertex(AZ::Vector3::CreateAxisX(-1.0f));
|
||||
spline.m_vertexContainer.AddVertex(AZ::Vector3::CreateZero());
|
||||
spline.m_vertexContainer.AddVertex(AZ::Vector3::CreateAxisX(1.0f));
|
||||
|
||||
// when (tube manipulator states are attempted to be created)
|
||||
const auto tubeManipulatorStates = LmbrCentral::GenerateTubeManipulatorStates(spline);
|
||||
|
||||
// then (three are returned)
|
||||
EXPECT_THAT(tubeManipulatorStates.size(), Eq(3));
|
||||
|
||||
EXPECT_THAT(tubeManipulatorStates[0].m_splineAddress, Eq(AZ::SplineAddress(0, 0.0f)));
|
||||
EXPECT_THAT(tubeManipulatorStates[0].m_vertIndex, Eq(0));
|
||||
|
||||
EXPECT_THAT(tubeManipulatorStates[1].m_splineAddress, Eq(AZ::SplineAddress(1, 0.0f)));
|
||||
EXPECT_THAT(tubeManipulatorStates[1].m_vertIndex, Eq(1));
|
||||
|
||||
EXPECT_THAT(tubeManipulatorStates[2].m_splineAddress, Eq(AZ::SplineAddress(1, 1.0f)));
|
||||
EXPECT_THAT(tubeManipulatorStates[2].m_vertIndex, Eq(2));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -6,12 +6,14 @@
|
||||
*/
|
||||
|
||||
#include "LmbrCentral_precompiled.h"
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <Shape/ShapeGeometryUtil.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <LmbrCentral/Shape/ShapeComponentBus.h>
|
||||
#include <Shape/ShapeGeometryUtil.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
@@ -91,4 +93,43 @@ namespace UnitTest
|
||||
|
||||
EXPECT_TRUE(triangles.size() == 18);
|
||||
}
|
||||
|
||||
// test double to record if DrawTrianglesIndexed or DrawLines are called
|
||||
class DebugShapeDebugDisplayRequests : public AzFramework::DebugDisplayRequests
|
||||
{
|
||||
public:
|
||||
void DrawTrianglesIndexed(
|
||||
[[maybe_unused]] const AZStd::vector<AZ::Vector3>& vertices,
|
||||
[[maybe_unused]] const AZStd::vector<AZ::u32>& indices,
|
||||
[[maybe_unused]] const AZ::Color& color) override
|
||||
{
|
||||
m_drawTrianglesIndexedCalled = true;
|
||||
}
|
||||
|
||||
void DrawLines([[maybe_unused]] const AZStd::vector<AZ::Vector3>& lines, [[maybe_unused]] const AZ::Color& color) override
|
||||
{
|
||||
m_drawLinesCalled = true;
|
||||
}
|
||||
|
||||
bool m_drawTrianglesIndexedCalled = false;
|
||||
bool m_drawLinesCalled = false;
|
||||
};
|
||||
|
||||
// DrawShape internally calls DrawTrianglesIndexed and DrawLines - with no geometry
|
||||
// we want to make sure the shape is not submitted to be drawn
|
||||
TEST(ShapeGeometry, Shape_not_attempted_to_be_drawn_with_no_geometry)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
|
||||
// given
|
||||
DebugShapeDebugDisplayRequests debugDisplayRequests;
|
||||
|
||||
// when
|
||||
LmbrCentral::DrawShape(
|
||||
debugDisplayRequests, LmbrCentral::ShapeDrawParams{ AZ::Colors::White, AZ::Colors::White, true }, LmbrCentral::ShapeMesh{});
|
||||
|
||||
// then
|
||||
EXPECT_THAT(debugDisplayRequests.m_drawTrianglesIndexedCalled, Eq(false));
|
||||
EXPECT_THAT(debugDisplayRequests.m_drawLinesCalled, Eq(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ set(FILES
|
||||
Tests/EditorCompoundShapeComponentTests.cpp
|
||||
Tests/EditorCylinderShapeComponentTests.cpp
|
||||
Tests/EditorPolygonPrismShapeComponentTests.cpp
|
||||
Tests/EditorTubeShapeComponentTests.cpp
|
||||
Tests/SpawnerComponentTest.cpp
|
||||
Tests/Builders/CopyDependencyBuilderTest.cpp
|
||||
Tests/Builders/SliceBuilderTests.cpp
|
||||
|
||||
+2
-1
@@ -493,7 +493,8 @@ namespace AZ::SceneGenerationComponents
|
||||
// Copy node attributes
|
||||
AZStd::apply([](const auto&&... nodePairView) {
|
||||
((AZStd::for_each(begin(nodePairView), end(nodePairView), [](const auto& nodePair) {
|
||||
auto& [originalNode, optimizedNode] = nodePair;
|
||||
auto& originalNode = nodePair.first;
|
||||
auto& optimizedNode = nodePair.second;
|
||||
optimizedNode->CloneAttributesFrom(&originalNode.get());
|
||||
})), ...);
|
||||
}, std::tuple {
|
||||
|
||||
@@ -77,6 +77,7 @@ ly_append_configurations_options(
|
||||
/Zc:forScope # Force Conformance in for Loop Scope
|
||||
/diagnostics:caret # Compiler diagnostic options: includes the column where the issue was found and places a caret (^) under the location in the line of code where the issue was detected.
|
||||
/Zc:__cplusplus
|
||||
/Zc:lambda # Use the new lambda processor (See https://developercommunity.visualstudio.com/t/A-lambda-that-binds-the-this-pointer-w/1467873 for more details)
|
||||
/favor:AMD64 # Create Code optimized for 64 bit
|
||||
/bigobj # Increase number of sections in obj files. Profiling has shown no meaningful impact in memory nore build times
|
||||
COMPILATION_DEBUG
|
||||
|
||||
Reference in New Issue
Block a user