Merge branch 'development' of https://github.com/aws-lumberyard-dev/o3de into scripting/rte_issues
This commit is contained in:
@@ -64,7 +64,7 @@ namespace AWSCore
|
||||
|
||||
void AWSCoreConfiguration::InitSourceProjectFolderPath()
|
||||
{
|
||||
auto sourceProjectFolder = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@");
|
||||
auto sourceProjectFolder = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@");
|
||||
if (!sourceProjectFolder)
|
||||
{
|
||||
AZ_Error(AWSCoreConfigurationName, false, ProjectSourceFolderNotFoundErrorMessage);
|
||||
|
||||
@@ -197,7 +197,7 @@ namespace AWSCore
|
||||
subMenu->addAction(AddExternalLinkAction(
|
||||
AWSMetricsAdvancedTopicsActionText, AWSMetricsAdvancedTopicsUrl, ":/Notifications/link.svg"));
|
||||
|
||||
AZStd::string priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@");
|
||||
AZStd::string priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@engroot@");
|
||||
AZStd::string configFilePath = priorAlias + "\\Gems\\AWSMetrics\\Code\\" + AZ::SettingsRegistryInterface::RegistryFolder;
|
||||
AzFramework::StringFunc::Path::Normalize(configFilePath);
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
m_normalizedSourceProjectFolder.c_str(), AZ::SettingsRegistryInterface::RegistryFolder);
|
||||
AzFramework::StringFunc::Path::Normalize(m_normalizedSetRegFolderPath);
|
||||
|
||||
m_localFileIO->SetAlias("@devassets@", m_normalizedSourceProjectFolder.c_str());
|
||||
m_localFileIO->SetAlias("@projectroot@", m_normalizedSourceProjectFolder.c_str());
|
||||
|
||||
CreateTestSetRegFile(TEST_VALID_RESOURCE_MAPPING_SETREG);
|
||||
}
|
||||
@@ -122,7 +122,7 @@ private:
|
||||
TEST_F(AWSCoreConfigurationTest, InitConfig_NoSourceProjectFolderFound_ReturnEmptyConfigFilePath)
|
||||
{
|
||||
m_settingsRegistry->MergeSettingsFile(m_normalizedSetRegFilePath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {});
|
||||
m_localFileIO->ClearAlias("@devassets@");
|
||||
m_localFileIO->ClearAlias("@projectroot@");
|
||||
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
m_awsCoreConfiguration->InitConfig();
|
||||
@@ -154,7 +154,7 @@ TEST_F(AWSCoreConfigurationTest, InitConfig_LoadValidSettingsRegistry_ReturnNonE
|
||||
TEST_F(AWSCoreConfigurationTest, ReloadConfiguration_NoSourceProjectFolderFound_ReturnEmptyConfigFilePath)
|
||||
{
|
||||
m_settingsRegistry->MergeSettingsFile(m_normalizedSetRegFilePath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {});
|
||||
m_localFileIO->ClearAlias("@devassets@");
|
||||
m_localFileIO->ClearAlias("@projectroot@");
|
||||
m_awsCoreConfiguration->ReloadConfiguration();
|
||||
|
||||
auto actualConfigFilePath = m_awsCoreConfiguration->GetResourceMappingConfigFilePath();
|
||||
|
||||
@@ -32,7 +32,7 @@ class AWSCoreEditorMenuTest
|
||||
{
|
||||
AWSCoreEditorUIFixture::SetUp();
|
||||
AWSCoreFixture::SetUp();
|
||||
m_localFileIO->SetAlias("@devroot@", "dummy engine root");
|
||||
m_localFileIO->SetAlias("@engroot@", "dummy engine root");
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
|
||||
@@ -52,6 +52,7 @@ class AWSGameLift(core.Construct):
|
||||
stack_name=stack_name,
|
||||
fleet_configurations=fleet_configurations,
|
||||
create_game_session_queue=self.node.try_get_context('create_game_session_queue') == 'true',
|
||||
flex_match=self.node.try_get_context('flex_match') == 'true',
|
||||
description=f'Contains resources for the AWS GameLift Gem stack as part of the {project_name} project',
|
||||
tags=tags,
|
||||
env=env
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
# Matchmaking rule formatted as a JSON string.
|
||||
# Comments are not allowed in JSON, but most elements support a description field.
|
||||
# For instructions on designing Matchmaking rule sets, please check:
|
||||
# https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-design-ruleset.html
|
||||
RULE_SET_BODY = '{"ruleLanguageVersion":"1.0","teams":[{"name":"Players","maxPlayers":4,"minPlayers":2}]}'
|
||||
|
||||
# A flag that determines whether a match that was created with this configuration
|
||||
# must be accepted by the matched players.
|
||||
ACCEPTANCE_REQUIRED = False
|
||||
|
||||
# The maximum duration, in seconds, that a matchmaking ticket can remain in process before timing out.
|
||||
# Requests that fail due to timing out can be resubmitted as needed.
|
||||
REQUEST_TIMEOUT_SECONDS = 300
|
||||
|
||||
# The number of player slots in a match to keep open for future players.
|
||||
# This parameter is not used if FlexMatchMode is set to STANDALONE.
|
||||
ADDITIONAL_PLAYER_COUNT = 2
|
||||
|
||||
# The method used to backfill game sessions that are created with this matchmaking configuration.
|
||||
# Specify MANUAL when your game manages backfill requests manually or does not use the match backfill feature.
|
||||
# Specify AUTOMATIC to have GameLift create a StartMatchBackfill request whenever a game session has one or more
|
||||
# open slots.
|
||||
BACKFILL_MODE = 'AUTOMATIC'
|
||||
@@ -0,0 +1,60 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import typing
|
||||
|
||||
from aws_cdk import (
|
||||
core,
|
||||
aws_gamelift as gamelift
|
||||
)
|
||||
|
||||
from . import flexmatch_configurations
|
||||
|
||||
FLEX_MATCH_MODE = 'WITH_QUEUE'
|
||||
|
||||
|
||||
class MatchmakingResoures:
|
||||
"""
|
||||
Create a matchmaking rule set and matchmaking configuration for Gamelift FlexMatch.
|
||||
For more information about Gamelift FlexMatch, please check
|
||||
https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-intro.html
|
||||
"""
|
||||
def __init__(self, stack: core.Stack, game_session_queue_arns: typing.List[str]):
|
||||
rule_set = gamelift.CfnMatchmakingRuleSet(
|
||||
scope=stack,
|
||||
id='MatchmakingRuleSet',
|
||||
name=f'{stack.stack_name}-MatchmakingRuleSet',
|
||||
rule_set_body=flexmatch_configurations.RULE_SET_BODY
|
||||
)
|
||||
|
||||
matchmaking_configuration = gamelift.CfnMatchmakingConfiguration(
|
||||
scope=stack,
|
||||
id='MatchmakingConfiguration',
|
||||
acceptance_required=flexmatch_configurations.ACCEPTANCE_REQUIRED,
|
||||
name=f'{stack.stack_name}-MatchmakingConfiguration',
|
||||
request_timeout_seconds=flexmatch_configurations.REQUEST_TIMEOUT_SECONDS,
|
||||
rule_set_name=rule_set.name,
|
||||
additional_player_count=flexmatch_configurations.ADDITIONAL_PLAYER_COUNT,
|
||||
backfill_mode=flexmatch_configurations.BACKFILL_MODE,
|
||||
flex_match_mode=FLEX_MATCH_MODE,
|
||||
game_session_queue_arns=game_session_queue_arns if len(game_session_queue_arns) else None
|
||||
)
|
||||
matchmaking_configuration.node.add_dependency(rule_set)
|
||||
|
||||
# Export the matchmaking rule set and configuration names as stack outputs
|
||||
core.CfnOutput(
|
||||
stack,
|
||||
id='MatchmakingRuleSetName',
|
||||
description='Name of the matchmaking rule set',
|
||||
export_name=f'{stack.stack_name}:MatchmakingRuleSet',
|
||||
value=rule_set.name)
|
||||
core.CfnOutput(
|
||||
stack,
|
||||
id='MatchmakingConfigurationName',
|
||||
description='Name of the matchmaking configuration',
|
||||
export_name=f'{stack.stack_name}:MatchmakingConfiguration',
|
||||
value=matchmaking_configuration.name)
|
||||
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
import typing
|
||||
|
||||
from aws_cdk import (
|
||||
core,
|
||||
aws_gamelift as gamelift
|
||||
)
|
||||
|
||||
|
||||
class GameSessionQueueResources:
|
||||
"""
|
||||
Create a game session queue which fulfills game session placement requests using the fleets.
|
||||
For more information about Gamelift game session queues, please check
|
||||
https://docs.aws.amazon.com/gamelift/latest/developerguide/queues-intro.html
|
||||
"""
|
||||
def __init__(self, stack: core.Stack, destinations: typing.List):
|
||||
self._game_session_queue = gamelift.CfnGameSessionQueue(
|
||||
scope=stack,
|
||||
id=f'{stack.stack_name}-GameLiftQueue',
|
||||
name=f'{stack.stack_name}-GameLiftQueue',
|
||||
destinations=[
|
||||
gamelift.CfnGameSessionQueue.DestinationProperty(
|
||||
destination_arn=resource_arn
|
||||
) for resource_arn in destinations
|
||||
]
|
||||
)
|
||||
|
||||
# Export the game session queue name as a stack output
|
||||
core.CfnOutput(
|
||||
scope=stack,
|
||||
id='GameSessionQueue',
|
||||
description='Name of the game session queue',
|
||||
export_name=f'{stack.stack_name}:GameSessionQueue',
|
||||
value=self._game_session_queue.name)
|
||||
|
||||
@property
|
||||
def game_session_queue_arn(self) -> str:
|
||||
return self._game_session_queue.attr_arn
|
||||
@@ -5,10 +5,13 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import typing
|
||||
from aws_cdk import (
|
||||
core,
|
||||
aws_gamelift as gamelift
|
||||
)
|
||||
|
||||
from aws_cdk import core
|
||||
from aws_cdk import aws_gamelift as gamelift
|
||||
from .flexmatch import matchmaking
|
||||
from .game_session_queue import game_session_queue
|
||||
|
||||
|
||||
class GameLiftStack(core.Stack):
|
||||
@@ -19,7 +22,9 @@ class GameLiftStack(core.Stack):
|
||||
"""
|
||||
def __init__(self, scope: core.Construct, id_: str,
|
||||
stack_name: str, fleet_configurations: dict,
|
||||
create_game_session_queue: bool, **kwargs) -> None:
|
||||
create_game_session_queue: bool,
|
||||
flex_match: bool,
|
||||
**kwargs) -> None:
|
||||
super().__init__(scope, id_, **kwargs)
|
||||
|
||||
self._stack_name = stack_name
|
||||
@@ -50,7 +55,7 @@ class GameLiftStack(core.Stack):
|
||||
queue_destinations.append(destination_arn)
|
||||
|
||||
# Export the GameLift fleet ids as a stack output
|
||||
fleets_output = core.CfnOutput(
|
||||
core.CfnOutput(
|
||||
self,
|
||||
id='GameLiftFleets',
|
||||
description='List of GameLift fleet ids',
|
||||
@@ -58,17 +63,13 @@ class GameLiftStack(core.Stack):
|
||||
value=','.join(fleet_ids)
|
||||
)
|
||||
|
||||
if create_game_session_queue:
|
||||
# Create a game session queue which fulfills game session placement requests using the fleets
|
||||
game_session_queue = self._create_game_session_queue(queue_destinations)
|
||||
game_session_queue_arns = []
|
||||
if flex_match or create_game_session_queue:
|
||||
queue = game_session_queue.GameSessionQueueResources(self, queue_destinations)
|
||||
game_session_queue_arns.append(queue.game_session_queue_arn)
|
||||
|
||||
# Export the game session queue name as a stack output
|
||||
game_session_queue_output = core.CfnOutput(
|
||||
self,
|
||||
id='GameSessionQueue',
|
||||
description='Name of the game session queue',
|
||||
export_name=f'{self._stack_name}:GameSessionQueue',
|
||||
value=game_session_queue.name)
|
||||
if flex_match:
|
||||
matchmaking.MatchmakingResoures(self, game_session_queue_arns)
|
||||
|
||||
def _create_fleet(self, fleet_configuration: dict, identifier: int) -> gamelift.CfnFleet:
|
||||
"""
|
||||
@@ -155,25 +156,3 @@ class GameLiftStack(core.Stack):
|
||||
)
|
||||
|
||||
return alias
|
||||
|
||||
def _create_game_session_queue(self, destinations: typing.List) -> gamelift.CfnGameSessionQueue:
|
||||
"""
|
||||
Create a placement queue that processes requests for new game sessions.
|
||||
:param destinations: Destinations of the queue.
|
||||
:return: Generated GameLift game session queue.
|
||||
"""
|
||||
game_session_queue = gamelift.CfnGameSessionQueue(
|
||||
self,
|
||||
id=f'{self._stack_name}-GameLiftQueue',
|
||||
name=f'{self._stack_name}-game-session-queue',
|
||||
destinations=[
|
||||
gamelift.CfnGameSessionQueue.DestinationProperty(
|
||||
destination_arn=resource_arn
|
||||
) for resource_arn in destinations
|
||||
]
|
||||
)
|
||||
|
||||
return game_session_queue
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace AWSMetrics
|
||||
|
||||
AZStd::string IdentityProvider::GetEngineVersion()
|
||||
{
|
||||
static constexpr const char* EngineConfigFilePath = "@root@/engine.json";
|
||||
static constexpr const char* EngineConfigFilePath = "@products@/engine.json";
|
||||
static constexpr const char* EngineVersionJsonKey = "O3DEVersion";
|
||||
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetDirectInstance();
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzCore/Settings/SettingsRegistryImpl.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
namespace AWSMetrics
|
||||
{
|
||||
@@ -34,15 +34,22 @@ namespace AWSMetrics
|
||||
// Set up the file IO and alias
|
||||
m_localFileIO = aznew AZ::IO::LocalFileIO();
|
||||
m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
// we need to set it to nullptr first because otherwise the
|
||||
// we need to set it to nullptr first because otherwise the
|
||||
// underneath code assumes that we might be leaking the previous instance
|
||||
AZ::IO::FileIOBase::SetInstance(nullptr);
|
||||
AZ::IO::FileIOBase::SetInstance(m_localFileIO);
|
||||
|
||||
const AZStd::string engineRoot = AZ::Test::GetEngineRootPath();
|
||||
m_localFileIO->SetAlias("@devroot@", engineRoot.c_str());
|
||||
m_localFileIO->SetAlias("@root@", engineRoot.c_str());
|
||||
m_localFileIO->SetAlias("@user@", GetTestFolderPath().c_str());
|
||||
const AZ::IO::Path engineRoot = AZ::Test::GetEngineRootPath();
|
||||
const auto productAssetPath = GetTestFolderPath() / "Cache";
|
||||
const auto userPath = GetTestFolderPath() / "user";
|
||||
m_localFileIO->CreatePath(productAssetPath.c_str());
|
||||
m_localFileIO->CreatePath(userPath.c_str());
|
||||
m_localFileIO->SetAlias("@engroot@", engineRoot.c_str());
|
||||
m_localFileIO->SetAlias("@products@", productAssetPath.c_str());
|
||||
m_localFileIO->SetAlias("@user@", userPath.c_str());
|
||||
// Copy engine.json to the cache
|
||||
EXPECT_TRUE(m_localFileIO->Copy((engineRoot / "engine.json").c_str(), "engine.json"));
|
||||
|
||||
|
||||
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
|
||||
m_registrationContext = AZStd::make_unique<AZ::JsonRegistrationContext>();
|
||||
@@ -69,6 +76,13 @@ namespace AWSMetrics
|
||||
m_serializeContext.reset();
|
||||
m_registrationContext.reset();
|
||||
|
||||
const auto productAssetPath = GetTestFolderPath() / "Cache";
|
||||
const auto userPath = GetTestFolderPath() / "user";
|
||||
// Clear the product asset cache alias to prevent cache write errors
|
||||
m_localFileIO->ClearAlias("@products@");
|
||||
m_localFileIO->DestroyPath(userPath.c_str());
|
||||
m_localFileIO->DestroyPath(productAssetPath.c_str());
|
||||
|
||||
AZ::IO::FileIOBase::SetInstance(nullptr);
|
||||
delete m_localFileIO;
|
||||
AZ::IO::FileIOBase::SetInstance(m_priorFileIO);
|
||||
@@ -97,22 +111,22 @@ namespace AWSMetrics
|
||||
bool CreateFile(const AZStd::string& filePath, const AZStd::string& content)
|
||||
{
|
||||
AZ::IO::HandleType fileHandle;
|
||||
// Suppress errors about writing to product asset cache
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
if (!m_localFileIO->Open(filePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText, fileHandle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_localFileIO->Write(fileHandle, content.c_str(), content.size());
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
|
||||
m_localFileIO->Close(fileHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
AZStd::string GetDefaultTestFilePath()
|
||||
{
|
||||
AZStd::string testFilePath = GetTestFolderPath();
|
||||
AzFramework::StringFunc::Path::Join(testFilePath.c_str(), "Test.json", testFilePath);
|
||||
|
||||
return testFilePath;
|
||||
return (GetTestFolderPath() / "Test.json").Native();
|
||||
}
|
||||
|
||||
bool RemoveFile(const AZStd::string& filePath)
|
||||
@@ -133,14 +147,16 @@ namespace AWSMetrics
|
||||
AZ::IO::FileIOBase* m_priorFileIO = nullptr;
|
||||
AZ::IO::FileIOBase* m_localFileIO = nullptr;
|
||||
|
||||
AZ::Test::ScopedAutoTempDirectory m_testDirectory;
|
||||
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
AZStd::unique_ptr<AZ::JsonRegistrationContext> m_registrationContext;
|
||||
AZStd::unique_ptr<AZ::SettingsRegistryImpl> m_settingsRegistry;
|
||||
|
||||
private:
|
||||
AZStd::string GetTestFolderPath()
|
||||
AZ::IO::Path GetTestFolderPath()
|
||||
{
|
||||
return AZ_TRAIT_TEST_ROOT_FOLDER;
|
||||
AZ::IO::Path testPathString{ m_testDirectory.GetDirectory() };
|
||||
return testPathString;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -142,14 +142,14 @@ namespace AssetValidation
|
||||
system.GetIConsole()->AddCommand("addseedlist", ConsoleCommandAddSeedList);
|
||||
system.GetIConsole()->AddCommand("removeseedlist", ConsoleCommandRemoveSeedList);
|
||||
system.GetIConsole()->AddCommand("printexcluded", ConsoleCommandTogglePrintExcluded);
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetValidationSystemComponent::IsKnownAsset(const char* assetPath)
|
||||
{
|
||||
AZStd::string lowerAsset{ assetPath };
|
||||
AZStd::replace(lowerAsset.begin(), lowerAsset.end(), AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR);
|
||||
|
||||
const AZStd::vector<AZStd::string> prefixes = { "./", "@assets@/" };
|
||||
const AZStd::vector<AZStd::string> prefixes = { "./", "@products@/" };
|
||||
for (const AZStd::string& prefix : prefixes)
|
||||
{
|
||||
if (lowerAsset.starts_with(prefix))
|
||||
@@ -392,7 +392,7 @@ namespace AssetValidation
|
||||
AssetValidationRequestBus::Broadcast(&AssetValidationRequestBus::Events::AddSeedList, seedfilepath);
|
||||
}
|
||||
|
||||
bool AssetValidationSystemComponent::AddSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId)
|
||||
bool AssetValidationSystemComponent::AddSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId)
|
||||
{
|
||||
for (const AzFramework::SeedInfo& thisSeed : seedList)
|
||||
{
|
||||
@@ -401,7 +401,7 @@ namespace AssetValidation
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetValidationSystemComponent::RemoveSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId)
|
||||
bool AssetValidationSystemComponent::RemoveSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId)
|
||||
{
|
||||
AssetValidationRequests::AssetSourceList removeList;
|
||||
for (const AzFramework::SeedInfo& thisSeed : seedList)
|
||||
|
||||
+1
-1
@@ -244,7 +244,7 @@ namespace ImageProcessingAtom
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPath projectConfigFolder;
|
||||
if (auto sourceGameRoot = fileIoBase->ResolvePath("@devassets@"); sourceGameRoot.has_value())
|
||||
if (auto sourceGameRoot = fileIoBase->ResolvePath("@projectroot@"); sourceGameRoot.has_value())
|
||||
{
|
||||
projectConfigFolder = *sourceGameRoot;
|
||||
projectConfigFolder /= s_projectConfigRelativeFolder;
|
||||
|
||||
@@ -139,16 +139,16 @@ namespace AZ
|
||||
//! Validates if a given .shadervariantlist file is located at the correct path for a given .shader full path.
|
||||
//! There are two valid paths:
|
||||
//! 1- Lower Precedence: The same folder where the .shader file is located.
|
||||
//! 2- Higher Precedence: <DEVROOT>/<GAME>/ShaderVariants/<Same Scan Folder Subpath as the .shader file>.
|
||||
//! 2- Higher Precedence: <project-path>/ShaderVariants/<Same Scan Folder Subpath as the .shader file>.
|
||||
//! The "Higher Precedence" path gives the option to game projects to override what variants to generate. If this
|
||||
//! file exists then the "Lower Precedence" path is disregarded.
|
||||
//! A .shader full path is located under an AP scan folder.
|
||||
//! Example: "<DEVROOT>/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader"
|
||||
//! - In this example the Scan Folder is "<DEVROOT>/Gems/Atom/Feature/Common/Assets", while the subfolder is "Materials/Types".
|
||||
//! Example: "<atom-gem-path>/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader"
|
||||
//! - In this example the Scan Folder is "<atom-gem-path>/Gems/Atom/Feature/Common/Assets", while the subfolder is "Materials/Types".
|
||||
//! The "Higher Precedence" expected valid location for the .shadervariantlist would be:
|
||||
//! - <DEVROOT>/<GameProject>/ShaderVariants/Materials/Types/StandardPBR_ForwardPass.shadervariantlist.
|
||||
//! - <atom-gem-path>/<GameProject>/ShaderVariants/Materials/Types/StandardPBR_ForwardPass.shadervariantlist.
|
||||
//! The "Lower Precedence" valid location would be:
|
||||
//! - <DEVROOT>/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shadervariantlist.
|
||||
//! - <atom-gem-path>/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shadervariantlist.
|
||||
//! @shouldExitEarlyFromProcessJob [out] Set to true if ProcessJob should do no work but return successfully.
|
||||
//! Set to false if ProcessJob should do work and create assets.
|
||||
//! When @shaderVariantListFileFullPath is provided by a Gem/Feature instead of the Game Project
|
||||
@@ -169,17 +169,13 @@ namespace AZ
|
||||
AZStd::string shaderVariantListFileRelativePath = shaderProductFileRelativePath;
|
||||
AzFramework::StringFunc::Path::ReplaceExtension(shaderVariantListFileRelativePath, RPI::ShaderVariantListSourceData::Extension);
|
||||
|
||||
const char * gameProjectPath = nullptr;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(gameProjectPath, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath);
|
||||
AZ::IO::FixedMaxPath gameProjectPath = AZ::Utils::GetProjectPath();
|
||||
|
||||
AZStd::string expectedHigherPrecedenceFileFullPath;
|
||||
AzFramework::StringFunc::Path::Join(gameProjectPath, RPI::ShaderVariantTreeAsset::CommonSubFolder, expectedHigherPrecedenceFileFullPath, false /* handle directory overlap? */, false /* be case insensitive? */);
|
||||
AzFramework::StringFunc::Path::Join(expectedHigherPrecedenceFileFullPath.c_str(), shaderProductFileRelativePath.c_str(), expectedHigherPrecedenceFileFullPath, false /* handle directory overlap? */, false /* be case insensitive? */);
|
||||
AzFramework::StringFunc::Path::ReplaceExtension(expectedHigherPrecedenceFileFullPath, AZ::RPI::ShaderVariantListSourceData::Extension);
|
||||
AzFramework::StringFunc::Path::Normalize(expectedHigherPrecedenceFileFullPath);
|
||||
auto expectedHigherPrecedenceFileFullPath = (gameProjectPath
|
||||
/ RPI::ShaderVariantTreeAsset::CommonSubFolder / shaderProductFileRelativePath).LexicallyNormal();
|
||||
expectedHigherPrecedenceFileFullPath.ReplaceExtension(AZ::RPI::ShaderVariantListSourceData::Extension);
|
||||
|
||||
AZStd::string normalizedShaderVariantListFileFullPath = shaderVariantListFileFullPath;
|
||||
AzFramework::StringFunc::Path::Normalize(normalizedShaderVariantListFileFullPath);
|
||||
auto normalizedShaderVariantListFileFullPath = AZ::IO::FixedMaxPath(shaderVariantListFileFullPath).LexicallyNormal();
|
||||
|
||||
if (expectedHigherPrecedenceFileFullPath == normalizedShaderVariantListFileFullPath)
|
||||
{
|
||||
@@ -203,23 +199,15 @@ namespace AZ
|
||||
}
|
||||
|
||||
// Check the "Lower Precedence" case, .shader path == .shadervariantlist path.
|
||||
AZStd::string normalizedShaderFileFullPath = shaderFileFullPath;
|
||||
AzFramework::StringFunc::Path::Normalize(normalizedShaderFileFullPath);
|
||||
AZ::IO::Path normalizedShaderFileFullPath = AZ::IO::Path(shaderFileFullPath).LexicallyNormal();
|
||||
|
||||
AZStd::string normalizedShaderFileFullPathWithoutExtension = normalizedShaderFileFullPath;
|
||||
AzFramework::StringFunc::Path::StripExtension(normalizedShaderFileFullPathWithoutExtension);
|
||||
auto normalizedShaderFileFullPathWithoutExtension = normalizedShaderFileFullPath;
|
||||
normalizedShaderFileFullPathWithoutExtension.ReplaceExtension("");
|
||||
|
||||
AZStd::string normalizedShaderVariantListFileFullPathWithoutExtension = normalizedShaderVariantListFileFullPath;
|
||||
AzFramework::StringFunc::Path::StripExtension(normalizedShaderVariantListFileFullPathWithoutExtension);
|
||||
auto normalizedShaderVariantListFileFullPathWithoutExtension = normalizedShaderVariantListFileFullPath;
|
||||
normalizedShaderVariantListFileFullPathWithoutExtension.ReplaceExtension("");
|
||||
|
||||
#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
|
||||
//In certain circumstances, the capitalization of the drive letter may not match
|
||||
const bool caseSensitive = false;
|
||||
#else
|
||||
//On the other platforms there's no drive letter, so it should be a non-issue.
|
||||
const bool caseSensitive = true;
|
||||
#endif
|
||||
if (!StringFunc::Equal(normalizedShaderFileFullPathWithoutExtension.c_str(), normalizedShaderVariantListFileFullPathWithoutExtension.c_str(), caseSensitive))
|
||||
if (normalizedShaderFileFullPathWithoutExtension != normalizedShaderVariantListFileFullPathWithoutExtension)
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "For shader file at path [%s], the shader variant list [%s] is expected to be located at [%s.%s] or [%s]"
|
||||
, normalizedShaderFileFullPath.c_str(), normalizedShaderVariantListFileFullPath.c_str(),
|
||||
|
||||
@@ -14,10 +14,14 @@
|
||||
#include <Atom/RPI.Public/Shader/ShaderSystemInterface.h>
|
||||
#include <Atom/Feature/Material/MaterialAssignment.h>
|
||||
#include <Atom/Feature/TransformService/TransformServiceFeatureProcessor.h>
|
||||
#include <Atom/Feature/Mesh/ModelReloaderSystemInterface.h>
|
||||
#include <RayTracing/RayTracingFeatureProcessor.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AtomCore/std/parallel/concurrency_checker.h>
|
||||
#include <AzCore/Console/Console.h>
|
||||
#include <AzFramework/Asset/AssetCatalogBus.h>
|
||||
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -38,6 +42,7 @@ namespace AZ
|
||||
private:
|
||||
class MeshLoader
|
||||
: private Data::AssetBus::Handler
|
||||
, private AzFramework::AssetCatalogEventBus::Handler
|
||||
{
|
||||
public:
|
||||
using ModelChangedEvent = MeshFeatureProcessorInterface::ModelChangedEvent;
|
||||
@@ -52,6 +57,15 @@ namespace AZ
|
||||
void OnAssetReady(Data::Asset<Data::AssetData> asset) override;
|
||||
void OnAssetError(Data::Asset<Data::AssetData> asset) override;
|
||||
|
||||
// AssetCatalogEventBus::Handler overrides...
|
||||
void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override;
|
||||
void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override;
|
||||
|
||||
void OnModelReloaded(Data::Asset<Data::AssetData> asset);
|
||||
ModelReloadedEvent::Handler m_modelReloadedEventHandler { [&](Data::Asset<RPI::ModelAsset> modelAsset)
|
||||
{
|
||||
OnModelReloaded(modelAsset);
|
||||
} };
|
||||
MeshFeatureProcessorInterface::ModelChangedEvent m_modelChangedEvent;
|
||||
Data::Asset<RPI::ModelAsset> m_modelAsset;
|
||||
MeshDataInstance* m_parent = nullptr;
|
||||
@@ -61,6 +75,7 @@ namespace AZ
|
||||
void Init(Data::Instance<RPI::Model> model);
|
||||
void BuildDrawPacketList(size_t modelLodIndex);
|
||||
void SetRayTracingData();
|
||||
void RemoveRayTracingData();
|
||||
void SetSortKey(RHI::DrawItemSortKey sortKey);
|
||||
RHI::DrawItemSortKey GetSortKey() const;
|
||||
void SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig);
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <AzCore/EBus/Event.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Data
|
||||
{
|
||||
template<class T>
|
||||
class Asset;
|
||||
}
|
||||
|
||||
namespace Render
|
||||
{
|
||||
using ModelReloadedEvent = Event<const Data::Asset<RPI::ModelAsset>>;
|
||||
|
||||
//! A system that handles reloading the hierarchy of model assets in the correct order
|
||||
class ModelReloaderSystemInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(AZ::Render::ModelReloaderSystemInterface, "{E7E05B1F-8928-4A1B-B75D-3D5433E65BCA}");
|
||||
|
||||
ModelReloaderSystemInterface()
|
||||
{
|
||||
Interface<ModelReloaderSystemInterface>::Register(this);
|
||||
}
|
||||
|
||||
virtual ~ModelReloaderSystemInterface()
|
||||
{
|
||||
Interface<ModelReloaderSystemInterface>::Unregister(this);
|
||||
}
|
||||
|
||||
static ModelReloaderSystemInterface* Get()
|
||||
{
|
||||
return Interface<ModelReloaderSystemInterface>::Get();
|
||||
}
|
||||
|
||||
//! Requests a model reload and passes in a callback event handler for when the reload is finished
|
||||
virtual void ReloadModel(
|
||||
Data::Asset<RPI::ModelAsset> modelAsset, ModelReloadedEvent::Handler& onReloadedEventHandler) = 0;
|
||||
|
||||
// Note that you have to delete these for safety reasons, you will trip a static_assert if you do not
|
||||
AZ_DISABLE_COPY_MOVE(ModelReloaderSystemInterface);
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
@@ -103,11 +103,15 @@
|
||||
#include <ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h>
|
||||
#include <ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h>
|
||||
#include <OcclusionCullingPlane/OcclusionCullingPlaneFeatureProcessor.h>
|
||||
#include <Mesh/ModelReloaderSystem.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
CommonSystemComponent::CommonSystemComponent() = default;
|
||||
CommonSystemComponent::~CommonSystemComponent() = default;
|
||||
|
||||
void CommonSystemComponent::Reflect(ReflectContext* context)
|
||||
{
|
||||
AuxGeomFeatureProcessor::Reflect(context);
|
||||
@@ -292,10 +296,13 @@ namespace AZ
|
||||
// setup handler for load pass template mappings
|
||||
m_loadTemplatesHandler = RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler([this]() { this->LoadPassTemplateMappings(); });
|
||||
RPI::PassSystemInterface::Get()->ConnectEvent(m_loadTemplatesHandler);
|
||||
|
||||
m_modelReloaderSystem = AZStd::make_unique<ModelReloaderSystem>();
|
||||
}
|
||||
|
||||
void CommonSystemComponent::Deactivate()
|
||||
{
|
||||
m_modelReloaderSystem.reset();
|
||||
m_loadTemplatesHandler.Disconnect();
|
||||
AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor<RayTracingFeatureProcessor>();
|
||||
AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor<DiffuseGlobalIlluminationFeatureProcessor>();
|
||||
|
||||
@@ -20,12 +20,17 @@ namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
class ModelReloaderSystem;
|
||||
|
||||
class CommonSystemComponent
|
||||
: public AZ::Component
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(CommonSystemComponent, "{BFB8FE2B-C952-4D0C-8E32-4FE7C7A97757}");
|
||||
|
||||
CommonSystemComponent();
|
||||
~CommonSystemComponent();
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
@@ -44,6 +49,8 @@ namespace AZ
|
||||
|
||||
RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler m_loadTemplatesHandler;
|
||||
|
||||
AZStd::unique_ptr<ModelReloaderSystem> m_modelReloaderSystem;
|
||||
|
||||
#if AZ_TRAIT_LUXCORE_SUPPORTED
|
||||
// LuxCore
|
||||
LuxCoreRenderer m_luxCore;
|
||||
|
||||
+3
-20
@@ -54,27 +54,10 @@ namespace AZ
|
||||
m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass);
|
||||
|
||||
// retrieve the number of threads per thread group from the shader
|
||||
const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" });
|
||||
if (numThreads)
|
||||
const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
const RHI::ShaderStageAttributeArguments& args = *numThreads;
|
||||
bool validArgs = args.size() == 3;
|
||||
if (validArgs)
|
||||
{
|
||||
validArgs &= args[0].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[1].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[2].type() == azrtti_typeid<int>();
|
||||
}
|
||||
|
||||
if (!validArgs)
|
||||
{
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeGridBlendDistancePass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_dispatchArgs.m_threadsPerGroupX = static_cast<uint16_t>(AZStd::any_cast<int>(args[0]));
|
||||
m_dispatchArgs.m_threadsPerGroupY = static_cast<uint16_t>(AZStd::any_cast<int>(args[1]));
|
||||
m_dispatchArgs.m_threadsPerGroupZ = static_cast<uint16_t>(AZStd::any_cast<int>(args[2]));
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeGridBlendDistancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-20
@@ -54,27 +54,10 @@ namespace AZ
|
||||
m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass);
|
||||
|
||||
// retrieve the number of threads per thread group from the shader
|
||||
const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" });
|
||||
if (numThreads)
|
||||
const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
const RHI::ShaderStageAttributeArguments& args = *numThreads;
|
||||
bool validArgs = args.size() == 3;
|
||||
if (validArgs)
|
||||
{
|
||||
validArgs &= args[0].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[1].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[2].type() == azrtti_typeid<int>();
|
||||
}
|
||||
|
||||
if (!validArgs)
|
||||
{
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_dispatchArgs.m_threadsPerGroupX = static_cast<uint16_t>(AZStd::any_cast<int>(args[0]));
|
||||
m_dispatchArgs.m_threadsPerGroupY = static_cast<uint16_t>(AZStd::any_cast<int>(args[1]));
|
||||
m_dispatchArgs.m_threadsPerGroupZ = static_cast<uint16_t>(AZStd::any_cast<int>(args[2]));
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-20
@@ -67,27 +67,10 @@ namespace AZ
|
||||
srgLayout = shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass);
|
||||
|
||||
// retrieve the number of threads per thread group from the shader
|
||||
const auto numThreads = shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" });
|
||||
if (numThreads)
|
||||
const auto outcome = RPI::GetComputeShaderNumThreads(shader->GetAsset(), dispatchArgs);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
const RHI::ShaderStageAttributeArguments& args = *numThreads;
|
||||
bool validArgs = args.size() == 3;
|
||||
if (validArgs)
|
||||
{
|
||||
validArgs &= args[0].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[1].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[2].type() == azrtti_typeid<int>();
|
||||
}
|
||||
|
||||
if (!validArgs)
|
||||
{
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeGridBorderUpdatePass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
dispatchArgs.m_threadsPerGroupX = static_cast<uint16_t>(AZStd::any_cast<int>(args[0]));
|
||||
dispatchArgs.m_threadsPerGroupY = static_cast<uint16_t>(AZStd::any_cast<int>(args[1]));
|
||||
dispatchArgs.m_threadsPerGroupZ = static_cast<uint16_t>(AZStd::any_cast<int>(args[2]));
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeGridBorderUpdatePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-20
@@ -58,27 +58,10 @@ namespace AZ
|
||||
m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass);
|
||||
|
||||
// retrieve the number of threads per thread group from the shader
|
||||
const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" });
|
||||
if (numThreads)
|
||||
const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
const RHI::ShaderStageAttributeArguments& args = *numThreads;
|
||||
bool validArgs = args.size() == 3;
|
||||
if (validArgs)
|
||||
{
|
||||
validArgs &= args[0].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[1].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[2].type() == azrtti_typeid<int>();
|
||||
}
|
||||
|
||||
if (!validArgs)
|
||||
{
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeClassificationPass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_dispatchArgs.m_threadsPerGroupX = static_cast<uint16_t>(AZStd::any_cast<int>(args[0]));
|
||||
m_dispatchArgs.m_threadsPerGroupY = static_cast<uint16_t>(AZStd::any_cast<int>(args[1]));
|
||||
m_dispatchArgs.m_threadsPerGroupZ = static_cast<uint16_t>(AZStd::any_cast<int>(args[2]));
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeClassificationPass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-20
@@ -58,27 +58,10 @@ namespace AZ
|
||||
m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass);
|
||||
|
||||
// retrieve the number of threads per thread group from the shader
|
||||
const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" });
|
||||
if (numThreads)
|
||||
const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
const RHI::ShaderStageAttributeArguments& args = *numThreads;
|
||||
bool validArgs = args.size() == 3;
|
||||
if (validArgs)
|
||||
{
|
||||
validArgs &= args[0].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[1].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[2].type() == azrtti_typeid<int>();
|
||||
}
|
||||
|
||||
if (!validArgs)
|
||||
{
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeRelocationPass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_dispatchArgs.m_threadsPerGroupX = static_cast<uint16_t>(AZStd::any_cast<int>(args[0]));
|
||||
m_dispatchArgs.m_threadsPerGroupY = static_cast<uint16_t>(AZStd::any_cast<int>(args[1]));
|
||||
m_dispatchArgs.m_threadsPerGroupZ = static_cast<uint16_t>(AZStd::any_cast<int>(args[2]));
|
||||
AZ_Error("PassSystem", false, "[DiffuseProbeRelocationPass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
|
||||
#include <Atom/Feature/RenderCommon.h>
|
||||
#include <Atom/Feature/Mesh/MeshFeatureProcessor.h>
|
||||
#include <Atom/Feature/Mesh/ModelReloaderSystemInterface.h>
|
||||
#include <Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h>
|
||||
#include <Atom/RPI.Public/Model/ModelLodUtils.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
@@ -18,6 +19,8 @@
|
||||
|
||||
#include <Atom/RPI.Reflect/Model/ModelAssetCreator.h>
|
||||
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
|
||||
#include <AtomCore/Instance/InstanceDatabase.h>
|
||||
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
@@ -175,6 +178,7 @@ namespace AZ
|
||||
{
|
||||
if (meshHandle.IsValid())
|
||||
{
|
||||
meshHandle->m_meshLoader.reset();
|
||||
meshHandle->DeInit();
|
||||
m_transformService->ReleaseObjectId(meshHandle->m_objectId);
|
||||
|
||||
@@ -487,10 +491,12 @@ namespace AZ
|
||||
}
|
||||
|
||||
Data::AssetBus::Handler::BusConnect(modelAsset.GetId());
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
MeshDataInstance::MeshLoader::~MeshLoader()
|
||||
{
|
||||
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
|
||||
Data::AssetBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
@@ -533,6 +539,7 @@ namespace AZ
|
||||
|
||||
if (model)
|
||||
{
|
||||
m_parent->RemoveRayTracingData();
|
||||
m_parent->Init(model);
|
||||
m_modelChangedEvent.Signal(AZStd::move(model));
|
||||
}
|
||||
@@ -545,10 +552,51 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MeshDataInstance::MeshLoader::OnModelReloaded(Data::Asset<Data::AssetData> asset)
|
||||
{
|
||||
OnAssetReady(asset);
|
||||
}
|
||||
|
||||
void MeshDataInstance::MeshLoader::OnAssetError(Data::Asset<Data::AssetData> asset)
|
||||
{
|
||||
// Note: m_modelAsset and asset represents same asset, but only m_modelAsset contains the file path in its hint from serialization
|
||||
AZ_Error("MeshDataInstance::MeshLoader", false, "Failed to load asset %s.", m_modelAsset.GetHint().c_str());
|
||||
AZ_Error(
|
||||
"MeshDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing",
|
||||
m_modelAsset.GetHint().c_str());
|
||||
|
||||
AzFramework::AssetSystemRequestBus::Broadcast(
|
||||
&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetByUuid, m_modelAsset.GetId().m_guid);
|
||||
}
|
||||
|
||||
void MeshDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
if (assetId == m_modelAsset.GetId())
|
||||
{
|
||||
Data::Asset<RPI::ModelAsset> modelAssetReference = m_modelAsset;
|
||||
|
||||
// If the asset was modified, reload it
|
||||
AZ::SystemTickBus::QueueFunction(
|
||||
[=]() mutable
|
||||
{
|
||||
ModelReloaderSystemInterface::Get()->ReloadModel(modelAssetReference, m_modelReloadedEventHandler);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void MeshDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
if (assetId == m_modelAsset.GetId())
|
||||
{
|
||||
Data::Asset<RPI::ModelAsset> modelAssetReference = m_modelAsset;
|
||||
|
||||
// If the asset didn't exist in the catalog when it first attempted to load, we need to try loading it again
|
||||
AZ::SystemTickBus::QueueFunction(
|
||||
[=]() mutable
|
||||
{
|
||||
ModelReloaderSystemInterface::Get()->ReloadModel(modelAssetReference, m_modelReloadedEventHandler);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// MeshDataInstance...
|
||||
@@ -557,14 +605,8 @@ namespace AZ
|
||||
{
|
||||
m_scene->GetCullingScene()->UnregisterCullable(m_cullable);
|
||||
|
||||
// remove from ray tracing
|
||||
RayTracingFeatureProcessor* rayTracingFeatureProcessor = m_scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
|
||||
if (rayTracingFeatureProcessor)
|
||||
{
|
||||
rayTracingFeatureProcessor->RemoveMesh(m_objectId);
|
||||
}
|
||||
RemoveRayTracingData();
|
||||
|
||||
m_meshLoader.reset();
|
||||
m_drawPacketListsByLod.clear();
|
||||
m_materialAssignments.clear();
|
||||
m_shaderResourceGroup = {};
|
||||
@@ -951,6 +993,16 @@ namespace AZ
|
||||
rayTracingFeatureProcessor->SetMesh(m_objectId, m_model->GetModelAsset()->GetId(), subMeshes);
|
||||
}
|
||||
|
||||
void MeshDataInstance::RemoveRayTracingData()
|
||||
{
|
||||
// remove from ray tracing
|
||||
RayTracingFeatureProcessor* rayTracingFeatureProcessor = m_scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
|
||||
if (rayTracingFeatureProcessor)
|
||||
{
|
||||
rayTracingFeatureProcessor->RemoveMesh(m_objectId);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey)
|
||||
{
|
||||
m_sortKey = sortKey;
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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 <Source/Mesh/ModelReloader.h>
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <Atom/RPI.Public/Model/Model.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
ModelReloader::ModelReloader(
|
||||
Data::Asset<RPI::ModelAsset> modelAsset, RemoveModelFromReloaderSystemEvent::Handler& removeReloaderFromSystemHandler)
|
||||
{
|
||||
m_modelAsset.push_back(modelAsset);
|
||||
m_pendingDependencyListStatus.reset();
|
||||
removeReloaderFromSystemHandler.Connect(m_onRemoveReloaderFromSystem);
|
||||
|
||||
// Iterate over the model and track the assets that need to be reloaded
|
||||
for (auto& modelLodAsset : modelAsset->GetLodAssets())
|
||||
{
|
||||
for (auto& mesh : modelLodAsset->GetMeshes())
|
||||
{
|
||||
for (auto& streamBufferInfo : mesh.GetStreamBufferInfoList())
|
||||
{
|
||||
InsertMeshDependencyIfUnique(streamBufferInfo.m_bufferAssetView.GetBufferAsset());
|
||||
|
||||
}
|
||||
InsertMeshDependencyIfUnique(mesh.GetIndexBufferAssetView().GetBufferAsset());
|
||||
}
|
||||
m_modelDependencies.push_back(modelLodAsset);
|
||||
}
|
||||
|
||||
AZ_Assert(
|
||||
m_meshDependencies.size() <= m_pendingDependencyListStatus.size(),
|
||||
"There are more buffers used by the model %s than are supported by the ModelReloader.", modelAsset.GetHint().c_str());
|
||||
|
||||
m_state = State::WaitingForMeshDependencies;
|
||||
ReloadDependenciesAndWait();
|
||||
}
|
||||
|
||||
void ModelReloader::ConnectOnReloadedEventHandler(ModelReloadedEvent::Handler& onReloadedEventHandler)
|
||||
{
|
||||
onReloadedEventHandler.Connect(m_onModelReloaded);
|
||||
}
|
||||
|
||||
void ModelReloader::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
DependencyList& pendingDependencies = GetPendingDependencyList();
|
||||
|
||||
const Data::AssetId& reloadedAssetId = asset.GetId();
|
||||
|
||||
// Find the index of the asset that was reloaded
|
||||
const auto matchesId = [reloadedAssetId](const Data::Asset<Data::AssetData>& asset){ return asset.GetId() == reloadedAssetId;};
|
||||
const auto& iter = AZStd::find_if(AZStd::begin(pendingDependencies), AZStd::end(pendingDependencies), matchesId);
|
||||
AZ_Assert(
|
||||
iter != AZStd::end(pendingDependencies),
|
||||
"ModelReloader - handling an AssetReloaded event for an asset that is not part of the dependency list.");
|
||||
size_t currentIndex = AZStd::distance(AZStd::begin(pendingDependencies), iter);
|
||||
|
||||
// Keep a reference to the newly reloaded asset to prevent it from being immediately released
|
||||
pendingDependencies[currentIndex] = asset;
|
||||
Data::AssetBus::MultiHandler::BusDisconnect(reloadedAssetId);
|
||||
|
||||
// Clear the bit, now that it has been reloaded
|
||||
m_pendingDependencyListStatus.reset(currentIndex);
|
||||
|
||||
if (m_pendingDependencyListStatus.none())
|
||||
{
|
||||
AdvanceToNextLevelOfHierarchy();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelReloader::OnAssetReloadError(Data::Asset<Data::AssetData> asset)
|
||||
{
|
||||
// An error is actually okay/expected in some situations.
|
||||
// For example, if the 2nd UV set was removed, and we tried to reload the second uv set, the reload would fail.
|
||||
// We want to treat it as a success, and mark that dependency as 'up to date'
|
||||
OnAssetReloaded(asset);
|
||||
}
|
||||
|
||||
void ModelReloader::InsertMeshDependencyIfUnique(Data::Asset<Data::AssetData> asset)
|
||||
{
|
||||
if (AZStd::find(AZStd::begin(m_meshDependencies), AZStd::end(m_meshDependencies), asset) == AZStd::end(m_meshDependencies))
|
||||
{
|
||||
// Multiple meshes may reference the same buffer, so only add the dependency if it is unique
|
||||
m_meshDependencies.push_back(asset);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelReloader::ReloadDependenciesAndWait()
|
||||
{
|
||||
// Get the current list of dependencies depending on the current state
|
||||
DependencyList& dependencies = GetPendingDependencyList();
|
||||
|
||||
if (!m_pendingDependencyListStatus.none())
|
||||
{
|
||||
AZ_Assert(
|
||||
m_pendingDependencyListStatus.none(),
|
||||
"ModelReloader attempting to add new dependencies while still waiting for other dependencies in the hierarchy to "
|
||||
"load.");
|
||||
}
|
||||
if (dependencies.empty())
|
||||
{
|
||||
// If the original model asset failed to load, it won't have any dependencies to reload
|
||||
AdvanceToNextLevelOfHierarchy();
|
||||
}
|
||||
AZ_Assert(
|
||||
dependencies.size() <= m_pendingDependencyListStatus.size(),
|
||||
"ModelReloader has more dependencies than can fit in the bitset. The size of m_pendingDependencyListStatus needs to be increased.");
|
||||
|
||||
// Set all bits to 1
|
||||
m_pendingDependencyListStatus.set();
|
||||
// Clear the least significant n-bits
|
||||
m_pendingDependencyListStatus <<= dependencies.size();
|
||||
// Set the least significant n-bits to 1, and the rest to 0
|
||||
m_pendingDependencyListStatus.flip();
|
||||
|
||||
// Reload all the assets
|
||||
for (Data::Asset<Data::AssetData>& dependencyAsset : dependencies)
|
||||
{
|
||||
Data::AssetBus::MultiHandler::BusConnect(dependencyAsset.GetId());
|
||||
dependencyAsset.Reload();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelReloader::AdvanceToNextLevelOfHierarchy()
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case State::WaitingForMeshDependencies:
|
||||
m_state = State::WaitingForModelDependencies;
|
||||
ReloadDependenciesAndWait();
|
||||
break;
|
||||
case State::WaitingForModelDependencies:
|
||||
m_state = State::WaitingForModel;
|
||||
ReloadDependenciesAndWait();
|
||||
break;
|
||||
case State::WaitingForModel:
|
||||
Data::AssetBus::MultiHandler::BusDisconnect();
|
||||
// Since the model asset is finished reloading, orphan model from the instance database
|
||||
// so that all of the buffer instances are re-created with the latest data
|
||||
RPI::Model::TEMPOrphanFromDatabase(m_modelAsset.front());
|
||||
// Signal that the model is ready
|
||||
m_onModelReloaded.Signal(m_modelAsset.front());
|
||||
// Remove this reloader from the ModelReloaderSystem
|
||||
m_onRemoveReloaderFromSystem.Signal(m_modelAsset.front().GetId());
|
||||
delete this;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ModelReloader::DependencyList& ModelReloader::GetPendingDependencyList()
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case State::WaitingForMeshDependencies:
|
||||
return m_meshDependencies;
|
||||
break;
|
||||
case State::WaitingForModelDependencies:
|
||||
return m_modelDependencies;
|
||||
break;
|
||||
case State::WaitingForModel:
|
||||
default:
|
||||
return m_modelAsset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <Atom/Feature/Mesh/ModelReloaderSystemInterface.h>
|
||||
#include <Source/Mesh/ModelReloaderSystem.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
class ModelAsset;
|
||||
}
|
||||
|
||||
namespace Render
|
||||
{
|
||||
//! ModelReloader takes care of reloading Buffer, ModelLod, and Model assets in the correct order
|
||||
//! The ModelReloaderSystem should be used to reload a model, rather than using a ModelReloader directly
|
||||
class ModelReloader
|
||||
: private Data::AssetBus::MultiHandler
|
||||
{
|
||||
using DependencyList = AZStd::vector<Data::Asset<Data::AssetData>>;
|
||||
public:
|
||||
AZ_RTTI(AZ::Render::ModelReloader, "{99B75A6A-62B6-490A-9953-029BE7D69452}");
|
||||
|
||||
ModelReloader() = default;
|
||||
|
||||
//! Reload a model asset
|
||||
//! @param modelAsset - the asset to be reloaded
|
||||
//! @param removeReloaderFromSystemHandler - an event that will tell the ModelReloaderSystem when to remove the reloader because it is finished
|
||||
ModelReloader(Data::Asset<RPI::ModelAsset> modelAsset, RemoveModelFromReloaderSystemEvent::Handler& removeReloaderFromSystemHandler);
|
||||
|
||||
//! Connects a handler that will handle an event when the model is finished reloading
|
||||
void ConnectOnReloadedEventHandler(ModelReloadedEvent::Handler& onReloadedEventHandler);
|
||||
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
WaitingForMeshDependencies,
|
||||
WaitingForModelDependencies,
|
||||
WaitingForModel
|
||||
};
|
||||
|
||||
// Data::AssetBus::MultiHandler overrides...
|
||||
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
void OnAssetReloadError(Data::Asset<Data::AssetData> asset) override;
|
||||
|
||||
void InsertMeshDependencyIfUnique(Data::Asset<Data::AssetData> asset);
|
||||
void ReloadDependenciesAndWait();
|
||||
void AdvanceToNextLevelOfHierarchy();
|
||||
DependencyList& GetPendingDependencyList();
|
||||
|
||||
ModelReloadedEvent m_onModelReloaded;
|
||||
RemoveModelFromReloaderSystemEvent m_onRemoveReloaderFromSystem;
|
||||
|
||||
// Keep track of all the asset references for each level of the hierarchy
|
||||
DependencyList m_modelAsset;
|
||||
DependencyList m_meshDependencies;
|
||||
DependencyList m_modelDependencies;
|
||||
|
||||
AZStd::bitset<1024> m_pendingDependencyListStatus;
|
||||
State m_state;
|
||||
};
|
||||
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 <Source/Mesh/ModelReloaderSystem.h>
|
||||
#include <Source/Mesh/ModelReloader.h>
|
||||
#include <AzCore/std/parallel/scoped_lock.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
void ModelReloaderSystem::ReloadModel(Data::Asset<RPI::ModelAsset> modelAsset, ModelReloadedEvent::Handler& onReloadedEventHandler)
|
||||
{
|
||||
AZStd::scoped_lock lock(m_pendingReloadMutex);
|
||||
if (m_pendingReloads.find(modelAsset.GetId()) == m_pendingReloads.end())
|
||||
{
|
||||
ModelReloader* reloader = new ModelReloader(modelAsset, m_removeModelHandler);
|
||||
m_pendingReloads[modelAsset.GetId()] = reloader;
|
||||
}
|
||||
|
||||
m_pendingReloads[modelAsset.GetId()]->ConnectOnReloadedEventHandler(onReloadedEventHandler);
|
||||
}
|
||||
|
||||
void ModelReloaderSystem::RemoveReloader(const Data::AssetId& assetId)
|
||||
{
|
||||
AZStd::scoped_lock lock(m_pendingReloadMutex);
|
||||
// We don't delete the ModelReloader here, because its in the middle of signaling this RemoveReloader event.
|
||||
// We only remove it from the pending reloads here.
|
||||
// The ModelReloader will delete itself after it finishes firing this event.
|
||||
m_pendingReloads.erase(assetId);
|
||||
}
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#include <Atom/Feature/Mesh/ModelReloaderSystemInterface.h>
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
class ModelReloader;
|
||||
|
||||
using RemoveModelFromReloaderSystemEvent = Event<const Data::AssetId&>;
|
||||
|
||||
class ModelReloaderSystem
|
||||
: public ModelReloaderSystemInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(Render::ModelReloaderSystem, "{8C85ECCD-B6C8-4949-B26C-9C4F1020F2B8}", Render::ModelReloaderSystemInterface);
|
||||
|
||||
void ReloadModel(Data::Asset<RPI::ModelAsset> modelAsset, ModelReloadedEvent::Handler& onReloadedEventHandler) override;
|
||||
|
||||
private:
|
||||
void RemoveReloader(const Data::AssetId& assetId);
|
||||
|
||||
// Keep track of all the pending reloads so there are no duplicates
|
||||
AZStd::unordered_map<Data::AssetId, ModelReloader*> m_pendingReloads;
|
||||
AZStd::mutex m_pendingReloadMutex;
|
||||
|
||||
RemoveModelFromReloaderSystemEvent::Handler m_removeModelHandler{
|
||||
[&](const Data::AssetId& assetId)
|
||||
{
|
||||
RemoveReloader(assetId);
|
||||
} };
|
||||
|
||||
friend class ModelReloader;
|
||||
};
|
||||
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <Atom/RPI.Public/Shader/Shader.h>
|
||||
#include <Atom/RPI.Public/Model/ModelLod.h>
|
||||
#include <Atom/RPI.Public/Buffer/Buffer.h>
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/BufferView.h>
|
||||
@@ -79,15 +80,11 @@ namespace AZ
|
||||
m_dispatchItem.m_pipelineState = m_morphTargetShader->AcquirePipelineState(pipelineStateDescriptor);
|
||||
|
||||
// Get the threads-per-group values from the compute shader [numthreads(x,y,z)]
|
||||
const auto& numThreads = m_morphTargetShader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, AZ::Name{ "numthreads" });
|
||||
auto& arguments = m_dispatchItem.m_arguments.m_direct;
|
||||
if (numThreads)
|
||||
const auto outcome = RPI::GetComputeShaderNumThreads(m_morphTargetShader->GetAsset(), arguments);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
const auto& args = *numThreads;
|
||||
// Check that the arguments are valid integers, and fall back to 1,1,1 if there is an error
|
||||
arguments.m_threadsPerGroupX = static_cast<uint16_t>(args[0].type() == azrtti_typeid<int>() ? AZStd::any_cast<int>(args[0]) : 1);
|
||||
arguments.m_threadsPerGroupY = static_cast<uint16_t>(args[1].type() == azrtti_typeid<int>() ? AZStd::any_cast<int>(args[1]) : 1);
|
||||
arguments.m_threadsPerGroupZ = static_cast<uint16_t>(args[2].type() == azrtti_typeid<int>() ? AZStd::any_cast<int>(args[2]) : 1);
|
||||
AZ_Error("MorphTargetDispatchItem", false, outcome.GetError().c_str());
|
||||
}
|
||||
|
||||
arguments.m_totalNumberOfThreadsX = m_morphTargetMetaData.m_vertexCount;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <Atom/RPI.Public/Shader/Shader.h>
|
||||
#include <Atom/RPI.Public/Model/ModelLod.h>
|
||||
#include <Atom/RPI.Public/Buffer/Buffer.h>
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
#include <Atom/RHI/BufferView.h>
|
||||
@@ -199,17 +200,14 @@ namespace AZ
|
||||
m_instanceSrg->Compile();
|
||||
m_dispatchItem.m_uniqueShaderResourceGroup = m_instanceSrg->GetRHIShaderResourceGroup();
|
||||
m_dispatchItem.m_pipelineState = m_skinningShader->AcquirePipelineState(pipelineStateDescriptor);
|
||||
|
||||
const auto& numThreads = m_skinningShader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, AZ::Name{ "numthreads" });
|
||||
auto& arguments = m_dispatchItem.m_arguments.m_direct;
|
||||
if (numThreads)
|
||||
{
|
||||
const auto& args = *numThreads;
|
||||
arguments.m_threadsPerGroupX = static_cast<uint16_t>(args[0].type() == azrtti_typeid<int>() ? AZStd::any_cast<int>(args[0]) : 1);
|
||||
arguments.m_threadsPerGroupY = static_cast<uint16_t>(args[1].type() == azrtti_typeid<int>() ? AZStd::any_cast<int>(args[1]) : 1);
|
||||
arguments.m_threadsPerGroupZ = static_cast<uint16_t>(args[2].type() == azrtti_typeid<int>() ? AZStd::any_cast<int>(args[2]) : 1);
|
||||
}
|
||||
|
||||
auto& arguments = m_dispatchItem.m_arguments.m_direct;
|
||||
const auto outcome = RPI::GetComputeShaderNumThreads(m_skinningShader->GetAsset(), arguments);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("SkinnedMeshInputBuffers", false, outcome.GetError().c_str());
|
||||
}
|
||||
|
||||
arguments.m_totalNumberOfThreadsX = xThreads;
|
||||
arguments.m_totalNumberOfThreadsY = yThreads;
|
||||
arguments.m_totalNumberOfThreadsZ = 1;
|
||||
|
||||
@@ -26,6 +26,7 @@ set(FILES
|
||||
Include/Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessor.h
|
||||
Include/Atom/Feature/LookupTable/LookupTableAsset.h
|
||||
Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
|
||||
Include/Atom/Feature/Mesh/ModelReloaderSystemInterface.h
|
||||
Include/Atom/Feature/PostProcessing/PostProcessingConstants.h
|
||||
Include/Atom/Feature/PostProcessing/SMAAFeatureProcessorInterface.h
|
||||
Include/Atom/Feature/PostProcess/PostFxLayerCategoriesConstants.h
|
||||
@@ -169,6 +170,10 @@ set(FILES
|
||||
Source/Math/MathFilter.cpp
|
||||
Source/Math/MathFilterDescriptor.h
|
||||
Source/Mesh/MeshFeatureProcessor.cpp
|
||||
Source/Mesh/ModelReloader.cpp
|
||||
Source/Mesh/ModelReloader.h
|
||||
Source/Mesh/ModelReloaderSystem.cpp
|
||||
Source/Mesh/ModelReloaderSystem.h
|
||||
Source/MorphTargets/MorphTargetComputePass.cpp
|
||||
Source/MorphTargets/MorphTargetComputePass.h
|
||||
Source/MorphTargets/MorphTargetDispatchItem.cpp
|
||||
|
||||
@@ -166,6 +166,10 @@ namespace AZ
|
||||
AZStd::array_view<ConstPtr<ImageView>> GetImageGroup() const;
|
||||
AZStd::array_view<ConstPtr<BufferView>> GetBufferGroup() const;
|
||||
AZStd::array_view<SamplerState> GetSamplerGroup() const;
|
||||
|
||||
//! Reset image and buffer views setup for this ShaderResourceGroupData
|
||||
//! So it won't hold references for any RHI resources
|
||||
void ResetViews();
|
||||
|
||||
//! Returns the opaque constant data populated by calls to SetConstant and SetConstantData.
|
||||
//!
|
||||
|
||||
@@ -330,6 +330,14 @@ namespace AZ
|
||||
return m_samplers;
|
||||
}
|
||||
|
||||
void ShaderResourceGroupData::ResetViews()
|
||||
{
|
||||
m_imageViews.assign(m_imageViews.size(), nullptr);
|
||||
m_bufferViews.assign(m_bufferViews.size(), nullptr);
|
||||
m_imageViewsUnboundedArray.assign(m_imageViewsUnboundedArray.size(), nullptr);
|
||||
m_bufferViewsUnboundedArray.assign(m_bufferViewsUnboundedArray.size(), nullptr);
|
||||
}
|
||||
|
||||
AZStd::array_view<uint8_t> ShaderResourceGroupData::GetConstantData() const
|
||||
{
|
||||
return m_constantsData.GetConstantData();
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace UnitTest
|
||||
m_application.reset();
|
||||
}
|
||||
|
||||
static constexpr const char TestDataFolder[] = "@devroot@/Gems/Atom/RHI/Code/Tests/UtilsTestsData/";
|
||||
static constexpr const char TestDataFolder[] = "@engroot@/Gems/Atom/RHI/Code/Tests/UtilsTestsData/";
|
||||
|
||||
AZStd::unique_ptr<AzFramework::Application> m_application;
|
||||
};
|
||||
|
||||
@@ -44,14 +44,14 @@ namespace AZ
|
||||
AZStd::string GetSourcePathByAssetId(const AZ::Data::AssetId& assetId);
|
||||
|
||||
//! Tries to resolve a relative file reference, given the path of a referencing file.
|
||||
//! @param originatingSourceFilePath Path to the parent file that references referencedSourceFilePath. May be absolute or relative to asset-root.
|
||||
//! @param originatingSourceFilePath Path to the parent file that references referencedSourceFilePath. May be absolute or relative to asset-root.
|
||||
//! @param referencedSourceFilePath Path that the parent file references. May be relative to the parent file location or relative to asset-root.
|
||||
//! @return A full path for referencedSourceFilePath, if a full path was found. If a full path could not be constructed, returns referencedSourceFilePath unmodified.
|
||||
AZStd::string ResolvePathReference(const AZStd::string& originatingSourceFilePath, const AZStd::string& referencedSourceFilePath);
|
||||
|
||||
//! Returns the list of paths where a source asset file could possibly appear.
|
||||
//! Returns the list of paths where a source asset file could possibly appear.
|
||||
//! This is intended for use by AssetBuilders when reporting dependencies, to support relative paths between source files.
|
||||
//! When a source data file references another file using a relative path, the path might be relative to the originating
|
||||
//! When a source data file references another file using a relative path, the path might be relative to the originating
|
||||
//! file or it might be a standard source asset path (i.e. relative to the logical asset-root). This function will help reporting
|
||||
//! dependencies on all possible locations where that file may appear at some point in the future.
|
||||
//! For example a file MyGem/Assets/Foo/a.json might reference another file as "Bar/b.json". In this case, calling
|
||||
@@ -94,9 +94,9 @@ namespace AZ
|
||||
template<typename AssetDataT>
|
||||
Outcome<AZ::Data::Asset<AssetDataT>> LoadAsset(const AZ::Data::AssetId& assetId, [[maybe_unused]] const char* sourcePathForDebug)
|
||||
{
|
||||
if (nullptr == AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"))
|
||||
if (nullptr == AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"))
|
||||
{
|
||||
// The absence of "@assets@" is not necessarily the reason LoadAsset() can't be used in CreateJobs(), but it
|
||||
// The absence of "@products@" is not necessarily the reason LoadAsset() can't be used in CreateJobs(), but it
|
||||
// is a symptom of calling LoadAsset() from CreateJobs() which is not supported.
|
||||
AZ_Assert(false, "It appears AssetUtils::LoadAsset() is being called in CreateJobs(). It can only be used in ProcessJob().");
|
||||
return AZ::Failure();
|
||||
|
||||
@@ -268,6 +268,8 @@ namespace AZ
|
||||
AZStd::vector<RHI::StreamBufferView> m_cachedStreamBufferViews;
|
||||
AZStd::vector<RHI::IndexBufferView> m_cachedIndexBufferViews;
|
||||
AZStd::vector<Data::Instance<ShaderResourceGroup>> m_cachedDrawSrg;
|
||||
|
||||
uint32_t m_nextDrawSrgIdx = 0;
|
||||
|
||||
// structure includes DrawItem and stream and index buffer index
|
||||
using BufferViewIndexType = uint32_t;
|
||||
|
||||
@@ -37,6 +37,10 @@ namespace AZ
|
||||
|
||||
static Data::Instance<Model> FindOrCreate(const Data::Asset<ModelAsset>& modelAsset);
|
||||
|
||||
//! Orphan the model, its lods, and all their buffers so that they can be replaced in the instance database
|
||||
//! This is a temporary function, that will be removed once the Model/ModelAsset classes no longer need it
|
||||
static void TEMPOrphanFromDatabase(const Data::Asset<ModelAsset>& modelAsset);
|
||||
|
||||
~Model() = default;
|
||||
|
||||
//! Blocks the CPU until the streaming upload is complete. Returns immediately if no
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
|
||||
#include <Atom/RHI/DispatchItem.h>
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
#include <Atom/RPI.Public/Image/StreamingImage.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
|
||||
@@ -40,6 +41,23 @@ namespace AZ
|
||||
|
||||
//! Loads a streaming image asset for the given file path
|
||||
Data::Instance<RPI::StreamingImage> LoadStreamingTexture(AZStd::string_view path);
|
||||
|
||||
//! Looks for a three arguments attribute named @attributeName in the given shader asset.
|
||||
//! Assigns the value to each non-null output variables.
|
||||
//! @param shaderAsset
|
||||
//! @param attributeName
|
||||
//! @param numThreadsX Can be NULL. If not NULL it takes the value of the 1st argument of the attribute. Becomes 1 on error.
|
||||
//! @param numThreadsY Can be NULL. If not NULL it takes the value of the 2nd argument of the attribute. Becomes 1 on error.
|
||||
//! @param numThreadsZ Can be NULL. If not NULL it takes the value of the 3rd argument of the attribute. Becomes 1 on error.
|
||||
//! @returns An Outcome instance with error message in case of error.
|
||||
AZ::Outcome<void, AZStd::string> GetComputeShaderNumThreads(const Data::Asset<ShaderAsset>& shaderAsset, const AZ::Name& attributeName, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ);
|
||||
|
||||
//! Same as above, but assumes the name of the attribute to be 'numthreads'.
|
||||
AZ::Outcome<void, AZStd::string> GetComputeShaderNumThreads(const Data::Asset<ShaderAsset>& shaderAsset, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ);
|
||||
|
||||
//! Same as above. Provided as a convenience when all arguments of the 'numthreads' attributes should be assigned to RHI::DispatchDirect::m_threadsPerGroup* variables.
|
||||
AZ::Outcome<void, AZStd::string> GetComputeShaderNumThreads(const Data::Asset<ShaderAsset>& shaderAsset, RHI::DispatchDirect& dispatchDirect);
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
|
||||
@@ -133,6 +133,9 @@ namespace AZ
|
||||
/// Returns an array of RPI buffers associated with the buffer shader input index.
|
||||
AZStd::array_view<Data::Instance<Buffer>> GetBufferArray(RHI::ShaderInputNameIndex& inputIndex) const;
|
||||
AZStd::array_view<Data::Instance<Buffer>> GetBufferArray(RHI::ShaderInputBufferIndex inputIndex) const;
|
||||
|
||||
//! Reset image and buffer views so that it won't hold references for any RHI resources
|
||||
void ResetViews();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Methods for assignment / access of RHI Image types.
|
||||
|
||||
@@ -60,6 +60,12 @@ namespace AZ
|
||||
const AZStd::string& GetName() const;
|
||||
|
||||
private:
|
||||
// AssetData overrides...
|
||||
bool HandleAutoReload() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called by asset creators to assign the asset to a ready state.
|
||||
void SetReady();
|
||||
|
||||
|
||||
@@ -77,6 +77,12 @@ namespace AZ
|
||||
float& distanceNormalized, AZ::Vector3& normal) const;
|
||||
|
||||
private:
|
||||
// AssetData overrides...
|
||||
bool HandleAutoReload() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetReady();
|
||||
|
||||
AZ::Name m_name;
|
||||
|
||||
@@ -149,6 +149,12 @@ namespace AZ
|
||||
const AZ::Aabb& GetAabb() const;
|
||||
|
||||
private:
|
||||
// AssetData overrides...
|
||||
bool HandleAutoReload() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::vector<Mesh> m_meshes;
|
||||
AZ::Aabb m_aabb = AZ::Aabb::CreateNull();
|
||||
|
||||
|
||||
@@ -518,7 +518,6 @@ namespace AZ
|
||||
if (drawSrg)
|
||||
{
|
||||
drawItem.m_uniqueShaderResourceGroup = drawSrg->GetRHIShaderResourceGroup();
|
||||
m_cachedDrawSrg.push_back(drawSrg);
|
||||
}
|
||||
|
||||
// Set scissor per draw if scissor is enabled.
|
||||
@@ -608,7 +607,6 @@ namespace AZ
|
||||
if (drawSrg)
|
||||
{
|
||||
drawItem.m_uniqueShaderResourceGroup = drawSrg->GetRHIShaderResourceGroup();
|
||||
m_cachedDrawSrg.push_back(drawSrg);
|
||||
}
|
||||
|
||||
// Set scissor per draw if scissor is enabled.
|
||||
@@ -635,7 +633,22 @@ namespace AZ
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto drawSrg = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_drawSrgLayout->GetName());
|
||||
|
||||
Data::Instance<ShaderResourceGroup> drawSrg;
|
||||
if (m_nextDrawSrgIdx == m_cachedDrawSrg.size())
|
||||
{
|
||||
drawSrg = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_drawSrgLayout->GetName());
|
||||
m_cachedDrawSrg.push_back(drawSrg);
|
||||
}
|
||||
else if (m_nextDrawSrgIdx < m_cachedDrawSrg.size())
|
||||
{
|
||||
drawSrg = m_cachedDrawSrg[m_nextDrawSrgIdx];
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Unexpected next draw srg index");
|
||||
}
|
||||
m_nextDrawSrgIdx++;
|
||||
|
||||
// Set fallback value for shader variant if draw srg contains constant for shader variant fallback
|
||||
if (m_hasShaderVariantKeyFallbackEntry)
|
||||
@@ -727,7 +740,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
for (auto& drawItemProperties : m_cachedDrawList)
|
||||
{
|
||||
{
|
||||
view->AddDrawItem(m_drawListTag, drawItemProperties);
|
||||
}
|
||||
}
|
||||
@@ -743,9 +756,14 @@ namespace AZ
|
||||
m_cachedDrawItems.clear();
|
||||
m_cachedStreamBufferViews.clear();
|
||||
m_cachedIndexBufferViews.clear();
|
||||
m_cachedDrawSrg.clear();
|
||||
m_cachedDrawList.clear();
|
||||
m_nextDrawSrgIdx = 0;
|
||||
m_drawFinalized = false;
|
||||
|
||||
for (auto srg:m_cachedDrawSrg)
|
||||
{
|
||||
srg->ResetViews();
|
||||
}
|
||||
}
|
||||
|
||||
const RHI::PipelineState* DynamicDrawContext::GetCurrentPipelineState()
|
||||
|
||||
@@ -31,6 +31,28 @@ namespace AZ
|
||||
modelAsset);
|
||||
}
|
||||
|
||||
|
||||
void Model::TEMPOrphanFromDatabase(const Data::Asset<ModelAsset>& modelAsset)
|
||||
{
|
||||
for (auto& modelLodAsset : modelAsset->GetLodAssets())
|
||||
{
|
||||
for(auto& mesh : modelLodAsset->GetMeshes())
|
||||
{
|
||||
for (auto& streamBufferInfo : mesh.GetStreamBufferInfoList())
|
||||
{
|
||||
Data::InstanceDatabase<Buffer>::Instance().TEMPOrphan(
|
||||
Data::InstanceId::CreateFromAssetId(streamBufferInfo.m_bufferAssetView.GetBufferAsset().GetId()));
|
||||
}
|
||||
Data::InstanceDatabase<Buffer>::Instance().TEMPOrphan(
|
||||
Data::InstanceId::CreateFromAssetId(mesh.GetIndexBufferAssetView().GetBufferAsset().GetId()));
|
||||
}
|
||||
Data::InstanceDatabase<ModelLod>::Instance().TEMPOrphan(Data::InstanceId::CreateFromAssetId(modelLodAsset.GetId()));
|
||||
}
|
||||
|
||||
Data::InstanceDatabase<Model>::Instance().TEMPOrphan(
|
||||
Data::InstanceId::CreateFromAssetId(modelAsset.GetId()));
|
||||
}
|
||||
|
||||
size_t Model::GetLodCount() const
|
||||
{
|
||||
return m_lods.size();
|
||||
|
||||
@@ -107,30 +107,13 @@ namespace AZ
|
||||
dispatchArgs.m_totalNumberOfThreadsY = passData->m_totalNumberOfThreadsY;
|
||||
dispatchArgs.m_totalNumberOfThreadsZ = passData->m_totalNumberOfThreadsZ;
|
||||
|
||||
const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" });
|
||||
if (numThreads)
|
||||
const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), dispatchArgs);
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
const RHI::ShaderStageAttributeArguments& args = *numThreads;
|
||||
bool validArgs = args.size() == 3;
|
||||
if (validArgs)
|
||||
{
|
||||
validArgs &= args[0].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[1].type() == azrtti_typeid<int>();
|
||||
validArgs &= args[2].type() == azrtti_typeid<int>();
|
||||
}
|
||||
|
||||
if (!validArgs)
|
||||
{
|
||||
AZ_Error("PassSystem", false, "[ComputePass '%s']: Shader '%s' contains invalid numthreads arguments.",
|
||||
GetPathName().GetCStr(),
|
||||
passData->m_shaderReference.m_filePath.data());
|
||||
return;
|
||||
}
|
||||
|
||||
dispatchArgs.m_threadsPerGroupX = aznumeric_cast<uint16_t>(AZStd::any_cast<int>(args[0]));
|
||||
dispatchArgs.m_threadsPerGroupY = aznumeric_cast<uint16_t>(AZStd::any_cast<int>(args[1]));
|
||||
dispatchArgs.m_threadsPerGroupZ = aznumeric_cast<uint16_t>(AZStd::any_cast<int>(args[2]));
|
||||
AZ_Error("PassSystem", false, "[ComputePass '%s']: Shader '%.*s' contains invalid numthreads arguments:\n%s",
|
||||
GetPathName().GetCStr(), passData->m_shaderReference.m_filePath.size(), passData->m_shaderReference.m_filePath.data(), outcome.GetError().c_str());
|
||||
}
|
||||
|
||||
m_dispatchItem.m_arguments = dispatchArgs;
|
||||
|
||||
m_isFullscreenPass = passData->m_makeFullscreenPass;
|
||||
|
||||
@@ -143,5 +143,79 @@ namespace AZ
|
||||
|
||||
return RPI::StreamingImage::FindOrCreate(streamingImageAsset);
|
||||
}
|
||||
|
||||
//! A helper function for GetComputeShaderNumThreads(), to consolidate error messages, etc.
|
||||
static bool GetAttributeArgumentByIndex(const Data::Asset<ShaderAsset>& shaderAsset, const AZ::Name& attributeName, const RHI::ShaderStageAttributeArguments& args, const size_t argIndex, uint16_t* value, AZStd::string& errorMsg)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
const auto numArguments = args.size();
|
||||
if (numArguments > argIndex)
|
||||
{
|
||||
if (args[argIndex].type() == azrtti_typeid<int>())
|
||||
{
|
||||
*value = aznumeric_caster(AZStd::any_cast<int>(args[argIndex]));
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = AZStd::string::format("Was expecting argument '%zu' in attribute '%s' to be of type 'int' from shader asset '%s'", argIndex, attributeName.GetCStr(), shaderAsset.GetHint().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = AZStd::string::format("Was expecting at least '%zu' arguments in attribute '%s' from shader asset '%s'", argIndex + 1, attributeName.GetCStr(), shaderAsset.GetHint().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> GetComputeShaderNumThreads(const Data::Asset<ShaderAsset>& shaderAsset, const AZ::Name& attributeName, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ)
|
||||
{
|
||||
// Set default 1, 1, 1 now. In case of errors later this is what the caller will get.
|
||||
if (numThreadsX)
|
||||
{
|
||||
*numThreadsX = 1;
|
||||
}
|
||||
if (numThreadsY)
|
||||
{
|
||||
*numThreadsY = 1;
|
||||
}
|
||||
if (numThreadsZ)
|
||||
{
|
||||
*numThreadsZ = 1;
|
||||
}
|
||||
const auto numThreads = shaderAsset->GetAttribute(RHI::ShaderStage::Compute, attributeName);
|
||||
if (!numThreads)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format("Couldn't find attribute '%s' in shader asset '%s'", attributeName.GetCStr(), shaderAsset.GetHint().c_str()));
|
||||
}
|
||||
const RHI::ShaderStageAttributeArguments& args = *numThreads;
|
||||
AZStd::string errorMsg;
|
||||
if (!GetAttributeArgumentByIndex(shaderAsset, attributeName, args, 0, numThreadsX, errorMsg))
|
||||
{
|
||||
return AZ::Failure(errorMsg);
|
||||
}
|
||||
if (!GetAttributeArgumentByIndex(shaderAsset, attributeName, args, 1, numThreadsY, errorMsg))
|
||||
{
|
||||
return AZ::Failure(errorMsg);
|
||||
}
|
||||
if (!GetAttributeArgumentByIndex(shaderAsset, attributeName, args, 2, numThreadsZ, errorMsg))
|
||||
{
|
||||
return AZ::Failure(errorMsg);
|
||||
}
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> GetComputeShaderNumThreads(const Data::Asset<ShaderAsset>& shaderAsset, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ)
|
||||
{
|
||||
return GetComputeShaderNumThreads(shaderAsset, Name{ "numthreads" }, numThreadsX, numThreadsY, numThreadsZ);
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> GetComputeShaderNumThreads(const Data::Asset<ShaderAsset>& shaderAsset, RHI::DispatchDirect& dispatchDirect)
|
||||
{
|
||||
return GetComputeShaderNumThreads(shaderAsset, &dispatchDirect.m_threadsPerGroupX, &dispatchDirect.m_threadsPerGroupY, &dispatchDirect.m_threadsPerGroupZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,6 +580,11 @@ namespace AZ
|
||||
return {};
|
||||
}
|
||||
|
||||
void ShaderResourceGroup::ResetViews()
|
||||
{
|
||||
m_data.ResetViews();
|
||||
}
|
||||
|
||||
const RHI::SamplerState& ShaderResourceGroup::GetSampler(RHI::ShaderInputNameIndex& inputIndex, uint32_t arrayIndex) const
|
||||
{
|
||||
inputIndex.ValidateOrFindSamplerIndex(GetLayout());
|
||||
|
||||
@@ -53,16 +53,6 @@ namespace UnitTest
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* AssetSystemStub::GetAbsoluteDevGameFolderPath()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* AssetSystemStub::GetAbsoluteDevRootFolderPath()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AssetSystemStub::GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& relativeProductPath)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -56,8 +56,6 @@ namespace UnitTest
|
||||
AZStd::unordered_map<AZStd::string, SourceInfo> m_sourceInfoMap;
|
||||
|
||||
bool GetSourceInfoBySourcePath(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder) override;
|
||||
const char* GetAbsoluteDevGameFolderPath() override;
|
||||
const char* GetAbsoluteDevRootFolderPath() override;
|
||||
bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& relativeProductPath) override;
|
||||
bool GenerateRelativeSourcePath(
|
||||
const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& watchFolder) override;
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace UnitTest
|
||||
|
||||
AZ::IO::Path assetPath = AZStd::string_view{ AZ::Utils::GetProjectPath() };
|
||||
assetPath /= "Cache";
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetPath.c_str());
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetPath.c_str());
|
||||
|
||||
m_jsonRegistrationContext = AZStd::make_unique<AZ::JsonRegistrationContext>();
|
||||
m_jsonSystemComponent = AZStd::make_unique<AZ::JsonSystemComponent>();
|
||||
@@ -90,7 +90,7 @@ namespace UnitTest
|
||||
JobManagerThreadDesc threadDesc;
|
||||
#if AZ_TRAIT_SET_JOB_PROCESSOR_ID
|
||||
threadDesc.m_cpuId = 0; // Don't set processors IDs on windows
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uint32_t numWorkerThreads = AZStd::thread::hardware_concurrency();
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace UnitTest
|
||||
desc.m_workerThreads.push_back(threadDesc);
|
||||
#if AZ_TRAIT_SET_JOB_PROCESSOR_ID
|
||||
threadDesc.m_cpuId++;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
m_jobManager = AZStd::make_unique<JobManager>(desc);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"description": "",
|
||||
"materialType": "Materials/Types/StandardMultilayerPBR.materialtype",
|
||||
"parentMaterial": "",
|
||||
"propertyLayoutVersion": 3,
|
||||
"properties": {
|
||||
"blend": {
|
||||
"blendSource": "BlendMaskVertexColors",
|
||||
"debugDrawMode": "FinalBlendWeights",
|
||||
"enableLayer2": true,
|
||||
"enableLayer3": true,
|
||||
"textureMap": ""
|
||||
},
|
||||
"parallax": {
|
||||
"enable": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b6d860c6fc3703914716a97910899eca2e66927688690646f697c6246ac310fb
|
||||
size 317340
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:91b8153f93e4773d872478fef40ff00c1b8d5f1ef13101cf62f81956e1c30107
|
||||
size 68800
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2cf646a0a977c2edc5ee2ab6351ef633f194ce60c59ea3cb8359f71648db668e
|
||||
size 374492
|
||||
@@ -173,7 +173,7 @@ namespace AtomToolsFramework
|
||||
AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast(
|
||||
&AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized);
|
||||
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml");
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml");
|
||||
|
||||
if (!AZ::RPI::RPISystemInterface::Get()->IsInitialized())
|
||||
{
|
||||
@@ -289,7 +289,7 @@ namespace AtomToolsFramework
|
||||
ExitMainLoop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AtomToolsApplication::SaveSettings()
|
||||
{
|
||||
if (m_activatedLocalUserSettings)
|
||||
@@ -378,7 +378,7 @@ namespace AtomToolsFramework
|
||||
ExitMainLoop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AtomToolsApplication::LaunchLocalServer()
|
||||
{
|
||||
// Determine if this is the first launch of the tool by attempting to connect to a running server
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
namespace MaterialEditor
|
||||
{
|
||||
CreateMaterialDialog::CreateMaterialDialog(QWidget* parent)
|
||||
: CreateMaterialDialog(QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials", parent)
|
||||
: CreateMaterialDialog(QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials", parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -106,7 +106,7 @@ namespace MaterialEditor
|
||||
menu->addAction("Create Material...", [entry]()
|
||||
{
|
||||
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
|
||||
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) +
|
||||
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) +
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" +
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
|
||||
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
|
||||
@@ -182,7 +182,7 @@ namespace MaterialEditor
|
||||
menu->addAction("Create Child Material...", [entry]()
|
||||
{
|
||||
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
|
||||
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) +
|
||||
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) +
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" +
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
|
||||
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
|
||||
|
||||
+1
-1
@@ -346,7 +346,7 @@ namespace MaterialEditor
|
||||
|
||||
AZStd::string ViewportSettingsInspector::GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const
|
||||
{
|
||||
AZStd::string savePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@");
|
||||
AZStd::string savePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@");
|
||||
savePath += AZ_CORRECT_FILESYSTEM_SEPARATOR;
|
||||
savePath += "Materials";
|
||||
savePath += AZ_CORRECT_FILESYSTEM_SEPARATOR;
|
||||
|
||||
@@ -16,10 +16,10 @@ import sys
|
||||
import os.path
|
||||
import filecmp
|
||||
|
||||
g_devroot = azlmbr.paths.devroot
|
||||
sys.path.append(os.path.join(g_devroot, 'Tests', 'Atom', 'Automated'))
|
||||
g_engroot = azlmbr.paths.engroot
|
||||
sys.path.append(os.path.join(g_engroot, 'Tests', 'Atom', 'Automated'))
|
||||
|
||||
g_materialTestFolder = os.path.join(g_devroot,'Gems','Atom','TestData','TestData','Materials','StandardPbrTestCases')
|
||||
g_materialTestFolder = os.path.join(g_engroot,'Gems','Atom','TestData','TestData','Materials','StandardPbrTestCases')
|
||||
|
||||
# Change this to True to replace the expected screenshot images
|
||||
g_replaceExpectedScreenshots = False
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ def main():
|
||||
|
||||
# clean previously generated shader variant list file so they don't clash.
|
||||
pre, ext = os.path.splitext(shaderAssetInfo.relativePath)
|
||||
projectShaderVariantListFilePath = os.path.join(azlmbr.paths.devassets, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist')
|
||||
projectShaderVariantListFilePath = os.path.join(azlmbr.paths.projectroot, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist')
|
||||
|
||||
pre, ext = os.path.splitext(filename)
|
||||
defaultShaderVariantListFilePath = f'{pre}.shadervariantlist'
|
||||
|
||||
@@ -46,7 +46,7 @@ static void DumfontTexture(IConsoleCmdArgs* cmdArgs)
|
||||
|
||||
if (fontName && *fontName && *fontName != '0')
|
||||
{
|
||||
AZStd::string fontFilePath("@devroot@/");
|
||||
AZStd::string fontFilePath("@engroot@/");
|
||||
fontFilePath += fontName;
|
||||
fontFilePath += ".bmp";
|
||||
|
||||
|
||||
+2
-2
@@ -389,7 +389,7 @@ namespace AZ
|
||||
|
||||
// create the full paths
|
||||
char projectPath[AZ_MAX_PATH_LEN];
|
||||
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN);
|
||||
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN);
|
||||
|
||||
AZStd::string irradianceTextureFullPath;
|
||||
AzFramework::StringFunc::Path::Join(projectPath, irradianceTextureRelativePath.c_str(), irradianceTextureFullPath, true, true);
|
||||
@@ -481,7 +481,7 @@ namespace AZ
|
||||
AZStd::string fullPath;
|
||||
|
||||
char projectPath[AZ_MAX_PATH_LEN];
|
||||
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN);
|
||||
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN);
|
||||
|
||||
if (!relativePath.empty())
|
||||
{
|
||||
|
||||
+1
-1
@@ -529,7 +529,7 @@ namespace AZ
|
||||
bool MaterialPropertyInspector::SaveMaterial() const
|
||||
{
|
||||
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
|
||||
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) +
|
||||
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) +
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" +
|
||||
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
|
||||
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
|
||||
|
||||
@@ -32,6 +32,23 @@ namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
struct MeshComponentNotificationBusHandler final
|
||||
: public MeshComponentNotificationBus::Handler
|
||||
, public AZ::BehaviorEBusHandler
|
||||
{
|
||||
AZ_EBUS_BEHAVIOR_BINDER(
|
||||
MeshComponentNotificationBusHandler, "{8B8F4977-817F-4C7C-9141-0E5FF899E1BC}", AZ::SystemAllocator, OnModelReady);
|
||||
|
||||
void OnModelReady(
|
||||
[[maybe_unused]] const Data::Asset<RPI::ModelAsset>& modelAsset,
|
||||
[[maybe_unused]] const Data::Instance<RPI::Model>& model) override
|
||||
{
|
||||
Call(FN_OnModelReady);
|
||||
}
|
||||
};
|
||||
} // namespace Internal
|
||||
|
||||
namespace MeshComponentControllerVersionUtility
|
||||
{
|
||||
@@ -173,6 +190,12 @@ namespace AZ
|
||||
->VirtualProperty("MinimumScreenCoverage", "GetMinimumScreenCoverage", "SetMinimumScreenCoverage")
|
||||
->VirtualProperty("QualityDecayRate", "GetQualityDecayRate", "SetQualityDecayRate")
|
||||
;
|
||||
|
||||
behaviorContext->EBus<MeshComponentNotificationBus>("MeshComponentNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "render")
|
||||
->Attribute(AZ::Script::Attributes::Module, "render")
|
||||
->Handler<Internal::MeshComponentNotificationBusHandler>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +329,7 @@ namespace AZ
|
||||
return model ? model->GetUvNames() : AZStd::unordered_set<AZ::Name>();
|
||||
}
|
||||
|
||||
void MeshComponentController::OnMaterialsUpdated([[maybe_unused]] const MaterialAssignmentMap& materials)
|
||||
void MeshComponentController::OnMaterialsUpdated(const MaterialAssignmentMap& materials)
|
||||
{
|
||||
if (m_meshFeatureProcessor)
|
||||
{
|
||||
|
||||
+1
-1
@@ -321,7 +321,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
char projectPath[AZ_MAX_PATH_LEN];
|
||||
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN);
|
||||
AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN);
|
||||
|
||||
// retrieve the source cubemap path from the configuration
|
||||
// we need to make sure to use the same source cubemap for each bake
|
||||
|
||||
@@ -57,9 +57,8 @@ option bool o_enableMarschner_R = true;
|
||||
option bool o_enableMarschner_TRT = true;
|
||||
option bool o_enableMarschner_TT = true;
|
||||
|
||||
option bool o_enableDiffuseLobe = true;
|
||||
option bool o_enableSpecularLobe = true;
|
||||
option bool o_enableTransmittanceLobe = true;
|
||||
option bool o_enableLongtitudeCoeff = true;
|
||||
option bool o_enableAzimuthCoeff = true;
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Longitudinal functions (M_R, M_TT, M_RTR)
|
||||
@@ -196,8 +195,8 @@ float3 HairMarschnerBSDF(Surface surface, LightingData lightingData, const float
|
||||
// R Path - single reflection from the hair towards the eye.
|
||||
if (o_enableMarschner_R)
|
||||
{
|
||||
float lighting_R = o_enableDiffuseLobe ? M_R(surface, Lh, sinLiPlusSinLr) : 1.0f;
|
||||
if (o_enableSpecularLobe)
|
||||
float lighting_R = o_enableLongtitudeCoeff ? M_R(surface, Lh, sinLiPlusSinLr) : 1.0f;
|
||||
if (o_enableAzimuthCoeff)
|
||||
lighting_R *= N_R(surface, cos_O2, Wi, Wr, f0);
|
||||
|
||||
// The following lines are a cheap method to get occluded reflection by accoounting
|
||||
@@ -221,8 +220,8 @@ float3 HairMarschnerBSDF(Surface surface, LightingData lightingData, const float
|
||||
// on the average thickness.
|
||||
if (o_enableMarschner_TT)
|
||||
{
|
||||
float3 lighting_TT = o_enableDiffuseLobe ? M_TT(surface, Lh, sinLiPlusSinLr) : float3(1.0f, 1.0f, 1.0f);
|
||||
if (o_enableSpecularLobe)
|
||||
float3 lighting_TT = o_enableLongtitudeCoeff ? M_TT(surface, Lh, sinLiPlusSinLr) : float3(1.0f, 1.0f, 1.0f);
|
||||
if (o_enableAzimuthCoeff)
|
||||
lighting_TT *= N_TT(surface, n2, cos_O, cos_O2, cos_Ld, f0);
|
||||
|
||||
// Reduce back transmittance based on the thickness of the hair
|
||||
@@ -234,8 +233,8 @@ float3 HairMarschnerBSDF(Surface surface, LightingData lightingData, const float
|
||||
// the hair towards the eye.
|
||||
if (o_enableMarschner_TRT)
|
||||
{
|
||||
float3 lighting_TRT = o_enableDiffuseLobe ? M_TRT(surface, Lh, sinLiPlusSinLr) : float3(1.0f, 1.0f, 1.0f);
|
||||
if (o_enableSpecularLobe)
|
||||
float3 lighting_TRT = o_enableLongtitudeCoeff ? M_TRT(surface, Lh, sinLiPlusSinLr) : float3(1.0f, 1.0f, 1.0f);
|
||||
if (o_enableAzimuthCoeff)
|
||||
lighting_TRT *= N_TRT(surface, cos_O, cos_Ld, f0);
|
||||
lighting += lighting_TRT;
|
||||
}
|
||||
|
||||
@@ -47,9 +47,8 @@ namespace AZ
|
||||
shaderOption.SetValue(AZ::Name("o_enableMarschner_R"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableMarschner_R });
|
||||
shaderOption.SetValue(AZ::Name("o_enableMarschner_TRT"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableMarschner_TRT });
|
||||
shaderOption.SetValue(AZ::Name("o_enableMarschner_TT"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableMarschner_TT });
|
||||
shaderOption.SetValue(AZ::Name("o_enableDiffuseLobe"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableDiffuseLobe });
|
||||
shaderOption.SetValue(AZ::Name("o_enableSpecularLobe"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableSpecularLobe });
|
||||
shaderOption.SetValue(AZ::Name("o_enableTransmittanceLobe"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableTransmittanceLobe });
|
||||
shaderOption.SetValue(AZ::Name("o_enableLongtitudeCoeff"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableLongtitudeCoeff });
|
||||
shaderOption.SetValue(AZ::Name("o_enableAzimuthCoeff"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableAzimuthCoeff });
|
||||
|
||||
m_shaderOptions = shaderOption.GetShaderVariantKeyFallbackValue();
|
||||
}
|
||||
|
||||
@@ -135,6 +135,11 @@ namespace AZ
|
||||
|
||||
void HairFeatureProcessor::EnablePasses(bool enable)
|
||||
{
|
||||
if (!m_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& [passName, pass] : m_computePasses)
|
||||
{
|
||||
pass->SetEnabled(enable);
|
||||
@@ -339,14 +344,14 @@ namespace AZ
|
||||
resultSuccess &= InitPPLLFillPass();
|
||||
resultSuccess &= InitPPLLResolvePass();
|
||||
|
||||
m_initialized = resultSuccess;
|
||||
|
||||
// Don't enable passes if no hair object was added yet (depending on activation order)
|
||||
if (m_hairRenderObjects.empty())
|
||||
if (m_initialized && m_hairRenderObjects.empty())
|
||||
{
|
||||
EnablePasses(false);
|
||||
}
|
||||
|
||||
m_initialized = resultSuccess;
|
||||
|
||||
// this might not be an error - if the pass system is still empty / minimal
|
||||
// and these passes are not part of the minimal pipeline, they will not
|
||||
// be created.
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace AZ
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<HairGlobalSettings>()
|
||||
->Version(2)
|
||||
->Version(3)
|
||||
->Field("EnableShadows", &HairGlobalSettings::m_enableShadows)
|
||||
->Field("EnableDirectionalLights", &HairGlobalSettings::m_enableDirectionalLights)
|
||||
->Field("EnablePunctualLights", &HairGlobalSettings::m_enablePunctualLights)
|
||||
@@ -31,9 +31,8 @@ namespace AZ
|
||||
->Field("EnableMarschner_R", &HairGlobalSettings::m_enableMarschner_R)
|
||||
->Field("EnableMarschner_TRT", &HairGlobalSettings::m_enableMarschner_TRT)
|
||||
->Field("EnableMarschner_TT", &HairGlobalSettings::m_enableMarschner_TT)
|
||||
->Field("EnableDiffuseLobe", &HairGlobalSettings::m_enableDiffuseLobe)
|
||||
->Field("EnableSpecularLobe", &HairGlobalSettings::m_enableSpecularLobe)
|
||||
->Field("EnableTransmittanceLobe", &HairGlobalSettings::m_enableTransmittanceLobe)
|
||||
->Field("EnableLongtitudeCoeff", &HairGlobalSettings::m_enableLongtitudeCoeff)
|
||||
->Field("EnableAzimuthCoeff", &HairGlobalSettings::m_enableAzimuthCoeff)
|
||||
;
|
||||
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
@@ -51,9 +50,8 @@ namespace AZ
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableMarschner_R, "Enable Marschner R", "Enable Marschner R.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableMarschner_TRT, "Enable Marschner TRT", "Enable Marschner TRT.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableMarschner_TT, "Enable Marschner TT", "Enable Marschner TT.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableDiffuseLobe, "Enable Diffuse Lobe", "Enable Diffuse Lobe.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableSpecularLobe, "Enable Specular Lobe", "Enable Specular Lobe.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableTransmittanceLobe, "Enable Transmittance Lobe", "Enable Transmittance Lobe.")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableLongtitudeCoeff, "Enable Longtitude", "Enable Longtitude Contribution")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableAzimuthCoeff, "Enable Azimuth", "Enable Azimuth Contribution")
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,8 @@ namespace AZ
|
||||
bool m_enableMarschner_R = true;
|
||||
bool m_enableMarschner_TRT = true;
|
||||
bool m_enableMarschner_TT = true;
|
||||
bool m_enableDiffuseLobe = true;
|
||||
bool m_enableSpecularLobe = true;
|
||||
bool m_enableTransmittanceLobe = true;
|
||||
bool m_enableLongtitudeCoeff = true;
|
||||
bool m_enableAzimuthCoeff = true;
|
||||
};
|
||||
} // namespace Hair
|
||||
} // namespace Render
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace AudioControlBuilder
|
||||
Audio::ATLXmlTags::ATLPreloadRequestTag, "preload request"));
|
||||
}
|
||||
|
||||
// For each preload request in the control file, determine which config group is used for this platform and register each
|
||||
// For each preload request in the control file, determine which config group is used for this platform and register each
|
||||
// bank listed in that preload request as a dependency.
|
||||
while (preloadRequestNode)
|
||||
{
|
||||
@@ -163,7 +163,7 @@ namespace AudioControlBuilder
|
||||
const AZ::rapidxml::xml_node<char>* configGroupNode = configGroupMap[configGroupName];
|
||||
if (!configGroupNode)
|
||||
{
|
||||
// The config group this platform uses isn't defined in the control file. This might be intentional, so just
|
||||
// The config group this platform uses isn't defined in the control file. This might be intentional, so just
|
||||
// generate a warning and keep going to the next preload node.
|
||||
AZ_TracePrintf("Audio Control Builder", "%s node for config group %s is not defined, so no banks are referenced.",
|
||||
Audio::ATLXmlTags::ATLConfigGroupTag, configGroupName.c_str());
|
||||
@@ -188,7 +188,7 @@ namespace AudioControlBuilder
|
||||
}
|
||||
|
||||
// Prepend the bank name with the relative path to the wwise sounds folder to get relative path to the bank from
|
||||
// the @assets@ alias and push that into the list of banks referenced.
|
||||
// the @products@ alias and push that into the list of banks referenced.
|
||||
AZStd::string soundsPrefix = Audio::Wwise::DefaultBanksPath;
|
||||
banksReferenced.emplace_back(soundsPrefix + bankNameAttribute->value());
|
||||
|
||||
@@ -496,7 +496,7 @@ namespace AudioControlBuilder
|
||||
pathDependencies.emplace(relativeBankPath, AssetBuilderSDK::ProductPathDependencyType::ProductFile);
|
||||
}
|
||||
|
||||
// For each bank figure out what events are included in the bank, then run through every event referenced in the file and
|
||||
// For each bank figure out what events are included in the bank, then run through every event referenced in the file and
|
||||
// make sure it is in the list gathered from the banks.
|
||||
const auto triggersNode = node->first_node(Audio::ATLXmlTags::TriggersNodeTag);
|
||||
if (!triggersNode)
|
||||
@@ -520,7 +520,7 @@ namespace AudioControlBuilder
|
||||
|
||||
AZStd::set<AZStd::string> wwiseEventsInReferencedBanks;
|
||||
|
||||
// Load all bankdeps files for all banks referenced and aggregate the list of events in those files.
|
||||
// Load all bankdeps files for all banks referenced and aggregate the list of events in those files.
|
||||
for (const AZStd::string& relativeBankPath : banksReferenced)
|
||||
{
|
||||
// Create the full path to the bankdeps file from the bank file.
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace WwiseBuilder
|
||||
{
|
||||
fileNames.push_back(dependenciesArray[dependencyIndex].GetString());
|
||||
}
|
||||
|
||||
|
||||
// The dependency array is empty, which likely means it was modified by hand. However, every bank is dependent
|
||||
// on init.bnk (other than itself), so just force add it as a dependency here. and emit a warning.
|
||||
if (fileNames.size() == 0)
|
||||
@@ -93,7 +93,7 @@ namespace WwiseBuilder
|
||||
|
||||
void WwiseBuilderWorker::Initialize()
|
||||
{
|
||||
AZ::IO::Path configFile("@devassets@");
|
||||
AZ::IO::Path configFile("@projectroot@");
|
||||
configFile /= Audio::Wwise::DefaultBanksPath;
|
||||
configFile /= Audio::Wwise::ConfigFile;
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace WwiseBuilder
|
||||
{
|
||||
AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Starting Job.\n");
|
||||
AZ::IO::PathView fullPath(request.m_fullPath);
|
||||
|
||||
|
||||
if (m_isShuttingDown)
|
||||
{
|
||||
AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled job %s because shutdown was requested.\n", request.m_fullPath.c_str());
|
||||
@@ -204,7 +204,7 @@ namespace WwiseBuilder
|
||||
AZ::Outcome<AZStd::string, AZStd::string> gatherProductDependenciesResponse = GatherProductDependencies(request.m_fullPath, request.m_sourceFile, dependencyPaths);
|
||||
if (!gatherProductDependenciesResponse.IsSuccess())
|
||||
{
|
||||
AZ_Error(WwiseBuilderWindowName, false, "Dependency gathering for %s failed. %s",
|
||||
AZ_Error(WwiseBuilderWindowName, false, "Dependency gathering for %s failed. %s",
|
||||
request.m_fullPath.c_str(), gatherProductDependenciesResponse.GetError().c_str());
|
||||
}
|
||||
else
|
||||
|
||||
@@ -28,7 +28,7 @@ protected:
|
||||
{
|
||||
m_app.Start(AZ::ComponentApplication::Descriptor());
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
@@ -39,7 +39,7 @@ protected:
|
||||
assetRoot /= "Cache";
|
||||
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str());
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetRoot.c_str());
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -158,7 +158,7 @@ TEST_F(WwiseBuilderTests, WwiseBuilder_InitBank_NoMetadata_NoDependencies)
|
||||
|
||||
TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_NoMetadata_NoDependencies)
|
||||
{
|
||||
// Should generate a warning after trying to find metadata for the given bank, when the bank is not the init bank.
|
||||
// Should generate a warning after trying to find metadata for the given bank, when the bank is not the init bank.
|
||||
// Warning should be about not being able to generate full dependency information without the metadata file.
|
||||
TestSuccessCaseNoDependencies("test_doesNotExist.bnk", true);
|
||||
}
|
||||
@@ -180,15 +180,15 @@ TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_MultipleDependencies)
|
||||
|
||||
TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_DependencyArrayNonexistent_NoDependencies)
|
||||
{
|
||||
// Should generate a warning when trying to get dependency info from metadata file, but the dependency field does
|
||||
// not an empty array. Warning should be describing that a dependency on the init bank was added by default, but
|
||||
// Should generate a warning when trying to get dependency info from metadata file, but the dependency field does
|
||||
// not an empty array. Warning should be describing that a dependency on the init bank was added by default, but
|
||||
// the full dependency list could not be generated.
|
||||
TestSuccessCaseNoDependencies("test_bank7.bnk", true);
|
||||
}
|
||||
|
||||
TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_NoElementsInDependencyArray_NoDependencies)
|
||||
{
|
||||
// Should generate a warning when trying to get dependency info from metadata file, but the dependency field is
|
||||
// Should generate a warning when trying to get dependency info from metadata file, but the dependency field is
|
||||
// an empty array. Warning should be describing that a dependency on the init bank was added by default, but the
|
||||
// full dependency list could not be generated.
|
||||
TestSuccessCaseNoDependencies("test_bank8.bnk", true);
|
||||
@@ -196,8 +196,8 @@ TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_NoElementsInDependencyArray_N
|
||||
|
||||
TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_MissingInitBankDependency_MultipleDependencies)
|
||||
{
|
||||
// Should generate a warning when trying to get dependency info from metadata file, but the dependency info in the
|
||||
// metadata doesn't include the init bank. Warning should be describing that a dependency on the init bank was
|
||||
// Should generate a warning when trying to get dependency info from metadata file, but the dependency info in the
|
||||
// metadata doesn't include the init bank. Warning should be describing that a dependency on the init bank was
|
||||
// added by default.
|
||||
AZStd::vector<const char*> expectedPaths = {
|
||||
"Sounds/wwise/init.bnk",
|
||||
|
||||
@@ -231,7 +231,7 @@ namespace UnitTest
|
||||
m_app.Start(AZ::ComponentApplication::Descriptor());
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
@@ -253,10 +253,10 @@ namespace UnitTest
|
||||
AZ_TEST_ASSERT(serializeContext != nullptr);
|
||||
Audio::Wwise::ConfigurationSettings::Reflect(serializeContext);
|
||||
|
||||
// Set the @assets@ alias to the path where *this* cpp file lives.
|
||||
// Set the @products@ alias to the path where *this* cpp file lives.
|
||||
AZStd::string rootFolder(AZ::Test::GetCurrentExecutablePath());
|
||||
AZ::StringFunc::Path::Join(rootFolder.c_str(), "Test.Assets/Gems/AudioEngineWwise", rootFolder);
|
||||
m_fileIO->SetAlias("@assets@", rootFolder.c_str());
|
||||
m_fileIO->SetAlias("@products@", rootFolder.c_str());
|
||||
|
||||
// So we don't have to compute it in each test...
|
||||
AZStd::string defaultBanksPath(Audio::Wwise::DefaultBanksPath);
|
||||
@@ -303,26 +303,12 @@ namespace UnitTest
|
||||
m_mapEntry.m_bankSubPath = "soundbanks";
|
||||
config.m_platformMappings.push_back(m_mapEntry);
|
||||
|
||||
// Unfortunately we are writing to the config file that is simulated to be in the @assets@ subfolder
|
||||
// This will cause an issue during save. Since 'm_configFilePath' is an absolute path, we need to
|
||||
// reset the @assets@ alias to a meaningful assets path that does not contain any root of the m_configFilePath
|
||||
// in order to write to the config file and proceed
|
||||
//AZStd::string rootFolder(AZ::Test::GetCurrentExecutablePath());
|
||||
//AZ::IO::Path tempAssetPath(rootFolder);
|
||||
//tempAssetPath /= "Cache";
|
||||
|
||||
//AZStd::string previousAlias = m_fileIO->GetAlias("@assets@");
|
||||
//m_fileIO->SetAlias("@assets@", tempAssetPath.c_str());
|
||||
|
||||
config.Save(m_configFilePath);
|
||||
|
||||
//m_fileIO->SetAlias("@assets@", previousAlias.c_str());
|
||||
m_wwiseImpl.SetBankPaths();
|
||||
|
||||
//m_fileIO->SetAlias("@assets@", tempAssetPath.c_str());
|
||||
m_fileIO->Remove(m_configFilePath.c_str());
|
||||
|
||||
//m_fileIO->SetAlias("@assets@", previousAlias.c_str());
|
||||
EXPECT_STREQ(m_wwiseImpl.m_soundbankFolder.c_str(), "sounds/wwise/soundbanks/");
|
||||
}
|
||||
|
||||
|
||||
@@ -977,7 +977,7 @@ namespace Audio
|
||||
, m_rPreloadRequests(rPreloadRequests)
|
||||
, m_nTriggerImplIDCounter(AUDIO_TRIGGER_IMPL_ID_NUM_RESERVED)
|
||||
, m_rFileCacheMgr(rFileCacheMgr)
|
||||
, m_rootPath("@assets@")
|
||||
, m_rootPath("@products@")
|
||||
#if !defined(AUDIO_RELEASE)
|
||||
, m_pDebugNameStore(nullptr)
|
||||
#endif // !AUDIO_RELEASE
|
||||
|
||||
@@ -292,7 +292,7 @@ namespace Blast
|
||||
|
||||
void BlastSystemComponent::SaveConfiguration()
|
||||
{
|
||||
auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@");
|
||||
auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@");
|
||||
|
||||
if (!assetRoot)
|
||||
{
|
||||
@@ -309,7 +309,7 @@ namespace Blast
|
||||
|
||||
void BlastSystemComponent::CheckoutConfiguration()
|
||||
{
|
||||
const auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@");
|
||||
const auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@");
|
||||
|
||||
AZStd::string fullPath;
|
||||
AzFramework::StringFunc::Path::Join(assetRoot, DefaultConfigurationPath, fullPath);
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace CertificateManager
|
||||
{
|
||||
static bool ReadFileIntoString(const char* filename, AZStd::vector<char>& outBuffer)
|
||||
{
|
||||
AZStd::string certificatePath = "@assets@/certificates/";
|
||||
AZStd::string certificatePath = "@products@/certificates/";
|
||||
certificatePath.append(filename);
|
||||
|
||||
AZ::IO::FileIOBase* fileBase = AZ::IO::FileIOBase::GetInstance();
|
||||
@@ -58,7 +58,7 @@ namespace CertificateManager
|
||||
return true;
|
||||
}
|
||||
|
||||
FileDataSource::FileDataSource()
|
||||
FileDataSource::FileDataSource()
|
||||
: m_privateKeyPEM(nullptr)
|
||||
, m_certificatePEM(nullptr)
|
||||
, m_certificateAuthorityCertPEM(nullptr)
|
||||
@@ -73,13 +73,13 @@ namespace CertificateManager
|
||||
azfree(m_privateKeyPEM);
|
||||
azfree(m_certificatePEM);
|
||||
azfree(m_certificateAuthorityCertPEM);
|
||||
}
|
||||
}
|
||||
|
||||
void FileDataSource::ConfigureDataSource(const char* keyPath, const char* certPath, const char* caPath)
|
||||
{
|
||||
ConfigurePrivateKey(keyPath);
|
||||
ConfigureCertificate(certPath);
|
||||
ConfigureCertificateAuthority(caPath);
|
||||
ConfigureCertificateAuthority(caPath);
|
||||
}
|
||||
|
||||
void FileDataSource::ConfigurePrivateKey(const char* path)
|
||||
@@ -107,7 +107,7 @@ namespace CertificateManager
|
||||
if (path != nullptr)
|
||||
{
|
||||
LoadGenericFile(path,m_certificatePEM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileDataSource::ConfigureCertificateAuthority(const char* path)
|
||||
@@ -133,7 +133,7 @@ namespace CertificateManager
|
||||
{
|
||||
return m_certificateAuthorityCertPEM;
|
||||
}
|
||||
|
||||
|
||||
bool FileDataSource::HasPublicKey() const
|
||||
{
|
||||
return m_certificatePEM != nullptr;
|
||||
@@ -143,7 +143,7 @@ namespace CertificateManager
|
||||
{
|
||||
return m_certificatePEM;
|
||||
}
|
||||
|
||||
|
||||
bool FileDataSource::HasPrivateKey() const
|
||||
{
|
||||
return m_privateKeyPEM != nullptr;
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace EMotionFX
|
||||
|
||||
// Create EMotion FX allocators
|
||||
Allocators::Create();
|
||||
|
||||
|
||||
// create the new object
|
||||
gEMFX = AZ::Environment::CreateVariable<EMotionFXManager*>(kEMotionFXInstanceVarName);
|
||||
gEMFX.Set(EMotionFXManager::Create());
|
||||
@@ -166,11 +166,11 @@ namespace EMotionFX
|
||||
|
||||
delete m_debugDraw;
|
||||
m_debugDraw = nullptr;
|
||||
|
||||
|
||||
|
||||
m_eventManager->Destroy();
|
||||
m_eventManager = nullptr;
|
||||
|
||||
|
||||
// delete the thread datas
|
||||
for (uint32 i = 0; i < m_threadDatas.size(); ++i)
|
||||
{
|
||||
@@ -341,7 +341,7 @@ namespace EMotionFX
|
||||
void EMotionFXManager::InitAssetFolderPaths()
|
||||
{
|
||||
// Initialize the asset source folder path.
|
||||
const char* assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@");
|
||||
const char* assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@");
|
||||
if (assetSourcePath)
|
||||
{
|
||||
m_assetSourceFolder = assetSourcePath;
|
||||
@@ -361,12 +361,12 @@ namespace EMotionFX
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning("EMotionFX", false, "Failed to set asset source path for alias '@devassets@'.");
|
||||
AZ_Warning("EMotionFX", false, "Failed to set asset source path for alias '@projectroot@'.");
|
||||
}
|
||||
|
||||
|
||||
// Initialize the asset cache folder path.
|
||||
const char* assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@");
|
||||
const char* assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@");
|
||||
if (assetCachePath)
|
||||
{
|
||||
m_assetCacheFolder = assetCachePath;
|
||||
@@ -386,7 +386,7 @@ namespace EMotionFX
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning("EMotionFX", false, "Failed to set asset cache path for alias '@assets@'.");
|
||||
AZ_Warning("EMotionFX", false, "Failed to set asset cache path for alias '@products@'.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -72,13 +72,13 @@ namespace EMStudio
|
||||
{
|
||||
AZStd::string filename;
|
||||
|
||||
AZStd::string assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@");
|
||||
AZStd::string assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@");
|
||||
AzFramework::StringFunc::AssetDatabasePath::Normalize(assetCachePath);
|
||||
|
||||
AZStd::string relativePath;
|
||||
EBUS_EVENT_RESULT(relativePath, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, assetId);
|
||||
AzFramework::StringFunc::AssetDatabasePath::Join(assetCachePath.c_str(), relativePath.c_str(), filename);
|
||||
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ namespace EMStudio
|
||||
void FileManager::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, [[maybe_unused]] AZ::TypeId sourceTypeId)
|
||||
{
|
||||
AZStd::string filename;
|
||||
AZStd::string assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@");
|
||||
AZStd::string assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@");
|
||||
AzFramework::StringFunc::AssetDatabasePath::Normalize(assetSourcePath);
|
||||
AzFramework::StringFunc::AssetDatabasePath::Join(assetSourcePath.c_str(), relativePath.c_str(), filename);
|
||||
|
||||
@@ -373,7 +373,7 @@ namespace EMStudio
|
||||
const ProductAssetBrowserEntry* product = azrtti_cast<const ProductAssetBrowserEntry*>(assetBrowserEntry);
|
||||
|
||||
filename.clear();
|
||||
AZStd::string cachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@");
|
||||
AZStd::string cachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@");
|
||||
AzFramework::StringFunc::AssetDatabasePath::Normalize(cachePath);
|
||||
AzFramework::StringFunc::AssetDatabasePath::Join(cachePath.c_str(), product->GetRelativePath().c_str(), filename);
|
||||
|
||||
@@ -395,7 +395,7 @@ namespace EMStudio
|
||||
{
|
||||
return AZStd::string();
|
||||
}
|
||||
|
||||
|
||||
return filenames[0];
|
||||
}
|
||||
|
||||
@@ -435,12 +435,12 @@ namespace EMStudio
|
||||
AZStd::string result;
|
||||
if (EMStudio::GetCommandManager()->ExecuteCommand(command, result))
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
"Actor <font color=green>successfully</font> saved");
|
||||
}
|
||||
else
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
AZStd::string::format("Actor <font color=red>failed</font> to save<br/><br/>%s", result.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
@@ -574,12 +574,12 @@ namespace EMStudio
|
||||
AZStd::string result;
|
||||
if (GetCommandManager()->ExecuteCommand(command, result) == false)
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
AZStd::string::format("MotionSet <font color=red>failed</font> to save<br/><br/>%s", result.c_str()).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
"MotionSet <font color=green>successfully</font> saved");
|
||||
}
|
||||
}
|
||||
@@ -608,7 +608,7 @@ namespace EMStudio
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
AZStd::string FileManager::LoadAnimGraphFileDialog([[maybe_unused]] QWidget* parent)
|
||||
{
|
||||
GetManager()->SetAvoidRendering(true);
|
||||
@@ -618,7 +618,7 @@ namespace EMStudio
|
||||
{
|
||||
return AZStd::string();
|
||||
}
|
||||
|
||||
|
||||
return filenames[0];
|
||||
}
|
||||
|
||||
|
||||
+14
-14
@@ -378,7 +378,7 @@ namespace EMStudio
|
||||
// reset action
|
||||
m_resetAction = menu->addAction(tr("&Reset"), this, &MainWindow::OnReset, QKeySequence::New);
|
||||
m_resetAction->setObjectName("EMFX.MainWindow.ResetAction");
|
||||
|
||||
|
||||
// save all
|
||||
m_saveAllAction = menu->addAction(tr("Save All..."), this, &MainWindow::OnSaveAll, QKeySequence::Save);
|
||||
m_saveAllAction->setObjectName("EMFX.MainWindow.SaveAllAction");
|
||||
@@ -467,7 +467,7 @@ namespace EMStudio
|
||||
menu->addAction("Documentation", this, []
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl("https://o3de.org/docs/"));
|
||||
});
|
||||
});
|
||||
|
||||
menu->addAction("Forums", this, []
|
||||
{
|
||||
@@ -491,7 +491,7 @@ namespace EMStudio
|
||||
|
||||
// load preferences
|
||||
PluginOptionsNotificationsBus::Router::BusRouterConnect();
|
||||
LoadPreferences();
|
||||
LoadPreferences();
|
||||
m_autosaveTimer->setInterval(m_options.GetAutoSaveInterval() * 60 * 1000);
|
||||
|
||||
// Create the dirty file manager and register the workspace callback.
|
||||
@@ -1072,7 +1072,7 @@ namespace EMStudio
|
||||
// get only the version number of EMotion FX
|
||||
AZStd::string emfxVersionString = EMotionFX::GetEMotionFX().GetVersionString();
|
||||
AzFramework::StringFunc::Replace(emfxVersionString, "EMotion FX ", "", true /* case sensitive */);
|
||||
|
||||
|
||||
// set the window title
|
||||
// only set the EMotion FX version if the filename is empty
|
||||
AZStd::string windowTitle;
|
||||
@@ -1359,7 +1359,7 @@ namespace EMStudio
|
||||
void MainWindow::LoadCharacter(const AZ::Data::AssetId& actorAssetId, const AZ::Data::AssetId& animgraphId, const AZ::Data::AssetId& motionSetId)
|
||||
{
|
||||
m_characterFiles.clear();
|
||||
AZStd::string cachePath = gEnv->pFileIO->GetAlias("@assets@");
|
||||
AZStd::string cachePath = gEnv->pFileIO->GetAlias("@products@");
|
||||
AZStd::string filename;
|
||||
AzFramework::StringFunc::AssetDatabasePath::Normalize(cachePath);
|
||||
|
||||
@@ -1543,12 +1543,12 @@ namespace EMStudio
|
||||
AZStd::string result;
|
||||
if (EMStudio::GetCommandManager()->ExecuteCommand(command, result))
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
"Workspace <font color=green>successfully</font> saved");
|
||||
}
|
||||
else
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
AZStd::string::format("Workspace <font color=red>failed</font> to save<br/><br/>%s", result.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
@@ -1575,12 +1575,12 @@ namespace EMStudio
|
||||
AZStd::string result;
|
||||
if (EMStudio::GetCommandManager()->ExecuteCommand(command, result))
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
"Workspace <font color=green>successfully</font> saved");
|
||||
}
|
||||
else
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
AZStd::string::format("Workspace <font color=red>failed</font> to save<br/><br/>%s", result.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
@@ -1644,7 +1644,7 @@ namespace EMStudio
|
||||
|
||||
Workspace* workspace = GetManager()->GetWorkspace();
|
||||
workspace->SetDirtyFlag(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::OnReset()
|
||||
{
|
||||
@@ -2312,7 +2312,7 @@ namespace EMStudio
|
||||
|
||||
void MainWindow::Activate(const AZ::Data::AssetId& actorAssetId, const EMotionFX::AnimGraph* animGraph, const EMotionFX::MotionSet* motionSet)
|
||||
{
|
||||
AZStd::string cachePath = gEnv->pFileIO->GetAlias("@assets@");
|
||||
AZStd::string cachePath = gEnv->pFileIO->GetAlias("@products@");
|
||||
AZStd::string filename;
|
||||
AzFramework::StringFunc::AssetDatabasePath::Normalize(cachePath);
|
||||
|
||||
@@ -2776,17 +2776,17 @@ namespace EMStudio
|
||||
AZStd::string result;
|
||||
if (GetCommandManager()->ExecuteCommandGroup(commandGroup, result, false))
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS,
|
||||
"Autosave <font color=green>completed</font>");
|
||||
}
|
||||
else
|
||||
{
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR,
|
||||
AZStd::string::format("Autosave <font color=red>failed</font><br/><br/>%s", result.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MainWindow::moveEvent(QMoveEvent* event)
|
||||
{
|
||||
MCORE_UNUSED(event);
|
||||
|
||||
@@ -428,7 +428,7 @@ namespace EMStudio
|
||||
continue;
|
||||
}
|
||||
|
||||
AzFramework::StringFunc::Replace(commands[i], "@assets@/", assetCacheFolder.c_str(), true /* case sensitive */);
|
||||
AzFramework::StringFunc::Replace(commands[i], "@products@/", assetCacheFolder.c_str(), true /* case sensitive */);
|
||||
|
||||
// add the command to the command group
|
||||
commandGroup->AddCommandString(commands[i]);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <Integration/Assets/AnimGraphAsset.h>
|
||||
#include <EMotionFX/Source/Allocators.h>
|
||||
#include <EMotionFX/Source/AnimGraphManager.h>
|
||||
@@ -66,14 +68,10 @@ namespace EMotionFX
|
||||
// through this method. Once EMotionFX is integrated to the asset system this can go away.
|
||||
AZStd::string assetFilename;
|
||||
EBUS_EVENT_RESULT(assetFilename, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, asset.GetId());
|
||||
const char* devAssetsPath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@");
|
||||
if (devAssetsPath)
|
||||
AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
|
||||
if (!projectPath.empty())
|
||||
{
|
||||
AZStd::string assetSourcePath = devAssetsPath;
|
||||
|
||||
AzFramework::StringFunc::AssetDatabasePath::Normalize(assetSourcePath);
|
||||
AZStd::string filename;
|
||||
AzFramework::StringFunc::AssetDatabasePath::Join(assetSourcePath.c_str(), assetFilename.c_str(), filename);
|
||||
AZ::IO::FixedMaxPathString filename{ (projectPath / assetFilename).LexicallyNormal().FixedMaxPathStringAsPosix() };
|
||||
|
||||
assetData->m_emfxAnimGraph->SetFileName(filename.c_str());
|
||||
}
|
||||
@@ -81,7 +79,7 @@ namespace EMotionFX
|
||||
{
|
||||
if (GetEMotionFX().GetIsInEditorMode())
|
||||
{
|
||||
AZ_Warning("EMotionFX", false, "Failed to retrieve asset source path with alias '@devassets@'. Cannot set absolute filename for '%s'", assetFilename.c_str());
|
||||
AZ_Warning("EMotionFX", false, "Failed to retrieve project root path . Cannot set absolute filename for '%s'", assetFilename.c_str());
|
||||
}
|
||||
assetData->m_emfxAnimGraph->SetFileName(assetFilename.c_str());
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <Integration/Assets/MotionSetAsset.h>
|
||||
#include <EMotionFX/Source/MotionSet.h>
|
||||
@@ -46,7 +47,7 @@ namespace EMotionFX
|
||||
const char* motionFile = entry->GetFilename();
|
||||
AZ::Data::AssetId motionAssetId;
|
||||
EBUS_EVENT_RESULT(motionAssetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, motionFile, azrtti_typeid<MotionAsset>(), false);
|
||||
|
||||
|
||||
// if it failed to find it, it might be still compiling - try forcing an immediate compile:
|
||||
if (!motionAssetId.IsValid())
|
||||
{
|
||||
@@ -149,14 +150,11 @@ namespace EMotionFX
|
||||
// through this method. Once EMotionFX is integrated to the asset system this can go away.
|
||||
AZStd::string assetFilename;
|
||||
EBUS_EVENT_RESULT(assetFilename, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, asset.GetId());
|
||||
const char* devAssetsPath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@");
|
||||
if (devAssetsPath)
|
||||
{
|
||||
AZStd::string assetSourcePath = devAssetsPath;
|
||||
|
||||
AZ::StringFunc::AssetDatabasePath::Normalize(assetSourcePath);
|
||||
AZStd::string filename;
|
||||
AZ::StringFunc::AssetDatabasePath::Join(assetSourcePath.c_str(), assetFilename.c_str(), filename);
|
||||
AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
|
||||
if (!projectPath.empty())
|
||||
{
|
||||
AZ::IO::FixedMaxPathString filename{ (projectPath / assetFilename).LexicallyNormal().FixedMaxPathStringAsPosix() };
|
||||
|
||||
assetData->m_emfxMotionSet->SetFilename(filename.c_str());
|
||||
}
|
||||
@@ -164,11 +162,11 @@ namespace EMotionFX
|
||||
{
|
||||
if (GetEMotionFX().GetIsInEditorMode())
|
||||
{
|
||||
AZ_Warning("EMotionFX", false, "Failed to retrieve asset source path with alias '@devassets@'. Cannot set absolute filename for '%s'", assetFilename.c_str());
|
||||
AZ_Warning("EMotionFX", false, "Failed to retrieve project root path . Cannot set absolute filename for '%s'", assetFilename.c_str());
|
||||
}
|
||||
assetData->m_emfxMotionSet->SetFilename(assetFilename.c_str());
|
||||
}
|
||||
|
||||
|
||||
// now load them in:
|
||||
const EMotionFX::MotionSet::MotionEntries& motionEntries = assetData->m_emfxMotionSet->GetMotionEntries();
|
||||
// Get the motions in the motion set. Escalate them to the top of the build queue first so that they can be done in parallel.
|
||||
@@ -179,7 +177,7 @@ namespace EMotionFX
|
||||
const char* motionFilename = motionEntry->GetFilename();
|
||||
AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, motionFilename);
|
||||
}
|
||||
|
||||
|
||||
// now that they're all escalated, the asset processor will be processing them across all threads, and we can request them one by one:
|
||||
for (const auto& item : motionEntries)
|
||||
{
|
||||
|
||||
@@ -487,9 +487,9 @@ namespace EMotionFX
|
||||
return;
|
||||
}
|
||||
|
||||
SetMediaRoot("@assets@");
|
||||
// \todo Right now we're pointing at the @devassets@ location (source) and working from there, because .actor and .motion (motion) aren't yet processed through
|
||||
// the scene pipeline. Once they are, we'll need to update various segments of the Tool to always read from the @assets@ cache, but write to the @devassets@ data/metadata.
|
||||
SetMediaRoot("@products@");
|
||||
// \todo Right now we're pointing at the @projectroot@ location (source) and working from there, because .actor and .motion (motion) aren't yet processed through
|
||||
// the scene pipeline. Once they are, we'll need to update various segments of the Tool to always read from the @products@ cache, but write to the @projectroot@ data/metadata.
|
||||
EMotionFX::GetEMotionFX().InitAssetFolderPaths();
|
||||
|
||||
// Register EMotionFX event handler
|
||||
|
||||
@@ -25,11 +25,11 @@ namespace EMotionFX
|
||||
ExecuteCommands({
|
||||
R"str(CreateMotionSet -name MotionSet0)str",
|
||||
R"str(CreateMotionSet -name MotionSet1)str",
|
||||
R"str(MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str",
|
||||
R"str(MotionSetAddMotion -motionSetID 1 -motionFilenamesAndIds @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str",
|
||||
R"str(MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str",
|
||||
R"str(MotionSetAddMotion -motionSetID 1 -motionFilenamesAndIds @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str",
|
||||
R"str(MotionSetRemoveMotion -motionSetID 0 -motionIds rin_idle)str",
|
||||
R"str(RemoveMotionSet -motionSetID 0)str",
|
||||
R"str(RemoveMotion -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion)str",
|
||||
R"str(RemoveMotion -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion)str",
|
||||
});
|
||||
|
||||
EMStudio::MotionSetsWindowPlugin* motionSetsWindowPlugin = static_cast<EMStudio::MotionSetsWindowPlugin*>(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::MotionSetsWindowPlugin::CLASS_ID));
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace EMotionFX
|
||||
ASSERT_TRUE(motionSet) << "Motion set with id 0 does not exist";
|
||||
motionSetsWindowPlugin->SetSelectedSet(motionSet);
|
||||
|
||||
const std::string filename = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion";
|
||||
const std::string filename = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion";
|
||||
ExecuteCommands({
|
||||
"ImportMotion -filename " + filename,
|
||||
"MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds " + filename + ";rin_idle",
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace EMotionFX
|
||||
// By using this mock catalog, we can pretend to load the specific referenced assets without actually loading anything.
|
||||
UnitTest::MockLoadAssetCatalogAndHandler testAssetCatalog({ referencedAnimGraph, referencedMotionSet });
|
||||
|
||||
const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExample.animgraph";
|
||||
const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExample.animgraph";
|
||||
AZStd::vector<AssetBuilderSDK::ProductDependency> productDependencies;
|
||||
EMotionFXBuilder::AnimGraphBuilderWorker builderWorker;
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace EMotionFX
|
||||
|
||||
TEST_F(EMotionFXBuilderTests, TestAnimGraphAsset_NoDependency_OutputNoProductDependencies)
|
||||
{
|
||||
const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExampleNoDependency.animgraph";
|
||||
const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExampleNoDependency.animgraph";
|
||||
AZStd::vector<AssetBuilderSDK::ProductDependency> productDependencies;
|
||||
EMotionFXBuilder::AnimGraphBuilderWorker builderWorker;
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace EMotionFX
|
||||
|
||||
TEST_F(EMotionFXBuilderTests, TestAnimGraphAsset_InvalidFilePath_OutputNoProductDependencies)
|
||||
{
|
||||
const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.animgraph";
|
||||
const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.animgraph";
|
||||
AZStd::vector<AssetBuilderSDK::ProductDependency> productDependencies;
|
||||
EMotionFXBuilder::AnimGraphBuilderWorker builderWorker;
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace EMotionFX
|
||||
|
||||
TEST_F(EMotionFXBuilderTests, TestAnimGraphAsset_EmptyFile_OutputNoProductDependencies)
|
||||
{
|
||||
const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyAnimGraphExample.animgraph";
|
||||
const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyAnimGraphExample.animgraph";
|
||||
AZStd::vector<AssetBuilderSDK::ProductDependency> productDependencies;
|
||||
EMotionFXBuilder::AnimGraphBuilderWorker builderWorker;
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace EMotionFX
|
||||
|
||||
TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_HasReferenceNode_OutputProductDependencies)
|
||||
{
|
||||
const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset";
|
||||
const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset";
|
||||
ProductPathDependencySet productDependencies;
|
||||
EMotionFXBuilder::MotionSetBuilderWorker builderWorker;
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace EMotionFX
|
||||
|
||||
TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_NoDependency_OutputNoProductDependencies)
|
||||
{
|
||||
const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExampleNoDependency.motionset";
|
||||
const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExampleNoDependency.motionset";
|
||||
ProductPathDependencySet productDependencies;
|
||||
EMotionFXBuilder::MotionSetBuilderWorker builderWorker;
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace EMotionFX
|
||||
|
||||
TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_InvalidFilePath_OutputNoProductDependencies)
|
||||
{
|
||||
const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.motionset";
|
||||
const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.motionset";
|
||||
ProductPathDependencySet productDependencies;
|
||||
EMotionFXBuilder::MotionSetBuilderWorker builderWorker;
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace EMotionFX
|
||||
|
||||
TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_EmptyFile_OutputNoProductDependencies)
|
||||
{
|
||||
const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyMotionSetExample.motionset";
|
||||
const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyMotionSetExample.motionset";
|
||||
ProductPathDependencySet productDependencies;
|
||||
EMotionFXBuilder::MotionSetBuilderWorker builderWorker;
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace EMotionFX
|
||||
{
|
||||
using testing::_;
|
||||
|
||||
const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset";
|
||||
const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset";
|
||||
|
||||
MockAssetSystemRequests assetSystem;
|
||||
EXPECT_CALL(assetSystem, CompileAssetSync(_))
|
||||
|
||||
@@ -302,7 +302,7 @@ namespace EMotionFX
|
||||
GetEMotionFX().SetMediaRootFolder(assetFolder.c_str());
|
||||
GetEMotionFX().InitAssetFolderPaths();
|
||||
|
||||
const char* actorFilename = "@assets@\\animationsamples\\advanced_rinlocomotion\\actor\\rinactor.actor";
|
||||
const char* actorFilename = "@products@\\animationsamples\\advanced_rinlocomotion\\actor\\rinactor.actor";
|
||||
|
||||
Importer* importer = GetEMotionFX().GetImporter();
|
||||
importer->SetLoggingEnabled(false);
|
||||
@@ -402,9 +402,9 @@ namespace EMotionFX
|
||||
|
||||
// This path points to assets in the advance rin demo.
|
||||
// To test different assets, change the path here.
|
||||
const char* actorFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor";
|
||||
const char* motionSetFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset";
|
||||
const char* animGraphFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph";
|
||||
const char* actorFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor";
|
||||
const char* motionSetFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset";
|
||||
const char* animGraphFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph";
|
||||
|
||||
Importer* importer = GetEMotionFX().GetImporter();
|
||||
importer->SetLoggingEnabled(false);
|
||||
@@ -714,9 +714,9 @@ namespace EMotionFX
|
||||
|
||||
// This path points to assets in the advance rin demo.
|
||||
// To test different assets, change the path here.
|
||||
const char* actorFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor";
|
||||
const char* motionSetFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset";
|
||||
const char* animGraphFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph";
|
||||
const char* actorFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor";
|
||||
const char* motionSetFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset";
|
||||
const char* animGraphFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph";
|
||||
|
||||
Importer* importer = GetEMotionFX().GetImporter();
|
||||
importer->SetLoggingEnabled(false);
|
||||
@@ -772,13 +772,13 @@ namespace EMotionFX
|
||||
TEST_F(PerformanceTestFixture, DISABLED_MotionSamplingPerformanceNonUniform)
|
||||
{
|
||||
// Make sure that the motion is set to use NonUniform sampling! Change this in the scene settings! Otherwise you get wrong results.
|
||||
TestMotionSamplingPerformance("@assets@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_idle.motion");
|
||||
TestMotionSamplingPerformance("@products@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_idle.motion");
|
||||
}
|
||||
|
||||
TEST_F(PerformanceTestFixture, DISABLED_MotionSamplingPerformanceUniform)
|
||||
{
|
||||
// Make sure that the motion is set to use Uniform sampling! Change this in the scene settings! Otherwise you get wrong results.
|
||||
TestMotionSamplingPerformance("@assets@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_walk_kick_01.motion");
|
||||
TestMotionSamplingPerformance("@products@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_walk_kick_01.motion");
|
||||
}
|
||||
|
||||
} // namespace EMotionFX
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace EMotionFX
|
||||
ASSERT_EQ(GetActorManager().GetNumActors(), 0);
|
||||
|
||||
// Load an Actor
|
||||
const char* actorCmd{ "ImportActor -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor" };
|
||||
const char* actorCmd{ "ImportActor -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor" };
|
||||
{
|
||||
AZStd::string result;
|
||||
EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(actorCmd, result)) << result.c_str();
|
||||
|
||||
@@ -297,16 +297,16 @@ namespace EMotionFX
|
||||
INSTANTIATE_TEST_CASE_P(Integ_TestPoses, INTEG_PoseComparisonFixture,
|
||||
::testing::Values(
|
||||
PoseComparisonFixtureParams (
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor",
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph",
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset",
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording"
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording"
|
||||
),
|
||||
PoseComparisonFixtureParams (
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor",
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph",
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset",
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording"
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording"
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -314,10 +314,10 @@ namespace EMotionFX
|
||||
INSTANTIATE_TEST_CASE_P(Integ_TestPoseComparison, INTEG_TestPoseComparisonFixture,
|
||||
::testing::Values(
|
||||
PoseComparisonFixtureParams (
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor",
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph",
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset",
|
||||
"@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording"
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset",
|
||||
"@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -30,12 +30,12 @@ namespace EMotionFX
|
||||
motionSetsWindowPlugin->SetSelectedSet(motionSet);
|
||||
|
||||
ExecuteCommands({
|
||||
"ImportMotion -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion",
|
||||
"MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle"
|
||||
"ImportMotion -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion",
|
||||
"MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle"
|
||||
});
|
||||
|
||||
char resolvedPath[AZ::IO::MaxPathLength];
|
||||
EXPECT_TRUE(AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", resolvedPath, AZ_ARRAY_SIZE(resolvedPath)));
|
||||
EXPECT_TRUE(AZ::IO::FileIOBase::GetInstance()->ResolvePath("@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", resolvedPath, AZ_ARRAY_SIZE(resolvedPath)));
|
||||
m_motionFileName = resolvedPath;
|
||||
AzFramework::ApplicationRequests::Bus::Broadcast([](AzFramework::ApplicationRequests* requests, AZStd::string& path) { requests->NormalizePathKeepCase(path); }, m_motionFileName);
|
||||
m_motionName = "rin_idle";
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace EMotionFX
|
||||
|
||||
RecordProperty("test_case_id", "C16302179");
|
||||
|
||||
const AZStd::string motionAsset("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion");
|
||||
const AZStd::string motionAsset("@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion");
|
||||
const AZStd::string createAnimGraphCmd("CreateAnimGraph");
|
||||
const AZStd::string motionSetName("TestMotionSet");
|
||||
const AZStd::string createMotionSetCmd("CreateMotionSet -motionSetID 42 -name " + motionSetName);
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace EMotionFX
|
||||
RecordProperty("test_case_id", "C1559124");
|
||||
|
||||
const QString assetName = "rin_idle"; // Asset name to appear in table
|
||||
const AZStd::string motionCmd = AZStd::string::format("ImportMotion -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion");
|
||||
const AZStd::string motionCmd = AZStd::string::format("ImportMotion -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion");
|
||||
|
||||
auto motionWindowPlugin = static_cast<EMStudio::MotionWindowPlugin*>(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::MotionWindowPlugin::CLASS_ID));
|
||||
ASSERT_TRUE(motionWindowPlugin) << "Could not find the Motion Window Plugin";
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace EMotionFX
|
||||
EXPECT_EQ(table->rowCount(), 1) << "Expected the table to have no rows yet";
|
||||
|
||||
// Create actor and actor instance.
|
||||
const char* actorFilename = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor";
|
||||
const char* actorFilename = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor";
|
||||
AZStd::unique_ptr<EMotionFX::Actor> m_actor = EMotionFX::GetImporter().LoadActor(actorFilename);
|
||||
EXPECT_TRUE(m_actor.get() != nullptr) << "Actor not loaded.";
|
||||
EMotionFX::ActorInstance* m_actorInstance = ActorInstance::Create(m_actor.get());
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace EMotionFX
|
||||
EMStudio::GetMainWindow()->ApplicationModeChanged("AnimGraph");
|
||||
|
||||
// Load Rin anim graph.
|
||||
const char* rinGraph = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph";
|
||||
const char* rinGraph = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph";
|
||||
const AZStd::string rinGraphPath = ResolvePath(rinGraph);
|
||||
AZStd::string command = AZStd::string::format("LoadAnimGraph -filename \"%s\"", rinGraphPath.c_str());
|
||||
AZStd::string result;
|
||||
|
||||
@@ -551,7 +551,7 @@ namespace EMotionFX
|
||||
|
||||
QString GetTestMotionFileName() const
|
||||
{
|
||||
AZStd::string resolvedAssetPath = this->ResolvePath("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion");
|
||||
AZStd::string resolvedAssetPath = this->ResolvePath("@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion");
|
||||
return QString::fromUtf8(resolvedAssetPath.data(), aznumeric_cast<int>(resolvedAssetPath.size()));
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ The API:
|
||||
- ExecuteByString(string) – runs a string buffer in the Python VM; it returns no value
|
||||
- ExecuteByFilename(string) – loads a file off of the disk to execute in the
|
||||
Python VM; the call returns no value. The filename can contain an alias such as
|
||||
‘\@devroot\@’ to execute a project relative file inside the Editor
|
||||
‘\@projectroot\@’ to execute a project relative file inside the Editor
|
||||
|
||||
#### New Console Commands
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user