Legacy Mesh component removal

* Removed legacy components

* More legacy render component removal

* Starting removal of legacy mesh component dependencies

* Removed old light components that were allowing Atom test to succeed

* Testing increasing the timeout to see if it lets it pass in Jenkins

* put original timeout back

* reordered components to test if it is component specific or not

* Testing disabiling the test to see if we get a green

* Fixed the removal of the test to sandbox

* Removed Legacy Mesh Component and associated tendrils

* Removed some missed references

* Fixed some issues with unity builds and ambiguous naming

* Addressed review feedback
This commit is contained in:
Terry Michaels
2021-05-03 17:17:18 -05:00
committed by GitHub
parent 13c7b06308
commit 55f2b24302
48 changed files with 981 additions and 5031 deletions
+1 -1
View File
@@ -55,7 +55,7 @@ public:
Matrix34 m_matInv;
Vec3 m_eyePosInWS;
Vec3 m_eyePosInOS;
Plane m_volumeTraceStartPlane;
Plane_tpl<f32> m_volumeTraceStartPlane;
AABB m_renderBoundsOS;
bool m_viewerInsideVolume;
bool m_nearPlaneIntersectsVolume;
+1 -1
View File
@@ -25,7 +25,7 @@ public:
virtual void mfPrepare(bool bCheckOverflow);
virtual bool mfDraw(CShader* ef, SShaderPass* sfm);
virtual void mfGetPlane(Plane& pl);
virtual void mfGetPlane(Plane_tpl<f32>& pl);
virtual void Create(uint32 nVerticesCount, SVF_P3F_C4B_T2F* pVertices, uint32 nIndicesCount, const void* pIndices, uint32 nIndexSizeof);
void ReleaseOcean();
+2 -2
View File
@@ -27,7 +27,7 @@ public:
virtual ~CREWaterVolume();
virtual void mfPrepare(bool bCheckOverflow);
virtual bool mfDraw(CShader* ef, SShaderPass* sfm);
virtual void mfGetPlane(Plane& pl);
virtual void mfGetPlane(Plane_tpl<f32>& pl);
virtual void mfCenter(Vec3& vCenter, CRenderObject* pObj);
virtual void GetMemoryUsage(ICrySizer* pSizer) const
@@ -69,7 +69,7 @@ public:
Vec3 m_center;
AABB m_WSBBox;
Plane m_fogPlane;
Plane_tpl<f32> m_fogPlane;
float m_fogDensity;
Vec3 m_fogColor;
bool m_fogColorAffectedBySun;
+9 -9
View File
@@ -594,7 +594,7 @@ public:
ILINE const Vec3& GetFPVertex(int nId) const; //get far-plane vertices
ILINE const Vec3& GetPPVertex(int nId) const; //get projection-plane vertices
ILINE const Plane* GetFrustumPlane(int numplane) const { return &m_fp[numplane]; }
ILINE const Plane_tpl<f32>* GetFrustumPlane(int numplane) const { return &m_fp[numplane]; }
//////////////////////////////////////////////////////////////////////////
// Z-Buffer ranges.
@@ -720,7 +720,7 @@ private:
Vec3 m_cltn, m_crtn, m_clbn, m_crbn; //this are the 4 vertices of the near-plane in cam-space
Vec3 m_cltf, m_crtf, m_clbf, m_crbf; //this are the 4 vertices of the farclip-plane in cam-space
Plane m_fp [FRUSTUM_PLANES]; //
Plane_tpl<f32> m_fp [FRUSTUM_PLANES]; //
uint32 m_idx1[FRUSTUM_PLANES], m_idy1[FRUSTUM_PLANES], m_idz1[FRUSTUM_PLANES]; //
uint32 m_idx2[FRUSTUM_PLANES], m_idy2[FRUSTUM_PLANES], m_idz2[FRUSTUM_PLANES]; //
@@ -742,7 +742,7 @@ public:
m_crtp = arrvVerts[2];
m_crbp = arrvVerts[3];
}
inline void SetFrustumPlane(int i, const Plane& plane)
inline void SetFrustumPlane(int i, const Plane_tpl<f32>& plane)
{
m_fp[i] = plane;
//do not break strict aliasing rules, use union instead of reinterpret_casts
@@ -1180,12 +1180,12 @@ inline void CCamera::UpdateFrustum()
//-------------------------------------------------------------------------------
//--- calculate the six frustum-planes using the frustum edges in world-space ---
//-------------------------------------------------------------------------------
m_fp[FR_PLANE_NEAR ] = Plane::CreatePlane(m_crtn + GetPosition(), m_cltn + GetPosition(), m_crbn + GetPosition());
m_fp[FR_PLANE_RIGHT ] = Plane::CreatePlane(m_crbf + GetPosition(), m_crtf + GetPosition(), GetPosition());
m_fp[FR_PLANE_LEFT ] = Plane::CreatePlane(m_cltf + GetPosition(), m_clbf + GetPosition(), GetPosition());
m_fp[FR_PLANE_TOP ] = Plane::CreatePlane(m_crtf + GetPosition(), m_cltf + GetPosition(), GetPosition());
m_fp[FR_PLANE_BOTTOM] = Plane::CreatePlane(m_clbf + GetPosition(), m_crbf + GetPosition(), GetPosition());
m_fp[FR_PLANE_FAR ] = Plane::CreatePlane(m_crtf + GetPosition(), m_crbf + GetPosition(), m_cltf + GetPosition()); //clip-plane
m_fp[FR_PLANE_NEAR ] = Plane_tpl<f32>::CreatePlane(m_crtn + GetPosition(), m_cltn + GetPosition(), m_crbn + GetPosition());
m_fp[FR_PLANE_RIGHT ] = Plane_tpl<f32>::CreatePlane(m_crbf + GetPosition(), m_crtf + GetPosition(), GetPosition());
m_fp[FR_PLANE_LEFT ] = Plane_tpl<f32>::CreatePlane(m_cltf + GetPosition(), m_clbf + GetPosition(), GetPosition());
m_fp[FR_PLANE_TOP ] = Plane_tpl<f32>::CreatePlane(m_crtf + GetPosition(), m_cltf + GetPosition(), GetPosition());
m_fp[FR_PLANE_BOTTOM] = Plane_tpl<f32>::CreatePlane(m_clbf + GetPosition(), m_crbf + GetPosition(), GetPosition());
m_fp[FR_PLANE_FAR ] = Plane_tpl<f32>::CreatePlane(m_crtf + GetPosition(), m_crbf + GetPosition(), m_cltf + GetPosition()); //clip-plane
uint32 rh = m_Matrix.IsOrthonormalRH();
if (rh == 0)
@@ -1168,17 +1168,6 @@ namespace Distance {
return fDist2;
}
// Compute both the min and max distances of a box to a plane, in the sense of the plane normal.
inline void AABB_Plane(float* pfDistMin, float* pfDistMax, const AABB& box, const Plane& pl)
{
float fDist0 = pl.DistFromPlane(box.min),
fDistX = (box.max.x - box.min.x) * pl.n.x,
fDistY = (box.max.y - box.min.y) * pl.n.y,
fDistZ = (box.max.z - box.min.z) * pl.n.z;
*pfDistMin = fDist0 + min(fDistX, 0.f) + min(fDistY, 0.f) + min(fDistZ, 0.f);
*pfDistMax = fDist0 + max(fDistX, 0.f) + max(fDistY, 0.f) + max(fDistZ, 0.f);
}
//----------------------------------------------------------------------------------
// Distance: Sphere_Triangle
//----------------------------------------------------------------------------------
+2 -2
View File
@@ -22,7 +22,7 @@
#include <Cry_Geo.h>
namespace Intersect {
inline bool Ray_Plane(const Ray& ray, const Plane& plane, Vec3& output, bool bSingleSidePlane = true)
inline bool Ray_Plane(const Ray& ray, const Plane_tpl<f32>& plane, Vec3& output, bool bSingleSidePlane = true)
{
float cosine = plane.n | ray.direction;
@@ -49,7 +49,7 @@ namespace Intersect {
return true; //intersection occurred
}
inline bool Line_Plane(const Line& line, const Plane& plane, Vec3& output, bool bSingleSidePlane = true)
inline bool Line_Plane(const Line& line, const Plane_tpl<f32>& plane, Vec3& output, bool bSingleSidePlane = true)
{
float cosine = plane.n | line.direction;
+2 -25
View File
@@ -945,29 +945,6 @@ namespace Overlap {
}
}
/*!
*
* we use the SEPARATING-AXIS-TEST for OBB/Plane overlap.
*
* Example:
* bool result=Overlap::OBB_Plane( pos,obb, plane );
*
*/
inline bool OBB_Plane(const Vec3& pos, const OBB& obb, const Plane& plane)
{
//the new center-position in world-space
Vec3 p = obb.m33 * obb.c + pos;
//extract the orientation-vectors from the columns of the 3x3 matrix
//and scale them by the half-lengths
Vec3 ax = Vec3(obb.m33.m00, obb.m33.m10, obb.m33.m20) * obb.h.x;
Vec3 ay = Vec3(obb.m33.m01, obb.m33.m11, obb.m33.m21) * obb.h.y;
Vec3 az = Vec3(obb.m33.m02, obb.m33.m12, obb.m33.m22) * obb.h.z;
//check OBB against Plane, using the plane-normal as separating axis
return fabsf(plane | p) < (fabsf(plane.n | ax) + fabsf(plane.n | ay) + fabsf(plane.n | az));
}
/*!
*
* we use the SEPARATING AXIS TEST to check if a triangle and AABB overlap.
@@ -1214,7 +1191,7 @@ namespace Overlap {
//test if the box intersects the plane of the triangle
//compute plane equation of triangle: normal*x+d=0
Plane plane = Plane::CreatePlane((e0 % e1), v0);
Plane_tpl<f32> plane = Plane_tpl<f32>::CreatePlane((e0 % e1), v0);
Vec3 vmin, vmax;
if (plane.n.x > 0.0f)
@@ -1505,7 +1482,7 @@ namespace Overlap {
//test if the box overlaps the plane of the triangle
//compute plane equation of triangle: normal*x+d=0
Plane plane = Plane::CreatePlane((e0 % e1), v0);
Plane_tpl<f32> plane = Plane_tpl<f32>::CreatePlane((e0 % e1), v0);
Vec3 vmin, vmax;
if (plane.n.x > 0.0f)
+1 -1
View File
@@ -458,7 +458,7 @@ struct SClipVolumeBlendInfo
{
static const int BlendPlaneCount = 2;
Plane blendPlanes[BlendPlaneCount];
Plane_tpl<f32> blendPlanes[BlendPlaneCount];
struct IClipVolume* blendVolumes[BlendPlaneCount];
};
@@ -731,8 +731,8 @@ struct IWaterVolumeRenderNode
virtual void SetAuxPhysParams(pe_params_area*) = 0;
virtual void CreateOcean(uint64 volumeID, /* TBD */ bool keepSerializationParams = false) = 0;
virtual void CreateArea(uint64 volumeID, const Vec3* pVertices, unsigned int numVertices, const Vec2& surfUVScale, const Plane& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
virtual void CreateRiver(uint64 volumeID, const Vec3* pVertices, unsigned int numVertices, float uTexCoordBegin, float uTexCoordEnd, const Vec2& surfUVScale, const Plane& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
virtual void CreateArea(uint64 volumeID, const Vec3* pVertices, unsigned int numVertices, const Vec2& surfUVScale, const Plane_tpl<f32>& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
virtual void CreateRiver(uint64 volumeID, const Vec3* pVertices, unsigned int numVertices, float uTexCoordBegin, float uTexCoordEnd, const Vec2& surfUVScale, const Plane_tpl<f32>& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
virtual void CreateRiver(uint64 volumeID, const AZStd::vector<AZ::Vector3>& verticies, const AZ::Transform& transform, float uTexCoordBegin, float uTexCoordEnd, const AZ::Vector2& surfUVScale, const AZ::Plane& fogPlane, bool keepSerializationParams = false, int nSID = -1) = 0;
virtual void SetAreaPhysicsArea(const Vec3* pVertices, unsigned int numVertices, bool keepSerializationParams = false) = 0;
+2 -2
View File
@@ -119,7 +119,7 @@ struct IRenderElement
virtual void mfCenter(Vec3& centr, CRenderObject* pObj) = 0;
virtual void mfGetBBox(Vec3& vMins, Vec3& vMaxs) = 0;
virtual void mfReset() = 0;
virtual void mfGetPlane(Plane& pl) = 0;
virtual void mfGetPlane(Plane_tpl<f32>& pl) = 0;
virtual void mfExport(struct SShaderSerializeContext& SC) = 0;
virtual void mfImport(struct SShaderSerializeContext& SC, uint32& offset) = 0;
virtual void mfPrecache(const SShaderItem& SH) = 0;
@@ -265,7 +265,7 @@ public:
void mfPrecache([[maybe_unused]] const SShaderItem& SH) override {}
void mfExport([[maybe_unused]] struct SShaderSerializeContext& SC) override { CryFatalError("mfExport has not been implemented for this render element type"); }
void mfImport([[maybe_unused]] struct SShaderSerializeContext& SC, [[maybe_unused]] uint32& offset) override { CryFatalError("mfImport has not been implemented for this render element type"); }
void mfGetPlane(Plane& pl) override;
void mfGetPlane(Plane_tpl<f32>& pl) override;
void* mfGetPointer([[maybe_unused]] ESrcPointer ePT, [[maybe_unused]] int* Stride, [[maybe_unused]] EParamType Type, [[maybe_unused]] ESrcPointer Dst, [[maybe_unused]] int Flags) override { return nullptr; }
uint16 mfGetFlags() override { return m_Flags; }
-3
View File
@@ -157,9 +157,6 @@ AZ_POP_DISABLE_WARNING
#include "Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h"
// LmbrCentral
#include <LmbrCentral/Rendering/MeshComponentBus.h>
// AWSNativeSDK
#include <AzToolsFramework/Undo/UndoSystem.h>
#include <AWSNativeSDKInit/AWSNativeSDKInit.h>
@@ -0,0 +1,355 @@
/*
* 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 "AttachmentComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Component/Entity.h>
#include <MathConversion.h>
#include <LmbrCentral/Rendering/MeshAsset.h>
#include <LmbrCentral/Animation/AttachmentComponentBus.h>
#include <LmbrCentral/Animation/SkeletalHierarchyRequestBus.h>
namespace AZ
{
namespace Render
{
/// Behavior Context handler for AttachmentComponentNotificationBus
class BehaviorAttachmentComponentNotificationBusHandler : public LmbrCentral::AttachmentComponentNotificationBus::Handler,
public AZ::BehaviorEBusHandler
{
public:
AZ_EBUS_BEHAVIOR_BINDER(
BehaviorAttachmentComponentNotificationBusHandler, "{636B95A0-5C7D-4EE7-8645-955665315451}", AZ::SystemAllocator,
OnAttached, OnDetached);
void OnAttached(AZ::EntityId id) override
{
Call(FN_OnAttached, id);
}
void OnDetached(AZ::EntityId id) override
{
Call(FN_OnDetached, id);
}
};
void AttachmentConfiguration::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AttachmentConfiguration>()
->Version(1)
->Field("Target ID", &AttachmentConfiguration::m_targetId)
->Field("Target Bone Name", &AttachmentConfiguration::m_targetBoneName)
->Field("Target Offset", &AttachmentConfiguration::m_targetOffset)
->Field("Attached Initially", &AttachmentConfiguration::m_attachedInitially)
->Field("Scale Source", &AttachmentConfiguration::m_scaleSource);
}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->EBus<LmbrCentral::AttachmentComponentRequestBus>("AttachmentComponentRequestBus")
->Event("Attach", &LmbrCentral::AttachmentComponentRequestBus::Events::Attach)
->Event("Detach", &LmbrCentral::AttachmentComponentRequestBus::Events::Detach)
->Event("SetAttachmentOffset", &LmbrCentral::AttachmentComponentRequestBus::Events::SetAttachmentOffset);
behaviorContext->EBus<LmbrCentral::AttachmentComponentNotificationBus>("AttachmentComponentNotificationBus")
->Handler<BehaviorAttachmentComponentNotificationBusHandler>();
}
}
void AttachmentComponent::Reflect(AZ::ReflectContext* context)
{
AttachmentConfiguration::Reflect(context);
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AttachmentComponent, AZ::Component>()->Version(1)->Field(
"Configuration", &AttachmentComponent::m_initialConfiguration);
}
}
//=========================================================================
// BoneFollower
//=========================================================================
void BoneFollower::Activate(AZ::Entity* owner, const AttachmentConfiguration& configuration, bool targetCanAnimate)
{
AZ_Assert(owner, "owner is required");
AZ_Assert(!m_ownerId.IsValid(), "BoneFollower is already Activated");
m_ownerId = owner->GetId();
m_targetCanAnimate = targetCanAnimate;
m_isUpdatingOwnerTransform = false;
m_scaleSource = configuration.m_scaleSource;
m_cachedOwnerTransform = AZ::Transform::CreateIdentity();
EBUS_EVENT_ID_RESULT(m_cachedOwnerTransform, m_ownerId, AZ::TransformBus, GetWorldTM);
if (configuration.m_attachedInitially)
{
Attach(configuration.m_targetId, configuration.m_targetBoneName.c_str(), configuration.m_targetOffset);
}
LmbrCentral::AttachmentComponentRequestBus::Handler::BusConnect(m_ownerId);
}
void BoneFollower::Deactivate()
{
AZ_Assert(m_ownerId.IsValid(), "BoneFollower was never Activated");
LmbrCentral::AttachmentComponentRequestBus::Handler::BusDisconnect();
Detach();
m_ownerId.SetInvalid();
}
AZ::EntityId BoneFollower::GetTargetEntityId()
{
return m_targetId;
}
AZ::Transform BoneFollower::GetOffset()
{
return m_targetOffset;
}
void BoneFollower::Attach(AZ::EntityId targetId, const char* targetBoneName, const AZ::Transform& offset)
{
AZ_Assert(m_ownerId.IsValid(), "BoneFollower must be Activated to use.")
// safe to try and detach, even if we weren't attached
Detach();
if (!targetId.IsValid())
{
return;
}
if (targetId == m_ownerId)
{
AZ_Error("Attachment Component", false, "AttachmentComponent cannot target itself");
return;
}
// Note: the target entity may not be activated yet. That's ok.
// When mesh is ready we are notified via MeshComponentEvents::OnModelReady
// When transform is ready we are notified via TransformNotificationBus::OnTransformChanged
m_targetId = targetId;
m_targetBoneName = targetBoneName;
m_targetOffset = offset;
BindTargetBone();
m_targetBoneTransform = AZ::Transform::Identity();
m_isTargetEntityTransformKnown = false; // target's transform may not be available yet
AZ::TransformBus::EventResult(
m_cachedOwnerTransform, m_ownerId, &AZ::TransformBus::Events::GetWorldTM); // owner query will always succeed
MeshComponentNotificationBus::Handler::BusConnect(m_targetId); // fires OnModelReady if asset is already ready
AZ::TransformNotificationBus::Handler::BusConnect(m_targetId);
if (m_targetCanAnimate)
{
// Only register for per-frame updates when target can animate
AZ::TickBus::Handler::BusConnect();
}
// update owner's transform
UpdateOwnerTransformIfNecessary();
// alert others that we've attached
LmbrCentral::AttachmentComponentNotificationBus::Event(m_targetId, &LmbrCentral::AttachmentComponentNotificationBus::Events::OnAttached, m_ownerId);
}
void BoneFollower::Detach()
{
AZ_Assert(m_ownerId.IsValid(), "BoneFollower must be Activated to use.");
if (m_targetId.IsValid())
{
// alert others that we're detaching
EBUS_EVENT_ID(m_targetId, LmbrCentral::AttachmentComponentNotificationBus, OnDetached, m_ownerId);
MeshComponentNotificationBus::Handler::BusDisconnect();
AZ::TransformNotificationBus::Handler::BusDisconnect(m_targetId);
AZ::TickBus::Handler::BusDisconnect();
m_targetId.SetInvalid();
}
}
const char* BoneFollower::GetJointName()
{
return m_targetBoneName.c_str();
}
void BoneFollower::SetAttachmentOffset(const AZ::Transform& offset)
{
AZ_Assert(m_ownerId.IsValid(), "BoneFollower must be Activated to use.");
if (m_targetId.IsValid())
{
m_targetOffset = offset;
UpdateOwnerTransformIfNecessary();
}
}
void BoneFollower::OnModelReady([[maybe_unused]] const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset, [[maybe_unused]] const AZ::Data::Instance<AZ::RPI::Model>& model)
{
// reset character values
BindTargetBone();
m_targetBoneTransform = QueryBoneTransform();
// move owner if necessary
UpdateOwnerTransformIfNecessary();
}
void BoneFollower::BindTargetBone()
{
m_targetBoneId = -1;
LmbrCentral::SkeletalHierarchyRequestBus::EventResult(
m_targetBoneId, m_targetId, &LmbrCentral::SkeletalHierarchyRequests::GetJointIndexByName, m_targetBoneName.c_str());
}
void BoneFollower::UpdateOwnerTransformIfNecessary()
{
// Can't update until target entity's transform is known
if (!m_isTargetEntityTransformKnown)
{
if (AZ::TransformBus::GetNumOfEventHandlers(m_targetId) == 0)
{
return;
}
AZ::TransformBus::EventResult(m_targetEntityTransform, m_targetId, &AZ::TransformBus::Events::GetWorldTM);
m_isTargetEntityTransformKnown = true;
}
AZ::Transform finalTransform;
if (m_scaleSource == AttachmentConfiguration::ScaleSource::WorldScale)
{
// apply offset in world-space
finalTransform = m_targetEntityTransform * m_targetBoneTransform;
finalTransform.SetScale(AZ::Vector3::CreateOne());
finalTransform *= m_targetOffset;
}
else if (m_scaleSource == AttachmentConfiguration::ScaleSource::TargetEntityScale)
{
// apply offset in target-entity-space (ignoring bone scale)
AZ::Transform boneNoScale = m_targetBoneTransform;
boneNoScale.SetScale(AZ::Vector3::CreateOne());
finalTransform = m_targetEntityTransform * boneNoScale * m_targetOffset;
}
else // AttachmentConfiguration::ScaleSource::TargetEntityScale
{
// apply offset in target-bone-space
finalTransform = m_targetEntityTransform * m_targetBoneTransform * m_targetOffset;
}
if (m_cachedOwnerTransform != finalTransform)
{
AZ_Warning(
"Attachment Component", !m_isUpdatingOwnerTransform,
"AttachmentComponent detected a cycle when updating transform, do not target child entities.");
if (!m_isUpdatingOwnerTransform)
{
m_cachedOwnerTransform = finalTransform;
m_isUpdatingOwnerTransform = true;
EBUS_EVENT_ID(m_ownerId, AZ::TransformBus, SetWorldTM, finalTransform);
m_isUpdatingOwnerTransform = false;
}
}
}
AZ::Transform BoneFollower::QueryBoneTransform() const
{
AZ::Transform boneTransform = AZ::Transform::CreateIdentity();
if (m_targetBoneId >= 0)
{
LmbrCentral::SkeletalHierarchyRequestBus::EventResult(
boneTransform, m_targetId, &LmbrCentral::SkeletalHierarchyRequests::GetJointTransformCharacterRelative, m_targetBoneId);
}
return boneTransform;
}
// fires when target's transform changes
void BoneFollower::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
{
m_targetEntityTransform = world;
m_isTargetEntityTransformKnown = true;
UpdateOwnerTransformIfNecessary();
}
void BoneFollower::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
{
m_targetBoneTransform = QueryBoneTransform();
UpdateOwnerTransformIfNecessary();
}
int BoneFollower::GetTickOrder()
{
return AZ::TICK_ATTACHMENT;
}
void BoneFollower::Reattach(bool detachFirst)
{
#ifdef AZ_ENABLE_TRACING
AZ::Entity* ownerEntity = nullptr;
AZ::Entity* targetEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(ownerEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_ownerId);
AZ::ComponentApplicationBus::BroadcastResult(targetEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_targetId);
AZ_TracePrintf(
"BoneFollower", "Reattaching entity '%s' to entity '%s'", ownerEntity ? ownerEntity->GetName().c_str() : "",
targetEntity ? targetEntity->GetName().c_str() : "");
#endif
if (m_targetId.IsValid() && detachFirst)
{
LmbrCentral::AttachmentComponentNotificationBus::Event(m_targetId, &LmbrCentral::AttachmentComponentNotificationBus::Events::OnDetached, m_ownerId);
}
if (m_targetId != m_ownerId)
{
LmbrCentral::AttachmentComponentNotificationBus::Event(m_targetId, &LmbrCentral::AttachmentComponentNotificationBus::Events::OnAttached, m_ownerId);
}
}
//=========================================================================
// AttachmentComponent
//=========================================================================
void AttachmentComponent::Activate()
{
#ifdef AZ_ENABLE_TRACING
bool isStaticTransform = false;
AZ::TransformBus::EventResult(isStaticTransform, GetEntityId(), &AZ::TransformBus::Events::IsStaticTransform);
AZ_Warning(
"Attachment Component", !isStaticTransform, "Attachment needs to move, but entity '%s' %s has a static transform.",
GetEntity()->GetName().c_str(), GetEntityId().ToString().c_str());
#endif
m_boneFollower.Activate(GetEntity(), m_initialConfiguration, true);
}
void AttachmentComponent::Deactivate()
{
m_boneFollower.Deactivate();
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,189 @@
/*
* 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 <LmbrCentral/Animation/AttachmentComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Math/Transform.h>
struct ISkeletonPose;
namespace AZ
{
namespace Render
{
/*!
* Configuration data for AttachmentComponent.
*/
struct AttachmentConfiguration
{
AZ_TYPE_INFO(AttachmentConfiguration, "{74B5DC69-DE44-4640-836A-55339E116795}");
virtual ~AttachmentConfiguration() = default;
static void Reflect(AZ::ReflectContext* context);
//! Attach to this entity.
AZ::EntityId m_targetId;
//! Attach to this bone on target entity.
AZStd::string m_targetBoneName;
//! Offset from target.
AZ::Transform m_targetOffset = AZ::Transform::Identity();
//! Whether to attach to target upon activation.
//! If false, the entity remains detached until Attach() is called.
bool m_attachedInitially = true;
//! Source from which to retrieve scale information.
enum class ScaleSource : AZ::u8
{
WorldScale, // Scaled in world space.
TargetEntityScale, // Adopt scaling of attachment target entity.
TargetBoneScale, // Adopt scaling of attachment target entity/joint.
};
ScaleSource m_scaleSource = ScaleSource::WorldScale;
};
/*
* Common functionality for game and editor attachment components.
* The BoneFollower tracks movement of the target's bone and
* updates the owning entity's TransformComponent to follow.
* This class should be a member within the attachment component
* and be activated/deactivated along with the component.
* \ref AttachmentComponent
*/
class BoneFollower
: public LmbrCentral::AttachmentComponentRequestBus::Handler
, public AZ::TransformNotificationBus::Handler
, public AZ::Render::MeshComponentNotificationBus::Handler
, public AZ::Data::AssetBus::Handler
, public AZ::TickBus::Handler
{
public:
void Activate(AZ::Entity* owner, const AttachmentConfiguration& initialConfiguration, bool targetCanAnimate);
void Deactivate();
////////////////////////////////////////////////////////////////////////
// AttachmentComponentRequests
void Reattach(bool detachFirst);
void Attach(AZ::EntityId targetId, const char* targetBoneName, const AZ::Transform& offset) override;
void Detach() override;
void SetAttachmentOffset(const AZ::Transform& offset) override;
const char* GetJointName() override;
AZ::EntityId GetTargetEntityId() override;
AZ::Transform GetOffset() override;
////////////////////////////////////////////////////////////////////////
private:
////////////////////////////////////////////////////////////////////////
// AZ::TickBus
//! Check target bone transform every frame.
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
//! Make sure target bone transform updates after animation update.
int GetTickOrder() override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// AZ::TransformNotificationBus
//! When target's transform changes
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// MeshComponentEvents
//! When target's mesh changes
void OnModelReady(const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset, const AZ::Data::Instance<AZ::RPI::Model>& model) override;
////////////////////////////////////////////////////////////////////////
void BindTargetBone();
AZ::Transform QueryBoneTransform() const;
void UpdateOwnerTransformIfNecessary();
//! Entity which which is being attached.
AZ::EntityId m_ownerId;
//! Whether to query bone position per-frame (false while in editor)
bool m_targetCanAnimate = false;
AZ::EntityId m_targetId;
AZStd::string m_targetBoneName;
AZ::Transform m_targetOffset; //!< local transform
AZ::Transform m_targetBoneTransform; //!< local transform of bone
AZ::Transform m_targetEntityTransform; //!< world transform of target
bool m_isTargetEntityTransformKnown = false;
//! Cached value, so we don't update owner's position unnecessarily.
AZ::Transform m_cachedOwnerTransform;
bool m_isUpdatingOwnerTransform = false; //!< detect infinite loops when updating owner's transform
// Cached character values to avoid repeated lookup.
// These are set by calling ResetCharacter()
int m_targetBoneId; //!< negative when bone not found
AttachmentConfiguration::ScaleSource m_scaleSource;
};
/*!
* The AttachmentComponent lets an entity stick to a particular bone on
* a target entity. This is achieved by tracking movement of the target's
* bone and updating the entity's TransformComponent accordingly.
*/
class AttachmentComponent
: public AZ::Component
{
public:
AZ_COMPONENT(AttachmentComponent, "{2D17A64A-7AC5-4C02-AC36-C5E8141FFDDF}");
friend class EditorAttachmentComponent;
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("AttachmentService", 0x5aaa7b63));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("AttachmentService", 0x5aaa7b63));
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
}
~AttachmentComponent() override = default;
private:
////////////////////////////////////////////////////////////////////////
// AZ::Component
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
//! Initial configuration for m_attachment
AttachmentConfiguration m_initialConfiguration;
//! Implements actual attachment functionality
BoneFollower m_boneFollower;
};
} // namespace Render
} // namespace AZ
@@ -0,0 +1,242 @@
/*
* 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 "EditorAttachmentComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Transform.h>
#include <LmbrCentral/Animation/SkeletalHierarchyRequestBus.h>
namespace AZ
{
namespace Render
{
void EditorAttachmentComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<EditorAttachmentComponent, EditorComponentBase>()
->Version(1)
->Field("Target ID", &EditorAttachmentComponent::m_targetId)
->Field("Target Bone Name", &EditorAttachmentComponent::m_targetBoneName)
->Field("Position Offset", &EditorAttachmentComponent::m_positionOffset)
->Field("Rotation Offset", &EditorAttachmentComponent::m_rotationOffset)
->Field("Scale Offset", &EditorAttachmentComponent::m_scaleOffset)
->Field("Attached Initially", &EditorAttachmentComponent::m_attachedInitially)
->Field("Scale Source", &EditorAttachmentComponent::m_scaleSource);
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext
->Class<EditorAttachmentComponent>(
"Attachment", "The Attachment component lets an entity attach to a bone on the skeleton of another entity")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Animation")
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Attachment.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Attachment.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(
AZ::Edit::Attributes::HelpPageURL,
"https://docs.aws.amazon.com/lumberyard/latest/userguide/component-attachment.html")
->DataElement(0, &EditorAttachmentComponent::m_targetId, "Target entity", "Attach to this entity.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetIdChanged)
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &EditorAttachmentComponent::m_targetBoneName, "Joint name",
"Attach to this joint on target entity.")
->Attribute(AZ::Edit::Attributes::StringList, &EditorAttachmentComponent::GetTargetBoneOptions)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetBoneChanged)
->DataElement(
0, &EditorAttachmentComponent::m_positionOffset, "Position offset", "Local position offset from target bone")
->Attribute(AZ::Edit::Attributes::Suffix, "m")
->Attribute(AZ::Edit::Attributes::Step, 0.01f)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetOffsetChanged)
->DataElement(
0, &EditorAttachmentComponent::m_rotationOffset, "Rotation offset", "Local rotation offset from target bone")
->Attribute(AZ::Edit::Attributes::Suffix, "deg")
->Attribute(AZ::Edit::Attributes::Step, 0.01f)
->Attribute(AZ::Edit::Attributes::Min, -AZ::RadToDeg(AZ::Constants::TwoPi))
->Attribute(AZ::Edit::Attributes::Max, AZ::RadToDeg(AZ::Constants::TwoPi))
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetOffsetChanged)
->DataElement(0, &EditorAttachmentComponent::m_scaleOffset, "Scale offset", "Local scale offset from target entity")
->Attribute(AZ::Edit::Attributes::Step, 0.1f)
->Attribute(AZ::Edit::Attributes::Min, 0.001f)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetOffsetChanged)
->DataElement(
0, &EditorAttachmentComponent::m_attachedInitially, "Attached initially",
"Whether to attach to target upon activation.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnAttachedInitiallyChanged)
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &EditorAttachmentComponent::m_scaleSource, "Scaling",
"How object scale should be determined. "
"Use world scale = Attached object is scaled in world space, Use target entity scale = Attached object adopts "
"scale of target entity., Use target bone scale = Attached object adopts scale of target entity/joint.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnScaleSourceChanged)
->EnumAttribute(AttachmentConfiguration::ScaleSource::WorldScale, "Use world scale")
->EnumAttribute(AttachmentConfiguration::ScaleSource::TargetEntityScale, "Use target entity scale")
->EnumAttribute(AttachmentConfiguration::ScaleSource::TargetBoneScale, "Use target bone scale");
}
}
}
void EditorAttachmentComponent::Activate()
{
Base::Activate();
m_boneFollower.Activate(GetEntity(), CreateAttachmentConfiguration(),
false); // Entity's don't animate in Editor
}
void EditorAttachmentComponent::Deactivate()
{
m_boneFollower.Deactivate();
Base::Deactivate();
}
void EditorAttachmentComponent::BuildGameEntity(AZ::Entity* gameEntity)
{
AttachmentComponent* component = gameEntity->CreateComponent<AttachmentComponent>();
if (component)
{
component->m_initialConfiguration = CreateAttachmentConfiguration();
}
}
AttachmentConfiguration EditorAttachmentComponent::CreateAttachmentConfiguration() const
{
AttachmentConfiguration configuration;
configuration.m_targetId = m_targetId;
configuration.m_targetBoneName = m_targetBoneName;
configuration.m_targetOffset = GetTargetOffset();
configuration.m_attachedInitially = m_attachedInitially;
configuration.m_scaleSource = m_scaleSource;
return configuration;
}
AZ::Transform EditorAttachmentComponent::GetTargetOffset() const
{
AZ::Transform offset = AZ::ConvertEulerDegreesToTransform(m_rotationOffset);
offset.SetTranslation(m_positionOffset);
offset.MultiplyByScale(m_scaleOffset);
return offset;
}
AZStd::vector<AZStd::string> EditorAttachmentComponent::GetTargetBoneOptions() const
{
AZStd::vector<AZStd::string> names;
// insert blank entry, so user may choose to bind to NO bone.
names.push_back("");
// track whether currently-set bone is found
bool currentTargetBoneFound = false;
// Get character and iterate over bones
AZ::u32 jointCount = 0;
LmbrCentral::SkeletalHierarchyRequestBus::EventResult(jointCount, m_targetId, &LmbrCentral::SkeletalHierarchyRequests::GetJointCount);
for (AZ::u32 jointIndex = 0; jointIndex < jointCount; ++jointIndex)
{
const char* name = nullptr;
LmbrCentral::SkeletalHierarchyRequestBus::EventResult(name, m_targetId, &LmbrCentral::SkeletalHierarchyRequests::GetJointNameByIndex, jointIndex);
if (name)
{
names.push_back(name);
if (!currentTargetBoneFound)
{
currentTargetBoneFound = (m_targetBoneName == names.back());
}
}
}
// If we never found currently-set bone name,
// stick it at top of list, just in case user wants to keep it anyway
if (!currentTargetBoneFound && !m_targetBoneName.empty())
{
names.insert(names.begin(), m_targetBoneName);
}
return names;
}
AZ::u32 EditorAttachmentComponent::OnTargetIdChanged()
{
// Warn about bad setups (it won't crash, but it's nice to handle this early)
if (m_targetId == GetEntityId())
{
AZ_Warning(GetEntity()->GetName().c_str(), false, "AttachmentComponent cannot target self.") m_targetId.SetInvalid();
}
// Warn about children attaching to a parent
AZ::EntityId parentOfTarget;
AZ::TransformBus::EventResult(parentOfTarget, m_targetId, &AZ::TransformBus::Events::GetParentId);
while (parentOfTarget.IsValid())
{
if (parentOfTarget == GetEntityId())
{
AZ_Warning(
GetEntity()->GetName().c_str(), parentOfTarget != GetEntityId(), "AttachmentComponent cannot target child entity");
m_targetId.SetInvalid();
break;
}
AZ::EntityId currentParentId = parentOfTarget;
parentOfTarget.SetInvalid();
AZ::TransformBus::EventResult(parentOfTarget, currentParentId, &AZ::TransformBus::Events::GetParentId);
}
AttachOrDetachAsNecessary();
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues; // refresh bone options
}
AZ::u32 EditorAttachmentComponent::OnTargetBoneChanged()
{
AttachOrDetachAsNecessary();
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 EditorAttachmentComponent::OnTargetOffsetChanged()
{
EBUS_EVENT_ID(GetEntityId(), LmbrCentral::AttachmentComponentRequestBus, SetAttachmentOffset, GetTargetOffset());
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 EditorAttachmentComponent::OnAttachedInitiallyChanged()
{
AttachOrDetachAsNecessary();
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 EditorAttachmentComponent::OnScaleSourceChanged()
{
m_boneFollower.Deactivate();
m_boneFollower.Activate(GetEntity(), CreateAttachmentConfiguration(), false);
return AZ::Edit::PropertyRefreshLevels::None;
}
void EditorAttachmentComponent::AttachOrDetachAsNecessary()
{
if (m_attachedInitially && m_targetId.IsValid())
{
EBUS_EVENT_ID(
GetEntityId(), LmbrCentral::AttachmentComponentRequestBus, Attach, m_targetId, m_targetBoneName.c_str(), GetTargetOffset());
}
else
{
EBUS_EVENT_ID(GetEntityId(), LmbrCentral::AttachmentComponentRequestBus, Detach);
}
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,104 @@
/*
* 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 <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include "AttachmentComponent.h"
namespace AZ
{
namespace Render
{
/*!
* In-editor attachment component.
* \ref AttachmentComponent
*/
class EditorAttachmentComponent
: public AzToolsFramework::Components::EditorComponentBase
{
private:
using Base = AzToolsFramework::Components::EditorComponentBase;
public:
AZ_COMPONENT(EditorAttachmentComponent, "{DA6072FD-E696-47D8-81D9-1F77D3464200}", Base);
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
AttachmentComponent::GetProvidedServices(provided);
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
AttachmentComponent::GetIncompatibleServices(incompatible);
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
AttachmentComponent::GetRequiredServices(required);
}
~EditorAttachmentComponent() override = default;
void BuildGameEntity(AZ::Entity* gameEntity) override;
protected:
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
AZ::u32 OnTargetIdChanged();
AZ::u32 OnTargetBoneChanged();
AZ::u32 OnTargetOffsetChanged();
AZ::u32 OnAttachedInitiallyChanged();
AZ::u32 OnScaleSourceChanged();
//! Invoked when an attachment property changes
void AttachOrDetachAsNecessary();
//! For populating ComboBox
AZStd::vector<AZStd::string> GetTargetBoneOptions() const;
//! Create runtime configuration from editor configuration
AttachmentConfiguration CreateAttachmentConfiguration() const;
//! Create AZ::Transform from position and rotation
AZ::Transform GetTargetOffset() const;
//! Attach to this entity.
AZ::EntityId m_targetId;
//! Attach to this bone on target entity.
AZStd::string m_targetBoneName;
//! Offset from target bone's position.
AZ::Vector3 m_positionOffset = AZ::Vector3::CreateZero();
//! Offset from target bone's rotation.
AZ::Vector3 m_rotationOffset = AZ::Vector3::CreateZero();
//! Offset from target entity's scale.
AZ::Vector3 m_scaleOffset = AZ::Vector3::CreateOne();
//! Observe scale information from the specified source.
AttachmentConfiguration::ScaleSource m_scaleSource = AttachmentConfiguration::ScaleSource::WorldScale;
//! Whether to attach to target upon activation.
//! If false, the entity remains detached until Attach() is called.
bool m_attachedInitially = true;
//! Implements actual attachment functionality
AZ::Render::BoneFollower m_boneFollower;
};
} // namespace Render
} // namespace AZ
@@ -39,6 +39,7 @@
#include <SkyBox/PhysicalSkyComponent.h>
#include <Scripting/EntityReferenceComponent.h>
#include <SurfaceData/SurfaceDataMeshComponent.h>
#include <Animation/AttachmentComponent.h>
#ifdef ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
#include <EditorCommonFeaturesSystemComponent.h>
@@ -69,6 +70,7 @@
#include <SkyBox/EditorPhysicalSkyComponent.h>
#include <Scripting/EditorEntityReferenceComponent.h>
#include <SurfaceData/EditorSurfaceDataMeshComponent.h>
#include <Animation/EditorAttachmentComponent.h>
#endif
namespace AZ
@@ -111,6 +113,7 @@ namespace AZ
DiffuseProbeGridComponent::CreateDescriptor(),
DeferredFogComponent::CreateDescriptor(),
SurfaceData::SurfaceDataMeshComponent::CreateDescriptor(),
AttachmentComponent::CreateDescriptor(),
#ifdef ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
EditorAreaLightComponent::CreateDescriptor(),
@@ -141,6 +144,7 @@ namespace AZ
EditorDiffuseProbeGridComponent::CreateDescriptor(),
EditorDeferredFogComponent::CreateDescriptor(),
SurfaceData::EditorSurfaceDataMeshComponent::CreateDescriptor(),
EditorAttachmentComponent::CreateDescriptor(),
#endif
});
}
@@ -11,6 +11,8 @@
set(FILES
Source/Module.cpp
Source/Animation/EditorAttachmentComponent.h
Source/Animation/EditorAttachmentComponent.cpp
Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h
Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h
Source/EditorCommonFeaturesSystemComponent.h
@@ -10,6 +10,8 @@
#
set(FILES
Source/Animation/AttachmentComponent.h
Source/Animation/AttachmentComponent.cpp
Source/CoreLights/AreaLightComponent.h
Source/CoreLights/AreaLightComponent.cpp
Source/CoreLights/AreaLightComponentConfig.cpp
@@ -18,7 +18,7 @@
#include <Integration/Rendering/RenderActorInstance.h>
#include <LmbrCentral/Rendering/MeshComponentBus.h>
#include <LmbrCentral/Animation/SkeletalHierarchyRequestBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
@@ -24,7 +24,6 @@
#include <AzFramework/Visibility/BoundsBus.h>
#include <LmbrCentral/Animation/AttachmentComponentBus.h>
#include <LmbrCentral/Rendering/MeshComponentBus.h>
#include <Integration/Components/ActorComponent.h>
#include <Integration/Rendering/RenderBackendManager.h>
@@ -414,9 +413,6 @@ namespace EMotionFX
CheckAttachToEntity();
// Send general mesh creation notification to interested parties.
LmbrCentral::MeshComponentNotificationBus::Event(entityId, &LmbrCentral::MeshComponentNotifications::OnMeshCreated, m_configuration.m_actorAsset);
Physics::RagdollConfiguration ragdollConfiguration;
[[maybe_unused]] bool ragdollConfigValid = GetRagdollConfiguration(ragdollConfiguration);
AZ_Assert(ragdollConfigValid, "Ragdoll Configuration is not valid");
@@ -460,11 +456,6 @@ namespace EMotionFX
m_attachmentTargetActor = nullptr;
// Send general mesh destruction notification to interested parties.
LmbrCentral::MeshComponentNotificationBus::Event(
GetEntityId(),
&LmbrCentral::MeshComponentNotifications::OnMeshDestroyed);
ActorComponentNotificationBus::Event(
GetEntityId(),
&ActorComponentNotificationBus::Events::OnActorInstanceDestroyed,
@@ -22,7 +22,7 @@
#include <Integration/Components/AnimAudioComponent.h>
#include <LmbrCentral/Audio/AudioProxyComponentBus.h>
#include <LmbrCentral/Rendering/MeshComponentBus.h> // for SkeletalHierarchyRequestBus
#include <LmbrCentral/Animation/SkeletalHierarchyRequestBus.h>
#include <MathConversion.h>
@@ -26,8 +26,6 @@
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <LmbrCentral/Rendering/MeshComponentBus.h>
#include <Integration/Editor/Components/EditorActorComponent.h>
#include <Integration/AnimGraphComponentBus.h>
#include <Integration/Rendering/RenderBackendManager.h>
@@ -255,11 +253,6 @@ namespace EMotionFX
{
if (m_actorInstance)
{
// Send general mesh destruction notification to interested parties.
LmbrCentral::MeshComponentNotificationBus::Event(
GetEntityId(),
&LmbrCentral::MeshComponentNotifications::OnMeshDestroyed);
ActorComponentNotificationBus::Event(
GetEntityId(),
&ActorComponentNotificationBus::Events::OnActorInstanceDestroyed,
@@ -848,11 +841,6 @@ namespace EMotionFX
if (m_actorInstance)
{
// Send general mesh destruction notification to interested parties.
LmbrCentral::MeshComponentNotificationBus::Event(
GetEntityId(),
&LmbrCentral::MeshComponentNotifications::OnMeshDestroyed);
ActorComponentNotificationBus::Event(
GetEntityId(),
&ActorComponentNotificationBus::Events::OnActorInstanceDestroyed,
@@ -941,9 +929,6 @@ namespace EMotionFX
{
LmbrCentral::AttachmentComponentRequestBus::Event(attachment, &LmbrCentral::AttachmentComponentRequestBus::Events::Reattach, true);
}
// Send general mesh creation notification to interested parties.
LmbrCentral::MeshComponentNotificationBus::Event(GetEntityId(), &LmbrCentral::MeshComponentNotifications::OnMeshCreated, m_actorAsset);
}
} //namespace Integration
} // namespace EMotionFX
@@ -21,7 +21,6 @@
#include <AzCore/std/sort.h>
#include <AzCore/std/string/conversions.h>
#include <LmbrCentral/Rendering/MaterialOwnerBus.h>
#include <LmbrCentral/Rendering/MeshComponentBus.h>
#include <LmbrCentral/Rendering/RenderNodeBus.h>
#include <IRenderAuxGeom.h>
#include <IViewSystem.h>
@@ -518,18 +517,6 @@ namespace ImGui
ImGui::EndChild(); // End the "Meshes in Scene" Child
}
}
// Check to make sure the Tick Bus Connection status matches the debug enabled flag
if (m_meshDebugEnabled && !AZ::TickBus::Handler::BusIsConnected())
{
// Connect to the Tick Bus
AZ::TickBus::Handler::BusConnect();
}
else if (!m_meshDebugEnabled && AZ::TickBus::Handler::BusIsConnected())
{
// Disconnect from the Tick Bus
AZ::TickBus::Handler::BusDisconnect();
}
}
// Mesh Mouse Over Helper function
@@ -597,81 +584,6 @@ namespace ImGui
instanceOptions.m_mousedOverForDraw |= ImGui::IsItemHovered();
}
void ImGuiLYAssetExplorer::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
// Search through all entities for Asset Components
OnTick_FindAssets();
// Check for all relevant pointers here. ( Actually requires checking all of these for different edge cases! :(
if (gEnv && gEnv->pRenderer && gEnv->pSystem &&
gEnv->pSystem->GetIViewSystem() && gEnv->pSystem->GetIViewSystem()->GetActiveView() &&
gEnv->pSystem->GetIViewSystem()->GetActiveView()->GetCurrentParams())
{
// Get the Camera View Position from the view system.
const Vec3& cameraPosVec3 = gEnv->pSystem->GetIViewSystem()->GetActiveView()->GetCurrentParams()->position;
const AZ::Vector3 cameraPos(cameraPosVec3.x, cameraPosVec3.y, cameraPosVec3.z);
// Loop through all Meshes to draw the appropriate ones!
for (const MeshInstanceDisplayList& meshInstanceList : m_meshInstanceDisplayList)
{
// bunch of different ways to filter results. First check for Mesh and Instance Name Filters...
bool displayMesh = true;
if (m_meshNameFilter)
{
displayMesh &= meshInstanceList.m_passesFilter;
}
if (m_entityNameFilter)
{
displayMesh &= meshInstanceList.m_childrenPassFilter;
}
// ..Mouse Overs and Selection Filters should override other filters, so do it after.. Mouse Over THEN Selection Filter for precedence.
if (m_anyMousedOverForDraw)
{
displayMesh = meshInstanceList.m_mousedOverForDraw || meshInstanceList.m_childMousedOverForDraw;
}
else if (m_selectionFilter)
{
displayMesh = meshInstanceList.m_selectedForDraw;
for (const auto& meshInstance : meshInstanceList.m_instanceOptionMap)
{
displayMesh |= meshInstance.second.m_selectedForDraw;
}
}
if (displayMesh)
{
for (const auto& meshInstance : meshInstanceList.m_instanceOptionMap)
{
AZ::Data::Asset<AZ::Data::AssetData> meshAsset;
LmbrCentral::MeshComponentRequestBus::EventResult(meshAsset, meshInstance.first, &LmbrCentral::MeshComponentRequests::GetMeshAsset);
// See if we pass name filter first..
bool displayEntity = true;
if (m_entityNameFilter)
{
displayEntity = meshInstance.second.m_passesFilter;
}
// ..Mouse Overs and Selection Filters should override other filters, so do it after.. Mouse Over THEN Selection Filter for precedence.
if (m_anyMousedOverForDraw)
{
displayEntity = meshInstance.second.m_mousedOverForDraw || meshInstanceList.m_mousedOverForDraw;
}
else if (m_selectionFilter)
{
displayEntity = meshInstance.second.m_selectedForDraw | meshInstanceList.m_selectedForDraw;
}
if (displayEntity)
{
OnTick_DrawEntity(meshInstance.first, meshAsset.GetId(), gEnv->pRenderer, cameraPos);
}
}
}
}
}
}
MeshInstanceDisplayList& ImGuiLYAssetExplorer::FindOrCreateMeshInstanceList(const char* meshName)
{
// Walk the list and see if an entry for this mesh exists already. If we find one, return it!
@@ -696,250 +608,6 @@ namespace ImGui
m_meshInstanceDisplayList.push_back(meshList);
return m_meshInstanceDisplayList.back();
}
// Scan the scene for Meshes!
void ImGuiLYAssetExplorer::OnTick_FindAssets()
{
// Retrieve Id map from game entity context (editor->runtime).
AzFramework::EntityContextId gameContextId = AzFramework::EntityContextId::CreateNull();
AzFramework::GameEntityContextRequestBus::BroadcastResult(gameContextId, &AzFramework::GameEntityContextRequests::GetGameEntityContextId);
// Get the Root Slice Component
AZ::SliceComponent* rootSliceComponent;
AzFramework::SliceEntityOwnershipServiceRequestBus::EventResult(rootSliceComponent, gameContextId,
&AzFramework::SliceEntityOwnershipServiceRequests::GetRootSlice);
if (rootSliceComponent)
{
// Get an unordered_set of all EntityIds in the slice
AZ::SliceComponent::EntityIdSet entityIds;
rootSliceComponent->GetEntityIds(entityIds);
// Loop through Mesh Map and "un-verify" them
for (MeshInstanceDisplayList& meshInstanceList : m_meshInstanceDisplayList)
{
for (auto& meshInstance : meshInstanceList.m_instanceOptionMap)
{
meshInstance.second.m_verifiedThisFrame = false;
}
}
for (auto it = entityIds.begin(); it != entityIds.end(); it++)
{
AZ::Data::Asset<AZ::Data::AssetData> meshAsset;
LmbrCentral::MeshComponentRequestBus::EventResult(meshAsset, *it, &LmbrCentral::MeshComponentRequests::GetMeshAsset);
if (meshAsset.IsReady())
{
// Get the Asset Info so we can get the mesh path
AZ::Data::AssetInfo assetInfo;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, meshAsset.GetId());
AZStd::string meshPath = assetInfo.m_relativePath;
AZStd::to_lower(meshPath.begin(), meshPath.end());
// Save off this mesh instance into the instance map
MeshInstanceDisplayList& displayList = FindOrCreateMeshInstanceList(meshPath.c_str());
if (!displayList.m_instanceOptionMap.count(*it))
{
// Get the Entity Name, for easy searching later
AZStd::string entityName;
AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, *it);
// Init the instance entry and options
MeshInstanceOptions& meshOptions = displayList.m_instanceOptionMap[*it];
meshOptions.m_verifiedThisFrame = true;
meshOptions.m_passesFilter = true;
meshOptions.m_selectedForDraw = false;
meshOptions.m_mousedOverForDraw = false;
meshOptions.m_instanceLabel = AZStd::string::format("%s%s", (*it).ToString().c_str(), entityName.c_str());
AZStd::to_lower(meshOptions.m_instanceLabel.begin(), meshOptions.m_instanceLabel.end());
}
else
{
displayList.m_instanceOptionMap[*it].m_verifiedThisFrame = true;
}
}
}
// Loop through Mesh Map again and remove any "un-verify"-ed entries!
for (auto meshInstanceListIter = m_meshInstanceDisplayList.begin(); meshInstanceListIter != m_meshInstanceDisplayList.end();)
{
for (auto meshInstanceIter = (*meshInstanceListIter).m_instanceOptionMap.begin(); meshInstanceIter != (*meshInstanceListIter).m_instanceOptionMap.end();)
{
if (!(*meshInstanceIter).second.m_verifiedThisFrame)
{
// erase this instance from the map and set the iterator correctly.
meshInstanceIter = (*meshInstanceListIter).m_instanceOptionMap.erase(meshInstanceIter);
}
else
{
// increment the iterator
meshInstanceIter++;
}
}
// Remove the Mesh Entry if there are no instances remaining
if ((*meshInstanceListIter).m_instanceOptionMap.empty())
{
meshInstanceListIter = m_meshInstanceDisplayList.erase(meshInstanceListIter);
}
else
{
// increment the iterator
meshInstanceListIter++;
}
}
}
}
// We know we want to draw this Entity/Mesh ( depending on distance from Cam ).. so draw!
void ImGuiLYAssetExplorer::OnTick_DrawEntity(const AZ::EntityId& entity, const AZ::Data::AssetId& assetId, IRenderer* renderer, const AZ::Vector3& cameraPos)
{
// Get the Entity Position so we can see how far from the camera we are.
AZ::Vector3 worldPos = AZ::Vector3::CreateZero();
AZ::TransformBus::EventResult(worldPos, entity, &AZ::TransformBus::Events::GetWorldTranslation);
// Get Our Distance From The Camera! ( Used just for draw alpha value )
float distFromCamera = m_distanceFilter_far + 1.0f; // Default to just outside camera view ( i.e. Don't draw )
if (m_anyMousedOverForDraw || m_selectionFilter || !m_distanceFilter)
{
// If we have either the Selection Filter or Mouse Over state on or the distance filter is off, and we made it this far, we are the lucky selected one! Draw ourselves by setting dist to 0.0f
distFromCamera = 0.0;
}
else if (m_distanceFilter)
{
// Distance filter is on and we aren't selected, so actually find the distance from the camera
distFromCamera = worldPos.GetDistance(cameraPos);
}
// Only draw things within view distance ( cheese it to zero above to force drawing far things )
if (distFromCamera <= m_distanceFilter_far)
{
// Find an interpolated Alpha.. 1.0f while inside near radius, interp 1.0 -> 0.0 while heading toward far radius
float alpha = (distFromCamera <= m_distanceFilter_near) ? 1.0f : (1.0f - ((distFromCamera - m_distanceFilter_near) / (m_distanceFilter_far - m_distanceFilter_near)));
// The string to hold label text we will build.
AZStd::string entityLabel;
// Grab the Asset Info to get the mesh path name.
AZ::Data::AssetInfo assetInfo;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, assetId);
// Start the label with either the EntName and Mesh, or just Mesh
if (m_inWorld_label_entityName)
{
AZ::ComponentApplicationBus::BroadcastResult(entityLabel, &AZ::ComponentApplicationBus::Events::GetEntityName, entity);
entityLabel = AZStd::string::format("Entity: %s %s\nMesh: %s", entity.ToString().c_str(), entityLabel.c_str(), assetInfo.m_relativePath.c_str());
}
else
{
entityLabel = AZStd::string::format("Mesh: %s", assetInfo.m_relativePath.c_str());
}
// See if we should add the Material!
if (m_inWorld_label_materialName)
{
_smart_ptr<IMaterial> material;
LmbrCentral::MaterialOwnerRequestBus::EventResult(material, entity, &LmbrCentral::MaterialOwnerRequests::GetMaterial);
if (material)
{
entityLabel.append(AZStd::string::format("\nMaterial: %s", material->GetName()));
}
}
// Get The Render Node for mesh debug draw and Lod Info
IRenderNode* renderNode = nullptr;
LmbrCentral::RenderNodeRequestBus::EventResult(renderNode, entity, &LmbrCentral::RenderNodeRequests::GetRenderNode);
if (renderNode != nullptr && renderNode->GetEntityStatObj())
{
// Debug Draw Mesh
if (m_inWorld_debugDrawMesh)
{
SGeometryDebugDrawInfo dd;
dd.color.Set(0.0f, 0.0f, 255.0f, 0.5f * alpha);
dd.lineColor.Set(255.0f, 0.0f, 0.0f, 0.75f * alpha);
renderNode->GetEntityStatObj()->DebugDraw(dd, 0.2f);
}
// Draw Total Lods info
if (m_inWorld_label_totalLods)
{
entityLabel.append(AZStd::string::format("\nTotal Lods: %d", renderNode->GetEntityStatObj()->GetLoadedLodsNum()));
}
// Draw Misc Lod Info
if (m_inWorld_label_miscLod)
{
entityLabel.append(AZStd::string::format("\nFirst Lod Distance: %f", renderNode->GetFirstLodDistance()));
float distances[SMeshLodInfo::s_nMaxLodCount];
renderNode->GetLodDistances(gEnv->p3DEngine->GetFrameLodInfo(), distances);
for (int i = 0; i < SMeshLodInfo::s_nMaxLodCount; i++)
{
entityLabel.append(AZStd::string::format("\n frameLod: %d - %f", i, distances[i]));
}
}
}
// Draw the label in the world
if (m_inWorld_drawLabel)
{
SDrawTextInfo ti;
ti.xscale = ti.yscale = m_inWorld_labelTextSize * alpha;
ti.flags = eDrawText_FixedSize | eDrawText_Center | eDrawText_800x600;
if (m_inWorld_label_framed)
{
ti.flags |= eDrawText_Framed;
}
if (m_inWorld_label_monoSpace)
{
ti.flags |= eDrawText_Monospace;
}
{
ti.color[0] = m_inWorld_label_textColor.Value.x;
ti.color[1] = m_inWorld_label_textColor.Value.y;
ti.color[2] = m_inWorld_label_textColor.Value.z;
ti.color[3] = alpha;
}
Vec3 labelPos(worldPos.GetX(), worldPos.GetY(), worldPos.GetZ() - m_inWorld_originSphereRadius);
renderer->DrawTextQueued(labelPos, ti, entityLabel.c_str());
}
// Draw the sphere and/or AABB in the world
if (m_inWorld_drawOriginSphere || m_inWorld_drawAABB)
{
IRenderAuxGeom* pAuxGeom = renderer->GetIRenderAuxGeom();
if (pAuxGeom)
{
const ColorF sphereColor(m_inWorld_label_textColor.Value.x, m_inWorld_label_textColor.Value.y, m_inWorld_label_textColor.Value.z, alpha);
Vec3 spherePos(worldPos.GetX(), worldPos.GetY(), worldPos.GetZ());
// draw a sample sphere
SAuxGeomRenderFlags oldFlags = pAuxGeom->GetRenderFlags();
SAuxGeomRenderFlags flags = oldFlags;
flags.SetDepthWriteFlag(e_DepthWriteOff);
flags.SetDepthTestFlag(e_DepthTestOff);
flags.SetDrawInFrontMode(e_DrawInFrontOn);
flags.SetFillMode(e_FillModeSolid);
flags.SetCullMode(e_CullModeNone);
pAuxGeom->SetRenderFlags(flags);
if ( m_inWorld_drawOriginSphere)
{
pAuxGeom->DrawSphere(spherePos, m_inWorld_originSphereRadius, sphereColor, false);
}
if (m_inWorld_drawAABB && renderNode)
{
pAuxGeom->DrawAABB(renderNode->GetBBox(), false, sphereColor, EBoundingBoxDrawStyle::eBBD_Extremes_Color_Encoded);
}
// Restore rendering state
pAuxGeom->SetRenderFlags(oldFlags);
}
}
}
}
} // namespace ImGui
} // namespace ImGui
#endif // IMGUI_ENABLED
@@ -43,7 +43,6 @@ namespace ImGui
class ImGuiLYAssetExplorer
: public ImGuiAssetExplorerRequestBus::Handler
, public AZ::TickBus::Handler
{
public:
@@ -61,10 +60,6 @@ namespace ImGui
void SetEnabled(bool enabled) override { m_enabled = enabled; m_meshDebugEnabled = enabled; }
// -- ImGuiAssetExplorerRequestBus::Handler Interface ----------------------
// -- AZ::TickBus::Handler Interface ---------------------------------------
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
// -- AZ::TickBus::Handler Interface ---------------------------------------
// Toggle the menu on and off
void ToggleEnabled() { m_enabled = !m_enabled; }
@@ -117,9 +112,6 @@ namespace ImGui
void ImGuiUpdate_DrawMeshMouseOver(MeshInstanceDisplayList& meshDisplayList);
void ImGuiUpdate_DrawEntityInstanceMouseOver(MeshInstanceDisplayList& meshDisplayList, AZ::EntityId& entityInstance, AZStd::string& entityName, MeshInstanceOptions& instanceOptions);
// Helper functions for the OnTick callback
void OnTick_DrawEntity(const AZ::EntityId& entity, const AZ::Data::AssetId& assetId, IRenderer* renderer, const AZ::Vector3& cameraPos);
void OnTick_FindAssets();
};
}
#endif // IMGUI_ENABLED
@@ -1,349 +0,0 @@
/*
* 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 "LmbrCentral_precompiled.h"
#include "AttachmentComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Component/Entity.h>
#include <MathConversion.h>
#include <LmbrCentral/Rendering/MeshAsset.h>
#include <LmbrCentral/Animation/AttachmentComponentBus.h>
namespace LmbrCentral
{
/// Behavior Context handler for AttachmentComponentNotificationBus
class BehaviorAttachmentComponentNotificationBusHandler : public AttachmentComponentNotificationBus::Handler, public AZ::BehaviorEBusHandler
{
public:
AZ_EBUS_BEHAVIOR_BINDER(BehaviorAttachmentComponentNotificationBusHandler, "{636B95A0-5C7D-4EE7-8645-955665315451}", AZ::SystemAllocator
, OnAttached, OnDetached);
void OnAttached(AZ::EntityId id) override
{
Call(FN_OnAttached, id);
}
void OnDetached(AZ::EntityId id) override
{
Call(FN_OnDetached, id);
}
};
void AttachmentConfiguration::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AttachmentConfiguration>()
->Version(1)
->Field("Target ID", &AttachmentConfiguration::m_targetId)
->Field("Target Bone Name", &AttachmentConfiguration::m_targetBoneName)
->Field("Target Offset", &AttachmentConfiguration::m_targetOffset)
->Field("Attached Initially", &AttachmentConfiguration::m_attachedInitially)
->Field("Scale Source", &AttachmentConfiguration::m_scaleSource)
;
}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->EBus<AttachmentComponentRequestBus>("AttachmentComponentRequestBus")
->Event("Attach", &AttachmentComponentRequestBus::Events::Attach)
->Event("Detach", &AttachmentComponentRequestBus::Events::Detach)
->Event("SetAttachmentOffset", &AttachmentComponentRequestBus::Events::SetAttachmentOffset);
behaviorContext->EBus<AttachmentComponentNotificationBus>("AttachmentComponentNotificationBus")
->Handler<BehaviorAttachmentComponentNotificationBusHandler>();
}
}
void AttachmentComponent::Reflect(AZ::ReflectContext* context)
{
AttachmentConfiguration::Reflect(context);
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AttachmentComponent, AZ::Component>()
->Version(1)
->Field("Configuration", &AttachmentComponent::m_initialConfiguration)
;
}
}
//=========================================================================
// BoneFollower
//=========================================================================
void BoneFollower::Activate(AZ::Entity* owner, const AttachmentConfiguration& configuration, bool targetCanAnimate)
{
AZ_Assert(owner, "owner is required");
AZ_Assert(!m_ownerId.IsValid(), "BoneFollower is already Activated");
m_ownerId = owner->GetId();
m_targetCanAnimate = targetCanAnimate;
m_isUpdatingOwnerTransform = false;
m_scaleSource = configuration.m_scaleSource;
m_cachedOwnerTransform = AZ::Transform::CreateIdentity();
EBUS_EVENT_ID_RESULT(m_cachedOwnerTransform, m_ownerId, AZ::TransformBus, GetWorldTM);
if (configuration.m_attachedInitially)
{
Attach(configuration.m_targetId, configuration.m_targetBoneName.c_str(), configuration.m_targetOffset);
}
AttachmentComponentRequestBus::Handler::BusConnect(m_ownerId);
}
void BoneFollower::Deactivate()
{
AZ_Assert(m_ownerId.IsValid(), "BoneFollower was never Activated");
AttachmentComponentRequestBus::Handler::BusDisconnect();
Detach();
m_ownerId.SetInvalid();
}
AZ::EntityId BoneFollower::GetTargetEntityId()
{
return m_targetId;
}
AZ::Transform BoneFollower::GetOffset()
{
return m_targetOffset;
}
void BoneFollower::Attach(AZ::EntityId targetId, const char* targetBoneName, const AZ::Transform& offset)
{
AZ_Assert(m_ownerId.IsValid(), "BoneFollower must be Activated to use.")
// safe to try and detach, even if we weren't attached
Detach();
if (!targetId.IsValid())
{
return;
}
if (targetId == m_ownerId)
{
AZ_Error("Attachment Component", false, "AttachmentComponent cannot target itself");
return;
}
// Note: the target entity may not be activated yet. That's ok.
// When mesh is ready we are notified via MeshComponentEvents::OnMeshCreated
// When transform is ready we are notified via TransformNotificationBus::OnTransformChanged
m_targetId = targetId;
m_targetBoneName = targetBoneName;
m_targetOffset = offset;
BindTargetBone();
m_targetBoneTransform = AZ::Transform::Identity();
m_isTargetEntityTransformKnown = false; // target's transform may not be available yet
AZ::TransformBus::EventResult(m_cachedOwnerTransform, m_ownerId, &AZ::TransformBus::Events::GetWorldTM); // owner query will always succeed
MeshComponentNotificationBus::Handler::BusConnect(m_targetId); // fires OnMeshCreated if asset is already ready
AZ::TransformNotificationBus::Handler::BusConnect(m_targetId);
if (m_targetCanAnimate)
{
// Only register for per-frame updates when target can animate
AZ::TickBus::Handler::BusConnect();
}
// update owner's transform
UpdateOwnerTransformIfNecessary();
// alert others that we've attached
AttachmentComponentNotificationBus::Event(m_targetId, &AttachmentComponentNotificationBus::Events::OnAttached, m_ownerId);
}
void BoneFollower::Detach()
{
AZ_Assert(m_ownerId.IsValid(), "BoneFollower must be Activated to use.");
if (m_targetId.IsValid())
{
// alert others that we're detaching
EBUS_EVENT_ID(m_targetId, AttachmentComponentNotificationBus, OnDetached, m_ownerId);
MeshComponentNotificationBus::Handler::BusDisconnect();
AZ::TransformNotificationBus::Handler::BusDisconnect(m_targetId);
AZ::TickBus::Handler::BusDisconnect();
m_targetId.SetInvalid();
}
}
const char* BoneFollower::GetJointName()
{
return m_targetBoneName.c_str();
}
void BoneFollower::SetAttachmentOffset(const AZ::Transform& offset)
{
AZ_Assert(m_ownerId.IsValid(), "BoneFollower must be Activated to use.");
if (m_targetId.IsValid())
{
m_targetOffset = offset;
UpdateOwnerTransformIfNecessary();
}
}
void BoneFollower::OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset)
{
(void)asset;
// reset character values
BindTargetBone();
m_targetBoneTransform = QueryBoneTransform();
// move owner if necessary
UpdateOwnerTransformIfNecessary();
}
void BoneFollower::BindTargetBone()
{
m_targetBoneId = -1;
SkeletalHierarchyRequestBus::EventResult(m_targetBoneId, m_targetId, &SkeletalHierarchyRequests::GetJointIndexByName, m_targetBoneName.c_str());
}
void BoneFollower::UpdateOwnerTransformIfNecessary()
{
// Can't update until target entity's transform is known
if (!m_isTargetEntityTransformKnown)
{
if (AZ::TransformBus::GetNumOfEventHandlers(m_targetId) == 0)
{
return;
}
AZ::TransformBus::EventResult(m_targetEntityTransform, m_targetId, &AZ::TransformBus::Events::GetWorldTM);
m_isTargetEntityTransformKnown = true;
}
AZ::Transform finalTransform;
if (m_scaleSource == AttachmentConfiguration::ScaleSource::WorldScale)
{
// apply offset in world-space
finalTransform = m_targetEntityTransform * m_targetBoneTransform;
finalTransform.SetScale(AZ::Vector3::CreateOne());
finalTransform *= m_targetOffset;
}
else if (m_scaleSource == AttachmentConfiguration::ScaleSource::TargetEntityScale)
{
// apply offset in target-entity-space (ignoring bone scale)
AZ::Transform boneNoScale = m_targetBoneTransform;
boneNoScale.SetScale(AZ::Vector3::CreateOne());
finalTransform = m_targetEntityTransform * boneNoScale * m_targetOffset;
}
else // AttachmentConfiguration::ScaleSource::TargetEntityScale
{
// apply offset in target-bone-space
finalTransform = m_targetEntityTransform * m_targetBoneTransform * m_targetOffset;
}
if (m_cachedOwnerTransform != finalTransform)
{
AZ_Warning("Attachment Component", !m_isUpdatingOwnerTransform, "AttachmentComponent detected a cycle when updating transform, do not target child entities.");
if (!m_isUpdatingOwnerTransform)
{
m_cachedOwnerTransform = finalTransform;
m_isUpdatingOwnerTransform = true;
EBUS_EVENT_ID(m_ownerId, AZ::TransformBus, SetWorldTM, finalTransform);
m_isUpdatingOwnerTransform = false;
}
}
}
AZ::Transform BoneFollower::QueryBoneTransform() const
{
AZ::Transform boneTransform = AZ::Transform::CreateIdentity();
if (m_targetBoneId >= 0)
{
SkeletalHierarchyRequestBus::EventResult(boneTransform, m_targetId, &SkeletalHierarchyRequests::GetJointTransformCharacterRelative, m_targetBoneId);
}
return boneTransform;
}
// fires when target's transform changes
void BoneFollower::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
{
m_targetEntityTransform = world;
m_isTargetEntityTransformKnown = true;
UpdateOwnerTransformIfNecessary();
}
void BoneFollower::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
{
m_targetBoneTransform = QueryBoneTransform();
UpdateOwnerTransformIfNecessary();
}
int BoneFollower::GetTickOrder()
{
return AZ::TICK_ATTACHMENT;
}
void BoneFollower::Reattach(bool detachFirst)
{
#ifdef AZ_ENABLE_TRACING
AZ::Entity* ownerEntity = nullptr;
AZ::Entity* targetEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(ownerEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_ownerId);
AZ::ComponentApplicationBus::BroadcastResult(targetEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_targetId);
AZ_TracePrintf("BoneFollower", "Reattaching entity '%s' to entity '%s'", ownerEntity ? ownerEntity->GetName().c_str() : "",
targetEntity ? targetEntity->GetName().c_str() : "");
#endif
if (m_targetId.IsValid() && detachFirst)
{
AttachmentComponentNotificationBus::Event(m_targetId, &AttachmentComponentNotificationBus::Events::OnDetached, m_ownerId);
}
if (m_targetId != m_ownerId)
{
AttachmentComponentNotificationBus::Event(m_targetId, &AttachmentComponentNotificationBus::Events::OnAttached, m_ownerId);
}
}
//=========================================================================
// AttachmentComponent
//=========================================================================
void AttachmentComponent::Activate()
{
#ifdef AZ_ENABLE_TRACING
bool isStaticTransform = false;
AZ::TransformBus::EventResult(isStaticTransform, GetEntityId(), &AZ::TransformBus::Events::IsStaticTransform);
AZ_Warning("Attachment Component", !isStaticTransform,
"Attachment needs to move, but entity '%s' %s has a static transform.", GetEntity()->GetName().c_str(), GetEntityId().ToString().c_str());
#endif
m_boneFollower.Activate(GetEntity(), m_initialConfiguration, true);
}
void AttachmentComponent::Deactivate()
{
m_boneFollower.Deactivate();
}
} // namespace LmbrCentral
@@ -1,186 +0,0 @@
/*
* 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 <LmbrCentral/Animation/AttachmentComponentBus.h>
#include <LmbrCentral/Rendering/MeshComponentBus.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Math/Transform.h>
struct ISkeletonPose;
namespace LmbrCentral
{
/*!
* Configuration data for AttachmentComponent.
*/
struct AttachmentConfiguration
{
AZ_TYPE_INFO(AttachmentConfiguration, "{74B5DC69-DE44-4640-836A-55339E116795}");
virtual ~AttachmentConfiguration() = default;
static void Reflect(AZ::ReflectContext* context);
//! Attach to this entity.
AZ::EntityId m_targetId;
//! Attach to this bone on target entity.
AZStd::string m_targetBoneName;
//! Offset from target.
AZ::Transform m_targetOffset = AZ::Transform::Identity();
//! Whether to attach to target upon activation.
//! If false, the entity remains detached until Attach() is called.
bool m_attachedInitially = true;
//! Source from which to retrieve scale information.
enum class ScaleSource : AZ::u8
{
WorldScale, // Scaled in world space.
TargetEntityScale, // Adopt scaling of attachment target entity.
TargetBoneScale, // Adopt scaling of attachment target entity/joint.
};
ScaleSource m_scaleSource = ScaleSource::WorldScale;
};
/*
* Common functionality for game and editor attachment components.
* The BoneFollower tracks movement of the target's bone and
* updates the owning entity's TransformComponent to follow.
* This class should be a member within the attachment component
* and be activated/deactivated along with the component.
* \ref AttachmentComponent
*/
class BoneFollower
: public AttachmentComponentRequestBus::Handler
, public AZ::TransformNotificationBus::Handler
, public MeshComponentNotificationBus::Handler
, public AZ::Data::AssetBus::Handler
, public AZ::TickBus::Handler
{
public:
void Activate(AZ::Entity* owner, const AttachmentConfiguration& initialConfiguration, bool targetCanAnimate);
void Deactivate();
////////////////////////////////////////////////////////////////////////
// AttachmentComponentRequests
void Reattach(bool detachFirst);
void Attach(AZ::EntityId targetId, const char* targetBoneName, const AZ::Transform& offset) override;
void Detach() override;
void SetAttachmentOffset(const AZ::Transform& offset) override;
const char* GetJointName() override;
AZ::EntityId GetTargetEntityId() override;
AZ::Transform GetOffset() override;
////////////////////////////////////////////////////////////////////////
private:
////////////////////////////////////////////////////////////////////////
// AZ::TickBus
//! Check target bone transform every frame.
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
//! Make sure target bone transform updates after animation update.
int GetTickOrder() override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// AZ::TransformNotificationBus
//! When target's transform changes
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// MeshComponentEvents
//! When target's mesh changes
void OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset) override;
////////////////////////////////////////////////////////////////////////
void BindTargetBone();
AZ::Transform QueryBoneTransform() const;
void UpdateOwnerTransformIfNecessary();
//! Entity which which is being attached.
AZ::EntityId m_ownerId;
//! Whether to query bone position per-frame (false while in editor)
bool m_targetCanAnimate = false;
AZ::EntityId m_targetId;
AZStd::string m_targetBoneName;
AZ::Transform m_targetOffset; //!< local transform
AZ::Transform m_targetBoneTransform; //!< local transform of bone
AZ::Transform m_targetEntityTransform; //!< world transform of target
bool m_isTargetEntityTransformKnown = false;
//! Cached value, so we don't update owner's position unnecessarily.
AZ::Transform m_cachedOwnerTransform;
bool m_isUpdatingOwnerTransform = false; //!< detect infinite loops when updating owner's transform
// Cached character values to avoid repeated lookup.
// These are set by calling ResetCharacter()
int m_targetBoneId; //!< negative when bone not found
AttachmentConfiguration::ScaleSource m_scaleSource;
};
/*!
* The AttachmentComponent lets an entity stick to a particular bone on
* a target entity. This is achieved by tracking movement of the target's
* bone and updating the entity's TransformComponent accordingly.
*/
class AttachmentComponent
: public AZ::Component
{
public:
AZ_COMPONENT(AttachmentComponent, "{2D17A64A-7AC5-4C02-AC36-C5E8141FFDDF}");
friend class EditorAttachmentComponent;
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("AttachmentService", 0x5aaa7b63));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("AttachmentService", 0x5aaa7b63));
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
}
~AttachmentComponent() override = default;
private:
////////////////////////////////////////////////////////////////////////
// AZ::Component
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
//! Initial configuration for m_attachment
AttachmentConfiguration m_initialConfiguration;
//! Implements actual attachment functionality
BoneFollower m_boneFollower;
};
} // namespace LmbrCentral
@@ -1,238 +0,0 @@
/*
* 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 "LmbrCentral_precompiled.h"
#include "EditorAttachmentComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Transform.h>
namespace LmbrCentral
{
void EditorAttachmentComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<EditorAttachmentComponent, EditorComponentBase>()
->Version(1)
->Field("Target ID", &EditorAttachmentComponent::m_targetId)
->Field("Target Bone Name", &EditorAttachmentComponent::m_targetBoneName)
->Field("Position Offset", &EditorAttachmentComponent::m_positionOffset)
->Field("Rotation Offset", &EditorAttachmentComponent::m_rotationOffset)
->Field("Scale Offset", &EditorAttachmentComponent::m_scaleOffset)
->Field("Attached Initially", &EditorAttachmentComponent::m_attachedInitially)
->Field("Scale Source", &EditorAttachmentComponent::m_scaleSource)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<EditorAttachmentComponent>(
"Attachment", "The Attachment component lets an entity attach to a bone on the skeleton of another entity")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Animation")
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Attachment.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Attachment.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://docs.aws.amazon.com/lumberyard/latest/userguide/component-attachment.html")
->DataElement(0, &EditorAttachmentComponent::m_targetId,
"Target entity", "Attach to this entity.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetIdChanged)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorAttachmentComponent::m_targetBoneName,
"Joint name", "Attach to this joint on target entity.")
->Attribute(AZ::Edit::Attributes::StringList, &EditorAttachmentComponent::GetTargetBoneOptions)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetBoneChanged)
->DataElement(0, &EditorAttachmentComponent::m_positionOffset,
"Position offset", "Local position offset from target bone")
->Attribute(AZ::Edit::Attributes::Suffix, "m")
->Attribute(AZ::Edit::Attributes::Step, 0.01f)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetOffsetChanged)
->DataElement(0, &EditorAttachmentComponent::m_rotationOffset,
"Rotation offset", "Local rotation offset from target bone")
->Attribute(AZ::Edit::Attributes::Suffix, "deg")
->Attribute(AZ::Edit::Attributes::Step, 0.01f)
->Attribute(AZ::Edit::Attributes::Min, -AZ::RadToDeg(AZ::Constants::TwoPi))
->Attribute(AZ::Edit::Attributes::Max, AZ::RadToDeg(AZ::Constants::TwoPi))
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetOffsetChanged)
->DataElement(0, &EditorAttachmentComponent::m_scaleOffset,
"Scale offset", "Local scale offset from target entity")
->Attribute(AZ::Edit::Attributes::Step, 0.1f)
->Attribute(AZ::Edit::Attributes::Min, 0.001f)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnTargetOffsetChanged)
->DataElement(0, &EditorAttachmentComponent::m_attachedInitially,
"Attached initially", "Whether to attach to target upon activation.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnAttachedInitiallyChanged)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorAttachmentComponent::m_scaleSource,
"Scaling", "How object scale should be determined. "
"Use world scale = Attached object is scaled in world space, Use target entity scale = Attached object adopts scale of target entity., Use target bone scale = Attached object adopts scale of target entity/joint.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAttachmentComponent::OnScaleSourceChanged)
->EnumAttribute(AttachmentConfiguration::ScaleSource::WorldScale, "Use world scale")
->EnumAttribute(AttachmentConfiguration::ScaleSource::TargetEntityScale, "Use target entity scale")
->EnumAttribute(AttachmentConfiguration::ScaleSource::TargetBoneScale, "Use target bone scale")
;
}
}
}
void EditorAttachmentComponent::Activate()
{
Base::Activate();
m_boneFollower.Activate(GetEntity(),
CreateAttachmentConfiguration(),
false); // Entity's don't animate in Editor
}
void EditorAttachmentComponent::Deactivate()
{
m_boneFollower.Deactivate();
Base::Deactivate();
}
void EditorAttachmentComponent::BuildGameEntity(AZ::Entity* gameEntity)
{
AttachmentComponent* component = gameEntity->CreateComponent<AttachmentComponent>();
if (component)
{
component->m_initialConfiguration = CreateAttachmentConfiguration();
}
}
AttachmentConfiguration EditorAttachmentComponent::CreateAttachmentConfiguration() const
{
AttachmentConfiguration configuration;
configuration.m_targetId = m_targetId;
configuration.m_targetBoneName = m_targetBoneName;
configuration.m_targetOffset = GetTargetOffset();
configuration.m_attachedInitially = m_attachedInitially;
configuration.m_scaleSource = m_scaleSource;
return configuration;
}
AZ::Transform EditorAttachmentComponent::GetTargetOffset() const
{
AZ::Transform offset = AZ::ConvertEulerDegreesToTransform(m_rotationOffset);
offset.SetTranslation(m_positionOffset);
offset.MultiplyByScale(m_scaleOffset);
return offset;
}
AZStd::vector<AZStd::string> EditorAttachmentComponent::GetTargetBoneOptions() const
{
AZStd::vector<AZStd::string> names;
// insert blank entry, so user may choose to bind to NO bone.
names.push_back("");
// track whether currently-set bone is found
bool currentTargetBoneFound = false;
// Get character and iterate over bones
AZ::u32 jointCount = 0;
SkeletalHierarchyRequestBus::EventResult(jointCount, m_targetId, &SkeletalHierarchyRequests::GetJointCount);
for (AZ::u32 jointIndex = 0; jointIndex < jointCount; ++jointIndex)
{
const char* name = nullptr;
SkeletalHierarchyRequestBus::EventResult(name, m_targetId, &SkeletalHierarchyRequests::GetJointNameByIndex, jointIndex);
if (name)
{
names.push_back(name);
if (!currentTargetBoneFound)
{
currentTargetBoneFound = (m_targetBoneName == names.back());
}
}
}
// If we never found currently-set bone name,
// stick it at top of list, just in case user wants to keep it anyway
if (!currentTargetBoneFound && !m_targetBoneName.empty())
{
names.insert(names.begin(), m_targetBoneName);
}
return names;
}
AZ::u32 EditorAttachmentComponent::OnTargetIdChanged()
{
// Warn about bad setups (it won't crash, but it's nice to handle this early)
if (m_targetId == GetEntityId())
{
AZ_Warning(GetEntity()->GetName().c_str(), false, "AttachmentComponent cannot target self.")
m_targetId.SetInvalid();
}
// Warn about children attaching to a parent
AZ::EntityId parentOfTarget;
AZ::TransformBus::EventResult(parentOfTarget, m_targetId, &AZ::TransformBus::Events::GetParentId);
while (parentOfTarget.IsValid())
{
if (parentOfTarget == GetEntityId())
{
AZ_Warning(GetEntity()->GetName().c_str(), parentOfTarget != GetEntityId(), "AttachmentComponent cannot target child entity");
m_targetId.SetInvalid();
break;
}
AZ::EntityId currentParentId = parentOfTarget;
parentOfTarget.SetInvalid();
AZ::TransformBus::EventResult(parentOfTarget, currentParentId, &AZ::TransformBus::Events::GetParentId);
}
AttachOrDetachAsNecessary();
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues; // refresh bone options
}
AZ::u32 EditorAttachmentComponent::OnTargetBoneChanged()
{
AttachOrDetachAsNecessary();
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 EditorAttachmentComponent::OnTargetOffsetChanged()
{
EBUS_EVENT_ID(GetEntityId(), AttachmentComponentRequestBus, SetAttachmentOffset, GetTargetOffset());
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 EditorAttachmentComponent::OnAttachedInitiallyChanged()
{
AttachOrDetachAsNecessary();
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 EditorAttachmentComponent::OnScaleSourceChanged()
{
m_boneFollower.Deactivate();
m_boneFollower.Activate(GetEntity(),
CreateAttachmentConfiguration(),
false);
return AZ::Edit::PropertyRefreshLevels::None;
}
void EditorAttachmentComponent::AttachOrDetachAsNecessary()
{
if (m_attachedInitially && m_targetId.IsValid())
{
EBUS_EVENT_ID(GetEntityId(), AttachmentComponentRequestBus, Attach, m_targetId, m_targetBoneName.c_str(), GetTargetOffset());
}
else
{
EBUS_EVENT_ID(GetEntityId(), AttachmentComponentRequestBus, Detach);
}
}
} // namespace LmbrCentral
@@ -1,101 +0,0 @@
/*
* 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 <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include "AttachmentComponent.h"
namespace LmbrCentral
{
/*!
* In-editor attachment component.
* \ref AttachmentComponent
*/
class EditorAttachmentComponent
: public AzToolsFramework::Components::EditorComponentBase
{
private:
using Base = AzToolsFramework::Components::EditorComponentBase;
public:
AZ_COMPONENT(EditorAttachmentComponent, "{DA6072FD-E696-47D8-81D9-1F77D3464200}", Base);
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
AttachmentComponent::GetProvidedServices(provided);
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
AttachmentComponent::GetIncompatibleServices(incompatible);
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
AttachmentComponent::GetRequiredServices(required);
}
~EditorAttachmentComponent() override = default;
void BuildGameEntity(AZ::Entity* gameEntity) override;
protected:
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
AZ::u32 OnTargetIdChanged();
AZ::u32 OnTargetBoneChanged();
AZ::u32 OnTargetOffsetChanged();
AZ::u32 OnAttachedInitiallyChanged();
AZ::u32 OnScaleSourceChanged();
//! Invoked when an attachment property changes
void AttachOrDetachAsNecessary();
//! For populating ComboBox
AZStd::vector<AZStd::string> GetTargetBoneOptions() const;
//! Create runtime configuration from editor configuration
AttachmentConfiguration CreateAttachmentConfiguration() const;
//! Create AZ::Transform from position and rotation
AZ::Transform GetTargetOffset() const;
//! Attach to this entity.
AZ::EntityId m_targetId;
//! Attach to this bone on target entity.
AZStd::string m_targetBoneName;
//! Offset from target bone's position.
AZ::Vector3 m_positionOffset = AZ::Vector3::CreateZero();
//! Offset from target bone's rotation.
AZ::Vector3 m_rotationOffset = AZ::Vector3::CreateZero();
//! Offset from target entity's scale.
AZ::Vector3 m_scaleOffset = AZ::Vector3::CreateOne();
//! Observe scale information from the specified source.
AttachmentConfiguration::ScaleSource m_scaleSource = AttachmentConfiguration::ScaleSource::WorldScale;
//! Whether to attach to target upon activation.
//! If false, the entity remains detached until Attach() is called.
bool m_attachedInitially = true;
//! Implements actual attachment functionality
LmbrCentral::BoneFollower m_boneFollower;
};
} // namespace LmbrCentral
@@ -21,7 +21,6 @@
#include <AzFramework/Metrics/MetricsPlainTextNameRegistration.h>
// Component descriptors
#include "Animation/AttachmentComponent.h"
#include "Audio/AudioAreaEnvironmentComponent.h"
#include "Audio/AudioEnvironmentComponent.h"
#include "Audio/AudioListenerComponent.h"
@@ -33,7 +32,6 @@
#include "Audio/AudioSystemComponent.h"
#include "Audio/AudioTriggerComponent.h"
#include "Bundling/BundlingSystemComponent.h"
#include "Rendering/MeshComponent.h"
#include "Ai/NavigationComponent.h"
#include "Scripting/TagComponent.h"
#include "Scripting/SimpleStateComponent.h"
@@ -74,9 +72,6 @@
#include <LmbrCentral/Rendering/MeshAsset.h>
#include <LmbrCentral/Rendering/MaterialHandle.h>
// Asset handlers
#include <Rendering/MeshAssetHandler.h>
// Scriptable Ebus Registration
#include "Events/ReflectScriptableEvents.h"
@@ -194,7 +189,6 @@ namespace LmbrCentral
: AZ::Module()
{
m_descriptors.insert(m_descriptors.end(), {
AttachmentComponent::CreateDescriptor(),
AudioAreaEnvironmentComponent::CreateDescriptor(),
AudioEnvironmentComponent::CreateDescriptor(),
AudioListenerComponent::CreateDescriptor(),
@@ -209,7 +203,6 @@ namespace LmbrCentral
LmbrCentralAllocatorComponent::CreateDescriptor(),
LmbrCentralAssetBuilderAllocatorComponent::CreateDescriptor(),
LmbrCentralSystemComponent::CreateDescriptor(),
MeshComponent::CreateDescriptor(),
NavigationComponent::CreateDescriptor(),
SimpleStateComponent::CreateDescriptor(),
SpawnerComponent::CreateDescriptor(),
@@ -329,13 +322,6 @@ namespace LmbrCentral
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
;
}
MaterialHandle::Reflect(serializeContext);
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
MaterialHandle::Reflect(behaviorContext);
}
ReflectScriptableEvents::Reflect(context);
@@ -379,10 +365,6 @@ namespace LmbrCentral
// Register asset handlers. Requires "AssetDatabaseService"
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!");
auto meshAssetHandler = aznew MeshAssetHandler();
meshAssetHandler->Register(); // registers self with AssetManager
m_assetHandlers.emplace_back(meshAssetHandler);
// Add asset types and extensions to AssetCatalog. Uses "AssetCatalogService".
auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler();
if (assetCatalog)
@@ -518,8 +500,6 @@ namespace LmbrCentral
gEnv = system.GetGlobalEnvironment();
#endif
REGISTER_INT(s_meshAssetHandler_AsyncCvar, 1, 0, "Enables asynchronous loading of legacy mesh formats");
// Enable catalog now that application's asset root is set.
if (system.GetGlobalEnvironment()->IsEditor())
{
@@ -536,11 +516,6 @@ namespace LmbrCentral
void LmbrCentralSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system)
{
if (gEnv->pConsole)
{
gEnv->pConsole->UnregisterVariable(s_meshAssetHandler_AsyncCvar, true);
}
EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, StopMonitoringAssets);
#if !defined(AZ_MONOLITHIC_BUILD)
@@ -16,7 +16,6 @@
#include "Ai/EditorNavigationAreaComponent.h"
#include "Ai/EditorNavigationSeedComponent.h"
#include "Animation/EditorAttachmentComponent.h"
#include "Audio/EditorAudioAreaEnvironmentComponent.h"
#include "Audio/EditorAudioEnvironmentComponent.h"
#include "Audio/EditorAudioListenerComponent.h"
@@ -25,7 +24,6 @@
#include "Audio/EditorAudioRtpcComponent.h"
#include "Audio/EditorAudioSwitchComponent.h"
#include "Audio/EditorAudioTriggerComponent.h"
#include "Rendering/EditorMeshComponent.h"
#include "Scripting/EditorLookAtComponent.h"
#include "Scripting/EditorRandomTimedSpawnerComponent.h"
#include "Scripting/EditorSpawnerComponent.h"
@@ -61,7 +59,6 @@ namespace LmbrCentral
: LmbrCentralModule()
{
m_descriptors.insert(m_descriptors.end(), {
EditorAttachmentComponent::CreateDescriptor(),
EditorAudioAreaEnvironmentComponent::CreateDescriptor(),
EditorAudioEnvironmentComponent::CreateDescriptor(),
EditorAudioListenerComponent::CreateDescriptor(),
@@ -70,7 +67,6 @@ namespace LmbrCentral
EditorAudioRtpcComponent::CreateDescriptor(),
EditorAudioSwitchComponent::CreateDescriptor(),
EditorAudioTriggerComponent::CreateDescriptor(),
EditorMeshComponent::CreateDescriptor(),
EditorTagComponent::CreateDescriptor(),
EditorSphereShapeComponent::CreateDescriptor(),
EditorDiskShapeComponent::CreateDescriptor(),
@@ -107,8 +103,6 @@ namespace LmbrCentral
typeIds.emplace_back(descriptor->GetUuid());
}
EBUS_EVENT(AzFramework::MetricsPlainTextNameRegistrationBus, RegisterForNameSending, typeIds);
EditorMeshBus::Handler::BusConnect();
}
LmbrCentralEditorModule::~LmbrCentralEditorModule()
@@ -123,11 +117,6 @@ namespace LmbrCentral
return requiredComponents;
}
bool LmbrCentralEditorModule::AddMeshComponentWithAssetId(const AZ::EntityId& targetEntity, const AZ::Uuid& meshAssetId)
{
return AddMeshComponentWithMesh(targetEntity, meshAssetId);
}
} // namespace LmbrCentral
AZ_DECLARE_MODULE_CLASS(Gem_LmbrCentralEditor, LmbrCentral::LmbrCentralEditorModule)
@@ -13,13 +13,6 @@
#include "LmbrCentral.h"
#include <LmbrCentral/Rendering/EditorMeshBus.h>
namespace Water
{
class WaterVolumeConverter;
}
namespace LmbrCentral
{
/**
@@ -31,7 +24,6 @@ namespace LmbrCentral
*/
class LmbrCentralEditorModule
: public LmbrCentralModule
, public EditorMeshBus::Handler
{
public:
AZ_RTTI(LmbrCentralEditorModule, "{1BF648D7-3703-4B52-A688-67C253A059F2}", LmbrCentralModule);
@@ -39,7 +31,5 @@ namespace LmbrCentral
LmbrCentralEditorModule();
~LmbrCentralEditorModule();
AZ::ComponentTypeList GetRequiredSystemComponents() const override;
bool AddMeshComponentWithAssetId(const AZ::EntityId& targetEntity, const AZ::Uuid& meshAssetId) override;
};
} // namespace LmbrCentral
@@ -1,580 +0,0 @@
/*
* 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 "LmbrCentral_precompiled.h"
#include "EditorMeshComponent.h"
#include <AzFramework/Viewport/ViewportColors.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/std/string/string_view.h>
#include <AzToolsFramework/API/EntityCompositionRequestBus.h>
#include <MathConversion.h>
#include <INavigationSystem.h> // For updating nav tiles on creation of editor physics.
#include <IPhysics.h> // For basic physicalization at edit-time for object snapping.
#include <IEditor.h>
#include <Settings.h>
#include <I3DEngine.h>
#include <AzCore/Interface/Interface.h>
#include <AzFramework/Render/GeometryIntersectionBus.h>
#include <AzCore/Console/IConsole.h>
namespace LmbrCentral
{
AZ_CVAR(bool, cl_editorMeshIntersectionDebug, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enable editor mesh intersection debugging");
void EditorMeshComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorMeshComponent, EditorComponentBase>()
->Version(1)
->Field("Static Mesh Render Node", &EditorMeshComponent::m_mesh)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorMeshComponent>("Mesh", "The Mesh component is the primary method of adding visual geometry to entities")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Rendering")
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/StaticMesh.svg")
->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo<LmbrCentral::MeshAsset>::Uuid())
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/StaticMesh.png")
->Attribute(AZ::Edit::Attributes::DynamicIconOverride, &EditorMeshComponent::GetMeshViewportIconPath)
->Attribute(AZ::Edit::Attributes::PreferNoViewportIcon, true)
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://docs.aws.amazon.com/lumberyard/latest/userguide/component-static-mesh.html")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->DataElement(AZ::Edit::UIHandlers::Default, &EditorMeshComponent::m_mesh)
;
editContext->Class<MeshComponentRenderNode::MeshRenderOptions>(
"Render Options", "Rendering options for the mesh.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game", 0x232b318c))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
->ClassElement(AZ::Edit::ClassElements::Group, "Options")
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentRenderNode::MeshRenderOptions::m_opacity, "Opacity", "Opacity value")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Max, 1.f)
->Attribute(AZ::Edit::Attributes::Step, 0.1f)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_maxViewDist, "Max view distance", "Maximum view distance in meters.")
->Attribute(AZ::Edit::Attributes::Suffix, " m")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::Max, &MeshComponentRenderNode::GetDefaultMaxViewDist)
->Attribute(AZ::Edit::Attributes::Step, 0.1f)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_viewDistMultiplier, "View distance multiplier", "Adjusts max view distance. If 1.0 then default is used. 1.1 would be 10% further than default.")
->Attribute(AZ::Edit::Attributes::Suffix, "x")
->Attribute(AZ::Edit::Attributes::Min, 0.f)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->DataElement(AZ::Edit::UIHandlers::Slider, &MeshComponentRenderNode::MeshRenderOptions::m_lodRatio, "LOD distance ratio", "Controls LOD ratio over distance.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->Attribute(AZ::Edit::Attributes::Min, 0)
->Attribute(AZ::Edit::Attributes::Max, 255)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_castShadows, "Cast shadows", "Casts shadows.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_lodBoundingBoxBased, "LOD based on Bounding Boxes", "LOD based on Bounding Boxes.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_useVisAreas, "Use VisAreas", "Allow VisAreas to control this component's visibility.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->ClassElement(AZ::Edit::ClassElements::Group, "Advanced")
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_rainOccluder, "Rain occluder", "Occludes dynamic raindrops.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentRenderNode::MeshRenderOptions::StaticPropertyVisibility)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_affectDynamicWater, "Affect dynamic water", "Will generate ripples in dynamic water.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentRenderNode::MeshRenderOptions::StaticPropertyVisibility)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_receiveWind, "Receive wind", "Receives wind.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMajorChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_acceptDecals, "Accept decals", "Can receive decals.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_affectNavmesh, "Affect navmesh", "Will affect navmesh generation.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentRenderNode::MeshRenderOptions::StaticPropertyVisibility)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_visibilityOccluder, "Visibility occluder", "Is appropriate for occluding visibility of other objects.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentRenderNode::MeshRenderOptions::StaticPropertyVisibility)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_dynamicMesh, "Deformable mesh", "Enables vertex deformation on mesh.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMajorChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::MeshRenderOptions::m_affectGI, "Affects GI", "Affects the global illumination results.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::MeshRenderOptions::OnMinorChanged)
->Attribute(AZ::Edit::Attributes::Visibility, &MeshComponentRenderNode::MeshRenderOptions::StaticPropertyVisibility)
;
editContext->Class<MeshComponentRenderNode>(
"Mesh Rendering", "Attach geometry to the entity.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::m_visible, "Visible", "Is currently visible.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::RefreshRenderState)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::m_meshAsset, "Mesh asset", "Mesh asset reference")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::OnAssetPropertyChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::m_material, "Material override", "Optionally specify an override material.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::OnAssetPropertyChanged)
->DataElement(AZ::Edit::UIHandlers::Default, &MeshComponentRenderNode::m_renderOptions, "Render options", "Render/draw options.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &MeshComponentRenderNode::RefreshRenderState)
;
}
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<EditorMeshComponent>()->RequestBus("MeshComponentRequestBus");
}
}
void EditorMeshComponent::Activate()
{
EditorComponentBase::Activate();
m_mesh.AttachToEntity(m_entity->GetId());
bool isStatic = false;
AZ::TransformBus::EventResult(isStatic, m_entity->GetId(), &AZ::TransformBus::Events::IsStaticTransform);
m_mesh.SetTransformStaticState(isStatic);
bool visible = false;
AzToolsFramework::EditorEntityInfoRequestBus::EventResult(
visible, GetEntityId(), &AzToolsFramework::EditorEntityInfoRequestBus::Events::IsVisible);
m_mesh.UpdateAuxiliaryRenderFlags(!visible, ERF_HIDDEN);
// Note we are purposely connecting to buses before calling m_mesh.CreateMesh().
// m_mesh.CreateMesh() can result in events (eg: OnMeshCreated) that we want receive.
MaterialOwnerRequestBus::Handler::BusConnect(m_entity->GetId());
AzFramework::BoundsRequestBus::Handler::BusConnect(m_entity->GetId());
MeshComponentRequestBus::Handler::BusConnect(m_entity->GetId());
MeshComponentNotificationBus::Handler::BusConnect(m_entity->GetId());
LegacyMeshComponentRequestBus::Handler::BusConnect(m_entity->GetId());
RenderNodeRequestBus::Handler::BusConnect(m_entity->GetId());
AZ::TransformNotificationBus::Handler::BusConnect(m_entity->GetId());
AzToolsFramework::EditorVisibilityNotificationBus::Handler::BusConnect(GetEntityId());
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusConnect(GetEntityId());
AzToolsFramework::EditorComponentSelectionNotificationsBus::Handler::BusConnect(GetEntityId());
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
AzFramework::EntityIdContextQueryBus::EventResult(m_contextId, GetEntityId(), &AzFramework::EntityIdContextQueries::GetOwningContextId);
AzFramework::RenderGeometry::IntersectionRequestBus::Handler::BusConnect({ GetEntityId(), m_contextId });
m_mesh.m_renderOptions.m_changeCallback =
[this]()
{
m_mesh.RefreshRenderState();
AffectNavmesh();
};
m_mesh.CreateMesh();
}
void EditorMeshComponent::Deactivate()
{
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
AZ::Data::AssetBus::Handler::BusDisconnect();
MaterialOwnerRequestBus::Handler::BusDisconnect();
AzFramework::BoundsRequestBus::Handler::BusDisconnect();
MeshComponentRequestBus::Handler::BusDisconnect();
MeshComponentNotificationBus::Handler::BusDisconnect();
LegacyMeshComponentRequestBus::Handler::BusDisconnect();
RenderNodeRequestBus::Handler::BusDisconnect();
AZ::TransformNotificationBus::Handler::BusDisconnect();
AzToolsFramework::EditorVisibilityNotificationBus::Handler::BusDisconnect();
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
AzToolsFramework::EditorComponentSelectionRequestsBus::Handler::BusDisconnect();
AzToolsFramework::EditorComponentSelectionNotificationsBus::Handler::BusDisconnect();
AzFramework::RenderGeometry::IntersectionRequestBus::Handler::BusDisconnect();
m_mesh.m_renderOptions.m_changeCallback = nullptr;
m_mesh.DestroyMesh();
m_mesh.AttachToEntity(AZ::EntityId());
EditorComponentBase::Deactivate();
}
void EditorMeshComponent::OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset)
{
AZ::Data::AssetBus::Handler::BusDisconnect();
AZ::Data::AssetBus::Handler::BusConnect(asset.GetId());
using namespace AzFramework::RenderGeometry;
IntersectionNotificationBus::Event(m_contextId, &IntersectionNotifications::OnGeometryChanged, GetEntityId());
}
void EditorMeshComponent::OnMeshDestroyed()
{
using namespace AzFramework::RenderGeometry;
IntersectionNotificationBus::Event(m_contextId, &IntersectionNotifications::OnGeometryChanged, GetEntityId());
}
IRenderNode* EditorMeshComponent::GetRenderNode()
{
return &m_mesh;
}
float EditorMeshComponent::GetRenderNodeRequestBusOrder() const
{
return s_renderNodeRequestBusOrder;
}
void EditorMeshComponent::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
{
AZ_UNUSED(world);
using namespace AzFramework::RenderGeometry;
IntersectionNotificationBus::Event(m_contextId, &IntersectionNotifications::OnGeometryChanged, GetEntityId());
}
void EditorMeshComponent::OnStaticChanged(bool isStatic)
{
m_mesh.SetTransformStaticState(isStatic);
if (m_mesh.m_renderOptions.m_changeCallback)
{
m_mesh.m_renderOptions.m_changeCallback();
}
AffectNavmesh();
}
AZ::Aabb EditorMeshComponent::GetWorldBounds()
{
return m_mesh.CalculateWorldAABB();
}
AZ::Aabb EditorMeshComponent::GetLocalBounds()
{
return m_mesh.CalculateLocalAABB();
}
AzFramework::RenderGeometry::RayResult EditorMeshComponent::RenderGeometryIntersect(const AzFramework::RenderGeometry::RayRequest& ray)
{
AzFramework::RenderGeometry::RayResult result;
if (!GetVisibility() && ray.m_onlyVisible)
{
return result;
}
if (IStatObj* geometry = GetStatObj())
{
const AZ::Vector3 rayDirection = (ray.m_endWorldPosition - ray.m_startWorldPosition);
const AZ::Transform& transform = GetTransform()->GetWorldTM();
const AZ::Transform inverseTransform = transform.GetInverse();
const AZ::Vector3 rayStartLocal = inverseTransform.TransformPoint(ray.m_startWorldPosition);
const AZ::Vector3 rayDistNormLocal = inverseTransform.TransformVector(rayDirection).GetNormalized();
SRayHitInfo hi;
hi.inReferencePoint = AZVec3ToLYVec3(rayStartLocal);
hi.inRay = Ray(hi.inReferencePoint, AZVec3ToLYVec3(rayDistNormLocal));
hi.bInFirstHit = true;
hi.bGetVertColorAndTC = true;
if (geometry->RayIntersection(hi))
{
AZ::Matrix3x4 invTransformMatrix = AZ::Matrix3x4::CreateFromTransform(inverseTransform);
invTransformMatrix.Transpose();
result.m_uv = LYVec2ToAZVec2(hi.vHitTC);
result.m_worldPosition = transform.TransformPoint(LYVec3ToAZVec3(hi.vHitPos));
result.m_worldNormal = invTransformMatrix.Multiply3x3(LYVec3ToAZVec3(hi.vHitNormal)).GetNormalized();
result.m_distance = (result.m_worldPosition - ray.m_startWorldPosition).GetLength();
result.m_entityAndComponent = { GetEntityId(), GetId() };
if (cl_editorMeshIntersectionDebug)
{
m_debugPos = result.m_worldPosition;
m_debugNormal = result.m_worldNormal;
}
}
}
return result;
}
void EditorMeshComponent::SetMeshAsset(const AZ::Data::AssetId& id)
{
m_mesh.SetMeshAsset(id);
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationRequests::AddDirtyEntity,
GetEntityId());
}
void EditorMeshComponent::SetMaterial(_smart_ptr<IMaterial> material)
{
m_mesh.SetMaterial(material);
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
AzToolsFramework::Refresh_AttributesAndValues);
}
_smart_ptr<IMaterial> EditorMeshComponent::GetMaterial()
{
return m_mesh.GetMaterial();
}
void EditorMeshComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId)
{
SetMeshAsset(assetId);
}
void EditorMeshComponent::OnEntityVisibilityChanged(bool visibility)
{
m_mesh.UpdateAuxiliaryRenderFlags(!visibility, ERF_HIDDEN);
m_mesh.RefreshRenderState();
}
static void DecideColor(
const bool selected, const bool mouseHovered, const bool visible,
ColorB& triangleColor, ColorB& lineColor)
{
const ColorB translucentPurple = ColorB(250, 0, 250, 30);
// default both colors to hidden
triangleColor = ColorB(AZ::u32(0));
lineColor = ColorB(AZ::u32(0));
if (selected)
{
if (!visible)
{
lineColor = Col_Black;
if (mouseHovered)
{
triangleColor = translucentPurple;
}
}
}
else
{
if (mouseHovered)
{
triangleColor = translucentPurple;
lineColor = AZColorToLYColorF(AzFramework::ViewportColors::HoverColor);
}
}
}
void EditorMeshComponent::DisplayEntityViewport(
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay)
{
const bool mouseHovered = m_accentType == AzToolsFramework::EntityAccentType::Hover;
IEditor* editor = nullptr;
AzToolsFramework::EditorRequests::Bus::BroadcastResult(editor, &AzToolsFramework::EditorRequests::GetEditor);
const bool highlightGeometryOnMouseHover = editor->GetEditorSettings()->viewports.bHighlightMouseOverGeometry;
// if the mesh component is not visible, when selected we still draw the wireframe to indicate the shapes extent and position
const bool highlightGeometryWhenSelected = editor->GetEditorSettings()->viewports.bHighlightSelectedGeometry || !GetVisibility();
if ((!IsSelected() && mouseHovered && highlightGeometryOnMouseHover) || (IsSelected() && highlightGeometryWhenSelected))
{
AZ::Transform transform = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(transform, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
ColorB triangleColor, lineColor;
DecideColor(IsSelected(), mouseHovered, GetVisibility(), triangleColor, lineColor);
SGeometryDebugDrawInfo dd;
dd.tm = AZTransformToLYTransform(transform);
dd.bExtrude = true;
dd.color = triangleColor;
dd.lineColor = lineColor;
if (IStatObj* geometry = GetStatObj())
{
geometry->DebugDraw(dd);
}
}
if (cl_editorMeshIntersectionDebug)
{
debugDisplay.DrawArrow(m_debugPos, m_debugPos + (0.1f * m_debugNormal), 0.1f);
debugDisplay.DrawBall(m_debugPos, 0.03f);
debugDisplay.DrawWireBox(GetWorldBounds().GetMin(), GetWorldBounds().GetMax());
}
}
void EditorMeshComponent::BuildGameEntity(AZ::Entity* gameEntity)
{
if (auto meshComponent = gameEntity->CreateComponent<MeshComponent>())
{
m_mesh.CopyPropertiesTo(meshComponent->m_meshRenderNode);
// ensure we do not copy across the edit time entity id
meshComponent->m_meshRenderNode.m_renderOptions.m_attachedToEntityId = AZ::EntityId();
}
}
IStatObj* EditorMeshComponent::GetStatObj()
{
return m_mesh.GetEntityStatObj();
}
bool EditorMeshComponent::GetVisibility()
{
return m_mesh.GetVisible();
}
void EditorMeshComponent::SetVisibility(bool visible)
{
m_mesh.SetVisible(visible);
}
void EditorMeshComponent::AffectNavmesh()
{
// Refresh the nav tile when the flag changes.
INavigationSystem* pNavigationSystem = nullptr; // INavigationSystem will be converted to an AZInterface (LY-111343)
if (pNavigationSystem)
{
pNavigationSystem->WorldChanged(AZAabbToLyAABB(GetWorldBounds()));
}
}
AZStd::string_view staticViewportIcon = "Icons/Components/Viewport/StaticMesh.png";
AZStd::string_view dynamicViewportIcon = "Icons/Components/Viewport/DynamicMesh.png";
AZStd::string EditorMeshComponent::GetMeshViewportIconPath() const
{
if (m_mesh.m_renderOptions.IsStatic())
{
return staticViewportIcon;
}
return dynamicViewportIcon;
}
void EditorMeshComponent::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> /*asset*/)
{
using namespace AzFramework::RenderGeometry;
IntersectionNotificationBus::Event(m_contextId, &IntersectionNotifications::OnGeometryChanged, GetEntityId());
}
void EditorMeshComponent::OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& /*assetInfo*/)
{
if (m_mesh.m_meshAsset.GetId() != assetId)
{
return;
}
// If this editor mesh component is loaded and active in the level, it's referencing an asset that was just removed.
// Clearing this asset reference will help visualize this change. Note that this won't clear all references to this
// asset automatically, any levels that aren't loaded won't have the reference removed.
// Set the mesh asset to invalid on the main thread.
AZ::TickBus::QueueFunction([this, assetId]()
{
// Emit a warning so users know this has occurred, it may not be intentional because the asset was removed before
// the references were cleared. Do this on the main thread.
AZ_Warning("EditorMeshComponent", false, "asset with ID %s referenced by entity named '%s' with ID %s was removed, this reference will be cleared on the associated component.",
assetId.ToString<AZStd::string>().c_str(),
GetEntity() ? GetEntity()->GetName().c_str() : "Invalid entity",
GetEntityId().ToString().c_str());
m_mesh.DestroyMesh();
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationRequests::AddDirtyEntity,
GetEntityId());
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
AzToolsFramework::Refresh_AttributesAndValues);
});
}
AZ::Aabb EditorMeshComponent::GetEditorSelectionBoundsViewport(
const AzFramework::ViewportInfo& /*viewportInfo*/)
{
return GetWorldBounds();
}
bool EditorMeshComponent::EditorSelectionIntersectRayViewport(
const AzFramework::ViewportInfo& /*viewportInfo*/,
const AZ::Vector3& src, const AZ::Vector3& dir, float& distance)
{
if (IStatObj* geometry = GetStatObj())
{
AZ::Transform transform = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(transform, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
auto legacyTransform = AZTransformToLYTransform(transform);
const auto legacySrc = AZVec3ToLYVec3(src);
const auto legacyDir = AZVec3ToLYVec3(dir);
const Matrix34 inverseTM = legacyTransform.GetInverted();
const Vec3 raySrcLocal = inverseTM.TransformPoint(legacySrc);
const Vec3 rayDirLocal = inverseTM.TransformVector(legacyDir).GetNormalized();
SRayHitInfo hi;
hi.inReferencePoint = raySrcLocal;
hi.inRay = Ray(raySrcLocal, rayDirLocal);
if (geometry->RayIntersection(hi))
{
const Vec3 worldHitPos = legacyTransform.TransformPoint(hi.vHitPos);
distance = legacySrc.GetDistance(worldHitPos);
return true;
}
}
return false;
}
void EditorMeshComponent::OnAccentTypeChanged(AzToolsFramework::EntityAccentType accent)
{
m_accentType = accent;
}
bool AddMeshComponentWithMesh(const AZ::EntityId& targetEntity, const AZ::Uuid& meshAssetId)
{
// Error handling for failures should be done at the call site, this function can be invoked from Python.
if (!targetEntity.IsValid())
{
return false;
}
AZ::ComponentTypeList componentsToAdd;
componentsToAdd.push_back(AZ::AzTypeInfo<LmbrCentral::EditorMeshComponent>::Uuid());
AZStd::vector<AZ::EntityId> entityList;
entityList.push_back(targetEntity);
AzToolsFramework::EntityCompositionRequests::AddComponentsOutcome outcome =
AZ::Failure(AZStd::string("Failed to call AddComponentsToEntities on EntityCompositionRequestBus"));
AzToolsFramework::EntityCompositionRequestBus::BroadcastResult(outcome, &AzToolsFramework::EntityCompositionRequests::AddComponentsToEntities, entityList, componentsToAdd);
if (!outcome.IsSuccess())
{
return false;
}
AZ::Data::AssetId meshAsset(meshAssetId);
// If necessary, the call site can verify if the mesh was actually set.
LmbrCentral::MeshComponentRequestBus::Event(
targetEntity,
&LmbrCentral::MeshComponentRequestBus::Events::SetMeshAsset,
meshAsset);
return true;
}
} // namespace LmbrCentral
@@ -1,175 +0,0 @@
/*
* 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/TransformBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzFramework/Visibility/BoundsBus.h>
#include <AzFramework/Render/GeometryIntersectionBus.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <LmbrCentral/Rendering/RenderNodeBus.h>
#include <LmbrCentral/Rendering/RenderBoundsBus.h>
#include "MeshComponent.h"
struct IPhysicalEntity;
namespace LmbrCentral
{
/**
* In-editor mesh component.
* Conducts some additional listening and operations to ensure immediate
* effects when changing fields in the editor.
*/
class EditorMeshComponent
: public AzToolsFramework::Components::EditorComponentBase
, public AZ::Data::AssetBus::Handler
, private AzFramework::AssetCatalogEventBus::Handler
, public AzFramework::BoundsRequestBus::Handler
, private AzFramework::RenderGeometry::IntersectionRequestBus::Handler
, private MeshComponentRequestBus::Handler
, private MaterialOwnerRequestBus::Handler
, private MeshComponentNotificationBus::Handler
, private RenderNodeRequestBus::Handler
, private AZ::TransformNotificationBus::Handler
, private AzToolsFramework::EntitySelectionEvents::Bus::Handler
, private AzToolsFramework::EditorVisibilityNotificationBus::Handler
, private AzFramework::EntityDebugDisplayEventBus::Handler
, private LegacyMeshComponentRequestBus::Handler
, private AzToolsFramework::EditorComponentSelectionRequestsBus::Handler
, private AzToolsFramework::EditorComponentSelectionNotificationsBus::Handler
{
public:
AZ_COMPONENT(EditorMeshComponent, "{FC315B86-3280-4D03-B4F0-5553D7D08432}", AzToolsFramework::Components::EditorComponentBase)
~EditorMeshComponent() = default;
const float s_renderNodeRequestBusOrder = 100.f;
// AZ::Component overrides ...
void Activate() override;
void Deactivate() override;
// BoundsRequestBus and MeshComponentRequestBus overrides ...
AZ::Aabb GetWorldBounds() override;
AZ::Aabb GetLocalBounds() override;
// IntersectionRequestBus overrides ...
AzFramework::RenderGeometry::RayResult RenderGeometryIntersect(const AzFramework::RenderGeometry::RayRequest& ray) override;
// MeshComponentRequestBus overrides ...
void SetMeshAsset(const AZ::Data::AssetId& id) override;
AZ::Data::Asset<AZ::Data::AssetData> GetMeshAsset() override { return m_mesh.GetMeshAsset(); }
void SetVisibility(bool visible) override;
bool GetVisibility() override;
// MaterialOwnerRequestBus overrides ...
void SetMaterial(_smart_ptr<IMaterial>) override;
_smart_ptr<IMaterial> GetMaterial() override;
// MeshComponentNotificationBus overrides ...
void OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset) override;
void OnMeshDestroyed() override;
// RenderNodeRequestBus overrides ...
IRenderNode* GetRenderNode() override;
float GetRenderNodeRequestBusOrder() const override;
// TransformNotificationBus overrides ...
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
void OnStaticChanged(bool isStatic) override;
// EditorVisibilityNotificationBus overrides ...
void OnEntityVisibilityChanged(bool visibility) override;
// AzFramework::EntityDebugDisplayEventBus overrides ....
void DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
//! Called when you want to change the game asset through code (like when creating components based on assets).
void SetPrimaryAsset(const AZ::Data::AssetId& assetId) override;
// LegacyMeshComponentRequests overrides ...
IStatObj* GetStatObj() override;
// EditorComponentBase overrides ...
void BuildGameEntity(AZ::Entity* gameEntity) override;
// AZ::Data::AssetBus overrides ...
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
// AzFramework::AssetCatalogEventBus overrides ...
void OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& assetInfo) override;
// EditorComponentSelectionRequestsBus overrides ...
AZ::Aabb GetEditorSelectionBoundsViewport(
const AzFramework::ViewportInfo& viewportInfo) override;
bool EditorSelectionIntersectRayViewport(
const AzFramework::ViewportInfo& viewportInfo,
const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) override;
bool SupportsEditorRayIntersect() override { return true; }
// EditorComponentSelectionNotificationsBus overrides ...
void OnAccentTypeChanged(AzToolsFramework::EntityAccentType accent) override;
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("MeshService", 0x71d8a455));
provided.push_back(AZ_CRC("LegacyMeshService", 0xb462a299));
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
}
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC("EditorVisibilityService", 0x90888caf));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("MeshService", 0x71d8a455));
incompatible.push_back(AZ_CRC("LegacyMeshService", 0xb462a299));
}
static void Reflect(AZ::ReflectContext* context);
protected:
// Decides if this mesh affects the navmesh or not.
void AffectNavmesh();
AZStd::string GetMeshViewportIconPath() const;
AzToolsFramework::EntityAccentType m_accentType = AzToolsFramework::EntityAccentType::None; ///< State of the entity selection in the viewport.
MeshComponentRenderNode m_mesh; ///< IRender node implementation.
AzFramework::EntityContextId m_contextId;
AZ::Vector3 m_debugPos = AZ::Vector3(0);
AZ::Vector3 m_debugNormal = AZ::Vector3(0);
};
// Helper function useful for automation.
bool AddMeshComponentWithMesh(const AZ::EntityId& targetEntity, const AZ::Uuid& meshAssetId);
} // namespace LmbrCentral
@@ -1,399 +0,0 @@
/*
* 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 "LmbrCentral_precompiled.h"
#include <LmbrCentral/Rendering/MaterialHandle.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Math/Color.h>
#include <IRenderer.h>
#include <ISystem.h>
#include <I3DEngine.h>
namespace LmbrCentral
{
// Provides a set of reflected functions for operating on IMaterial through a MaterialHandle
// We keep these cpp-private instead of putting them in the header to align with the fact that
// MaterialHandle is not useful on the code side, and only exists to support reflection. If it
// were possible to reflect IMaterial directly, we'd still have this same set of functions here.
namespace MaterialHandleFunctions
{
void SetParamVector4(MaterialHandle* thisPtr, const AZStd::string& name, const AZ::Vector4& value)
{
if (thisPtr && thisPtr->m_material)
{
if (!thisPtr->m_material->IsMaterialGroup())
{
Vec4 vec4(value.GetX(), value.GetY(), value.GetZ(), value.GetW());
thisPtr->m_material->SetGetMaterialParamVec4(name.c_str(), vec4, false, true);
}
else
{
AZ_Error("Material", false, "SetParamVector4 only accepts single Materials, not Material Groups");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to SetParamVector4");
}
}
void SetParamVector3(MaterialHandle* thisPtr, const AZStd::string& name, const AZ::Vector3& value)
{
if (thisPtr && thisPtr->m_material)
{
if (!thisPtr->m_material->IsMaterialGroup())
{
Vec3 vec3(value.GetX(), value.GetY(), value.GetZ());
thisPtr->m_material->SetGetMaterialParamVec3(name.c_str(), vec3, false, true);
}
else
{
AZ_Error("Material", false, "SetParamVector3 only accepts single Materials, not Material Groups");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to SetParamVector3");
}
}
void SetParamColor(MaterialHandle* thisPtr, const AZStd::string& name, const AZ::Color& value)
{
if (thisPtr && thisPtr->m_material)
{
if (!thisPtr->m_material->IsMaterialGroup())
{
// When value had garbage data is was not only making the material render black, it also corrupted something
// on the GPU, making black boxes flicker over the sky.
// It was garbage due to a bug in the Color object node where all fields have to be set to some value manually; the default is not 0.
if ((value.GetR() < 0 || value.GetR() > 1) ||
(value.GetG() < 0 || value.GetG() > 1) ||
(value.GetB() < 0 || value.GetB() > 1) ||
(value.GetA() < 0 || value.GetA() > 1))
{
return;
}
Vec4 vec4(value.GetR(), value.GetG(), value.GetB(), value.GetA());
thisPtr->m_material->SetGetMaterialParamVec4(name.c_str(), vec4, false, true);
}
else
{
AZ_Error("Material", false, "SetParamColor only accepts single Materials, not Material Groups");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to SetParamColor");
}
}
void SetParamFloat(MaterialHandle* thisPtr, const AZStd::string& name, float value)
{
if (thisPtr && thisPtr->m_material)
{
if (!thisPtr->m_material->IsMaterialGroup())
{
thisPtr->m_material->SetGetMaterialParamFloat(name.c_str(), value, false, true);
}
else
{
AZ_Error("Material", false, "SetParamFloat only accepts single Materials, not Material Groups");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to SetParamFloat");
}
}
AZ::Vector4 GetParamVector4(MaterialHandle* thisPtr, const AZStd::string& name)
{
AZ::Vector4 value = AZ::Vector4::CreateZero();
if (thisPtr && thisPtr->m_material)
{
if (!thisPtr->m_material->IsMaterialGroup())
{
Vec4 vec4;
if (thisPtr->m_material->SetGetMaterialParamVec4(name.c_str(), vec4, true, true))
{
value.Set(vec4.x, vec4.y, vec4.z, vec4.w);
}
}
else
{
AZ_Error("Material", false, "GetParamVector4 only accepts single Materials, not Material Groups");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to GetParamVector4");
}
return value;
}
AZ::Vector3 GetParamVector3(MaterialHandle* thisPtr, const AZStd::string& name)
{
AZ::Vector3 value = AZ::Vector3::CreateZero();
if (thisPtr && thisPtr->m_material)
{
if (!thisPtr->m_material->IsMaterialGroup())
{
Vec3 vec3;
if (thisPtr->m_material->SetGetMaterialParamVec3(name.c_str(), vec3, true, true))
{
value.Set(vec3.x, vec3.y, vec3.z);
}
}
else
{
AZ_Error("Material", false, "GetParamVector3 only accepts single Materials, not Material Groups");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to GetParamVector3");
}
return value;
}
AZ::Color GetParamColor(MaterialHandle* thisPtr, const AZStd::string& name)
{
AZ::Color value = AZ::Color::CreateZero();
if (thisPtr && thisPtr->m_material)
{
if (!thisPtr->m_material->IsMaterialGroup())
{
Vec4 vec4;
if (thisPtr->m_material->SetGetMaterialParamVec4(name.c_str(), vec4, true, true))
{
value.Set(vec4.x, vec4.y, vec4.z, vec4.w);
}
}
else
{
AZ_Error("Material", false, "GetParamColor only accepts single Materials, not Material Groups");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to GetParamColor");
}
return value;
}
float GetParamFloat(MaterialHandle* thisPtr, const AZStd::string& name)
{
float value = 0.0f;
if (thisPtr && thisPtr->m_material)
{
if (!thisPtr->m_material->IsMaterialGroup())
{
thisPtr->m_material->SetGetMaterialParamFloat(name.c_str(), value, true, true);
}
else
{
AZ_Error("Material", false, "GetParamFloat only accepts single Materials, not Material Groups");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to GetParamFloat");
}
return value;
}
MaterialHandle Clone(MaterialHandle* thisPtr)
{
MaterialHandle copy;
if (thisPtr && thisPtr->m_material)
{
if (!thisPtr->m_material->IsSubMaterial())
{
copy.m_material = gEnv->p3DEngine->GetMaterialManager()->CloneMultiMaterial(thisPtr->m_material);
}
else
{
AZ_Error("Material", false, "Clone does not support Sub-Materials");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to Clone");
}
return copy;
}
MaterialHandle FindByName(const AZStd::string& name)
{
MaterialHandle found;
found.m_material = gEnv->p3DEngine->GetMaterialManager()->FindMaterial(name.c_str());
return found;
}
MaterialHandle LoadByName(const AZStd::string& name)
{
LmbrCentral::MaterialHandle handle;
handle.m_material = gEnv->p3DEngine->GetMaterialManager()->LoadMaterial(name.c_str(), false, false, IMaterialManager::ELoadingFlagsPreviewMode);
AZ_Error(nullptr, handle.m_material, "Material.LoadByName('%s') failed", name.c_str());
return handle;
}
_smart_ptr<IMaterial> GetSubMaterialHelper(_smart_ptr<IMaterial> materialGroup, int materialId)
{
if (materialGroup)
{
if (materialGroup->IsMaterialGroup())
{
int subMtlCount = materialGroup->GetSubMtlCount();
if (materialId >= 1 && materialId <= subMtlCount)
{
return materialGroup->GetSubMtl(materialId-1);
}
else
{
AZ_Error("Material", false, "Invalid Material ID %d passed to FindSubMaterial. %d Materials are available.", materialId, subMtlCount);
}
}
else
{
AZ_Error("Material", false, "FindSubMaterial does not support single Material");
}
}
else
{
AZ_Warning("Material", false, "Invalid Material passed to FindSubMaterial.");
}
return nullptr;
}
MaterialHandle FindSubMaterial(const AZStd::string& name, int id, bool shouldLoad)
{
MaterialHandle found;
_smart_ptr<IMaterial> materialGroup = gEnv->p3DEngine->GetMaterialManager()->FindMaterial(name.c_str());
if (materialGroup)
{
found.m_material = GetSubMaterialHelper(materialGroup, id);
}
else
{
if (shouldLoad)
{
materialGroup = gEnv->p3DEngine->GetMaterialManager()->LoadMaterial(name.c_str(), false, false, IMaterialManager::ELoadingFlagsPreviewMode);
if (materialGroup)
{
found.m_material = GetSubMaterialHelper(materialGroup, id);
}
else
{
AZ_Error("Material", false, "Load Material '%s' failed", name.c_str());
}
}
else
{
AZ_Warning("Material", false, "No Sub-Material is found since Material '%s' is not loaded", name.c_str());
}
}
return found;
}
AZStd::string ToString(MaterialHandle* thisPtr)
{
if (!thisPtr || !thisPtr->m_material)
{
return "Invalid";
}
else
{
return thisPtr->m_material->GetName();
}
}
}
void MaterialHandle::Reflect(AZ::SerializeContext* serializeContext)
{
// This is required in order to create a MaterialHandle variable in script canvas.
serializeContext->Class<MaterialHandle>()->Version(0);
}
void MaterialHandle::Reflect(AZ::BehaviorContext* behaviorContext)
{
const char* setMaterialParamTooltip = "Sets a Material param value";
const char* getMaterialParamTooltip = "Returns a Material param value";
AZ::BehaviorParameterOverrides setMaterialDetails = { "Material", "The Material to modify" };
AZ::BehaviorParameterOverrides getMaterialDetails = { "Material", "The Material to inspect" };
AZ::BehaviorParameterOverrides setParamNameDetails = { "ParamName", "The name of the Material param to set" };
AZ::BehaviorParameterOverrides getParamNameDetails = { "ParamName", "The name of the Material param to return" };
const AZStd::array<AZ::BehaviorParameterOverrides, 2> getMaterialParamArgs = { { getMaterialDetails,getParamNameDetails } };
const char* newValueTooltip = "The new value to apply";
behaviorContext->Class<MaterialHandle>("Material")
->Attribute(AZ::Script::Attributes::Category, "Rendering")
->Method("ToString", &MaterialHandleFunctions::ToString)
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) // Hide this node because it doesn't really make sense for the user (GetName would be better), but we need "ToString" in order to provide nice output in Material Variable nodes in script canvas.
->Method("FindByName", &MaterialHandleFunctions::FindByName, { { { "Name", "Full path name of the Material" } } })
->Attribute(AZ::Script::Attributes::ToolTip, "Find a Material by name. Returns Invalid if the Material is not already loaded.")
->Method("LoadByName", &MaterialHandleFunctions::LoadByName, { { { "Name", "Full path name of the Material" } } })
->Attribute(AZ::Script::Attributes::ToolTip, "Find a Material by name, loading the asset if needed. Returns Invalid if the Material could not be found or loaded.")
->Method("Clone", &MaterialHandleFunctions::Clone, { { { "Material", "The Material to clone" } } })
->Attribute(AZ::Script::Attributes::ToolTip, "Creates a copy of the given Material.")
->Method("FindSubMaterial", &MaterialHandleFunctions::FindSubMaterial,
{ { { "Name", "Full path name of the Material Group to get a Sub-Material from" },
{ "MaterialID", "The ID of a Sub-Material to access. IDs start at 1.", behaviorContext->MakeDefaultValue(1) },
{ "ShouldLoad", "Whether to load the Material Group or not if it's not loaded", behaviorContext->MakeDefaultValue(true) } } })
->Attribute(AZ::Script::Attributes::ToolTip, "Find a Sub-Material from a Material Group by specified Material ID. Returns Invalid if the Material Group could not be found or loaded or the Sub-Material could not be found.")
->Method("SetParamVector4", &MaterialHandleFunctions::SetParamVector4,
{ { setMaterialDetails,setParamNameDetails,{ "Vector4", newValueTooltip } } })
->Attribute(AZ::Script::Attributes::ToolTip, setMaterialParamTooltip)
->Method("SetParamVector3", &MaterialHandleFunctions::SetParamVector3,
{ { setMaterialDetails,setParamNameDetails,{ "Vector3", newValueTooltip } } })
->Attribute(AZ::Script::Attributes::ToolTip, setMaterialParamTooltip)
->Method("SetParamColor", &MaterialHandleFunctions::SetParamColor,
{ { setMaterialDetails,setParamNameDetails,{ "Color", newValueTooltip } } })
->Attribute(AZ::Script::Attributes::ToolTip, setMaterialParamTooltip)
->Method("SetParamNumber", &MaterialHandleFunctions::SetParamFloat, // Using "ParamNumber" instead of "ParamFloat" because in Script Canvas all primitives are just "numbers"
{ { setMaterialDetails,setParamNameDetails,{ "Number", newValueTooltip } } })
->Attribute(AZ::Script::Attributes::ToolTip, setMaterialParamTooltip)
->Method("GetParamVector4", &MaterialHandleFunctions::GetParamVector4, getMaterialParamArgs)
->Attribute(AZ::Script::Attributes::ToolTip, getMaterialParamTooltip)
->Method("GetParamVector3", &MaterialHandleFunctions::GetParamVector3, getMaterialParamArgs)
->Attribute(AZ::Script::Attributes::ToolTip, getMaterialParamTooltip)
->Method("GetParamColor", &MaterialHandleFunctions::GetParamColor, getMaterialParamArgs)
->Attribute(AZ::Script::Attributes::ToolTip, getMaterialParamTooltip)
->Method("GetParamNumber", &MaterialHandleFunctions::GetParamFloat, getMaterialParamArgs) // Using "ParamNumber" instead of "ParamFloat" because in Script Canvas all primitives are just "numbers"
->Attribute(AZ::Script::Attributes::ToolTip, getMaterialParamTooltip)
;
}
}
@@ -1,265 +0,0 @@
/*
* 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 "LmbrCentral_precompiled.h"
#include <AzCore/IO/GenericStreams.h>
#include <AzFramework/Asset/SimpleAsset.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/Asset/AssetSystemBus.h>
#include <AzCore/std/parallel/binary_semaphore.h>
#include <LmbrCentral/Rendering/MeshAsset.h>
#include "MeshAssetHandler.h"
#include <CryFile.h>
#include <I3DEngine.h>
namespace LmbrCentral
{
//////////////////////////////////////////////////////////////////////////
const AZStd::string MeshAssetHandlerHelper::s_assetAliasToken = "@assets@/";
// what mesh do we use as a placeholder when its currently busy compiling?
static const char* g_meshCompilingSubstituteAsset = "engineassets/objects/default.cgf";
MeshAssetHandlerHelper::MeshAssetHandlerHelper()
: m_asyncLoadCvar(nullptr)
{
}
void MeshAssetHandlerHelper::StripAssetAlias(const char*& assetPath)
{
const size_t assetAliasTokenLen = s_assetAliasToken.size() - 1;
if (0 == strncmp(assetPath, s_assetAliasToken.c_str(), assetAliasTokenLen))
{
assetPath += assetAliasTokenLen;
}
}
ICVar* MeshAssetHandlerHelper::GetAsyncLoadCVar()
{
if (!m_asyncLoadCvar)
{
m_asyncLoadCvar = gEnv->pConsole->GetCVar(s_meshAssetHandler_AsyncCvar);
}
return m_asyncLoadCvar;
}
//////////////////////////////////////////////////////////////////////////
// Static Mesh Asset Handler
//////////////////////////////////////////////////////////////////////////
void AsyncStatObjLoadCallback(const AZ::Data::Asset<MeshAsset>& asset, _smart_ptr<IStatObj> statObj)
{
if (statObj)
{
asset.Get()->m_statObj = statObj;
}
else
{
#if defined(AZ_ENABLE_TRACING)
AZStd::string assetDescription = asset.ToString<AZStd::string>();
AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetDescription, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset.GetId());
AZ_Error("MeshAssetHandler", false, "Failed to load mesh asset %s", assetDescription.c_str());
#endif // AZ_ENABLE_TRACING
}
}
MeshAssetHandler::~MeshAssetHandler()
{
Unregister();
}
AZ::Data::AssetPtr MeshAssetHandler::CreateAsset([[maybe_unused]] const AZ::Data::AssetId& id, const AZ::Data::AssetType& type)
{
(void)type;
AZ_Assert(type == AZ::AzTypeInfo<MeshAsset>::Uuid(), "Invalid asset type! We handle only 'MeshAsset'");
return aznew MeshAsset();
}
AZ::Data::AssetId MeshAssetHandler::AssetMissingInCatalog([[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset)
{
// if tracing is disabled, we are likely in a situation where we specifically don't want any diagnostic information or "errors" to appear
// so in that case, don't load anything, don't substitute anything, don't escalate anything, just let the empty blank asset return.
#if defined(AZ_ENABLE_TRACING)
if (asset.GetId().IsValid())
{
// find out whether its still compiling or it will never be available because its source file is missing.
// this also escalates it, if found, to the top of the build queue:
AzFramework::AssetSystem::AssetStatus statusResult = AzFramework::AssetSystem::AssetStatus_Unknown;
AzFramework::AssetSystemRequestBus::BroadcastResult(statusResult, &AzFramework::AssetSystem::AssetSystemRequests::GetAssetStatusById, asset.GetId());
if ((statusResult == AzFramework::AssetSystem::AssetStatus_Compiling) || (statusResult == AzFramework::AssetSystem::AssetStatus_Queued))
{
// note that we can also check other codes and substitute other meshes if we want, here...
// its currently compiling and will finish soon.
// substitute a placeholder mesh:
if (!m_missingMeshAssetId.IsValid())
{
// substitute the missing mesh assetId so that there's at least something to render that indicates a problem
// in builds where there is no diagnostics or tracing, don't substitute anything, to prefer that there's no visual indication that
// something is wrong in shipped games.
AZ::Data::AssetCatalogRequestBus::BroadcastResult(m_missingMeshAssetId, &AZ::Data::AssetCatalogRequests::GetAssetIdByPath, g_meshCompilingSubstituteAsset, azrtti_typeid<MeshAsset>(), false);
AZ_Error("Mesh Asset Handler", m_missingMeshAssetId.IsValid(), "Attempted to substitute %s for a missing asset, but it is also missing!", g_meshCompilingSubstituteAsset);
}
if (m_missingMeshAssetId.IsValid())
{
AZ_TracePrintf("MeshAssetHandler", " - substituting with default asset ID %s\n", m_missingMeshAssetId.ToString<AZStd::string>().c_str());
// substitute the missing mesh asset.
return m_missingMeshAssetId;
}
}
}
#endif // defined(AZ_ENABLE_TRACING)
// otherwise, if we get here, it means that either it was truly missing, in which case let an error occur, or the missing default substitute asset
// is also itself missing!
return AZ::Data::AssetId();
}
void MeshAssetHandler::GetCustomAssetStreamInfoForLoad(AZ::Data::AssetStreamInfo& streamInfo)
{
// The StatObj system only takes in a file name for loading, not a memory buffer.
// If we set our stream data length to 0, the asset system will skip any file I/O for reading the data, and will instead
// go directly into the AssetHandler for processing.
streamInfo.m_dataLen = 0;
}
AZ::Data::AssetHandler::LoadResult MeshAssetHandler::LoadAssetData(
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
const AZ::Data::AssetFilterCB& /*assetLoadFilterCB*/)
{
const char* assetPath = stream->GetFilename();
AZ_Assert(asset.GetType() == AZ::AzTypeInfo<MeshAsset>::Uuid(), "Invalid asset type! We only load 'MeshAsset'");
if (MeshAsset* meshAsset = asset.GetAs<MeshAsset>())
{
AZ_Assert(!meshAsset->m_statObj.get(), "Attempting to create static mesh without cleaning up the old one.");
// Strip the alias. StatObj instances are stored in a dictionary by their path,
// so to share instances with legacy cry entities, we need to use the same un-aliased format.
StripAssetAlias(assetPath);
// Temporary cvar guard while async loading of legacy mesh formats is stabilized.
ICVar* cvar = GetAsyncLoadCVar();
if (!cvar || cvar->GetIVal() == 0)
{
if (gEnv->mMainThreadId != CryGetCurrentThreadId())
{
AZStd::binary_semaphore signaller;
auto callback = [&asset, &signaller](IStatObj* obj)
{
AsyncStatObjLoadCallback(asset, obj);
signaller.release();
};
gEnv->p3DEngine->LoadStatObjAsync(callback, assetPath);
signaller.acquire();
}
else
{
AsyncStatObjLoadCallback(asset, gEnv->p3DEngine->LoadStatObjAutoRef(assetPath));
}
}
else
{
_smart_ptr<IStatObj> statObj = gEnv->p3DEngine->LoadStatObjAutoRef(assetPath);
if (statObj)
{
meshAsset->m_statObj = statObj;
}
else
{
#if defined(AZ_ENABLE_TRACING)
AZStd::string assetDescription = asset.GetId().ToString<AZStd::string>();
AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetDescription, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, asset.GetId());
AZ_Error("MeshAssetHandler", false, "Failed to load mesh asset \"%s\".", assetDescription.c_str());
#endif // AZ_ENABLE_TRACING
}
}
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
}
return AZ::Data::AssetHandler::LoadResult::Error;
}
void MeshAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr)
{
delete ptr;
}
void MeshAssetHandler::GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes)
{
assetTypes.push_back(AZ::AzTypeInfo<MeshAsset>::Uuid());
}
void MeshAssetHandler::Register()
{
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!");
AZ::Data::AssetManager::Instance().RegisterHandler(this, AZ::AzTypeInfo<MeshAsset>::Uuid());
AZ::AssetTypeInfoBus::Handler::BusConnect(AZ::AzTypeInfo<MeshAsset>::Uuid());
}
void MeshAssetHandler::Unregister()
{
AZ::AssetTypeInfoBus::Handler::BusDisconnect(AZ::AzTypeInfo<MeshAsset>::Uuid());
if (AZ::Data::AssetManager::IsReady())
{
AZ::Data::AssetManager::Instance().UnregisterHandler(this);
}
}
AZ::Data::AssetType MeshAssetHandler::GetAssetType() const
{
return AZ::AzTypeInfo<MeshAsset>::Uuid();
}
const char* MeshAssetHandler::GetAssetTypeDisplayName() const
{
return "Static Mesh";
}
const char* MeshAssetHandler::GetGroup() const
{
return "Geometry";
}
const char* MeshAssetHandler::GetBrowserIcon() const
{
return "Icons/Components/StaticMesh.svg";
}
AZ::Uuid MeshAssetHandler::GetComponentTypeId() const
{
return AZ::Uuid("{FC315B86-3280-4D03-B4F0-5553D7D08432}");
}
void MeshAssetHandler::GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions)
{
extensions.push_back(CRY_GEOMETRY_FILE_EXT);
}
} // namespace LmbrCentral
@@ -1,97 +0,0 @@
/*
* 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/Asset/AssetCommon.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/Asset/AssetTypeInfoBus.h>
struct ICVar;
namespace LmbrCentral
{
static const char* s_meshAssetHandler_AsyncCvar = "az_Asset_EnableAsyncMeshLoading";
/**
* Base class for mesh asset handlers. Contains shared utilities and functionality.
*/
class MeshAssetHandlerHelper
{
public:
MeshAssetHandlerHelper();
protected:
/**
* Removes the asset alias from a string
*
* StatObjs, CharacterInstances and GeometryCaches are stored in
* dictionaries by their path which is not aliased like the new AZ systems.
* To look up mesh instances we need the un-aliased path.
*
* This method assumes that the alias will be at the beginning of the string.
*
* @param assetPath The asset path string to remove the alias from
*/
void StripAssetAlias(const char*& assetPath);
static const AZStd::string s_assetAliasToken; //< The token used to strip the asset alias in StripAssetAlias
ICVar* GetAsyncLoadCVar();
ICVar* m_asyncLoadCvar;
};
/**
* Handler for static mesh assets (cgf).
*/
class MeshAssetHandler
: public AZ::Data::AssetHandler
, public AZ::AssetTypeInfoBus::Handler
, private MeshAssetHandlerHelper
{
public:
AZ_CLASS_ALLOCATOR(MeshAssetHandler, AZ::SystemAllocator, 0);
~MeshAssetHandler() override;
//////////////////////////////////////////////////////////////////////////////////////////////
// AZ::Data::AssetHandler
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override;
void GetCustomAssetStreamInfoForLoad(AZ::Data::AssetStreamInfo& streamInfo) override;
AZ::Data::AssetHandler::LoadResult LoadAssetData(
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
const AZ::Data::AssetFilterCB& assetLoadFilterCB) override;
AZ::Data::AssetId AssetMissingInCatalog(const AZ::Data::Asset<AZ::Data::AssetData>& asset) override;
void DestroyAsset(AZ::Data::AssetPtr ptr) override;
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override;
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
// AZ::AssetTypeInfoBus::Handler
AZ::Data::AssetType GetAssetType() const override;
const char* GetAssetTypeDisplayName() const override;
const char* GetGroup() const override;
const char* GetBrowserIcon() const override;
AZ::Uuid GetComponentTypeId() const override;
void GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions) override;
//////////////////////////////////////////////////////////////////////////////////////////////
void Register();
void Unregister();
AZ::Data::AssetId m_missingMeshAssetId;
};
} // namespace LmbrCentral
File diff suppressed because it is too large Load Diff
@@ -1,393 +0,0 @@
/*
* 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/Component.h>
#include <AzCore/Component/ComponentBus.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <IEntityRenderState.h>
#include <LmbrCentral/Rendering/MaterialOwnerBus.h>
#include <LmbrCentral/Rendering/MeshComponentBus.h>
#include <LmbrCentral/Rendering/MeshModificationBus.h>
#include <LmbrCentral/Rendering/RenderNodeBus.h>
#include <LmbrCentral/Rendering/MaterialAsset.h>
#include <LmbrCentral/Rendering/MeshAsset.h>
#include <LmbrCentral/Rendering/RenderBoundsBus.h>
#include <AzFramework/Entity/EntityContext.h>
#include <AzFramework/Render/GeometryIntersectionBus.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzFramework/Visibility/BoundsBus.h>
namespace LmbrCentral
{
class MaterialOwnerRequestBusHandlerImpl;
/*!
* RenderNode implementation responsible for integrating with the renderer.
* The node owns render flags, the mesh instance, and the render transform.
*/
class MeshComponentRenderNode
: public IRenderNode
, public AZ::TransformNotificationBus::Handler
, public AZ::Data::AssetBus::Handler
{
friend class EditorMeshComponent;
public:
using MaterialPtr = _smart_ptr < IMaterial > ;
using MeshPtr = _smart_ptr < IStatObj > ;
AZ_TYPE_INFO(MeshComponentRenderNode, "{46FF2BC4-BEF9-4CC4-9456-36C127C310D7}");
MeshComponentRenderNode();
~MeshComponentRenderNode() override;
void CopyPropertiesTo(MeshComponentRenderNode& rhs) const;
//! Notifies render node which entity owns it, for subscribing to transform
//! bus, etc.
void AttachToEntity(AZ::EntityId id);
//! Returns true after all required assets are loaded
bool IsReady() const override;
//! Instantiate mesh instance.
void CreateMesh();
//! Destroy mesh instance.
void DestroyMesh();
//! Returns true if the node has geometry assigned.
bool HasMesh() const;
//! Assign a new mesh asset
void SetMeshAsset(const AZ::Data::AssetId& id);
//! Get the mesh asset
AZ::Data::Asset<AZ::Data::AssetData> GetMeshAsset() { return m_meshAsset; }
//! Invoked in the editor when the user assigns a new asset.
void OnAssetPropertyChanged();
//! Render the mesh
void RenderMesh(const struct SRendParams& inRenderParams, const struct SRenderingPassInfo& passInfo);
//! Updates the render node's world transform based on the entity's.
void UpdateWorldTransform(const AZ::Transform& entityTransform);
//! Computes world-space AABB.
AZ::Aabb CalculateWorldAABB() const;
//! Computes local-space AABB.
AZ::Aabb CalculateLocalAABB() const;
//////////////////////////////////////////////////////////////////////////
// AZ::Data::AssetBus::Handler
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AZ::TransformNotificationBus::Handler interface implementation
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// IRenderNode interface implementation
void Render(const struct SRendParams& inRenderParams, const struct SRenderingPassInfo& passInfo) override;
bool GetLodDistances(const SFrameLodInfo& frameLodInfo, float* distances) const override;
float GetFirstLodDistance() const override { return m_lodDistance; }
EERType GetRenderNodeType() override;
bool CanExecuteRenderAsJob() override;
const char* GetName() const override;
const char* GetEntityClassName() const override;
Vec3 GetPos(bool bWorldOnly = true) const override;
const AABB GetBBox() const override;
void SetBBox(const AABB& WSBBox) override;
void OffsetPosition(const Vec3& delta) override;
void SetMaterial(_smart_ptr<IMaterial> pMat) override;
_smart_ptr<IMaterial> GetMaterial(Vec3* pHitPos = nullptr) override;
_smart_ptr<IMaterial> GetMaterialOverride() override;
IStatObj* GetEntityStatObj(unsigned int nPartId = 0, unsigned int nSubPartId = 0, Matrix34A* pMatrix = nullptr, bool bReturnOnlyVisible = false) override;
_smart_ptr<IMaterial> GetEntitySlotMaterial(unsigned int nPartId, bool bReturnOnlyVisible = false, bool* pbDrawNear = nullptr) override;
float GetMaxViewDist() override;
void GetMemoryUsage(class ICrySizer* pSizer) const override;
AZ::EntityId GetEntityId() override { return m_renderOptions.m_attachedToEntityId; }
float GetUniformScale() override;
float GetColumnScale(int column) override;
//////////////////////////////////////////////////////////////////////////
//! Invoked in the editor when a property requiring render state refresh
//! has changed.
void RefreshRenderState();
//! Set/get auxiliary render flags.
void SetAuxiliaryRenderFlags(uint32 flags);
uint32 GetAuxiliaryRenderFlags() const { return m_auxiliaryRenderFlags; }
void UpdateAuxiliaryRenderFlags(bool on, uint32 mask);
void SetVisible(bool isVisible);
bool GetVisible();
static void Reflect(AZ::ReflectContext* context);
static float GetDefaultMaxViewDist();
static AZ::Uuid GetRenderOptionsUuid() { return AZ::AzTypeInfo<MeshRenderOptions>::Uuid(); }
//! Registers or unregisters our render node with the render.
void RegisterWithRenderer(bool registerWithRenderer);
bool IsRegisteredWithRenderer() const { return m_isRegisteredWithRenderer; }
//! This function caches off the static flag stat of the transform;
void SetTransformStaticState(bool isStatic);
const AZ::Transform& GetTransform() const;
void SetContextId(AzFramework::EntityContextId contextId) { m_contextId = contextId; }
protected:
//! Calculates base LOD distance based on mesh characteristics.
//! We do this each time the mesh resource changes.
void UpdateLodDistance(const SFrameLodInfo& frameLodInfo);
//! Computes desired LOD level for the assigned mesh instance.
CLodValue ComputeLOD(int wantedLod, const SRenderingPassInfo& passInfo);
//! Computes the entity-relative (local space) bounding box for
//! the assigned mesh.
virtual void UpdateLocalBoundingBox();
//! Updates the world-space bounding box and world space transform
//! for the assigned mesh.
void UpdateWorldBoundingBox();
//! Applies configured render options to the render node.
void ApplyRenderOptions();
//! Populates the render mesh from the mesh asset
void BuildRenderMesh();
class MeshRenderOptions
{
public:
AZ_TYPE_INFO(MeshRenderOptions, "{EFF77BEB-CB99-44A3-8F15-111B0200F50D}")
MeshRenderOptions();
float m_opacity; //!< Alpha/opacity value for rendering.
float m_maxViewDist; //!< Maximum draw distance.
float m_viewDistMultiplier; //!< Adjusts max view distance. If 1.0 then default max view distance is used.
AZ::u32 m_lodRatio; //!< Controls LOD distance ratio.
bool m_useVisAreas; //!< Allow VisAreas to control this component's visibility.
bool m_castShadows; //!< Casts shadows.
bool m_lodBoundingBoxBased; //!< LOD based on Bounding Boxes.
bool m_rainOccluder; //!< Occludes raindrops.
bool m_affectNavmesh; //!< Cuts out of the navmesh.
bool m_affectDynamicWater; //!< Affects dynamic water (ripples).
bool m_acceptDecals; //!< Accepts decals.
bool m_receiveWind; //!< Receives wind.
bool m_visibilityOccluder; //!< Appropriate for visibility occluding.
bool m_dynamicMesh; // Mesh can change or deform independent of transform
bool m_hasStaticTransform;
bool m_affectGI; //!< Mesh affects Global Illumination.
//! The Id of the entity we're associated with, for bus subscription.
//Moved from render mesh to this struct for serialization/reflection utility
AZ::EntityId m_attachedToEntityId;
AZStd::function<void()> m_changeCallback;
// Minor property changes don't require refreshing/rebuilding the property tree since no other properties
// are shown/hidden as a result of a change.
AZ::u32 OnMinorChanged()
{
if (m_changeCallback)
{
m_changeCallback();
}
return AZ::Edit::PropertyRefreshLevels::None;
}
AZ::u32 OnMajorChanged()
{
if (m_changeCallback)
{
m_changeCallback();
}
return AZ::Edit::PropertyRefreshLevels::EntireTree;
}
//Returns true if the transform is static and the mesh is not deformable.
bool IsStatic() const;
bool AffectsGi() const;
AZ::Crc32 StaticPropertyVisibility() const;
static void Reflect(AZ::ReflectContext* context);
private:
static bool VersionConverter(AZ::SerializeContext& context,
AZ::SerializeContext::DataElementNode& classElement);
};
//! Should be visible.
bool m_visible;
//! User-specified material override.
AzFramework::SimpleAssetReference<MaterialAsset> m_material;
//! Render flags/options.
MeshRenderOptions m_renderOptions;
//! Currently-assigned material. Null if no material is manually assigned.
MaterialPtr m_materialOverride;
//! World and render transforms.
//! These are equivalent, but for different math libraries.
AZ::Transform m_worldTransform;
Matrix34 m_renderTransform;
//! Local and world bounding boxes.
AABB m_localBoundingBox;
AABB m_worldBoundingBox;
//! Additional render flags -- for special editor behavior, etc.
uint32 m_auxiliaryRenderFlags;
//! Remember which flags have ever been toggled externally so that we can shut them off
uint32 m_auxiliaryRenderFlagsHistory;
//! Reference to current asset
AZ::Data::Asset<MeshAsset> m_meshAsset;
MeshPtr m_statObj;
//! Computed LOD distance.
float m_lodDistance;
//! Computed first LOD distance (the following are multiplies of the index)
float m_lodDistanceScaled;
//! Scale we need to multiply the distance by.
float m_lodDistanceScaleValue;
//! Identifies whether we've already registered our node with the renderer.
bool m_isRegisteredWithRenderer;
//! Tracks if the object was moved so we can notify the renderer.
bool m_objectMoved;
// Helper to store indices for meshes to be modified by other components.
MeshModificationRequestHelper m_modificationHelper;
// EntityContext of the component
AzFramework::EntityContextId m_contextId;
};
class MeshComponent
: public AZ::Component
, public MeshComponentRequestBus::Handler
, public MaterialOwnerRequestBus::Handler
, public RenderNodeRequestBus::Handler
, public LegacyMeshComponentRequestBus::Handler
, public AzFramework::BoundsRequestBus::Handler
, public AzFramework::RenderGeometry::IntersectionRequestBus::Handler
{
public:
friend class EditorMeshComponent;
AZ_COMPONENT(MeshComponent, "{2F4BAD46-C857-4DCB-A454-C412DE67852A}");
MeshComponent();
~MeshComponent() override;
AZ_DISABLE_COPY_MOVE(MeshComponent);
// AZ::Component overrides ...
void Activate() override;
void Deactivate() override;
// BoundsRequestBus and MeshComponentRequestBus overrides ...
AZ::Aabb GetWorldBounds() override;
AZ::Aabb GetLocalBounds() override;
// MeshComponentRequestBus overrides ...
void SetMeshAsset(const AZ::Data::AssetId& id) override;
AZ::Data::Asset<AZ::Data::AssetData> GetMeshAsset() override { return m_meshRenderNode.GetMeshAsset(); }
void SetVisibility(bool newVisibility) override;
bool GetVisibility() override;
// MaterialOwnerRequestBus overrides ...
bool IsMaterialOwnerReady() override;
void SetMaterial(_smart_ptr<IMaterial>) override;
_smart_ptr<IMaterial> GetMaterial() override;
void SetMaterialHandle(const MaterialHandle& materialHandle) override;
MaterialHandle GetMaterialHandle() override;
void SetMaterialParamVector4(const AZStd::string& /*name*/, const AZ::Vector4& /*value*/, int /*materialId = 1*/) override;
void SetMaterialParamVector3(const AZStd::string& /*name*/, const AZ::Vector3& /*value*/, int /*materialId = 1*/) override;
void SetMaterialParamColor(const AZStd::string& /*name*/, const AZ::Color& /*value*/, int /*materialId = 1*/) override;
void SetMaterialParamFloat(const AZStd::string& /*name*/, float /*value*/, int /*materialId = 1*/) override;
AZ::Vector4 GetMaterialParamVector4(const AZStd::string& /*name*/, int /*materialId = 1*/) override;
AZ::Vector3 GetMaterialParamVector3(const AZStd::string& /*name*/, int /*materialId = 1*/) override;
AZ::Color GetMaterialParamColor(const AZStd::string& /*name*/, int /*materialId = 1*/) override;
float GetMaterialParamFloat(const AZStd::string& /*name*/, int /*materialId = 1*/) override;
// RenderNodeRequestBus overrides ...
IRenderNode* GetRenderNode() override;
float GetRenderNodeRequestBusOrder() const override;
static const float s_renderNodeRequestBusOrder;
// MeshComponentRequestBus overrides ...
IStatObj* GetStatObj() override;
// IntersectionRequestBus overrides ...
AzFramework::RenderGeometry::RayResult RenderGeometryIntersect(const AzFramework::RenderGeometry::RayRequest& ray) override;
protected:
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("MeshService", 0x71d8a455));
provided.push_back(AZ_CRC("LegacyMeshService", 0xb462a299));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("MeshService", 0x71d8a455));
incompatible.push_back(AZ_CRC("LegacyMeshService", 0xb462a299));
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
}
static void Reflect(AZ::ReflectContext* context);
void RequireSendingRenderMeshForEditing(size_t lodIndex, size_t primitiveIndex);
void NoRenderMeshesForEditing();
//////////////////////////////////////////////////////////////////////////
// Reflected Data
MeshComponentRenderNode m_meshRenderNode;
MaterialOwnerRequestBusHandlerImpl* m_materialBusHandler;
};
} // namespace LmbrCentral
@@ -1,293 +0,0 @@
/*
* 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 "LmbrCentral_precompiled.h"
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/Asset/AssetSystemBus.h>
#include <AzTest/AzTest.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <Rendering/MeshAssetHandler.h>
#include "Source/Rendering/EditorMeshComponent.h"
namespace UnitTest
{
// base physical entity which can be derived from to detect other specific use-cases
struct PhysicalEntityPlaceHolder
: public IPhysicalEntity
{
pe_type GetType() const override { return PE_NONE; }
int AddRef() override { return 0; }
int Release() override { return 0; }
int SetParams([[maybe_unused]] const pe_params* params, [[maybe_unused]] int bThreadSafe = 0) override { return 0; }
int GetParams([[maybe_unused]] pe_params* params) const override { return 0; }
int GetStatus([[maybe_unused]] pe_status* status) const override { return 0; }
int Action(const pe_action*, [[maybe_unused]] int bThreadSafe = 0) override { return 0; }
int AddGeometry([[maybe_unused]] phys_geometry* pgeom, [[maybe_unused]] pe_geomparams* params, [[maybe_unused]] int id = -1, [[maybe_unused]] int bThreadSafe = 0) override { return 0; }
void RemoveGeometry([[maybe_unused]] int id, [[maybe_unused]] int bThreadSafe = 0) override {}
PhysicsForeignData GetForeignData([[maybe_unused]] int itype = 0) const override { return PhysicsForeignData{}; }
int GetiForeignData() const override { return 0; }
int GetStateSnapshot([[maybe_unused]] class CStream& stm, [[maybe_unused]] float time_back = 0, [[maybe_unused]] int flags = 0) override { return 0; }
int GetStateSnapshot([[maybe_unused]] TSerialize ser, [[maybe_unused]] float time_back = 0, [[maybe_unused]] int flags = 0) override { return 0; }
int SetStateFromSnapshot([[maybe_unused]] class CStream& stm, [[maybe_unused]] int flags = 0) override { return 0; }
int PostSetStateFromSnapshot() override { return 0; }
unsigned int GetStateChecksum() override { return 0; }
void SetNetworkAuthority([[maybe_unused]] int authoritive = -1, [[maybe_unused]] int paused = -1) override {}
int SetStateFromSnapshot([[maybe_unused]] TSerialize ser, [[maybe_unused]] int flags = 0) override { return 0; }
int SetStateFromTypedSnapshot([[maybe_unused]] TSerialize ser, [[maybe_unused]] int type, [[maybe_unused]] int flags = 0) override { return 0; }
int GetStateSnapshotTxt([[maybe_unused]] char* txtbuf, [[maybe_unused]] int szbuf, [[maybe_unused]] float time_back = 0) override { return 0; }
void SetStateFromSnapshotTxt([[maybe_unused]] const char* txtbuf, [[maybe_unused]] int szbuf) override {}
int DoStep([[maybe_unused]] float time_interval) override { return 0; }
int DoStep([[maybe_unused]] float time_interval, [[maybe_unused]] int iCaller) override { return 0; }
void StartStep([[maybe_unused]] float time_interval) override {}
void StepBack([[maybe_unused]] float time_interval) override {}
void GetMemoryStatistics([[maybe_unused]] ICrySizer* pSizer) const override {}
};
// special test fake to validate incoming pe_params
struct PhysicalEntitySetParamsCheck
: public PhysicalEntityPlaceHolder
{
int SetParams(const pe_params* params, [[maybe_unused]] int bThreadSafe = 0) override
{
if (params->type == pe_params_pos::type_id)
{
pe_params_pos* params_pos = (pe_params_pos*)params;
Vec3 s;
if (Matrix34* m34 = params_pos->pMtx3x4)
{
s.Set(m34->GetColumn(0).len(), m34->GetColumn(1).len(), m34->GetColumn(2).len());
Matrix33 m33(m34->GetColumn(0) / s.x, m34->GetColumn(1) / s.y, m34->GetColumn(2) / s.z);
// ensure passed in params_pos->pMtx3x4 is orthonormal
// ref - see Cry_Quat.h - explicit ILINE Quat_tpl<F>(const Matrix33_tpl<F>&m)
m_isOrthonormal = m33.IsOrthonormalRH(0.1f);
}
}
return 0;
}
bool m_isOrthonormal = false;
};
class TestEditorMeshComponent
: public LmbrCentral::EditorMeshComponent
{
public:
AZ_EDITOR_COMPONENT(TestEditorMeshComponent, "{6C6B593A-1946-4239-AE16-E8B96D9835E5}", LmbrCentral::EditorMeshComponent)
static void Reflect(AZ::ReflectContext* context);
TestEditorMeshComponent() = default;
};
void TestEditorMeshComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<TestEditorMeshComponent>()
->Version(0);
}
}
class EditorMeshComponentTestFixture
: public ToolsApplicationFixture
{
AZStd::unique_ptr<AZ::ComponentDescriptor> m_testMeshComponentDescriptor;
public:
void SetUpEditorFixtureImpl() override
{
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
m_testMeshComponentDescriptor =
AZStd::unique_ptr<AZ::ComponentDescriptor>(TestEditorMeshComponent::CreateDescriptor());
m_testMeshComponentDescriptor->Reflect(serializeContext);
}
void TearDownEditorFixtureImpl() override
{
m_testMeshComponentDescriptor.reset();
}
};
struct MeshAssetHandlerFixture
: ScopedAllocatorSetupFixture
{
protected:
void SetUp() override
{
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
AZ::Data::AssetManager::Create(AZ::Data::AssetManager::Descriptor());
AZ::Data::AssetManager::Instance().SetAssetInfoUpgradingEnabled(false);
m_handler.Register();
}
void TearDown() override
{
m_handler.Unregister();
AZ::Data::AssetManager::Destroy();
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
}
LmbrCentral::MeshAssetHandler m_handler;
};
struct MockAssetSystemRequestHandler
: AzFramework::AssetSystemRequestBus::Handler
{
MockAssetSystemRequestHandler()
{
BusConnect();
}
~MockAssetSystemRequestHandler()
{
BusDisconnect();
}
AzFramework::AssetSystem::AssetStatus GetAssetStatusById([[maybe_unused]] const AZ::Data::AssetId& assetId) override
{
m_statusRequest = true;
return AzFramework::AssetSystem::AssetStatus_Queued;
}
MOCK_METHOD1(CompileAssetSync, AzFramework::AssetSystem::AssetStatus (const AZStd::string&));
MOCK_METHOD1(CompileAssetSync_FlushIO, AzFramework::AssetSystem::AssetStatus (const AZStd::string&));
MOCK_METHOD1(CompileAssetSyncById, AzFramework::AssetSystem::AssetStatus (const AZ::Data::AssetId&));
MOCK_METHOD1(CompileAssetSyncById_FlushIO, AzFramework::AssetSystem::AssetStatus (const AZ::Data::AssetId&));
MOCK_METHOD4(ConfigureSocketConnection, bool (const AZStd::string&, const AZStd::string&, const AZStd::string&, const AZStd::string&));
MOCK_METHOD1(Connect, bool (const char*));
MOCK_METHOD2(ConnectWithTimeout, bool (const char*, AZStd::chrono::duration<float>));
MOCK_METHOD0(Disconnect, bool ());
MOCK_METHOD1(EscalateAssetBySearchTerm, bool (AZStd::string_view));
MOCK_METHOD1(EscalateAssetByUuid, bool (const AZ::Uuid&));
MOCK_METHOD0(GetAssetProcessorPingTimeMilliseconds, float ());
MOCK_METHOD1(GetAssetStatus, AzFramework::AssetSystem::AssetStatus (const AZStd::string&));
MOCK_METHOD1(GetAssetStatus_FlushIO, AzFramework::AssetSystem::AssetStatus (const AZStd::string&));
MOCK_METHOD2(GetAssetStatusSearchType, AzFramework::AssetSystem::AssetStatus(const AZStd::string&, int));
MOCK_METHOD2(GetAssetStatusSearchType_FlushIO, AzFramework::AssetSystem::AssetStatus(const AZStd::string&, int));
MOCK_METHOD1(GetAssetStatusById_FlushIO, AzFramework::AssetSystem::AssetStatus (const AZ::Data::AssetId&));
MOCK_METHOD3(GetUnresolvedProductReferences, void (AZ::Data::AssetId, AZ::u32&, AZ::u32&));
MOCK_METHOD0(SaveCatalog, bool ());
MOCK_METHOD1(SetAssetProcessorIP, void (const AZStd::string&));
MOCK_METHOD1(SetAssetProcessorPort, void (AZ::u16));
MOCK_METHOD1(SetBranchToken, void (const AZStd::string&));
MOCK_METHOD1(SetProjectName, void (const AZStd::string&));
MOCK_METHOD0(ShowAssetProcessor, void ());
MOCK_METHOD1(ShowInAssetProcessor, void (const AZStd::string&));
MOCK_METHOD1(WaitUntilAssetProcessorReady, bool(AZStd::chrono::duration<float>));
MOCK_METHOD1(WaitUntilAssetProcessorConnected, bool(AZStd::chrono::duration<float>));
MOCK_METHOD1(WaitUntilAssetProcessorDisconnected, bool(AZStd::chrono::duration<float>));
MOCK_METHOD0(AssetProcessorIsReady, bool());
MOCK_METHOD0(ConnectedWithAssetProcessor, bool());
MOCK_METHOD0(DisconnectedWithAssetProcessor, bool());
MOCK_METHOD0(NegotiationWithAssetProcessorFailed, bool());
MOCK_METHOD0(StartDisconnectingAssetProcessor, void());
MOCK_METHOD1(EstablishAssetProcessorConnection, bool(const AzFramework::AssetSystem::ConnectionSettings&));
MOCK_METHOD3(AppendAssetToPrioritySet, bool (const AZStd::string&, const AZ::Uuid&, uint32_t));
MOCK_METHOD3(AppendAssetsToPrioritySet, bool (const AZStd::string&, const AZStd::vector<AZ::Uuid>&, uint32_t));
MOCK_METHOD2(RemoveAssetFromPrioritySet, bool (const AZStd::string&, const AZ::Uuid&));
MOCK_METHOD2(RemoveAssetsFromPrioritySet, bool (const AZStd::string&, const AZStd::vector<AZ::Uuid>&));
bool m_statusRequest = false;
};
struct MockCatalog
: AZ::Data::AssetCatalogRequestBus::Handler
{
MockCatalog()
{
BusConnect();
}
~MockCatalog()
{
BusDisconnect();
}
AZ::Data::AssetId GetAssetIdByPath(const char*, const AZ::Data::AssetType&, bool) override
{
m_generatedId = AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 1234);
return m_generatedId;
}
MOCK_METHOD1(GetAssetInfoById, AZ::Data::AssetInfo (const AZ::Data::AssetId&));
MOCK_METHOD1(AddAssetType, void (const AZ::Data::AssetType&));
MOCK_METHOD1(AddDeltaCatalog, bool (AZStd::shared_ptr<AzFramework::AssetRegistry>));
MOCK_METHOD1(AddExtension, void (const char*));
MOCK_METHOD0(ClearCatalog, void ());
MOCK_METHOD5(CreateBundleManifest, bool (const AZStd::string&, const AZStd::vector<AZStd::string>&, const AZStd::string&, int, const AZStd::vector<AZStd::string>&));
MOCK_METHOD2(CreateDeltaCatalog, bool (const AZStd::vector<AZStd::string>&, const AZStd::string&));
MOCK_METHOD0(DisableCatalog, void ());
MOCK_METHOD1(EnableCatalogForAsset, void (const AZ::Data::AssetType&));
MOCK_METHOD3(EnumerateAssets, void (BeginAssetEnumerationCB, AssetEnumerationCB, EndAssetEnumerationCB));
MOCK_METHOD1(GenerateAssetIdTEMP, AZ::Data::AssetId (const char*));
MOCK_METHOD1(GetAllProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> (const AZ::Data::AssetId&));
MOCK_METHOD3(GetAllProductDependenciesFilter, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> (const AZ::Data::AssetId&, const AZStd::unordered_set<AZ::Data::AssetId>&, const AZStd::vector<AZStd::string>&));
MOCK_METHOD1(GetAssetPathById, AZStd::string (const AZ::Data::AssetId&));
MOCK_METHOD1(GetDirectProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> (const AZ::Data::AssetId&));
MOCK_METHOD1(GetHandledAssetTypes, void (AZStd::vector<AZ::Data::AssetType>&));
MOCK_METHOD0(GetRegisteredAssetPaths, AZStd::vector<AZStd::string> ());
MOCK_METHOD2(InsertDeltaCatalog, bool (AZStd::shared_ptr<AzFramework::AssetRegistry>, size_t));
MOCK_METHOD2(InsertDeltaCatalogBefore, bool (AZStd::shared_ptr<AzFramework::AssetRegistry>, AZStd::shared_ptr<AzFramework::AssetRegistry>));
MOCK_METHOD1(LoadCatalog, bool (const char*));
MOCK_METHOD2(RegisterAsset, void (const AZ::Data::AssetId&, AZ::Data::AssetInfo&));
MOCK_METHOD1(RemoveDeltaCatalog, bool (AZStd::shared_ptr<AzFramework::AssetRegistry>));
MOCK_METHOD1(SaveCatalog, bool (const char*));
MOCK_METHOD0(StartMonitoringAssets, void ());
MOCK_METHOD0(StopMonitoringAssets, void ());
MOCK_METHOD1(UnregisterAsset, void (const AZ::Data::AssetId&));
AZ::Data::AssetId m_generatedId{};
};
struct MockAssetData
: LmbrCentral::MeshAsset
{
MockAssetData(AZ::Data::AssetId assetId)
{
m_assetId = assetId;
}
};
TEST_F(MeshAssetHandlerFixture, LoadAsset_StillInQueue_LoadsSubstituteAsset)
{
MockAssetSystemRequestHandler assetSystem;
MockCatalog catalog;
AZ::Data::AssetId assetId(AZ::Uuid::CreateRandom(), 0);
AZ::Data::Asset<AZ::Data::AssetData> asset(aznew MockAssetData(assetId), AZ::Data::AssetLoadBehavior::Default);
auto substituteAssetId = m_handler.AssetMissingInCatalog(asset);
ASSERT_TRUE(assetSystem.m_statusRequest);
ASSERT_TRUE(catalog.m_generatedId.IsValid());
ASSERT_EQ(substituteAssetId, catalog.m_generatedId);
}
} // namespace UnitTest
@@ -0,0 +1,54 @@
/*
* 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 <AzCore/Math/Transform.h>
namespace LmbrCentral
{
/*!
* SkeletonHierarchyRequestBus
* Messages serviced by components to provide information about skeletal hierarchies.
*/
class SkeletalHierarchyRequests
: public AZ::ComponentBus
{
public:
/**
* \return Number of joints in the skeleton joint hierarchy.
*/
virtual AZ::u32 GetJointCount() { return 0; }
/**
* \param jointIndex Index of joint whose name should be returned.
* \return Name of the joint at the specified index. Null if joint index is not valid.
*/
virtual const char* GetJointNameByIndex(AZ::u32 /*jointIndex*/) { return nullptr; }
/**
* \param jointName Name of joint whose index should be returned.
* \return Index of the joint with the specified name. -1 if the joint was not found.
*/
virtual AZ::s32 GetJointIndexByName(const char* /*jointName*/) { return 0; }
/**
* \param jointIndex Index of joint whose local-space transform should be returned.
* \return Joint's character-space transform. Identify if joint index was not valid.
*/
virtual AZ::Transform GetJointTransformCharacterRelative(AZ::u32 /*jointIndex*/) { return AZ::Transform::CreateIdentity(); }
};
using SkeletalHierarchyRequestBus = AZ::EBus<SkeletalHierarchyRequests>;
} // namespace LmbrCentral
@@ -1,28 +0,0 @@
/*
* 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/EBus/EBus.h>
namespace LmbrCentral
{
class EditorMeshBusRequests :
public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
virtual bool AddMeshComponentWithAssetId(const AZ::EntityId& targetEntity, const AZ::Uuid& meshAssetId) = 0;
};
using EditorMeshBus = AZ::EBus<EditorMeshBusRequests>;
}
@@ -1,164 +0,0 @@
/*
* 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 <AzCore/Math/Aabb.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Asset/AssetCommon.h>
struct IStatObj;
struct SRenderingPassInfo;
struct SRendParams;
namespace LmbrCentral
{
/*!
* MeshComponentRequestBus
* Messages serviced by the mesh component.
*/
class MeshComponentRequests
: public AZ::ComponentBus
{
public:
/**
* Returns the axis aligned bounding box in world coordinates
*/
virtual AZ::Aabb GetWorldBounds() = 0;
/**
* Returns the axis aligned bounding box in model coordinates
*/
virtual AZ::Aabb GetLocalBounds() = 0;
/**
* Sets the mesh asset for this component
*/
virtual void SetMeshAsset(const AZ::Data::AssetId& id) = 0;
/**
* Returns the asset used by the mesh
*/
virtual AZ::Data::Asset<AZ::Data::AssetData> GetMeshAsset() = 0;
/**
* Returns true if the mesh is currently visible
*/
virtual bool GetVisibility() { return true; }
/**
* Sets the current visibility of the mesh
*/
virtual void SetVisibility([[maybe_unused]] bool isVisible) {}
};
using MeshComponentRequestBus = AZ::EBus<MeshComponentRequests>;
/*!
* SkeletonHierarchyRequestBus
* Messages serviced by components to provide information about skeletal hierarchies.
*/
class SkeletalHierarchyRequests
: public AZ::ComponentBus
{
public:
/**
* \return Number of joints in the skeleton joint hierarchy.
*/
virtual AZ::u32 GetJointCount() { return 0; }
/**
* \param jointIndex Index of joint whose name should be returned.
* \return Name of the joint at the specified index. Null if joint index is not valid.
*/
virtual const char* GetJointNameByIndex(AZ::u32 /*jointIndex*/) { return nullptr; }
/**
* \param jointName Name of joint whose index should be returned.
* \return Index of the joint with the specified name. -1 if the joint was not found.
*/
virtual AZ::s32 GetJointIndexByName(const char* /*jointName*/) { return 0; }
/**
* \param jointIndex Index of joint whose local-space transform should be returned.
* \return Joint's character-space transform. Identify if joint index was not valid.
*/
virtual AZ::Transform GetJointTransformCharacterRelative(AZ::u32 /*jointIndex*/) { return AZ::Transform::CreateIdentity(); }
};
using SkeletalHierarchyRequestBus = AZ::EBus<SkeletalHierarchyRequests>;
/*!
* LegacyMeshComponentRequestBus
* Messages serviced by the mesh component.
*/
class LegacyMeshComponentRequests
: public AZ::ComponentBus
{
public:
virtual IStatObj* GetStatObj() = 0;
};
using LegacyMeshComponentRequestBus = AZ::EBus<LegacyMeshComponentRequests>;
/*!
* MeshComponentNotificationBus
* Events dispatched by the mesh component.
*/
class MeshComponentNotifications
: public AZ::ComponentBus
{
public:
/**
* Notifies listeners the mesh instance has been created.
* \param asset - The asset the mesh instance is based on.
*/
virtual void OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset) { (void)asset; }
/**
* Notifies listeners that the mesh instance has been destroyed.
*/
virtual void OnMeshDestroyed() {}
virtual void OnBoundsReset() {};
/*
* Notifies listeners prior to making the render call
*/
virtual void OnMeshPreRender([[maybe_unused]] const struct SRendParams& inOutRenderParams, [[maybe_unused]] const SRenderingPassInfo& passInfo) {};
/**
* When connecting to this bus if the asset is ready you will immediately get an OnMeshCreated event
**/
template<class Bus>
struct ConnectionPolicy
: public AZ::EBusConnectionPolicy<Bus>
{
static void Connect(typename Bus::BusPtr& busPtr, typename Bus::Context& context, typename Bus::HandlerNode& handler, typename Bus::Context::ConnectLockGuard& connectLock, const typename Bus::BusIdType& id = 0)
{
AZ::EBusConnectionPolicy<Bus>::Connect(busPtr, context, handler, connectLock, id);
AZ::Data::Asset<AZ::Data::AssetData> asset;
EBUS_EVENT_ID_RESULT(asset, id, MeshComponentRequestBus, GetMeshAsset);
if (asset.GetStatus() == AZ::Data::AssetData::AssetStatus::Ready)
{
handler->OnMeshCreated(asset);
}
}
};
};
using MeshComponentNotificationBus = AZ::EBus<MeshComponentNotifications>;
} // namespace LmbrCentral
@@ -12,7 +12,6 @@
#pragma once
#include <LmbrCentral/Rendering/MaterialOwnerBus.h>
#include <LmbrCentral/Rendering/MeshComponentBus.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Math/Color.h>
@@ -28,8 +27,7 @@ namespace LmbrCentral
//! This does not actually inherit the MaterialOwnerRequestBus::Handler interface because it is
//! not intended to subscribe to that bus, but it does provide implementations for all the same functions.
class MaterialOwnerRequestBusHandlerImpl
: public MeshComponentNotificationBus::Handler
, public AZ::TickBus::Handler
: public AZ::TickBus::Handler
, public MaterialOwnerRequestBus::Handler
{
using MaterialPtr = _smart_ptr < IMaterial >;
@@ -57,14 +55,7 @@ namespace LmbrCentral
if (m_renderNode)
{
if (!m_renderNode->IsReady())
{
// Some material owners, in particular MeshComponents, may not be ready upon activation because the
// actual mesh data and default material haven't been loaded yet. Until the RenderNode is ready,
// it's material probably isn't valid.
MeshComponentNotificationBus::Handler::BusConnect(entityId);
}
else
if (m_renderNode->IsReady())
{
// For some material owner types (like DecalComponent), the material is ready immediately. But we can't
// send the event yet because components are still being Activated, so we delay until the first tick.
@@ -81,7 +72,6 @@ namespace LmbrCentral
void Deactivate()
{
m_notificationBus = nullptr;
MeshComponentNotificationBus::Handler::BusDisconnect();
MaterialOwnerRequestBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
}
@@ -300,16 +290,6 @@ namespace LmbrCentral
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// MeshComponentNotificationBus interface implementation
void OnMeshCreated([[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset) override
{
AZ_Assert(IsMaterialOwnerReady(), "Got OnMeshCreated but the RenderNode still isn't ready");
SendReadyEvent();
MeshComponentNotificationBus::Handler::BusDisconnect();
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// TickBus interface implementation
void OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) override
@@ -12,14 +12,11 @@
set(FILES
include/LmbrCentral/Rendering/EditorCameraCorrectionBus.h
include/LmbrCentral/Rendering/EditorLightComponentBus.h
include/LmbrCentral/Rendering/EditorMeshBus.h
include/LmbrCentral/Shape/EditorPolygonPrismShapeComponentBus.h
include/LmbrCentral/Shape/EditorSplineComponentBus.h
include/LmbrCentral/Shape/EditorTubeShapeComponentBus.h
include/LmbrCentral/Component/EditorWrappedComponentBase.h
include/LmbrCentral/Component/EditorWrappedComponentBase.inl
Source/Animation/EditorAttachmentComponent.h
Source/Animation/EditorAttachmentComponent.cpp
Source/Audio/EditorAudioAreaEnvironmentComponent.h
Source/Audio/EditorAudioAreaEnvironmentComponent.cpp
Source/Audio/EditorAudioEnvironmentComponent.h
@@ -40,8 +37,6 @@ set(FILES
Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderComponent.cpp
Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.h
Source/Builders/BenchmarkAssetBuilder/BenchmarkAssetBuilderWorker.cpp
Source/Rendering/EditorMeshComponent.h
Source/Rendering/EditorMeshComponent.cpp
Source/Scripting/EditorLookAtComponent.h
Source/Scripting/EditorLookAtComponent.cpp
Source/Scripting/EditorRandomTimedSpawnerComponent.cpp
@@ -19,7 +19,6 @@ set(FILES
Tests/EditorCompoundShapeComponentTests.cpp
Tests/EditorCylinderShapeComponentTests.cpp
Tests/EditorPolygonPrismShapeComponentTests.cpp
Tests/EditorMeshComponentTests.cpp
Tests/SpawnerComponentTest.cpp
Tests/Builders/CopyDependencyBuilderTest.cpp
Tests/Builders/SliceBuilderTests.cpp
@@ -17,6 +17,7 @@ set(FILES
include/LmbrCentral/Ai/NavigationSystemBus.h
include/LmbrCentral/Ai/NavigationSeedBus.h
include/LmbrCentral/Animation/AttachmentComponentBus.h
include/LmbrCentral/Animation/SkeletalHierarchyRequestBus.h
include/LmbrCentral/Audio/AudioEnvironmentComponentBus.h
include/LmbrCentral/Audio/AudioListenerComponentBus.h
include/LmbrCentral/Audio/AudioMultiPositionComponentBus.h
@@ -40,7 +41,6 @@ set(FILES
include/LmbrCentral/Rendering/MaterialHandle.h
include/LmbrCentral/Rendering/MaterialOwnerBus.h
include/LmbrCentral/Rendering/MeshAsset.h
include/LmbrCentral/Rendering/MeshComponentBus.h
include/LmbrCentral/Rendering/MeshModificationBus.h
include/LmbrCentral/Rendering/RenderNodeBus.h
include/LmbrCentral/Rendering/GiRegistrationBus.h
@@ -69,8 +69,6 @@ set(FILES
include/LmbrCentral/Terrain/TerrainSystemRequestBus.h
Source/Ai/NavigationSystemComponent.h
Source/Ai/NavigationSystemComponent.cpp
Source/Animation/AttachmentComponent.h
Source/Animation/AttachmentComponent.cpp
Source/Audio/AudioAreaEnvironmentComponent.h
Source/Audio/AudioAreaEnvironmentComponent.cpp
Source/Audio/AudioEnvironmentComponent.h
@@ -99,11 +97,6 @@ set(FILES
Source/Events/ReflectScriptableEvents.cpp
Source/Geometry/GeometrySystemComponent.h
Source/Geometry/GeometrySystemComponent.cpp
Source/Rendering/MaterialHandle.cpp
Source/Rendering/MeshAssetHandler.h
Source/Rendering/MeshAssetHandler.cpp
Source/Rendering/MeshComponent.h
Source/Rendering/MeshComponent.cpp
Source/Rendering/EntityDebugDisplayComponent.h
Source/Rendering/EntityDebugDisplayComponent.cpp
Source/Scripting/LookAtComponent.h
@@ -345,7 +345,6 @@ namespace PhysX
AzToolsFramework::BoxManipulatorRequestBus::Handler::BusConnect(
AZ::EntityComponentIdPair(GetEntityId(), GetId()));
ColliderShapeRequestBus::Handler::BusConnect(GetEntityId());
LmbrCentral::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
EditorColliderComponentRequestBus::Handler::BusConnect(AZ::EntityComponentIdPair(GetEntityId(), GetId()));
m_nonUniformScaleChangedHandler = AZ::NonUniformScaleChangedEvent::Handler(
@@ -394,7 +393,6 @@ namespace PhysX
m_nonUniformScaleChangedHandler.Disconnect();
EditorColliderComponentRequestBus::Handler::BusDisconnect();
AZ::Render::MeshComponentNotificationBus::Handler::BusDisconnect();
LmbrCentral::MeshComponentNotificationBus::Handler::BusDisconnect();
ColliderShapeRequestBus::Handler::BusDisconnect();
AzToolsFramework::BoxManipulatorRequestBus::Handler::BusDisconnect();
AZ::TransformNotificationBus::Handler::BusDisconnect();
@@ -1179,17 +1177,7 @@ namespace PhysX
AZ::Render::MeshComponentRequestBus::EventResult(atomMeshAsset, GetEntityId(),
&AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
if (atomMeshAsset.GetId().IsValid())
{
return atomMeshAsset;
}
// Try legacy render MeshComponent
AZ::Data::Asset<AZ::Data::AssetData> legacyMeshAsset;
LmbrCentral::MeshComponentRequestBus::EventResult(legacyMeshAsset,
GetEntityId(), &LmbrCentral::MeshComponentRequests::GetMeshAsset);
return legacyMeshAsset;
return atomMeshAsset;
}
void EditorColliderComponent::SetCollisionMeshFromRender()
@@ -1264,14 +1252,6 @@ namespace PhysX
renderMeshAsset.GetHint().c_str());
}
}
void EditorColliderComponent::OnMeshCreated([[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset)
{
if (ShouldUpdateCollisionMeshFromRender())
{
SetCollisionMeshFromRender();
}
}
void EditorColliderComponent::OnModelReady([[maybe_unused]] const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset,
[[maybe_unused]] const AZ::Data::Instance<AZ::RPI::Model>& model)
@@ -32,8 +32,6 @@
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
#include <AzToolsFramework/UI/PropertyEditor/ComponentEditor.hxx>
#include <LmbrCentral/Rendering/MeshComponentBus.h>
#include <PhysX/ColliderShapeBus.h>
#include <PhysX/EditorColliderComponentRequestBus.h>
#include <PhysX/MeshAsset.h>
@@ -105,7 +103,6 @@ namespace PhysX
, private PhysX::MeshColliderComponentRequestsBus::Handler
, private AZ::TransformNotificationBus::Handler
, private PhysX::ColliderShapeRequestBus::Handler
, private LmbrCentral::MeshComponentNotificationBus::Handler
, private AZ::Render::MeshComponentNotificationBus::Handler
, private PhysX::EditorColliderComponentRequestBus::Handler
, private Physics::WorldBodyRequestBus::Handler
@@ -175,9 +172,6 @@ namespace PhysX
AZ::Transform GetCurrentTransform() override;
AZ::Vector3 GetBoxScale() override;
// LmbrCentral::MeshComponentNotificationBus
void OnMeshCreated(const AZ::Data::Asset<AZ::Data::AssetData>& asset) override;
// AZ::Render::MeshComponentNotificationBus
void OnModelReady(const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset,
const AZ::Data::Instance<AZ::RPI::Model>& model) override;