Merge branch 'main' into Atom/santorac/DepthBasedLayerBlending

This commit is contained in:
Chris Santora
2021-05-20 12:16:06 -07:00
37 changed files with 11610 additions and 88 deletions
@@ -43,6 +43,7 @@ set(GEM_DEPENDENCIES
Gem::GradientSignal
Gem::Vegetation
Gem::Atom_AtomBridge
Gem::AtomFont
Gem::NvCloth
Gem::Blast
Gem::AWSCore
@@ -55,6 +55,7 @@ set(GEM_DEPENDENCIES
Gem::Atom_RHI.Private
Gem::Atom_Feature_Common.Editor
Gem::Atom_AtomBridge.Editor
Gem::AtomFont
Gem::NvCloth.Editor
Gem::Blast.Editor
Gem::AWSCore.Editor
@@ -0,0 +1,97 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import pytest
import os
import logging
import ly_test_tools.log.log_monitor
from AWS.Windows.resource_mappings.resource_mappings import resource_mappings
from AWS.Windows.cdk.cdk import cdk
from AWS.common.aws_utils import aws_utils
from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor as asset_processor
AWS_PROJECT_NAME = 'AWS-AutomationTest'
AWS_CLIENT_AUTH_FEATURE_NAME = 'AWSClientAuth'
AWS_CLIENT_AUTH_DEFAULT_PROFILE_NAME = 'default'
GAME_LOG_NAME = 'Game.log'
logger = logging.getLogger(__name__)
@pytest.mark.SUITE_periodic
@pytest.mark.usefixtures('automatic_process_killer')
@pytest.mark.usefixtures('asset_processor')
@pytest.mark.usefixtures('workspace')
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.usefixtures('cdk')
@pytest.mark.parametrize('feature_name', [AWS_CLIENT_AUTH_FEATURE_NAME])
@pytest.mark.usefixtures('resource_mappings')
@pytest.mark.parametrize('resource_mappings_filename', ['aws_resource_mappings.json'])
@pytest.mark.usefixtures('aws_utils')
@pytest.mark.parametrize('region_name', ['us-west-2'])
@pytest.mark.parametrize('assume_role_arn', ['arn:aws:iam::645075835648:role/o3de-automation-tests'])
@pytest.mark.parametrize('session_name', ['o3de-Automation-session'])
class TestAWSClientAuthPasswordSignIn(object):
"""
Test class to verify AWS Cognito IDP Password sign in and Cognito Identity pool authenticated authorization.
"""
def test_password_signin_credentials(self,
launcher: pytest.fixture,
cdk: pytest.fixture,
resource_mappings: pytest.fixture,
workspace: pytest.fixture,
asset_processor: pytest.fixture,
aws_utils: pytest.fixture
):
"""
Setup: Deploys cdk and updates resource mapping file.
Tests: Sign up new test user, admin confirm the user, sign in and get aws credentials.
Verification: Log monitor looks for success credentials log.
"""
logger.info(f'Cdk stack names:\n{cdk.list()}')
stacks = cdk.deploy()
resource_mappings.populate_output_keys(stacks)
asset_processor.start()
asset_processor.wait_for_idle()
file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), GAME_LOG_NAME)
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor)
launcher.args = ['+LoadLevel', 'AWS/ClientAuthPasswordSignUp']
with launcher.start(launch_ap=False):
result = log_monitor.monitor_log_for_lines(
expected_lines=['(Script) - Signup Success'],
unexpected_lines=['(Script) - Signup Fail'],
halt_on_unexpected=True,
)
assert result, 'Sign Up Success.'
launcher.stop()
cognito_idp = aws_utils.client('cognito-idp')
user_pool_id = resource_mappings.get_resource_name_id(f'{AWS_CLIENT_AUTH_FEATURE_NAME}.CognitoUserPoolId')
print(f'UserPoolId:{user_pool_id}')
cognito_idp.admin_confirm_sign_up(
UserPoolId=user_pool_id,
Username='test1'
)
launcher.args = ['+LoadLevel', 'AWS/ClientAuthPasswordSignIn']
with launcher.start(launch_ap=False):
result = log_monitor.monitor_log_for_lines(
expected_lines=['(Script) - SignIn Success', '(Script) - Success credentials'],
unexpected_lines=['(Script) - SignIn Fail', '(Script) - Fail credentials'],
halt_on_unexpected=True,
)
assert result, 'Sign in Success, fetched authenticated AWS temp credentials.'
@@ -39,6 +39,7 @@ class ResourceMappings:
self._region = region
self._feature_name = feature_name
self._account_id = account_id
self._resource_mappings = {}
assert os.path.exists(self._resource_mapping_file_path), \
f'Invalid resource mapping file path {self._resource_mapping_file_path}'
@@ -79,6 +80,7 @@ class ResourceMappings:
resource_mappings[AWS_RESOURCE_MAPPINGS_KEY][resource_key]['Name/ID'] = output.get('OutputValue',
'InvalidId')
self._resource_mappings = resource_mappings
with open(self._resource_mapping_file_path, 'w') as file_content:
json.dump(resource_mappings, file_content, indent=4)
@@ -103,6 +105,9 @@ class ResourceMappings:
self._region = ''
self._client = None
def get_resource_name_id(self, resource_key: str):
return self._resource_mappings[AWS_RESOURCE_MAPPINGS_KEY][resource_key]['Name/ID']
@pytest.fixture(scope='function')
def resource_mappings(
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:43b1a23b62fe2ffa05545ac99524f40b6fff49d6e35925b9d6138c00d8082e86
size 9073
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,6 @@
<download name="ClientAuthPasswordSignIn" type="Map">
<index src="filelist.xml" dest="filelist.xml"/>
<files>
<file src="level.pak" dest="level.pak" size="DE5" md5="29bd2aae87e99a8fd026fe0cf8156071"/>
</files>
</download>
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f583e0b1b7016a11583383e6c6fcd29f9e796c1a9cd4b6ddb10f7dc91deec17a
size 3557
@@ -0,0 +1,12 @@
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3b948461412d201b3a80abafa60e916f860e46e28109333fbd263a2d5fc53c5a
size 9103
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,6 @@
<download name="ClientAuthPasswordSignUp" type="Map">
<index src="filelist.xml" dest="filelist.xml"/>
<files>
<file src="level.pak" dest="level.pak" size="DE1" md5="0795859fc4ac009a50dd08ffabb03dec"/>
</files>
</download>
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8cdb456f6eb348be27249d80e9d2262e1e0bdabf2c1ff02c1a64a5609dcd823c
size 3553
@@ -0,0 +1,12 @@
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
@@ -0,0 +1,5 @@
{
"AWS":
{
}
}
@@ -84,6 +84,7 @@ namespace AzToolsFramework
AZStd::vector<AZ::Entity*> entities;
AZStd::vector<AZStd::unique_ptr<Instance>> instances;
AZStd::unordered_map<Instance*, PrefabDom> nestedInstanceLinkPatchesMap;
// Retrieve all entities affected and identify Instances
if (!RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonRootEntityOwningInstance->get(), entities, instances))
@@ -96,6 +97,16 @@ namespace AzToolsFramework
// target templates of the other instances.
for (auto& nestedInstance : instances)
{
auto linkRef = m_prefabSystemComponentInterface->FindLink(nestedInstance->GetLinkId());
if (linkRef.has_value())
{
PrefabDom oldLinkPatches;
oldLinkPatches.CopyFrom(linkRef->get().GetLinkDom(), oldLinkPatches.GetAllocator());
nestedInstanceLinkPatchesMap.emplace(nestedInstance.get(), AZStd::move(oldLinkPatches));
}
RemoveLink(nestedInstance, commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
}
@@ -122,6 +133,9 @@ namespace AzToolsFramework
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
// Apply the correct transform to the container for the new instance, and store the patch for use when creating the link.
PrefabDom patch = ApplyContainerTransformAndGeneratePatch(containerEntityId, commonRootEntityId, topLevelEntities);
// Parent the non-container top level entities to the container entity.
// Parenting the top level container entities will be done during the creation of links.
for (AZ::Entity* topLevelEntity : topLevelEntities)
@@ -141,35 +155,55 @@ namespace AzToolsFramework
instanceToCreate->get().GetNestedInstances([&](AZStd::unique_ptr<Instance>& nestedInstance) {
AZ_Assert(nestedInstance, "Invalid nested instance found in the new prefab created.");
EntityOptionalReference nestedInstanceContainerEntity = nestedInstance->GetContainerEntity();
AZ_Assert(
nestedInstanceContainerEntity, "Invalid container entity found for the nested instance used in prefab creation.");
AZ::EntityId parentId;
AZ::TransformBus::EventResult(
parentId, nestedInstanceContainerEntity->get().GetId(), &AZ::TransformBus::Events::GetParentId);
AZ::EntityId nestedInstanceContainerEntityId = nestedInstanceContainerEntity->get().GetId();
PrefabDom previousPatch;
auto entityIterator = AZStd::find_if(
entities.begin(), entities.end(), [parentId](AZ::Entity* entity) { return entity->GetId() == parentId; });
// If the previous parent entity of the nested instance is not part of the entities of the newly created prefab,
// then set the parent of the nested prefab as the container entity of the newly created prefab.
if (entityIterator == entities.end())
// Retrieve the previous patch if it exists
if (nestedInstanceLinkPatchesMap.contains(nestedInstance.get()))
{
parentId = containerEntityId;
previousPatch = AZStd::move(nestedInstanceLinkPatchesMap[nestedInstance.get()]);
}
// These link creations shouldn't be undone because that would put the template in a non-usable state if a user
// chooses to instantiate the template after undoing the creation.
CreateLink(
{&nestedInstanceContainerEntity->get()}, *nestedInstance, instanceToCreate->get().GetTemplateId(),
undoBatch.GetUndoBatch(), parentId, false);
CreateLink(*nestedInstance, instanceToCreate->get().GetTemplateId(), undoBatch.GetUndoBatch(), AZStd::move(previousPatch), false);
// If this nested instance's container is a top level entity in the new prefab, re-parent it and apply the change.
if (AZStd::find(topLevelEntities.begin(), topLevelEntities.end(), &nestedInstanceContainerEntity->get()) != topLevelEntities.end())
{
Prefab::PrefabDom containerEntityDomBefore;
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *nestedInstanceContainerEntity);
AZ::TransformBus::Event(nestedInstanceContainerEntityId, &AZ::TransformBus::Events::SetParent, containerEntityId);
PrefabDom containerEntityDomAfter;
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *nestedInstanceContainerEntity);
PrefabDom reparentPatch;
m_instanceToTemplateInterface->GeneratePatch(reparentPatch, containerEntityDomBefore, containerEntityDomAfter);
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(reparentPatch, nestedInstanceContainerEntityId);
// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes as a separate step
m_prefabUndoCache.Store(nestedInstanceContainerEntityId, AZStd::move(containerEntityDomAfter));
// Save these changes as patches to the link
PrefabUndoLinkUpdate* linkUpdate = aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast<AZ::u64>(nestedInstanceContainerEntityId)));
linkUpdate->SetParent(undoBatch.GetUndoBatch());
linkUpdate->Capture(reparentPatch, nestedInstance->GetLinkId());
linkUpdate->Redo();
}
});
// Create a link between the templates of the newly created instance and the instance it's being parented under.
CreateLink(
topLevelEntities, instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(),
undoBatch.GetUndoBatch(), commonRootEntityId);
instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch(),
AZStd::move(patch));
for (AZ::Entity* topLevelEntity : topLevelEntities)
{
@@ -199,6 +233,40 @@ namespace AzToolsFramework
return AZ::Success();
}
PrefabDom PrefabPublicHandler::ApplyContainerTransformAndGeneratePatch(AZ::EntityId containerEntityId, AZ::EntityId parentEntityId, const EntityList& childEntities)
{
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
AZ_Assert(containerEntity, "Invalid container entity passed to ApplyContainerTransformAndGeneratePatch.");
// Generate the transform for the container entity out of the top level entities, and set it
// This step needs to be done before anything is parented to the container, else children position will be wrong
Prefab::PrefabDom containerEntityDomBefore;
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *containerEntity);
AZ::Vector3 containerEntityTranslation(AZ::Vector3::CreateZero());
AZ::Quaternion containerEntityRotation(AZ::Quaternion::CreateZero());
// Set container entity to be child of common root
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, parentEntityId);
// Set the transform (translation, rotation) of the container entity
GenerateContainerEntityTransform(childEntities, containerEntityTranslation, containerEntityRotation);
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalTranslation, containerEntityTranslation);
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, containerEntityRotation);
PrefabDom containerEntityDomAfter;
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *containerEntity);
PrefabDom patch;
m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
return AZStd::move(patch);
}
PrefabOperationResult PrefabPublicHandler::InstantiatePrefab(
AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position)
{
@@ -249,10 +317,10 @@ namespace AzToolsFramework
// Initialize Undo Batch object
ScopedUndoBatch undoBatch("Instantiate Prefab");
// Instantiate the Prefab
PrefabDom instanceToParentUnderDomBeforeCreate;
m_instanceToTemplateInterface->GenerateDomForInstance(instanceToParentUnderDomBeforeCreate, instanceToParentUnder->get());
// Instantiate the Prefab
auto instanceToCreate = prefabEditorEntityOwnershipInterface->InstantiatePrefab(relativePath, instanceToParentUnder);
if (!instanceToCreate)
@@ -264,11 +332,32 @@ namespace AzToolsFramework
PrefabUndoHelpers::UpdatePrefabInstance(
instanceToParentUnder->get(), "Update prefab instance", instanceToParentUnderDomBeforeCreate, undoBatch.GetUndoBatch());
CreateLink({}, instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(), undoBatch.GetUndoBatch(), parent);
// Create Link with correct container patches
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
AZ_Assert(containerEntity, "Invalid container entity detected in InstantiatePrefab.");
// Apply position
Prefab::PrefabDom containerEntityDomBefore;
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *containerEntity);
// Set container entity's parent
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, parent);
// Set the position of the container entity
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetWorldTranslation, position);
PrefabDom containerEntityDomAfter;
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *containerEntity);
// Generate patch to be stored in the link
PrefabDom patch;
m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
CreateLink(instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(), undoBatch.GetUndoBatch(), AZStd::move(patch));
// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
}
return AZ::Success();
@@ -335,33 +424,9 @@ namespace AzToolsFramework
}
void PrefabPublicHandler::CreateLink(
const EntityList& topLevelEntities, Instance& sourceInstance, TemplateId targetTemplateId,
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId commonRootEntityId, const bool isUndoRedoSupportNeeded)
Instance& sourceInstance, TemplateId targetTemplateId,
UndoSystem::URSequencePoint* undoBatch, PrefabDom patch, const bool isUndoRedoSupportNeeded)
{
AZ::EntityId containerEntityId = sourceInstance.GetContainerEntityId();
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
Prefab::PrefabDom containerEntityDomBefore;
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, *containerEntity);
AZ::Vector3 containerEntityTranslation(AZ::Vector3::CreateZero());
AZ::Quaternion containerEntityRotation(AZ::Quaternion::CreateZero());
// Set the transform (translation, rotation) of the container entity
GenerateContainerEntityTransform(topLevelEntities, containerEntityTranslation, containerEntityRotation);
// Set container entity to be child of common root
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, commonRootEntityId);
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalTranslation, containerEntityTranslation);
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, containerEntityRotation);
PrefabDom containerEntityDomAfter;
m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, *containerEntity);
PrefabDom patch;
m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
LinkId linkId;
if (isUndoRedoSupportNeeded)
{
@@ -377,9 +442,6 @@ namespace AzToolsFramework
}
sourceInstance.SetLinkId(linkId);
// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
}
void PrefabPublicHandler::RemoveLink(
@@ -68,20 +68,32 @@ namespace AzToolsFramework
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const;
/**
* Applies the correct transform changes to the container entity based on the parent and child entities provided, and returns an appropriate patch.
* The container will be parented to parentId, moved to the average transform of the future direct children and its cache will be updated.
* This helper function won't support undo/redo, update the templates or create any links. All that needs to be done by the caller.
*
* \param containerEntityId The container to apply the changes to.
* \param parentEntityId The id of the entity the container should be parented to.
* \param childEntities A list of entities that will subsequently be parented to this container.
* \return The PrefabDom containing the patches that should be stored in the parent link.
*/
PrefabDom ApplyContainerTransformAndGeneratePatch(
AZ::EntityId containerEntityId, AZ::EntityId parentEntityId, const EntityList& childEntities);
/**
* Creates a link between the templates of an instance and its parent.
*
* \param topLevelEntities The list of entities that are immediate children to the container entity of the instance.
* \param sourceInstance The instance that corresponds to the source template of the link.
* \param targetInstance The id of the target template.
* \param undoBatch The undo batch to set as parent for this create link action.
* \param commonRootEntityId The id of the entity that the source instance should be parented under.
* \param patch The patch to store in the newly created link dom.
* \param isUndoRedoSupportNeeded The flag indicating whether the link should be created with undo/redo support or not.
*/
void CreateLink(
const EntityList& topLevelEntities, Instance& sourceInstance, TemplateId targetTemplateId,
UndoSystem::URSequencePoint* undoBatch, AZ::EntityId commonRootEntityId, const bool isUndoRedoSupportNeeded = true);
Instance& sourceInstance, TemplateId targetTemplateId, UndoSystem::URSequencePoint* undoBatch,
PrefabDom patch, const bool isUndoRedoSupportNeeded = true);
/**
* Removes the link between template of the sourceInstance and the template corresponding to targetTemplateId.
@@ -457,15 +457,6 @@ void EditorViewportWidget::Update()
return;
}
static bool sentOnWindowCreated = false;
if (!sentOnWindowCreated && windowHandle()->isActive())
{
sentOnWindowCreated = true;
AzFramework::WindowSystemNotificationBus::Broadcast(
&AzFramework::WindowSystemNotificationBus::Handler::OnWindowCreated,
reinterpret_cast<AzFramework::NativeWindowHandle>(winId()));
}
m_updatingCameraPosition = true;
if (!ed_useNewCameraSystem)
{
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.1359 15.3956L19.6728 7.8125L21.087 9.22671L12 18.5245L12 18.5245L2.86273 9.27696L4.27695 7.86275L12.1359 15.3956Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 286 B

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2732 10.1288L19.8101 17.7119L21.2243 16.2977L12.1373 6.99994L12.1373 6.99995L3 16.2475L4.41421 17.6617L12.2732 10.1288Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 292 B

@@ -58,13 +58,6 @@ namespace O3DE::ProjectManager
hLayout->addWidget(m_gemListView);
hLayout->addWidget(m_gemInspector);
// Select the first entry after everything got correctly sized
QTimer::singleShot(100, [=]{
QModelIndex firstModelIndex = m_gemListView->model()->index(0,0);
m_gemListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
});
}
QVector<GemInfo> GemCatalogScreen::GenerateTestData()
@@ -32,21 +32,36 @@ namespace O3DE::ProjectManager
{
switch (platform)
{
case O3DE::ProjectManager::GemInfo::Android:
case Android:
return "Android";
case O3DE::ProjectManager::GemInfo::iOS:
case iOS:
return "iOS";
case O3DE::ProjectManager::GemInfo::Linux:
case Linux:
return "Linux";
case O3DE::ProjectManager::GemInfo::macOS:
case macOS:
return "macOS";
case O3DE::ProjectManager::GemInfo::Windows:
case Windows:
return "Windows";
default:
return "<Unknown Platform>";
}
}
QString GemInfo::GetTypeString(Type type)
{
switch (type)
{
case Asset:
return "Asset";
case Code:
return "Code";
case Tool:
return "Tool";
default:
return "<Unknown Type>";
}
}
bool GemInfo::IsPlatformSupported(Platform platform) const
{
return (m_platforms & platform);
@@ -36,6 +36,16 @@ namespace O3DE::ProjectManager
Q_DECLARE_FLAGS(Platforms, Platform)
static QString GetPlatformString(Platform platform);
enum Type
{
Asset = 1 << 0,
Code = 1 << 1,
Tool = 1 << 2,
NumTypes = 3
};
Q_DECLARE_FLAGS(Types, Type)
static QString GetTypeString(Type type);
GemInfo() = default;
GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded);
bool IsPlatformSupported(Platform platform) const;
@@ -50,6 +60,7 @@ namespace O3DE::ProjectManager
bool m_isAdded = false; //! Is the gem currently added and enabled in the project?
QString m_summary;
Platforms m_platforms;
Types m_types; //! Asset and/or Code and/or Tool
QStringList m_features;
QString m_directoryLink;
QString m_documentationLink;
@@ -62,3 +73,4 @@ namespace O3DE::ProjectManager
} // namespace O3DE::ProjectManager
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Platforms)
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Types)
@@ -10,7 +10,8 @@
*
*/
#include "GemModel.h"
#include <AzCore/std/string/string.h>
#include <GemCatalog/GemModel.h>
namespace O3DE::ProjectManager
{
@@ -32,8 +33,11 @@ namespace O3DE::ProjectManager
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
item->setData(gemInfo.m_name, RoleName);
const QString uuidString = gemInfo.m_uuid.ToString<AZStd::string>().c_str();
item->setData(uuidString, RoleUuid);
item->setData(gemInfo.m_creator, RoleCreator);
item->setData(static_cast<int>(gemInfo.m_platforms), RolePlatforms);
item->setData(aznumeric_cast<int>(gemInfo.m_platforms), RolePlatforms);
item->setData(aznumeric_cast<int>(gemInfo.m_types), RoleTypes);
item->setData(gemInfo.m_summary, RoleSummary);
item->setData(gemInfo.m_isAdded, RoleIsAdded);
@@ -48,6 +52,8 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_features, RoleFeatures);
appendRow(item);
m_uuidToNameMap[uuidString] = gemInfo.m_displayName;
}
void GemModel::Clear()
@@ -65,11 +71,21 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleCreator).toString();
}
QString GemModel::GetUuidString(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleUuid).toString();
}
GemInfo::Platforms GemModel::GetPlatforms(const QModelIndex& modelIndex)
{
return static_cast<GemInfo::Platforms>(modelIndex.data(RolePlatforms).toInt());
}
GemInfo::Types GemModel::GetTypes(const QModelIndex& modelIndex)
{
return static_cast<GemInfo::Types>(modelIndex.data(RoleTypes).toInt());
}
QString GemModel::GetSummary(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleSummary).toString();
@@ -90,9 +106,35 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleDocLink).toString();
}
AZ::Outcome<QString> GemModel::FindGemNameByUuidString(const QString& uuidString) const
{
const auto iterator = m_uuidToNameMap.find(uuidString);
if (iterator != m_uuidToNameMap.end())
{
return AZ::Success(iterator.value());
}
return AZ::Failure();
}
QStringList GemModel::GetDependingGems(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleDependingGems).toStringList();
QStringList result = modelIndex.data(RoleDependingGems).toStringList();
if (result.isEmpty())
{
return {};
}
for (QString& dependingGemString : result)
{
AZ::Outcome<QString> gemNameOutcome = FindGemNameByUuidString(dependingGemString);
if (gemNameOutcome.IsSuccess())
{
dependingGemString = gemNameOutcome.GetValue();
}
}
return result;
}
QStringList GemModel::GetConflictingGems(const QModelIndex& modelIndex)
@@ -13,7 +13,8 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include "GemInfo.h"
#include <AzCore/Outcome/Outcome.h>
#include <GemCatalog/GemInfo.h>
#include <QAbstractItemModel>
#include <QStandardItemModel>
#include <QItemSelectionModel>
@@ -33,14 +34,18 @@ namespace O3DE::ProjectManager
void AddGem(const GemInfo& gemInfo);
void Clear();
AZ::Outcome<QString> FindGemNameByUuidString(const QString& uuidString) const;
QStringList GetDependingGems(const QModelIndex& modelIndex);
static QString GetName(const QModelIndex& modelIndex);
static QString GetCreator(const QModelIndex& modelIndex);
static QString GetUuidString(const QModelIndex& modelIndex);
static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex);
static GemInfo::Types GetTypes(const QModelIndex& modelIndex);
static QString GetSummary(const QModelIndex& modelIndex);
static bool IsAdded(const QModelIndex& modelIndex);
static QString GetDirectoryLink(const QModelIndex& modelIndex);
static QString GetDocLink(const QModelIndex& modelIndex);
static QStringList GetDependingGems(const QModelIndex& modelIndex);
static QStringList GetConflictingGems(const QModelIndex& modelIndex);
static QString GetVersion(const QModelIndex& modelIndex);
static QString GetLastUpdated(const QModelIndex& modelIndex);
@@ -51,6 +56,7 @@ namespace O3DE::ProjectManager
enum UserRole
{
RoleName = Qt::UserRole,
RoleUuid,
RoleCreator,
RolePlatforms,
RoleSummary,
@@ -63,8 +69,10 @@ namespace O3DE::ProjectManager
RoleLastUpdated,
RoleBinarySize,
RoleFeatures,
RoleTypes
};
QHash<QString, QString> m_uuidToNameMap;
QItemSelectionModel* m_selectionModel = nullptr;
};
} // namespace O3DE::ProjectManager
@@ -27,7 +27,12 @@ namespace O3DE::ProjectManager
void LinkLabel::mousePressEvent([[maybe_unused]] QMouseEvent* event)
{
QDesktopServices::openUrl(m_url);
if (m_url.isValid())
{
QDesktopServices::openUrl(m_url);
}
emit clicked();
}
void LinkLabel::enterEvent([[maybe_unused]] QEvent* event)
@@ -26,10 +26,16 @@ namespace O3DE::ProjectManager
class LinkLabel
: public QLabel
{
Q_OBJECT // AUTOMOC
public:
LinkLabel(const QString& text, const QUrl& url = {}, QWidget* parent = nullptr);
LinkLabel(const QString& text = {}, const QUrl& url = {}, QWidget* parent = nullptr);
void SetUrl(const QUrl& url);
signals:
void clicked();
private:
void mousePressEvent(QMouseEvent* event) override;
void enterEvent(QEvent* event) override;
@@ -426,7 +426,7 @@ namespace O3DE::ProjectManager
{
// required
gemInfo.m_name = Py_To_String(data["Name"]);
gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"]));
gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"]));
// optional
gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name);
@@ -437,7 +437,8 @@ namespace O3DE::ProjectManager
{
for (auto dependency : data["Dependencies"])
{
gemInfo.m_dependingGemUuids.push_back(Py_To_String(dependency["Uuid"]));
const AZ::Uuid uuid = Py_To_String(dependency["Uuid"]);
gemInfo.m_dependingGemUuids.push_back(uuid.ToString<AZStd::string>().c_str());
}
}
if (data.contains("Tags"))
@@ -9,6 +9,8 @@
<file>Resources/iOS.svg</file>
<file>Resources/Linux.svg</file>
<file>Resources/macOS.svg</file>
<file>Resources/ArrowDownLine.svg</file>
<file>Resources/ArrowUpLine.svg</file>
<file>Resources/Backgrounds/FirstTimeBackgroundImage.jpg</file>
</qresource>
</RCC>
@@ -76,7 +76,7 @@ class CognitoUserPool:
scope,
'CognitoUserPoolId',
description="Cognito User pool id",
value=self._user_pool.attr_provider_name)
value=self._user_pool.ref)
core.CfnOutput(
scope,
@@ -13,8 +13,14 @@
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/Asset/AssetCommon.h>
#include <Atom/ImageProcessing/ImageObject.h>
namespace AssetBuilderSDK
{
struct JobProduct;
}
namespace ImageProcessingAtom
{
class ImageProcessingRequests
@@ -35,4 +41,39 @@ namespace ImageProcessingAtom
virtual IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) = 0;
};
using ImageProcessingRequestBus = AZ::EBus<ImageProcessingRequests>;
class ImageBuilderRequests
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
/////////////////////////////////////////////////////////////////////////
//! Create an image object
virtual IImageObjectPtr CreateImage(
AZ::u32 width,
AZ::u32 height,
AZ::u32 maxMipCount,
EPixelFormat pixelFormat) = 0;
//! Convert an image and save its products to the specified folder
virtual AZStd::vector<AssetBuilderSDK::JobProduct> ConvertImageObject(
IImageObjectPtr imageObject,
const AZStd::string& presetName,
const AZStd::string& platformName,
const AZStd::string& outputDir,
const AZ::Data::AssetId& sourceAssetId,
const AZStd::string& sourceAssetName) = 0;
//! Return whether the specified platform is supported by the image builder
virtual bool DoesSupportPlatform(const AZStd::string& platformId) = 0;
//! Return whether the specified preset requires an image to be square and a power of 2
virtual bool IsPresetFormatSquarePow2(const AZStd::string& presetName, const AZStd::string& platformName) = 0;
};
using ImageBuilderRequestBus = AZ::EBus<ImageBuilderRequests>;
} // namespace ImageProcessingAtom
@@ -13,8 +13,6 @@
#include <AzCore/EBus/EBus.h>
class QString;
namespace ImageProcessingAtomEditor
{
class ImageProcessingEditorRequests
@@ -88,11 +88,13 @@ namespace ImageProcessingAtom
m_assetHandlers.emplace_back(AZ::RPI::MakeAssetHandler<AZ::RPI::StreamingImageAssetHandler>());
ImageProcessingRequestBus::Handler::BusConnect();
ImageBuilderRequestBus::Handler::BusConnect();
}
void BuilderPluginComponent::Deactivate()
{
ImageProcessingRequestBus::Handler::BusDisconnect();
ImageBuilderRequestBus::Handler::BusDisconnect();
m_imageBuilder.BusDisconnect();
BuilderSettingManager::DestroyInstance();
CPixelFormats::DestroyInstance();
@@ -146,6 +148,78 @@ namespace ImageProcessingAtom
return image;
}
IImageObjectPtr BuilderPluginComponent::CreateImage(
AZ::u32 width,
AZ::u32 height,
AZ::u32 maxMipCount,
EPixelFormat pixelFormat)
{
IImageObjectPtr image(IImageObject::CreateImage(width, height, maxMipCount, pixelFormat));
return image;
}
AZStd::vector<AssetBuilderSDK::JobProduct> BuilderPluginComponent::ConvertImageObject(
IImageObjectPtr imageObject,
const AZStd::string& presetName,
const AZStd::string& platformName,
const AZStd::string& outputDir,
const AZ::Data::AssetId& sourceAssetId,
const AZStd::string& sourceAssetName)
{
AZStd::vector<AssetBuilderSDK::JobProduct> outProducts;
AZStd::string_view presetFilePath;
const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetName, platformName, &presetFilePath);
if (preset == nullptr)
{
AZ_Assert(false, "Cannot find preset with name %s.", presetName.c_str());
return outProducts;
}
AZStd::unique_ptr<ImageConvertProcessDescriptor> desc = AZStd::make_unique<ImageConvertProcessDescriptor>();
TextureSettings& textureSettings = desc->m_textureSetting;
textureSettings.m_preset = preset->m_uuid;
desc->m_inputImage = imageObject;
desc->m_presetSetting = *preset;
desc->m_isPreview = false;
desc->m_platform = platformName;
desc->m_filePath = presetFilePath;
desc->m_isStreaming = BuilderSettingManager::Instance()->GetBuilderSetting(platformName)->m_enableStreaming;
desc->m_imageName = sourceAssetName;
desc->m_outputFolder = outputDir;
desc->m_sourceAssetId = sourceAssetId;
// Create an image convert process
ImageConvertProcess process(AZStd::move(desc));
process.ProcessAll();
bool result = process.IsSucceed();
if (result)
{
process.GetAppendOutputProducts(outProducts);
}
return outProducts;
}
bool BuilderPluginComponent::DoesSupportPlatform(const AZStd::string& platformId)
{
return ImageProcessingAtom::BuilderSettingManager::Instance()->DoesSupportPlatform(platformId);
}
bool BuilderPluginComponent::IsPresetFormatSquarePow2(const AZStd::string& presetName, const AZStd::string& platformName)
{
AZStd::string_view filePath;
const PresetSettings* preset = BuilderSettingManager::Instance()->GetPreset(presetName, platformName, &filePath);
if (preset == nullptr)
{
AZ_Assert(false, "Cannot find preset with name %s.", presetName.c_str());
return false;
}
const PixelFormatInfo* info = CPixelFormats::GetInstance().GetPixelFormatInfo(preset->m_pixelFormat);
return info->bSquarePow2;
}
void ImageBuilderWorker::ShutDown()
{
// it is important to note that this will be called on a different thread than your process job thread
@@ -47,6 +47,7 @@ namespace ImageProcessingAtom
class BuilderPluginComponent
: public AZ::Component
, protected ImageProcessingRequestBus::Handler
, protected ImageBuilderRequestBus::Handler
{
public:
AZ_COMPONENT(BuilderPluginComponent, "{A227F803-D2E4-406E-93EC-121EF45A64A1}")
@@ -71,6 +72,24 @@ namespace ImageProcessingAtom
IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// ImageBuilderRequestBus interface implementation
IImageObjectPtr CreateImage(
AZ::u32 width,
AZ::u32 height,
AZ::u32 maxMipCount,
EPixelFormat pixelFormat) override;
AZStd::vector<AssetBuilderSDK::JobProduct> ConvertImageObject(
IImageObjectPtr imageObject,
const AZStd::string& presetName,
const AZStd::string& platformName,
const AZStd::string& outputDir,
const AZ::Data::AssetId& sourceAssetId,
const AZStd::string& sourceAssetName) override;
bool DoesSupportPlatform(const AZStd::string& platformId) override;
bool IsPresetFormatSquarePow2(const AZStd::string& presetName, const AZStd::string& platformName) override;
////////////////////////////////////////////////////////////////////////
private:
BuilderPluginComponent(const BuilderPluginComponent&) = delete;
@@ -123,6 +123,12 @@ namespace AZ
m_windowHandle = m_nativeWindow->GetWindowHandle();
}
else
{
// Disable default scene creation for non-games projects
// This can be manually overridden via the DefaultWindowBus.
m_createDefaultScene = false;
}
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
TickBus::Handler::BusConnect();
@@ -351,6 +357,17 @@ namespace AZ
scene->AddRenderPipeline(brdfTexturePipeline);
}
// Send notification when the scene and its pipeline are ready.
// Use the first created pipeline's scene as our default scene for now to allow
// consumers waiting on scene availability to initialize.
if (!m_defaultSceneReady)
{
m_defaultScene = scene;
Render::Bootstrap::NotificationBus::Broadcast(
&Render::Bootstrap::NotificationBus::Handler::OnBootstrapSceneReady, m_defaultScene.get());
m_defaultSceneReady = true;
}
return true;
}
@@ -364,9 +381,6 @@ namespace AZ
{
m_renderPipelineId = pipeline->GetId();
}
// Send notification when the scene and its pipeline are ready
Render::Bootstrap::NotificationBus::Broadcast(&Render::Bootstrap::NotificationBus::Handler::OnBootstrapSceneReady, m_defaultScene.get());
}
void BootstrapSystemComponent::DestroyDefaultScene()
@@ -125,6 +125,7 @@ namespace AZ
Data::Instance<RPI::AttachmentImage> m_brdfTexture;
bool m_createDefaultScene = true;
bool m_defaultSceneReady = false;
// Maps AZ scenes to RPI scene weak pointers to allow looking up a ScenePtr instead of a raw Scene*
AZStd::unordered_map<AzFramework::Scene*, AZStd::weak_ptr<AZ::RPI::Scene>> m_azSceneToAtomSceneMap;
@@ -77,12 +77,16 @@ namespace AZ
}
};
// If PBR material properties aren't in use, fall back to legacy properties. Don't do that if some PBR material properties are set, though.
bool anyPBRInUse = false;
handleTexture("specularF0", SceneAPI::DataTypes::IMaterialData::TextureMapType::Specular);
handleTexture("normal", SceneAPI::DataTypes::IMaterialData::TextureMapType::Normal);
AZStd::optional<bool> useColorMap = materialData.GetUseColorMap();
// If the useColorMap property exists, this is a PBR material and the color should be set to baseColor.
if (useColorMap.has_value())
{
anyPBRInUse = true;
handleTexture("baseColor", SceneAPI::DataTypes::IMaterialData::TextureMapType::BaseColor);
}
else
@@ -97,17 +101,19 @@ namespace AZ
AZStd::optional<AZ::Vector3> baseColor = materialData.GetBaseColor();
if (baseColor.has_value())
{
anyPBRInUse = true;
sourceData.m_properties["baseColor"]["color"].m_value = toColor(baseColor.value());
}
sourceData.m_properties["opacity"]["factor"].m_value = materialData.GetOpacity();
auto applyOptionalPropertiesFunc = [&sourceData](const auto& propertyGroup, const auto& propertyName, const auto& propertyOptional)
auto applyOptionalPropertiesFunc = [&sourceData, &anyPBRInUse](const auto& propertyGroup, const auto& propertyName, const auto& propertyOptional)
{
// Only set PBR settings if they were specifically set in the scene's data.
// Otherwise, leave them unset so the data driven default properties are used.
if (propertyOptional.has_value())
{
anyPBRInUse = true;
sourceData.m_properties[propertyGroup][propertyName].m_value = propertyOptional.value();
}
};
@@ -127,6 +133,13 @@ namespace AZ
handleTexture("ambientOcclusion", SceneAPI::DataTypes::IMaterialData::TextureMapType::AmbientOcclusion);
applyOptionalPropertiesFunc("ambientOcclusion", "useTexture", materialData.GetUseAOMap());
if (!anyPBRInUse)
{
// If it doesn't have the useColorMap property, then it's a non-PBR material and the baseColor
// texture needs to be set to the diffuse color.
sourceData.m_properties["baseColor"]["color"].m_value = toColor(materialData.GetDiffuseColor());
}
return true;
}