Merge branch 'o3de:development' into rapidjson-natvis

monroegm-disable-blank-issue-2
lumberyard-employee-dm 4 years ago committed by GitHub
commit d40bfd21a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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

@ -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

@ -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

Loading…
Cancel
Save