Merge branch 'main' into mp_session_integ

This commit is contained in:
puvvadar
2021-06-04 13:22:46 -07:00
153 changed files with 3209 additions and 1506 deletions
@@ -9,11 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
"""
C24064528: The File menu options function normally
C16780778: The File menu options function normally-New view interaction Model enabled
"""
import os
import sys
@@ -54,7 +49,10 @@ class TestFileMenuOptions(EditorTestHelper):
("Save",),
("Save As",),
("Save Level Statistics",),
("Project Settings", "Project Settings Tool"),
("Edit Project Settings",),
("Edit Platform Settings",),
("New Project",),
("Open Project",),
("Show Log File",),
("Resave All Slices",),
("Exit",),
@@ -15,6 +15,7 @@ import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import ly_test_tools._internal.pytest_plugin as internal_plugin
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
@@ -40,6 +41,10 @@ class TestBasicEditorWorkflows(object):
@pytest.mark.SUITE_main
def test_BasicEditorWorkflows_LevelEntityComponentCRUD(self, request, editor, level, launcher_platform):
# Skip test if running against Debug build
if "debug" in internal_plugin.build_directory:
pytest.skip("Does not execute against debug builds.")
expected_lines = [
"Create and load new level: True",
"New entity creation: True",
@@ -7,8 +7,6 @@ distribution (the "License"). All use of this software is governed by the Licens
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.
C16780783: Base Edit Menu Options (New Viewport Interaction Model)
"""
import os
@@ -17,6 +15,7 @@ import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import ly_test_tools.environment.process_utils as process_utils
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
@@ -33,6 +32,7 @@ class TestMenus(object):
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
process_utils.kill_processes_named("o3de", ignore_extensions=True) # Kill ProjectManager windows
request.addfinalizer(teardown)
@@ -80,8 +80,7 @@ class TestMenus(object):
expected_lines,
cfg_args=[level],
run_python="--runpython",
auto_test_mode=True,
timeout=log_monitor_timeout,
timeout=log_monitor_timeout
)
@pytest.mark.test_case_id("C16780807")
@@ -107,13 +106,13 @@ class TestMenus(object):
"Menus_ViewMenuOptions.py",
expected_lines,
cfg_args=[level],
auto_test_mode=True,
run_python="--runpython",
timeout=log_monitor_timeout,
timeout=log_monitor_timeout
)
@pytest.mark.test_case_id("C16780778")
@pytest.mark.SUITE_sandbox
@pytest.mark.xfail # LYN-4208
def test_Menus_FileMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"New Level Action triggered",
@@ -122,7 +121,10 @@ class TestMenus(object):
"Save Action triggered",
"Save As Action triggered",
"Save Level Statistics Action triggered",
"Project Settings Tool Action triggered",
"Edit Project Settings Action triggered",
"Edit Platform Settings Action triggered",
"New Project Action triggered",
"Open Project Action triggered",
"Show Log File Action triggered",
"Resave All Slices Action triggered",
"Exit Action triggered",
@@ -135,7 +137,6 @@ class TestMenus(object):
"Menus_FileMenuOptions.py",
expected_lines,
cfg_args=[level],
auto_test_mode=True,
run_python="--runpython",
timeout=log_monitor_timeout,
)
timeout=log_monitor_timeout
)
@@ -16,6 +16,7 @@ import logging
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import ly_test_tools._internal.pytest_plugin as internal_plugin
import editor_python_test_tools.hydra_test_utils as hydra
from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole
@@ -46,6 +47,11 @@ class TestDynamicSliceInstanceSpawner(object):
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
def test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(self, request, editor, level, workspace, project,
launcher_platform):
# Skip test if running against Debug build
if "debug" in internal_plugin.build_directory:
pytest.skip("Does not execute against debug builds.")
# Ensure temp level does not already exist
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@@ -16,6 +16,7 @@ import logging
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import ly_test_tools._internal.pytest_plugin as internal_plugin
import editor_python_test_tools.hydra_test_utils as hydra
logger = logging.getLogger(__name__)
@@ -40,6 +41,11 @@ class TestEmptyInstanceSpawner(object):
@pytest.mark.SUITE_main
@pytest.mark.dynveg_area
def test_EmptyInstanceSpawner_EmptySpawnerWorks(self, request, editor, level, launcher_platform):
# Skip test if running against Debug build
if "debug" in internal_plugin.build_directory:
pytest.skip("Does not execute against debug builds.")
cfg_args = [level]
expected_lines = [
@@ -23,6 +23,7 @@ import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import ly_test_tools._internal.pytest_plugin as internal_plugin
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
@@ -46,6 +47,11 @@ class TestGraphComponentSync(object):
@pytest.mark.BAT
@pytest.mark.SUITE_main
def test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(self, request, editor, level, launcher_platform):
# Skip test if running against Debug build
if "debug" in internal_plugin.build_directory:
pytest.skip("Does not execute against debug builds.")
cfg_args = [level]
expected_lines = [
@@ -122,6 +128,11 @@ class TestGraphComponentSync(object):
"""
Verifies a Gradient Mixer can be setup in Landscape Canvas and all references are property set.
"""
# Skip test if running against Debug build
if "debug" in internal_plugin.build_directory:
pytest.skip("Does not execute against debug builds.")
cfg_args = [level]
expected_lines = [
+51 -55
View File
@@ -26,6 +26,7 @@
#include <AzFramework/IO/FileOperations.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/Path/Path.h>
#ifdef WIN32
#include <time.h>
@@ -88,7 +89,6 @@ CLog::CLog(ISystem* pSystem)
m_nMainThreadId = CryGetCurrentThreadId();
m_logFileHandle = AZ::IO::InvalidHandle;
#if defined(KEEP_LOG_FILE_OPEN)
m_bFirstLine = true;
#endif
@@ -162,35 +162,6 @@ void CLog::RegisterConsoleVariables()
REGISTER_COMMAND("log_flush", &LogFlushFile, 0, "Flush the log file");
#endif
}
/*
//testbed
{
int iSave0 = m_pLogVerbosity->GetIVal();
int iSave1 = m_pLogFileVerbosity->GetIVal();
for(int i=0;i<=4;++i)
{
m_pLogVerbosity->Set(i);
m_pLogFileVerbosity->Set(i);
LogWithType(eAlways,"CLog selftest: Verbosity=%d FileVerbosity=%d",m_pLogVerbosity->GetIVal(),m_pLogFileVerbosity->GetIVal());
LogWithType(eAlways,"--------------");
LogWithType(eError,"eError");
LogWithType(eWarning,"eWarning");
LogWithType(eMessage,"eMessage");
LogWithType(eInput,"eInput");
LogWithType(eInputResponse,"eInputResponse");
LogWarning("LogWarning()");
LogError("LogError()");
LogWithType(eAlways,"--------------");
}
m_pLogVerbosity->Set(iSave0);
m_pLogFileVerbosity->Set(iSave1);
}
*/
#undef DEFAULT_VERBOSITY
}
@@ -210,7 +181,7 @@ CLog::~CLog()
UnregisterConsoleVariables();
CloseLogFile(true);
CloseLogFile();
}
void CLog::UnregisterConsoleVariables()
@@ -224,31 +195,36 @@ void CLog::UnregisterConsoleVariables()
}
//////////////////////////////////////////////////////////////////////////
void CLog::CloseLogFile([[maybe_unused]] bool forceClose)
void CLog::CloseLogFile()
{
if (m_logFileHandle != AZ::IO::InvalidHandle)
{
AZ::IO::FileIOBase::GetDirectInstance()->Close(m_logFileHandle);
m_logFileHandle = AZ::IO::InvalidHandle;
}
m_logFileHandle.Close();
}
//////////////////////////////////////////////////////////////////////////
AZ::IO::HandleType CLog::OpenLogFile(const char* filename, const char* mode)
bool CLog::OpenLogFile(const char* filename, int mode)
{
using namespace AZ::IO;
AZ_Assert(m_logFileHandle == AZ::IO::InvalidHandle, "Attempt to open log file when one is already open. This would lead to a handle leak.");
if ((!filename) || (filename[0] == 0))
if (m_logFileHandle.IsOpen())
{
return m_logFileHandle;
// Can only AZ_Assert if a file is open, otherwise the AZ_Assert
// would eventually lead to OpenLogFile being opened up again
AZ_Assert(false, "Attempt to open log file when one is already open. This would lead to a handle leak.");
return false;
}
if (filename == nullptr || filename[0] == '\0')
{
return false;
}
// it is assumed that @log@ points at the appropriate place (so for apple, to the user profile dir)
AZ::IO::FileIOBase::GetDirectInstance()->Open(filename, AZ::IO::GetOpenModeFromStringMode(mode), m_logFileHandle);
AZ::IO::FileIOBase* fileSystem = AZ::IO::FileIOBase::GetDirectInstance();
if (AZ::IO::FixedMaxPath logFilePath; fileSystem->ReplaceAlias(logFilePath, filename))
{
logFilePath = logFilePath.LexicallyNormal();
m_logFileHandle.Open(logFilePath.c_str(), mode);
}
if (m_logFileHandle != AZ::IO::InvalidHandle)
if (m_logFileHandle.IsOpen())
{
#if defined(KEEP_LOG_FILE_OPEN)
m_bFirstLine = true;
@@ -257,11 +233,11 @@ AZ::IO::HandleType CLog::OpenLogFile(const char* filename, const char* mode)
else
{
#if defined(LINUX) || defined(APPLE)
syslog(LOG_NOTICE, "Failed to open log file [%s], mode [%s]", filename, mode);
syslog(LOG_NOTICE, "Failed to open log file [%s], mode [%d]", filename, mode);
#endif
}
return m_logFileHandle;
return m_logFileHandle.IsOpen();
}
//////////////////////////////////////////////////////////////////////////
@@ -1114,12 +1090,15 @@ void CLog::LogStringToFile(const char* szString, ELogType logType, bool bAdd, [[
if (logToFile)
{
if (m_logFileHandle == AZ::IO::InvalidHandle)
if (!m_logFileHandle.IsOpen())
{
OpenLogFile(m_szFilename, "w+t");
constexpr auto openMode = AZ::IO::SystemFile::OpenMode::SF_OPEN_APPEND
| AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE
| AZ::IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY;
OpenLogFile(m_szFilename, openMode);
}
if (m_logFileHandle != AZ::IO::InvalidHandle)
if (m_logFileHandle.IsOpen())
{
#if defined(KEEP_LOG_FILE_OPEN)
if (m_bFirstLine)
@@ -1130,9 +1109,9 @@ void CLog::LogStringToFile(const char* szString, ELogType logType, bool bAdd, [[
if (bAdd)
{
// if adding to a prior line erase the \n at the end.
AZ::IO::FileIOBase::GetDirectInstance()->Seek(m_logFileHandle, -2, AZ::IO::SeekType::SeekFromEnd);
m_logFileHandle.Seek(-2, AZ::IO::SystemFile::SeekMode::SF_SEEK_END);
}
AZ::IO::FPutS(tempString.c_str(), m_logFileHandle);
m_logFileHandle.Write(tempString.c_str(), tempString.size());
#if !defined(KEEP_LOG_FILE_OPEN)
CloseLogFile();
#endif
@@ -1383,6 +1362,23 @@ bool CLog::SetFileName(const char* fileNameOrAbsolutePath, bool backupLogs)
CreateBackupFile();
AZ::IO::FileIOBase* fileSystem = AZ::IO::FileIOBase::GetDirectInstance();
AZ::IO::FixedMaxPath newLogFilePath;
if (fileSystem->ReplaceAlias(newLogFilePath, m_szFilename))
{
newLogFilePath = newLogFilePath.LexicallyNormal();
}
if (m_logFileHandle.IsOpen() && newLogFilePath != m_logFileHandle.Name())
{
constexpr auto openMode = AZ::IO::SystemFile::OpenMode::SF_OPEN_APPEND
| AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE
| AZ::IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY;
if(AZ::IO::SystemFile newLogFile; newLogFile.Open(m_szFilename, openMode))
{
m_logFileHandle = AZStd::move(newLogFile);
}
}
return true;
}
@@ -1537,9 +1533,9 @@ const char* CLog::GetModuleFilter()
void CLog::FlushAndClose()
{
#if defined(KEEP_LOG_FILE_OPEN)
if (m_logFileHandle)
if (m_logFileHandle.IsOpen())
{
CloseLogFile(true);
CloseLogFile();
}
#endif
}
+7 -11
View File
@@ -137,8 +137,8 @@ private: // -------------------------------------------------------------------
void LogStringToConsole(const char* szString, ELogType logType, bool bAdd) {}
#endif // !defined(EXCLUDE_NORMAL_LOG)
AZ::IO::HandleType OpenLogFile(const char* filename, const char* mode);
void CloseLogFile(bool force = false);
bool OpenLogFile(const char* filename, int mode);
void CloseLogFile();
// will format the message into m_szTemp
void FormatMessage(const char* szCommand, ...) PRINTF_PARAMS(2, 3);
@@ -152,15 +152,11 @@ private: // -------------------------------------------------------------------
virtual const char* GetAssetScopeString();
#endif
ISystem* m_pSystem; //
float m_fLastLoadingUpdateTime; // for non-frequent streamingEngine update
//char m_szTemp[MAX_TEMP_LENGTH_SIZE]; //
char m_szFilename[MAX_FILENAME_SIZE]; // can be with path
mutable char m_sBackupFilename[MAX_FILENAME_SIZE]; // can be with path
AZ::IO::HandleType m_logFileHandle;
CryStackStringT<char, 32> m_LogMode; //mode m_pLogFile has been opened with
AZ::IO::HandleType m_errFileHandle;
int m_nErrCount;
ISystem* m_pSystem; //
float m_fLastLoadingUpdateTime; // for non-frequent streamingEngine update
char m_szFilename[MAX_FILENAME_SIZE]; // can be with path
mutable char m_sBackupFilename[MAX_FILENAME_SIZE]; // can be with path
AZ::IO::SystemFile m_logFileHandle;
bool m_backupLogs;
+1 -1
View File
@@ -1208,7 +1208,7 @@ bool CSystem::Init(const SSystemInitParams& startupParams)
{
assetPlatform = AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME);
AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, R"(A valid asset platform is missing in "%s/assets" key in the SettingsRegistry.)""\n"
R"(This typically done by setting he "assets" field in the bootstrap.cfg for within a .setreg file)""\n"
R"(This typically done by setting the "assets" field within a .setreg file)""\n"
R"(A fallback of %s will be used.)",
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey,
assetPlatform.c_str());
+39 -21
View File
@@ -30,7 +30,7 @@ namespace Platform
using FileHandleType = SystemFile::FileHandleType;
void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode);
void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode);
SystemFile::SizeType Tell(FileHandleType handle, const SystemFile* systemFile);
bool Eof(FileHandleType handle, const SystemFile* systemFile);
AZ::u64 ModificationTime(FileHandleType handle, const SystemFile* systemFile);
@@ -68,9 +68,8 @@ void SystemFile::CreatePath(const char* fileName)
}
SystemFile::SystemFile()
: m_handle{ AZ_TRAIT_SYSTEMFILE_INVALID_HANDLE }
{
m_fileName[0] = '\0';
m_handle = AZ_TRAIT_SYSTEMFILE_INVALID_HANDLE;
}
SystemFile::~SystemFile()
@@ -81,6 +80,25 @@ SystemFile::~SystemFile()
}
}
SystemFile::SystemFile(SystemFile&& other)
: SystemFile{}
{
AZStd::swap(m_fileName, other.m_fileName);
AZStd::swap(m_handle, other.m_handle);
}
SystemFile& SystemFile::operator=(SystemFile&& other)
{
// Close the current file and take over the SystemFile handle and filename
Close();
m_fileName = AZStd::move(other.m_fileName);
m_handle = AZStd::move(other.m_handle);
other.m_fileName = {};
other.m_handle = AZ_TRAIT_SYSTEMFILE_INVALID_HANDLE;
return *this;
}
bool SystemFile::Open(const char* fileName, int mode, int platformFlags)
{
AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Open - %s", fileName);
@@ -88,42 +106,42 @@ bool SystemFile::Open(const char* fileName, int mode, int platformFlags)
if (fileName) // If we reopen the file we are allowed to have NULL file name
{
if (strlen(fileName) > AZ_ARRAY_SIZE(m_fileName) - 1)
if (strlen(fileName) > m_fileName.max_size())
{
EBUS_EVENT(FileIOEventBus, OnError, this, nullptr, 0);
return false;
}
// store the filename
azsnprintf(m_fileName, AZ_ARRAY_SIZE(m_fileName), "%s", fileName);
m_fileName = fileName;
}
if (FileIOBus::HasHandlers())
{
bool isOpen = false;
bool isHandled = false;
EBUS_EVENT_RESULT(isHandled, FileIOBus, OnOpen, *this, m_fileName, mode, platformFlags, isOpen);
EBUS_EVENT_RESULT(isHandled, FileIOBus, OnOpen, *this, m_fileName.c_str(), mode, platformFlags, isOpen);
if (isHandled)
{
return isOpen;
}
}
AZ_Assert(!IsOpen(), "This file (%s) is already open!", m_fileName);
AZ_Assert(!IsOpen(), "This file (%s) is already open!", m_fileName.c_str());
return PlatformOpen(mode, platformFlags);
}
bool SystemFile::ReOpen(int mode, int platformFlags)
{
AZ_Assert(strlen(m_fileName) > 0, "Missing filename. You must call open first!");
AZ_Assert(!m_fileName.empty(), "Missing filename. You must call open first!");
return Open(0, mode, platformFlags);
}
void SystemFile::Close()
{
AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Close - %s", m_fileName);
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Close - %s", m_fileName);
AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Close - %s", m_fileName.c_str());
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Close - %s", m_fileName.c_str());
if (FileIOBus::HasHandlers())
{
@@ -138,9 +156,9 @@ void SystemFile::Close()
PlatformClose();
}
void SystemFile::Seek(SizeType offset, SeekMode mode)
void SystemFile::Seek(SeekSizeType offset, SeekMode mode)
{
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Seek - %s:%i", m_fileName, offset);
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Seek - %s:%i", m_fileName.c_str(), offset);
if (FileIOBus::HasHandlers())
{
@@ -167,15 +185,15 @@ bool SystemFile::Eof()
AZ::u64 SystemFile::ModificationTime()
{
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::ModTime - %s", m_fileName);
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::ModTime - %s", m_fileName.c_str());
return Platform::ModificationTime(m_handle, this);
}
SystemFile::SizeType SystemFile::Read(SizeType byteSize, void* buffer)
{
AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Read - %s:%i", m_fileName, byteSize);
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Read - %s:%i", m_fileName, byteSize);
AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Read - %s:%i", m_fileName.c_str(), byteSize);
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Read - %s:%i", m_fileName.c_str(), byteSize);
if (FileIOBus::HasHandlers())
{
@@ -193,8 +211,8 @@ SystemFile::SizeType SystemFile::Read(SizeType byteSize, void* buffer)
SystemFile::SizeType SystemFile::Write(const void* buffer, SizeType byteSize)
{
AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Write - %s:%i", m_fileName, byteSize);
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Write - %s:%i", m_fileName, byteSize);
AZ_PROFILE_INTERVAL_SCOPED(AZ::Debug::ProfileCategory::AzCore, this, "SystemFile::Write - %s:%i", m_fileName.c_str(), byteSize);
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Write - %s:%i", m_fileName.c_str(), byteSize);
if (FileIOBus::HasHandlers())
{
@@ -212,14 +230,14 @@ SystemFile::SizeType SystemFile::Write(const void* buffer, SizeType byteSize)
void SystemFile::Flush()
{
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Flush - %s", m_fileName);
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Flush - %s", m_fileName.c_str());
Platform::Flush(m_handle, this);
}
SystemFile::SizeType SystemFile::Length() const
{
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Length - %s", m_fileName);
AZ_PROFILE_SCOPE_STALL_DYNAMIC(AZ::Debug::ProfileCategory::AzCore, "SystemFile::Length - %s", m_fileName.c_str());
return Platform::Length(m_handle, this);
}
@@ -379,9 +397,9 @@ namespace
HasPosixEnumOption(PermissionModeFlags::Write);
#undef HasPosixEnumOption
}
}
FileDescriptorRedirector::FileDescriptorRedirector(int sourceFileDescriptor)
: m_sourceFileDescriptor(sourceFileDescriptor)
{
+13 -8
View File
@@ -12,10 +12,11 @@
#pragma once
#include <AzCore/base.h>
#include <AzCore/std/function/function_fwd.h>
#include <AzCore/std/string/string.h>
#include <AzCore/IO/Path/Path_fwd.h>
#include <AzCore/IO/SystemFile_Platform.h>
#include <AzCore/std/function/function_fwd.h>
#include <AzCore/std/string/fixed_string.h>
// Establish a consistent size that works across platforms. It's actually larger than this
// on platforms we support, but this is a good least common denominator
@@ -51,11 +52,15 @@ namespace AZ
};
using SizeType = AZ::IO::Internal::SizeType;
using SeekSizeType = AZ::IO::Internal::SeekSizeType;
using FileHandleType = AZ::IO::Internal::FileHandleType;
SystemFile();
~SystemFile();
SystemFile(SystemFile&&);
SystemFile& operator=(SystemFile&&);
/**
* Opens a file.
* \param fileName full file name including path
@@ -69,7 +74,7 @@ namespace AZ
/// Closes a file, if file already close it has no effect.
void Close();
/// Seek in current file.
void Seek(SizeType offset, SeekMode mode);
void Seek(SeekSizeType offset, SeekMode mode);
/// Get the cursor position in the current file.
SizeType Tell();
/// Is the cursor at the end of the file?
@@ -87,7 +92,7 @@ namespace AZ
/// Return disc offset if possible, otherwise 0
SizeType DiskOffset() const;
/// Return file name or NULL if file is not open.
AZ_FORCE_INLINE const char* Name() const { return m_fileName; }
AZ_FORCE_INLINE const char* Name() const { return m_fileName.c_str(); }
bool IsOpen() const;
/// Return native handle to the file.
@@ -124,12 +129,12 @@ namespace AZ
private:
static void CreatePath(const char * fileName);
bool PlatformOpen(int mode, int platformFlags);
void PlatformClose();
FileHandleType m_handle;
char m_fileName[AZ_MAX_PATH_LEN];
FileHandleType m_handle;
AZ::IO::FixedMaxPathString m_fileName;
};
/**
@@ -641,6 +641,8 @@ namespace AZ::SettingsRegistryMergeUtils
}
else
{
// Set the default ProjectUserPath to the <engine-root>/user directory
registry.Set(FilePathKey_ProjectUserPath, (engineRoot / "user").LexicallyNormal().Native());
AZ_TracePrintf("SettingsRegistryMergeUtils",
R"(Project path isn't set in the Settings Registry at "%.*s". Project-related filepaths will not be set)" "\n",
aznumeric_cast<int>(projectPathKey.size()), projectPathKey.data());
@@ -101,7 +101,7 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
createPath = (mode & SF_OPEN_CREATE_PATH) == SF_OPEN_CREATE_PATH;
}
bool isApkFile = AZ::Android::Utils::IsApkPath(m_fileName);
bool isApkFile = AZ::Android::Utils::IsApkPath(m_fileName.c_str());
if (createPath)
{
@@ -111,19 +111,19 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
return false;
}
CreatePath(m_fileName);
CreatePath(m_fileName.c_str());
}
int errorCode = 0;
if (isApkFile)
{
AZ::u64 size = 0;
m_handle = AZ::Android::APKFileHandler::Open(m_fileName, openMode, size);
m_handle = AZ::Android::APKFileHandler::Open(m_fileName.c_str(), openMode, size);
errorCode = EACCES; // general error when a file can't be opened from inside the APK
}
else
{
m_handle = fopen(m_fileName, openMode);
m_handle = fopen(m_fileName.c_str(), openMode);
errorCode = errno;
}
@@ -233,7 +233,7 @@ namespace Platform
}
}
void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode)
void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode)
{
if (handle != PlatformSpecificInvalidHandle)
{
@@ -15,6 +15,9 @@
#include <cstdio>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <AzCore/std/typetraits/underlying_type.h>
namespace AZ
{
@@ -23,6 +26,7 @@ namespace AZ
namespace Internal
{
using SizeType = AZ::u64;
using SeekSizeType = AZ::s64;
using FileHandleType = FILE*;
}
@@ -37,7 +41,7 @@ namespace AZ
#else
Temporary = 0, // (Not applicable for this platform) Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified.
#endif
Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists.
Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists.
Truncate = O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY.
// Note: The TRUNC flag destroys the contents of the specified file.
@@ -22,9 +22,10 @@ namespace AZ
namespace Internal
{
using SizeType = AZ::u64;
using SeekSizeType = AZ::s64;
using FileHandleType = int;
}
namespace PosixInternal
{
enum class OpenFlags : int
@@ -36,7 +37,7 @@ namespace AZ
#else
Temporary = 0, // (Not applicable for this platform) Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified.
#endif
Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists.
Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists.
Truncate = O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY.
// Note: The TRUNC flag destroys the contents of the specified file.
@@ -13,6 +13,9 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <AzCore/std/typetraits/underlying_type.h>
namespace AZ
{
@@ -21,6 +24,7 @@ namespace AZ
namespace Internal
{
using SizeType = AZ::u64;
using SeekSizeType = AZ::s64;
using FileHandleType = int;
}
@@ -35,7 +39,7 @@ namespace AZ
#else
Temporary = 0, // (Not applicable for this platform) Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified.
#endif
Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists.
Exclusive = O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists.
Truncate = O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY.
// Note: The TRUNC flag destroys the contents of the specified file.
@@ -86,9 +86,9 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
if (createPath)
{
CreatePath(m_fileName);
CreatePath(m_fileName.c_str());
}
m_handle = open(m_fileName, desiredAccess, permissions);
m_handle = open(m_fileName.c_str(), desiredAccess, permissions);
if (m_handle == PlatformSpecificInvalidHandle)
{
@@ -119,7 +119,7 @@ namespace Platform
{
using FileHandleType = AZ::IO::SystemFile::FileHandleType;
void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode)
void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode)
{
if (handle != PlatformSpecificInvalidHandle)
{
@@ -209,19 +209,19 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
if (createPath)
{
CreatePath(m_fileName);
CreatePath(m_fileName.c_str());
}
# ifdef _UNICODE
wchar_t fileNameW[AZ_MAX_PATH_LEN];
size_t numCharsConverted;
m_handle = INVALID_HANDLE_VALUE;
if (mbstowcs_s(&numCharsConverted, fileNameW, m_fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
if (mbstowcs_s(&numCharsConverted, fileNameW, m_fileName.c_str(), AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
{
m_handle = CreateFileW(fileNameW, dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0);
}
# else //!_UNICODE
m_handle = CreateFile(m_fileName, dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0);
m_handle = CreateFile(m_fileName.c_str(), dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0);
# endif // !_UNICODE
if (m_handle == INVALID_HANDLE_VALUE)
@@ -261,7 +261,7 @@ namespace Platform
{
using FileHandleType = AZ::IO::SystemFile::FileHandleType;
void Seek(FileHandleType handle, const SystemFile* systemFile, SizeType offset, SystemFile::SeekMode mode)
void Seek(FileHandleType handle, const SystemFile* systemFile, SystemFile::SeekSizeType offset, SystemFile::SeekMode mode)
{
if (handle != PlatformSpecificInvalidHandle)
{
@@ -13,6 +13,9 @@
#include <fcntl.h>
#include <corecrt_io.h>
#include <sys/stat.h>
#include <AzCore/std/typetraits/underlying_type.h>
namespace AZ
{
@@ -21,6 +24,7 @@ namespace AZ
namespace Internal
{
using SizeType = AZ::u64;
using SeekSizeType = AZ::s64;
using FileHandleType = void*;
}
@@ -31,7 +35,7 @@ namespace AZ
Append = _O_APPEND, // Moves the file pointer to the end of the file before every write operation.
Create = _O_CREAT, // Creates a file and opens it for writing. Has no effect if the file specified by filename exists. PermissionMode is required.
Temporary = _O_TEMPORARY, // Applies only when used with CREAT. Creates a file as temporary; the file is deleted when the last file descriptor is closed. PermissionMode equired when CREAT is specified.
Exclusive = _O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists.
Exclusive = _O_EXCL, // Applies only when used with CREAT. Returns an error value if a file specified by filename exists.
Truncate = _O_TRUNC, // Opens a file and truncates it to zero length; the file must have write permission. Cannot be specified with RDONLY.
// Note: The TRUNC flag destroys the contents of the specified file.
@@ -711,8 +711,8 @@ namespace AzFramework
}
}
AZ::IO::FixedMaxPath projectUserPath;
if (m_settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath))
if (AZ::IO::FixedMaxPath projectUserPath;
m_settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath))
{
fileIoBase->SetAlias("@user@", projectUserPath.c_str());
AZ::IO::FixedMaxPath projectLogPath = projectUserPath / "log";
@@ -721,6 +721,15 @@ namespace AzFramework
CreateUserCache(projectUserPath, *fileIoBase);
}
else
{
AZ::IO::FixedMaxPath fallbackLogPath = GetEngineRoot();
fallbackLogPath /= "user";
fileIoBase->SetAlias("@user@", fallbackLogPath.c_str());
fallbackLogPath /= "log";
fileIoBase->SetAlias("@log@", fallbackLogPath.c_str());
fileIoBase->CreatePath(fallbackLogPath.c_str());
}
}
}
@@ -12,17 +12,22 @@
#pragma once
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h>
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/Manipulators/PlanarManipulator.h>
namespace AzManipulatorTestFramework
{
//! Create a linear manipulator with a unit sphere bounds.
//! Create a linear manipulator with a unit sphere bound.
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> CreateLinearManipulator(
const AzToolsFramework::ManipulatorManagerId manipulatorManagerId,
const AZ::Vector3& position = AZ::Vector3::CreateZero(),
const float radius = 1.0f);
const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position = AZ::Vector3::CreateZero(),
float radius = 1.0f);
//! Create a planar manipulator with a unit sphere bound.
AZStd::shared_ptr<AzToolsFramework::PlanarManipulator> CreatePlanarManipulator(
const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position = AZ::Vector3::CreateZero(),
float radius = 1.0f);
//! Create a mouse pick from the specified ray and screen point.
AzToolsFramework::ViewportInteraction::MousePick CreateMousePick(
@@ -34,14 +39,12 @@ namespace AzManipulatorTestFramework
//! Create a mouse interaction from the specified pick, buttons, interaction id and keyboard modifiers.
AzToolsFramework::ViewportInteraction::MouseInteraction CreateMouseInteraction(
const AzToolsFramework::ViewportInteraction::MousePick& mousePick,
AzToolsFramework::ViewportInteraction::MouseButtons buttons,
const AzToolsFramework::ViewportInteraction::MousePick& mousePick, AzToolsFramework::ViewportInteraction::MouseButtons buttons,
AzToolsFramework::ViewportInteraction::InteractionId interactionId,
AzToolsFramework::ViewportInteraction::KeyboardModifiers modifiers);
//! Create a mouse buttons from the specified mouse button.
AzToolsFramework::ViewportInteraction::MouseButtons CreateMouseButtons(
AzToolsFramework::ViewportInteraction::MouseButton button);
AzToolsFramework::ViewportInteraction::MouseButtons CreateMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton button);
//! Create a mouse interaction event from the specified interaction and event.
AzToolsFramework::ViewportInteraction::MouseInteractionEvent CreateMouseInteractionEvent(
@@ -61,5 +64,5 @@ namespace AzManipulatorTestFramework
AzFramework::ScreenPoint GetCameraStateViewportCenter(const AzFramework::CameraState& cameraState);
//! Default viewport size (1080p) in 16:9 aspect ratio.
const auto DefaultViewportSize = AZ::Vector2(1920.0f, 1080.0f);
inline const auto DefaultViewportSize = AZ::Vector2(1920.0f, 1080.0f);
} // namespace AzManipulatorTestFramework
@@ -14,7 +14,6 @@
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h>
namespace AzManipulatorTestFramework
@@ -28,22 +27,21 @@ namespace AzManipulatorTestFramework
using MouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent;
using MousePick = AzToolsFramework::ViewportInteraction::MousePick;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> CreateLinearManipulator(
const AzToolsFramework::ManipulatorManagerId manipulatorManagerId,
const AZ::Vector3& position,
const float radius)
// create a default sphere view for a manipulator for simple intersection
template<typename Manipulator>
void SetupManipulatorView(
AZStd::shared_ptr<Manipulator> manipulator, const AzToolsFramework::ManipulatorManagerId manipulatorManagerId,
const AZ::Vector3& position, const float radius)
{
auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(AZ::Transform::CreateIdentity());
manipulator->SetLocalPosition(position);
// unit sphere view
auto sphereView = AzToolsFramework::CreateManipulatorViewSphere(
AZ::Colors::Red, radius,
[](const MouseInteraction& /*mouseInteraction*/, const bool /*mouseOver*/,
const AZ::Color& defaultColor)
{
return defaultColor;
}, true);
[]([[maybe_unused]] const MouseInteraction& mouseInteraction, [[maybe_unused]] const bool mouseOver,
const AZ::Color& defaultColor)
{
return defaultColor;
},
true);
// unit sphere bound
AzToolsFramework::Picking::BoundShapeSphere sphereBound;
@@ -62,6 +60,26 @@ namespace AzManipulatorTestFramework
// this would occur internally when the manipulator is drawn but we must do manually here to ensure that the
// bounds will always be valid upon instantiation
view->RefreshBound(manipulatorManagerId, manipulator->GetManipulatorId(), sphereBound);
}
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> CreateLinearManipulator(
const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position, const float radius)
{
auto manipulator = AzToolsFramework::LinearManipulator::MakeShared(AZ::Transform::CreateIdentity());
manipulator->SetLocalPosition(position);
SetupManipulatorView(manipulator, manipulatorManagerId, position, radius);
return manipulator;
}
AZStd::shared_ptr<AzToolsFramework::PlanarManipulator> CreatePlanarManipulator(
const AzToolsFramework::ManipulatorManagerId manipulatorManagerId, const AZ::Vector3& position, const float radius)
{
auto manipulator = AzToolsFramework::PlanarManipulator::MakeShared(AZ::Transform::CreateIdentity());
manipulator->SetLocalPosition(position);
SetupManipulatorView(manipulator, manipulatorManagerId, position, radius);
return manipulator;
}
@@ -104,8 +122,7 @@ namespace AzManipulatorTestFramework
return buttons;
}
MouseInteractionEvent CreateMouseInteractionEvent(
const MouseInteraction& mouseInteraction, MouseEvent event)
MouseInteractionEvent CreateMouseInteractionEvent(const MouseInteraction& mouseInteraction, MouseEvent event)
{
return MouseInteractionEvent(mouseInteraction, event);
}
@@ -114,8 +131,7 @@ namespace AzManipulatorTestFramework
{
AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Event(
AzToolsFramework::GetEntityContextId(),
&AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions,
event);
&AzToolsFramework::ViewportInteraction::InternalMouseViewportRequests::InternalHandleAllMouseInteractions, event);
}
AzFramework::CameraState SetCameraStatePosition(const AZ::Vector3& position, AzFramework::CameraState& cameraState)
@@ -133,9 +149,7 @@ namespace AzManipulatorTestFramework
AzFramework::ScreenPoint GetCameraStateViewportCenter(const AzFramework::CameraState& cameraState)
{
return {
aznumeric_cast<int>(cameraState.m_viewportSize.GetX() / 2.f),
aznumeric_cast<int>(cameraState.m_viewportSize.GetY() / 2.f)
};
return { aznumeric_cast<int>(cameraState.m_viewportSize.GetX() / 2.f),
aznumeric_cast<int>(cameraState.m_viewportSize.GetY() / 2.f) };
}
} // namespace UnitTest
} // namespace AzManipulatorTestFramework
@@ -10,52 +10,55 @@
*
*/
#include "AzManipulatorTestFrameworkTestFixtures.h"
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include "AzManipulatorTestFrameworkTestFixtures.h"
#include <AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h>
#include <AzToolsFramework/Manipulators/PlanarManipulator.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AZTestShared/Math/MathTestHelpers.h>
namespace UnitTest
{
class GridSnappingFixture
: public ToolsApplicationFixture
class GridSnappingFixture : public ToolsApplicationFixture
{
public:
GridSnappingFixture()
: m_viewportManipulatorInteraction(AZStd::make_unique<AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction>())
, m_actionDispatcher(AZStd::make_unique<AzManipulatorTestFramework::ImmediateModeActionDispatcher>(*m_viewportManipulatorInteraction))
, m_linearManipulator(
AzManipulatorTestFramework::CreateLinearManipulator(
m_viewportManipulatorInteraction->GetManipulatorManager().GetId(),
/*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f),
/*radius=*/m_boundsRadius))
{}
, m_actionDispatcher(
AZStd::make_unique<AzManipulatorTestFramework::ImmediateModeActionDispatcher>(*m_viewportManipulatorInteraction))
{
}
protected:
void SetUpEditorFixtureImpl() override
{
m_cameraState = AzFramework::CreateIdentityDefaultCamera(
AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
m_cameraState =
AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
}
public:
const float m_boundsRadius = 1.0f;
AZStd::unique_ptr<AzManipulatorTestFramework::ManipulatorViewportInteraction> m_viewportManipulatorInteraction;
AZStd::unique_ptr<AzManipulatorTestFramework::ImmediateModeActionDispatcher> m_actionDispatcher;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> m_linearManipulator;
AzFramework::CameraState m_cameraState;
};
TEST_F(GridSnappingFixture, MouseDownWithSnappingEnabledSnapsToClosestGridSize)
{
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> linearManipulator(AzManipulatorTestFramework::CreateLinearManipulator(
m_viewportManipulatorInteraction->GetManipulatorManager().GetId(),
/*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f),
/*radius=*/m_boundsRadius));
// the initial starting position of the manipulator (in front of the camera)
const auto initialPositionWorld = m_linearManipulator->GetLocalPosition();
const auto initialPositionWorld = linearManipulator->GetLocalPosition();
// where the manipulator should end up (in front and to the left of the camera)
const auto finalPositionWorld = AZ::Vector3(-10.0f, 50.0f, 0.0f);
// perspective scale factor for manipulator distance to camera
@@ -66,21 +69,18 @@ namespace UnitTest
// adjusted final world position taking into account the manipulator position relative to the camera
const auto finalPositionWorldAdjusted = finalPositionWorld - (vectorToInitialPositionWorld * scaledRadiusBound);
// calculate the position in screen space of the initial position of the manipulator
const auto initialPositionScreen =
AzFramework::WorldToScreen(initialPositionWorld, m_cameraState);
const auto initialPositionScreen = AzFramework::WorldToScreen(initialPositionWorld, m_cameraState);
// calculate the position in screen space of the final position of the manipulator
const auto finalPositionScreen = AzFramework::WorldToScreen(finalPositionWorldAdjusted, m_cameraState);
// callback to update the manipulator's current position
m_linearManipulator->InstallMouseMoveCallback(
[this](const AzToolsFramework::LinearManipulator::Action& action)
{
auto pos = action.LocalPosition();
m_linearManipulator->SetLocalPosition(pos);
});
linearManipulator->InstallMouseMoveCallback(
[this, linearManipulator](const AzToolsFramework::LinearManipulator::Action& action)
{
linearManipulator->SetLocalPosition(action.LocalPosition());
});
m_actionDispatcher
->EnableSnapToGrid()
m_actionDispatcher->EnableSnapToGrid()
->GridSize(5.0f)
->CameraState(m_cameraState)
->MousePosition(initialPositionScreen)
@@ -89,7 +89,67 @@ namespace UnitTest
->MousePosition(finalPositionScreen)
->MouseLButtonUp()
->ExpectManipulatorNotBeingInteracted()
->ExpectTrue(m_linearManipulator->GetLocalPosition().IsClose(finalPositionWorld, 0.01f))
;
->ExpectTrue(linearManipulator->GetLocalPosition().IsClose(finalPositionWorld, 0.01f));
}
template<typename Manipulator>
void ValidateManipulatorSnappingBehavior(
AZStd::shared_ptr<Manipulator> manipulator, AzManipulatorTestFramework::ImmediateModeActionDispatcher* actionDispatcher,
const AzFramework::CameraState& cameraState)
{
manipulator->SetLocalOrientation(AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(180.0f, 0.0f, 135.0f)));
// the initial starting position of the manipulator (in front of the camera)
const auto initialPositionWorld = manipulator->GetLocalPosition() + AZ::Vector3::CreateAxisX(0.15f);
// where the manipulator should end up (unmoved)
const auto finalPositionWorld = manipulator->GetLocalPosition();
// where we should move the mouse to
const auto attemptPositionWorld = manipulator->GetLocalPosition() + AZ::Vector3::CreateAxisX(0.35f);
// calculate the position in screen space of the initial position of the manipulator
const auto initialPositionScreen = AzFramework::WorldToScreen(initialPositionWorld, cameraState);
// calculate the position in screen space of the final position of the manipulator
const auto attemptPositionScreen = AzFramework::WorldToScreen(attemptPositionWorld, cameraState);
// callback to update the manipulator's current position
manipulator->InstallMouseMoveCallback(
[manipulator](const typename Manipulator::Action& action)
{
manipulator->SetLocalPosition(action.LocalPosition());
});
actionDispatcher->EnableSnapToGrid()
->GridSize(1.0f)
->CameraState(cameraState)
->MousePosition(initialPositionScreen)
->MouseLButtonDown()
->ExpectManipulatorBeingInteracted()
->MousePosition(attemptPositionScreen)
->MouseLButtonUp()
->ExpectManipulatorNotBeingInteracted()
->ExpectThat(manipulator->GetLocalPosition(), IsCloseTolerance(finalPositionWorld, 0.01f));
}
TEST_F(GridSnappingFixture, MouseDownAndMoveLinearManipulatorDoesNotSnapWithMovementSmallerThanHalfGridSize)
{
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> linearManipulator(AzManipulatorTestFramework::CreateLinearManipulator(
m_viewportManipulatorInteraction->GetManipulatorManager().GetId(),
/*position=*/AZ::Vector3(0.0f, 10.0f, 0.0f),
/*radius=*/m_boundsRadius));
linearManipulator->SetAxis(AZ::Vector3::CreateAxisY());
ValidateManipulatorSnappingBehavior(linearManipulator, m_actionDispatcher.get(), m_cameraState);
}
TEST_F(GridSnappingFixture, MouseDownAndMovePlanarManipulatorDoesNotSnapWithMovementSmallerThanHalfGridSize)
{
AZStd::shared_ptr<AzToolsFramework::PlanarManipulator> planarManipulator(AzManipulatorTestFramework::CreatePlanarManipulator(
m_viewportManipulatorInteraction->GetManipulatorManager().GetId(),
/*position=*/AZ::Vector3(0.0f, 10.0f, 0.0f),
/*radius=*/m_boundsRadius));
planarManipulator->SetAxes(AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ());
ValidateManipulatorSnappingBehavior(planarManipulator, m_actionDispatcher.get(), m_cameraState);
}
} // namespace UnitTest
@@ -139,7 +139,7 @@ namespace AzNetworking
NetworkOutputSerializer networkSerializer(buffer.GetBuffer(), buffer.GetSize());
{
ISerializer& serializer = networkSerializer; // To get the default typeinfo parameters in ISerializer
ISerializer& networkISerializer = networkSerializer; // To get the default typeinfo parameters in ISerializer
// First, serialize out the header
if (!header.SerializePacketFlags(networkSerializer))
@@ -148,7 +148,7 @@ namespace AzNetworking
return false;
}
if (!serializer.Serialize(header, "Header"))
if (!networkISerializer.Serialize(header, "Header"))
{
AZLOG(NET_FragmentQueue, "Reconstructed fragmented packet failed header serialization");
return false;
@@ -433,6 +433,11 @@ namespace AzToolsFramework
return m_manipulatorSpaceWithLocalTransform.GetSpace();
}
const AZ::Vector3& Manipulators::GetNonUniformScale() const
{
return m_manipulatorSpaceWithLocalTransform.GetNonUniformScale();
}
void Manipulators::SetSpace(const AZ::Transform& worldFromLocal)
{
m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal);
@@ -192,8 +192,7 @@ namespace AzToolsFramework
/// for each vertex associated with the translation manipulator to use with offset calculations when updating.
template<typename Vertex>
void InitializeVertexLookup(
IndexedTranslationManipulator<Vertex>& translationManipulator,
const AZ::EntityId entityId, const AZ::Vector3& snapOffset)
IndexedTranslationManipulator<Vertex>& translationManipulator, const AZ::EntityId entityId)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -202,7 +201,7 @@ namespace AzToolsFramework
AZ::FixedVerticesRequestBus<Vertex>::Bind(fixedVertices, entityId);
translationManipulator.Process(
[snapOffset, fixedVertices]
[fixedVertices]
(typename IndexedTranslationManipulator<Vertex>::VertexLookup& vertexLookup)
{
Vertex vertex;
@@ -213,7 +212,7 @@ namespace AzToolsFramework
if (found)
{
vertexLookup.m_start = vertex + AZ::AdaptVertexIn<Vertex>(snapOffset);
vertexLookup.m_start = vertex;
vertexLookup.m_offset = Vertex::CreateZero();
}
});
@@ -250,10 +249,10 @@ namespace AzToolsFramework
// linear manipulator callbacks
m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseDownCallback(
[this](const LinearManipulator::Action& action)
[this]([[maybe_unused]] const LinearManipulator::Action& action)
{
BeginBatchMovement();
InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_positionSnapOffset);
InitializeVertexLookup(*m_translationManipulator, GetEntityId());
});
m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseMoveCallback(
@@ -264,17 +263,17 @@ namespace AzToolsFramework
});
m_translationManipulator->m_manipulator.InstallLinearManipulatorMouseUpCallback(
[this](const LinearManipulator::Action& /*action*/)
[this]([[maybe_unused]] const LinearManipulator::Action& action)
{
EndBatchMovement();
});
// planar manipulator callbacks
m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseDownCallback(
[this](const PlanarManipulator::Action& action)
[this]([[maybe_unused]] const PlanarManipulator::Action& action)
{
BeginBatchMovement();
InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_snapOffset);
InitializeVertexLookup(*m_translationManipulator, GetEntityId());
});
m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseMoveCallback(
@@ -285,17 +284,17 @@ namespace AzToolsFramework
});
m_translationManipulator->m_manipulator.InstallPlanarManipulatorMouseUpCallback(
[this](const PlanarManipulator::Action& /*action*/)
[this]([[maybe_unused]] const PlanarManipulator::Action& action)
{
EndBatchMovement();
});
// surface manipulator callbacks
m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseDownCallback(
[this](const SurfaceManipulator::Action& action)
[this]([[maybe_unused]] const SurfaceManipulator::Action& action)
{
BeginBatchMovement();
InitializeVertexLookup(*m_translationManipulator, GetEntityId(), action.m_start.m_snapOffset);
InitializeVertexLookup(*m_translationManipulator, GetEntityId());
});
m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseMoveCallback(
@@ -306,7 +305,7 @@ namespace AzToolsFramework
});
m_translationManipulator->m_manipulator.InstallSurfaceManipulatorMouseUpCallback(
[this](const SurfaceManipulator::Action& /*action*/)
[this]([[maybe_unused]] const SurfaceManipulator::Action& action)
{
EndBatchMovement();
});
@@ -893,7 +892,7 @@ namespace AzToolsFramework
{
BeginBatchMovement();
InitializeVertexLookup(*m_translationManipulator, GetEntityId(), AZ::Vector3::CreateZero());
InitializeVertexLookup(*m_translationManipulator, GetEntityId());
// note: AdaptVertexIn/Out is to ensure we clamp the vertex local Z position to 0 if
// dealing with Vector2s when setting the position of the manipulator.
const AZ::Vector3 localOffset =
@@ -23,8 +23,8 @@ namespace AzToolsFramework
{
LinearManipulator::Starter CalculateLinearManipulationDataStart(
const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
const float intersectionDistance, const AzFramework::CameraState& cameraState)
const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance,
const AzFramework::CameraState& cameraState)
{
const ManipulatorInteraction manipulatorInteraction =
BuildManipulatorInteraction(
@@ -50,28 +50,9 @@ namespace AzToolsFramework
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection,
localIntersectionPoint, startTransition.m_localNormal, start.m_localHitPosition);
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
// calculate position amount to snap, to align with grid
const AZ::Vector3 positionSnapOffset = snapping && !gridSnapAction.m_localSnapping
? CalculateSnappedOffset(localTransform.GetTranslation(), axis, gridSize * scaleRecip)
: AZ::Vector3::CreateZero();
const AZ::Vector3 localScale = AZ::Vector3(localTransform.GetUniformScale());
const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform);
// calculate scale amount to snap, to align to round scale value
const AZ::Vector3 scaleSnapOffset = snapping && !gridSnapAction.m_localSnapping
? localRotation.GetInverseFull().TransformVector(CalculateSnappedOffset(
localRotation.TransformVector(localScale), axis, gridSize * scaleRecip))
: AZ::Vector3::CreateZero();
start.m_screenPosition = interaction.m_mousePick.m_screenCoordinates;
start.m_positionSnapOffset = positionSnapOffset;
start.m_scaleSnapOffset = scaleSnapOffset;
start.m_localPosition = localTransform.GetTranslation() + positionSnapOffset;
start.m_localScale = localScale + scaleSnapOffset;
start.m_localPosition = localTransform.GetTranslation();
start.m_localScale = AZ::Vector3(localTransform.GetUniformScale());;
start.m_localAxis = axis;
// sign to determine which side of the linear axis we pressed
// (useful to know when the visual axis flips to face the camera)
@@ -87,7 +68,7 @@ namespace AzToolsFramework
LinearManipulator::Action CalculateLinearManipulationDataAction(
const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter,
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction)
const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction)
{
const ManipulatorInteraction manipulatorInteraction =
BuildManipulatorInteraction(
@@ -108,31 +89,34 @@ namespace AzToolsFramework
GetCameraState(interaction.m_interactionId.m_viewportId));
const AZ::Vector3 axis = TransformDirectionNoScaling(localTransform, fixed.m_axis);
// The local positions have been transformed to the reference frame of the object being manipulated. But they appear in the world
// with non-uniform scale applied, and the object being manipulated will want to work with unscaled deltas, so we need to divide by
// the non-uniform scale here.
// the local positions have been transformed to the reference frame of the object being manipulated, but they appear in the world
// with non-uniform scale applied, the object being manipulated will want to work with unscaled deltas, so we need to divide by
// the non-uniform scale here
const AZ::Vector3 hitDelta = (localHitPosition - start.m_localHitPosition) / nonUniformScale;
const AZ::Vector3 unsnappedOffset = axis * axis.Dot(hitDelta);
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal * axis.Dot(manipulatorInteraction.m_nonUniformScaleReciprocal);
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
const float scaleRecip =
manipulatorInteraction.m_scaleReciprocal * fixed.m_axis.Dot(manipulatorInteraction.m_nonUniformScaleReciprocal);
const float gridSize = gridSnapParams.m_gridSize;
const bool snapping = gridSnapParams.m_gridSnap;
LinearManipulator::Action action;
action.m_fixed = fixed;
action.m_start = start;
action.m_current.m_localPositionOffset = snapping
? unsnappedOffset + CalculateSnappedOffset(unsnappedOffset, axis, gridSize * scaleRecip)
? CalculateSnappedAmount(unsnappedOffset, axis, gridSize * scaleRecip)
: unsnappedOffset;
action.m_current.m_screenPosition = interaction.m_mousePick.m_screenCoordinates;
action.m_viewportId = interaction.m_interactionId.m_viewportId;
const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform);
const AZ::Vector3 scaledUnsnappedOffset = unsnappedOffset * startTransition.m_screenToWorldScale * NonUniformScaleReciprocal(nonUniformScale);
const AZ::Vector3 scaledUnsnappedOffset =
unsnappedOffset * startTransition.m_screenToWorldScale * NonUniformScaleReciprocal(nonUniformScale);
// how much to adjust the scale based on movement
const AZ::Quaternion invLocalRotation = localRotation.GetInverseFull();
action.m_current.m_localScaleOffset = snapping
? invLocalRotation.TransformVector((scaledUnsnappedOffset + CalculateSnappedOffset(scaledUnsnappedOffset, axis, gridSize * scaleRecip)))
? invLocalRotation.TransformVector(CalculateSnappedAmount(scaledUnsnappedOffset, axis, gridSize * scaleRecip))
: invLocalRotation.TransformVector(scaledUnsnappedOffset);
// record what modifier keys are held during this action
@@ -171,19 +155,18 @@ namespace AzToolsFramework
const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
m_starter = CalculateLinearManipulationDataStart(
m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction, rayIntersectionDistance,
m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, rayIntersectionDistance,
GetCameraState(interaction.m_interactionId.m_viewportId));
if (m_onLeftMouseDownCallback)
{
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
m_onLeftMouseDownCallback(CalculateLinearManipulationDataAction(
m_fixed, m_starter, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
m_fixed, m_starter, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), gridSnapParams, interaction));
}
}
@@ -195,8 +178,8 @@ namespace AzToolsFramework
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
m_onMouseMoveCallback(CalculateLinearManipulationDataAction(
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams,
interaction));
}
}
@@ -208,8 +191,7 @@ namespace AzToolsFramework
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
m_onLeftMouseUpCallback(CalculateLinearManipulationDataAction(
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams, interaction));
}
}
@@ -232,8 +214,8 @@ namespace AzToolsFramework
GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId);
const auto action = CalculateLinearManipulationDataAction(
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction);
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(), gridSnapParams,
mouseInteraction);
// display the exact hit (ray intersection) of the mouse pick on the manipulator
DrawTransformAxes(
@@ -20,7 +20,7 @@
namespace AzToolsFramework
{
struct GridSnapAction;
struct GridSnapParameters;
/// LinearManipulator serves as a visual tool for users to modify values
/// in one dimension on an axis defined in 3D space.
@@ -68,8 +68,6 @@ namespace AzToolsFramework
AZ::Vector3 m_localScale; ///< The current scale of the manipulator in local space.
AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens.
AZ::Vector3 m_localAxis; ///< The axis in the local space of the manipulator itself.
AZ::Vector3 m_positionSnapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid.
AZ::Vector3 m_scaleSnapOffset; ///< The snap offset amount to ensure manipulator is aligned to round scale increments.
float m_sign; ///< Used to determine which side of the axis we clicked on in case it's flipped to face the camera.
AzFramework::ScreenPoint m_screenPosition; ///< The initial position in screen space of the manipulator.
};
@@ -91,7 +89,7 @@ namespace AzToolsFramework
ViewportInteraction::KeyboardModifiers m_modifiers;
int m_viewportId; ///< The id of the viewport this manipulator is being used in.
AZ::Vector3 LocalScale() const { return m_start.m_localScale + m_current.m_localScaleOffset; }
AZ::Vector3 LocalScaleOffset() const { return m_start.m_scaleSnapOffset + m_current.m_localScaleOffset; }
AZ::Vector3 LocalScaleOffset() const { return m_current.m_localScaleOffset; }
AZ::Vector3 LocalPosition() const { return m_start.m_localPosition + m_current.m_localPositionOffset; }
AZ::Vector3 LocalPositionOffset() const { return m_current.m_localPositionOffset; }
AZ::Vector2 ScreenOffset() const
@@ -162,11 +160,11 @@ namespace AzToolsFramework
LinearManipulator::Starter CalculateLinearManipulationDataStart(
const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
float intersectionDistance, const AzFramework::CameraState& cameraState);
const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance,
const AzFramework::CameraState& cameraState);
LinearManipulator::Action CalculateLinearManipulationDataAction(
const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter,
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction);
const GridSnapParameters& gridSnapParams, const ViewportInteraction::MouseInteraction& interaction);
} // namespace AzToolsFramework
@@ -42,12 +42,6 @@ namespace AzToolsFramework
{
}
GridSnapAction::GridSnapAction(const GridSnapParameters& gridSnapParameters, const bool localSnapping)
: m_gridSnapParams(gridSnapParameters)
, m_localSnapping(localSnapping)
{
}
ManipulatorInteraction BuildManipulatorInteraction(
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection)
@@ -57,19 +51,39 @@ namespace AzToolsFramework
return {localFromWorldUniform.TransformPoint(worldRayOrigin),
TransformDirectionNoScaling(localFromWorldUniform, worldRayDirection),
ScaleReciprocal(worldFromLocalUniform),
NonUniformScaleReciprocal(nonUniformScale)};
NonUniformScaleReciprocal(nonUniformScale),
ScaleReciprocal(worldFromLocalUniform)};
}
AZ::Vector3 CalculateSnappedOffset(
const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size)
struct SnapAdjustment
{
float m_existingSnapDistance; //!< How far to snap up or down to align to the grid.
float m_nextSnapDistance; //!< The snap increment (will return full signed value (grid size) when distance
//!< moved is greater than half of the grid size in either direction).
};
static SnapAdjustment CalculateSnapDistance(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size)
{
// calculate total distance along axis
const float axisDistance = axis.Dot(unsnappedPosition);
// round to nearest step size
const float snappedAxisDistance = floorf((axisDistance / size) + 0.5f) * size;
return { axisDistance, snappedAxisDistance };
}
AZ::Vector3 CalculateSnappedOffset(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size)
{
const auto snapAdjustment = CalculateSnapDistance(unsnappedPosition, axis, size);
// return offset along axis to snap to step size
return axis * (snappedAxisDistance - axisDistance);
return axis * (snapAdjustment.m_nextSnapDistance - snapAdjustment.m_existingSnapDistance);
}
AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, const float size)
{
const auto snapAdjustment = CalculateSnapDistance(unsnappedPosition, axis, size);
// return offset along axis to snap to step size
return axis * snapAdjustment.m_nextSnapDistance;
}
AZ::Vector3 CalculateSnappedTerrainPosition(
@@ -31,24 +31,15 @@ namespace AzToolsFramework
float m_gridSize;
};
/// Structure to encapsulate the current grid snapping state.
struct GridSnapAction
{
GridSnapAction(const GridSnapParameters& gridSnapParameters, bool localSnapping);
GridSnapParameters m_gridSnapParams;
bool m_localSnapping;
};
/// Structure to hold transformed incoming viewport interaction from world space to manipulator space.
struct ManipulatorInteraction
{
AZ::Vector3 m_localRayOrigin; ///< The ray origin (start) in the reference from of the manipulator.
AZ::Vector3 m_localRayDirection; ///< The ray direction in the reference from of the manipulator.
float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the
///< ray from world space to local space.
AZ::Vector3 m_nonUniformScaleReciprocal; ///< Handles inverting any non-uniform scale which was applied
///< separately from the transform.
float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the
///< ray from world space to local space.
};
/// Build a ManipulatorInteraction structure from the incoming viewport interaction.
@@ -56,11 +47,16 @@ namespace AzToolsFramework
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection);
/// Calculate the offset along an axis to adjust a position
/// to stay snapped to a given grid size.
/// Calculate the offset along an axis to adjust a position to stay snapped to a given grid size.
/// @note This is snap up or down to the nearest grid segment (e.g. 0.2 snaps to 0.0 -> delta 0.2,
/// 0.7 snaps to 1.0 -> delta 0.3).
AZ::Vector3 CalculateSnappedOffset(
const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size);
/// Return the amount to snap from the starting position given the current grid size.
/// @note A movement of more than half size (in either direction) will cause a snap by size.
AZ::Vector3 CalculateSnappedAmount(const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float size);
/// For a given point on the terrain, calculate the closest xy position snapped to the grid
/// (z position is aligned to terrain height, not snapped to z grid)
AZ::Vector3 CalculateSnappedTerrainPosition(
@@ -59,17 +59,16 @@ namespace AzToolsFramework
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const ViewportInteraction::MouseInteraction& interaction,
const AZStd::vector<LinearManipulator::Fixed>& fixedAxes,
const AZStd::vector<LinearManipulator::Starter>& starterStates, const GridSnapAction& gridSnapAction)
const AZStd::vector<LinearManipulator::Starter>& starterStates, const GridSnapParameters& gridSnapParams)
{
MultiLinearManipulator::Action action;
action.m_viewportId = interaction.m_interactionId.m_viewportId;
// build up action state for each axis
for (size_t fixedIndex = 0; fixedIndex < fixedAxes.size(); ++fixedIndex)
{
action.m_actions.push_back(
CalculateLinearManipulationDataAction(
fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, nonUniformScale, localTransform,
gridSnapAction, interaction));
action.m_actions.push_back(CalculateLinearManipulationDataAction(
fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, nonUniformScale, localTransform, gridSnapParams,
interaction));
}
return action;
@@ -79,8 +78,6 @@ namespace AzToolsFramework
const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
const AzFramework::CameraState cameraState = GetCameraState(interaction.m_interactionId.m_viewportId);
// build up initial start state for each axis
@@ -88,20 +85,19 @@ namespace AzToolsFramework
{
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
const auto linearStart = CalculateLinearManipulationDataStart(
fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction,
rayIntersectionDistance, cameraState);
fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, rayIntersectionDistance,
cameraState);
m_starters.push_back(linearStart);
}
if (m_onLeftMouseDownCallback)
{
const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
// pass action containing all linear actions for each axis to handler
m_onLeftMouseDownCallback(BuildMultiLinearManipulatorAction(
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
interaction, m_fixedAxes, m_starters, gridSnapAction));
interaction, m_fixedAxes, m_starters, gridSnapParams));
}
}
@@ -111,11 +107,9 @@ namespace AzToolsFramework
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt());
m_onMouseMoveCallback(BuildMultiLinearManipulatorAction(
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
interaction, m_fixedAxes, m_starters, gridSnapAction));
interaction, m_fixedAxes, m_starters, gridSnapParams));
}
}
@@ -125,11 +119,9 @@ namespace AzToolsFramework
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt());
m_onLeftMouseUpCallback(BuildMultiLinearManipulatorAction(
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
interaction, m_fixedAxes, m_starters, gridSnapAction));
interaction, m_fixedAxes, m_starters, gridSnapParams));
m_starters.clear();
}
@@ -20,8 +20,6 @@
namespace AzToolsFramework
{
struct GridSnapAction;
//! MultiLinearManipulator serves as a visual tool for users to modify values
//! in one or more dimensions on axes defined in 3D space.
class MultiLinearManipulator
@@ -22,8 +22,7 @@
namespace AzToolsFramework
{
PlanarManipulator::StartInternal PlanarManipulator::CalculateManipulationDataStart(
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance)
{
const ManipulatorInteraction manipulatorInteraction =
@@ -31,8 +30,6 @@ namespace AzToolsFramework
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
const AZ::Vector3 normal = TransformDirectionNoScaling(localTransform, fixed.m_normal);
const AZ::Vector3 axis1 = TransformDirectionNoScaling(localTransform, fixed.m_axis1);
const AZ::Vector3 axis2 = TransformDirectionNoScaling(localTransform, fixed.m_axis2);
// initial intersect point
const AZ::Vector3 localIntersectionPoint =
@@ -43,25 +40,14 @@ namespace AzToolsFramework
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection,
localIntersectionPoint, normal, startInternal.m_localHitPosition);
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
// calculate amount to snap to align with grid
const AZ::Vector3 snapOffset = snapping && !gridSnapAction.m_localSnapping
? CalculateSnappedOffset(localTransform.GetTranslation(), axis1, gridSize * scaleRecip) +
CalculateSnappedOffset(localTransform.GetTranslation(), axis2, gridSize * scaleRecip)
: AZ::Vector3::CreateZero();
startInternal.m_snapOffset = snapOffset;
startInternal.m_localPosition = localTransform.GetTranslation() + snapOffset;
startInternal.m_localPosition = localTransform.GetTranslation();
return startInternal;
}
PlanarManipulator::Action PlanarManipulator::CalculateManipulationDataAction(
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams,
const ViewportInteraction::MouseInteraction& interaction)
{
const ManipulatorInteraction manipulatorInteraction =
@@ -88,20 +74,18 @@ namespace AzToolsFramework
const AZ::Vector3 hitDelta = (localHitPosition - startInternal.m_localHitPosition) / nonUniformScale;
const AZ::Vector3 unsnappedOffset = axis1.Dot(hitDelta) * axis1 + axis2.Dot(hitDelta) * axis2;
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
const AZ::Vector3 nonUniformScaleRecip = manipulatorInteraction.m_nonUniformScaleReciprocal;
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
const float gridSize = gridSnapParams.m_gridSize;
const bool snapping = gridSnapParams.m_gridSnap;
Action action;
action.m_fixed = fixed;
action.m_start.m_localPosition = startInternal.m_localPosition;
action.m_start.m_snapOffset = startInternal.m_snapOffset;
action.m_start.m_localHitPosition = startInternal.m_localHitPosition;
action.m_current.m_localOffset = snapping
? unsnappedOffset +
CalculateSnappedOffset(unsnappedOffset, axis1, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis1)) +
CalculateSnappedOffset(unsnappedOffset, axis2, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis2))
? CalculateSnappedAmount(unsnappedOffset, axis1, gridSize * scaleRecip * nonUniformScaleRecip.Dot(fixed.m_axis1)) +
CalculateSnappedAmount(unsnappedOffset, axis2, gridSize * scaleRecip * nonUniformScaleRecip.Dot(fixed.m_axis2))
: unsnappedOffset;
// record what modifier keys are held during this action
@@ -141,18 +125,17 @@ namespace AzToolsFramework
{
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
m_startInternal = CalculateManipulationDataStart(
m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()),
interaction, rayIntersectionDistance);
if (m_onLeftMouseDownCallback)
{
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
m_onLeftMouseDownCallback(CalculateManipulationDataAction(
m_fixed, m_startInternal, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
gridSnapParams, interaction));
}
}
@@ -164,8 +147,7 @@ namespace AzToolsFramework
m_onMouseMoveCallback(CalculateManipulationDataAction(
m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(),
TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
TransformNormalizedScale(GetLocalTransform()), gridSnapParams, interaction));
}
}
@@ -177,8 +159,7 @@ namespace AzToolsFramework
m_onLeftMouseUpCallback(CalculateManipulationDataAction(
m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(),
TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
TransformNormalizedScale(GetLocalTransform()), gridSnapParams, interaction));
}
}
@@ -195,8 +176,7 @@ namespace AzToolsFramework
const GridSnapParameters gridSnapParams = GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId);
const auto action = CalculateManipulationDataAction(
m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(),
TransformNormalizedScale(GetLocalTransform()),
GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction);
TransformNormalizedScale(GetLocalTransform()), gridSnapParams, mouseInteraction);
// display the exact hit (ray intersection) of the mouse pick on the manipulator
DrawTransformAxes(
@@ -21,7 +21,7 @@
namespace AzToolsFramework
{
class ManipulatorView;
struct GridSnapAction;
struct GridSnapParameters;
/// PlanarManipulator serves as a visual tool for users to modify values
/// in two dimension in a plane defined two non-collinear axes in 3D space.
@@ -58,7 +58,6 @@ namespace AzToolsFramework
{
AZ::Vector3 m_localPosition; ///< The current position of the manipulator in local space.
AZ::Vector3 m_localHitPosition; ///< The intersection point in local space between the ray and the manipulator when the mouse down event happens.
AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid.
};
/// The state of the manipulator during an interaction.
@@ -120,7 +119,6 @@ namespace AzToolsFramework
{
AZ::Vector3 m_localPosition; ///< The starting position of the manipulator in local space.
AZ::Vector3 m_localHitPosition; ///< The intersection point in world space between the ray and the manipulator when the mouse down event happens.
AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid.
};
Fixed m_fixed;
@@ -134,12 +132,11 @@ namespace AzToolsFramework
static StartInternal CalculateManipulationDataStart(
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance);
const AZ::Transform& localTransform, const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance);
static Action CalculateManipulationDataAction(
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction);
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform, const GridSnapParameters& gridSnapParams,
const ViewportInteraction::MouseInteraction& interaction);
};
} // namespace AzToolsFramework
@@ -174,6 +174,8 @@ namespace AzToolsFramework
static EntityAlias GenerateEntityAlias();
AliasPath GetAbsoluteInstanceAliasPath() const;
static InstanceAlias GenerateInstanceAlias();
protected:
/**
* Gets the entities owned by this instance
@@ -190,8 +192,6 @@ namespace AzToolsFramework
bool RegisterEntity(const AZ::EntityId& entityId, const EntityAlias& entityAlias);
AZStd::unique_ptr<AZ::Entity> DetachEntity(const EntityAlias& entityAlias);
static InstanceAlias GenerateInstanceAlias();
// Provide access to private data members in the serializer
friend class JsonInstanceSerializer;
friend class InstanceEntityIdMapper;
@@ -152,6 +152,30 @@ namespace AzToolsFramework
Instance::EntityList newEntities;
if (PrefabDomUtils::LoadInstanceFromPrefabDom(*instanceToUpdate, newEntities, currentTemplate.GetPrefabDom()))
{
// If a link was created for a nested instance before the changes were propagated,
// then we associate it correctly here
instanceToUpdate->GetNestedInstances([&](AZStd::unique_ptr<Instance>& nestedInstance) {
if (nestedInstance->GetLinkId() != InvalidLinkId)
{
return;
}
for (auto linkId : currentTemplate.GetLinks())
{
LinkReference nestedLink = m_prefabSystemComponentInterface->FindLink(linkId);
if (!nestedLink.has_value())
{
continue;
}
if (nestedLink->get().GetInstanceName() == nestedInstance->GetInstanceAlias())
{
nestedInstance->SetLinkId(linkId);
break;
}
}
});
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
&AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded, newEntities);
}
@@ -899,16 +899,29 @@ namespace AzToolsFramework
if (!EntitiesBelongToSameInstance(entityIds))
{
return AZ::Failure(AZStd::string("Cannot duplicate multiple "
"entities belonging to different instances with one operation."));
return AZ::Failure(AZStd::string("Cannot duplicate multiple entities belonging to different instances with one operation."
"Change your selection to contain entities in the same instance."));
}
// We've already verified the entities are all owned by the same instance,
// so we can just retrieve our instance from the first entity in the list.
InstanceOptionalReference commonEntityOwningInstance = GetOwnerInstanceByEntityId(entityIds[0]);
AZ_Assert(
commonEntityOwningInstance.has_value(),
"Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided");
AZ::EntityId firstEntityIdToDuplicate = entityIds[0];
InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDuplicate);
if (!commonOwningInstance.has_value())
{
return AZ::Failure(AZStd::string("Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided."));
}
// If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you
// cannot duplicate an instance from itself.
if (commonOwningInstance->get().GetContainerEntityId() == firstEntityIdToDuplicate)
{
commonOwningInstance = commonOwningInstance->get().GetParentInstance();
}
if (!commonOwningInstance.has_value())
{
return AZ::Failure(AZStd::string("Failed to duplicate : Couldn't get a valid owning instance for the common root entity of the entities provided."));
}
// This will cull out any entities that have ancestors in the list, since we will end up duplicating
// the full nested hierarchy with what is returned from RetrieveAndSortPrefabEntitiesAndInstances
@@ -921,105 +934,63 @@ namespace AzToolsFramework
{
AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "DuplicateEntitiesInInstance::UndoCaptureAndDuplicateEntities");
// Take a snapshot of the instance DOM before we manipulate it
Prefab::PrefabDom instanceDomBefore;
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, commonEntityOwningInstance->get());
AZStd::vector<AZ::Entity*> entities;
AZStd::vector<Instance*> instances;
// Gather all entities/instances in the hierarchy, but don't detach them because we are duplicating not deleting.
EntityList inputEntityList = EntityIdSetToEntityList(duplicationSet);
bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonEntityOwningInstance->get(), entities, instances);
bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances);
if (!success)
{
return AZ::Failure(AZStd::string("Failed to retrieve entities and instances from the given list of entity ids for duplication"));
}
// Make a copy of our before instance DOM where we will add our duplicated entities
Prefab::PrefabDom instanceDomAfter;
// Take a snapshot of the instance DOM before we manipulate it
PrefabDom instanceDomBefore;
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, commonOwningInstance->get());
// Make a copy of our before instance DOM where we will add our duplicated entities and/or instances
PrefabDom instanceDomAfter;
instanceDomAfter.CopyFrom(instanceDomBefore, instanceDomAfter.GetAllocator());
AZStd::unordered_map<EntityAlias, EntityAlias> oldAliasToNewAliasMap;
AZStd::unordered_map<EntityAlias, QString> aliasToEntityDomMap;
EntityIdList duplicatedEntityAndInstanceIds;
for (AZ::Entity* entity : entities)
{
EntityAliasOptionalReference oldAliasRef = commonEntityOwningInstance->get().GetEntityAlias(entity->GetId());
AZ_Assert(oldAliasRef.has_value(), "No alias found for Entity in the DOM");
EntityAlias oldAlias = oldAliasRef.value();
// Duplicate any nested entities and instances as requested
AZStd::unordered_map<InstanceAlias, Instance*> newInstanceAliasToOldInstanceMap;
DuplicateNestedEntitiesInInstance(commonOwningInstance->get(),
entities, instanceDomAfter, duplicatedEntityAndInstanceIds);
DuplicateNestedInstancesInInstance(commonOwningInstance->get(),
instances, instanceDomAfter, duplicatedEntityAndInstanceIds,
newInstanceAliasToOldInstanceMap);
// Give this the outer allocator so that the memory reference will be valid when
// it gets used for AddMember
Prefab::PrefabDom entityDomBefore(&instanceDomAfter.GetAllocator());
m_instanceToTemplateInterface->GenerateDomForEntity(entityDomBefore, *entity);
// Keep track of the old alias <-> new alias mapping for this duplicated entity
// so we can fixup references later
EntityAlias newEntityAlias = Instance::GenerateEntityAlias();
oldAliasToNewAliasMap.insert(AZStd::make_pair(oldAlias, newEntityAlias));
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
entityDomBefore.Accept(writer);
// Store our duplicated Entity DOM with its new alias as a string
// so that we can fixup entity alias references before adding it
// to the Entities member of our instance DOM
QString entityDomString(buffer.GetString());
aliasToEntityDomMap.insert(AZStd::make_pair(newEntityAlias, entityDomString));
}
auto entitiesIter = instanceDomAfter.FindMember(PrefabDomUtils::EntitiesName);
AZ_Assert(entitiesIter != instanceDomAfter.MemberEnd(), "Instance DOM missing the Entities member.");
// Now that all the duplicated Entity DOMs have been created, we need to iterate
// through them and replace any previous EntityAlias references with the new ones.
// These are more than just parent entity references for nested entities, this will
// also cover any EntityId references that were made in the components between them.
for (auto aliasEntityPair : aliasToEntityDomMap)
{
EntityAlias newEntityAlias = aliasEntityPair.first;
QString newEntityDomString = aliasEntityPair.second;
// Replace all of the old alias references with the new ones
// We bookend the aliases with \" and also with a / as an extra precaution to prevent
// inadvertently replacing a matching string vs. where an actual EntityId is expected
// This will cover both cases where an alias could be used in a normal entity vs. an instance
for (auto aliasMapIter : oldAliasToNewAliasMap)
{
ReplaceOldAliases(newEntityDomString, aliasMapIter.first, aliasMapIter.second);
}
// Create the new Entity DOM from parsing the JSON string
Prefab::PrefabDom entityDomAfter(&instanceDomAfter.GetAllocator());
entityDomAfter.Parse(newEntityDomString.toUtf8().constData());
// Add the new Entity DOM to the Entities member of the instance
rapidjson::Value aliasName(newEntityAlias.c_str(), newEntityAlias.length(), instanceDomAfter.GetAllocator());
entitiesIter->value.AddMember(AZStd::move(aliasName), entityDomAfter, instanceDomAfter.GetAllocator());
}
PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity duplication");
PrefabUndoInstance* command = aznew PrefabUndoInstance("Entity/Instance duplication");
command->SetParent(undoBatch.GetUndoBatch());
command->Capture(instanceDomBefore, instanceDomAfter, commonEntityOwningInstance->get().GetTemplateId());
command->RunRedo();
command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId());
command->Redo();
EntityIdList duplicatedEntityIds;
for (auto aliasMapIter : oldAliasToNewAliasMap)
// Create links for our duplicated instances (if any were duplicated)
for (auto [newInstanceAlias, oldInstance] : newInstanceAliasToOldInstanceMap)
{
EntityAlias newEntityAlias = aliasMapIter.second;
LinkId oldLinkId = oldInstance->GetLinkId();
auto linkRef = m_prefabSystemComponentInterface->FindLink(oldLinkId);
AZ_Assert(
linkRef.has_value(), "Unable to find link with id '%llu' during instance duplication.",
oldLinkId);
AliasPath absoluteEntityPath = commonEntityOwningInstance->get().GetAbsoluteInstanceAliasPath();
absoluteEntityPath.Append(newEntityAlias);
PrefabDomValueReference linkPatches = linkRef->get().GetLinkPatches();
AZ_Assert(
linkPatches.has_value(), "Link with id '%llu' is missing patches.",
oldLinkId);
AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteEntityPath);
duplicatedEntityIds.push_back(newEntityId);
PrefabDom linkPatchesCopy;
linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator());
m_prefabSystemComponentInterface->CreateLink(
commonOwningInstance->get().GetTemplateId(), oldInstance->GetTemplateId(), newInstanceAlias, linkPatchesCopy);
}
// Select the duplicated entities
auto selectionUndo = aznew SelectionCommand(duplicatedEntityIds, "Select Duplicated Entities");
// Select the duplicated entities/instances
auto selectionUndo = aznew SelectionCommand(duplicatedEntityAndInstanceIds, "Select Duplicated Entities/Instances");
selectionUndo->SetParent(undoBatch.GetUndoBatch());
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo);
}
@@ -1508,8 +1479,159 @@ namespace AzToolsFramework
return true;
}
void PrefabPublicHandler::DuplicateNestedEntitiesInInstance(Instance& commonOwningInstance,
const AZStd::vector<AZ::Entity*>& entities, PrefabDom& domToAddDuplicatedEntitiesUnder,
EntityIdList& duplicatedEntityIds)
{
if (entities.empty())
{
return;
}
AZStd::unordered_map<EntityAlias, EntityAlias> oldAliasToNewAliasMap;
AZStd::unordered_map<EntityAlias, QString> aliasToEntityDomMap;
for (AZ::Entity* entity : entities)
{
EntityAliasOptionalReference oldAliasRef = commonOwningInstance.GetEntityAlias(entity->GetId());
AZ_Assert(oldAliasRef.has_value(), "No alias found for Entity in the DOM");
EntityAlias oldAlias = oldAliasRef.value();
// Give this the outer allocator so that the memory reference will be valid when
// it gets used for AddMember
PrefabDom entityDomBefore(&domToAddDuplicatedEntitiesUnder.GetAllocator());
m_instanceToTemplateInterface->GenerateDomForEntity(entityDomBefore, *entity);
// Keep track of the old alias <-> new alias mapping for this duplicated entity
// so we can fixup references later
EntityAlias newEntityAlias = Instance::GenerateEntityAlias();
oldAliasToNewAliasMap.emplace(oldAlias, newEntityAlias);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
entityDomBefore.Accept(writer);
// Store our duplicated Entity DOM with its new alias as a string
// so that we can fixup entity alias references before adding it
// to the Entities member of our instance DOM
QString entityDomString(buffer.GetString());
aliasToEntityDomMap.emplace(newEntityAlias, entityDomString);
}
auto entitiesIter = domToAddDuplicatedEntitiesUnder.FindMember(PrefabDomUtils::EntitiesName);
AZ_Assert(entitiesIter != domToAddDuplicatedEntitiesUnder.MemberEnd(), "Instance DOM missing the Entities member.");
// Now that all the duplicated Entity DOMs have been created, we need to iterate
// through them and replace any previous EntityAlias references with the new ones.
// These are more than just parent entity references for nested entities, this will
// also cover any EntityId references that were made in the components between them.
for (auto [newEntityAlias, newEntityDomString] : aliasToEntityDomMap)
{
// Replace all of the old alias references with the new ones
for (auto [oldAlias, newAlias] : oldAliasToNewAliasMap)
{
ReplaceOldAliases(newEntityDomString, oldAlias, newAlias);
}
// Create the new Entity DOM from parsing the JSON string
PrefabDom entityDomAfter(&domToAddDuplicatedEntitiesUnder.GetAllocator());
entityDomAfter.Parse(newEntityDomString.toUtf8().constData());
// Add the new Entity DOM to the Entities member of the instance
rapidjson::Value aliasName(newEntityAlias.c_str(), newEntityAlias.length(), domToAddDuplicatedEntitiesUnder.GetAllocator());
entitiesIter->value.AddMember(AZStd::move(aliasName), entityDomAfter, domToAddDuplicatedEntitiesUnder.GetAllocator());
}
for (auto aliasMapIter : oldAliasToNewAliasMap)
{
EntityAlias newEntityAlias = aliasMapIter.second;
AliasPath absoluteEntityPath = commonOwningInstance.GetAbsoluteInstanceAliasPath();
absoluteEntityPath.Append(newEntityAlias);
AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteEntityPath);
duplicatedEntityIds.push_back(newEntityId);
}
}
void PrefabPublicHandler::DuplicateNestedInstancesInInstance(Instance& commonOwningInstance,
const AZStd::vector<Instance*>& instances, PrefabDom& domToAddDuplicatedInstancesUnder,
EntityIdList& duplicatedEntityIds, AZStd::unordered_map<InstanceAlias, Instance*>& newInstanceAliasToOldInstanceMap)
{
if (instances.empty())
{
return;
}
AZStd::unordered_map<InstanceAlias, InstanceAlias> oldInstanceAliasToNewInstanceAliasMap;
AZStd::unordered_map<InstanceAlias, QString> aliasToInstanceDomMap;
for (auto instance : instances)
{
PrefabDom nestedInstanceDomBefore;
m_instanceToTemplateInterface->GenerateDomForInstance(nestedInstanceDomBefore, *instance);
// Keep track of the old alias <-> new alias mapping for this duplicated instance
// so we can fixup references later
InstanceAlias oldAlias = instance->GetInstanceAlias();
InstanceAlias newInstanceAlias = Instance::GenerateInstanceAlias();
oldInstanceAliasToNewInstanceAliasMap.emplace(oldAlias, newInstanceAlias);
// Keep track of our new instance alias with the Instance it was duplicated from,
// so that after all instances are duplicated, we can go back and create links for them
newInstanceAliasToOldInstanceMap.emplace(newInstanceAlias, instance);
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
nestedInstanceDomBefore.Accept(writer);
// Store our duplicated Instance DOM with its new alias as a string
// so that we can fixup instance alias references before adding it
// to the Instances member of our instance DOM
QString instanceDomString(buffer.GetString());
aliasToInstanceDomMap.emplace(newInstanceAlias, instanceDomString);
}
auto instancesIter = domToAddDuplicatedInstancesUnder.FindMember(PrefabDomUtils::InstancesName);
AZ_Assert(instancesIter != domToAddDuplicatedInstancesUnder.MemberEnd(), "Instance DOM missing the Instances member.");
// Now that all the duplicated Instance DOMs have been created, we need to iterate
// through them and replace any previous InstanceAlias references with the new ones.
for (auto [newInstanceAlias, newInstanceDomString]: aliasToInstanceDomMap)
{
// Replace all of the old alias references with the new ones
for (auto [oldAlias, newAlias] : oldInstanceAliasToNewInstanceAliasMap)
{
ReplaceOldAliases(newInstanceDomString, oldAlias, newAlias);
}
// Create the new Instance DOM from parsing the JSON string
PrefabDom nestedInstanceDomAfter(&domToAddDuplicatedInstancesUnder.GetAllocator());
nestedInstanceDomAfter.Parse(newInstanceDomString.toUtf8().constData());
// Add the new Instance DOM to the Instances member of the instance
rapidjson::Value aliasName(newInstanceAlias.c_str(), newInstanceAlias.length(), domToAddDuplicatedInstancesUnder.GetAllocator());
instancesIter->value.AddMember(AZStd::move(aliasName), nestedInstanceDomAfter, domToAddDuplicatedInstancesUnder.GetAllocator());
}
for (auto aliasMapIter : oldInstanceAliasToNewInstanceAliasMap)
{
InstanceAlias newInstanceAlias = aliasMapIter.second;
AliasPath absoluteInstancePath = commonOwningInstance.GetAbsoluteInstanceAliasPath();
absoluteInstancePath.Append(newInstanceAlias);
AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteInstancePath);
duplicatedEntityIds.push_back(newEntityId);
}
}
void PrefabPublicHandler::ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias)
{
// Replace all of the old alias references with the new ones
// We bookend the aliases with \" and also with a / as an extra precaution to prevent
// inadvertently replacing a matching string vs. where an actual EntityId is expected
// This will cover both cases where an alias could be used in a normal entity vs. an instance
QString oldAliasQuotes = QString("\"%1\"").arg(oldAlias.data());
QString newAliasQuotes = QString("\"%1\"").arg(newAlias.data());
@@ -73,6 +73,33 @@ namespace AzToolsFramework
InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const;
bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const;
/**
* Duplicate a list of entities owned by a common owning instance by directly
* copying/modifying their entries in the instance DOM
*
* \param commonOwningInstance The common owning instance of all the entities being duplicated.
* \param entities The list of Entities that will be duplicated.
* \param domToAddDuplicatedEntitiesUnder The DOM of the common owning instance where the duplicated
* entity DOM values will be added to.
* \param duplicatedEntityIds A list of EntityIds corresponding to the entities that were duplicated.
*/
void DuplicateNestedEntitiesInInstance(Instance& commonOwningInstance,
const AZStd::vector<AZ::Entity*>& entities, PrefabDom& domToAddDuplicatedEntitiesUnder,
EntityIdList& duplicatedEntityIds);
/**
* Duplicate a list of instances owned by a common owning instance by directly
* copying/modifying their entries in the instance DOM
*
* \param commonOwningInstance The common owning instance of all the instances being duplicated.
* \param entities The list of Instances that will be duplicated.
* \param domToAddDuplicatedInstancesUnder The DOM of the common owning instance where the duplicated
* instance DOM values will be added to.
* \param duplicatedEntityIds A list of EntityIds corresponding to the instances that were duplicated.
*/
void DuplicateNestedInstancesInInstance(Instance& commonOwningInstance,
const AZStd::vector<Instance*>& instances, PrefabDom& domToAddDuplicatedInstancesUnder,
EntityIdList& duplicatedEntityIds, AZStd::unordered_map<InstanceAlias, Instance*>& newInstanceAliasToOldInstanceMap);
/**
* Applies the correct transform changes to the container entity based on the parent and child entities provided, and returns an appropriate patch.
@@ -37,13 +37,13 @@ namespace AzToolsFramework
axisLength, AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor,
AzFramework::ViewportColors::ZAxisColor);
auto mouseDownCallback = [this](const LinearManipulator::Action& action) {
auto mouseDownCallback = [this]([[maybe_unused]] const LinearManipulator::Action& action)
{
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(
nonUniformScale, m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
m_initialScale = nonUniformScale + action.m_start.m_scaleSnapOffset;
m_initialScale = nonUniformScale;
AZ::NonUniformScaleRequestBus::Event(
m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, m_initialScale);
@@ -51,29 +51,37 @@ namespace AzToolsFramework
m_manipulators->InstallAxisLeftMouseDownCallback(mouseDownCallback);
m_manipulators->InstallAxisMouseMoveCallback([this](const LinearManipulator::Action& action) {
const AZ::Vector3 scaleMultiplier =
(AZ::Vector3::CreateOne() + ((action.LocalScaleOffset() * action.m_start.m_sign) / m_initialScale));
m_manipulators->InstallAxisMouseMoveCallback(
[this](const LinearManipulator::Action& action)
{
const AZ::Vector3 scaleMultiplier =
(AZ::Vector3::CreateOne() + ((action.LocalScaleOffset() * action.m_start.m_sign) / m_initialScale));
AZ::NonUniformScaleRequestBus::Event(
m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale,
(scaleMultiplier * m_initialScale).GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale)));
});
AZ::NonUniformScaleRequestBus::Event(
m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale,
(scaleMultiplier * m_initialScale)
.GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale)));
});
m_manipulators->InstallUniformLeftMouseDownCallback(mouseDownCallback);
m_manipulators->InstallUniformMouseMoveCallback([this](const LinearManipulator::Action& action) {
const auto sumVectorElements = [](const AZ::Vector3& vec) { return vec.GetX() + vec.GetY() + vec.GetZ(); };
m_manipulators->InstallUniformMouseMoveCallback(
[this](const LinearManipulator::Action& action)
{
const auto sumVectorElements = [](const AZ::Vector3& vec)
{
return vec.GetX() + vec.GetY() + vec.GetZ();
};
const float minScaleMultiplier = AZ::MinTransformScale / m_initialScale.GetMinElement();
const float maxScaleMultiplier = AZ::MaxTransformScale / m_initialScale.GetMaxElement();
const float scaleMultiplier = AZ::GetClamp(
1.0f + sumVectorElements(action.m_start.m_sign * action.LocalScaleOffset() / m_initialScale), minScaleMultiplier,
maxScaleMultiplier);
const float minScaleMultiplier = AZ::MinTransformScale / m_initialScale.GetMinElement();
const float maxScaleMultiplier = AZ::MaxTransformScale / m_initialScale.GetMaxElement();
const float scaleMultiplier = AZ::GetClamp(
1.0f + sumVectorElements(action.m_start.m_sign * action.LocalScaleOffset() / m_initialScale), minScaleMultiplier,
maxScaleMultiplier);
AZ::NonUniformScaleRequestBus::Event(
m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, scaleMultiplier * m_initialScale);
});
AZ::NonUniformScaleRequestBus::Event(
m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, scaleMultiplier * m_initialScale);
});
}
NonUniformScaleComponentMode::~NonUniformScaleComponentMode()
@@ -423,15 +423,14 @@ namespace AzToolsFramework
}
}
static void InitializeTranslationLookup(
EntityIdManipulators& entityIdManipulators, const AZ::Vector3& snapOffset)
static void InitializeTranslationLookup(EntityIdManipulators& entityIdManipulators)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
for (auto& entityIdLookup : entityIdManipulators.m_lookups)
{
entityIdLookup.second.m_initial =
AZ::Transform::CreateTranslation(GetWorldTranslation(entityIdLookup.first) + snapOffset);
AZ::Transform::CreateTranslation(GetWorldTranslation(entityIdLookup.first));
}
}
@@ -820,7 +819,7 @@ namespace AzToolsFramework
// moving with ctrl - setting override
pivotOverrideFrame.m_translationOverride =
entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation();
InitializeTranslationLookup(entityIdManipulators, -action.LocalPositionOffset());
InitializeTranslationLookup(entityIdManipulators);
}
else
{
@@ -1277,12 +1276,12 @@ namespace AzToolsFramework
// linear
translationManipulators->InstallLinearManipulatorMouseDownCallback(
[this, manipulatorEntityIds](const LinearManipulator::Action& action) mutable
[this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) mutable
{
// important to sort entityIds based on hierarchy order when updating transforms
BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds);
InitializeTranslationLookup(m_entityIdManipulators, action.m_start.m_positionSnapOffset);
InitializeTranslationLookup(m_entityIdManipulators);
m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation();
m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(
@@ -1302,19 +1301,19 @@ namespace AzToolsFramework
});
translationManipulators->InstallLinearManipulatorMouseUpCallback(
[this](const LinearManipulator::Action& /*action*/) mutable
[this]([[maybe_unused]] const LinearManipulator::Action& action) mutable
{
EndRecordManipulatorCommand();
});
// planar
translationManipulators->InstallPlanarManipulatorMouseDownCallback(
[this, manipulatorEntityIds](const PlanarManipulator::Action& action)
[this, manipulatorEntityIds]([[maybe_unused]] const PlanarManipulator::Action& action)
{
// important to sort entityIds based on hierarchy order when updating transforms
BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds);
InitializeTranslationLookup(m_entityIdManipulators, action.m_start.m_snapOffset);
InitializeTranslationLookup(m_entityIdManipulators);
m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation();
m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(
@@ -1340,11 +1339,11 @@ namespace AzToolsFramework
// surface
translationManipulators->InstallSurfaceManipulatorMouseDownCallback(
[this, manipulatorEntityIds](const SurfaceManipulator::Action& action)
[this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action)
{
BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds);
InitializeTranslationLookup(m_entityIdManipulators, action.m_start.m_snapOffset);
InitializeTranslationLookup(m_entityIdManipulators);
m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation();
m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(
@@ -3326,26 +3325,16 @@ namespace AzToolsFramework
}
static void DrawManipulatorGrid(
AzFramework::DebugDisplayRequests& debugDisplay, const EntityIdManipulators& entityIdManipulators,
const float gridSize, const float localSnapping)
AzFramework::DebugDisplayRequests& debugDisplay, const EntityIdManipulators& entityIdManipulators, const float gridSize)
{
const AZ::Matrix3x3 orientation =
AZ::Matrix3x3::CreateFromTransform(entityIdManipulators.m_manipulators->GetLocalTransform());
const AZ::Vector3 unsnappedTranslation =
const AZ::Vector3 translation =
entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation();
// calculate the offset to snap by to align the manipulator to the grid
// note: only perform this if we are not snapping in local space
const AZ::Vector3 snappedOffset = !localSnapping
? CalculateSnappedOffset(unsnappedTranslation, orientation.GetBasisX(), gridSize) +
CalculateSnappedOffset(unsnappedTranslation, orientation.GetBasisY(), gridSize)
: AZ::Vector3::CreateZero();
const AZ::Vector3 snappedTranslation = unsnappedTranslation + snappedOffset;
DrawSnappingGrid(
debugDisplay, AZ::Transform::CreateFromMatrix3x3AndTranslation(orientation, snappedTranslation),
debugDisplay, AZ::Transform::CreateFromMatrix3x3AndTranslation(orientation, translation),
gridSize);
}
@@ -3484,7 +3473,7 @@ namespace AzToolsFramework
const GridSnapParameters gridSnapParams = GridSnapSettings(viewportInfo.m_viewportId);
if (gridSnapParams.m_gridSnap && m_entityIdManipulators.m_manipulators)
{
DrawManipulatorGrid(debugDisplay, m_entityIdManipulators, gridSnapParams.m_gridSize, modifiers.Alt());
DrawManipulatorGrid(debugDisplay, m_entityIdManipulators, gridSnapParams.m_gridSize);
}
}
}
+7 -7
View File
@@ -118,10 +118,10 @@ void CVarMenu::AddUniqueCVarsItem(QString displayName,
// Otherwise we could have just used the action's currently checked
// state and updated the CVar's value only
bool cVarOn = (cVar->GetFVal() == availableCVar.m_onValue);
bool checked = !cVarOn;
SetCVar(cVar, checked ? availableCVar.m_onValue : availableCVar.m_offValue);
action->setChecked(checked);
if (checked)
bool cVarChecked = !cVarOn;
SetCVar(cVar, cVarChecked ? availableCVar.m_onValue : availableCVar.m_offValue);
action->setChecked(cVarChecked);
if (cVarChecked)
{
// Set the rest of the CVars in the group to their off values
SetCVarsToOffValue(availableCVars, availableCVar);
@@ -132,9 +132,9 @@ void CVarMenu::AddUniqueCVarsItem(QString displayName,
// Initialize the action's checked state based on its associated CVar's current value
ICVar* cVar = gEnv->pConsole->GetCVar(availableCVar.m_cVarName.toUtf8().data());
bool checked = (cVar && cVar->GetFVal() == availableCVar.m_onValue);
action->setChecked(checked);
if (checked)
bool cVarChecked = (cVar && cVar->GetFVal() == availableCVar.m_onValue);
action->setChecked(cVarChecked);
if (cVarChecked)
{
// Set the rest of the CVars in the group to their off values
SetCVarsToOffValue(availableCVars, availableCVar);
+8
View File
@@ -2281,6 +2281,14 @@ int CCryEditApp::IdleProcessing(bool bBackgroundUpdate)
return 0;
}
// Ensure we don't get called re-entrantly
// This can occur when a nested Qt event loop fires (e.g. by way of a modal dialog calling exec)
if (m_idleProcessingRunning)
{
return 0;
}
QScopedValueRollback<bool> guard(m_idleProcessingRunning, true);
////////////////////////////////////////////////////////////////////////
// Call the update function of the engine
////////////////////////////////////////////////////////////////////////
+2
View File
@@ -335,6 +335,8 @@ private:
// If this flag is set, the next OnIdle() will update, even if the app is in the background, and then
// this flag will be reset.
bool m_bForceProcessIdle = false;
// This is set while IdleProcessing is running to prevent re-entrancy
bool m_idleProcessingRunning = false;
// Keep the editor alive, even if no focus is set
bool m_bKeepEditorActive = false;
// Currently creating a new level
@@ -2887,9 +2887,12 @@ void EditorViewportWidget::UpdateCameraFromViewportContext()
AZ::Matrix3x4 matrix;
matrix.SetBasisAndTranslation(cameraState.m_side, cameraState.m_forward, cameraState.m_up, cameraState.m_position);
auto m = AZMatrix3x4ToLYMatrix3x4(matrix);
m_updatingCameraPosition = true;
SetViewTM(m);
SetFOV(cameraState.m_fovOrZoom);
m_Camera.SetZRange(cameraState.m_nearClip, cameraState.m_farClip);
m_updatingCameraPosition = false;
}
void EditorViewportWidget::SetAsActiveViewport()
@@ -205,10 +205,10 @@ CTrackViewAnimNode::CTrackViewAnimNode(IAnimSequence* pSequence, IAnimNode* anim
for (int i = 0; i < nodeCount; ++i)
{
IAnimNode* node = pSequence->GetNode(i);
IAnimNode* pParentNode = node->GetParent();
IAnimNode* pNodeParentNode = node->GetParent();
// If our node is the parent, then the current node is a child of it
if (animNode == pParentNode)
if (animNode == pNodeParentNode)
{
CTrackViewAnimNodeFactory animNodeFactory;
CTrackViewAnimNode* pNewTVAnimNode = animNodeFactory.BuildAnimNode(pSequence, node, this);
@@ -68,12 +68,12 @@ CTrackViewTrack::CTrackViewTrack(IAnimTrack* pTrack, CTrackViewAnimNode* pTrackA
{
// Search for child tracks
const unsigned int subTrackCount = m_pAnimTrack->GetSubTrackCount();
for (unsigned int subTrackIndex = 0; subTrackIndex < subTrackCount; ++subTrackIndex)
for (unsigned int subTrackI = 0; subTrackI < subTrackCount; ++subTrackI)
{
IAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackIndex);
IAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackI);
CTrackViewTrackFactory trackFactory;
CTrackViewTrack* pNewTVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackIndex);
CTrackViewTrack* pNewTVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackI);
m_childNodes.push_back(std::unique_ptr<CTrackViewNode>(pNewTVTrack));
}
@@ -11,7 +11,7 @@
*/
#include <ProjectButtonWidget.h>
#include <AzQtComponents/Utilities/DesktopUtilities.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
@@ -81,18 +81,24 @@ namespace O3DE::ProjectManager
m_projectImageLabel = new LabelButton(this);
m_projectImageLabel->setFixedSize(s_projectImageWidth, s_projectImageHeight);
m_projectImageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); });
vLayout->addWidget(m_projectImageLabel);
m_projectImageLabel->setPixmap(
QPixmap(m_projectInfo.m_imagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding));
QMenu* newProjectMenu = new QMenu(this);
m_editProjectAction = newProjectMenu->addAction(tr("Edit Project Settings..."));
newProjectMenu->addSeparator();
m_copyProjectAction = newProjectMenu->addAction(tr("Duplicate"));
newProjectMenu->addSeparator();
m_removeProjectAction = newProjectMenu->addAction(tr("Remove from O3DE"));
m_deleteProjectAction = newProjectMenu->addAction(tr("Delete this Project"));
QMenu* menu = new QMenu(this);
menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); });
menu->addSeparator();
menu->addAction(tr("Open Project folder..."), this, [this]()
{
AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path);
});
menu->addSeparator();
menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo.m_path); });
menu->addSeparator();
menu->addAction(tr("Remove from O3DE"), this, [this]() { emit RemoveProject(m_projectInfo.m_path); });
menu->addAction(tr("Delete this Project"), this, [this]() { emit DeleteProject(m_projectInfo.m_path); });
QFrame* footer = new QFrame(this);
QHBoxLayout* hLayout = new QHBoxLayout();
@@ -104,17 +110,11 @@ namespace O3DE::ProjectManager
QPushButton* projectMenuButton = new QPushButton(this);
projectMenuButton->setObjectName("projectMenuButton");
projectMenuButton->setMenu(newProjectMenu);
projectMenuButton->setMenu(menu);
hLayout->addWidget(projectMenuButton);
}
vLayout->addWidget(footer);
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); });
connect(m_editProjectAction, &QAction::triggered, [this]() { emit EditProject(m_projectInfo.m_path); });
connect(m_copyProjectAction, &QAction::triggered, [this]() { emit CopyProject(m_projectInfo.m_path); });
connect(m_removeProjectAction, &QAction::triggered, [this]() { emit RemoveProject(m_projectInfo.m_path); });
connect(m_deleteProjectAction, &QAction::triggered, [this]() { emit DeleteProject(m_projectInfo.m_path); });
}
void ProjectButton::SetButtonEnabled(bool enabled)
@@ -71,9 +71,5 @@ namespace O3DE::ProjectManager
ProjectInfo m_projectInfo;
LabelButton* m_projectImageLabel;
QAction* m_editProjectAction;
QAction* m_copyProjectAction;
QAction* m_removeProjectAction;
QAction* m_deleteProjectAction;
};
} // namespace O3DE::ProjectManager
@@ -294,7 +294,8 @@ namespace O3DE::ProjectManager
RegisterThisEngine();
return result == 0 && !PyErr_Occurred();
} catch ([[maybe_unused]] const std::exception& e)
}
catch ([[maybe_unused]] const std::exception& e)
{
AZ_Warning("ProjectManagerWindow", false, "Py_Initialize() failed with %s", e.what());
return false;
@@ -320,25 +321,25 @@ namespace O3DE::ProjectManager
bool registrationResult = true; // already registered is considered successful
bool pythonResult = ExecuteWithLock(
[&]
{
// check current engine path against all other registered engines
// to see if we are already registered
auto allEngines = m_manifest.attr("get_engines")();
if (pybind11::isinstance<pybind11::list>(allEngines))
{
// check current engine path against all other registered engines
// to see if we are already registered
auto allEngines = m_manifest.attr("get_engines")();
if (pybind11::isinstance<pybind11::list>(allEngines))
for (auto engine : allEngines)
{
for (auto engine : allEngines)
AZ::IO::FixedMaxPath enginePath(Py_To_String(engine["path"]));
if (enginePath.Compare(m_enginePath) == 0)
{
AZ::IO::FixedMaxPath enginePath(Py_To_String(engine["path"]));
if (enginePath.Compare(m_enginePath) == 0)
{
return;
}
return;
}
}
}
auto result = m_register.attr("register")(m_enginePath.c_str());
registrationResult = (result.cast<int>() == 0);
});
auto result = m_register.attr("register")(m_enginePath.c_str());
registrationResult = (result.cast<int>() == 0);
});
bool finalResult = (registrationResult && pythonResult);
AZ_Assert(finalResult, "Registration of this engine failed!");
@@ -378,12 +379,12 @@ namespace O3DE::ProjectManager
auto o3deData = m_manifest.attr("load_o3de_manifest")();
if (pybind11::isinstance<pybind11::dict>(o3deData))
{
engineInfo.m_path = Py_To_String(enginePath);
engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]);
engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]);
engineInfo.m_path = Py_To_String(enginePath);
engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]);
engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]);
engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]);
engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]);
engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"third_party_path","");
engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]);
engineInfo.m_thirdPartyPath = Py_To_String(o3deData["default_third_party_folder"]);
}
auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath);
@@ -391,8 +392,8 @@ namespace O3DE::ProjectManager
{
try
{
engineInfo.m_version = Py_To_String_Optional(engineData,"O3DEVersion","0.0.0.0");
engineInfo.m_name = Py_To_String_Optional(engineData,"engine_name","O3DE");
engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0");
engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE");
}
catch ([[maybe_unused]] const std::exception& e)
{
@@ -416,44 +417,32 @@ namespace O3DE::ProjectManager
bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo)
{
bool result = ExecuteWithLock([&] {
pybind11::str enginePath = engineInfo.m_path.toStdString();
pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString();
pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString();
pybind11::str enginePath = engineInfo.m_path.toStdString();
pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString();
pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString();
pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString();
pybind11::str defaultThirdPartyFolder = engineInfo.m_thirdPartyPath.toStdString();
auto registrationResult = m_register.attr("register")(
enginePath, // engine_path
pybind11::none(), // project_path
enginePath, // engine_path
pybind11::none(), // project_path
pybind11::none(), // gem_path
pybind11::none(), // external_subdir_path
pybind11::none(), // template_path
pybind11::none(), // restricted_path
pybind11::none(), // repo_uri
pybind11::none(), // external_subdir_path
pybind11::none(), // template_path
pybind11::none(), // restricted_path
pybind11::none(), // repo_uri
pybind11::none(), // default_engines_folder
defaultProjectsFolder,
defaultGemsFolder,
defaultTemplatesFolder
defaultTemplatesFolder,
pybind11::none(), // default_restricted_folder
defaultThirdPartyFolder
);
if (registrationResult.cast<int>() != 0)
{
result = false;
}
auto manifest = m_manifest.attr("load_o3de_manifest")();
if (pybind11::isinstance<pybind11::dict>(manifest))
{
try
{
manifest["third_party_path"] = engineInfo.m_thirdPartyPath.toStdString();
m_manifest.attr("save_o3de_manifest")(manifest);
}
catch ([[maybe_unused]] const std::exception& e)
{
AZ_Warning("PythonBindings", false, "Failed to set third party path.");
}
}
});
return result;
@@ -477,12 +466,12 @@ namespace O3DE::ProjectManager
QVector<GemInfo> gems;
auto result = ExecuteWithLockErrorHandling([&]
{
for (auto path : m_manifest.attr("get_engine_gems")())
{
for (auto path : m_manifest.attr("get_engine_gems")())
{
gems.push_back(GemInfoFromPath(path));
}
});
gems.push_back(GemInfoFromPath(path));
}
});
if (!result.IsSuccess())
{
return AZ::Failure<AZStd::string>(result.GetError().c_str());
@@ -497,13 +486,13 @@ namespace O3DE::ProjectManager
QVector<GemInfo> gems;
auto result = ExecuteWithLockErrorHandling([&]
{
pybind11::str pyProjectPath = projectPath.toStdString();
for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath))
{
pybind11::str pyProjectPath = projectPath.toStdString();
for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath))
{
gems.push_back(GemInfoFromPath(path));
}
});
gems.push_back(GemInfoFromPath(path));
}
});
if (!result.IsSuccess())
{
return AZ::Failure<AZStd::string>(result.GetError().c_str());
@@ -518,12 +507,12 @@ namespace O3DE::ProjectManager
// Retrieve the path to the cmake file that lists the enabled gems.
pybind11::str enabledGemsFilename;
auto result = ExecuteWithLockErrorHandling([&]
{
const pybind11::str pyProjectPath = projectPath.toStdString();
enabledGemsFilename = m_cmake.attr("get_enabled_gem_cmake_file")(
pybind11::none(), // project_name
pyProjectPath); // project_path
});
{
const pybind11::str pyProjectPath = projectPath.toStdString();
enabledGemsFilename = m_cmake.attr("get_enabled_gem_cmake_file")(
pybind11::none(), // project_name
pyProjectPath); // project_path
});
if (!result.IsSuccess())
{
return AZ::Failure<AZStd::string>(result.GetError().c_str());
@@ -532,13 +521,13 @@ namespace O3DE::ProjectManager
// Retrieve the actual list of names from the cmake file.
QVector<AZStd::string> gemNames;
result = ExecuteWithLockErrorHandling([&]
{
const auto pyGemNames = m_cmake.attr("get_enabled_gems")(enabledGemsFilename);
for (auto gemName : pyGemNames)
{
const auto pyGemNames = m_cmake.attr("get_enabled_gems")(enabledGemsFilename);
for (auto gemName : pyGemNames)
{
gemNames.push_back(Py_To_String(gemName));
}
});
gemNames.push_back(Py_To_String(gemName));
}
});
if (!result.IsSuccess())
{
return AZ::Failure<AZStd::string>(result.GetError().c_str());
@@ -552,13 +541,13 @@ namespace O3DE::ProjectManager
bool registrationResult = false;
bool result = ExecuteWithLock(
[&]
{
pybind11::str projectPath = path.toStdString();
auto pythonRegistrationResult = m_register.attr("register")(pybind11::none(), projectPath);
{
pybind11::str projectPath = path.toStdString();
auto pythonRegistrationResult = m_register.attr("register")(pybind11::none(), projectPath);
// Returns an exit code so boolify it then invert result
registrationResult = !pythonRegistrationResult.cast<bool>();
});
// Returns an exit code so boolify it then invert result
registrationResult = !pythonRegistrationResult.cast<bool>();
});
return result && registrationResult;
}
@@ -568,30 +557,31 @@ namespace O3DE::ProjectManager
bool registrationResult = false;
bool result = ExecuteWithLock(
[&]
{
pybind11::str projectPath = path.toStdString();
auto pythonRegistrationResult = m_register.attr("register")(
pybind11::none(), // engine_path
projectPath, // project_path
pybind11::none(), // gem_path
pybind11::none(), // external_subdir_path
pybind11::none(), // template_path
pybind11::none(), // restricted_path
pybind11::none(), // repo_uri
pybind11::none(), // default_engines_folder
pybind11::none(), // default_projects_folder
pybind11::none(), // default_gems_folder
pybind11::none(), // default_templates_folder
pybind11::none(), // default_restricted_folder
pybind11::none(), // external_subdir_engine_path
pybind11::none(), // external_subdir_project_path
true, // remove
false // force
{
pybind11::str projectPath = path.toStdString();
auto pythonRegistrationResult = m_register.attr("register")(
pybind11::none(), // engine_path
projectPath, // project_path
pybind11::none(), // gem_path
pybind11::none(), // external_subdir_path
pybind11::none(), // template_path
pybind11::none(), // restricted_path
pybind11::none(), // repo_uri
pybind11::none(), // default_engines_folder
pybind11::none(), // default_projects_folder
pybind11::none(), // default_gems_folder
pybind11::none(), // default_templates_folder
pybind11::none(), // default_restricted_folder
pybind11::none(), // default_third_party_folder
pybind11::none(), // external_subdir_engine_path
pybind11::none(), // external_subdir_project_path
true, // remove
false // force
);
// Returns an exit code so boolify it then invert result
registrationResult = !pythonRegistrationResult.cast<bool>();
});
// Returns an exit code so boolify it then invert result
registrationResult = !pythonRegistrationResult.cast<bool>();
});
return result && registrationResult;
}
@@ -649,12 +639,12 @@ namespace O3DE::ProjectManager
try
{
// required
gemInfo.m_name = Py_To_String(data["gem_name"]);
gemInfo.m_name = Py_To_String(data["gem_name"]);
// optional
gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name);
gemInfo.m_summary = Py_To_String_Optional(data, "Summary", "");
gemInfo.m_version = Py_To_String_Optional(data, "Version", "");
gemInfo.m_summary = Py_To_String_Optional(data, "Summary", "");
gemInfo.m_version = Py_To_String_Optional(data, "Version", "");
if (data.contains("Tags"))
{
@@ -685,7 +675,7 @@ namespace O3DE::ProjectManager
try
{
projectInfo.m_projectName = Py_To_String(projectData["project_name"]);
projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName);
projectInfo.m_displayName = Py_To_String_Optional(projectData, "display_name", projectInfo.m_projectName);
}
catch ([[maybe_unused]] const std::exception& e)
{
@@ -727,33 +717,33 @@ namespace O3DE::ProjectManager
AZ::Outcome<void, AZStd::string> PythonBindings::AddGemToProject(const QString& gemPath, const QString& projectPath)
{
return ExecuteWithLockErrorHandling([&]
{
pybind11::str pyGemPath = gemPath.toStdString();
pybind11::str pyProjectPath = projectPath.toStdString();
{
pybind11::str pyGemPath = gemPath.toStdString();
pybind11::str pyProjectPath = projectPath.toStdString();
m_enableGemProject.attr("enable_gem_in_project")(
pybind11::none(), // gem name not needed as path is provided
pyGemPath,
pybind11::none(), // project name not needed as path is provided
pyProjectPath
m_enableGemProject.attr("enable_gem_in_project")(
pybind11::none(), // gem name not needed as path is provided
pyGemPath,
pybind11::none(), // project name not needed as path is provided
pyProjectPath
);
});
});
}
AZ::Outcome<void, AZStd::string> PythonBindings::RemoveGemFromProject(const QString& gemPath, const QString& projectPath)
{
return ExecuteWithLockErrorHandling([&]
{
pybind11::str pyGemPath = gemPath.toStdString();
pybind11::str pyProjectPath = projectPath.toStdString();
{
pybind11::str pyGemPath = gemPath.toStdString();
pybind11::str pyProjectPath = projectPath.toStdString();
m_disableGemProject.attr("disable_gem_in_project")(
pybind11::none(), // gem name not needed as path is provided
pyGemPath,
pybind11::none(), // project name not needed as path is provided
pyProjectPath
m_disableGemProject.attr("disable_gem_in_project")(
pybind11::none(), // gem name not needed as path is provided
pyGemPath,
pybind11::none(), // project name not needed as path is provided
pyProjectPath
);
});
});
}
bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo)
@@ -773,8 +763,8 @@ namespace O3DE::ProjectManager
{
// required
templateInfo.m_displayName = Py_To_String(data["display_name"]);
templateInfo.m_name = Py_To_String(data["template_name"]);
templateInfo.m_summary = Py_To_String(data["summary"]);
templateInfo.m_name = Py_To_String(data["template_name"]);
templateInfo.m_summary = Py_To_String(data["summary"]);
// optional
if (data.contains("canonical_tags"))
@@ -806,7 +796,7 @@ namespace O3DE::ProjectManager
QVector<ProjectTemplateInfo> templates;
bool result = ExecuteWithLock([&] {
for (auto path : m_manifest.attr("get_project_templates")())
for (auto path : m_manifest.attr("get_templates_for_project_creation")())
{
templates.push_back(ProjectTemplateInfoFromPath(path));
}
@@ -70,6 +70,52 @@ namespace LUAEditor
, m_bIsModified(false)
, m_bIsBeingSaved(false)
, m_PresetLineAtOpen(1){}
// Copy constructor does not copy over open file handle
DocumentInfo(const DocumentInfo& other)
: m_assetId(other.m_assetId)
, m_scriptAsset(other.m_scriptAsset)
, m_assetName(other.m_assetName)
, m_displayName(other.m_displayName)
, m_lastKnownModTime(other.m_lastKnownModTime)
, m_sourceControlInfo(other.m_sourceControlInfo)
, m_bSourceControl_Ready(other.m_bSourceControl_Ready)
, m_bSourceControl_BusyGettingStats(other.m_bSourceControl_BusyGettingStats)
, m_bSourceControl_BusyRequestingEdit(other.m_bSourceControl_BusyRequestingEdit)
, m_bSourceControl_CanWrite(other.m_bSourceControl_CanWrite)
, m_bSourceControl_CanCheckOut(other.m_bSourceControl_CanCheckOut)
, m_bDataIsLoaded(other.m_bDataIsLoaded)
, m_bDataIsWritten(other.m_bDataIsWritten)
, m_bCloseAfterSave(other.m_bCloseAfterSave)
, m_bUntitledDocument(other.m_bUntitledDocument)
, m_bIsModified(other.m_bIsModified)
, m_bIsBeingSaved(other.m_bIsBeingSaved)
, m_PresetLineAtOpen(other.m_PresetLineAtOpen)
{}
DocumentInfo& operator=(const DocumentInfo& other)
{
m_assetId = other.m_assetId;
m_scriptAsset = other.m_scriptAsset;
m_assetName = other.m_assetName;
m_displayName = other.m_displayName;
m_lastKnownModTime = other.m_lastKnownModTime;
m_sourceControlInfo = other.m_sourceControlInfo;
m_bSourceControl_Ready = other.m_bSourceControl_Ready;
m_bSourceControl_BusyGettingStats = other.m_bSourceControl_BusyGettingStats;
m_bSourceControl_BusyRequestingEdit = other.m_bSourceControl_BusyRequestingEdit;
m_bSourceControl_CanWrite = other.m_bSourceControl_CanWrite;
m_bSourceControl_CanCheckOut = other.m_bSourceControl_CanCheckOut;
m_bDataIsLoaded = other.m_bDataIsLoaded;
m_bDataIsWritten = other.m_bDataIsWritten;
m_bCloseAfterSave = other.m_bCloseAfterSave;
m_bUntitledDocument = other.m_bUntitledDocument;
m_bIsModified = other.m_bIsModified;
m_bIsBeingSaved = other.m_bIsBeingSaved;
m_PresetLineAtOpen = other.m_PresetLineAtOpen;
return *this;
}
};
class ContextInterface
@@ -8,7 +8,8 @@
"Name": "IBLSpecular",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm"
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
@@ -34,7 +35,8 @@
"UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}",
"Name": "IBLSpecular",
"FileMasks": [
"_iblspecularcm"
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
@@ -59,7 +61,8 @@
"UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}",
"Name": "IBLSpecular",
"FileMasks": [
"_iblspecularcm"
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
@@ -84,7 +87,8 @@
"UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}",
"Name": "IBLSpecular",
"FileMasks": [
"_iblspecularcm"
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
@@ -109,7 +113,8 @@
"UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}",
"Name": "IBLSpecular",
"FileMasks": [
"_iblspecularcm"
"_iblspecularcm",
"_iblspecularcm256"
],
"SourceColor": "Linear",
"DestColor": "Linear",
@@ -0,0 +1,135 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 512,
"MaxTextureSize": 512,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"PlatformsPresets": {
"android": {
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 512,
"MaxTextureSize": 512,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"ios": {
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 512,
"MaxTextureSize": 512,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"mac": {
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 512,
"MaxTextureSize": 512,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"provo": {
"UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}",
"Name": "IBLSpecularHigh",
"FileMasks": [
"_iblspecularcm512"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 512,
"MaxTextureSize": 512,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
}
}
}
}
@@ -0,0 +1,135 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 128,
"MaxTextureSize": 128,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"PlatformsPresets": {
"android": {
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 128,
"MaxTextureSize": 128,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"ios": {
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 128,
"MaxTextureSize": 128,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"mac": {
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 128,
"MaxTextureSize": 128,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"provo": {
"UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}",
"Name": "IBLSpecularLow",
"FileMasks": [
"_iblspecularcm128"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 128,
"MaxTextureSize": 128,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
}
}
}
}
@@ -0,0 +1,135 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 1024,
"MaxTextureSize": 1024,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"PlatformsPresets": {
"android": {
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 1024,
"MaxTextureSize": 1024,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"ios": {
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 1024,
"MaxTextureSize": 1024,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"mac": {
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 1024,
"MaxTextureSize": 1024,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"provo": {
"UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}",
"Name": "IBLSpecularVeryHigh",
"FileMasks": [
"_iblspecularcm1024"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 1024,
"MaxTextureSize": 1024,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
}
}
}
}
@@ -0,0 +1,135 @@
{
"Type": "JsonSerialization",
"Version": 1,
"ClassName": "MultiplatformPresetSettings",
"ClassData": {
"DefaultPreset": {
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"Description": "The input cubemap generates an IBL specular output cubemap.",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 64,
"MaxTextureSize": 64,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"PlatformsPresets": {
"android": {
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 64,
"MaxTextureSize": 64,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"ios": {
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 64,
"MaxTextureSize": 64,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"mac": {
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 64,
"MaxTextureSize": 64,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
},
"provo": {
"UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}",
"Name": "IBLSpecularVeryLow",
"FileMasks": [
"_iblspecularcm64"
],
"SourceColor": "Linear",
"DestColor": "Linear",
"SuppressEngineReduce": true,
"PixelFormat": "R9G9B9E5",
"DiscardAlpha": true,
"MinTextureSize": 64,
"MaxTextureSize": 64,
"IsPowerOf2": true,
"CubemapSettings": {
"Filter": "GGX",
"MipAngle": 7.0,
"MipSlope": 2.299999952316284,
"EdgeFixup": -431602080.0,
"SubId": 2000
},
"MipMapSetting": {
"MipGenType": "Box"
}
}
}
}
}
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a476e99b55cf2a76fef6775c5a57dad29f8ffcb942c625bab04c89051a72a560
size 62626
oid sha256:838830c99f344f5b68e5e85c9bc52751350caf48e662c9c2b767ab77039bbd8f
size 103472
@@ -177,4 +177,5 @@ namespace AZ
} // namespace Render
AZ_TYPE_INFO_SPECIALIZE(Render::DisplayMapperOperationType, "{41CA80B1-9E0D-41FB-A235-9638D2A905A5}");
AZ_TYPE_INFO_SPECIALIZE(Render::OutputDeviceTransformType, "{B94085B7-C0D4-466A-A791-188A4559EC8D}");
} // namespace AZ
@@ -12,11 +12,13 @@
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <ACES/Aces.h>
#include <Atom/RPI.Reflect/Pass/PassAsset.h>
#include <Atom/RPI.Reflect/Pass/PassData.h>
#include <Atom/RPI.Reflect/System/AnyAsset.h>
#include <AzCore/Asset/AssetCommon.h>
namespace AZ
{
@@ -33,6 +35,7 @@ namespace AZ
AZ_TYPE_INFO(AcesParameterOverrides, "{3EE8C0D4-3792-46C0-B91C-B89A81C36B91}");
static void Reflect(ReflectContext* context);
// Load preconfigured preset for specific ODT mode defined by m_preset
void LoadPreset();
// When enabled allows parameter overrides for ACES configuration
@@ -98,6 +101,5 @@ namespace AZ
DisplayMapperConfigurationDescriptor m_config;
};
} // namespace RPI
} // namespace Render
} // namespace AZ
@@ -311,14 +311,9 @@ namespace AZ
{
auto tileBufferResolution = GetTileDataBufferResolution();
// generate a UUID for the buffer name to keep it unique when there are multiple render pipelines
AZ::Uuid uuid = AZ::Uuid::CreateRandom();
AZStd::string uuidString;
uuid.ToString(uuidString);
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite;
desc.m_bufferName = AZStd::string::format("LightList_%s", uuidString.c_str());
desc.m_bufferName = "LightList";
desc.m_elementSize = sizeof(uint32_t);
desc.m_byteCount = tileBufferResolution.m_width * tileBufferResolution.m_height * 256 * sizeof(uint32_t);
m_lightList = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
@@ -118,14 +118,9 @@ namespace AZ
void LightCullingRemap::CreateRemappedLightListBuffer()
{
// generate a UUID for the buffer name to keep it unique when there are multiple render pipelines
AZ::Uuid uuid = AZ::Uuid::CreateRandom();
AZStd::string uuidString;
uuid.ToString(uuidString);
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite;
desc.m_bufferName = AZStd::string::format("LightListRemapped_%s", uuidString.c_str());
desc.m_bufferName = "LightListRemapped";
desc.m_elementSize = RHI::GetFormatSize(LightListRemappedFormat);
desc.m_byteCount = m_tileDim.m_width * m_tileDim.m_height * NumBins * MaxLightsPerTile * desc.m_elementSize;
m_lightListRemapped = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
@@ -23,6 +23,15 @@ namespace AZ
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Enum<OutputDeviceTransformType>()
->Version(0)
->Value("48Nits", OutputDeviceTransformType::OutputDeviceTransformType_48Nits)
->Value("1000Nits", OutputDeviceTransformType::OutputDeviceTransformType_1000Nits)
->Value("2000Nits", OutputDeviceTransformType::OutputDeviceTransformType_2000Nits)
->Value("4000Nits", OutputDeviceTransformType::OutputDeviceTransformType_4000Nits)
->Value("NumOutputDeviceTransformTypes", OutputDeviceTransformType::NumOutputDeviceTransformTypes)
;
serializeContext->Class<AcesParameterOverrides>()
->Version(0)
->Field("OverrideDefaults", &AcesParameterOverrides::m_overrideDefaults)
@@ -38,6 +47,22 @@ namespace AZ
->Field("SurroundGamma", &AcesParameterOverrides::m_surroundGamma)
->Field("Gamma", &AcesParameterOverrides::m_gamma);
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->Class<AcesParameterOverrides>("AcesParameterOverrides")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "render")
->Attribute(AZ::Script::Attributes::Module, "render")
->Constructor()
->Method("LoadPreset", &AcesParameterOverrides::LoadPreset)
->Property("overrideDefaults", BehaviorValueProperty(&AcesParameterOverrides::m_overrideDefaults))
->Property("preset", BehaviorValueProperty(&AcesParameterOverrides::m_preset))
->Property("alterSurround", BehaviorValueProperty(&AcesParameterOverrides::m_alterSurround))
->Property("applyDesaturation", BehaviorValueProperty(&AcesParameterOverrides::m_applyDesaturation))
->Property("applyCATD60toD65", BehaviorValueProperty(&AcesParameterOverrides::m_applyCATD60toD65))
;
}
}
void AcesParameterOverrides::LoadPreset()
@@ -71,11 +96,12 @@ namespace AZ
;
serializeContext->Class<DisplayMapperConfigurationDescriptor>()
->Version(1)
->Version(2)
->Field("Name", &DisplayMapperConfigurationDescriptor::m_name)
->Field("OperationType", &DisplayMapperConfigurationDescriptor::m_operationType)
->Field("LdrGradingLutEnabled", &DisplayMapperConfigurationDescriptor::m_ldrGradingLutEnabled)
->Field("LdrColorGradingLut", &DisplayMapperConfigurationDescriptor::m_ldrColorGradingLut)
->Field("AcesParameterOverrides", &DisplayMapperConfigurationDescriptor::m_acesParameterOverrides)
;
}
}
@@ -74,6 +74,7 @@ namespace AZ
desc.m_elementFormat = filters.front()->GetElementFormat();
desc.m_byteCount = totalElementCount * elementSize;
desc.m_bufferData = data.data();
desc.m_isUniqueName = true;
auto buffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
@@ -100,16 +100,9 @@ namespace AZ
bool ExposureControlSettings::InitCommonBuffer()
{
// generate a UUID for the buffer name to keep it unique
AZ::Uuid uuid = AZ::Uuid::CreateRandom();
AZStd::string uuidString;
uuid.ToString(uuidString);
AZStd::string bufferName = AZStd::string::format("%s_%s", ExposureControlBufferBaseName, uuidString.c_str());
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::Constant;
desc.m_bufferName = bufferName;
desc.m_bufferName = ExposureControlBufferName;
desc.m_byteCount = sizeof(ShaderParameters);
desc.m_elementSize = sizeof(ShaderParameters);
@@ -117,7 +110,7 @@ namespace AZ
if (!m_buffer)
{
AZ_Assert(false, "Failed to create the RPI::Buffer[%s] which is used for the exposure control feature.", bufferName.c_str());
AZ_Assert(false, "Failed to create the RPI::Buffer[%s] which is used for the exposure control feature.", desc.m_bufferName.c_str());
return false;
}
@@ -28,8 +28,8 @@ namespace AZ
{
class PostProcessSettings;
// Base name of the buffer used for the exposure control feature. Usually distinct identifier will be added to this name for each exposure control settings.
static const char* const ExposureControlBufferBaseName = "ExposureControlBuffer";
// Name of the buffer used for the exposure control feature
static const char* const ExposureControlBufferName = "ExposureControlBuffer";
// The post process sub-settings class for the exposure control feature
class ExposureControlSettings final
@@ -47,9 +47,8 @@ namespace AZ
m_getDepthPass = static_cast<DepthOfFieldWriteFocusDepthFromGpuPass*>(pass.get());
// Create buffer for read back focus depth. We append static counter to avoid name conflicts.
AZStd::string bufferName = AZStd::string::format("DepthOfFieldReadBackAutoFocusDepthBuffer_%d", s_bufferInstance++);
RPI::CommonBufferDescriptor desc;
desc.m_bufferName = bufferName;
desc.m_bufferName = "DepthOfFieldReadBackAutoFocusDepthBuffer";
desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite;
desc.m_byteCount = sizeof(float);
desc.m_elementSize = aznumeric_cast<uint32_t>(desc.m_byteCount);
@@ -71,6 +71,7 @@ namespace AZ
desc.m_bufferName = bufferName;
desc.m_byteCount = sizeof(ShaderParameters);
desc.m_elementSize = sizeof(ShaderParameters);
desc.m_isUniqueName = true;
m_buffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
}
@@ -34,7 +34,7 @@ namespace AZ
{
namespace Render
{
static const char* const EyeAdaptationBufferBaseName = "EyeAdaptationBuffer";
static const char* const EyeAdaptationBufferName = "EyeAdaptationBuffer";
RPI::Ptr<EyeAdaptationPass> EyeAdaptationPass::Create(const RPI::PassDescriptor& descriptor)
{
@@ -49,12 +49,10 @@ namespace AZ
void EyeAdaptationPass::InitBuffer()
{
AZStd::string bufferName = AZStd::string::format("%s_%p", EyeAdaptationBufferBaseName, this);
ExposureCalculationData defaultData;
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite;
desc.m_bufferName = bufferName;
desc.m_bufferName = EyeAdaptationBufferName;
desc.m_byteCount = sizeof(ExposureCalculationData);
desc.m_elementSize = aznumeric_cast<uint32_t>(desc.m_byteCount);
desc.m_bufferData = &defaultData;
@@ -62,14 +62,9 @@ namespace AZ
void LuminanceHistogramGeneratorPass::CreateHistogramBuffer()
{
// generate a UUID for the buffer name to keep it unique when there are multiple render pipelines
AZ::Uuid uuid = AZ::Uuid::CreateRandom();
AZStd::string uuidString;
uuid.ToString(uuidString);
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::ReadWrite;
desc.m_bufferName = AZStd::string::format("LuminanceHistogramBuffer_%s", uuidString.c_str());
desc.m_bufferName = "LuminanceHistogramBuffer";
desc.m_elementSize = sizeof(uint32_t);
desc.m_byteCount = NumHistogramBins * sizeof(uint32_t);
desc.m_elementFormat = RHI::Format::R32_UINT;
@@ -210,12 +210,10 @@ namespace AZ
if (m_meshInfoBuffer == nullptr)
{
AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString<AZStd::string>();
// allocate the MeshInfo structured buffer
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
desc.m_bufferName = AZStd::string::format("RayTracingMeshInfo_%s", uuidString.c_str());
desc.m_bufferName = "RayTracingMeshInfo";
desc.m_byteCount = newMeshByteCount;
desc.m_elementSize = sizeof(MeshInfo);
m_meshInfoBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
@@ -283,12 +281,10 @@ namespace AZ
if (m_materialInfoBuffer == nullptr)
{
AZStd::string uuidString = AZ::Uuid::CreateRandom().ToString<AZStd::string>();
// allocate the MaterialInfo structured buffer
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
desc.m_bufferName = AZStd::string::format("RayTracingMaterialInfo_%s", uuidString.c_str());
desc.m_bufferName = "RayTracingMaterialInfo";
desc.m_byteCount = newMaterialByteCount;
desc.m_elementSize = sizeof(MaterialInfo);
m_materialInfoBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
@@ -193,7 +193,7 @@ namespace AZ
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::Constant;
desc.m_bufferName = AZStd::string::format("SkyboxBuffer_%p", this);
desc.m_bufferName = "SkyboxBuffer";
desc.m_byteCount = byteCount;
desc.m_elementSize = byteCount;
desc.m_bufferData = &m_physicalSkyData;
@@ -89,13 +89,13 @@ namespace AZ
// Create the transform buffer, grow by powers of two
RPI::CommonBufferDescriptor desc2;
desc2.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
desc2.m_bufferName = AZStd::string::format("'m_objectToWorldBuffer_%" PRIXPTR, reinterpret_cast<uintptr_t>(this));
desc2.m_bufferName = "m_objectToWorldBuffer";
desc2.m_byteCount = byteCount;
desc2.m_elementSize = elementSize;
m_objectToWorldBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc2);
desc2.m_bufferName = AZStd::string::format("'m_objectToWorldHistoryBuffer_%p", this);
desc2.m_bufferName = "m_objectToWorldHistoryBuffer";
m_objectToWorldHistoryBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc2);
}
else
@@ -119,7 +119,7 @@ namespace AZ
// Create the normal buffer, grow by powers of two
RPI::CommonBufferDescriptor desc2;
desc2.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
desc2.m_bufferName = AZStd::string::format("'m_objectToWorldInverseTransposeBuffer_%" PRIXPTR, reinterpret_cast<uintptr_t>(this));
desc2.m_bufferName = "m_objectToWorldInverseTransposeBuffer";
desc2.m_byteCount = byteCount;
desc2.m_elementSize = elementSize;
@@ -40,13 +40,11 @@ namespace AZ
if (m_bufferIndex.IsValid())
{
AZStd::string bufferName = AZStd::string::format("%s_%" PRIXPTR, descriptor.m_bufferName.c_str(), reinterpret_cast<uintptr_t>(this));
uint32_t byteCount = RHI::NextPowerOfTwo(GetMax<uint32_t>(BufferMinSize, m_elementCount * m_elementSize));
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
desc.m_bufferName = bufferName;
desc.m_bufferName = descriptor.m_bufferName;
desc.m_byteCount = byteCount;
desc.m_elementSize = descriptor.m_elementSize;
@@ -261,8 +261,8 @@ namespace AZ
if (vulkanDescriptor.m_constantDataPool && constantDataSize)
{
m_constantDataBuffer = Buffer::Create();
const RHI::BufferDescriptor descriptor(RHI::BufferBindFlags::Constant, constantDataSize);
RHI::BufferInitRequest request(*m_constantDataBuffer, descriptor);
const RHI::BufferDescriptor bufferDescriptor(RHI::BufferBindFlags::Constant, constantDataSize);
RHI::BufferInitRequest request(*m_constantDataBuffer, bufferDescriptor);
RHI::ResultCode rhiResult = vulkanDescriptor.m_constantDataPool->InitBuffer(request);
if (rhiResult != RHI::ResultCode::Success)
{
@@ -112,6 +112,8 @@ namespace AZ
AZStd::mutex m_pendingUploadMutex;
RHI::BufferViewDescriptor m_bufferViewDescriptor;
RHI::AttachmentId m_attachmentId;
};
template <class structureType>
@@ -35,7 +35,7 @@ namespace AZ
// BufferSystemInterface overrides...
RHI::Ptr<RHI::BufferPool> GetCommonBufferPool(CommonBufferPoolType poolType) override;
Data::Instance<Buffer> CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor) override;
Data::Instance<Buffer> FindCommonBuffer(AZStd::string_view bufferName) override;
Data::Instance<Buffer> FindCommonBuffer(AZStd::string_view uniqueBufferName) override;
void Init();
void Shutdown();
@@ -53,6 +53,9 @@ namespace AZ
RHI::Format m_elementFormat = RHI::Format::Unknown; //<! [optional] If it's specified with a valid format, the size of this format will be used instead of m_elementSize
AZ::u64 m_byteCount = 0;
const void* m_bufferData = nullptr; //<! [optional] Initial data content of this buffer. This data buffer size needs to be same as m_bufferSizeInbytes
//! Set to true if you want this buffer to be discoverable by BufferSystemInterface::FindCommonBuffer using m_bufferName.
//! Note that create buffer may fail if there is a buffer with the same name.
bool m_isUniqueName = false;
};
class BufferSystemInterface
@@ -78,7 +81,7 @@ namespace AZ
virtual Data::Instance<Buffer> CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor) = 0;
//! Find a buffer by name. The buffer has to be created by CreateBufferFromCommonPool function
virtual Data::Instance<Buffer> FindCommonBuffer(AZStd::string_view bufferName) = 0;
virtual Data::Instance<Buffer> FindCommonBuffer(AZStd::string_view uniqueBufferName) = 0;
};
} // namespace RPI
} // namespace AZ
@@ -60,11 +60,15 @@ namespace AZ
const Data::Asset<ResourcePoolAsset>& GetPoolAsset() const;
CommonBufferPoolType GetCommonPoolType() const;
const AZStd::string& GetName() const;
private:
// Called by asset creators to assign the asset to a ready state.
void SetReady();
AZStd::string m_name;
AZStd::vector<uint8_t> m_buffer;
RHI::BufferDescriptor m_bufferDescriptor;
@@ -114,7 +114,7 @@ namespace AZ
if (auto* serialize = azrtti_cast<SerializeContext*>(context))
{
serialize->Class<ModelAssetBuilderComponent, SceneAPI::SceneCore::ExportingComponent>()
->Version(26); // [ATOM-14992]
->Version(27); // [ATOM-15658]
}
}
@@ -14,9 +14,11 @@
#include <Atom/RPI.Reflect/Model/MorphTargetDelta.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/Containers/Utilities/SceneGraphUtilities.h>
#include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
#include <SceneAPI/SceneCore/Containers/Views/FilterIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzCore/Asset/AssetManagerBus.h>
@@ -27,62 +29,42 @@ namespace AZ::RPI
AZStd::unordered_map<AZStd::string, MorphTargetExporter::SourceBlendShapeInfo> MorphTargetExporter::GetBlendShapeInfos(
const Containers::Scene& scene,
const AZStd::optional<AZStd::string>& filterMeshName) const
const MeshData* meshData) const
{
const Containers::SceneGraph& sceneGraph = scene.GetGraph();
const auto contentStorage = sceneGraph.GetContentStorage();
const auto nameStorage = sceneGraph.GetNameStorage();
const auto foundBaseMeshIter = AZStd::find_if(sceneGraph.GetContentStorage().cbegin(), sceneGraph.GetContentStorage().cend(), [meshData](const auto& nodeData)
{
return nodeData.get() == meshData;
});
if (foundBaseMeshIter == sceneGraph.GetContentStorage().cend())
{
return {};
}
const auto baseMeshNodeIndex = sceneGraph.ConvertToNodeIndex(foundBaseMeshIter);
const auto childBlendShapeDatas = Containers::MakeDerivedFilterView<DataTypes::IBlendShapeData>(
Containers::Views::MakeSceneGraphChildView(sceneGraph, baseMeshNodeIndex, sceneGraph.GetContentStorage().cbegin(), true)
);
AZStd::unordered_map<AZStd::string, SourceBlendShapeInfo> result;
const auto keyValueView = Containers::Views::MakePairView(nameStorage, contentStorage);
const auto filteredView = Containers::Views::MakeFilterView(keyValueView, Containers::DerivedTypeFilter<DataTypes::IBlendShapeData>());
for (const auto& [name, object] : filteredView)
for (auto it = childBlendShapeDatas.cbegin(); it != childBlendShapeDatas.cend(); ++it)
{
const Containers::SceneGraph::NodeIndex sceneNodeIndex = sceneGraph.Find(name.GetPath());
const Containers::SceneGraph::NodeIndex blendShapeNodeIndex = sceneGraph.ConvertToNodeIndex(it.GetBaseIterator().GetBaseIterator().GetHierarchyIterator());
AZStd::set<AZ::Crc32> types;
Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, types, scene, sceneNodeIndex);
if (types.find(Events::GraphMetaInfo::GetIgnoreVirtualType()) == types.end())
Events::GraphMetaInfoBus::Broadcast(&Events::GraphMetaInfo::GetVirtualTypes, types, scene, blendShapeNodeIndex);
if (!types.contains(Events::GraphMetaInfo::GetIgnoreVirtualType()))
{
const char* sceneNodePath = name.GetPath();
const Containers::SceneGraph::NodeIndex nodeIndex = sceneGraph.Find(sceneNodePath);
if (nodeIndex.IsValid())
{
const AZStd::string meshNodeName = SourceBlendShapeInfo::GetMeshNodeName(sceneGraph, nodeIndex);
if (!filterMeshName.has_value() ||
(filterMeshName.has_value() && filterMeshName.value() == meshNodeName))
{
const AZStd::string blendShapeName = sceneGraph.GetNodeName(nodeIndex).GetName();
SourceBlendShapeInfo& blendShapeInfo = result[blendShapeName];
blendShapeInfo.m_sceneNodeIndices.push_back(nodeIndex);
}
}
else
{
AZ_Warning(ModelAssetBuilderComponent::s_builderName, false, "Cannot retrieve scene graph index for blend shape node with path %s.", sceneNodePath);
}
const AZStd::string blendShapeName{sceneGraph.GetNodeName(blendShapeNodeIndex).GetName(), sceneGraph.GetNodeName(blendShapeNodeIndex).GetNameLength()};
result[blendShapeName].m_sceneNodeIndices.emplace_back(blendShapeNodeIndex);
}
}
return result;
}
AZStd::string MorphTargetExporter::SourceBlendShapeInfo::GetMeshNodeName(const Containers::SceneGraph& sceneGraph,
const Containers::SceneGraph::NodeIndex& sceneNodeIndex)
{
const auto* blendShapeData =
azrtti_cast<const DataTypes::IBlendShapeData*>(sceneGraph.GetNodeContent(sceneNodeIndex).get());
AZ_Assert(blendShapeData, "Cannot get mesh node name from scene node. Node is expected to be a blend shape.");
if (blendShapeData)
{
Containers::SceneGraph::NodeIndex morphMeshParentIndex = sceneGraph.GetNodeParent(sceneNodeIndex);
return sceneGraph.GetNodeName(morphMeshParentIndex).GetName();
}
return {};
}
void MorphTargetExporter::ProduceMorphTargets(const Containers::Scene& scene,
uint32_t vertexOffset,
const ModelAssetBuilderComponent::SourceMeshContent& sourceMesh,
@@ -92,9 +74,14 @@ namespace AZ::RPI
{
const Containers::SceneGraph& sceneGraph = scene.GetGraph();
#if defined(AZ_ENABLE_TRACING)
const auto baseMeshIt = AZStd::find(sceneGraph.GetContentStorage().cbegin(), sceneGraph.GetContentStorage().cend(), sourceMesh.m_meshData);
const Containers::SceneGraph::NodeIndex baseMeshIndex = sceneGraph.ConvertToNodeIndex(baseMeshIt);
const AZStd::string_view baseMeshName{sceneGraph.GetNodeName(baseMeshIndex).GetName(), sceneGraph.GetNodeName(baseMeshIndex).GetNameLength()};
#endif
// Get the blend shapes for the given mesh
const AZStd::string_view meshName = sourceMesh.m_name.GetStringView();
AZStd::unordered_map<AZStd::string, SourceBlendShapeInfo> blendShapeInfos = GetBlendShapeInfos(scene, meshName);
AZStd::unordered_map<AZStd::string, SourceBlendShapeInfo> blendShapeInfos = GetBlendShapeInfos(scene, sourceMesh.m_meshData.get());
for (const auto& iter : blendShapeInfos)
{
@@ -109,12 +96,12 @@ namespace AZ::RPI
{
#if defined(AZ_ENABLE_TRACING)
const Containers::SceneGraph::NodeIndex morphMeshParentIndex = sceneGraph.GetNodeParent(sceneNodeIndex);
const char* meshNodeName = sceneGraph.GetNodeName(morphMeshParentIndex).GetName();
const AZStd::string_view sourceMeshName{sceneGraph.GetNodeName(morphMeshParentIndex).GetName(), sceneGraph.GetNodeName(morphMeshParentIndex).GetNameLength()};
#endif
AZ_Assert(AZ::StringFunc::Equal(sourceMesh.m_name.GetCStr(), meshNodeName, /*bCaseSensitive=*/true),
"Scene graph mesh node (%s) has a different name than the product mesh (%s).",
meshNodeName, sourceMesh.m_name.GetCStr());
AZ_Assert(AZ::StringFunc::Equal(baseMeshName, sourceMeshName, /*bCaseSensitive=*/true),
"Scene graph mesh node (%.*s) has a different name than the product mesh (%.*s).",
AZ_STRING_ARG(sourceMeshName), AZ_STRING_ARG(baseMeshName));
const DataTypes::MatrixType globalTransform = Utilities::BuildWorldTransform(sceneGraph, sceneNodeIndex);
BuildMorphTargetMesh(vertexOffset, sourceMesh, productMesh, metaAssetCreator, blendShapeName, blendShapeData, globalTransform, coordSysConverter, scene.GetSourceFilename());
@@ -39,12 +39,9 @@ namespace AZ
struct SourceBlendShapeInfo
{
AZStd::vector<AZ::SceneAPI::Containers::SceneGraph::NodeIndex> m_sceneNodeIndices;
static AZStd::string GetMeshNodeName(const AZ::SceneAPI::Containers::SceneGraph& sceneGraph,
const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& sceneNodeIndex);
};
//! Retrieve all scene graph nodes per blend shape for all available blend shapes.
AZStd::unordered_map<AZStd::string, SourceBlendShapeInfo> GetBlendShapeInfos(const AZ::SceneAPI::Containers::Scene& scene, const AZStd::optional<AZStd::string>& filterMeshName = AZStd::nullopt) const;
AZStd::unordered_map<AZStd::string, SourceBlendShapeInfo> GetBlendShapeInfos(const AZ::SceneAPI::Containers::Scene& scene, const MeshData* meshData) const;
//! Calculate position delta tolerance that is used to indicate whether a given vertex is part of the sparse set of morphed vertices
//! or if it will be skipped and optimized out due to a hardly visible or no movement at all.
@@ -32,10 +32,6 @@ namespace AZ
auto buffer = Data::InstanceDatabase<Buffer>::Instance().FindOrCreate(
Data::InstanceId::CreateFromAssetId(bufferAsset.GetId()),
bufferAsset);
if (buffer && buffer->m_rhiBuffer)
{
buffer->m_rhiBuffer->SetName(Name(bufferAsset.GetHint()));
}
return buffer;
}
@@ -170,6 +166,16 @@ namespace AZ
return resultCode;
}
}
m_rhiBuffer->SetName(Name(bufferAsset.GetName()));
// Only generate buffer's attachment id if the buffer is writable
if (RHI::CheckBitsAny(m_rhiBuffer->GetDescriptor().m_bindFlags,
RHI::BufferBindFlags::ShaderWrite | RHI::BufferBindFlags::CopyWrite | RHI::BufferBindFlags::DynamicInputAssembly))
{
// attachment id = bufferName_bufferInstanceId
m_attachmentId = Name(bufferAsset.GetName() + "_" + bufferAsset.GetId().m_guid.ToString<AZStd::string>(false, false));
}
return RHI::ResultCode::Success;
}
@@ -312,7 +318,8 @@ namespace AZ
const RHI::AttachmentId& Buffer::GetAttachmentId() const
{
return m_rhiBuffer->GetName();
AZ_Assert(!m_attachmentId.GetStringView().empty(), "Read-only buffer doesn't need attachment id");
return m_attachmentId;
}
const RHI::BufferViewDescriptor& Buffer::GetBufferViewDescriptor() const
@@ -152,15 +152,22 @@ namespace AZ
}
Data::Instance<Buffer> BufferSystem::CreateBufferFromCommonPool(const CommonBufferDescriptor& descriptor)
{
Uuid bufferId = Uuid::CreateName(descriptor.m_bufferName.c_str());
// Report error if there is a buffer with same name.
// Note: this shouldn't return the existing buffer because users are expecting a newly created buffer.
if (Data::InstanceDatabase<Buffer>::Instance().Find(Data::InstanceId(bufferId)))
{
Uuid bufferId;
if (descriptor.m_isUniqueName)
{
AZ_Error("BufferSystem", false, "Buffer with same name '%s' already exist", descriptor.m_bufferName.c_str());
return nullptr;
bufferId = Uuid::CreateName(descriptor.m_bufferName.c_str());
// Report error if there is a buffer with same name.
// Note: this shouldn't return the existing buffer because users are expecting a newly created buffer.
if (Data::InstanceDatabase<Buffer>::Instance().Find(Data::InstanceId(bufferId)))
{
AZ_Error("BufferSystem", false, "Buffer with same name '%s' already exist", descriptor.m_bufferName.c_str());
return nullptr;
}
}
else
{
bufferId = Uuid::CreateRandom();
}
RHI::Ptr<RHI::BufferPool> bufferPool = GetCommonBufferPool(descriptor.m_poolType);
@@ -207,9 +214,9 @@ namespace AZ
return nullptr;
}
Data::Instance<Buffer> BufferSystem::FindCommonBuffer(AZStd::string_view bufferName)
Data::Instance<Buffer> BufferSystem::FindCommonBuffer(AZStd::string_view uniqueBufferName)
{
Uuid bufferId = Uuid::CreateName(bufferName.data());
Uuid bufferId = Uuid::CreateName(uniqueBufferName.data());
return Data::InstanceDatabase<Buffer>::Instance().Find(Data::InstanceId(bufferId));
}
} // namespace RPI
@@ -30,7 +30,7 @@ namespace AZ
// Create the ring buffer from common pool
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::DynamicInputAssembly;
desc.m_bufferName = AZStd::string::format("DyanmicBufferRing_%p", this);
desc.m_bufferName = "DyanmicBufferRing";
desc.m_elementSize = 1;
desc.m_byteCount = ringBufferSize;
m_ringBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
@@ -30,7 +30,8 @@ namespace AZ
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<BufferAsset>()
->Version(1)
->Version(2)
->Field("Name", &BufferAsset::m_name)
->Field("Buffer", &BufferAsset::m_buffer)
->Field("BufferDescriptor", &BufferAsset::m_bufferDescriptor)
->Field("BufferViewDescriptor", &BufferAsset::m_bufferViewDescriptor)
@@ -80,5 +81,10 @@ namespace AZ
{
return m_poolType;
}
const AZStd::string& BufferAsset::GetName() const
{
return m_name;
}
} //namespace RPI
} // namespace AZ
@@ -152,7 +152,10 @@ namespace AZ
void BufferAssetCreator::SetBufferName(AZStd::string_view name)
{
m_asset.SetHint(name);
if (ValidateIsReady())
{
m_asset->m_name = name;
}
}
bool BufferAssetCreator::Clone(const Data::Asset<BufferAsset>& sourceAsset, Data::Asset<BufferAsset>& clonedResult, Data::AssetId& inOutLastCreatedAssetId)
@@ -474,6 +474,7 @@ namespace UnitTest
desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
desc.m_bufferName = "Buffer1";
desc.m_byteCount = bufferInfo.m_bufferDescriptor.m_byteCount;
desc.m_isUniqueName = true;
Data::Instance<RPI::Buffer> bufferInst = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
// buffer created
@@ -488,8 +489,33 @@ namespace UnitTest
EXPECT_EQ(bufferFound2.get(), nullptr);
}
// Failed if creates a buffer with duplicated name with existing buffer
TEST_F(BufferTests, BufferSystem_CreateDuplicatedNamedBuffer_Fail)
// Failed if creates a buffe which has a same name with existing buffer
// and has m_isUniqueName is enabled
TEST_F(BufferTests, BufferSystem_CreateDuplicatedNamedBufferEnableUniqueName_Fail)
{
using namespace AZ;
ExpectedBuffer bufferInfo = CreateValidBuffer();
RPI::CommonBufferDescriptor desc;
desc.m_poolType = RPI::CommonBufferPoolType::ReadOnly;
desc.m_bufferName = "Buffer1";
desc.m_byteCount = bufferInfo.m_bufferDescriptor.m_byteCount;
desc.m_isUniqueName = true;
Data::Instance<RPI::Buffer> bufferInst = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
// buffer created
EXPECT_NE(bufferInst.get(), nullptr);
AZ_TEST_START_ASSERTTEST;
Data::Instance<RPI::Buffer> bufferInst2 = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
AZ_TEST_STOP_ASSERTTEST(1);
// buffer NOT created
EXPECT_EQ(bufferInst2.get(), nullptr);
}
// create a buffer which has a same name with existing buffer
TEST_F(BufferTests, BufferSystem_CreateDuplicatedNamedBuffers_Success)
{
using namespace AZ;
@@ -503,12 +529,10 @@ namespace UnitTest
Data::Instance<RPI::Buffer> bufferInst = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
// buffer created
EXPECT_NE(bufferInst.get(), nullptr);
AZ_TEST_START_ASSERTTEST;
Data::Instance<RPI::Buffer> bufferInst2 = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
AZ_TEST_STOP_ASSERTTEST(1);
// buffer NOT created
EXPECT_EQ(bufferInst2.get(), nullptr);
// buffer created
EXPECT_NE(bufferInst2.get(), nullptr);
}
// Buffer instance creation unit tests
@@ -510,9 +510,9 @@ namespace ShaderManagementConsole
AZStd::vector<AZ::Uuid> documentIdsToClose;
documentIdsToClose.reserve(m_tabWidget->count());
const AZ::Uuid documentIdToKeepOpen = GetDocumentIdFromTab(tabIndex);
for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex)
for (int tabI = 0; tabI < m_tabWidget->count(); ++tabI)
{
const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex);
const AZ::Uuid documentId = GetDocumentIdFromTab(tabI);
if (documentId != documentIdToKeepOpen)
{
documentIdsToClose.push_back(documentId);
@@ -0,0 +1,119 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/ComponentBus.h>
#include <Atom/Feature/Material/MaterialAssignment.h>
#include <ACES/Aces.h>
namespace AZ
{
namespace Render
{
struct AcesParameterOverrides;
//! DisplayMapperComponentRequests provides an interface to request operations on a DisplayMapperComponent
class DisplayMapperComponentRequests
: public ComponentBus
{
public:
AZ_RTTI(AZ::Render::DisplayMapperComponentRequests, "{9E2E8AF5-1176-44B4-A461-E09867753349}");
/// Overrides the default AZ::EBusTraits handler policy to allow one listener only.
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
//! Load preconfigured preset for specific ODT mode
virtual void LoadPreset(OutputDeviceTransformType preset) = 0;
//! Set display mapper type
virtual void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) = 0;
//! Get display mapper type
virtual DisplayMapperOperationType GetDisplayMapperOperationType() const = 0;
//! Set ACES parameter overrides for ACES mapping, display mapper must be set to Aces to see the difference
virtual void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) = 0;
//! Get ACES parameter overrides
virtual const AcesParameterOverrides& GetAcesParameterOverrides() const = 0;
// Enable or disable ACES parameter overrides
virtual void SetOverrideAcesParameters(bool value) = 0;
// Check if ACES parameters are overriding default preset values
virtual bool GetOverrideAcesParameters() const = 0;
// Set gamma adjustment to compensate for dim surround
virtual void SetAlterSurround(bool value) = 0;
// Get gamma adjustment to compensate for dim surround
virtual bool GetAlterSurround() const = 0;
// Set desaturation to compensate for luminance difference
virtual void SetApplyDesaturation(bool value) = 0;
// Get desaturation to compensate for luminance difference
virtual bool GetApplyDesaturation() const = 0;
// Set color appearance transform (CAT) from ACES white point to assumed observer adapted white point
virtual void SetApplyCATD60toD65(bool value) = 0;
// Get color appearance transform (CAT) from ACES white point to assumed observer adapted white point
virtual bool GetApplyCATD60toD65() const = 0;
// Set reference black luminance value
virtual void SetCinemaLimitsBlack(float value) = 0;
// Get reference black luminance value
virtual float GetCinemaLimitsBlack() const = 0;
// Set reference white luminance value
virtual void SetCinemaLimitsWhite(float value) = 0;
// Get reference white luminance value
virtual float GetCinemaLimitsWhite() const = 0;
// Set min luminance value
virtual void SetMinPoint(float value) = 0;
// Get min luminance value
virtual float GetMinPoint() const = 0;
// Set mid luminance value
virtual void SetMidPoint(float value) = 0;
// Get mid luminance value
virtual float GetMidPoint() const = 0;
// Set max luminance value
virtual void SetMaxPoint(float value) = 0;
// Get max luminance value
virtual float GetMaxPoint() const = 0;
// Set gamma adjustment value
virtual void SetSurroundGamma(float value) = 0;
// Get gamma adjustment value
virtual float GetSurroundGamma() const = 0;
// Set optional gamma value that is applied as basic gamma curve OETF
virtual void SetGamma(float value) = 0;
// Get optional gamma value that is applied as basic gamma curve OETF
virtual float GetGamma() const = 0;
};
using DisplayMapperComponentRequestBus = EBus<DisplayMapperComponentRequests>;
//! DisplayMapperComponent can send out notifications on the DisplayMapperComponentNotifications
class DisplayMapperComponentNotifications : public ComponentBus
{
public:
//! Notifies that display mapper type changed
virtual void OnDisplayMapperOperationTypeUpdated([[maybe_unused]] const DisplayMapperOperationType& displayMapperOperationType)
{
}
//! Notifies that ACES parameter overrides changed
virtual void OnAcesParameterOverridesUpdated([[maybe_unused]] const AcesParameterOverrides& acesParameterOverrides)
{
}
};
using DisplayMapperComponentNotificationBus = EBus<DisplayMapperComponentNotifications>;
} // namespace Render
} // namespace AZ
@@ -54,13 +54,14 @@ namespace AZ
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &GridComponentConfig::m_gridSize, "Grid Size", "Grid width and depth")
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
->Attribute(AZ::Edit::Attributes::Min, GridComponentController::MinGridSize)
->Attribute(AZ::Edit::Attributes::Max, GridComponentController::MaxGridSize)
->Attribute(AZ::Edit::Attributes::Suffix, " m")
->DataElement(AZ::Edit::UIHandlers::Default, &GridComponentConfig::m_primarySpacing, "Primary Grid Spacing", "Amount of space between grid lines")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->Attribute(AZ::Edit::Attributes::Min, GridComponentController::MinSpacing)
->Attribute(AZ::Edit::Attributes::Suffix, " m")
->DataElement(AZ::Edit::UIHandlers::Default, &GridComponentConfig::m_secondarySpacing, "Secondary Grid Spacing", "Amount of space between sub-grid lines")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->Attribute(AZ::Edit::Attributes::Min, GridComponentController::MinSpacing)
->Attribute(AZ::Edit::Attributes::Suffix, " m")
->DataElement(AZ::Edit::UIHandlers::Color, &GridComponentConfig::m_axisColor, "Axis Color", "Color of the grid axis")
->DataElement(AZ::Edit::UIHandlers::Color, &GridComponentConfig::m_primaryColor, "Primary Color", "Color of the primary grid lines")
@@ -115,7 +115,7 @@ namespace AZ
void GridComponentController::SetSize(float gridSize)
{
m_configuration.m_gridSize = gridSize;
m_configuration.m_gridSize = AZStd::clamp(gridSize, MinGridSize, MaxGridSize);
m_dirty = true;
}
@@ -126,7 +126,7 @@ namespace AZ
void GridComponentController::SetPrimarySpacing(float gridPrimarySpacing)
{
m_configuration.m_primarySpacing = gridPrimarySpacing;
m_configuration.m_primarySpacing = AZStd::max(gridPrimarySpacing, MinSpacing);
m_dirty = true;
}
@@ -137,7 +137,7 @@ namespace AZ
void GridComponentController::SetSecondarySpacing(float gridSecondarySpacing)
{
m_configuration.m_secondarySpacing = gridSecondarySpacing;
m_configuration.m_secondarySpacing = AZStd::max(gridSecondarySpacing, MinSpacing);
m_dirty = true;
}
@@ -46,6 +46,10 @@ namespace AZ
void SetConfiguration(const GridComponentConfig& config);
const GridComponentConfig& GetConfiguration() const;
static constexpr float MinGridSize = 0.0f;
static constexpr float MaxGridSize = 1000000.0f;
static constexpr float MinSpacing = 0.01f;
private:
AZ_DISABLE_COPY(GridComponentController);
@@ -39,6 +39,5 @@ namespace AZ
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common);
}
}
} // namespace Render
} // namespace AZ
@@ -10,6 +10,8 @@
*
*/
#include "AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h"
#include <AzCore/RTTI/BehaviorContext.h>
#include <Atom/RPI.Public/Scene.h>
@@ -32,6 +34,69 @@ namespace AZ
->Version(0)
->Field("Configuration", &DisplayMapperComponentController::m_configuration);
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<DisplayMapperComponentRequestBus>("DisplayMapperComponentRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "render")
->Attribute(AZ::Script::Attributes::Module, "render")
// LoadPreset
->Event("LoadPreset", &DisplayMapperComponentRequestBus::Events::LoadPreset)
// DisplayMapperOperationType
->Event("SetDisplayMapperOperationType", &DisplayMapperComponentRequestBus::Events::SetDisplayMapperOperationType)
->Event("GetDisplayMapperOperationType", &DisplayMapperComponentRequestBus::Events::GetDisplayMapperOperationType)
->VirtualProperty("DisplayMapperOperationType", "GetDisplayMapperOperationType", "SetDisplayMapperOperationType")
// AcesParameterOverrides
->Event("SetAcesParameterOverrides", &DisplayMapperComponentRequestBus::Events::SetAcesParameterOverrides)
->Event("GetAcesParameterOverrides", &DisplayMapperComponentRequestBus::Events::GetAcesParameterOverrides)
->VirtualProperty("AcesParameterOverrides", "GetAcesParameterOverrides", "SetAcesParameterOverrides")
// OverrideAcesParameters
->Event("SetOverrideAcesParameters", &DisplayMapperComponentRequestBus::Events::SetOverrideAcesParameters)
->Event("GetOverrideAcesParameters", &DisplayMapperComponentRequestBus::Events::GetOverrideAcesParameters)
->VirtualProperty("OverrideAcesParameters", "GetOverrideAcesParameters", "SetOverrideAcesParameters")
// AlterSurround
->Event("SetAlterSurround", &DisplayMapperComponentRequestBus::Events::SetAlterSurround)
->Event("GetAlterSurround", &DisplayMapperComponentRequestBus::Events::GetAlterSurround)
->VirtualProperty("AlterSurround", "GetAlterSurround", "SetAlterSurround")
// ApplyDesaturation
->Event("SetApplyDesaturation", &DisplayMapperComponentRequestBus::Events::SetApplyDesaturation)
->Event("GetApplyDesaturation", &DisplayMapperComponentRequestBus::Events::GetApplyDesaturation)
->VirtualProperty("ApplyDesaturation", "GetApplyDesaturation", "SetApplyDesaturation")
// ApplyCATD60toD65
->Event("SetApplyCATD60toD65", &DisplayMapperComponentRequestBus::Events::SetApplyCATD60toD65)
->Event("GetApplyCATD60toD65", &DisplayMapperComponentRequestBus::Events::GetApplyCATD60toD65)
->VirtualProperty("ApplyCATD60toD65", "GetApplyCATD60toD65", "SetApplyCATD60toD65")
// CinemaLimitsBlack
->Event("SetCinemaLimitsBlack", &DisplayMapperComponentRequestBus::Events::SetCinemaLimitsBlack)
->Event("GetCinemaLimitsBlack", &DisplayMapperComponentRequestBus::Events::GetCinemaLimitsBlack)
->VirtualProperty("CinemaLimitsBlack", "GetCinemaLimitsBlack", "SetCinemaLimitsBlack")
// CinemaLimitsWhite
->Event("SetCinemaLimitsWhite", &DisplayMapperComponentRequestBus::Events::SetCinemaLimitsWhite)
->Event("GetCinemaLimitsWhite", &DisplayMapperComponentRequestBus::Events::GetCinemaLimitsWhite)
->VirtualProperty("CinemaLimitsWhite", "GetCinemaLimitsWhite", "SetCinemaLimitsWhite")
// MinPoint
->Event("SetMinPoint", &DisplayMapperComponentRequestBus::Events::SetMinPoint)
->Event("GetMinPoint", &DisplayMapperComponentRequestBus::Events::GetMinPoint)
->VirtualProperty("MinPoint", "GetMinPoint", "SetMinPoint")
// MidPoint
->Event("SetMidPoint", &DisplayMapperComponentRequestBus::Events::SetMidPoint)
->Event("GetMidPoint", &DisplayMapperComponentRequestBus::Events::GetMidPoint)
->VirtualProperty("MidPoint", "GetMidPoint", "SetMidPoint")
// MaxPoint
->Event("SetMaxPoint", &DisplayMapperComponentRequestBus::Events::SetMaxPoint)
->Event("GetMaxPoint", &DisplayMapperComponentRequestBus::Events::GetMaxPoint)
->VirtualProperty("MaxPoint", "GetMaxPoint", "SetMaxPoint")
// SurroundGamma
->Event("SetSurroundGamma", &DisplayMapperComponentRequestBus::Events::SetSurroundGamma)
->Event("GetSurroundGamma", &DisplayMapperComponentRequestBus::Events::GetSurroundGamma)
->VirtualProperty("SurroundGamma", "GetSurroundGamma", "SetSurroundGamma")
// Gamma
->Event("SetGamma", &DisplayMapperComponentRequestBus::Events::SetGamma)
->Event("GetGamma", &DisplayMapperComponentRequestBus::Events::GetGamma)
->VirtualProperty("Gamma", "GetGamma", "SetGamma")
;
}
}
void DisplayMapperComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
@@ -57,10 +122,14 @@ namespace AZ
void DisplayMapperComponentController::Activate(EntityId entityId)
{
m_entityId = entityId;
DisplayMapperComponentRequestBus::Handler::BusConnect(m_entityId);
}
void DisplayMapperComponentController::Deactivate()
{
DisplayMapperComponentRequestBus::Handler::BusDisconnect(m_entityId);
m_postProcessInterface = nullptr;
m_entityId.SetInvalid();
}
@@ -76,6 +145,219 @@ namespace AZ
return m_configuration;
}
void DisplayMapperComponentController::LoadPreset(OutputDeviceTransformType preset)
{
AcesParameterOverrides propertyOverrides;
propertyOverrides.m_preset = preset;
propertyOverrides.m_overrideDefaults = true;
propertyOverrides.LoadPreset();
SetAcesParameterOverrides(propertyOverrides);
}
void DisplayMapperComponentController::SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType)
{
if (m_configuration.m_displayMapperOperation != displayMapperOperationType)
{
m_configuration.m_displayMapperOperation = displayMapperOperationType;
OnConfigChanged();
DisplayMapperComponentNotificationBus::Broadcast(
&DisplayMapperComponentNotificationBus::Handler::OnDisplayMapperOperationTypeUpdated,
m_configuration.m_displayMapperOperation);
}
}
DisplayMapperOperationType DisplayMapperComponentController::GetDisplayMapperOperationType() const
{
return m_configuration.m_displayMapperOperation;
}
void DisplayMapperComponentController::SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides)
{
m_configuration.m_acesParameterOverrides = parameterOverrides;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
DisplayMapperComponentNotificationBus::Broadcast(
&DisplayMapperComponentNotificationBus::Handler::OnAcesParameterOverridesUpdated,
m_configuration.m_acesParameterOverrides);
}
const AcesParameterOverrides& DisplayMapperComponentController::GetAcesParameterOverrides() const
{
return m_configuration.m_acesParameterOverrides;
}
void DisplayMapperComponentController::SetOverrideAcesParameters(bool value)
{
if (m_configuration.m_acesParameterOverrides.m_overrideDefaults == value)
{
return; // prevents flickering when set via TrackView
}
m_configuration.m_acesParameterOverrides.m_overrideDefaults = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
bool DisplayMapperComponentController::GetOverrideAcesParameters() const
{
return m_configuration.m_acesParameterOverrides.m_overrideDefaults;
}
void DisplayMapperComponentController::SetAlterSurround(bool value)
{
if (m_configuration.m_acesParameterOverrides.m_alterSurround != value)
{
return; // prevents flickering when set via TrackView
}
m_configuration.m_acesParameterOverrides.m_alterSurround = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
bool DisplayMapperComponentController::GetAlterSurround() const
{
return m_configuration.m_acesParameterOverrides.m_alterSurround;
}
void DisplayMapperComponentController::SetApplyDesaturation(bool value)
{
if (m_configuration.m_acesParameterOverrides.m_applyDesaturation != value)
{
return; // prevents flickering when set via TrackView
}
m_configuration.m_acesParameterOverrides.m_applyDesaturation = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
bool DisplayMapperComponentController::GetApplyDesaturation() const
{
return m_configuration.m_acesParameterOverrides.m_applyDesaturation;
}
void DisplayMapperComponentController::SetApplyCATD60toD65(bool value)
{
if (m_configuration.m_acesParameterOverrides.m_applyCATD60toD65 != value)
{
return; // prevents flickering when set via TrackView
}
m_configuration.m_acesParameterOverrides.m_applyCATD60toD65 = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
bool DisplayMapperComponentController::GetApplyCATD60toD65() const
{
return m_configuration.m_acesParameterOverrides.m_applyCATD60toD65;
}
void DisplayMapperComponentController::SetCinemaLimitsBlack(float value)
{
m_configuration.m_acesParameterOverrides.m_cinemaLimitsBlack = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
float DisplayMapperComponentController::GetCinemaLimitsBlack() const
{
return m_configuration.m_acesParameterOverrides.m_cinemaLimitsBlack;
}
void DisplayMapperComponentController::SetCinemaLimitsWhite(float value)
{
m_configuration.m_acesParameterOverrides.m_cinemaLimitsWhite = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
float DisplayMapperComponentController::GetCinemaLimitsWhite() const
{
return m_configuration.m_acesParameterOverrides.m_cinemaLimitsWhite;
}
void DisplayMapperComponentController::SetMinPoint(float value)
{
m_configuration.m_acesParameterOverrides.m_minPoint = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
float DisplayMapperComponentController::GetMinPoint() const
{
return m_configuration.m_acesParameterOverrides.m_minPoint;
}
void DisplayMapperComponentController::SetMidPoint(float value)
{
m_configuration.m_acesParameterOverrides.m_midPoint = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
float DisplayMapperComponentController::GetMidPoint() const
{
return m_configuration.m_acesParameterOverrides.m_midPoint;
}
void DisplayMapperComponentController::SetMaxPoint(float value)
{
m_configuration.m_acesParameterOverrides.m_maxPoint = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
float DisplayMapperComponentController::GetMaxPoint() const
{
return m_configuration.m_acesParameterOverrides.m_maxPoint;
}
void DisplayMapperComponentController::SetSurroundGamma(float value)
{
m_configuration.m_acesParameterOverrides.m_surroundGamma = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
float DisplayMapperComponentController::GetSurroundGamma() const
{
return m_configuration.m_acesParameterOverrides.m_surroundGamma;
}
void DisplayMapperComponentController::SetGamma(float value)
{
m_configuration.m_acesParameterOverrides.m_gamma = value;
if (m_configuration.m_displayMapperOperation == DisplayMapperOperationType::Aces)
{
OnConfigChanged();
}
}
float DisplayMapperComponentController::GetGamma() const
{
return m_configuration.m_acesParameterOverrides.m_gamma;
}
void DisplayMapperComponentController::OnConfigChanged()
{
// Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene.
@@ -12,10 +12,12 @@
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TransformBus.h>
#include <AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConfig.h>
#include <AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h>
#include <Atom/Feature/PostProcess/PostProcessSettingsInterface.h>
#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
@@ -24,7 +26,10 @@ namespace AZ
{
namespace Render
{
struct AcesParameterOverrides;
class DisplayMapperComponentController final
: DisplayMapperComponentRequestBus::Handler
{
public:
friend class EditorDisplayMapperComponent;
@@ -43,6 +48,35 @@ namespace AZ
void SetConfiguration(const DisplayMapperComponentConfig& config);
const DisplayMapperComponentConfig& GetConfiguration() const;
//! DisplayMapperComponentRequestBus::Handler overrides...
void LoadPreset(OutputDeviceTransformType preset) override;
void SetDisplayMapperOperationType(DisplayMapperOperationType displayMapperOperationType) override;
DisplayMapperOperationType GetDisplayMapperOperationType() const override;
void SetAcesParameterOverrides(const AcesParameterOverrides& parameterOverrides) override;
const AcesParameterOverrides& GetAcesParameterOverrides() const override;
void SetOverrideAcesParameters(bool value) override;
bool GetOverrideAcesParameters() const override;
void SetAlterSurround(bool value) override;
bool GetAlterSurround() const override;
void SetApplyDesaturation(bool value) override;
bool GetApplyDesaturation() const override;
void SetApplyCATD60toD65(bool value) override;
bool GetApplyCATD60toD65() const override;
void SetCinemaLimitsBlack(float value) override;
float GetCinemaLimitsBlack() const override;
void SetCinemaLimitsWhite(float value) override;
float GetCinemaLimitsWhite() const override;
void SetMinPoint(float value) override;
float GetMinPoint() const override;
void SetMidPoint(float value) override;
float GetMidPoint() const override;
void SetMaxPoint(float value) override;
float GetMaxPoint() const override;
void SetSurroundGamma(float value) override;
float GetSurroundGamma() const override;
void SetGamma(float value) override;
float GetGamma() const override;
private:
AZ_DISABLE_COPY(DisplayMapperComponentController);
@@ -10,10 +10,9 @@
*
*/
#include "Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h"
#include <AzCore/RTTI/BehaviorContext.h>
#include <PostProcess/DisplayMapper/EditorDisplayMapperComponent.h>
#include <Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h>
namespace AZ
{
@@ -54,54 +53,89 @@ namespace AZ
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
// m_overrideDefaults
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_overrideDefaults, "Override Defaults",
"When enabled allows parameter overrides for ACES configuration")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
// m_alterSurround
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_alterSurround, "Alter Surround",
"Apply gamma adjustment to compensate for dim surround")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
// m_applyDesaturation
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_applyDesaturation, "Alter Desaturation",
"Apply desaturation to compensate for luminance difference")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
// m_applyCATD60toD65
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &AcesParameterOverrides::m_applyCATD60toD65, "Alter CAT D60 to D65",
"Apply Color appearance transform (CAT) from ACES white point to assumed observer adapted white point")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
// m_cinemaLimitsBlack
->DataElement(
Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsBlack,
Edit::UIHandlers::Slider, &AcesParameterOverrides::m_cinemaLimitsBlack,
"Cinema Limit (black)",
"Reference black luminance value")
->Attribute(AZ::Edit::Attributes::Min, 0.02f)
->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_cinemaLimitsWhite)
->Attribute(AZ::Edit::Attributes::Step, 0.005f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
// m_cinemaLimitsWhite
->DataElement(
Edit::UIHandlers::Default, &AcesParameterOverrides::m_cinemaLimitsWhite,
Edit::UIHandlers::Slider, &AcesParameterOverrides::m_cinemaLimitsWhite,
"Cinema Limit (white)",
"Reference white luminance value")
->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_cinemaLimitsBlack)
->Attribute(AZ::Edit::Attributes::Max, 4000.f)
->Attribute(AZ::Edit::Attributes::Step, 0.005f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
// m_minPoint
->DataElement(
Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_minPoint, "Min Point (luminance)",
Edit::UIHandlers::Slider, &AcesParameterOverrides::m_minPoint, "Min Point (luminance)",
"Linear extension below this")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(AZ::Edit::Attributes::Min, 0.002f)
->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_midPoint)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
// m_midPoint
->DataElement(Edit::UIHandlers::Slider, &AcesParameterOverrides::m_midPoint,
"Mid Point (luminance)", "Middle gray")
->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_minPoint)
->Attribute(AZ::Edit::Attributes::Max, &AcesParameterOverrides::m_maxPoint)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
// m_maxPoint
->DataElement(
Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_midPoint, "Mid Point (luminance)",
"Middle gray")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(
Edit::UIHandlers::Vector2, &AcesParameterOverrides::m_maxPoint, "Max Point (luminance)",
Edit::UIHandlers::Slider, &AcesParameterOverrides::m_maxPoint, "Max Point (luminance)",
"Linear extension above this")
->Attribute(AZ::Edit::Attributes::Min, &AcesParameterOverrides::m_midPoint)
->Attribute(AZ::Edit::Attributes::Max, 4000.f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues)
// m_surroundGamma
->DataElement(
AZ::Edit::UIHandlers::Slider, &AcesParameterOverrides::m_surroundGamma, "Surround Gamma",
"Gamma adjustment to be applied to compensate for the condition of the viewing environment")
->Attribute(AZ::Edit::Attributes::Min, 0.6f)
->Attribute(AZ::Edit::Attributes::Max, 1.2f)
->Attribute(AZ::Edit::Attributes::Step, 0.005f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
// m_gamma
->DataElement(
AZ::Edit::UIHandlers::Default, &AcesParameterOverrides::m_surroundGamma, "Surround Gamma",
"Gamma adjustment to be applied to compensate for the condition of the viewing environment")
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->DataElement(
AZ::Edit::UIHandlers::Default, &AcesParameterOverrides::m_gamma, "Gamma",
AZ::Edit::UIHandlers::Slider, &AcesParameterOverrides::m_gamma, "Gamma",
"Optional gamma value that is applied as basic gamma curve OETF")
->Attribute(AZ::Edit::Attributes::Min, 0.2f)
->Attribute(AZ::Edit::Attributes::Max, 4.0f)
->Attribute(AZ::Edit::Attributes::Step, 0.005f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
// Load preset group
@@ -145,6 +179,8 @@ namespace AZ
if (auto behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<EditorDisplayMapperComponent>()->RequestBus("DisplayMapperComponentRequestBus");
behaviorContext->ConstantProperty("EditorDisplayMapperComponentTypeId", BehaviorConstant(Uuid(EditorDisplayMapperComponentTypeId)))
->Attribute(AZ::Script::Attributes::Module, "render")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation);
@@ -39,6 +39,7 @@ namespace AZ
serializeContext->Class<EditorReflectionProbeComponent, BaseClass>()
->Version(2, ConvertToEditorRenderComponentAdapter<1>)
->Field("useBakedCubemap", &EditorReflectionProbeComponent::m_useBakedCubemap)
->Field("bakedCubeMapQualityLevel", &EditorReflectionProbeComponent::m_bakedCubeMapQualityLevel)
->Field("bakedCubeMapRelativePath", &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath)
->Field("authoredCubeMapAsset", &EditorReflectionProbeComponent::m_authoredCubeMapAsset)
;
@@ -67,6 +68,13 @@ namespace AZ
->DataElement(AZ::Edit::UIHandlers::Default, &EditorReflectionProbeComponent::m_useBakedCubemap, "Use Baked Cubemap", "Selects between a cubemap that captures the environment at location in the scene or a preauthored cubemap")
->Attribute(AZ::Edit::Attributes::ChangeValidate, &EditorReflectionProbeComponent::OnUseBakedCubemapValidate)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnUseBakedCubemapChanged)
->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorReflectionProbeComponent::m_bakedCubeMapQualityLevel, "Baked Cubemap Quality", "Resolution of the baked cubemap")
->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting)
->EnumAttribute(BakedCubeMapQualityLevel::VeryLow, "Very Low")
->EnumAttribute(BakedCubeMapQualityLevel::Low, "Low")
->EnumAttribute(BakedCubeMapQualityLevel::Medium, "Medium")
->EnumAttribute(BakedCubeMapQualityLevel::High, "High")
->EnumAttribute(BakedCubeMapQualityLevel::VeryHigh, "Very High")
->DataElement(AZ::Edit::UIHandlers::MultiLineEdit, &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath, "Baked Cubemap Path", "Baked Cubemap Path")
->Attribute(AZ::Edit::Attributes::ReadOnly, true)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting)
@@ -332,6 +340,12 @@ namespace AZ
// clear it to force the generation of a new filename
cubeMapRelativePath.clear();
}
// if the quality level changed we need to generate a new filename
if (m_controller.m_configuration.m_bakedCubeMapQualityLevel != m_bakedCubeMapQualityLevel)
{
cubeMapRelativePath.clear();
}
}
// build a new cubemap path if necessary
@@ -345,7 +359,10 @@ namespace AZ
AZStd::string uuidString;
uuid.ToString(uuidString);
cubeMapRelativePath = "ReflectionProbes/" + entity->GetName() + "_" + uuidString + "_iblspecularcm.dds";
// determine the filemask suffix from the cubemap quality level setting
AZStd::string fileSuffix = BakedCubeMapFileSuffixes[aznumeric_cast<uint32_t>(m_bakedCubeMapQualityLevel)];
cubeMapRelativePath = "ReflectionProbes/" + entity->GetName() + "_" + uuidString + fileSuffix;
// replace any invalid filename characters
auto invalidCharacters = [](char letter)
@@ -384,6 +401,7 @@ namespace AZ
// save the relative source path in the configuration
AzToolsFramework::ScopedUndoBatch undoBatch("Cubemap path changed.");
m_controller.m_configuration.m_bakedCubeMapRelativePath = cubeMapRelativePath;
m_controller.m_configuration.m_bakedCubeMapQualityLevel = m_bakedCubeMapQualityLevel;
SetDirty();
// update UI cubemap path display
@@ -77,6 +77,7 @@ namespace AZ
// UI settings
// the user can select between a baked cubemap or an authored cubemap asset
bool m_useBakedCubemap = true;
BakedCubeMapQualityLevel m_bakedCubeMapQualityLevel = BakedCubeMapQualityLevel::Medium;
AZStd::string m_bakedCubeMapRelativePath;
Data::Asset<RPI::StreamingImageAsset> m_bakedCubeMapAsset;
Data::Asset<RPI::StreamingImageAsset> m_authoredCubeMapAsset;
@@ -46,6 +46,7 @@ namespace AZ
->Field("InnerLength", &ReflectionProbeComponentConfig::m_innerLength)
->Field("InnerWidth", &ReflectionProbeComponentConfig::m_innerWidth)
->Field("UseBakedCubemap", &ReflectionProbeComponentConfig::m_useBakedCubemap)
->Field("BakedCubemapQualityLevel", &ReflectionProbeComponentConfig::m_bakedCubeMapQualityLevel)
->Field("BakedCubeMapRelativePath", &ReflectionProbeComponentConfig::m_bakedCubeMapRelativePath)
->Field("BakedCubeMapAsset", &ReflectionProbeComponentConfig::m_bakedCubeMapAsset)
->Field("AuthoredCubeMapAsset", &ReflectionProbeComponentConfig::m_authoredCubeMapAsset)
@@ -24,6 +24,29 @@ namespace AZ
{
namespace Render
{
enum class BakedCubeMapQualityLevel : uint32_t
{
VeryLow, // 64
Low, // 128
Medium, // 256
High, // 512
VeryHigh, // 1024
Count
};
static const char* BakedCubeMapFileSuffixes[] =
{
"_iblspecularcm64.dds",
"_iblspecularcm128.dds",
"_iblspecularcm256.dds",
"_iblspecularcm512.dds",
"_iblspecularcm1024.dds"
};
static_assert(AZ_ARRAY_SIZE(BakedCubeMapFileSuffixes) == aznumeric_cast<uint32_t>(BakedCubeMapQualityLevel::Count),
"BakedCubeMapFileSuffixes must have the same number of entries as BakedCubeMapQualityLevel");
class ReflectionProbeComponentConfig final
: public AZ::ComponentConfig
{
@@ -43,6 +66,7 @@ namespace AZ
bool m_showVisualization = true;
bool m_useBakedCubemap = true;
BakedCubeMapQualityLevel m_bakedCubeMapQualityLevel = BakedCubeMapQualityLevel::Medium;
AZStd::string m_bakedCubeMapRelativePath;
Data::Asset<RPI::StreamingImageAsset> m_bakedCubeMapAsset;
Data::Asset<RPI::StreamingImageAsset> m_authoredCubeMapAsset;
@@ -36,6 +36,7 @@ set(FILES
Include/AtomLyIntegration/CommonFeatures/PostProcess/Bloom/BloomComponentConfig.h
Include/AtomLyIntegration/CommonFeatures/PostProcess/DepthOfField/DepthOfFieldBus.h
Include/AtomLyIntegration/CommonFeatures/PostProcess/DepthOfField/DepthOfFieldComponentConfig.h
Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h
Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConfig.h
Include/AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConstants.h
Include/AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlBus.h

Some files were not shown because too many files have changed in this diff Show More