Merge remote-tracking branch 'upstream/development' into hultonha_LY-69118_lambda_crash
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class BehaviorContext;
|
||||
class EditContext;
|
||||
class SerializeContext;
|
||||
} // namespace AZ
|
||||
|
||||
// this just provides a convenient template to avoid the necessary boilerplate when you derive from AWSScriptBehaviorBase
|
||||
#define AWS_SCRIPT_BEHAVIOR_DEFINITION(className, guidString) \
|
||||
AZ_TYPE_INFO(className, guidString) \
|
||||
AZ_CLASS_ALLOCATOR(className, AZ::SystemAllocator, 0) \
|
||||
void ReflectSerialization(AZ::SerializeContext* serializeContext) override; \
|
||||
void ReflectBehaviors(AZ::BehaviorContext* behaviorContext) override; \
|
||||
void ReflectEditParameters(AZ::EditContext* editContext) override; \
|
||||
className(); \
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
//! An interface for AWS ScriptCanvas Behaviors to inherit from
|
||||
class AWSScriptBehaviorBase
|
||||
{
|
||||
public:
|
||||
virtual ~AWSScriptBehaviorBase() = default;
|
||||
|
||||
virtual void ReflectSerialization(AZ::SerializeContext* reflectContext) = 0;
|
||||
virtual void ReflectBehaviors(AZ::BehaviorContext* behaviorContext) = 0;
|
||||
virtual void ReflectEditParameters(AZ::EditContext* editContext) = 0;
|
||||
|
||||
virtual void Init() {}
|
||||
virtual void Activate() {}
|
||||
virtual void Deactivate() {}
|
||||
};
|
||||
} // namespace AWSCore
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <ScriptCanvas/AWSScriptBehaviorBase.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
using DynamoDBAttributeValueMap = AZStd::unordered_map<AZStd::string, AZStd::string>;
|
||||
@@ -55,10 +53,14 @@ namespace AWSCore
|
||||
};
|
||||
|
||||
class AWSScriptBehaviorDynamoDB
|
||||
: public AWSScriptBehaviorBase
|
||||
{
|
||||
public:
|
||||
AWS_SCRIPT_BEHAVIOR_DEFINITION(AWSScriptBehaviorDynamoDB, "{569E74F6-1268-4199-9653-A3B603FC9F4F}");
|
||||
AZ_RTTI(AWSScriptBehaviorDynamoDB, "{569E74F6-1268-4199-9653-A3B603FC9F4F}");
|
||||
|
||||
AWSScriptBehaviorDynamoDB() = default;
|
||||
virtual ~AWSScriptBehaviorDynamoDB() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void GetItem(const AZStd::string& tableResourceKey, const DynamoDBAttributeValueMap& keyMap);
|
||||
static void GetItemRaw(const AZStd::string& table, const DynamoDBAttributeValueMap& keyMap, const AZStd::string& region);
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <ScriptCanvas/AWSScriptBehaviorBase.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
//! AWS Script Behavior notifications for ScriptCanvas behaviors that interact with AWS Lambda
|
||||
@@ -53,10 +51,14 @@ namespace AWSCore
|
||||
};
|
||||
|
||||
class AWSScriptBehaviorLambda
|
||||
: public AWSScriptBehaviorBase
|
||||
{
|
||||
public:
|
||||
AWS_SCRIPT_BEHAVIOR_DEFINITION(AWSScriptBehaviorLambda, "{9E71534D-34B3-4723-B180-2552513DDA3D}");
|
||||
AZ_RTTI(AWSScriptBehaviorLambda, "{9E71534D-34B3-4723-B180-2552513DDA3D}");
|
||||
|
||||
AWSScriptBehaviorLambda() = default;
|
||||
virtual ~AWSScriptBehaviorLambda() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void Invoke(const AZStd::string& functionResourceKey, const AZStd::string& payload);
|
||||
static void InvokeRaw(const AZStd::string& functionName, const AZStd::string& payload, const AZStd::string& region);
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <ScriptCanvas/AWSScriptBehaviorBase.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
//! AWS Script Behavior notifications for ScriptCanvas behaviors that interact with AWS S3
|
||||
@@ -68,7 +66,6 @@ namespace AWSCore
|
||||
};
|
||||
|
||||
class AWSScriptBehaviorS3
|
||||
: public AWSScriptBehaviorBase
|
||||
{
|
||||
static constexpr const char AWSScriptBehaviorS3Name[] = "AWSScriptBehaviorS3";
|
||||
static constexpr const char OutputFileIsEmptyErrorMessage[] = "Request validation failed, output file is empty.";
|
||||
@@ -81,7 +78,12 @@ namespace AWSCore
|
||||
static constexpr const char RegionNameIsEmptyErrorMessage[] = "Request validation failed, region name is empty.";
|
||||
|
||||
public:
|
||||
AWS_SCRIPT_BEHAVIOR_DEFINITION(AWSScriptBehaviorS3, "{7F4E956C-7463-4236-B320-C992D36A9C6E}");
|
||||
AZ_RTTI(AWSScriptBehaviorS3, "{7F4E956C-7463-4236-B320-C992D36A9C6E}");
|
||||
|
||||
AWSScriptBehaviorS3() = default;
|
||||
virtual ~AWSScriptBehaviorS3() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void GetObject(const AZStd::string& bucketResourceKey, const AZStd::string& objectKey, const AZStd::string& outFile);
|
||||
static void GetObjectRaw(const AZStd::string& bucket, const AZStd::string& objectKey, const AZStd::string& region, const AZStd::string& outFile);
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
@@ -30,23 +29,8 @@ namespace AWSCore
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
||||
|
||||
static bool AddedBehaviours()
|
||||
{
|
||||
return m_alreadyAddedBehaviors;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
void Init() override;
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void AddBehaviors(); // Add any behaviors you derived from AWSScriptBehaviorBase to the implementation of this function
|
||||
|
||||
static AZStd::vector<AZStd::unique_ptr<AWSScriptBehaviorBase>> m_behaviors;
|
||||
static bool m_alreadyAddedBehaviors;
|
||||
};
|
||||
} // namespace AWSCore
|
||||
|
||||
@@ -20,39 +20,30 @@
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
AWSScriptBehaviorDynamoDB::AWSScriptBehaviorDynamoDB()
|
||||
void AWSScriptBehaviorDynamoDB::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorDynamoDB::ReflectSerialization(AZ::SerializeContext* serializeContext)
|
||||
{
|
||||
if (serializeContext)
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AWSScriptBehaviorDynamoDB>()
|
||||
->Version(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorDynamoDB::ReflectBehaviors(AZ::BehaviorContext* behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorDynamoDB>("AWSScriptBehaviorDynamoDB")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("GetItem", &AWSScriptBehaviorDynamoDB::GetItem,
|
||||
{{{"Table Resource KeyName", "The name of the table containing the requested item."},
|
||||
{"Key Map", "A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve."}}})
|
||||
->Method("GetItemRaw", &AWSScriptBehaviorDynamoDB::GetItemRaw,
|
||||
{{{"Table Name", "The name of the table containing the requested item."},
|
||||
{"Key Map", "A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve."},
|
||||
{"Region Name", "The region of the table located in."}}});
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorDynamoDB>("AWSScriptBehaviorDynamoDB")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("GetItem", &AWSScriptBehaviorDynamoDB::GetItem,
|
||||
{{{"Table Resource KeyName", "The name of the table containing the requested item."},
|
||||
{"Key Map", "A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve."}}})
|
||||
->Method("GetItemRaw", &AWSScriptBehaviorDynamoDB::GetItemRaw,
|
||||
{{{"Table Name", "The name of the table containing the requested item."},
|
||||
{"Key Map", "A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve."},
|
||||
{"Region Name", "The region of the table located in."}}});
|
||||
|
||||
behaviorContext->EBus<AWSScriptBehaviorDynamoDBNotificationBus>("AWSDynamoDBBehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorDynamoDBNotificationBusHandler>();
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorDynamoDB::ReflectEditParameters(AZ::EditContext* editContext)
|
||||
{
|
||||
AZ_UNUSED(editContext);
|
||||
behaviorContext->EBus<AWSScriptBehaviorDynamoDBNotificationBus>("AWSDynamoDBBehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorDynamoDBNotificationBusHandler>();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorDynamoDB::GetItem(const AZStd::string& tableResourceKey, const DynamoDBAttributeValueMap& keyMap)
|
||||
|
||||
@@ -21,39 +21,30 @@
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
AWSScriptBehaviorLambda::AWSScriptBehaviorLambda()
|
||||
void AWSScriptBehaviorLambda::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorLambda::ReflectSerialization(AZ::SerializeContext* serializeContext)
|
||||
{
|
||||
if (serializeContext)
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AWSScriptBehaviorLambda>()
|
||||
->Version(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorLambda::ReflectBehaviors(AZ::BehaviorContext* behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorLambda>("AWSScriptBehaviorLambda")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("Invoke", &AWSScriptBehaviorLambda::Invoke,
|
||||
{{{"Function Resource KeyName", "The resource key name of the lambda function in resource mapping config file."},
|
||||
{"Payload", "The JSON that you want to provide to your Lambda function as input."}}})
|
||||
->Method("InvokeRaw", &AWSScriptBehaviorLambda::InvokeRaw,
|
||||
{{{"Function Name", "The name of the Lambda function, version, or alias."},
|
||||
{"Payload", "The JSON that you want to provide to your Lambda function as input."},
|
||||
{"Region Name", "The region of the lambda function located in."}}});
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorLambda>("AWSScriptBehaviorLambda")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("Invoke", &AWSScriptBehaviorLambda::Invoke,
|
||||
{{{"Function Resource KeyName", "The resource key name of the lambda function in resource mapping config file."},
|
||||
{"Payload", "The JSON that you want to provide to your Lambda function as input."}}})
|
||||
->Method("InvokeRaw", &AWSScriptBehaviorLambda::InvokeRaw,
|
||||
{{{"Function Name", "The name of the Lambda function, version, or alias."},
|
||||
{"Payload", "The JSON that you want to provide to your Lambda function as input."},
|
||||
{"Region Name", "The region of the lambda function located in."}}});
|
||||
|
||||
behaviorContext->EBus<AWSScriptBehaviorLambdaNotificationBus>("AWSLambdaBehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorLambdaNotificationBusHandler>();
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorLambda::ReflectEditParameters(AZ::EditContext* editContext)
|
||||
{
|
||||
AZ_UNUSED(editContext);
|
||||
behaviorContext->EBus<AWSScriptBehaviorLambdaNotificationBus>("AWSLambdaBehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorLambdaNotificationBusHandler>();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorLambda::Invoke(const AZStd::string& functionResourceKey, const AZStd::string& payload)
|
||||
|
||||
@@ -24,49 +24,39 @@
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
AWSScriptBehaviorS3::AWSScriptBehaviorS3()
|
||||
void AWSScriptBehaviorS3::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorS3::ReflectSerialization(AZ::SerializeContext* serializeContext)
|
||||
{
|
||||
if (serializeContext)
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AWSScriptBehaviorS3>()
|
||||
->Version(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorS3::ReflectBehaviors(AZ::BehaviorContext* behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorS3>(AWSScriptBehaviorS3Name)
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("GetObject", &AWSScriptBehaviorS3::GetObject,
|
||||
{{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Outfile Name", "Filename where the content will be saved."}}})
|
||||
->Method("GetObjectRaw", &AWSScriptBehaviorS3::GetObjectRaw,
|
||||
{{{"Bucket Name", "The name of the bucket containing the object."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Region Name", "The region of the bucket located in."},
|
||||
{"Outfile Name", "Filename where the content will be saved."}}})
|
||||
->Method("HeadObject", &AWSScriptBehaviorS3::HeadObject,
|
||||
{{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
|
||||
{"Object KeyName", "The object key."}}})
|
||||
->Method("HeadObjectRaw", &AWSScriptBehaviorS3::HeadObjectRaw,
|
||||
{{{"Bucket Name", "The name of the bucket containing the object."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Region Name", "The region of the bucket located in."}}})
|
||||
;
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorS3>(AWSScriptBehaviorS3Name)
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("GetObject", &AWSScriptBehaviorS3::GetObject,
|
||||
{{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Outfile Name", "Filename where the content will be saved."}}})
|
||||
->Method("GetObjectRaw", &AWSScriptBehaviorS3::GetObjectRaw,
|
||||
{{{"Bucket Name", "The name of the bucket containing the object."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Region Name", "The region of the bucket located in."},
|
||||
{"Outfile Name", "Filename where the content will be saved."}}})
|
||||
->Method("HeadObject", &AWSScriptBehaviorS3::HeadObject,
|
||||
{{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
|
||||
{"Object KeyName", "The object key."}}})
|
||||
->Method("HeadObjectRaw", &AWSScriptBehaviorS3::HeadObjectRaw,
|
||||
{{{"Bucket Name", "The name of the bucket containing the object."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Region Name", "The region of the bucket located in."}}});
|
||||
|
||||
behaviorContext->EBus<AWSScriptBehaviorS3NotificationBus>("AWSS3BehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorS3NotificationBusHandler>();
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorS3::ReflectEditParameters(AZ::EditContext* editContext)
|
||||
{
|
||||
AZ_UNUSED(editContext);
|
||||
behaviorContext->EBus<AWSScriptBehaviorS3NotificationBus>("AWSS3BehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorS3NotificationBusHandler>();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorS3::GetObject(
|
||||
|
||||
@@ -12,35 +12,17 @@
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
AZStd::vector<AZStd::unique_ptr<AWSScriptBehaviorBase>> AWSScriptBehaviorsComponent::m_behaviors;
|
||||
bool AWSScriptBehaviorsComponent::m_alreadyAddedBehaviors = false;
|
||||
|
||||
void AWSScriptBehaviorsComponent::AddBehaviors()
|
||||
{
|
||||
if (!m_alreadyAddedBehaviors)
|
||||
{
|
||||
// Add new script behaviors here
|
||||
m_behaviors.push_back(AZStd::make_unique<AWSScriptBehaviorDynamoDB>());
|
||||
m_behaviors.push_back(AZStd::make_unique<AWSScriptBehaviorLambda>());
|
||||
m_behaviors.push_back(AZStd::make_unique<AWSScriptBehaviorS3>());
|
||||
m_alreadyAddedBehaviors = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorsComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AddBehaviors();
|
||||
AWSScriptBehaviorDynamoDB::Reflect(context);
|
||||
AWSScriptBehaviorLambda::Reflect(context);
|
||||
AWSScriptBehaviorS3::Reflect(context);
|
||||
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<AWSScriptBehaviorsComponent, AZ::Component>()
|
||||
->Version(0);
|
||||
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->ReflectSerialization(serialize);
|
||||
}
|
||||
|
||||
if (AZ::EditContext* editContext = serialize->GetEditContext())
|
||||
{
|
||||
editContext->Class<AWSScriptBehaviorsComponent>("AWSScriptBehaviors", "Provides ScriptCanvas functions for calling AWS")
|
||||
@@ -49,19 +31,6 @@ namespace AWSCore
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("AWS"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->ReflectEditParameters(editContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->ReflectBehaviors(behaviorContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,31 +55,12 @@ namespace AWSCore
|
||||
AZ_UNUSED(dependent);
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorsComponent::Init()
|
||||
{
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->Init();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorsComponent::Activate()
|
||||
{
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->Activate();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorsComponent::Deactivate()
|
||||
{
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->Deactivate();
|
||||
}
|
||||
|
||||
// this forces the vector to release its capacity, clear/shrink_to_fit is not
|
||||
m_behaviors.swap(AZStd::vector<AZStd::unique_ptr<AWSScriptBehaviorBase>>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,18 +15,6 @@
|
||||
|
||||
using namespace AWSCore;
|
||||
|
||||
class AWSScriptBehaviorsComponentMock
|
||||
: public AWSScriptBehaviorsComponent
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AWSScriptBehaviorsComponentMock, "{78579706-E1B2-4788-A34D-A58D3F273FF9}");
|
||||
|
||||
int GetBehaviorsNum()
|
||||
{
|
||||
return m_behaviors.size();
|
||||
}
|
||||
};
|
||||
|
||||
class AWSScriptBehaviorsComponentTest
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
@@ -38,7 +26,7 @@ public:
|
||||
m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
|
||||
|
||||
m_entity = AZStd::make_unique<AZ::Entity>();
|
||||
m_scriptBehaviorsComponent.reset(m_entity->CreateComponent<AWSScriptBehaviorsComponentMock>());
|
||||
m_scriptBehaviorsComponent.reset(m_entity->CreateComponent<AWSScriptBehaviorsComponent>());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -56,20 +44,16 @@ protected:
|
||||
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor> m_componentDescriptor;
|
||||
AZStd::unique_ptr<AWSScriptBehaviorsComponentMock> m_scriptBehaviorsComponent;
|
||||
AZStd::unique_ptr<AWSScriptBehaviorsComponent> m_scriptBehaviorsComponent;
|
||||
AZStd::unique_ptr<AZ::Entity> m_entity;
|
||||
};
|
||||
|
||||
TEST_F(AWSScriptBehaviorsComponentTest, InitActivateDeactivate_Call_GetExpectedNumOfAddedBehaviors)
|
||||
TEST_F(AWSScriptBehaviorsComponentTest, Reflect)
|
||||
{
|
||||
m_componentDescriptor.reset(AWSScriptBehaviorsComponentMock::CreateDescriptor());
|
||||
int oldEBusNum = m_behaviorContext->m_ebuses.size();
|
||||
m_componentDescriptor.reset(AWSScriptBehaviorsComponent::CreateDescriptor());
|
||||
m_componentDescriptor->Reflect(m_serializeContext.get());
|
||||
m_componentDescriptor->Reflect(m_behaviorContext.get());
|
||||
EXPECT_TRUE(AWSScriptBehaviorsComponentMock::AddedBehaviours());
|
||||
EXPECT_TRUE(m_scriptBehaviorsComponent->GetBehaviorsNum() == 3);
|
||||
|
||||
m_entity->Init();
|
||||
m_entity->Activate();
|
||||
m_entity->Deactivate();
|
||||
EXPECT_TRUE(m_scriptBehaviorsComponent->GetBehaviorsNum() == 0);
|
||||
EXPECT_TRUE(m_behaviorContext->m_ebuses.size() - oldEBusNum == 3);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ set(FILES
|
||||
Include/Public/Framework/ServiceRequestJobConfig.h
|
||||
Include/Public/Framework/Util.h
|
||||
Include/Public/ResourceMapping/AWSResourceMappingBus.h
|
||||
Include/Public/ScriptCanvas/AWSScriptBehaviorBase.h
|
||||
Include/Public/ScriptCanvas/AWSScriptBehaviorDynamoDB.h
|
||||
Include/Public/ScriptCanvas/AWSScriptBehaviorLambda.h
|
||||
Include/Public/ScriptCanvas/AWSScriptBehaviorS3.h
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace AZ
|
||||
shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder";
|
||||
// Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update
|
||||
// ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder".
|
||||
shaderVariantAssetBuilderDescriptor.m_version = 23; // ATOM-15472
|
||||
shaderVariantAssetBuilderDescriptor.m_version = 24; // ATOM-15978
|
||||
shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
|
||||
shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderVariantAssetBuilder>();
|
||||
shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
#include "ShaderAssetBuilder.h"
|
||||
#include "ShaderBuilderUtility.h"
|
||||
#include "SrgLayoutUtility.h"
|
||||
#include "AzslData.h"
|
||||
#include "AzslCompiler.h"
|
||||
#include <CommonFiles/Preprocessor.h>
|
||||
@@ -520,6 +521,96 @@ namespace AZ
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static bool LoadSrgLayoutListFromShaderAssetBuilder(
|
||||
const RHI::ShaderPlatformInterface* shaderPlatformInterface,
|
||||
const AssetBuilderSDK::PlatformInfo& platformInfo,
|
||||
const AzslCompiler& azslCompiler, const AZStd::string& shaderSourceFileFullPath,
|
||||
const RPI::SupervariantIndex supervariantIndex,
|
||||
const bool platformUsesRegisterSpaces,
|
||||
RPI::ShaderResourceGroupLayoutList& srgLayoutList,
|
||||
RootConstantData& rootConstantData)
|
||||
{
|
||||
auto srgJsonPathOutcome = ShaderBuilderUtility::ObtainBuildArtifactPathFromShaderAssetBuilder(
|
||||
shaderPlatformInterface->GetAPIUniqueIndex(), platformInfo.m_identifier, shaderSourceFileFullPath, supervariantIndex.GetIndex(), AZ::RPI::ShaderAssetSubId::SrgJson);
|
||||
if (!srgJsonPathOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", srgJsonPathOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto srgJsonPath = srgJsonPathOutcome.TakeValue();
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(srgJsonPath);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
SrgDataContainer srgData;
|
||||
if (!azslCompiler.ParseSrgPopulateSrgData(jsonOutcome.GetValue(), srgData))
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to parse srg data");
|
||||
return false;
|
||||
}
|
||||
// Add all Shader Resource Group Assets that were defined in the shader code to the shader asset
|
||||
if (!SrgLayoutUtility::LoadShaderResourceGroupLayouts(ShaderVariantAssetBuilderName, srgData, platformUsesRegisterSpaces, srgLayoutList))
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to load ShaderResourceGroupLayouts");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto srgLayout : srgLayoutList)
|
||||
{
|
||||
if (!srgLayout->Finalize())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false,
|
||||
"Failed to finalize SrgLayout %s", srgLayout->GetName().GetCStr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Access the root constants reflection
|
||||
if (!azslCompiler.ParseSrgPopulateRootConstantData(
|
||||
jsonOutcome.GetValue(),
|
||||
rootConstantData)) // consuming data from --srg ("InlineConstantBuffer" subjson section)
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to obtain root constant data reflection");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadBindingDependenciesFromShaderAssetBuilder(
|
||||
const RHI::ShaderPlatformInterface* shaderPlatformInterface,
|
||||
const AssetBuilderSDK::PlatformInfo& platformInfo,
|
||||
const AzslCompiler& azslCompiler, const AZStd::string& shaderSourceFileFullPath,
|
||||
const RPI::SupervariantIndex supervariantIndex,
|
||||
BindingDependencies& bindingDependencies)
|
||||
{
|
||||
auto bindingsJsonPathOutcome = ShaderBuilderUtility::ObtainBuildArtifactPathFromShaderAssetBuilder(
|
||||
shaderPlatformInterface->GetAPIUniqueIndex(), platformInfo.m_identifier, shaderSourceFileFullPath, supervariantIndex.GetIndex(), AZ::RPI::ShaderAssetSubId::BindingdepJson);
|
||||
if (!bindingsJsonPathOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", bindingsJsonPathOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto bindingsJsonPath = bindingsJsonPathOutcome.TakeValue();
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(bindingsJsonPath);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
if (!azslCompiler.ParseBindingdepPopulateBindingDependencies(jsonOutcome.GetValue(), bindingDependencies))
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to parse binding dependencies data");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Returns the content of the hlsl file for the given supervariant as produced by ShaderAsssetBuilder.
|
||||
@@ -773,6 +864,50 @@ namespace AZ
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
//! It is important to keep this refcounted pointer outside of the if block to prevent it from being destroyed.
|
||||
RHI::Ptr<RHI::PipelineLayoutDescriptor> pipelineLayoutDescriptor;
|
||||
if (shaderPlatformInterface->VariantCompilationRequiresSrgLayoutData())
|
||||
{
|
||||
AZStd::string azslcCompilerParameters =
|
||||
shaderPlatformInterface->GetAzslCompilerParameters(buildOptions.m_compilerArguments);
|
||||
const bool platformUsesRegisterSpaces =
|
||||
(AzFramework::StringFunc::Find(azslcCompilerParameters, "--use-spaces") != AZStd::string::npos);
|
||||
|
||||
RPI::ShaderResourceGroupLayoutList srgLayoutList;
|
||||
RootConstantData rootConstantData;
|
||||
if (!LoadSrgLayoutListFromShaderAssetBuilder(
|
||||
shaderPlatformInterface, request.m_platformInfo, azslc, shaderSourceFileFullPath, supervariantIndex,
|
||||
platformUsesRegisterSpaces,
|
||||
srgLayoutList,
|
||||
rootConstantData))
|
||||
{
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
BindingDependencies bindingDependencies;
|
||||
if (!LoadBindingDependenciesFromShaderAssetBuilder(
|
||||
shaderPlatformInterface, request.m_platformInfo, azslc, shaderSourceFileFullPath, supervariantIndex,
|
||||
bindingDependencies))
|
||||
{
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
pipelineLayoutDescriptor =
|
||||
ShaderBuilderUtility::BuildPipelineLayoutDescriptorForApi(
|
||||
ShaderVariantAssetBuilderName, srgLayoutList, shaderEntryPoints, buildOptions.m_compilerArguments, rootConstantData,
|
||||
shaderPlatformInterface, bindingDependencies);
|
||||
if (!pipelineLayoutDescriptor)
|
||||
{
|
||||
AZ_Error(
|
||||
ShaderVariantAssetBuilderName, false, "Failed to build pipeline layout descriptor for api=[%s]",
|
||||
shaderPlatformInterface->GetAPIName().GetCStr());
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the shader variant creation context:
|
||||
ShaderVariantCreationContext shaderVariantCreationContext =
|
||||
|
||||
@@ -144,6 +144,12 @@ namespace AZ
|
||||
const ShaderResourceGroupInfoList& srgInfoList,
|
||||
const RootConstantsInfo& rootConstantsInfo,
|
||||
const ShaderCompilerArguments& shaderCompilerArguments) = 0;
|
||||
|
||||
//! In general, shader compilation doesn't require SRG Layout data, but RHIs like
|
||||
//! Metal don't do well if unused resources (descriptors) are not bound. If this function returns TRUE
|
||||
//! the ShaderVariantAssetBuilder will invoke BuildPipelineLayoutDescriptor() so the RHI gets the chance to
|
||||
//! build SRG Layout data which will be useful when compiling MetalISL to Metal byte code.
|
||||
virtual bool VariantCompilationRequiresSrgLayoutData() const { return false; }
|
||||
|
||||
//! See AZ::RHI::Factory::GetAPIUniqueIndex() for details.
|
||||
//! See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax.
|
||||
|
||||
@@ -159,7 +159,13 @@ namespace AZ
|
||||
arguments += " -Zi"; // Generate debug information
|
||||
arguments += " -Zss"; // Compute Shader Hash considering source information
|
||||
}
|
||||
arguments += " " + m_dxcAdditionalFreeArguments;
|
||||
// strip spaces at both sides
|
||||
AZStd::string dxcAdditionalFreeArguments = m_dxcAdditionalFreeArguments;
|
||||
AzFramework::StringFunc::TrimWhiteSpace(dxcAdditionalFreeArguments, true, true);
|
||||
if (!dxcAdditionalFreeArguments.empty())
|
||||
{
|
||||
arguments += " " + dxcAdditionalFreeArguments;
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ namespace AZ
|
||||
const ShaderResourceGroupInfoList& srgInfoList,
|
||||
const RootConstantsInfo& rootConstantsInfo,
|
||||
const RHI::ShaderCompilerArguments& shaderCompilerArguments) override;
|
||||
|
||||
bool VariantCompilationRequiresSrgLayoutData() const override { return true; }
|
||||
|
||||
bool CompilePlatformInternal(
|
||||
const AssetBuilderSDK::PlatformInfo& platform,
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace AZ
|
||||
{
|
||||
AZ_UNUSED(device);
|
||||
m_hardwareQueueClass = hardwareQueueClass;
|
||||
m_supportsInterDrawTimestamps = AZ::RHI::QueryTypeFlags::Timestamp == (device->GetFeatures().m_queryTypesMask[static_cast<uint32_t>(hardwareQueueClass)] & AZ::RHI::QueryTypeFlags::Timestamp);
|
||||
}
|
||||
|
||||
void CommandListBase::Reset()
|
||||
@@ -64,7 +65,10 @@ namespace AZ
|
||||
[m_encoder endEncoding];
|
||||
m_encoder = nil;
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
m_timeStampQueue.clear();
|
||||
if (m_supportsInterDrawTimestamps)
|
||||
{
|
||||
m_timeStampQueue.clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -144,9 +148,12 @@ namespace AZ
|
||||
m_isEncoded = true;
|
||||
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
for(auto& timeStamp: m_timeStampQueue)
|
||||
if (m_supportsInterDrawTimestamps)
|
||||
{
|
||||
SampleCounters(timeStamp.m_counterSampleBuffer, timeStamp.m_timeStampIndex);
|
||||
for(auto& timeStamp: m_timeStampQueue)
|
||||
{
|
||||
SampleCounters(timeStamp.m_counterSampleBuffer, timeStamp.m_timeStampIndex);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -195,6 +202,11 @@ namespace AZ
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
void CommandListBase::SampleCounters(id<MTLCounterSampleBuffer> counterSampleBuffer, uint32_t sampleIndex)
|
||||
{
|
||||
if (!m_supportsInterDrawTimestamps)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ_Assert(sampleIndex >= 0, "Invalid sample index");
|
||||
//useBarrier - Inserting a barrier ensures that encoded work is complete before the GPU samples the hardware counters.
|
||||
//If it is true there is a performance penalty but you will get consistent results
|
||||
@@ -231,6 +243,11 @@ namespace AZ
|
||||
|
||||
void CommandListBase::SamplePassCounters(id<MTLCounterSampleBuffer> counterSampleBuffer, uint32_t sampleIndex)
|
||||
{
|
||||
if (!m_supportsInterDrawTimestamps)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_encoder == nil)
|
||||
{
|
||||
//Queue the query to be activated upon encoder creation. Applies to timestamp queries
|
||||
|
||||
@@ -101,6 +101,8 @@ namespace AZ
|
||||
|
||||
const AZStd::set<id<MTLHeap>>* m_residentHeaps = nullptr;
|
||||
|
||||
bool m_supportsInterDrawTimestamps = AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING; // iOS/TVOS = false, MacOS = defaults to true
|
||||
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
struct TimeStampData
|
||||
{
|
||||
|
||||
@@ -328,14 +328,28 @@ namespace AZ
|
||||
m_features.m_indirectDrawSupport = false;
|
||||
|
||||
RHI::QueryTypeFlags counterSamplingFlags = RHI::QueryTypeFlags::None;
|
||||
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
counterSamplingFlags |= (RHI::QueryTypeFlags::Timestamp | RHI::QueryTypeFlags::PipelineStatistics);
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Copy)] = RHI::QueryTypeFlags::Timestamp;
|
||||
|
||||
bool supportsInterDrawTimestamps = true;
|
||||
#if defined(__IPHONE_14_0) || defined(__MAC_11_0) || defined(__TVOS_14_0)
|
||||
if (@available(macOS 11.0, iOS 14, tvOS 14, *))
|
||||
{
|
||||
supportsInterDrawTimestamps = [m_metalDevice supportsCounterSampling:MTLCounterSamplingPointAtDrawBoundary];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
supportsInterDrawTimestamps = ![m_metalDevice.name containsString:@"Apple"]; // Apple GPU's don't support inter draw timestamps at the M1/A14 generation
|
||||
}
|
||||
|
||||
if (supportsInterDrawTimestamps)
|
||||
{
|
||||
counterSamplingFlags |= (RHI::QueryTypeFlags::Timestamp | RHI::QueryTypeFlags::PipelineStatistics);
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Copy)] = RHI::QueryTypeFlags::Timestamp;
|
||||
}
|
||||
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Graphics)] = RHI::QueryTypeFlags::Occlusion | counterSamplingFlags;
|
||||
//Compute queue can do gfx work
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Compute)] = RHI::QueryTypeFlags::Occlusion |counterSamplingFlags;
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Compute)] = RHI::QueryTypeFlags::Occlusion | counterSamplingFlags;
|
||||
m_features.m_occlusionQueryPrecise = true;
|
||||
|
||||
//Values taken from https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
||||
|
||||
@@ -218,7 +218,8 @@ namespace AZ
|
||||
createInfo.extent = extent;
|
||||
createInfo.mipLevels = AZStd::min<uint32_t>(descriptor.m_mipLevels, formatProps.maxMipLevels);
|
||||
createInfo.arrayLayers = AZStd::min<uint32_t>(descriptor.m_arraySize, formatProps.maxArrayLayers);
|
||||
createInfo.samples = static_cast<VkSampleCountFlagBits>(RHI::FilterBits(static_cast<VkSampleCountFlags>(ConvertSampleCount(descriptor.m_multisampleState.m_samples)), formatProps.sampleCounts));
|
||||
VkSampleCountFlagBits sampleCountFlagBits = static_cast<VkSampleCountFlagBits>(RHI::FilterBits(static_cast<VkSampleCountFlags>(ConvertSampleCount(descriptor.m_multisampleState.m_samples)), formatProps.sampleCounts));
|
||||
createInfo.samples = (static_cast<uint32_t>(sampleCountFlagBits) > 0) ? sampleCountFlagBits : VK_SAMPLE_COUNT_1_BIT;
|
||||
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
createInfo.usage = GetImageUsageFlags();
|
||||
createInfo.sharingMode = exclusiveOwnership ? VK_SHARING_MODE_EXCLUSIVE : VK_SHARING_MODE_CONCURRENT;
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace AZ
|
||||
{
|
||||
AZ_Assert(IsQueryTypeValid(queryType), "Provided QueryType is invalid");
|
||||
|
||||
return static_cast<uint32_t>(m_queryTypeSupport) & static_cast<uint32_t>(queryType);
|
||||
return static_cast<uint32_t>(m_queryTypeSupport) & AZ_BIT(static_cast<uint32_t>(queryType));
|
||||
}
|
||||
|
||||
RPI::QueryPool* GpuQuerySystem::GetQueryPoolByType(RHI::QueryType queryType)
|
||||
|
||||
@@ -237,8 +237,8 @@ namespace EditorPythonBindings
|
||||
{
|
||||
ec->Class<PythonSystemComponent>("PythonSystemComponent", "The Python interpreter")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -284,10 +284,10 @@ namespace EditorPythonBindings
|
||||
ReleaseFunction m_releaseFunction;
|
||||
};
|
||||
ReleaseInitalizeWaiterScope scope([this]()
|
||||
{
|
||||
m_initalizeWaiter.release(m_initalizeWaiterCount);
|
||||
m_initalizeWaiterCount = 0;
|
||||
});
|
||||
{
|
||||
m_initalizeWaiter.release(m_initalizeWaiterCount);
|
||||
m_initalizeWaiterCount = 0;
|
||||
});
|
||||
|
||||
if (Py_IsInitialized())
|
||||
{
|
||||
@@ -327,6 +327,11 @@ namespace EditorPythonBindings
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PythonSystemComponent::IsPythonActive()
|
||||
{
|
||||
return Py_IsInitialized() != 0;
|
||||
}
|
||||
|
||||
void PythonSystemComponent::WaitForInitialization()
|
||||
{
|
||||
m_initalizeWaiterCount++;
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace EditorPythonBindings
|
||||
// AzToolsFramework::EditorPythonEventsInterface
|
||||
bool StartPython(bool silenceWarnings = false) override;
|
||||
bool StopPython(bool silenceWarnings = false) override;
|
||||
bool IsPythonActive() override;
|
||||
void WaitForInitialization() override;
|
||||
void ExecuteWithLock(AZStd::function<void()> executionCallback) override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -209,12 +209,17 @@ namespace Gestures
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline uint32_t IRecognizer::GetGesturePointerIndex(const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
const auto& mouseButtonIt = AZStd::find(AzFramework::InputDeviceMouse::Button::All.cbegin(),
|
||||
AzFramework::InputDeviceMouse::Button::All.cend(),
|
||||
inputChannel.GetInputChannelId());
|
||||
if (mouseButtonIt != AzFramework::InputDeviceMouse::Button::All.cend())
|
||||
// Only recognize gestures for the default mouse input device. The Editor may register synthetic
|
||||
// mouse input devices with the same mouse input channels, which can confuse gesture recognition.
|
||||
if (inputChannel.GetInputDevice().GetInputDeviceId() == AzFramework::InputDeviceMouse::Id)
|
||||
{
|
||||
return static_cast<uint32_t>(mouseButtonIt - AzFramework::InputDeviceMouse::Button::All.cbegin());
|
||||
const auto& mouseButtonIt = AZStd::find(AzFramework::InputDeviceMouse::Button::All.cbegin(),
|
||||
AzFramework::InputDeviceMouse::Button::All.cend(),
|
||||
inputChannel.GetInputChannelId());
|
||||
if (mouseButtonIt != AzFramework::InputDeviceMouse::Button::All.cend())
|
||||
{
|
||||
return static_cast<uint32_t>(mouseButtonIt - AzFramework::InputDeviceMouse::Button::All.cbegin());
|
||||
}
|
||||
}
|
||||
|
||||
const auto& touchIndexIt = AZStd::find(AzFramework::InputDeviceTouch::Touch::All.cbegin(),
|
||||
|
||||
@@ -63,7 +63,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
AUTORCC
|
||||
FILES_CMAKE
|
||||
lyshine_uicanvaseditor_files.cmake
|
||||
lyshine_editor_builder_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
@@ -78,7 +77,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
3rdParty::Qt::Widgets
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AssetBuilderSDK
|
||||
Legacy::EditorCommon
|
||||
Legacy::EditorCore
|
||||
Gem::LyShine.Static
|
||||
@@ -98,7 +96,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
|
||||
ly_add_target(
|
||||
NAME LyShine.Editor GEM_MODULE
|
||||
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
lyshine_common_module_files.cmake
|
||||
@@ -115,17 +112,72 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Legacy::CryCommon
|
||||
AZ::AssetBuilderSDK
|
||||
AZ::AzToolsFramework
|
||||
Gem::LyShine.Editor.Static
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas.Editor
|
||||
RUNTIME_DEPENDENCIES
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas.Editor
|
||||
)
|
||||
)
|
||||
|
||||
# by naming this target LyShine.Builders it ensures that it is loaded
|
||||
# in any pipeline tools (Like Asset Processor, AssetBuilder, etc)
|
||||
ly_add_target(
|
||||
NAME LyShine.Builders.Static STATIC
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
lyshine_editor_builder_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
Source
|
||||
PUBLIC
|
||||
Include
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AssetBuilderSDK
|
||||
Gem::LyShine.Static
|
||||
Legacy::CryCommon
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas.Editor
|
||||
Gem::AtomToolsFramework.Static
|
||||
Gem::AtomToolsFramework.Editor
|
||||
${additional_dependencies}
|
||||
PUBLIC
|
||||
Gem::Atom_RPI.Public
|
||||
Gem::Atom_Utils.Static
|
||||
Gem::Atom_Bootstrap.Headers
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME LyShine.Builders GEM_MODULE
|
||||
NAMESPACE Gem
|
||||
OUTPUT_NAME Gem.LyShine.Builders
|
||||
FILES_CMAKE
|
||||
lyshine_common_module_files.cmake
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
LYSHINE_BUILDER
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
Source
|
||||
Editor
|
||||
PUBLIC
|
||||
Include
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Legacy::CryCommon
|
||||
AZ::AssetBuilderSDK
|
||||
Gem::LyShine.Builders.Static
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas.Editor
|
||||
)
|
||||
|
||||
# by default, load the above "Gem::LyShine.Editor" module in dev tools:
|
||||
ly_create_alias(NAME LyShine.Builders NAMESPACE Gem TARGETS Gem::LyShine.Editor)
|
||||
ly_create_alias(NAME LyShine.Tools NAMESPACE Gem TARGETS Gem::LyShine.Editor)
|
||||
endif()
|
||||
|
||||
@@ -169,6 +221,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
LYSHINE_EDITOR
|
||||
LYSHINE_BUILDER
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Tests
|
||||
@@ -182,6 +235,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
Legacy::CryCommon
|
||||
AZ::AssetBuilderSDK
|
||||
Gem::LyShine.Editor.Static
|
||||
Gem::LyShine.Builders.Static
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas
|
||||
RUNTIME_DEPENDENCIES
|
||||
|
||||
@@ -52,9 +52,9 @@
|
||||
#include "World/UiCanvasProxyRefComponent.h"
|
||||
#include "World/UiCanvasOnMeshComponent.h"
|
||||
|
||||
#if defined (LYSHINE_EDITOR)
|
||||
# include "Pipeline/LyShineBuilder/LyShineBuilderComponent.h"
|
||||
#endif // LYSHINE_EDITOR
|
||||
#if defined(LYSHINE_BUILDER)
|
||||
#include "Pipeline/LyShineBuilder/LyShineBuilderComponent.h"
|
||||
#endif // LYSHINE_BUILDER
|
||||
|
||||
namespace LyShine
|
||||
{
|
||||
@@ -64,7 +64,7 @@ namespace LyShine
|
||||
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
|
||||
m_descriptors.insert(m_descriptors.end(), {
|
||||
LyShineSystemComponent::CreateDescriptor(),
|
||||
#if defined (LYSHINE_EDITOR)
|
||||
#if defined(LYSHINE_EDITOR)
|
||||
LyShineEditor::LyShineEditorSystemComponent::CreateDescriptor(),
|
||||
#endif
|
||||
UiCanvasAssetRefComponent::CreateDescriptor(),
|
||||
@@ -103,7 +103,7 @@ namespace LyShine
|
||||
UiRadioButtonComponent::CreateDescriptor(),
|
||||
UiRadioButtonGroupComponent::CreateDescriptor(),
|
||||
UiParticleEmitterComponent::CreateDescriptor(),
|
||||
#if defined(LYSHINE_EDITOR)
|
||||
#if defined(LYSHINE_BUILDER)
|
||||
// Builder
|
||||
LyShineBuilder::LyShineBuilderComponent::CreateDescriptor(),
|
||||
#endif
|
||||
@@ -123,7 +123,7 @@ namespace LyShine
|
||||
{
|
||||
return AZ::ComponentTypeList{
|
||||
azrtti_typeid<LyShineSystemComponent>(),
|
||||
#if defined (LYSHINE_EDITOR)
|
||||
#if defined(LYSHINE_EDITOR)
|
||||
azrtti_typeid<LyShineEditor::LyShineEditorSystemComponent>(),
|
||||
#endif
|
||||
#if AZ_LOADSCREENCOMPONENT_ENABLED
|
||||
|
||||
@@ -148,7 +148,6 @@ namespace LyShine
|
||||
{
|
||||
LyShineAllocatorScope::ActivateAllocators();
|
||||
|
||||
LyShineRequestBus::Handler::BusConnect();
|
||||
UiSystemBus::Handler::BusConnect();
|
||||
UiSystemToolsBus::Handler::BusConnect();
|
||||
UiFrameworkBus::Handler::BusConnect();
|
||||
@@ -196,7 +195,6 @@ namespace LyShine
|
||||
UiSystemBus::Handler::BusDisconnect();
|
||||
UiSystemToolsBus::Handler::BusDisconnect();
|
||||
UiFrameworkBus::Handler::BusDisconnect();
|
||||
LyShineRequestBus::Handler::BusDisconnect();
|
||||
CrySystemEventBus::Handler::BusDisconnect();
|
||||
|
||||
LyShineAllocatorScope::DeactivateAllocators();
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include <LmbrCentral/Rendering/MaterialAsset.h>
|
||||
|
||||
#include <LyShine/LyShineBus.h>
|
||||
#include <LyShine/Bus/UiSystemBus.h>
|
||||
#include <LyShine/Bus/UiCanvasManagerBus.h>
|
||||
#include <LyShine/Bus/Tools/UiSystemToolsBus.h>
|
||||
@@ -28,7 +27,6 @@ namespace LyShine
|
||||
|
||||
class LyShineSystemComponent
|
||||
: public AZ::Component
|
||||
, protected LyShineRequestBus::Handler
|
||||
, protected UiSystemBus::Handler
|
||||
, protected UiSystemToolsBus::Handler
|
||||
, protected LyShineAllocatorScope
|
||||
|
||||
@@ -8,4 +8,6 @@
|
||||
set(FILES
|
||||
Source/LyShineModule.cpp
|
||||
Source/LyShineModule.h
|
||||
Source/LyShineSystemComponent.cpp
|
||||
Source/LyShineSystemComponent.h
|
||||
)
|
||||
|
||||
@@ -26,8 +26,6 @@ set(FILES
|
||||
Source/EditorPropertyTypes.h
|
||||
Source/LyShineLoadScreen.cpp
|
||||
Source/LyShineLoadScreen.h
|
||||
Source/LyShineSystemComponent.cpp
|
||||
Source/LyShineSystemComponent.h
|
||||
Source/RenderGraph.cpp
|
||||
Source/RenderGraph.h
|
||||
Source/TextMarkup.cpp
|
||||
|
||||
@@ -61,6 +61,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::SceneCore
|
||||
AZ::SceneData
|
||||
AZ::SceneUI
|
||||
)
|
||||
# the SceneProcessing.Editor module above is only used in Builders and Tools.
|
||||
ly_create_alias(NAME SceneProcessing.Builders NAMESPACE Gem TARGETS Gem::SceneProcessing.Editor)
|
||||
@@ -111,6 +112,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
PRIVATE
|
||||
Gem::SceneProcessing.Editor.Static
|
||||
AZ::AzTest
|
||||
AZ::SceneData
|
||||
)
|
||||
ly_add_googletest(
|
||||
NAME Gem::SceneProcessing.Editor.Tests
|
||||
|
||||
+105
-22
@@ -96,6 +96,85 @@ namespace AZ::SceneGenerationComponents
|
||||
namespace Containers = AZ::SceneAPI::Containers;
|
||||
namespace Views = Containers::Views;
|
||||
|
||||
// @brief A class to map from a mesh's vertex index to it's welded vertex index
|
||||
//
|
||||
// When the mesh optimizer runs, it welds nearby vertices (if there are no blendshapes). This class provides a
|
||||
// constant time lookup to map from an unwelded vertex index to the welded one.
|
||||
// The welding works by rounding the vertex's position to the given position tolerance, then uses that rounded
|
||||
// Vector3 as a key into a unordered_map.
|
||||
template <class MeshDataType>
|
||||
class Vector3Map
|
||||
: private AZStd::unordered_map<AZ::Vector3, AZ::u32>
|
||||
{
|
||||
public:
|
||||
Vector3Map(const MeshDataType* meshData, bool hasBlendShapes, float positionTolerance)
|
||||
: m_meshData(meshData)
|
||||
, m_hasBlendShapes(hasBlendShapes)
|
||||
, m_positionTolerance(positionTolerance)
|
||||
, m_positionToleranceReciprocal(1.0f / positionTolerance)
|
||||
{
|
||||
}
|
||||
|
||||
using AZStd::unordered_map<AZ::Vector3, AZ::u32>::reserve;
|
||||
|
||||
AZ::u32 operator[](const AZ::u32 vertexIndex)
|
||||
{
|
||||
if (m_hasBlendShapes)
|
||||
{
|
||||
// Don't attempt to weld similar vertices if there's blendshapes
|
||||
// Welding the vertices here based on position could cause the vertices of a base shape to be welded,
|
||||
// and the vertices of the blendshape to not be welded, resulting in a vertex count mismatch between
|
||||
// the two
|
||||
return m_meshData->GetUsedPointIndexForControlPoint(m_meshData->GetControlPointIndex(vertexIndex));
|
||||
}
|
||||
|
||||
const auto& [iter, didInsert] = try_emplace(GetPositionForIndex(vertexIndex), m_currentOriginalVertexIndex);
|
||||
if (didInsert)
|
||||
{
|
||||
++m_currentOriginalVertexIndex;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
[[nodiscard]] AZ::u32 at(const AZ::u32 vertexIndex) const
|
||||
{
|
||||
if (m_hasBlendShapes)
|
||||
{
|
||||
// Don't attempt to weld similar vertices if there's blendshapes
|
||||
// Welding the vertices here based on position could cause the vertices of a base shape to be welded,
|
||||
// and the vertices of the blendshape to not be welded, resulting in a vertex count mismatch between
|
||||
// the two
|
||||
return m_meshData->GetUsedPointIndexForControlPoint(m_meshData->GetControlPointIndex(vertexIndex));
|
||||
}
|
||||
|
||||
auto iter = find(GetPositionForIndex(vertexIndex));
|
||||
AZSTD_CONTAINER_ASSERT(iter != end(), "Element with key is not present");
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
AZ::Vector3 GetPositionForIndex(const AZ::u32 vertexIndex) const
|
||||
{
|
||||
// Round the vertex position so that a float comparison can be made with entires in the map
|
||||
// pos = floor( x * 10 + 0.5) * 0.1
|
||||
return AZ::Vector3(
|
||||
AZ::Simd::Vec3::Floor(
|
||||
(m_meshData->GetPosition(vertexIndex) * m_positionToleranceReciprocal + AZ::Vector3(0.5f)).GetSimdValue()
|
||||
)
|
||||
) * m_positionTolerance;
|
||||
}
|
||||
|
||||
const MeshDataType* m_meshData;
|
||||
bool m_hasBlendShapes;
|
||||
float m_positionTolerance;
|
||||
float m_positionToleranceReciprocal;
|
||||
AZ::u32 m_currentOriginalVertexIndex = 0;
|
||||
};
|
||||
|
||||
template<class MeshDataType>
|
||||
Vector3Map(const MeshDataType*) -> Vector3Map<const MeshDataType>;
|
||||
|
||||
MeshOptimizerComponent::MeshOptimizerComponent()
|
||||
{
|
||||
BindToCall(&MeshOptimizerComponent::OptimizeMeshes);
|
||||
@@ -106,7 +185,7 @@ namespace AZ::SceneGenerationComponents
|
||||
auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<MeshOptimizerComponent, GenerationComponent>()->Version(2);
|
||||
serializeContext->Class<MeshOptimizerComponent, GenerationComponent>()->Version(4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +194,8 @@ namespace AZ::SceneGenerationComponents
|
||||
const MeshDataType* meshData,
|
||||
const SkinWeightDataView& skinWeights,
|
||||
AZ::u32 maxWeightsPerVertex,
|
||||
float weightThreshold)
|
||||
float weightThreshold,
|
||||
const Vector3Map<MeshDataType>& positionMap)
|
||||
{
|
||||
if (skinWeights.empty())
|
||||
{
|
||||
@@ -141,15 +221,12 @@ namespace AZ::SceneGenerationComponents
|
||||
for (size_t linkIndex = 0; linkIndex < linkCount; ++linkIndex)
|
||||
{
|
||||
const ISkinWeightData::Link& link = skinData.get().GetLink(controlPointIndex, linkIndex);
|
||||
skinningInfo->AddInfluence(usedPointIndex, {aznumeric_caster(link.boneId), link.weight});
|
||||
skinningInfo->AddInfluence(positionMap.at(usedPointIndex), {aznumeric_caster(link.boneId), link.weight});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (skinningInfo)
|
||||
{
|
||||
skinningInfo->Optimize(maxWeightsPerVertex, weightThreshold);
|
||||
}
|
||||
skinningInfo->Optimize(maxWeightsPerVertex, weightThreshold);
|
||||
|
||||
return skinningInfo;
|
||||
}
|
||||
@@ -192,17 +269,12 @@ namespace AZ::SceneGenerationComponents
|
||||
const AZStd::vector<AZStd::pair<const IMeshData*, NodeIndex>> meshes = [](const SceneGraph& graph)
|
||||
{
|
||||
AZStd::vector<AZStd::pair<const IMeshData*, NodeIndex>> meshes;
|
||||
for (auto it = graph.GetContentStorage().cbegin(); it != graph.GetContentStorage().cend(); ++it)
|
||||
const auto meshNodes = Containers::MakeDerivedFilterView<IMeshData>(graph.GetContentStorage());
|
||||
for (auto it = meshNodes.cbegin(); it != meshNodes.cend(); ++it)
|
||||
{
|
||||
// Skip anything that isn't a mesh.
|
||||
const auto* mesh = azdynamic_cast<const AZ::SceneAPI::DataTypes::IMeshData*>(it->get());
|
||||
if (!mesh)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the mesh data and node index and store them in the vector as a pair, so we can iterate over them later.
|
||||
meshes.emplace_back(mesh, graph.ConvertToNodeIndex(it));
|
||||
// The sequential calls to GetBaseIterator unwrap the layers of FilterIterators from the MakeDerivedFilterView
|
||||
meshes.emplace_back(&(*it), graph.ConvertToNodeIndex(it.GetBaseIterator().GetBaseIterator().GetBaseIterator()));
|
||||
}
|
||||
return meshes;
|
||||
}(graph);
|
||||
@@ -287,6 +359,12 @@ namespace AZ::SceneGenerationComponents
|
||||
|
||||
auto [optimizedMesh, optimizedUVs, optimizedTangents, optimizedBitangents, optimizedVertexColors, optimizedSkinWeights] = OptimizeMesh(mesh, mesh, uvDatas, tangentDatas, bitangentDatas, colorDatas, skinWeightDatas, meshGroup, hasBlendShapes);
|
||||
|
||||
AZ_TracePrintf(AZ::SceneAPI::Utilities::LogWindow, "Base mesh: %zu vertices, optimized mesh: %zu vertices, %0.02f%% of the original",
|
||||
mesh->GetUsedControlPointCount(),
|
||||
optimizedMesh->GetUsedControlPointCount(),
|
||||
((float)optimizedMesh->GetUsedControlPointCount() / (float)mesh->GetUsedControlPointCount()) * 100.0f
|
||||
);
|
||||
|
||||
const NodeIndex optimizedMeshNodeIndex = graph.AddChild(graph.GetNodeParent(nodeIndex), name.c_str(), AZStd::move(optimizedMesh));
|
||||
|
||||
auto addOptimizedNodes = [&graph, &optimizedMeshNodeIndex](const auto& originalNodeIndexes, auto& optimizedNodes)
|
||||
@@ -428,10 +506,9 @@ namespace AZ::SceneGenerationComponents
|
||||
const AZStd::vector<MeshBuilder::MeshBuilderVertexAttributeLayerVector3*> bitangentLayers = makeLayersForData(bitangents);
|
||||
const AZStd::vector<MeshBuilder::MeshBuilderVertexAttributeLayerColor*> vertexColorLayers = makeLayersForData(vertexColors);
|
||||
|
||||
const auto* skinRule = meshGroup.GetRuleContainerConst().FindFirstByType<SceneAPI::DataTypes::ISkinRule>().get();
|
||||
const AZ::u32 maxWeightsPerVertex = skinRule ? skinRule->GetMaxWeightsPerVertex() : 4;
|
||||
const float weightThreshold = skinRule ? skinRule->GetWeightThreshold() : 0.001f;
|
||||
meshBuilder.SetSkinningInfo(ExtractSkinningInfo(meshData, skinWeights, maxWeightsPerVertex, weightThreshold));
|
||||
constexpr float positionTolerance = 0.0001f;
|
||||
Vector3Map positionMap(meshData, hasBlendShapes, positionTolerance);
|
||||
positionMap.reserve(vertexCount);
|
||||
|
||||
// Add the vertex data to all the layers
|
||||
const AZ::u32 faceCount = meshData->GetFaceCount();
|
||||
@@ -440,8 +517,8 @@ namespace AZ::SceneGenerationComponents
|
||||
meshBuilder.BeginPolygon(baseMesh->GetFaceMaterialId(faceIndex));
|
||||
for (const AZ::u32 vertexIndex : meshData->GetFaceInfo(faceIndex).vertexIndex)
|
||||
{
|
||||
const int orgVertexNumber = meshData->GetUsedPointIndexForControlPoint(meshData->GetControlPointIndex(vertexIndex));
|
||||
AZ_Assert(orgVertexNumber >= 0, "Invalid vertex number");
|
||||
const AZ::u32 orgVertexNumber = positionMap[vertexIndex];
|
||||
|
||||
orgVtxLayer->SetCurrentVertexValue(orgVertexNumber);
|
||||
|
||||
posLayer->SetCurrentVertexValue(meshData->GetPosition(vertexIndex));
|
||||
@@ -471,6 +548,12 @@ namespace AZ::SceneGenerationComponents
|
||||
|
||||
meshBuilder.EndPolygon();
|
||||
}
|
||||
|
||||
const auto* skinRule = meshGroup.GetRuleContainerConst().FindFirstByType<SceneAPI::DataTypes::ISkinRule>().get();
|
||||
const AZ::u32 maxWeightsPerVertex = skinRule ? skinRule->GetMaxWeightsPerVertex() : 4;
|
||||
const float weightThreshold = skinRule ? skinRule->GetWeightThreshold() : 0.001f;
|
||||
meshBuilder.SetSkinningInfo(ExtractSkinningInfo(meshData, skinWeights, maxWeightsPerVertex, weightThreshold, positionMap));
|
||||
|
||||
meshBuilder.GenerateSubMeshVertexOrders();
|
||||
|
||||
// Create the resulting nodes
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Jobs/JobManagerComponent.h>
|
||||
#include <AzCore/Memory/MemoryComponent.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <SceneAPI/SceneCore/Containers/Scene.h>
|
||||
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/GraphData/IMeshData.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/GraphData/ISkinWeightData.h>
|
||||
#include <SceneAPI/SceneCore/Events/GenerateEventContext.h>
|
||||
#include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
|
||||
#include <SceneAPI/SceneData/GraphData/MeshData.h>
|
||||
#include <SceneAPI/SceneData/GraphData/SkinWeightData.h>
|
||||
#include <SceneAPI/SceneData/Groups/MeshGroup.h>
|
||||
#include <Generation/Components/MeshOptimizer/MeshOptimizerComponent.h>
|
||||
|
||||
#include <InitSceneAPIFixture.h>
|
||||
|
||||
namespace AZ::SceneAPI::DataTypes
|
||||
{
|
||||
void PrintTo(const ISkinWeightData::Link& link, ::std::ostream* os)
|
||||
{
|
||||
*os << '{' << link.boneId << ", " << link.weight << '}';
|
||||
}
|
||||
}
|
||||
|
||||
namespace SceneProcessing
|
||||
{
|
||||
class VertexDeduplicationFixture
|
||||
: public SceneProcessing::InitSceneAPIFixture
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
SceneProcessing::InitSceneAPIFixture::SetUp();
|
||||
|
||||
m_systemEntity = m_app.Create({}, {});
|
||||
m_systemEntity->AddComponent(aznew AZ::MemoryComponent());
|
||||
m_systemEntity->AddComponent(aznew AZ::JobManagerComponent());
|
||||
m_systemEntity->Init();
|
||||
m_systemEntity->Activate();
|
||||
}
|
||||
void TearDown() override
|
||||
{
|
||||
m_systemEntity->Deactivate();
|
||||
SceneProcessing::InitSceneAPIFixture::TearDown();
|
||||
}
|
||||
|
||||
static AZStd::unique_ptr<AZ::SceneAPI::DataTypes::IMeshData> MakePlaneMesh()
|
||||
{
|
||||
// Create a simple plane with 2 triangles, 6 total vertices, 2 shared vertices
|
||||
// 0 --- 1
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// 2 --- 3
|
||||
const AZStd::array planeVertexPositions = {
|
||||
AZ::Vector3{0.0f, 0.0f, 0.0f},
|
||||
AZ::Vector3{0.0f, 0.0f, 1.0f},
|
||||
AZ::Vector3{1.0f, 0.0f, 1.0f},
|
||||
AZ::Vector3{1.0f, 0.0f, 1.0f},
|
||||
AZ::Vector3{1.0f, 0.0f, 0.0f},
|
||||
AZ::Vector3{0.0f, 0.0f, 0.0f},
|
||||
};
|
||||
|
||||
auto mesh = AZStd::make_unique<AZ::SceneData::GraphData::MeshData>();
|
||||
|
||||
int i = 0;
|
||||
for (const AZ::Vector3& position : planeVertexPositions)
|
||||
{
|
||||
mesh->AddPosition(position);
|
||||
mesh->AddNormal(AZ::Vector3::CreateAxisY());
|
||||
|
||||
// This assumes that the data coming from the import process gives a unique control point
|
||||
// index to every vertex. This follows the behavior of the AssImp library.
|
||||
mesh->SetVertexIndexToControlPointIndexMap(i, i);
|
||||
++i;
|
||||
}
|
||||
|
||||
mesh->AddFace({0, 1, 2}, 0);
|
||||
mesh->AddFace({3, 4, 5}, 0);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
static AZStd::unique_ptr<AZ::SceneData::GraphData::SkinWeightData> MakeSkinData()
|
||||
{
|
||||
auto skinWeights = AZStd::make_unique<AZ::SceneData::GraphData::SkinWeightData>();
|
||||
|
||||
skinWeights->ResizeContainerSpace(6);
|
||||
|
||||
// Add bones 0 and 1 to the skin weights
|
||||
skinWeights->GetBoneId("0");
|
||||
skinWeights->GetBoneId("1");
|
||||
|
||||
skinWeights->AppendLink(0, {/*.boneId=*/0, /*.weight=*/1});
|
||||
skinWeights->AppendLink(1, {/*.boneId=*/0, /*.weight=*/1});
|
||||
skinWeights->AppendLink(2, {/*.boneId=*/0, /*.weight=*/1});
|
||||
skinWeights->AppendLink(3, {/*.boneId=*/1, /*.weight=*/1});
|
||||
skinWeights->AppendLink(4, {/*.boneId=*/1, /*.weight=*/1});
|
||||
skinWeights->AppendLink(5, {/*.boneId=*/1, /*.weight=*/1});
|
||||
|
||||
return skinWeights;
|
||||
}
|
||||
|
||||
private:
|
||||
AZ::ComponentApplication m_app;
|
||||
AZ::Entity* m_systemEntity;
|
||||
};
|
||||
|
||||
TEST_F(VertexDeduplicationFixture, CanDeduplicateVertices)
|
||||
{
|
||||
AZ::SceneAPI::Containers::Scene scene("testScene");
|
||||
AZ::SceneAPI::Containers::SceneGraph& graph = scene.GetGraph();
|
||||
|
||||
const auto meshNodeIndex = graph.AddChild(graph.GetRoot(), "testMesh", MakePlaneMesh());
|
||||
|
||||
// The original source mesh should have 6 vertices
|
||||
EXPECT_EQ(AZStd::rtti_pointer_cast<AZ::SceneAPI::DataTypes::IMeshData>(graph.GetNodeContent(meshNodeIndex))->GetVertexCount(), 6);
|
||||
|
||||
auto meshGroup = AZStd::make_unique<AZ::SceneAPI::SceneData::MeshGroup>();
|
||||
meshGroup->GetSceneNodeSelectionList().AddSelectedNode("testMesh");
|
||||
scene.GetManifest().AddEntry(AZStd::move(meshGroup));
|
||||
|
||||
AZ::SceneGenerationComponents::MeshOptimizerComponent component;
|
||||
AZ::SceneAPI::Events::GenerateSimplificationEventContext context(scene, "pc");
|
||||
component.OptimizeMeshes(context);
|
||||
|
||||
AZ::SceneAPI::Containers::SceneGraph::NodeIndex optimizedNodeIndex = graph.Find(AZStd::string("testMesh").append(AZ::SceneAPI::Utilities::OptimizedMeshSuffix));
|
||||
ASSERT_TRUE(optimizedNodeIndex.IsValid()) << "Mesh optimizer did not add an optimized version of the mesh";
|
||||
|
||||
const auto& optimizedMesh = AZStd::rtti_pointer_cast<AZ::SceneAPI::DataTypes::IMeshData>(graph.GetNodeContent(optimizedNodeIndex));
|
||||
ASSERT_TRUE(optimizedMesh);
|
||||
|
||||
// The optimized mesh should have 4 vertices, the 2 shared vertices are welded together
|
||||
EXPECT_EQ(optimizedMesh->GetVertexCount(), 4);
|
||||
}
|
||||
|
||||
MATCHER(VectorOfLinksEq, "")
|
||||
{
|
||||
return testing::ExplainMatchResult(
|
||||
testing::AllOf(
|
||||
testing::Field(&AZ::SceneData::GraphData::SkinWeightData::Link::boneId, testing::Eq(testing::get<0>(arg).boneId)),
|
||||
testing::Field(&AZ::SceneData::GraphData::SkinWeightData::Link::weight, testing::FloatEq(testing::get<0>(arg).weight))
|
||||
),
|
||||
testing::get<1>(arg),
|
||||
result_listener
|
||||
);
|
||||
}
|
||||
|
||||
MATCHER(VectorOfVectorOfLinksEq, "")
|
||||
{
|
||||
return testing::ExplainMatchResult(
|
||||
testing::UnorderedPointwise(VectorOfLinksEq(), testing::get<0>(arg)),
|
||||
testing::get<1>(arg),
|
||||
result_listener
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(VertexDeduplicationFixture, DeduplicatedVerticesRemapSkinning)
|
||||
{
|
||||
AZ::SceneAPI::Containers::Scene scene("testScene");
|
||||
AZ::SceneAPI::Containers::SceneGraph& graph = scene.GetGraph();
|
||||
|
||||
const auto meshNodeIndex = graph.AddChild(graph.GetRoot(), "testMesh", MakePlaneMesh());
|
||||
const auto skinDataNodeIndex = graph.AddChild(meshNodeIndex, "skinData", MakeSkinData());
|
||||
graph.MakeEndPoint(skinDataNodeIndex);
|
||||
|
||||
// The original source mesh should have 6 vertices
|
||||
EXPECT_EQ(AZStd::rtti_pointer_cast<AZ::SceneAPI::DataTypes::IMeshData>(graph.GetNodeContent(meshNodeIndex))->GetVertexCount(), 6);
|
||||
|
||||
auto meshGroup = AZStd::make_unique<AZ::SceneAPI::SceneData::MeshGroup>();
|
||||
meshGroup->GetSceneNodeSelectionList().AddSelectedNode("testMesh");
|
||||
scene.GetManifest().AddEntry(AZStd::move(meshGroup));
|
||||
|
||||
AZ::SceneGenerationComponents::MeshOptimizerComponent component;
|
||||
AZ::SceneAPI::Events::GenerateSimplificationEventContext context(scene, "pc");
|
||||
component.OptimizeMeshes(context);
|
||||
|
||||
AZ::SceneAPI::Containers::SceneGraph::NodeIndex optimizedNodeIndex = graph.Find(AZStd::string("testMesh").append(AZ::SceneAPI::Utilities::OptimizedMeshSuffix));
|
||||
ASSERT_TRUE(optimizedNodeIndex.IsValid()) << "Mesh optimizer did not add an optimized version of the mesh";
|
||||
|
||||
const auto& optimizedMesh = AZStd::rtti_pointer_cast<AZ::SceneAPI::DataTypes::IMeshData>(graph.GetNodeContent(optimizedNodeIndex));
|
||||
ASSERT_TRUE(optimizedMesh);
|
||||
|
||||
AZ::SceneAPI::Containers::SceneGraph::NodeIndex optimizedSkinDataNodeIndex = graph.Find(AZStd::string("testMesh").append(AZ::SceneAPI::Utilities::OptimizedMeshSuffix).append(".skinWeights"));
|
||||
ASSERT_TRUE(optimizedSkinDataNodeIndex.IsValid()) << "Mesh optimizer did not add an optimized version of the skin data";
|
||||
|
||||
const auto& optimizedSkinWeights = AZStd::rtti_pointer_cast<AZ::SceneAPI::DataTypes::ISkinWeightData>(graph.GetNodeContent(optimizedSkinDataNodeIndex));
|
||||
ASSERT_TRUE(optimizedSkinWeights);
|
||||
|
||||
const AZStd::vector<AZStd::vector<AZ::SceneData::GraphData::SkinWeightData::Link>> expectedLinks
|
||||
{
|
||||
/*0*/ { {0, 0.5f}, {1, 0.5f} },
|
||||
/*1*/ { {0, 1.0f} },
|
||||
/*2*/ { {0, 0.5f}, {1, 0.5f} },
|
||||
/*3*/ { {1, 1.0f} },
|
||||
};
|
||||
|
||||
AZStd::vector<AZStd::vector<AZ::SceneData::GraphData::SkinWeightData::Link>> gotLinks(optimizedMesh->GetVertexCount());
|
||||
for (unsigned int vertexIndex = 0; vertexIndex < optimizedMesh->GetVertexCount(); ++vertexIndex)
|
||||
{
|
||||
for (size_t linkIndex = 0; linkIndex < optimizedSkinWeights->GetLinkCount(vertexIndex); ++linkIndex)
|
||||
{
|
||||
gotLinks[vertexIndex].emplace_back(optimizedSkinWeights->GetLink(vertexIndex, linkIndex));
|
||||
}
|
||||
}
|
||||
EXPECT_THAT(gotLinks, testing::Pointwise(VectorOfVectorOfLinksEq(), expectedLinks));
|
||||
}
|
||||
} // namespace SceneProcessing
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
set(FILES
|
||||
Tests/InitSceneAPIFixture.h
|
||||
Tests/MeshBuilder/MeshOptimizerComponentTests.cpp
|
||||
Tests/MeshBuilder/MeshBuilderTests.cpp
|
||||
Tests/MeshBuilder/MeshVerticesTests.cpp
|
||||
Tests/MeshBuilder/SkinInfluencesTests.cpp
|
||||
|
||||
Reference in New Issue
Block a user