Merge branch 'main' into TIF/Runtime

This commit is contained in:
jonawals
2021-06-08 14:23:05 +01:00
718 changed files with 26957 additions and 17896 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 = [
@@ -137,5 +137,6 @@ enum class AnimParamType
Invalid = static_cast<int>(0xFFFFFFFF)
};
static const int OLD_APARAM_USER = 100;
#endif // CRYINCLUDE_CRYCOMMON_MAESTRO_TYPES_ANIMPARAMTYPE_H
@@ -1,14 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// If you make changes in ICryPak.h, make changes here, to dirty the PCH.
#include "CrySystem_precompiled.h"
+1 -1
View File
@@ -561,7 +561,7 @@ void DebugCallStack::LogExceptionInfo(EXCEPTION_POINTERS* pex)
if (pex)
{
MINIDUMP_TYPE mdumpValue;
MINIDUMP_TYPE mdumpValue = MiniDumpNormal;
bool bDump = true;
switch (g_cvars.sys_dump_type)
{
+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
@@ -66,7 +66,7 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
if (pSystem && !pSystem->IsQuitting())
{
LRESULT result;
LRESULT result = 0;
bool bAny = false;
for (std::vector<IWindowMessageHandler*>::const_iterator it = pSystem->m_windowMessageHandlers.begin(); it != pSystem->m_windowMessageHandlers.end(); ++it)
{
+2 -2
View File
@@ -634,7 +634,7 @@ ICVar* CSystem::attachVariable (const char* szVarName, int* pContainer, const ch
IConsole* pConsole = GetIConsole();
ICVar* pOldVar = pConsole->GetCVar (szVarName);
int nDefault;
int nDefault = 0;
if (pOldVar)
{
nDefault = pOldVar->GetIVal();
@@ -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());
@@ -75,6 +75,5 @@ set(FILES
ViewSystem/View.h
ViewSystem/ViewSystem.cpp
ViewSystem/ViewSystem.h
CrySystem_precompiled.cpp
WindowsErrorReporting.cpp
)
+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;
};
/**
@@ -127,13 +127,14 @@ namespace AZ
*/
class EditContext
{
public:
/// @cond EXCLUDE_DOCS
class ClassBuilder;
class EnumBuilder;
using ClassInfo = ClassBuilder; ///< @deprecated Use EditContext::ClassBuilder
using EnumInfo = EnumBuilder; ///< @deprecated Use EditContext::EnumBuilder
/// @endcond
public:
AZ_CLASS_ALLOCATOR(EditContext, SystemAllocator, 0);
/**
@@ -186,6 +187,7 @@ namespace AZ
* look at the unit tests and example to see use cases.
*
*/
public:
class ClassBuilder
{
friend EditContext;
@@ -399,6 +401,7 @@ namespace AZ
EnumBuilder* Value(const char* name, E value);
};
private:
typedef AZStd::list<Edit::ClassData> ClassDataListType;
typedef AZStd::unordered_map<AZ::Uuid, Edit::ElementData> EnumDataMapType;
@@ -28,7 +28,13 @@ namespace AZ
{
namespace IdUtils
{
template<typename IdType>
/**
* \param AllowDuplicates - If true allows the same id to be registered multiple times,
with the newer value overwriting the stored value. If false, duplicates are not allowed and
the first stored value is kept.The default is false.
*/
template<typename IdType, bool AllowDuplicates = false>
struct Remapper
{
/**
@@ -138,14 +144,18 @@ namespace AZ
* \param context - The serialize context for enumerating the @classPtr elements
*/
template<typename T, typename MapType>
static void GenerateNewIdsAndFixRefs(T* object, MapType& newIdMap, AZ::SerializeContext* context = nullptr)
static void GenerateNewIdsAndFixRefs(
T* object, MapType& newIdMap, AZ::SerializeContext* context = nullptr)
{
if (!context)
{
AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationRequests::GetSerializeContext);
if (!context)
{
AZ_Error("Serialization", false, "No serialize context provided! Failed to get component application default serialize context! ComponentApp is not started or input serialize context should not be null!");
AZ_Error(
"Serialization", false,
"No serialize context provided! Failed to get component application default serialize context! ComponentApp is "
"not started or input serialize context should not be null!");
return;
}
}
@@ -156,8 +166,16 @@ namespace AZ
{
if (idGenerator)
{
auto it = newIdMap.emplace(originalId, idGenerator());
return it.first->second;
if constexpr(AllowDuplicates)
{
auto it = newIdMap.insert_or_assign(originalId, idGenerator());
return it.first->second;
}
else
{
auto it = newIdMap.emplace(originalId, idGenerator());
return it.first->second;
}
}
return originalId;
}
@@ -30,8 +30,10 @@ namespace AZ
bool m_isModifiedContainer;
};
template<typename IdType>
unsigned int Remapper<IdType>::RemapIds(void* classPtr, const AZ::Uuid& classUuid, const typename Remapper<IdType>::IdMapper& mapper, AZ::SerializeContext* context, bool replaceId)
template<typename IdType, bool AllowDuplicates>
unsigned int Remapper<IdType, AllowDuplicates>::RemapIds(
void* classPtr, const AZ::Uuid& classUuid, const typename Remapper<IdType, AllowDuplicates>::IdMapper& mapper,
AZ::SerializeContext* context, bool replaceId)
{
if (!context)
{
@@ -152,16 +154,18 @@ namespace AZ
return replaced;
}
template<typename IdType>
unsigned int Remapper<IdType>::ReplaceIdsAndIdRefs(void* classPtr, const AZ::Uuid& classUuid, const IdMapper& mapper, AZ::SerializeContext* context /*= nullptr*/)
template<typename IdType, bool AllowDuplicates>
unsigned int Remapper<IdType, AllowDuplicates>::ReplaceIdsAndIdRefs(void* classPtr, const AZ::Uuid& classUuid, const IdMapper& mapper, AZ::SerializeContext* context /*= nullptr*/)
{
unsigned int replaced = RemapIds(classPtr, classUuid, mapper, context, true);
replaced += RemapIds(classPtr, classUuid, mapper, context, false);
return replaced;
}
template<typename IdType>
unsigned int Remapper<IdType>::RemapIdsAndIdRefs(void* classPtr, const AZ::Uuid& classUuid, const typename Remapper<IdType>::IdReplacer& mapper, AZ::SerializeContext* context)
template<typename IdType, bool AllowDuplicates>
unsigned int Remapper<IdType, AllowDuplicates>::RemapIdsAndIdRefs(
void* classPtr, const AZ::Uuid& classUuid, const typename Remapper<IdType, AllowDuplicates>::IdReplacer& mapper,
AZ::SerializeContext* context)
{
if (!context)
{
@@ -101,6 +101,9 @@ namespace AZ
class SerializeContext
: public ReflectContext
{
static const unsigned int VersionClassDeprecated = (unsigned int)-1;
public:
/// @cond EXCLUDE_DOCS
friend class EditContext;
class ClassBuilder;
@@ -108,9 +111,6 @@ namespace AZ
/// @endcond
class EnumBuilder;
static const unsigned int VersionClassDeprecated = (unsigned int)-1;
public:
class ClassData;
struct EnumerateInstanceCallContext;
struct ClassElement;
@@ -1131,6 +1131,7 @@ namespace AZ
* ->Version(3,&MyVersionConverter)
* ->Field("data",&MyStruct::m_data);
*/
public:
class ClassBuilder
{
friend class SerializeContext;
@@ -1330,7 +1331,8 @@ namespace AZ
AZStd::vector<AttributeSharedPair, AZStdFunctorAllocator>* m_currentAttributes = nullptr;
};
EditContext* m_editContext; ///< Pointer to optional edit context.
private:
EditContext* m_editContext; ///< Pointer to optional edit context.
UuidToClassMap m_uuidMap; ///< Map for all class in this serialize context
AZStd::unordered_multimap<AZ::Crc32, AZ::Uuid> m_classNameToUuid; /// Map all class names to their uuid
AZStd::unordered_multimap<Uuid, GenericClassInfo*> m_uuidGenericMap; ///< Uuid to ClassData map of reflected classes with GenericTypeInfo
@@ -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());
@@ -971,6 +971,10 @@ namespace AZ
*/
void RestoreCachedInstances();
/// Returns data flags for use when instantiating an instance of this slice.
/// These data flags include those harvested from the entire slice ancestry.
const DataFlagsPerEntity& GetDataFlagsForInstances() const;
protected:
//////////////////////////////////////////////////////////////////////////
@@ -1004,9 +1008,6 @@ namespace AZ
DataFlagsPerEntity* GetCorrectBundleOfDataFlags(EntityId entityId);
const DataFlagsPerEntity* GetCorrectBundleOfDataFlags(EntityId entityId) const;
/// Returns data flags for use when instantiating an instance of this slice.
/// These data flags include those harvested from the entire slice ancestry.
const DataFlagsPerEntity& GetDataFlagsForInstances() const;
void BuildDataFlagsForInstances();
/**
+3
View File
@@ -21,11 +21,14 @@ namespace AZStd
using std::asin;
using std::atan;
using std::atan2;
using std::ceil;
using std::cos;
using std::exp2;
using std::floor;
using std::fmod;
using std::round;
using std::sin;
using std::sqrt;
using std::tan;
using std::trunc;
} // namespace AZStd
@@ -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.
@@ -14,6 +14,9 @@
#include <sys/syslimits.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <AzCore/std/typetraits/underlying_type.h>
namespace AZ
{
@@ -22,9 +25,10 @@ namespace AZ
namespace Internal
{
using SizeType = AZ::u64;
using SeekSizeType = AZ::s64;
using FileHandleType = int;
}
namespace PosixInternal
{
enum class OpenFlags : int
@@ -36,7 +40,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.
@@ -13,9 +13,10 @@
#include <AzCore/Module/DynamicModuleHandle.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/Utils/Utils.h>
#include <dlfcn.h>
#include <libgen.h>
@@ -61,10 +62,11 @@ namespace AZ
// If it doesn't attempt to append the path to the executable path
if (!AZ::IO::SystemFile::Exists(fullFilePath.c_str()))
{
auto candidatePath = Platform::GetModulePath() / fullFilePath;
AZ::IO::FixedMaxPath candidatePath = Platform::GetModulePath() / fullFilePath;
if (AZ::IO::SystemFile::Exists(candidatePath.c_str()))
{
fullFilePath = candidatePath;
m_fileName.assign(candidatePath.Native().c_str(), candidatePath.Native().size());
return;
}
}
@@ -74,19 +76,26 @@ namespace AZ
{
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
if(AZ::IO::FixedMaxPath projectModulePath;
if (AZ::IO::FixedMaxPath projectModulePath;
settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
{
projectModulePath /= fullFilePath;
if (AZ::IO::SystemFile::Exists(projectModulePath.c_str()))
{
fullFilePath = projectModulePath;
m_fileName.assign(projectModulePath.c_str(), projectModulePath.Native().size());
}
}
}
}
m_fileName = AZStd::string_view{fullFilePath.Native()};
else
{
// The module does exist (in 'cwd'), but still needs to be an absolute path for the module to be loaded.
AZStd::optional<AZ::IO::FixedMaxPathString> absPathOptional = AZ::Utils::ConvertToAbsolutePath(m_fileName);
if (absPathOptional.has_value())
{
m_fileName.assign(absPathOptional->c_str(), absPathOptional->size());
}
}
}
~DynamicModuleHandleUnixLike() override
@@ -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.
@@ -24,9 +24,9 @@ namespace AZ
: public DynamicModuleHandle
{
public:
AZ_CLASS_ALLOCATOR(DynamicModuleHandleWindows, OSAllocator, 0)
AZ_CLASS_ALLOCATOR(DynamicModuleHandleWindows, OSAllocator, 0);
DynamicModuleHandleWindows(const char* fullFileName)
DynamicModuleHandleWindows(const char* fullFileName)
: DynamicModuleHandle(fullFileName)
, m_handle(nullptr)
{
@@ -52,6 +52,7 @@ namespace AZ
if (AZ::IO::SystemFile::Exists(candidatePath.c_str()))
{
m_fileName.assign(candidatePath.Native().c_str(), candidatePath.Native().size());
return;
}
}
}
@@ -65,7 +66,7 @@ namespace AZ
// Therefore an existence check is needed
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
if(AZ::IO::FixedMaxPath projectModulePath;
if (AZ::IO::FixedMaxPath projectModulePath;
settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
{
projectModulePath /= AZStd::string_view(m_fileName);
@@ -76,6 +77,15 @@ namespace AZ
}
}
}
else
{
// The module does exist (in 'cwd'), but still needs to be an absolute path for the module to be loaded.
AZStd::optional<AZ::IO::FixedMaxPathString> absPathOptional = AZ::Utils::ConvertToAbsolutePath(m_fileName);
if (absPathOptional.has_value())
{
m_fileName.assign(absPathOptional->c_str(), absPathOptional->size());
}
}
}
~DynamicModuleHandleWindows() override
+8 -8
View File
@@ -1914,7 +1914,7 @@ namespace UnitTest
TEST_F(String, StringView_CompareIsConstexpr)
{
using TypeParam = char;
auto MakeCompileTimeString1 = []() constexpr -> const TypeParam*
auto ThisTestMakeCompileTimeString1 = []() constexpr -> const TypeParam*
{
return "HelloWorld";
};
@@ -1922,7 +1922,7 @@ namespace UnitTest
{
return "HelloPearl";
};
constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1();
constexpr const TypeParam* compileTimeString1 = ThisTestMakeCompileTimeString1();
constexpr const TypeParam* compileTimeString2 = MakeCompileTimeString2();
constexpr basic_string_view<TypeParam> lhsView(compileTimeString1);
constexpr basic_string_view<TypeParam> rhsView(compileTimeString2);
@@ -1937,11 +1937,11 @@ namespace UnitTest
TEST_F(String, StringView_CompareOperatorsAreConstexpr)
{
using TypeParam = char;
auto MakeCompileTimeString1 = []() constexpr -> const TypeParam*
auto TestMakeCompileTimeString1 = []() constexpr -> const TypeParam*
{
return "HelloWorld";
};
constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1();
constexpr const TypeParam* compileTimeString1 = TestMakeCompileTimeString1();
constexpr basic_string_view<TypeParam> compareView(compileTimeString1);
static_assert(compareView == "HelloWorld", "string_view operator== comparison has failed");
static_assert(compareView != "MadWorld", "string_view operator!= comparison has failed");
@@ -1955,7 +1955,7 @@ namespace UnitTest
{
auto swap_test_func = []() constexpr -> basic_string_view<TypeParam>
{
constexpr auto MakeCompileTimeString1 = []() constexpr -> const TypeParam*
constexpr auto ThisTestMakeCompileTimeString1 = []() constexpr -> const TypeParam*
{
if constexpr (AZStd::is_same_v<TypeParam, char>)
{
@@ -1977,7 +1977,7 @@ namespace UnitTest
return L"InuWorld";
}
};
constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1();
constexpr const TypeParam* compileTimeString1 = ThisTestMakeCompileTimeString1();
constexpr const TypeParam* compileTimeString2 = MakeCompileTimeString2();
basic_string_view<TypeParam> lhsView(compileTimeString1);
basic_string_view<TypeParam> rhsView(compileTimeString2);
@@ -2001,7 +2001,7 @@ namespace UnitTest
TYPED_TEST(BasicStringViewConstexprFixture, HashString_FunctionIsConstexpr)
{
auto MakeCompileTimeString1 = []() constexpr -> const TypeParam*
auto ThisTestMakeCompileTimeString1 = []() constexpr -> const TypeParam*
{
if constexpr (AZStd::is_same_v<TypeParam, char>)
{
@@ -2012,7 +2012,7 @@ namespace UnitTest
return L"HelloWorld";
}
};
constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1();
constexpr const TypeParam* compileTimeString1 = ThisTestMakeCompileTimeString1();
constexpr basic_string_view<TypeParam> hashView(compileTimeString1);
constexpr size_t compileHash = AZStd::hash<basic_string_view<TypeParam>>{}(hashView);
static_assert(compileHash != 0, "Hash of \"HelloWorld\" should not be 0");
+2 -1
View File
@@ -395,7 +395,8 @@ namespace UnitTest
}
else
{
int result1, result2;
int result1 = 0;
int result2 = 0;
Job* job1 = aznew FibonacciJob2(m_n - 1, &result1, m_context);
Job* job2 = aznew FibonacciJob2(m_n - 2, &result2, m_context);
StartAsChild(job1);
@@ -59,7 +59,7 @@ namespace UnitTest
TEST(MATH_Matrix4x4, TestCreateFrom)
{
float testFloats[] =
float thisTestFloats[] =
{
1.0f, 2.0f, 3.0f, 4.0f,
5.0f, 6.0f, 7.0f, 8.0f,
@@ -67,20 +67,20 @@ namespace UnitTest
13.0f, 14.0f, 15.0f, 16.0f
};
float testFloatMtx[16];
Matrix4x4 m1 = Matrix4x4::CreateFromRowMajorFloat16(testFloats);
Matrix4x4 m1 = Matrix4x4::CreateFromRowMajorFloat16(thisTestFloats);
AZ_TEST_ASSERT(m1.GetRow(0) == Vector4(1.0f, 2.0f, 3.0f, 4.0f));
AZ_TEST_ASSERT(m1.GetRow(1) == Vector4(5.0f, 6.0f, 7.0f, 8.0f));
AZ_TEST_ASSERT(m1.GetRow(2) == Vector4(9.0f, 10.0f, 11.0f, 12.0f));
AZ_TEST_ASSERT(m1.GetRow(3) == Vector4(13.0f, 14.0f, 15.0f, 16.0f));
m1.StoreToRowMajorFloat16(testFloatMtx);
AZ_TEST_ASSERT(memcmp(testFloatMtx, testFloats, sizeof(testFloatMtx)) == 0);
m1 = Matrix4x4::CreateFromColumnMajorFloat16(testFloats);
AZ_TEST_ASSERT(memcmp(testFloatMtx, thisTestFloats, sizeof(testFloatMtx)) == 0);
m1 = Matrix4x4::CreateFromColumnMajorFloat16(thisTestFloats);
AZ_TEST_ASSERT(m1.GetRow(0) == Vector4(1.0f, 5.0f, 9.0f, 13.0f));
AZ_TEST_ASSERT(m1.GetRow(1) == Vector4(2.0f, 6.0f, 10.0f, 14.0f));
AZ_TEST_ASSERT(m1.GetRow(2) == Vector4(3.0f, 7.0f, 11.0f, 15.0f));
AZ_TEST_ASSERT(m1.GetRow(3) == Vector4(4.0f, 8.0f, 12.0f, 16.0f));
m1.StoreToColumnMajorFloat16(testFloatMtx);
AZ_TEST_ASSERT(memcmp(testFloatMtx, testFloats, sizeof(testFloatMtx)) == 0);
AZ_TEST_ASSERT(memcmp(testFloatMtx, thisTestFloats, sizeof(testFloatMtx)) == 0);
}
TEST(MATH_Matrix4x4, TestCreateFromMatrix3x4)
+12 -12
View File
@@ -119,10 +119,10 @@ namespace UnitTest
TEST(MATH_Obb, Contains)
{
const Vector3 position(1.0f, 2.0f, 3.0f);
const Quaternion rotation = Quaternion::CreateRotationZ(DegToRad(30.0f));
const Vector3 halfLengths(2.0f, 1.0f, 2.5f);
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths);
const Vector3 testPosition(1.0f, 2.0f, 3.0f);
const Quaternion testRotation = Quaternion::CreateRotationZ(DegToRad(30.0f));
const Vector3 testHalfLengths(2.0f, 1.0f, 2.5f);
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(testPosition, testRotation, testHalfLengths);
// test some pairs of points which should be just either side of the Obb boundary
EXPECT_TRUE(obb.Contains(Vector3(1.35f, 3.35f, 3.5f)));
EXPECT_FALSE(obb.Contains(Vector3(1.35f, 3.4f, 3.5f)));
@@ -134,10 +134,10 @@ namespace UnitTest
TEST(MATH_Obb, GetDistance)
{
const Vector3 position(5.0f, 3.0f, 2.0f);
const Quaternion rotation = Quaternion::CreateRotationX(DegToRad(60.0f));
const Vector3 halfLengths(0.5f, 2.0f, 1.5f);
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths);
const Vector3 testPosition(5.0f, 3.0f, 2.0f);
const Quaternion testRotation = Quaternion::CreateRotationX(DegToRad(60.0f));
const Vector3 testHalfLengths(0.5f, 2.0f, 1.5f);
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(testPosition, testRotation, testHalfLengths);
EXPECT_NEAR(obb.GetDistance(Vector3(5.3f, 3.2f, 1.8f)), 0.0f, 1e-3f);
EXPECT_NEAR(obb.GetDistance(Vector3(5.1f, 1.1f, 3.7f)), 0.9955f, 1e-3f);
EXPECT_NEAR(obb.GetDistance(Vector3(4.7f, 4.5f, 4.2f)), 0.6553f, 1e-3f);
@@ -146,10 +146,10 @@ namespace UnitTest
TEST(MATH_Obb, GetDistanceSq)
{
const Vector3 position(1.0f, 4.0f, 3.0f);
const Quaternion rotation = Quaternion::CreateRotationY(DegToRad(45.0f));
const Vector3 halfLengths(1.5f, 3.0f, 1.0f);
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths);
const Vector3 testPosition(1.0f, 4.0f, 3.0f);
const Quaternion testRotation = Quaternion::CreateRotationY(DegToRad(45.0f));
const Vector3 testHalfLengths(1.5f, 3.0f, 1.0f);
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(testPosition, testRotation, testHalfLengths);
EXPECT_NEAR(obb.GetDistanceSq(Vector3(1.1f, 4.3f, 2.7f)), 0.0f, 1e-3f);
EXPECT_NEAR(obb.GetDistanceSq(Vector3(-0.7f, 3.5f, 2.0f)), 0.8266f, 1e-3f);
EXPECT_NEAR(obb.GetDistanceSq(Vector3(2.4f, 0.5f, 1.5f)), 0.5532f, 1e-3f);
@@ -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());
}
}
}
@@ -1681,13 +1681,11 @@ namespace AZ::IO
AZStd::vector<AZStd::string> files;
do
{
if (AZStd::wildcard_match(pWildcardIn, fileIterator.m_filename))
{
AZStd::string foundFilename{ fileIterator.m_filename };
AZStd::to_lower(foundFilename.begin(), foundFilename.end());
files.emplace_back(AZStd::move(foundFilename));
}
} while (fileIterator = FindNext(fileIterator));
AZStd::string foundFilename{ fileIterator.m_filename };
AZStd::to_lower(foundFilename.begin(), foundFilename.end());
files.emplace_back(AZStd::move(foundFilename));
}
while (fileIterator = FindNext(fileIterator));
// Open files in alphabet order.
AZStd::sort(files.begin(), files.end());
@@ -38,20 +38,20 @@ namespace AzFramework
void SpawnableEntitiesContainer::SpawnAllEntities()
{
AZ_Assert(m_threadData, "Calling SpawnAllEntities on a Spawnable container that's not set.");
SpawnableEntitiesInterface::Get()->SpawnAllEntities(m_threadData->m_spawnedEntitiesTicket, SpawnablePriority_Default);
SpawnableEntitiesInterface::Get()->SpawnAllEntities(m_threadData->m_spawnedEntitiesTicket);
}
void SpawnableEntitiesContainer::SpawnEntities(AZStd::vector<size_t> entityIndices)
{
AZ_Assert(m_threadData, "Calling SpawnEntities on a Spawnable container that's not set.");
SpawnableEntitiesInterface::Get()->SpawnEntities(
m_threadData->m_spawnedEntitiesTicket, SpawnablePriority_Default, AZStd::move(entityIndices));
m_threadData->m_spawnedEntitiesTicket, AZStd::move(entityIndices));
}
void SpawnableEntitiesContainer::DespawnAllEntities()
{
AZ_Assert(m_threadData, "Calling DespawnEntities on a Spawnable container that's not set.");
SpawnableEntitiesInterface::Get()->DespawnAllEntities(m_threadData->m_spawnedEntitiesTicket, SpawnablePriority_Default);
SpawnableEntitiesInterface::Get()->DespawnAllEntities(m_threadData->m_spawnedEntitiesTicket);
}
void SpawnableEntitiesContainer::Reset(AZ::Data::Asset<Spawnable> spawnable)
@@ -69,7 +69,6 @@ namespace AzFramework
SpawnableEntitiesInterface::Get()->Barrier(
m_threadData->m_spawnedEntitiesTicket,
SpawnablePriority_Default,
[threadData = m_threadData](EntitySpawnTicket::Id) mutable
{
threadData.reset();
@@ -88,7 +87,6 @@ namespace AzFramework
AZ_Assert(m_threadData, "Calling DespawnEntities on a Spawnable container that's not set.");
SpawnableEntitiesInterface::Get()->Barrier(
m_threadData->m_spawnedEntitiesTicket,
SpawnablePriority_Default,
[generation = m_threadData->m_generation, callback = AZStd::move(callback)](EntitySpawnTicket::Id)
{
callback(generation);
@@ -115,7 +113,6 @@ namespace AzFramework
AZ_Assert(m_threadData, "SpawnableEntitiesContainer is monitoring a spawnable, but doesn't have the associated data.");
AZ_TracePrintf("Spawnables", "Reloading spawnable '%s'.\n", replacementAsset.GetHint().c_str());
SpawnableEntitiesInterface::Get()->ReloadSpawnable(
m_threadData->m_spawnedEntitiesTicket, SpawnablePriority_Default, AZStd::move(replacementAsset));
SpawnableEntitiesInterface::Get()->ReloadSpawnable(m_threadData->m_spawnedEntitiesTicket, AZStd::move(replacementAsset));
}
} // namespace AzFramework
@@ -21,6 +21,7 @@
namespace AZ
{
class Entity;
class SerializeContext;
}
namespace AzFramework
@@ -171,6 +172,77 @@ namespace AzFramework
using ClaimEntitiesCallback = AZStd::function<void(EntitySpawnTicket::Id, SpawnableEntityContainerView)>;
using BarrierCallback = AZStd::function<void(EntitySpawnTicket::Id)>;
struct SpawnAllEntitiesOptionalArgs final
{
//! Callback that's called after instances of entities have been created, but before they're spawned into the world. This
//! gives the opportunity to modify the entities if needed such as injecting additional components or modifying components.
EntityPreInsertionCallback m_preInsertionCallback;
//! Callback that's called when spawning entities has completed. This can be triggered from a different thread than the one that
//! made the function call to spawn. The returned list of entities contains all the newly created entities.
EntitySpawnCallback m_completionCallback;
//! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used.
AZ::SerializeContext* m_serializeContext { nullptr };
//! The priority at which this call will be executed.
SpawnablePriority m_priority { SpawnablePriority_Default };
};
struct SpawnEntitiesOptionalArgs final
{
//! Callback that's called after instances of entities have been created, but before they're spawned into the world. This
//! gives the opportunity to modify the entities if needed such as injecting additional components or modifying components.
EntityPreInsertionCallback m_preInsertionCallback;
//! Callback that's called when spawning entities has completed. This can be triggered from a different thread than the one that
//! made the function call to spawn. The returned list of entities contains all the newly created entities.
EntitySpawnCallback m_completionCallback;
//! The Serialize Context used to clone entities with. If this is not provided the global Serialize Contetx will be used.
AZ::SerializeContext* m_serializeContext{ nullptr };
//! The priority at which this call will be executed.
SpawnablePriority m_priority{ SpawnablePriority_Default };
//! Entity references are resolved by referring to the last entity spawned from a template entity in the spawnable. If this
//! is set to false entities from previous spawn calls are not taken into account. If set to true entity references may be
//! resolved to a previously spawned entity. A lookup table has to be constructed when true, which may negatively impact
//! performance, especially if a large number of entities are present on a ticket.
bool m_referencePreviouslySpawnedEntities{ false };
};
struct DespawnAllEntitiesOptionalArgs final
{
//! Callback that's called when despawning entities has completed. This can be triggered from a different thread than the one that
//! made the function call to despawn. The returned list of entities contains all the newly created entities.
EntityDespawnCallback m_completionCallback;
//! The priority at which this call will be executed.
SpawnablePriority m_priority { SpawnablePriority_Default };
};
struct ReloadSpawnableOptionalArgs final
{
//! Callback that's called when respawning entities has completed. This can be triggered from a different thread than the one that
//! made the function call to respawn. The returned list of entities contains all the newly created entities.
ReloadSpawnableCallback m_completionCallback;
//! The Serialize Context used to clone entities with. If this is not provided the global Serialize Context will be used.
AZ::SerializeContext* m_serializeContext { nullptr };
//! The priority at which this call will be executed.
SpawnablePriority m_priority { SpawnablePriority_Default };
};
struct ListEntitiesOptionalArgs final
{
//! The priority at which this call will be executed.
SpawnablePriority m_priority{ SpawnablePriority_Default };
};
struct ClaimEntitiesOptionalArgs final
{
//! The priority at which this call will be executed.
SpawnablePriority m_priority{ SpawnablePriority_Default };
};
struct BarrierOptionalArgs final
{
//! The priority at which this call will be executed.
SpawnablePriority m_priority{ SpawnablePriority_Default };
};
//! Interface definition to (de)spawn entities from a spawnable into the game world.
//!
//! While the callbacks of the individual calls are being processed they will block processing any other request. Callbacks can be
@@ -196,47 +268,34 @@ namespace AzFramework
//! Spawn instances of all entities in the spawnable.
//! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them.
//! @param priority The priority at which this call will be executed.
//! @param completionCallback Optional callback that's called when spawning entities has completed. This can be called from
//! a different thread than the one that made the function call. The returned list of entities contains all the newly
//! created entities.
virtual void SpawnAllEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, EntityPreInsertionCallback preInsertionCallback = {},
EntitySpawnCallback completionCallback = {}) = 0;
//! @param optionalArgs Optional additional arguments, see SpawnAllEntitiesOptionalArgs.
virtual void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnAllEntitiesOptionalArgs optionalArgs = {}) = 0;
//! Spawn instances of some entities in the spawnable.
//! @param ticket Stores the results of the call. Use this ticket to spawn additional entities or to despawn them.
//! @param priority The priority at which this call will be executed.
//! @param entityIndices The indices into the template entities stored in the spawnable that will be used to spawn entities from.
//! @param completionCallback Optional callback that's called when spawning entities has completed. This can be called from
//! a different thread than the one that made this function call. The returned list of entities contains all the newly
//! created entities.
//! @param optionalArgs Optional additional arguments, see SpawnEntitiesOptionalArgs.
virtual void SpawnEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector<size_t> entityIndices,
EntityPreInsertionCallback preInsertionCallback = {}, EntitySpawnCallback completionCallback = {}) = 0;
EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices, SpawnEntitiesOptionalArgs optionalArgs = {}) = 0;
//! Removes all entities in the provided list from the environment.
//! @param ticket The ticket previously used to spawn entities with.
//! @param priority The priority at which this call will be executed.
//! @param completionCallback Optional callback that's called when despawning entities has completed. This can be called from
//! a different thread than the one that made this function call.
virtual void DespawnAllEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, EntityDespawnCallback completionCallback = {}) = 0;
//! @param optionalArgs Optional additional arguments, see DespawnAllEntitiesOptionalArgs.
virtual void DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs = {}) = 0;
//! Removes all entities in the provided list from the environment and reconstructs the entities from the provided spawnable.
//! @param ticket Holds the information on the entities to reload.
//! @param priority The priority at which this call will be executed.
//! @param spawnable The spawnable that will replace the existing spawnable. Both need to have the same asset id.
//! @param completionCallback Optional callback that's called when the entities have been reloaded. This can be called from
//! a different thread than the one that made this function call. The returned list of entities contains all the replacement
//! entities.
//! @param optionalArgs Optional additional arguments, see ReloadSpawnableOptionalArgs.
virtual void ReloadSpawnable(
EntitySpawnTicket& ticket, SpawnablePriority priority, AZ::Data::Asset<Spawnable> spawnable,
ReloadSpawnableCallback completionCallback = {}) = 0;
EntitySpawnTicket& ticket, AZ::Data::Asset<Spawnable> spawnable, ReloadSpawnableOptionalArgs optionalArgs = {}) = 0;
//! List all entities that are spawned using this ticket.
//! @param ticket Only the entities associated with this ticket will be listed.
//! @param priority The priority at which this call will be executed.
//! @param listCallback Required callback that will be called to list the entities on.
virtual void ListEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ListEntitiesCallback listCallback) = 0;
//! @param optionalArgs Optional additional arguments, see ListEntitiesOptionalArgs.
virtual void ListEntities(
EntitySpawnTicket& ticket, ListEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) = 0;
//! List all entities that are spawned using this ticket with their spawnable index.
//! Spawnables contain a flat list of entities, which are used as templates to spawn entities from. For every spawned entity
//! the index of the entity in the spawnable that was used as a template is stored. This version of ListEntities will return
@@ -244,23 +303,24 @@ namespace AzFramework
//! the same index may appear multiple times as there are no restriction on how many instance of a specific entity can be
//! created.
//! @param ticket Only the entities associated with this ticket will be listed.
//! @param priority The priority at which this call will be executed.
//! @param listCallback Required callback that will be called to list the entities and indices on.
//! @param optionalArgs Optional additional arguments, see ListEntitiesOptionalArgs.
virtual void ListIndicesAndEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, ListIndicesEntitiesCallback listCallback) = 0;
EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) = 0;
//! Claim all entities that are spawned using this ticket. Ownership of the entities is transferred from the ticket to the
//! caller through the callback. After this call the ticket will have no entities associated with it. The caller of
//! this function will need to manage the entities after this call.
//! @param ticket Only the entities associated with this ticket will be released.
//! @param priority The priority at which this call will be executed.
//! @param listCallback Required callback that will be called to transfer the entities through.
virtual void ClaimEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ClaimEntitiesCallback listCallback) = 0;
//! @param optionalArgs Optional additional arguments, see ClaimEntitiesOptionalArgs.
virtual void ClaimEntities(
EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback, ClaimEntitiesOptionalArgs optionalArgs = {}) = 0;
//! Blocks until all operations made on the provided ticket before the barrier call have completed.
//! @param ticket The ticket to monitor.
//! @param priority The priority at which this call will be executed.
//! @param completionCallback Required callback that will be called as soon as the barrier has been reached.
virtual void Barrier(EntitySpawnTicket& ticket, SpawnablePriority priority, BarrierCallback completionCallback) = 0;
//! @param optionalArgs Optional additional arguments, see BarrierOptionalArgs.
virtual void Barrier(EntitySpawnTicket& ticket, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs = {}) = 0;
//! Register a handler for OnSpawned events.
virtual void AddOnSpawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler) = 0;
@@ -38,6 +38,10 @@ namespace AzFramework
SpawnableEntitiesManager::SpawnableEntitiesManager()
{
AZ::ComponentApplicationBus::BroadcastResult(m_defaultSerializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
AZ_Assert(
m_defaultSerializeContext, "Failed to retrieve serialization context during construction of the Spawnable Entities Manager.");
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
AZ::u64 value = aznumeric_caster(m_highPriorityThreshold);
@@ -46,58 +50,61 @@ namespace AzFramework
}
}
void SpawnableEntitiesManager::SpawnAllEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, EntityPreInsertionCallback preInsertionCallback,
EntitySpawnCallback completionCallback)
void SpawnableEntitiesManager::SpawnAllEntities(EntitySpawnTicket& ticket, SpawnAllEntitiesOptionalArgs optionalArgs)
{
AZ_Assert(ticket.IsValid(), "Ticket provided to SpawnAllEntities hasn't been initialized.");
SpawnAllEntitiesCommand queueEntry;
queueEntry.m_ticketId = ticket.GetId();
queueEntry.m_completionCallback = AZStd::move(completionCallback);
queueEntry.m_preInsertionCallback = AZStd::move(preInsertionCallback);
QueueRequest(ticket, priority, AZStd::move(queueEntry));
queueEntry.m_serializeContext =
optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext;
queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback);
queueEntry.m_preInsertionCallback = AZStd::move(optionalArgs.m_preInsertionCallback);
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
}
void SpawnableEntitiesManager::SpawnEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector<size_t> entityIndices,
EntityPreInsertionCallback preInsertionCallback, EntitySpawnCallback completionCallback)
EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices, SpawnEntitiesOptionalArgs optionalArgs)
{
AZ_Assert(ticket.IsValid(), "Ticket provided to SpawnEntities hasn't been initialized.");
SpawnEntitiesCommand queueEntry;
queueEntry.m_ticketId = ticket.GetId();
queueEntry.m_entityIndices = AZStd::move(entityIndices);
queueEntry.m_completionCallback = AZStd::move(completionCallback);
queueEntry.m_preInsertionCallback = AZStd::move(preInsertionCallback);
QueueRequest(ticket, priority, AZStd::move(queueEntry));
queueEntry.m_serializeContext =
optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext;
queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback);
queueEntry.m_preInsertionCallback = AZStd::move(optionalArgs.m_preInsertionCallback);
queueEntry.m_referencePreviouslySpawnedEntities = optionalArgs.m_referencePreviouslySpawnedEntities;
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
}
void SpawnableEntitiesManager::DespawnAllEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, EntityDespawnCallback completionCallback)
void SpawnableEntitiesManager::DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs)
{
AZ_Assert(ticket.IsValid(), "Ticket provided to DespawnAllEntities hasn't been initialized.");
DespawnAllEntitiesCommand queueEntry;
queueEntry.m_ticketId = ticket.GetId();
queueEntry.m_completionCallback = AZStd::move(completionCallback);
QueueRequest(ticket, priority, AZStd::move(queueEntry));
queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback);
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
}
void SpawnableEntitiesManager::ReloadSpawnable(
EntitySpawnTicket& ticket, SpawnablePriority priority, AZ::Data::Asset<Spawnable> spawnable,
ReloadSpawnableCallback completionCallback)
EntitySpawnTicket& ticket, AZ::Data::Asset<Spawnable> spawnable, ReloadSpawnableOptionalArgs optionalArgs)
{
AZ_Assert(ticket.IsValid(), "Ticket provided to ReloadSpawnable hasn't been initialized.");
ReloadSpawnableCommand queueEntry;
queueEntry.m_ticketId = ticket.GetId();
queueEntry.m_spawnable = AZStd::move(spawnable);
queueEntry.m_completionCallback = AZStd::move(completionCallback);
QueueRequest(ticket, priority, AZStd::move(queueEntry));
queueEntry.m_serializeContext =
optionalArgs.m_serializeContext == nullptr ? m_defaultSerializeContext : optionalArgs.m_serializeContext;
queueEntry.m_completionCallback = AZStd::move(optionalArgs.m_completionCallback);
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
}
void SpawnableEntitiesManager::ListEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ListEntitiesCallback listCallback)
void SpawnableEntitiesManager::ListEntities(
EntitySpawnTicket& ticket, ListEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs)
{
AZ_Assert(listCallback, "ListEntities called on spawnable entities without a valid callback to use.");
AZ_Assert(ticket.IsValid(), "Ticket provided to ListEntities hasn't been initialized.");
@@ -105,11 +112,11 @@ namespace AzFramework
ListEntitiesCommand queueEntry;
queueEntry.m_ticketId = ticket.GetId();
queueEntry.m_listCallback = AZStd::move(listCallback);
QueueRequest(ticket, priority, AZStd::move(queueEntry));
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
}
void SpawnableEntitiesManager::ListIndicesAndEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, ListIndicesEntitiesCallback listCallback)
EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs)
{
AZ_Assert(listCallback, "ListEntities called on spawnable entities without a valid callback to use.");
AZ_Assert(ticket.IsValid(), "Ticket provided to ListEntities hasn't been initialized.");
@@ -117,10 +124,11 @@ namespace AzFramework
ListIndicesEntitiesCommand queueEntry;
queueEntry.m_ticketId = ticket.GetId();
queueEntry.m_listCallback = AZStd::move(listCallback);
QueueRequest(ticket, priority, AZStd::move(queueEntry));
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
}
void SpawnableEntitiesManager::ClaimEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ClaimEntitiesCallback listCallback)
void SpawnableEntitiesManager::ClaimEntities(
EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback, ClaimEntitiesOptionalArgs optionalArgs)
{
AZ_Assert(listCallback, "ClaimEntities called on spawnable entities without a valid callback to use.");
AZ_Assert(ticket.IsValid(), "Ticket provided to ClaimEntities hasn't been initialized.");
@@ -128,10 +136,10 @@ namespace AzFramework
ClaimEntitiesCommand queueEntry;
queueEntry.m_ticketId = ticket.GetId();
queueEntry.m_listCallback = AZStd::move(listCallback);
QueueRequest(ticket, priority, AZStd::move(queueEntry));
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
}
void SpawnableEntitiesManager::Barrier(EntitySpawnTicket& ticket, SpawnablePriority priority, BarrierCallback completionCallback)
void SpawnableEntitiesManager::Barrier(EntitySpawnTicket& ticket, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs)
{
AZ_Assert(completionCallback, "Barrier on spawnable entities called without a valid callback to use.");
AZ_Assert(ticket.IsValid(), "Ticket provided to Barrier hasn't been initialized.");
@@ -139,7 +147,7 @@ namespace AzFramework
BarrierCommand queueEntry;
queueEntry.m_ticketId = ticket.GetId();
queueEntry.m_completionCallback = AZStd::move(completionCallback);
QueueRequest(ticket, priority, AZStd::move(queueEntry));
QueueRequest(ticket, optionalArgs.m_priority, AZStd::move(queueEntry));
}
void SpawnableEntitiesManager::AddOnSpawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler)
@@ -174,58 +182,57 @@ namespace AzFramework
auto SpawnableEntitiesManager::ProcessQueue(Queue& queue) -> CommandQueueStatus
{
AZStd::queue<Requests> pendingRequestQueue;
// Process delayed requests first.
// Only process the requests that are currently in this queue, not the ones that could be re-added if they still can't complete.
size_t delayedSize = queue.m_delayed.size();
for (size_t i = 0; i < delayedSize; ++i)
{
AZStd::scoped_lock queueLock(queue.m_pendingRequestMutex);
queue.m_pendingRequest.swap(pendingRequestQueue);
Requests& request = queue.m_delayed.front();
bool result = AZStd::visit(
[this](auto&& args) -> bool
{
return ProcessRequest(args);
},
request);
if (!result)
{
queue.m_delayed.emplace_back(AZStd::move(request));
}
queue.m_delayed.pop_front();
}
if (!pendingRequestQueue.empty() || !queue.m_delayed.empty())
// Process newly added requests.
while (true)
{
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
AZ_Assert(serializeContext, "Failed to retrieve serialization context.");
// Only process the requests that are currently in this queue, not the ones that could be re-added if they still can't complete.
size_t delayedSize = queue.m_delayed.size();
for (size_t i = 0; i < delayedSize; ++i)
AZStd::queue<Requests> pendingRequestQueue;
{
Requests& request = queue.m_delayed.front();
bool result = AZStd::visit([this, serializeContext](auto&& args) -> bool
{
return ProcessRequest(args, *serializeContext);
}, request);
if (!result)
{
queue.m_delayed.emplace_back(AZStd::move(request));
}
queue.m_delayed.pop_front();
AZStd::scoped_lock queueLock(queue.m_pendingRequestMutex);
queue.m_pendingRequest.swap(pendingRequestQueue);
}
do
if (!pendingRequestQueue.empty())
{
while (!pendingRequestQueue.empty())
{
Requests& request = pendingRequestQueue.front();
bool result = AZStd::visit([this, serializeContext](auto&& args) -> bool
bool result = AZStd::visit(
[this](auto&& args) -> bool
{
return ProcessRequest(args, *serializeContext);
}, request);
return ProcessRequest(args);
},
request);
if (!result)
{
queue.m_delayed.emplace_back(AZStd::move(request));
}
pendingRequestQueue.pop();
}
// Spawning entities can result in more entities being queued to spawn. Repeat spawning until the queue is
// empty to avoid a chain of entity spawning getting dragged out over multiple frames.
{
AZStd::scoped_lock queueLock(queue.m_pendingRequestMutex);
queue.m_pendingRequest.swap(pendingRequestQueue);
}
} while (!pendingRequestQueue.empty());
}
}
else
{
break;
}
};
return queue.m_delayed.empty() ? CommandQueueStatus::NoCommandsLeft : CommandQueueStatus::HasCommandsLeft;
}
@@ -250,24 +257,14 @@ namespace AzFramework
}
}
AZ::Entity* SpawnableEntitiesManager::SpawnSingleEntity(const AZ::Entity& entityTemplate, AZ::SerializeContext& serializeContext)
{
AZ::Entity* clone = serializeContext.CloneObject(&entityTemplate);
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
clone->SetId(AZ::Entity::MakeId());
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, clone);
return clone;
}
AZ::Entity* SpawnableEntitiesManager::CloneSingleEntity(const AZ::Entity& entityTemplate,
EntityIdMap& templateToCloneEntityIdMap, AZ::SerializeContext& serializeContext)
EntityIdMap& templateToCloneMap, AZ::SerializeContext& serializeContext)
{
return AZ::IdUtils::Remapper<AZ::EntityId>::CloneObjectAndGenerateNewIdsAndFixRefs(
&entityTemplate, templateToCloneEntityIdMap, &serializeContext);
return AZ::IdUtils::Remapper<AZ::EntityId, true>::CloneObjectAndGenerateNewIdsAndFixRefs(
&entityTemplate, templateToCloneMap, &serializeContext);
}
bool SpawnableEntitiesManager::ProcessRequest(SpawnAllEntitiesCommand& request, AZ::SerializeContext& serializeContext)
bool SpawnableEntitiesManager::ProcessRequest(SpawnAllEntitiesCommand& request)
{
Ticket& ticket = *request.m_ticket;
if (ticket.m_spawnable.IsReady() && request.m_requestId == ticket.m_currentRequestId)
@@ -291,13 +288,9 @@ namespace AzFramework
spawnedEntityIndices.reserve(spawnedEntityIndices.size() + entitiesToSpawnSize);
templateToCloneEntityIdMap.reserve(entitiesToSpawnSize);
// Mark all indices as spawned
for (size_t i = 0; i < entitiesToSpawnSize; ++i)
{
const AZ::Entity& entityTemplate = *entitiesToSpawn[i];
AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, serializeContext);
AZ::Entity* clone = CloneSingleEntity(*entitiesToSpawn[i], templateToCloneEntityIdMap, *request.m_serializeContext);
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
spawnedEntities.emplace_back(clone);
@@ -305,16 +298,8 @@ namespace AzFramework
}
// loadAll is true if every entity has been spawned only once
if (spawnedEntities.size() == entitiesToSpawnSize)
{
ticket.m_loadAll = true;
}
else
{
// Case where there were already spawns from a previous request
ticket.m_loadAll = false;
}
ticket.m_loadAll = (spawnedEntities.size() == entitiesToSpawnSize);
// Let other systems know about newly spawned entities for any pre-processing before adding to the scene/game context.
if (request.m_preInsertionCallback)
{
@@ -323,11 +308,10 @@ namespace AzFramework
}
// Add to the game context, now the entities are active
AZStd::for_each(ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end(),
[](AZ::Entity* entity)
for (auto it = ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount; it != ticket.m_spawnedEntities.end(); ++it)
{
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, entity);
});
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
}
// Let other systems know about newly spawned entities for any post-processing after adding to the scene/game context.
if (request.m_completionCallback)
@@ -347,21 +331,41 @@ namespace AzFramework
}
}
bool SpawnableEntitiesManager::ProcessRequest(SpawnEntitiesCommand& request, AZ::SerializeContext& serializeContext)
bool SpawnableEntitiesManager::ProcessRequest(SpawnEntitiesCommand& request)
{
Ticket& ticket = *request.m_ticket;
if (ticket.m_spawnable.IsReady() && request.m_requestId == ticket.m_currentRequestId)
{
AZStd::vector<AZ::Entity*>& spawnedEntities = ticket.m_spawnedEntities;
AZStd::vector<size_t>& spawnedEntityIndices = ticket.m_spawnedEntityIndices;
AZ_Assert(
spawnedEntities.size() == spawnedEntityIndices.size(),
"The indices for the spawned entities has gone out of sync with the entities.");
// Keep track how many entities there were in the array initially
// Keep track of how many entities there were in the array initially
size_t spawnedEntitiesInitialCount = spawnedEntities.size();
// These are 'template' entities we'll be cloning from
const Spawnable::EntityList& entitiesToSpawn = ticket.m_spawnable->GetEntities();
size_t entitiesToSpawnSize = request.m_entityIndices.size();
// Reconstruct the template to entity mapping.
EntityIdMap templateToCloneEntityIdMap;
if (!request.m_referencePreviouslySpawnedEntities)
{
templateToCloneEntityIdMap.reserve(entitiesToSpawnSize);
}
else
{
templateToCloneEntityIdMap.reserve(spawnedEntitiesInitialCount + entitiesToSpawnSize);
SpawnableConstIndexEntityContainerView indexEntityView(
spawnedEntities.begin(), spawnedEntityIndices.begin(), spawnedEntities.size());
for (auto& entry : indexEntityView)
{
templateToCloneEntityIdMap.insert_or_assign(entitiesToSpawn[entry.GetIndex()]->GetId(), entry.GetEntity()->GetId());
}
}
spawnedEntities.reserve(spawnedEntities.size() + entitiesToSpawnSize);
spawnedEntityIndices.reserve(spawnedEntityIndices.size() + entitiesToSpawnSize);
@@ -369,15 +373,11 @@ namespace AzFramework
{
if (index < entitiesToSpawn.size())
{
const AZ::Entity& entityTemplate = *entitiesToSpawn[index];
AZ::Entity* clone = serializeContext.CloneObject(&entityTemplate);
AZ::Entity* clone = CloneSingleEntity(*entitiesToSpawn[index], templateToCloneEntityIdMap, *request.m_serializeContext);
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
clone->SetId(AZ::Entity::MakeId());
spawnedEntities.push_back(clone);
spawnedEntityIndices.push_back(index);
}
}
ticket.m_loadAll = false;
@@ -390,11 +390,10 @@ namespace AzFramework
}
// Add to the game context, now the entities are active
AZStd::for_each(ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount, ticket.m_spawnedEntities.end(),
[](AZ::Entity* entity)
for (auto it = ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount; it != ticket.m_spawnedEntities.end(); ++it)
{
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, entity);
});
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
}
if (request.m_completionCallback)
{
@@ -413,8 +412,7 @@ namespace AzFramework
}
}
bool SpawnableEntitiesManager::ProcessRequest(DespawnAllEntitiesCommand& request,
[[maybe_unused]] AZ::SerializeContext& serializeContext)
bool SpawnableEntitiesManager::ProcessRequest(DespawnAllEntitiesCommand& request)
{
Ticket& ticket = *request.m_ticket;
if (request.m_requestId == ticket.m_currentRequestId)
@@ -447,7 +445,7 @@ namespace AzFramework
}
}
bool SpawnableEntitiesManager::ProcessRequest(ReloadSpawnableCommand& request, AZ::SerializeContext& serializeContext)
bool SpawnableEntitiesManager::ProcessRequest(ReloadSpawnableCommand& request)
{
Ticket& ticket = *request.m_ticket;
AZ_Assert(ticket.m_spawnable.GetId() == request.m_spawnable.GetId(),
@@ -470,39 +468,43 @@ namespace AzFramework
// Rebuild the list of entities.
ticket.m_spawnedEntities.clear();
const Spawnable::EntityList& entities = request.m_spawnable->GetEntities();
// Map keeps track of ids from template (spawnable) to clone (instance)
// Allowing patch ups of fields referring to entityIds outside of a given entity
EntityIdMap templateToCloneEntityIdMap;
if (ticket.m_loadAll)
{
// The new spawnable may have a different number of entities and since the intent of the user was
// to load every, simply start over.
// to spawn every entity, simply start over.
ticket.m_spawnedEntityIndices.clear();
size_t entitiesToSpawnSize = entities.size();
// Map keeps track of ids from template (spawnable) to clone (instance)
// Allowing patch ups of fields referring to entityIds outside of a given entity
EntityIdMap templateToCloneEntityIdMap;
templateToCloneEntityIdMap.reserve(entitiesToSpawnSize);
// Mark all indices as spawned
for (size_t i = 0; i < entitiesToSpawnSize; ++i)
{
const AZ::Entity& entityTemplate = *entities[i];
AZ::Entity* clone = CloneSingleEntity(entityTemplate, templateToCloneEntityIdMap, serializeContext);
AZ::Entity* clone = CloneSingleEntity(*entities[i], templateToCloneEntityIdMap, *request.m_serializeContext);
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
ticket.m_spawnedEntities.emplace_back(clone);
ticket.m_spawnedEntities.push_back(clone);
ticket.m_spawnedEntityIndices.push_back(i);
}
}
else
{
size_t entitiesSize = entities.size();
templateToCloneEntityIdMap.reserve(entitiesSize);
for (size_t index : ticket.m_spawnedEntityIndices)
{
ticket.m_spawnedEntities.push_back(
index < entitiesSize ? SpawnSingleEntity(*entities[index], serializeContext) : nullptr);
// It's possible for the new spawnable to have a different number of entities, so guard against this.
// It's also possible that the entities have moved within the spawnable to a new index. This can't be
// detected and will result in the incorrect entities being spawned.
if (index < entitiesSize)
{
AZ::Entity* clone = CloneSingleEntity(*entities[index], templateToCloneEntityIdMap, *request.m_serializeContext);
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
ticket.m_spawnedEntities.push_back(clone);
}
}
}
ticket.m_spawnable = AZStd::move(request.m_spawnable);
@@ -525,7 +527,7 @@ namespace AzFramework
}
}
bool SpawnableEntitiesManager::ProcessRequest(ListEntitiesCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext)
bool SpawnableEntitiesManager::ProcessRequest(ListEntitiesCommand& request)
{
Ticket& ticket = *request.m_ticket;
if (request.m_requestId == ticket.m_currentRequestId)
@@ -541,7 +543,7 @@ namespace AzFramework
}
}
bool SpawnableEntitiesManager::ProcessRequest(ListIndicesEntitiesCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext)
bool SpawnableEntitiesManager::ProcessRequest(ListIndicesEntitiesCommand& request)
{
Ticket& ticket = *request.m_ticket;
if (request.m_requestId == ticket.m_currentRequestId)
@@ -560,7 +562,7 @@ namespace AzFramework
}
}
bool SpawnableEntitiesManager::ProcessRequest(ClaimEntitiesCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext)
bool SpawnableEntitiesManager::ProcessRequest(ClaimEntitiesCommand& request)
{
Ticket& ticket = *request.m_ticket;
if (request.m_requestId == ticket.m_currentRequestId)
@@ -580,7 +582,7 @@ namespace AzFramework
}
}
bool SpawnableEntitiesManager::ProcessRequest(BarrierCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext)
bool SpawnableEntitiesManager::ProcessRequest(BarrierCommand& request)
{
Ticket& ticket = *request.m_ticket;
if (request.m_requestId == ticket.m_currentRequestId)
@@ -599,7 +601,7 @@ namespace AzFramework
}
}
bool SpawnableEntitiesManager::ProcessRequest(DestroyTicketCommand& request, [[maybe_unused]] AZ::SerializeContext& serializeContext)
bool SpawnableEntitiesManager::ProcessRequest(DestroyTicketCommand& request)
{
if (request.m_requestId == request.m_ticket->m_currentRequestId)
{
@@ -37,7 +37,7 @@ namespace AzFramework
AZ_CLASS_ALLOCATOR(SpawnableEntitiesManager, AZ::SystemAllocator, 0);
using EntityIdMap = AZStd::unordered_map<AZ::EntityId, AZ::EntityId>;
enum class CommandQueueStatus : bool
{
HasCommandsLeft,
@@ -57,26 +57,21 @@ namespace AzFramework
// The following functions are thread safe
//
void SpawnAllEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, EntityPreInsertionCallback preInsertionCallback = {},
EntitySpawnCallback completionCallback = {}) override;
void SpawnAllEntities(EntitySpawnTicket& ticket, SpawnAllEntitiesOptionalArgs optionalArgs = {}) override;
void SpawnEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, AZStd::vector<size_t> entityIndices,
EntityPreInsertionCallback preInsertionCallback = {},
EntitySpawnCallback completionCallback = {}) override;
void DespawnAllEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, EntityDespawnCallback completionCallback = {}) override;
EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices, SpawnEntitiesOptionalArgs optionalArgs = {}) override;
void DespawnAllEntities(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs = {}) override;
void ReloadSpawnable(
EntitySpawnTicket& ticket, SpawnablePriority priority, AZ::Data::Asset<Spawnable> spawnable,
ReloadSpawnableCallback completionCallback = {}) override;
EntitySpawnTicket& ticket, AZ::Data::Asset<Spawnable> spawnable, ReloadSpawnableOptionalArgs optionalArgs = {}) override;
void ListEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ListEntitiesCallback listCallback) override;
void ListEntities(
EntitySpawnTicket& ticket, ListEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) override;
void ListIndicesAndEntities(
EntitySpawnTicket& ticket, SpawnablePriority priority, ListIndicesEntitiesCallback listCallback) override;
void ClaimEntities(EntitySpawnTicket& ticket, SpawnablePriority priority, ClaimEntitiesCallback listCallback) override;
EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs = {}) override;
void ClaimEntities(
EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback, ClaimEntitiesOptionalArgs optionalArgs = {}) override;
void Barrier(EntitySpawnTicket& spawnInfo, SpawnablePriority priority, BarrierCallback completionCallback) override;
void Barrier(EntitySpawnTicket& spawnInfo, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs = {}) override;
void AddOnSpawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler) override;
void AddOnDespawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler) override;
@@ -105,6 +100,7 @@ namespace AzFramework
{
EntitySpawnCallback m_completionCallback;
EntityPreInsertionCallback m_preInsertionCallback;
AZ::SerializeContext* m_serializeContext;
Ticket* m_ticket;
EntitySpawnTicket::Id m_ticketId;
uint32_t m_requestId;
@@ -114,9 +110,11 @@ namespace AzFramework
AZStd::vector<size_t> m_entityIndices;
EntitySpawnCallback m_completionCallback;
EntityPreInsertionCallback m_preInsertionCallback;
AZ::SerializeContext* m_serializeContext;
Ticket* m_ticket;
EntitySpawnTicket::Id m_ticketId;
uint32_t m_requestId;
bool m_referencePreviouslySpawnedEntities;
};
struct DespawnAllEntitiesCommand
{
@@ -129,6 +127,7 @@ namespace AzFramework
{
AZ::Data::Asset<Spawnable> m_spawnable;
ReloadSpawnableCallback m_completionCallback;
AZ::SerializeContext* m_serializeContext;
Ticket* m_ticket;
EntitySpawnTicket::Id m_ticketId;
uint32_t m_requestId;
@@ -185,21 +184,18 @@ namespace AzFramework
CommandQueueStatus ProcessQueue(Queue& queue);
AZ::Entity* SpawnSingleEntity(const AZ::Entity& entityTemplate,
AZ::SerializeContext& serializeContext);
AZ::Entity* CloneSingleEntity(const AZ::Entity& entityTemplate,
EntityIdMap& templateToCloneEntityIdMap, AZ::SerializeContext& serializeContext);
bool ProcessRequest(SpawnAllEntitiesCommand& request, AZ::SerializeContext& serializeContext);
bool ProcessRequest(SpawnEntitiesCommand& request, AZ::SerializeContext& serializeContext);
bool ProcessRequest(DespawnAllEntitiesCommand& request, AZ::SerializeContext& serializeContext);
bool ProcessRequest(ReloadSpawnableCommand& request, AZ::SerializeContext& serializeContext);
bool ProcessRequest(ListEntitiesCommand& request, AZ::SerializeContext& serializeContext);
bool ProcessRequest(ListIndicesEntitiesCommand& request, AZ::SerializeContext& serializeContext);
bool ProcessRequest(ClaimEntitiesCommand& request, AZ::SerializeContext& serializeContext);
bool ProcessRequest(BarrierCommand& request, AZ::SerializeContext& serializeContext);
bool ProcessRequest(DestroyTicketCommand& request, AZ::SerializeContext& serializeContext);
AZ::Entity* CloneSingleEntity(
const AZ::Entity& entityTemplate, EntityIdMap& templateToCloneMap, AZ::SerializeContext& serializeContext);
bool ProcessRequest(SpawnAllEntitiesCommand& request);
bool ProcessRequest(SpawnEntitiesCommand& request);
bool ProcessRequest(DespawnAllEntitiesCommand& request);
bool ProcessRequest(ReloadSpawnableCommand& request);
bool ProcessRequest(ListEntitiesCommand& request);
bool ProcessRequest(ListIndicesEntitiesCommand& request);
bool ProcessRequest(ClaimEntitiesCommand& request);
bool ProcessRequest(BarrierCommand& request);
bool ProcessRequest(DestroyTicketCommand& request);
Queue m_highPriorityQueue;
Queue m_regularPriorityQueue;
@@ -207,6 +203,7 @@ namespace AzFramework
AZ::Event<AZ::Data::Asset<Spawnable>> m_onSpawnedEvent;
AZ::Event<AZ::Data::Asset<Spawnable>> m_onDespawnedEvent;
AZ::SerializeContext* m_defaultSerializeContext { nullptr };
//! The threshold used to determine if a request goes in the regular (if bigger than the value) or high priority queue (if smaller
//! or equal to this value). The starting value of 64 is chosen as it's between default values SpawnablePriority_High and
//! SpawnablePriority_Default which gives users a bit of room to fine tune the priorities as this value can be configured
@@ -22,7 +22,11 @@
namespace AzFramework
{
AZ_CVAR(
float, ed_cameraSystemDefaultPlaneHeight, 34.0f, nullptr, AZ::ConsoleFunctorFlags::Null,
float,
ed_cameraSystemDefaultPlaneHeight,
34.0f,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"The default height of the ground plane to do intersection tests against when orbiting");
AZ_CVAR(float, ed_cameraSystemBoostMultiplier, 3.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
AZ_CVAR(float, ed_cameraSystemTranslateSpeed, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
@@ -41,7 +45,11 @@ namespace AzFramework
AZ_CVAR(
AZ::CVarFixedString, ed_cameraSystemTranslateForwardKey, "keyboard_key_alphanumeric_W", nullptr, AZ::ConsoleFunctorFlags::Null, "");
AZ_CVAR(
AZ::CVarFixedString, ed_cameraSystemTranslateBackwardKey, "keyboard_key_alphanumeric_S", nullptr, AZ::ConsoleFunctorFlags::Null,
AZ::CVarFixedString,
ed_cameraSystemTranslateBackwardKey,
"keyboard_key_alphanumeric_S",
nullptr,
AZ::ConsoleFunctorFlags::Null,
"");
AZ_CVAR(
AZ::CVarFixedString, ed_cameraSystemTranslateLeftKey, "keyboard_key_alphanumeric_A", nullptr, AZ::ConsoleFunctorFlags::Null, "");
@@ -326,7 +334,9 @@ namespace AzFramework
}
Camera RotateCameraInput::StepCamera(
const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta,
const Camera& targetCamera,
const ScreenVector& cursorDelta,
[[maybe_unused]] const float scrollDelta,
[[maybe_unused]] const float deltaTime)
{
Camera nextCamera = targetCamera;
@@ -374,7 +384,9 @@ namespace AzFramework
}
Camera PanCameraInput::StepCamera(
const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta,
const Camera& targetCamera,
const ScreenVector& cursorDelta,
[[maybe_unused]] const float scrollDelta,
[[maybe_unused]] const float deltaTime)
{
Camera nextCamera = targetCamera;
@@ -473,7 +485,9 @@ namespace AzFramework
}
Camera TranslateCameraInput::StepCamera(
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta,
const Camera& targetCamera,
[[maybe_unused]] const ScreenVector& cursorDelta,
[[maybe_unused]] const float scrollDelta,
const float deltaTime)
{
Camera nextCamera = targetCamera;
@@ -630,7 +644,9 @@ namespace AzFramework
}
Camera OrbitDollyScrollCameraInput::StepCamera(
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta,
const Camera& targetCamera,
[[maybe_unused]] const ScreenVector& cursorDelta,
const float scrollDelta,
[[maybe_unused]] const float deltaTime)
{
Camera nextCamera = targetCamera;
@@ -666,7 +682,9 @@ namespace AzFramework
}
Camera OrbitDollyCursorMoveCameraInput::StepCamera(
const Camera& targetCamera, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta,
const Camera& targetCamera,
const ScreenVector& cursorDelta,
[[maybe_unused]] const float scrollDelta,
[[maybe_unused]] const float deltaTime)
{
Camera nextCamera = targetCamera;
@@ -686,7 +704,9 @@ namespace AzFramework
}
Camera ScrollTranslationCameraInput::StepCamera(
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta,
const Camera& targetCamera,
[[maybe_unused]] const ScreenVector& cursorDelta,
const float scrollDelta,
[[maybe_unused]] const float deltaTime)
{
Camera nextCamera = targetCamera;
@@ -128,12 +128,12 @@ namespace AzFramework
worldPosition, CameraView(cameraState), CameraProjection(cameraState), cameraState.m_viewportSize);
}
AZ::Vector3 ScreenToWorld(
const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize)
AZ::Vector3 ScreenNDCToWorld(
const AZ::Vector2& normalizedScreenPosition, const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection)
{
// convert screen space coordinates from <0, 1> to <-1,1> range
const auto ndcPosition = NDCFromScreenPoint(screenPosition, viewportSize) * 2.0f - AZ::Vector2::CreateOne();
const auto ndcPosition = normalizedScreenPosition * 2.0f - AZ::Vector2::CreateOne();
// transform ndc space position to clip space
const auto clipSpacePosition = inverseCameraProjection * Vector2ToVector4(ndcPosition, -1.0f, 1.0f);
@@ -145,6 +145,15 @@ namespace AzFramework
return worldPosition;
}
AZ::Vector3 ScreenToWorld(
const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize)
{
const auto normalizedScreenPosition = NDCFromScreenPoint(screenPosition, viewportSize);
return ScreenNDCToWorld(normalizedScreenPosition, inverseCameraView, inverseCameraProjection);
}
AZ::Vector3 ScreenToWorld(const ScreenPoint& screenPosition, const CameraState& cameraState)
{
return ScreenToWorld(
@@ -42,7 +42,7 @@ namespace AzFramework
const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection,
const AZ::Vector2& viewportSize);
//! Unprojects a position in screen space to world space.
//! Unprojects a position in screen space pixel coordinates to world space.
//! Note: The position returned will be on the near clip plane of the camera in world space.
AZ::Vector3 ScreenToWorld(const ScreenPoint& screenPosition, const CameraState& cameraState);
@@ -52,6 +52,12 @@ namespace AzFramework
const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize);
//! Unprojects a position in screen space normalized device coordinates to world space.
//! Note: The position returned will be on the near clip plane of the camera in world space.
AZ::Vector3 ScreenNDCToWorld(
const AZ::Vector2& ndcPosition, const AZ::Matrix4x4& inverseCameraView,
const AZ::Matrix4x4& inverseCameraProjection);
//! Returns the camera projection for the current camera state.
AZ::Matrix4x4 CameraProjection(const CameraState& cameraState);
@@ -353,6 +353,7 @@ namespace AzFramework
// Get the dimensions of the display device on which the window is currently displayed.
MONITORINFO monitorInfo;
memset(&monitorInfo, 0, sizeof(MONITORINFO)); // C4701 potentially uninitialized local variable 'monitorInfo' used
monitorInfo.cbSize = sizeof(MONITORINFO);
const BOOL success = monitor ? GetMonitorInfo(monitor, &monitorInfo) : FALSE;
if (!success)
@@ -97,7 +97,7 @@ namespace AzManipulatorTestFramework
if (m_logging)
{
AZStd::string message = AZStd::string::format(format, args...);
std::cout << "[ActionDispatcher] " << message.c_str() << "\n";
AZ_Printf("[ActionDispatcher] %s", message.c_str());
}
}
@@ -12,17 +12,24 @@
#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);
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(
@@ -40,8 +47,7 @@ namespace AzManipulatorTestFramework
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 +67,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
@@ -12,14 +12,13 @@
#pragma once
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/ActionDispatcher.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
namespace AzManipulatorTestFramework
{
//! Dispatches actions immediately to the manipulators.
class ImmediateModeActionDispatcher
: public ActionDispatcher<ImmediateModeActionDispatcher>
class ImmediateModeActionDispatcher : public ActionDispatcher<ImmediateModeActionDispatcher>
{
using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier;
using KeyboardModifiers = AzToolsFramework::ViewportInteraction::KeyboardModifiers;
@@ -62,7 +61,7 @@ namespace AzManipulatorTestFramework
void MouseLButtonUpImpl() override;
void MousePositionImpl(const AzFramework::ScreenPoint& position) override;
void KeyboardModifierDownImpl(const KeyboardModifier& keyModifier) override;
void KeyboardModifierUpImpl(const KeyboardModifier& keyModifier) override;
void KeyboardModifierUpImpl(const KeyboardModifier& keyModifier) override;
void ExpectManipulatorBeingInteractedImpl() override;
void ExpectManipulatorNotBeingInteractedImpl() override;
void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) override;
@@ -97,8 +96,7 @@ namespace AzManipulatorTestFramework
return this;
}
inline ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetKeyboardModifiers(
KeyboardModifiers& keyboardModifiers)
inline ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetKeyboardModifiers(KeyboardModifiers& keyboardModifiers)
{
keyboardModifiers = GetKeyboardModifiers();
return this;
@@ -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,23 @@ namespace AzManipulatorTestFramework
using MouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent;
using MousePick = AzToolsFramework::ViewportInteraction::MousePick;
AZStd::shared_ptr<AzToolsFramework::LinearManipulator> CreateLinearManipulator(
// 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 +62,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 +124,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 +133,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 +151,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
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ViewportInteraction.h>
@@ -19,10 +19,10 @@ namespace AzManipulatorTestFramework
using MouseInteraction = AzToolsFramework::ViewportInteraction::MouseInteraction;
using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
class CustomManipulatorManager
: public AzToolsFramework::ManipulatorManager
class CustomManipulatorManager : public AzToolsFramework::ManipulatorManager
{
using ManagerBase = AzToolsFramework::ManipulatorManager;
public:
using ManagerBase::ManagerBase;
@@ -31,18 +31,17 @@ namespace AzManipulatorTestFramework
};
//! Implementation of the manipulator interface using direct access to the manipulator manager.
class DirectCallManipulatorManager
: public ManipulatorManagerInterface
class DirectCallManipulatorManager : public ManipulatorManagerInterface
{
public:
DirectCallManipulatorManager(
ViewportInteractionInterface* viewportInteraction,
AZStd::shared_ptr<CustomManipulatorManager> manipulatorManager);
ViewportInteractionInterface* viewportInteraction, AZStd::shared_ptr<CustomManipulatorManager> manipulatorManager);
// ManipulatorManagerInterface ...
void ConsumeMouseInteractionEvent(const MouseInteractionEvent& event);
AzToolsFramework::ManipulatorManagerId GetId() const override;
bool ManipulatorBeingInteracted() const override;
private:
// Trigger the updating of manipulator bounds.
void DrawManipulators(const MouseInteraction& mouseInteraction);
@@ -61,8 +60,7 @@ namespace AzManipulatorTestFramework
}
DirectCallManipulatorManager::DirectCallManipulatorManager(
ViewportInteractionInterface* viewportInteraction,
AZStd::shared_ptr<CustomManipulatorManager> manipulatorManager)
ViewportInteractionInterface* viewportInteraction, AZStd::shared_ptr<CustomManipulatorManager> manipulatorManager)
: m_viewportInteraction(viewportInteraction)
, m_manipulatorManager(AZStd::move(manipulatorManager))
{
@@ -126,11 +124,9 @@ namespace AzManipulatorTestFramework
DirectCallManipulatorViewportInteraction::DirectCallManipulatorViewportInteraction()
: m_customManager(
AZStd::make_unique<CustomManipulatorManager>(
AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId"))))
AZStd::make_unique<CustomManipulatorManager>(AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId"))))
, m_viewportInteraction(AZStd::make_unique<ViewportInteraction>())
, m_manipulatorManager(
AZStd::make_unique<DirectCallManipulatorManager>(m_viewportInteraction.get(), m_customManager))
, m_manipulatorManager(AZStd::make_unique<DirectCallManipulatorManager>(m_viewportInteraction.get(), m_customManager))
{
}
@@ -10,8 +10,8 @@
*
*/
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzToolsFramework/ComponentMode/EditorComponentModeBus.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
@@ -33,8 +33,7 @@ namespace AzManipulatorTestFramework
using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier;
using MouseInteractionEvent = AzToolsFramework::ViewportInteraction::MouseInteractionEvent;
ImmediateModeActionDispatcher::ImmediateModeActionDispatcher(
ManipulatorViewportInteraction& viewportManipulatorInteraction)
ImmediateModeActionDispatcher::ImmediateModeActionDispatcher(ManipulatorViewportInteraction& viewportManipulatorInteraction)
: m_viewportManipulatorInteraction(viewportManipulatorInteraction)
{
}
@@ -126,8 +125,7 @@ namespace AzManipulatorTestFramework
void ImmediateModeActionDispatcher::EnterComponentModeImpl(const AZ::Uuid& uuid)
{
using AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus;
ComponentModeSystemRequestBus::Broadcast(
&ComponentModeSystemRequestBus::Events::AddSelectedComponentModesOfType, uuid);
ComponentModeSystemRequestBus::Broadcast(&ComponentModeSystemRequestBus::Events::AddSelectedComponentModesOfType, uuid);
}
const AzToolsFramework::ViewportInteraction::MouseInteractionEvent* ImmediateModeActionDispatcher::GetMouseInteractionEvent() const
@@ -144,8 +142,7 @@ namespace AzManipulatorTestFramework
AzToolsFramework::ViewportInteraction::MouseInteractionEvent* ImmediateModeActionDispatcher::GetMouseInteractionEvent()
{
return const_cast<MouseInteractionEvent*>(
static_cast<const ImmediateModeActionDispatcher*>(this)->GetMouseInteractionEvent());
return const_cast<MouseInteractionEvent*>(static_cast<const ImmediateModeActionDispatcher*>(this)->GetMouseInteractionEvent());
}
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::ExpectTrue(bool result)
@@ -162,8 +159,7 @@ namespace AzManipulatorTestFramework
return this;
}
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetEntityWorldTransform(
AZ::EntityId entityId, AZ::Transform& transform)
ImmediateModeActionDispatcher* ImmediateModeActionDispatcher::GetEntityWorldTransform(AZ::EntityId entityId, AZ::Transform& transform)
{
Log("Getting entity world transform");
transform = AzToolsFramework::GetWorldTransform(entityId);
@@ -11,17 +11,18 @@
*/
#include "AzManipulatorTestFrameworkTestFixtures.h"
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
namespace UnitTest
{
class AzManipulatorTestFrameworkBusCallTestFixture
: public LinearManipulatorTestFixture
class AzManipulatorTestFrameworkBusCallTestFixture : public LinearManipulatorTestFixture
{
protected:
AzManipulatorTestFrameworkBusCallTestFixture()
: LinearManipulatorTestFixture(AzToolsFramework::g_mainManipulatorManagerId) {}
: LinearManipulatorTestFixture(AzToolsFramework::g_mainManipulatorManagerId)
{
}
bool IsManipulatorInteractingBusCall() const
{
@@ -37,8 +38,8 @@ namespace UnitTest
TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportLeftMouseClick)
{
// given a left mouse down ray in world space
auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent(
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
auto event =
AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
// consume the mouse down and up events
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
@@ -56,8 +57,8 @@ namespace UnitTest
TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportMouseMoveHover)
{
// given a left mouse down ray in world space
const auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent(
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Move);
const auto event =
AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Move);
// consume the mouse move event
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
@@ -75,8 +76,8 @@ namespace UnitTest
TEST_F(AzManipulatorTestFrameworkBusCallTestFixture, ConsumeViewportMouseMoveActive)
{
// given a left mouse down ray in world space
auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent(
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
auto event =
AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
// consume the mouse down event
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
@@ -110,14 +111,14 @@ namespace UnitTest
const AZ::Vector3 initialManipulatorPosition = m_linearManipulator->GetLocalPosition();
m_linearManipulator->InstallMouseMoveCallback(
[&movementAlongAxis, this](const AzToolsFramework::LinearManipulator::Action& action)
{
movementAlongAxis = action.LocalPositionOffset();
m_linearManipulator->SetLocalPosition(action.LocalPosition());
});
{
movementAlongAxis = action.LocalPositionOffset();
m_linearManipulator->SetLocalPosition(action.LocalPosition());
});
// given a left mouse down ray in world space
auto event = AzManipulatorTestFramework::CreateMouseInteractionEvent(
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
auto event =
AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
// consume the mouse down event
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
@@ -134,7 +135,7 @@ namespace UnitTest
// consume the mouse up event
event.m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Up;
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
// expect the left mouse down/up sanity flags to be set
EXPECT_TRUE(m_receivedLeftMouseDown);
EXPECT_TRUE(m_receivedLeftMouseUp);
@@ -14,10 +14,10 @@
namespace UnitTest
{
class CustomManipulatorManager
: public AzToolsFramework::ManipulatorManager
class CustomManipulatorManager : public AzToolsFramework::ManipulatorManager
{
using ManagerBase = AzToolsFramework::ManipulatorManager;
public:
using ManagerBase::ManagerBase;
@@ -27,17 +27,17 @@ namespace UnitTest
}
};
class AzManipulatorTestFrameworkCustomManagerTestFixture
: public LinearManipulatorTestFixture
class AzManipulatorTestFrameworkCustomManagerTestFixture : public LinearManipulatorTestFixture
{
protected:
AzManipulatorTestFrameworkCustomManagerTestFixture()
: LinearManipulatorTestFixture(AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId"))) {}
: LinearManipulatorTestFixture(AzToolsFramework::ManipulatorManagerId(AZ::Crc32("TestManipulatorManagerId")))
{
}
void SetUpEditorFixtureImpl() override
{
m_manipulatorManager =
AZStd::make_shared<CustomManipulatorManager>(m_manipulatorManagerId);
m_manipulatorManager = AZStd::make_shared<CustomManipulatorManager>(m_manipulatorManagerId);
LinearManipulatorTestFixture::SetUpEditorFixtureImpl();
}
@@ -115,9 +115,9 @@ namespace UnitTest
m_linearManipulator->InstallMouseMoveCallback(
[&movementAlongAxis](const AzToolsFramework::LinearManipulator::Action& action)
{
movementAlongAxis = action.m_current.m_localPositionOffset;
});
{
movementAlongAxis = action.m_current.m_localPositionOffset;
});
// consume the mouse down event
m_manipulatorManager->ConsumeViewportMousePress(m_interaction);
@@ -141,4 +141,3 @@ namespace UnitTest
EXPECT_EQ(movementAlongAxis, expectedPositionAfterMovementAlongAxis);
}
} // namespace UnitTest
@@ -10,52 +10,55 @@
*
*/
#include "AzManipulatorTestFrameworkTestFixtures.h"
#include <AZTestShared/Math/MathTestHelpers.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>
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,68 @@ 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
@@ -15,8 +15,7 @@
namespace UnitTest
{
class AValidViewportInteraction
: public ToolsApplicationFixture
class AValidViewportInteraction : public ToolsApplicationFixture
{
public:
AValidViewportInteraction()
@@ -27,8 +26,7 @@ namespace UnitTest
protected:
void SetUpEditorFixtureImpl() override
{
m_cameraState =
AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AZ::Vector2(800.0f, 600.0f));
m_cameraState = AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AZ::Vector2(800.0f, 600.0f));
}
public:
@@ -11,49 +11,48 @@
*/
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
#include <AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
namespace UnitTest
{
class AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture
: public ToolsApplicationFixture
class AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture : public ToolsApplicationFixture
{
protected:
struct State
{
State(AZStd::unique_ptr<AzManipulatorTestFramework::ManipulatorViewportInteraction> viewportManipulatorInteraction)
: m_viewportManipulatorInteraction(viewportManipulatorInteraction.release())
, 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))
, m_linearManipulator(AzManipulatorTestFramework::CreateLinearManipulator(
m_viewportManipulatorInteraction->GetManipulatorManager().GetId(),
/*position=*/AZ::Vector3(0.0f, 50.0f, 0.0f),
/*radius=*/m_boundsRadius))
{
// default sanity check call backs
m_linearManipulator->InstallLeftMouseDownCallback(
[this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action)
{
m_receivedLeftMouseDown = true;
});
{
m_receivedLeftMouseDown = true;
});
m_linearManipulator->InstallMouseMoveCallback(
[this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action)
{
m_receivedMouseMove = true;
});
{
m_receivedMouseMove = true;
});
m_linearManipulator->InstallLeftMouseUpCallback(
[this]([[maybe_unused]] const AzToolsFramework::LinearManipulator::Action& action)
{
m_receivedLeftMouseUp = true;
});
{
m_receivedLeftMouseUp = true;
});
}
~State() = default;
@@ -79,13 +78,12 @@ namespace UnitTest
protected:
void SetUpEditorFixtureImpl() override
{
m_directState = AZStd::make_unique<State>(
AZStd::make_unique<AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction>());
m_busState = AZStd::make_unique<State>(
AZStd::make_unique<AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction>());
m_directState =
AZStd::make_unique<State>(AZStd::make_unique<AzManipulatorTestFramework::DirectCallManipulatorViewportInteraction>());
m_busState =
AZStd::make_unique<State>(AZStd::make_unique<AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction>());
m_cameraState =
AzFramework::CreateIdentityDefaultCamera(
AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
}
void TearDownEditorFixtureImpl() override
@@ -105,8 +103,7 @@ namespace UnitTest
{
// given a left mouse down ray in world space
// consume the mouse down and up events
state.m_actionDispatcher
->CameraState(m_cameraState)
state.m_actionDispatcher->CameraState(m_cameraState)
->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState))
->MouseLButtonDown()
->Trace("Expecting left mouse button down")
@@ -126,31 +123,27 @@ namespace UnitTest
->ExpectTrue(state.m_receivedLeftMouseUp)
->ExpectTrue(state.m_receivedMouseMove)
->ExpectFalse(state.m_linearManipulator->PerformingAction())
->ExpectManipulatorNotBeingInteracted()
;
->ExpectManipulatorNotBeingInteracted();
}
void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::ConsumeViewportMouseMoveHover(State& state)
{
// given a left mouse down ray in world space
// consume the mouse move event
state.m_actionDispatcher
->CameraState(m_cameraState)
state.m_actionDispatcher->CameraState(m_cameraState)
->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState))
->ExpectFalse(state.m_linearManipulator->PerformingAction())
->ExpectManipulatorNotBeingInteracted()
->ExpectFalse(state.m_receivedLeftMouseDown)
->ExpectFalse(state.m_receivedMouseMove)
->ExpectFalse(state.m_receivedLeftMouseUp)
;
->ExpectFalse(state.m_receivedLeftMouseUp);
}
void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::ConsumeViewportMouseMoveActive(State& state)
{
// given a left mouse down ray in world space
// consume the mouse move event
state.m_actionDispatcher
->CameraState(m_cameraState)
state.m_actionDispatcher->CameraState(m_cameraState)
->MouseLButtonDown()
->MousePosition(AzManipulatorTestFramework::GetCameraStateViewportCenter(m_cameraState))
->ExpectTrue(state.m_linearManipulator->PerformingAction())
@@ -158,8 +151,7 @@ namespace UnitTest
->MouseLButtonUp()
->ExpectTrue(state.m_receivedLeftMouseDown)
->ExpectTrue(state.m_receivedMouseMove)
->ExpectTrue(state.m_receivedLeftMouseUp)
;
->ExpectTrue(state.m_receivedLeftMouseUp);
}
void AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture::MoveManipulatorAlongAxis(State& state)
@@ -176,8 +168,7 @@ 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);
@@ -185,12 +176,11 @@ namespace UnitTest
state.m_linearManipulator->InstallMouseMoveCallback(
[&movementAlongAxis](const AzToolsFramework::LinearManipulator::Action& action)
{
movementAlongAxis = action.LocalPosition();
});
{
movementAlongAxis = action.LocalPosition();
});
state.m_actionDispatcher
->CameraState(m_cameraState)
state.m_actionDispatcher->CameraState(m_cameraState)
->MousePosition(initialPositionScreen)
->MouseLButtonDown()
->ExpectTrue(state.m_linearManipulator->PerformingAction())
@@ -199,8 +189,7 @@ namespace UnitTest
->MouseLButtonUp()
->ExpectTrue(state.m_receivedLeftMouseDown)
->ExpectTrue(state.m_receivedLeftMouseUp)
->ExpectTrue(movementAlongAxis.IsClose(finalPositionWorld, 0.01f))
;
->ExpectTrue(movementAlongAxis.IsClose(finalPositionWorld, 0.01f));
}
TEST_F(AzManipulatorTestFrameworkWorldSpaceBuilderTestFixture, ConsumeViewportLeftMouseClick)
@@ -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;
@@ -46,7 +46,7 @@ namespace AzNetworking
}
else if (m_updateRate < updateTimeMs)
{
AZLOG_INFO("TimedThread bled %d ms", aznumeric_cast<int32_t>(updateTimeMs - m_updateRate));
AZLOG(NET_TimedThread, "TimedThread bled %d ms", aznumeric_cast<int32_t>(updateTimeMs - m_updateRate));
}
}
OnStop();
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Icon / Locked Status</title>
<g id="Icon-/-Locked-Status" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group-9">
<g id="Icons-/-Icon-Grid" transform="translate(17.000000, 15.000000)" fill="#FFFFFF">
<path d="M3,0 C4.03553391,-1.90224492e-16 4.875,0.839466094 4.875,1.875 L4.875,3.6 L6,3.6 L6,8 L0,8 L0,3.6 L1.125,3.6 L1.125,1.875 C1.125,0.839466094 1.96446609,1.90224492e-16 3,0 Z M3.375,5.2 L2.625,5.2 L2.625,6.4 L3.375,6.4 L3.375,5.2 Z M3,0.8 C2.37867966,0.8 1.875,1.30367966 1.875,1.925 L1.875,1.925 L1.875,3.6 L4.125,3.6 L4.125,1.925 C4.125,1.30367966 3.62132034,0.8 3,0.8 Z" id="Combined-Shape"></path>
</g>
<rect id="Rectangle" fill="#F9F9F9" opacity="0" x="0" y="0" width="24" height="24"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1017 B

@@ -356,7 +356,8 @@
<file>img/UI20/toolbar/Load.svg</file>
<file>img/UI20/toolbar/Local.svg</file>
<file>img/UI20/toolbar/Locked.svg</file>
<file>img/UI20/toolbar/LUA.svg</file>
<file>img/UI20/toolbar/Locked_Status.svg</file>
<file>img/UI20/toolbar/LUA.svg</file>
<file>img/UI20/toolbar/Material.svg</file>
<file>img/UI20/toolbar/Measure.svg</file>
<file>img/UI20/toolbar/Move.svg</file>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Camera </title>
<g id="Camera-" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Icon-2" fill="#FFFFFF" transform="translate(1.666667, 4.166667)">
<path d="M11.5739175,9.2927927 C11.5739175,9.54639717 11.3384276,9.99926232 10.8312187,9.99926232 C10.3240097,9.99926232 2.37169783,10.0264342 2.13620796,10.0264342 C1.74674394,10.0264342 1.33916531,9.69131402 1.33916531,9.09353203 C1.33916531,8.76746913 1.35126587,5.13853395 1.35126587,4.84870026 C1.35126587,4.37772052 1.35727992,4.13013009 1.81014506,4.13013009 C2.2630102,4.13013009 10.840276,4.11201548 10.840276,4.11201548 C11.4199434,4.11201548 11.5829748,4.51959411 11.5829748,4.86377162 C11.5829748,5.20794912 11.5739175,9.03918822 11.5739175,9.2927927 L11.5739175,9.2927927 Z M2.65247422,1.24990779 C2.65247422,1.09593364 2.65247422,0.941959493 2.77927646,0.941959493 L9.83491536,0.941959493 C10.0070041,0.941959493 10.2062648,0.978188705 10.2062648,1.16839206 C10.2062648,1.35859542 10.1972075,2.73530545 10.1972075,2.73530545 L2.64943097,2.7111768 L2.65247422,1.24990779 Z M16.9539554,4.02144245 L16.374288,4.03049976 L14.6896297,5.50684012 L14.2548791,5.50684012 C14.2548791,5.50684012 13.1317736,3.56857731 13.0049713,3.31497283 C12.8781691,3.06136835 12.4615332,2.77153466 12.2622725,2.77153466 L11.139167,2.77153466 C11.139167,2.77153466 11.1210524,0.905730282 11.1210524,0.579667381 C11.1210524,0.253604479 10.8131041,2.81996648e-13 10.4145827,2.81996648e-13 L2.22678099,2.81996648e-13 C1.86144562,2.81996648e-13 1.66522821,0.208317965 1.66522821,0.45887919 L1.66522821,2.69907624 C1.3325716,2.7055975 1.26148988,2.70509029 1.06744623,2.70509029 C0.626681643,2.70509029 0.43343503,2.86812174 0.43343503,3.51423349 L0.43343503,9.83623086 C0.43343503,10.5698724 0.804784446,10.8778207 1.36633722,10.8778207 C1.72862933,10.8778207 11.5920321,10.8687634 12.0992411,10.8687634 C12.60645,10.8687634 12.8238253,10.4340129 13.0049713,10.198523 C13.1861174,9.9630331 14.309223,8.11534333 14.309223,8.11534333 L14.8164319,8.09722872 L16.4558037,9.60074099 L16.97207,9.60074099 L16.9539554,4.02144245 Z" id="Icon"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>debug</title>
<g id="debug" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M11.3615865,7.917238 L15.2274672,9.63843901 L16.4675037,9.16172668 C16.6979214,9.07292417 16.9553551,9.18924382 17.0442998,9.41972476 C17.1330234,9.64993705 17.0253844,9.89284574 16.7952509,9.98177479 L16.7952509,9.98177479 L15.3951151,10.4956726 C15.2842902,10.5384499 15.1889358,10.4726675 15.0806503,10.4244557 L15.0806503,10.4244557 L14.1703124,10.0191471 C14.3857263,10.9664393 14.4599954,12.0211666 14.2565873,12.952264 L14.2565873,12.952264 L15.6721159,13.5824979 C15.8976398,13.6829076 15.9908466,13.9650071 15.8904369,14.190531 C15.7900905,14.4159128 15.5180189,14.5355501 15.292495,14.4351404 L15.292495,14.4351404 L13.9556938,13.8399581 C13.6322377,14.54733 13.1335636,15.1766897 12.5630158,15.6037725 L12.5630158,15.6037725 L12.8756514,15.7429668 C12.983937,15.7911787 13.0605157,15.8995144 13.1027401,16.0104336 L13.1027401,16.0104336 L13.6353002,17.4447605 C13.7234077,17.6752093 13.6080984,17.9334334 13.3776496,18.021541 C13.2626228,18.0653422 13.1408059,18.058613 13.0364993,18.0121727 C12.9319085,17.9656059 12.8452864,17.8786807 12.8011855,17.7631798 L12.8011855,17.7631798 L12.3264968,16.520128 L11.644667,16.2165578 C10.4621412,16.7117239 8.87932984,16.9345084 7.56328989,16.4483518 L7.56328989,16.4483518 L11.3615865,7.917238 Z M5.52878415,4.3232224 C5.75937506,4.23517812 6.01946614,4.34552927 6.10779463,4.57624672 L6.10779463,4.57624672 L6.58675456,5.80894035 L10.4526353,7.53014136 L6.6529468,16.0643815 C5.4063142,15.4223335 4.43289769,14.215203 4.07288375,12.8629772 L4.07288375,12.8629772 L3.41379116,12.5695302 L2.17275891,13.0473317 C2.05755786,13.0919067 1.93523585,13.0847824 1.83064504,13.0382156 C1.72633845,12.9917753 1.64104404,12.9033978 1.59654788,12.7884022 C1.5078242,12.5581899 1.62471629,12.294881 1.85492858,12.2061574 L1.85492858,12.2061574 L3.27301757,11.6515537 C3.38384243,11.6087763 3.51545059,11.5931314 3.62387829,11.6414065 L3.62387829,11.6414065 L3.91988732,11.7731982 C3.85933759,11.0651327 3.99592287,10.2745607 4.30516824,9.5608618 L4.30516824,9.5608618 L2.97859873,8.970235 C2.7530748,8.86982528 2.6599312,8.58758374 2.76027765,8.36220193 C2.86068737,8.13667801 3.13269567,8.01718285 3.35821959,8.11759257 L3.35821959,8.11759257 L4.7450425,8.73504591 C5.26222301,7.94364898 6.01359598,7.25652125 6.89624338,6.79811742 L6.89624338,6.79811742 L6.10101221,6.4440577 C5.99258451,6.39578258 5.88032145,6.36759526 5.83803372,6.25681811 L5.83803372,6.25681811 L5.26971048,4.90243425 C5.18174504,4.67204872 5.29833534,4.41132994 5.52878415,4.3232224 Z M10.8942352,2.34455584 C11.1427316,2.24942103 11.4210854,2.3733521 11.5165098,2.62161032 L11.5165098,2.62161032 L11.9777045,3.8224019 C12.2035494,3.86678469 12.4283918,3.93403345 12.6476126,4.03163684 C12.8668334,4.12924023 13.0677354,4.25026013 13.2518379,4.38839772 L13.2518379,4.38839772 L14.4533966,3.92589245 C14.7019612,3.83060445 14.9816108,3.95162483 15.0770352,4.19988305 C15.1723915,4.44829447 15.0509158,4.72113321 14.8025726,4.81633622 L14.8025726,4.81633622 L13.9775725,5.12324418 C14.5520125,5.98310253 14.7248639,7.02632912 14.247419,8.09868801 L14.247419,8.09868801 L8.55503156,5.56427385 C9.03247651,4.49191495 9.9234901,3.92253515 10.946252,3.77379694 L10.946252,3.77379694 L10.6171125,2.96698358 C10.5217563,2.71857217 10.6457388,2.43969065 10.8942352,2.34455584 Z" id="Combined-Shape" fill="#FFFFFF"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>resolution</title>
<g id="resolution" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M17.7222222,2.5 L17.7222222,17.7222222 L2.5,17.7222222 L2.5,2.5 L17.7222222,2.5 Z M16.721,4.45 L3.499,4.45 L3.499,10.111 L10.1293705,10.1111111 L10.129,16.722 L16.722,16.722 L16.721,4.45 Z M9.128,11.722 L3.999,11.722 L4,16.222 L9.129,16.222 L9.128,11.722 Z" id="Combined-Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 654 B

@@ -15,4 +15,9 @@
<file alias="download.svg">Notifications/download.svg</file>
<file alias="link.svg">Notifications/link.svg</file>
</qresource>
<qresource prefix="/Menu">
<file alias="resolution.svg">Menu/resolution.svg</file>
<file alias="debug.svg">Menu/debug.svg</file>
<file alias="camera.svg">Menu/camera.svg</file>
</qresource>
</RCC>
@@ -1,28 +1,32 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "AngularManipulator.h"
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
#include <AzToolsFramework/Manipulators/ManipulatorSnapping.h>
#include <AzToolsFramework/Manipulators/ManipulatorView.h>
namespace AzToolsFramework
{
static const float s_circularRotateThresholdDegrees = 80.0f;
static const float CircularRotateThresholdDegrees = 80.0f;
AngularManipulator::ActionInternal AngularManipulator::CalculateManipulationDataStart(
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform,
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, const float rayDistance)
const Fixed& fixed,
const AZ::Transform& worldFromLocal,
const AZ::Transform& localTransform,
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
const float rayDistance)
{
const AZ::Transform worldFromLocalWithTransform = worldFromLocal * localTransform;
const AZ::Vector3 worldAxis = TransformDirectionNoScaling(worldFromLocalWithTransform, fixed.m_axis);
@@ -35,7 +39,7 @@ namespace AzToolsFramework
// if angular manipulator axis is at right angles to us, use initial ray direction
// as plane normal and use hit position on manipulator as plane point
const float pickAngle = AZ::RadToDeg(AZ::Acos(AZ::Abs(rayDirection.Dot(worldAxis))));
if (pickAngle > s_circularRotateThresholdDegrees)
if (pickAngle > CircularRotateThresholdDegrees)
{
actionInternal.m_start.m_planeNormal = -rayDirection;
actionInternal.m_start.m_planePoint = rayOrigin + rayDirection * rayDistance;
@@ -43,8 +47,8 @@ namespace AzToolsFramework
// store initial world hit position
Internal::CalculateRayPlaneIntersectingPoint(
rayOrigin, rayDirection, actionInternal.m_start.m_planePoint,
actionInternal.m_start.m_planeNormal, actionInternal.m_current.m_worldHitPosition);
rayOrigin, rayDirection, actionInternal.m_start.m_planePoint, actionInternal.m_start.m_planeNormal,
actionInternal.m_current.m_worldHitPosition);
// store entity transform (to go from local to world space)
// and store our own starting local transform
@@ -56,31 +60,33 @@ namespace AzToolsFramework
}
AngularManipulator::Action AngularManipulator::CalculateManipulationDataAction(
const Fixed& fixed, ActionInternal& actionInternal, const AZ::Transform& worldFromLocal,
const AZ::Transform& localTransform, const bool snapping, const float angleStepDegrees,
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
const Fixed& fixed,
ActionInternal& actionInternal,
const AZ::Transform& worldFromLocal,
const AZ::Transform& localTransform,
const bool snapping,
const float angleStepDegrees,
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
const ViewportInteraction::KeyboardModifiers keyboardModifiers)
{
const AZ::Transform worldFromLocalWithTransform = worldFromLocal * localTransform;
const AZ::Vector3 worldAxis = TransformDirectionNoScaling(worldFromLocalWithTransform, fixed.m_axis);
AZ::Vector3 worldHitPosition = AZ::Vector3::CreateZero();
Internal::CalculateRayPlaneIntersectingPoint(rayOrigin, rayDirection,
actionInternal.m_start.m_planePoint, actionInternal.m_start.m_planeNormal,
worldHitPosition);
Internal::CalculateRayPlaneIntersectingPoint(
rayOrigin, rayDirection, actionInternal.m_start.m_planePoint, actionInternal.m_start.m_planeNormal, worldHitPosition);
// get vector from center of rotation for current and previous frame
const AZ::Vector3 center = worldFromLocalWithTransform.GetTranslation();
const AZ::Vector3 currentWorldHitVector = (worldHitPosition - center).GetNormalizedSafe();
const AZ::Vector3 previousWorldHitVector =
(actionInternal.m_current.m_worldHitPosition - center).GetNormalizedSafe();
const AZ::Vector3 previousWorldHitVector = (actionInternal.m_current.m_worldHitPosition - center).GetNormalizedSafe();
// calculate which direction we rotated
const AZ::Vector3 worldAxisRight = worldAxis.Cross(previousWorldHitVector);
const float rotateSign = Sign(currentWorldHitVector.Dot(worldAxisRight));
// how far did we rotate this frame
const float rotationAngleRad = AZ::Acos(AZ::GetMin<float>(
1.0f, currentWorldHitVector.Dot(previousWorldHitVector)));
const float rotationAngleRad = AZ::Acos(AZ::GetMin<float>(1.0f, currentWorldHitVector.Dot(previousWorldHitVector)));
actionInternal.m_current.m_worldHitPosition = worldHitPosition;
// if we're snapping, only increment current radians when we know
@@ -148,16 +154,13 @@ namespace AzToolsFramework
// calculate initial state when mouse press first happens
m_actionInternal = CalculateManipulationDataStart(
m_fixed, TransformNormalizedScale(GetSpace()), TransformNormalizedScale(GetLocalTransform()),
interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection,
rayIntersectionDistance);
interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, rayIntersectionDistance);
if (m_onLeftMouseDownCallback)
{
m_onLeftMouseDownCallback(CalculateManipulationDataAction(
m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal,
m_actionInternal.m_start.m_localTransform, snapping, angleStep,
interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection,
interaction.m_keyboardModifiers));
m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal, m_actionInternal.m_start.m_localTransform, snapping,
angleStep, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, interaction.m_keyboardModifiers));
}
}
@@ -167,12 +170,9 @@ namespace AzToolsFramework
{
// calculate delta rotation
m_onMouseMoveCallback(CalculateManipulationDataAction(
m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal,
m_actionInternal.m_start.m_localTransform,
AngleSnapping(interaction.m_interactionId.m_viewportId),
AngleStep(interaction.m_interactionId.m_viewportId),
interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection,
interaction.m_keyboardModifiers));
m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal, m_actionInternal.m_start.m_localTransform,
AngleSnapping(interaction.m_interactionId.m_viewportId), AngleStep(interaction.m_interactionId.m_viewportId),
interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, interaction.m_keyboardModifiers));
}
}
@@ -181,12 +181,9 @@ namespace AzToolsFramework
if (m_onLeftMouseUpCallback)
{
m_onLeftMouseUpCallback(CalculateManipulationDataAction(
m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal,
m_actionInternal.m_start.m_localTransform,
AngleSnapping(interaction.m_interactionId.m_viewportId),
AngleStep(interaction.m_interactionId.m_viewportId),
interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection,
interaction.m_keyboardModifiers));
m_fixed, m_actionInternal, m_actionInternal.m_start.m_worldFromLocal, m_actionInternal.m_start.m_localTransform,
AngleSnapping(interaction.m_interactionId.m_viewportId), AngleStep(interaction.m_interactionId.m_viewportId),
interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, interaction.m_keyboardModifiers));
}
}
@@ -197,12 +194,9 @@ namespace AzToolsFramework
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
m_manipulatorView->Draw(
GetManipulatorManagerId(), managerState,
GetManipulatorId(), {
ApplySpace(GetLocalTransform()), GetNonUniformScale(),
AZ::Vector3::CreateZero(), MouseOver()
},
debugDisplay, cameraState, mouseInteraction);
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, cameraState,
mouseInteraction);
}
void AngularManipulator::SetAxis(const AZ::Vector3& axis)
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -22,14 +22,14 @@ namespace AzToolsFramework
{
class ManipulatorView;
/// AngularManipulator serves as a visual tool for users to change a component's property based on rotation
/// around an axis. The rotation angle increases if the rotation goes counter clock-wise when looking
/// in the opposite direction the rotation axis points to.
//! AngularManipulator serves as a visual tool for users to change a component's property based on rotation
//! around an axis. The rotation angle increases if the rotation goes counter clock-wise when looking
//! in the opposite direction the rotation axis points to.
class AngularManipulator
: public BaseManipulator
, public ManipulatorSpaceWithLocalTransform
{
/// Private constructor.
//! Private constructor.
explicit AngularManipulator(const AZ::Transform& worldFromLocal);
public:
@@ -42,33 +42,36 @@ namespace AzToolsFramework
~AngularManipulator() = default;
/// A Manipulator must only be created and managed through a shared_ptr.
//! A Manipulator must only be created and managed through a shared_ptr.
static AZStd::shared_ptr<AngularManipulator> MakeShared(const AZ::Transform& worldFromLocal);
/// The state of the manipulator at the start of an interaction.
//! The state of the manipulator at the start of an interaction.
struct Start
{
AZ::Quaternion m_space; ///< Starting orientation space of manipulator.
AZ::Quaternion m_rotation; ///< Starting local rotation of the manipulator.
AZ::Quaternion m_space; //!< Starting orientation space of manipulator.
AZ::Quaternion m_rotation; //!< Starting local rotation of the manipulator.
};
/// The state of the manipulator during an interaction.
//! The state of the manipulator during an interaction.
struct Current
{
AZ::Quaternion m_delta; ///< Amount of rotation to apply to manipulator during action.
AZ::Quaternion m_delta; //!< Amount of rotation to apply to manipulator during action.
};
/// Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state).
//! Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state).
struct Action
{
Start m_start;
Current m_current;
ViewportInteraction::KeyboardModifiers m_modifiers;
AZ::Quaternion LocalOrientation() const { return m_start.m_rotation * m_current.m_delta; }
AZ::Quaternion LocalOrientation() const
{
return m_start.m_rotation * m_current.m_delta;
}
};
/// This is the function signature of callbacks that will be invoked whenever a manipulator
/// is clicked on or dragged.
//! This is the function signature of callbacks that will be invoked whenever a manipulator
//! is clicked on or dragged.
using MouseActionCallback = AZStd::function<void(const Action&)>;
void InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback);
@@ -82,46 +85,49 @@ namespace AzToolsFramework
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
void SetAxis(const AZ::Vector3& axis);
const AZ::Vector3& GetAxis() const { return m_fixed.m_axis; }
const AZ::Vector3& GetAxis() const
{
return m_fixed.m_axis;
}
void SetView(AZStd::unique_ptr<ManipulatorView>&& view);
ManipulatorView* GetView() const { return m_manipulatorView.get(); }
ManipulatorView* GetView() const
{
return m_manipulatorView.get();
}
private:
void OnLeftMouseDownImpl(
const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(
const ViewportInteraction::MouseInteraction& interaction) override;
void OnMouseMoveImpl(
const ViewportInteraction::MouseInteraction& interaction) override;
void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void SetBoundsDirtyImpl() override;
void InvalidateImpl() override;
/// Unchanging data set once for the angular manipulator.
//! Unchanging data set once for the angular manipulator.
struct Fixed
{
AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); ///< Axis for this angular manipulator to rotate around.
AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); //!< Axis for this angular manipulator to rotate around.
};
/// Initial data recorded when a press first happens with an angular manipulator.
//! Initial data recorded when a press first happens with an angular manipulator.
struct StartInternal
{
AZ::Transform m_worldFromLocal; ///< Initial transform when pressed.
AZ::Transform m_localTransform; ///< Additional transform (offset) to apply to manipulator.
AZ::Vector3 m_planePoint; ///< Position on plane to use for ray intersection.
AZ::Vector3 m_planeNormal; ///< Normal of plane to use for ray intersection.
AZ::Transform m_worldFromLocal; //!< Initial transform when pressed.
AZ::Transform m_localTransform; //!< Additional transform (offset) to apply to manipulator.
AZ::Vector3 m_planePoint; //!< Position on plane to use for ray intersection.
AZ::Vector3 m_planeNormal; //!< Normal of plane to use for ray intersection.
};
/// Current data recorded each frame during an interaction with an angular manipulator.
//! Current data recorded each frame during an interaction with an angular manipulator.
struct CurrentInternal
{
float m_preSnapRadians = 0.0f; ///< Amount of rotation before a snap (snap increment accumulator).
float m_radians = 0.0f; ///< Amount of rotation about the axis for this action.
AZ::Vector3 m_worldHitPosition; ///< Initial world space hit position.
float m_preSnapRadians = 0.0f; //!< Amount of rotation before a snap (snap increment accumulator).
float m_radians = 0.0f; //!< Amount of rotation about the axis for this action.
AZ::Vector3 m_worldHitPosition; //!< Initial world space hit position.
};
/// Wrap start and current internal data during an interaction with an angular manipulator.
//! Wrap start and current internal data during an interaction with an angular manipulator.
struct ActionInternal
{
StartInternal m_start;
@@ -135,16 +141,25 @@ namespace AzToolsFramework
MouseActionCallback m_onLeftMouseUpCallback = nullptr;
MouseActionCallback m_onMouseMoveCallback = nullptr;
AZStd::unique_ptr<ManipulatorView> m_manipulatorView; ///< Look of manipulator.
AZStd::unique_ptr<ManipulatorView> m_manipulatorView; //!< Look of manipulator.
static ActionInternal CalculateManipulationDataStart(
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform,
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float rayDistance);
const Fixed& fixed,
const AZ::Transform& worldFromLocal,
const AZ::Transform& localTransform,
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
float rayDistance);
static Action CalculateManipulationDataAction(
const Fixed& fixed, ActionInternal& actionInternal, const AZ::Transform& worldFromLocal,
const AZ::Transform& localTransform, bool snapping, float angleStepDegrees,
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
const Fixed& fixed,
ActionInternal& actionInternal,
const AZ::Transform& worldFromLocal,
const AZ::Transform& localTransform,
bool snapping,
float angleStepDegrees,
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
ViewportInteraction::KeyboardModifiers keyboardModifiers);
};
} // namespace AzToolsFramework
@@ -1,33 +1,30 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "BaseManipulator.h"
#include <AzCore/Math/IntersectSegment.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
namespace AzToolsFramework
{
AZ_CVAR(
bool, cl_manipulatorDrawDebug, false, nullptr, AZ::ConsoleFunctorFlags::Null,
"Enable debug drawing for Manipulators");
AZ_CVAR(bool, cl_manipulatorDrawDebug, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enable debug drawing for Manipulators");
const AZ::Color BaseManipulator::s_defaultMouseOverColor = AZ::Color(1.0f, 1.0f, 0.0f, 1.0f); // yellow
AZ_CLASS_ALLOCATOR_IMPL(BaseManipulator, AZ::SystemAllocator, 0)
static bool EntityIdAndEntityComponentIdComparison(
const AZ::EntityId entityId, const AZ::EntityComponentIdPair& entityComponentId)
static bool EntityIdAndEntityComponentIdComparison(const AZ::EntityId entityId, const AZ::EntityComponentIdPair& entityComponentId)
{
return entityId == entityComponentId.GetEntityId();
}
@@ -38,8 +35,7 @@ namespace AzToolsFramework
EndUndoBatch();
}
bool BaseManipulator::OnLeftMouseDown(
const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
bool BaseManipulator::OnLeftMouseDown(const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -57,8 +53,7 @@ namespace AzToolsFramework
(*this.*m_onLeftMouseDownImpl)(interaction, rayIntersectionDistance);
ToolsApplicationNotificationBus::Broadcast(
&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values);
ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values);
return true;
}
@@ -66,8 +61,7 @@ namespace AzToolsFramework
return false;
}
bool BaseManipulator::OnRightMouseDown(
const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
bool BaseManipulator::OnRightMouseDown(const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -85,8 +79,7 @@ namespace AzToolsFramework
(*this.*m_onRightMouseDownImpl)(interaction, rayIntersectionDistance);
ToolsApplicationNotificationBus::Broadcast(
&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values);
ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values);
return true;
}
@@ -118,8 +111,7 @@ namespace AzToolsFramework
EndUndoBatch();
}
bool BaseManipulator::OnMouseOver(
const ManipulatorId manipulatorId, const ViewportInteraction::MouseInteraction& interaction)
bool BaseManipulator::OnMouseOver(const ManipulatorId manipulatorId, const ViewportInteraction::MouseInteraction& interaction)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -132,8 +124,7 @@ namespace AzToolsFramework
{
OnMouseWheelImpl(interaction);
ToolsApplicationNotificationBus::Broadcast(
&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values);
ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values);
}
void BaseManipulator::OnMouseMove(const ViewportInteraction::MouseInteraction& interaction)
@@ -142,16 +133,13 @@ namespace AzToolsFramework
if (!m_performingAction)
{
AZ_Warning(
"Manipulators", false,
"MouseMove action received, but this manipulator is not performing an action");
AZ_Warning("Manipulators", false, "MouseMove action received, but this manipulator is not performing an action");
return;
}
// ensure property grid (entity inspector) values are refreshed
ToolsApplicationNotificationBus::Broadcast(
&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values);
ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values);
OnMouseMoveImpl(interaction);
}
@@ -170,16 +158,14 @@ namespace AzToolsFramework
Unregister();
}
ManipulatorManagerRequestBus::Event(managerId,
&ManipulatorManagerRequestBus::Events::RegisterManipulator, shared_from_this());
ManipulatorManagerRequestBus::Event(managerId, &ManipulatorManagerRequestBus::Events::RegisterManipulator, shared_from_this());
}
void BaseManipulator::Unregister()
{
// if the manipulator has already been unregistered, the m_manipulatorManagerId
// should be invalid which makes the call below a no-op.
ManipulatorManagerRequestBus::Event(m_manipulatorManagerId,
&ManipulatorManagerRequestBus::Events::UnregisterManipulator, this);
ManipulatorManagerRequestBus::Event(m_manipulatorManagerId, &ManipulatorManagerRequestBus::Events::UnregisterManipulator, this);
}
void BaseManipulator::Invalidate()
@@ -197,8 +183,7 @@ namespace AzToolsFramework
if (m_performingAction)
{
AZ_Warning(
"Manipulators", false,
"MouseDown action received, but the manipulator (id: %d) is still performing an action",
"Manipulators", false, "MouseDown action received, but the manipulator (id: %d) is still performing an action",
GetManipulatorId());
return;
@@ -214,8 +199,7 @@ namespace AzToolsFramework
if (!m_performingAction)
{
AZ_Warning(
"Manipulators", false,
"MouseUp action received, but this manipulator (id: %d) didn't receive MouseDown action before",
"Manipulators", false, "MouseUp action received, but this manipulator (id: %d) didn't receive MouseDown action before",
GetManipulatorId());
return;
}
@@ -263,13 +247,13 @@ namespace AzToolsFramework
if (entityComponentIdPair.GetComponentId() != AZ::InvalidComponentId)
{
PropertyEditorEntityChangeNotificationBus::Event(
entityComponentIdPair.GetEntityId(),
&PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged,
entityComponentIdPair.GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged,
entityComponentIdPair.GetComponentId());
}
else
{
AZ_Warning("Manipulators", false,
AZ_Warning(
"Manipulators", false,
"This Manipulator was only registered with an EntityId and not an EntityComponentIdPair. "
"Please use AddEntityComponentIdPair() instead of AddEntityId() when registering what this "
"Manipulator is changing.");
@@ -280,8 +264,7 @@ namespace AzToolsFramework
for (const AZ::Component* component : entity->GetComponents())
{
PropertyEditorEntityChangeNotificationBus::Event(
entity->GetId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged,
component->GetId());
entity->GetId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, component->GetId());
}
}
}
@@ -298,9 +281,7 @@ namespace AzToolsFramework
{
// look for a match (keep looking in case we have several entity ids with different component ids)
const auto entityComponentPairId =
m_entityComponentIdPairs.find_as(
entityId, AZStd::hash<AZ::EntityId>(),
&EntityIdAndEntityComponentIdComparison);
m_entityComponentIdPairs.find_as(entityId, AZStd::hash<AZ::EntityId>(), &EntityIdAndEntityComponentIdComparison);
// update the afterErased variable so we can return an iterator
// to the correct position in the container.
@@ -334,9 +315,8 @@ namespace AzToolsFramework
bool BaseManipulator::HasEntityId(const AZ::EntityId entityId) const
{
return m_entityComponentIdPairs.find_as(
entityId, AZStd::hash<AZ::EntityId>(),
&EntityIdAndEntityComponentIdComparison) != m_entityComponentIdPairs.end();
return m_entityComponentIdPairs.find_as(entityId, AZStd::hash<AZ::EntityId>(), &EntityIdAndEntityComponentIdComparison) !=
m_entityComponentIdPairs.end();
}
bool BaseManipulator::HasEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair) const
@@ -346,7 +326,8 @@ namespace AzToolsFramework
void Manipulators::Register(const ManipulatorManagerId manipulatorManagerId)
{
ProcessManipulators([manipulatorManagerId](BaseManipulator* manipulator)
ProcessManipulators(
[manipulatorManagerId](BaseManipulator* manipulator)
{
manipulator->Register(manipulatorManagerId);
});
@@ -354,7 +335,8 @@ namespace AzToolsFramework
void Manipulators::Unregister()
{
ProcessManipulators([](BaseManipulator* manipulator)
ProcessManipulators(
[](BaseManipulator* manipulator)
{
if (manipulator->Registered())
{
@@ -365,7 +347,8 @@ namespace AzToolsFramework
void Manipulators::SetBoundsDirty()
{
ProcessManipulators([](BaseManipulator* manipulator)
ProcessManipulators(
[](BaseManipulator* manipulator)
{
manipulator->SetBoundsDirty();
});
@@ -373,7 +356,8 @@ namespace AzToolsFramework
void Manipulators::AddEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair)
{
ProcessManipulators([&entityComponentIdPair](BaseManipulator* manipulator)
ProcessManipulators(
[&entityComponentIdPair](BaseManipulator* manipulator)
{
manipulator->AddEntityComponentIdPair(entityComponentIdPair);
});
@@ -381,7 +365,8 @@ namespace AzToolsFramework
void Manipulators::RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair)
{
ProcessManipulators([&entityComponentIdPair](BaseManipulator* manipulator)
ProcessManipulators(
[&entityComponentIdPair](BaseManipulator* manipulator)
{
manipulator->RemoveEntityComponentIdPair(entityComponentIdPair);
});
@@ -389,7 +374,8 @@ namespace AzToolsFramework
void Manipulators::RemoveEntityId(const AZ::EntityId entityId)
{
ProcessManipulators([entityId](BaseManipulator* manipulator)
ProcessManipulators(
[entityId](BaseManipulator* manipulator)
{
manipulator->RemoveEntityId(entityId);
});
@@ -398,7 +384,8 @@ namespace AzToolsFramework
bool Manipulators::PerformingAction()
{
bool performingAction = false;
ProcessManipulators([&performingAction](BaseManipulator* manipulator)
ProcessManipulators(
[&performingAction](BaseManipulator* manipulator)
{
if (manipulator->PerformingAction())
{
@@ -412,7 +399,8 @@ namespace AzToolsFramework
bool Manipulators::Registered()
{
bool registered = false;
ProcessManipulators([&registered](BaseManipulator* manipulator)
ProcessManipulators(
[&registered](BaseManipulator* manipulator)
{
if (manipulator->Registered())
{
@@ -433,6 +421,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);
@@ -465,8 +458,12 @@ namespace AzToolsFramework
namespace Internal
{
bool CalculateRayPlaneIntersectingPoint(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
const AZ::Vector3& pointOnPlane, const AZ::Vector3& planeNormal, AZ::Vector3& resultIntersectingPoint)
bool CalculateRayPlaneIntersectingPoint(
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
const AZ::Vector3& pointOnPlane,
const AZ::Vector3& planeNormal,
AZ::Vector3& resultIntersectingPoint)
{
float t = 0.0f;
if (AZ::Intersect::IntersectRayPlane(rayOrigin, rayDirection, pointOnPlane, planeNormal, t) > 0)
@@ -479,11 +476,12 @@ namespace AzToolsFramework
}
AZ::Vector3 TryConstrainHitPositionToView(
const AZ::Vector3& currentLocalHitPosition, const AZ::Vector3& startLocalHitPosition,
const AZ::Transform& localFromWorld, const AzFramework::CameraState& cameraState)
const AZ::Vector3& currentLocalHitPosition,
const AZ::Vector3& startLocalHitPosition,
const AZ::Transform& localFromWorld,
const AzFramework::CameraState& cameraState)
{
if (currentLocalHitPosition.GetDistance(localFromWorld.TransformPoint(cameraState.m_position))
> cameraState.m_farClip)
if (currentLocalHitPosition.GetDistance(localFromWorld.TransformPoint(cameraState.m_position)) > cameraState.m_farClip)
{
return startLocalHitPosition;
}
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -22,13 +22,13 @@
#include <AzCore/std/containers/set.h>
#include <AzCore/std/smart_ptr/enable_shared_from_this.h>
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
#include "ManipulatorSpace.h"
#include <AzToolsFramework/Manipulators/ManipulatorSpace.h>
namespace AzFramework
{
struct CameraState;
class DebugDisplayRequests;
}
} // namespace AzFramework
namespace AzToolsFramework
{
@@ -46,9 +46,8 @@ namespace AzToolsFramework
struct ManipulatorManagerState;
/// The base class for manipulators, providing interfaces for users of manipulators to talk to.
class BaseManipulator
: public AZStd::enable_shared_from_this<BaseManipulator>
//! The base class for manipulators, providing interfaces for users of manipulators to talk to.
class BaseManipulator : public AZStd::enable_shared_from_this<BaseManipulator>
{
public:
AZ_CLASS_ALLOCATOR_DECL
@@ -61,139 +60,181 @@ namespace AzToolsFramework
using EntityComponentIds = AZStd::unordered_set<AZ::EntityComponentIdPair>;
/// Callback for the event when the mouse pointer is over this manipulator and the left mouse button is pressed.
/// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer.
/// @param rayIntersectionDistance The parameter value in the ray's explicit equation that represents the intersecting point on the target manipulator in world space.
/// @return Return true if OnLeftMouseDownImpl was attached and will be used.
//! Callback for the event when the mouse pointer is over this manipulator and the left mouse button is pressed.
//! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera
//! through the mouse pointer.
//! @param rayIntersectionDistance The parameter value in the ray's explicit equation that represents the intersecting point on the
//! target manipulator in world space.
//! @return Return true if OnLeftMouseDownImpl was attached and will be used.
bool OnLeftMouseDown(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance);
/// Callback for the event when this manipulator is active and the left mouse button is released.
/// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer.
//! Callback for the event when this manipulator is active and the left mouse button is released.
//! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera
//! through the mouse pointer.
void OnLeftMouseUp(const ViewportInteraction::MouseInteraction& interaction);
/// Callback for the event when the mouse pointer is over this manipulator and the right mouse button is pressed .
/// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer.
/// @param rayIntersectionDistance The parameter value in the ray's explicit equation that represents the intersecting point on the target manipulator in world space.
/// @return Return true if OnRightMouseDownImpl was attached and will be used.
//! Callback for the event when the mouse pointer is over this manipulator and the right mouse button is pressed .
//! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera
//! through the mouse pointer.
//! @param rayIntersectionDistance The parameter value in the ray's explicit equation that represents the intersecting point on the
//! target manipulator in world space.
//! @return Return true if OnRightMouseDownImpl was attached and will be used.
bool OnRightMouseDown(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance);
/// Callback for the event when this manipulator is active and the right mouse button is released.
/// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer.
//! Callback for the event when this manipulator is active and the right mouse button is released.
//! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera
//! through the mouse pointer.
void OnRightMouseUp(const ViewportInteraction::MouseInteraction& interaction);
/// Callback for the event when this manipulator is active and the mouse is moved.
/// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer.
//! Callback for the event when this manipulator is active and the mouse is moved.
//! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera
//! through the mouse pointer.
void OnMouseMove(const ViewportInteraction::MouseInteraction& interaction);
/// Callback for the event when this manipulator is active and the mouse wheel is scrolled.
/// @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera through the mouse pointer.
//! Callback for the event when this manipulator is active and the mouse wheel is scrolled.
//! @param interaction It contains various mouse states when the event happens, as well as a ray shooting from the viewing camera
//! through the mouse pointer.
void OnMouseWheel(const ViewportInteraction::MouseInteraction& interaction);
/// This function changes the state indicating whether the manipulator is under the mouse pointer.
/// It is called in the event of OnMouseMove and OnMouseWheel only when there is no manipulator currently performing actions.
//! This function changes the state indicating whether the manipulator is under the mouse pointer.
//! It is called in the event of OnMouseMove and OnMouseWheel only when there is no manipulator currently performing actions.
bool OnMouseOver(ManipulatorId manipulatorId, const ViewportInteraction::MouseInteraction& interaction);
/// Register itself to a manipulator manager so that it can receive various mouse events and perform manipulations.
/// @param managerId The id identifying a unique manipulator manager.
//! Register itself to a manipulator manager so that it can receive various mouse events and perform manipulations.
//! @param managerId The id identifying a unique manipulator manager.
void Register(ManipulatorManagerId managerId);
/// Unregister itself from the manipulator manager it was registered with.
//! Unregister itself from the manipulator manager it was registered with.
void Unregister();
/// Bounds will need to be recalculated next time we render.
//! Bounds will need to be recalculated next time we render.
void SetBoundsDirty();
/// Is this manipulator currently registered with a manipulator manager.
//! Is this manipulator currently registered with a manipulator manager.
bool Registered() const
{
return m_manipulatorId != InvalidManipulatorId &&
m_manipulatorManagerId != InvalidManipulatorManagerId;
return m_manipulatorId != InvalidManipulatorId && m_manipulatorManagerId != InvalidManipulatorManagerId;
}
/// Is the manipulator in the middle of an action (between mouse down and mouse up).
bool PerformingAction() const { return m_performingAction; }
//! Is the manipulator in the middle of an action (between mouse down and mouse up).
bool PerformingAction() const
{
return m_performingAction;
}
/// Is the mouse currently over the manipulator (intersecting manipulator bound).
bool MouseOver() const { return m_mouseOver; }
//! Is the mouse currently over the manipulator (intersecting manipulator bound).
bool MouseOver() const
{
return m_mouseOver;
}
/// The unique id of this manipulator.
ManipulatorId GetManipulatorId() const { return m_manipulatorId; }
//! The unique id of this manipulator.
ManipulatorId GetManipulatorId() const
{
return m_manipulatorId;
}
/// The unique id of the manager this manipulator was registered with.
ManipulatorManagerId GetManipulatorManagerId() const { return m_manipulatorManagerId; }
//! The unique id of the manager this manipulator was registered with.
ManipulatorManagerId GetManipulatorManagerId() const
{
return m_manipulatorManagerId;
}
/// Returns all EntityComponentIdPairs associated with this manipulator.
//! Returns all EntityComponentIdPairs associated with this manipulator.
const EntityComponentIds& EntityComponentIdPairs() const
{
return m_entityComponentIdPairs;
}
/// Add an entity and component the manipulator is responsible for.
//! Add an entity and component the manipulator is responsible for.
void AddEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair);
/// Remove an entity from being affected by this manipulator.
/// @note All components on this entity registered with the manipulator will be removed.
//! Remove an entity from being affected by this manipulator.
//! @note All components on this entity registered with the manipulator will be removed.
EntityComponentIds::iterator RemoveEntityId(AZ::EntityId entityId);
/// Remove a specific component (via a EntityComponentIdPair) being affected by this manipulator.
//! Remove a specific component (via a EntityComponentIdPair) being affected by this manipulator.
EntityComponentIds::iterator RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair);
/// Is this entity currently being tracked by this manipulator.
//! Is this entity currently being tracked by this manipulator.
bool HasEntityId(AZ::EntityId entityId) const;
/// Is this entity component pair currently being tracked by this manipulator.
//! Is this entity component pair currently being tracked by this manipulator.
bool HasEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair) const;
/// Forward a mouse over event in a case where we need the manipulator to immediately refresh.
/// @note Only call this when a mouse over event has just happened.
//! Forward a mouse over event in a case where we need the manipulator to immediately refresh.
//! @note Only call this when a mouse over event has just happened.
void ForwardMouseOverEvent(const ViewportInteraction::MouseInteraction& interaction);
static const AZ::Color s_defaultMouseOverColor;
protected:
/// Protected constructor.
//! Protected constructor.
BaseManipulator() = default;
/// Called when unregistering - users of manipulators should not call it directly.
//! Called when unregistering - users of manipulators should not call it directly.
void Invalidate();
/// The implementation to override in a derived class for Invalidate.
virtual void InvalidateImpl() {}
//! The implementation to override in a derived class for Invalidate.
virtual void InvalidateImpl()
{
}
/// The implementation to override in a derived class for OnLeftMouseDown.
/// Note: When implementing this function you must also call AttachLeftMouseDownImpl to ensure
/// m_onLeftMouseDownImpl is set to OnLeftMouseDownImpl, otherwise it will not be called
virtual void OnLeftMouseDownImpl(
const ViewportInteraction::MouseInteraction& /*interaction*/, float /*rayIntersectionDistance*/) {}
void AttachLeftMouseDownImpl() { m_onLeftMouseDownImpl = &BaseManipulator::OnLeftMouseDownImpl; }
//! The implementation to override in a derived class for OnLeftMouseDown.
//! Note: When implementing this function you must also call AttachLeftMouseDownImpl to ensure
//! m_onLeftMouseDownImpl is set to OnLeftMouseDownImpl, otherwise it will not be called
virtual void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& /*interaction*/, float /*rayIntersectionDistance*/)
{
}
/// The implementation to override in a derived class for OnRightMouseDown.
/// Note: When implementing this function you must also call AttachRightMouseDownImpl to ensure
/// m_onRightMouseDownImpl is set to OnRightMouseDownImpl, otherwise it will not be called
virtual void OnRightMouseDownImpl(
const ViewportInteraction::MouseInteraction& /*interaction*/, float /*rayIntersectionDistance*/) {}
void AttachRightMouseDownImpl() { m_onRightMouseDownImpl = &BaseManipulator::OnRightMouseDownImpl; }
void AttachLeftMouseDownImpl()
{
m_onLeftMouseDownImpl = &BaseManipulator::OnLeftMouseDownImpl;
}
/// The implementation to override in a derived class for OnLeftMouseUp.
virtual void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) {}
//! The implementation to override in a derived class for OnRightMouseDown.
//! Note: When implementing this function you must also call AttachRightMouseDownImpl to ensure
//! m_onRightMouseDownImpl is set to OnRightMouseDownImpl, otherwise it will not be called
virtual void OnRightMouseDownImpl(const ViewportInteraction::MouseInteraction& /*interaction*/, float /*rayIntersectionDistance*/)
{
}
/// The implementation to override in a derived class for OnRightMouseUp.
virtual void OnRightMouseUpImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) {}
void AttachRightMouseDownImpl()
{
m_onRightMouseDownImpl = &BaseManipulator::OnRightMouseDownImpl;
}
/// The implementation to override in a derived class for OnMouseMove.
virtual void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) {}
//! The implementation to override in a derived class for OnLeftMouseUp.
virtual void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& /*interaction*/)
{
}
/// The implementation to override in a derived class for OnMouseOver.
virtual void OnMouseOverImpl(
ManipulatorId /*manipulatorId*/, const ViewportInteraction::MouseInteraction& /*interaction*/) {}
//! The implementation to override in a derived class for OnRightMouseUp.
virtual void OnRightMouseUpImpl(const ViewportInteraction::MouseInteraction& /*interaction*/)
{
}
/// The implementation to override in a derived class for OnMouseWheel.
virtual void OnMouseWheelImpl(const ViewportInteraction::MouseInteraction& /*interaction*/) {}
//! The implementation to override in a derived class for OnMouseMove.
virtual void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& /*interaction*/)
{
}
/// The implementation to override in a derived class for SetBoundsDirty.
virtual void SetBoundsDirtyImpl() {}
//! The implementation to override in a derived class for OnMouseOver.
virtual void OnMouseOverImpl(ManipulatorId /*manipulatorId*/, const ViewportInteraction::MouseInteraction& /*interaction*/)
{
}
/// Rendering for the manipulator - it is recommended drawing be delegated to a ManipulatorView.
//! The implementation to override in a derived class for OnMouseWheel.
virtual void OnMouseWheelImpl(const ViewportInteraction::MouseInteraction& /*interaction*/)
{
}
//! The implementation to override in a derived class for SetBoundsDirty.
virtual void SetBoundsDirtyImpl()
{
}
//! Rendering for the manipulator - it is recommended drawing be delegated to a ManipulatorView.
virtual void Draw(
const ManipulatorManagerState& managerState,
AzFramework::DebugDisplayRequests& debugDisplay,
@@ -202,39 +243,39 @@ namespace AzToolsFramework
private:
friend class ManipulatorManager;
AZStd::unordered_set<AZ::EntityComponentIdPair> m_entityComponentIdPairs; ///< The entities this manipulator is associated with.
AZStd::unordered_set<AZ::EntityComponentIdPair> m_entityComponentIdPairs; //!< The entities this manipulator is associated with.
ManipulatorId m_manipulatorId = InvalidManipulatorId; ///< The unique id of this manipulator.
ManipulatorManagerId m_manipulatorManagerId = InvalidManipulatorManagerId; ///< The manager this manipulator was registered with.
UndoSystem::URSequencePoint* m_undoBatch = nullptr; ///< Undo active while mouse is pressed.
bool m_performingAction = false; ///< After mouse down and before mouse up.
bool m_mouseOver = false; ///< Is the mouse pointer over the manipulator bound.
ManipulatorId m_manipulatorId = InvalidManipulatorId; //!< The unique id of this manipulator.
ManipulatorManagerId m_manipulatorManagerId = InvalidManipulatorManagerId; //!< The manager this manipulator was registered with.
UndoSystem::URSequencePoint* m_undoBatch = nullptr; //!< Undo active while mouse is pressed.
bool m_performingAction = false; //!< After mouse down and before mouse up.
bool m_mouseOver = false; //!< Is the mouse pointer over the manipulator bound.
/// Member function pointers to OnLeftMouseDownImpl and OnRightMouseDownImpl.
/// Set in AttachLeft/RightMouseDownImpl.
//! Member function pointers to OnLeftMouseDownImpl and OnRightMouseDownImpl.
//! Set in AttachLeft/RightMouseDownImpl.
void (BaseManipulator::*m_onLeftMouseDownImpl)(
const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) = nullptr;
void (BaseManipulator::*m_onRightMouseDownImpl)(
const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) = nullptr;
/// Update the mouseOver state for this manipulator.
//! Update the mouseOver state for this manipulator.
void UpdateMouseOver(ManipulatorId manipulatorId);
/// Manage correctly ending the undo batch.
//! Manage correctly ending the undo batch.
void EndUndoBatch();
/// Record an action as having started.
//! Record an action as having started.
void BeginAction();
/// Record an action as having stopped.
//! Record an action as having stopped.
void EndAction();
/// Let other systems (UI) know that a component property has been modified by a manipulator.
//! Let other systems (UI) know that a component property has been modified by a manipulator.
void NotifyEntityComponentPropertyChanged();
};
/// Base class to be used when composing aggregate manipulator types - wraps some
/// common functionality all manipulators need.
//! Base class to be used when composing aggregate manipulator types - wraps some
//! common functionality all manipulators need.
class Manipulators
{
public:
@@ -249,8 +290,10 @@ namespace AzToolsFramework
bool PerformingAction();
bool Registered();
/// Refresh the Manipulator and/or View based on the current view position.
virtual void RefreshView(const AZ::Vector3& /*worldViewPosition*/) {}
//! Refresh the Manipulator and/or View based on the current view position.
virtual void RefreshView(const AZ::Vector3& /*worldViewPosition*/)
{
}
const AZ::Transform& GetLocalTransform() const;
const AZ::Transform& GetSpace() const;
@@ -262,39 +305,59 @@ namespace AzToolsFramework
void SetNonUniformScale(const AZ::Vector3& nonUniformScale);
protected:
/// Common processing for base manipulator type - Implement for all
/// individual manipulators used in an aggregate manipulator.
//! Common processing for base manipulator type - Implement for all
//! individual manipulators used in an aggregate manipulator.
virtual void ProcessManipulators(const AZStd::function<void(BaseManipulator*)>&) = 0;
///@{
/// Allows implementers to perform additional logic when updating the location of the manipulator group.
virtual void SetSpaceImpl([[maybe_unused]] const AZ::Transform& worldFromLocal) {}
virtual void SetLocalTransformImpl([[maybe_unused]] const AZ::Transform& localTransform) {}
virtual void SetLocalPositionImpl([[maybe_unused]] const AZ::Vector3& localPosition) {}
virtual void SetLocalOrientationImpl([[maybe_unused]] const AZ::Quaternion& localOrientation) {}
virtual void SetNonUniformScaleImpl([[maybe_unused]] const AZ::Vector3& nonUniformScale) {}
///@}
//!@{
//! Allows implementers to perform additional logic when updating the location of the manipulator group.
virtual void SetSpaceImpl([[maybe_unused]] const AZ::Transform& worldFromLocal)
{
}
ManipulatorSpaceWithLocalTransform m_manipulatorSpaceWithLocalTransform; ///< The space and local transform for the manipulators.
virtual void SetLocalTransformImpl([[maybe_unused]] const AZ::Transform& localTransform)
{
}
virtual void SetLocalPositionImpl([[maybe_unused]] const AZ::Vector3& localPosition)
{
}
virtual void SetLocalOrientationImpl([[maybe_unused]] const AZ::Quaternion& localOrientation)
{
}
virtual void SetNonUniformScaleImpl([[maybe_unused]] const AZ::Vector3& nonUniformScale)
{
}
//!@}
ManipulatorSpaceWithLocalTransform m_manipulatorSpaceWithLocalTransform; //!< The space and local transform for the manipulators.
};
namespace Internal
{
/// This helper function calculates the intersecting point between a ray and a plane.
/// @param rayOrigin The origin of the ray to test.
/// @param rayDirection The direction of the ray to test.
/// @param maxRayLength
/// @param pointOnPlane A point on the plane.
/// @param planeNormal The normal vector of the plane.
/// @param[out] resultIntersectingPoint This stores the result intersecting point. It will be left unchanged
/// if there is no intersection between the ray and the plane.
/// @return Was there an intersection
bool CalculateRayPlaneIntersectingPoint(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
const AZ::Vector3& pointOnPlane, const AZ::Vector3& planeNormal, AZ::Vector3& resultIntersectingPoint);
//! This helper function calculates the intersecting point between a ray and a plane.
//! @param rayOrigin The origin of the ray to test.
//! @param rayDirection The direction of the ray to test.
//! @param maxRayLength The maximum length of the ray to test.
//! @param pointOnPlane A point on the plane.
//! @param planeNormal The normal vector of the plane.
//! @param[out] resultIntersectingPoint This stores the result intersecting point. It will be left unchanged
//! if there is no intersection between the ray and the plane.
//! @return Was there an intersection
bool CalculateRayPlaneIntersectingPoint(
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
const AZ::Vector3& pointOnPlane,
const AZ::Vector3& planeNormal,
AZ::Vector3& resultIntersectingPoint);
/// Returns startLocalHitPosition if currentLocalHitPosition is further away than the camera's far clip plane.
//! Returns startLocalHitPosition if currentLocalHitPosition is further away than the camera's far clip plane.
AZ::Vector3 TryConstrainHitPositionToView(
const AZ::Vector3& currentLocalHitPosition, const AZ::Vector3& startLocalHitPosition,
const AZ::Transform& localFromWorld, const AzFramework::CameraState& cameraState);
}
const AZ::Vector3& currentLocalHitPosition,
const AZ::Vector3& startLocalHitPosition,
const AZ::Transform& localFromWorld,
const AzFramework::CameraState& cameraState);
} // namespace Internal
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -21,31 +21,30 @@ namespace AZ
namespace AzToolsFramework
{
/// Interface for handling box manipulator requests.
/// Used by \ref BoxComponentMode.
class BoxManipulatorRequests
: public AZ::EntityComponentBus
//! Interface for handling box manipulator requests.
//! Used by \ref BoxComponentMode.
class BoxManipulatorRequests : public AZ::EntityComponentBus
{
public:
/// Get the X/Y/Z dimensions of the box shape/collider.
//! Get the X/Y/Z dimensions of the box shape/collider.
virtual AZ::Vector3 GetDimensions() = 0;
/// Set the X/Y/Z dimensions of the box shape/collider.
//! Set the X/Y/Z dimensions of the box shape/collider.
virtual void SetDimensions(const AZ::Vector3& dimensions) = 0;
/// Get the transform of the box shape/collider.
/// This is used by \ref BoxComponentMode instead of the \ref \AZ::TransformBus
/// because a collider may have an additional translation/orientation offset from
/// the Entity transform.
//! Get the transform of the box shape/collider.
//! This is used by \ref BoxComponentMode instead of the \ref \AZ::TransformBus
//! because a collider may have an additional translation/orientation offset from
//! the Entity transform.
virtual AZ::Transform GetCurrentTransform() = 0;
/// Get the scale currently applied to the box.
/// With the Box Shape, the largest x/y/z component is taken
/// so scale is always uniform, with colliders the scale may
/// be different per component.
//! Get the scale currently applied to the box.
//! With the Box Shape, the largest x/y/z component is taken
//! so scale is always uniform, with colliders the scale may
//! be different per component.
virtual AZ::Vector3 GetBoxScale() = 0;
protected:
~BoxManipulatorRequests() = default;
};
/// Type to inherit to implement BoxManipulatorRequests
//! Type to inherit to implement BoxManipulatorRequests
using BoxManipulatorRequestBus = AZ::EBus<BoxManipulatorRequests>;
} // namespace AzToolsFramework
@@ -1,22 +1,22 @@
/*
* 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.
*
*/
* 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/Math/VertexContainer.h>
#include <AzCore/Math/VertexContainerInterface.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
#include <AzToolsFramework/Manipulators/HoverSelection.h>
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
#include <AzToolsFramework/Manipulators/SelectionManipulator.h>
#include <AzToolsFramework/Manipulators/TranslationManipulators.h>
#include <AzToolsFramework/Viewport/ActionBus.h>
@@ -24,37 +24,74 @@
namespace AzToolsFramework
{
/// Concrete implementation of AZ::VariableVertices backed by an AZ::VertexContainer.
//! Concrete implementation of AZ::VariableVertices backed by an AZ::VertexContainer.
template<typename Vertex>
class VariableVerticesVertexContainer
: public AZ::VariableVertices<Vertex>
class VariableVerticesVertexContainer : public AZ::VariableVertices<Vertex>
{
public:
explicit VariableVerticesVertexContainer(AZ::VertexContainer<Vertex>& vertexContainer)
: m_vertexContainer(vertexContainer) {}
: m_vertexContainer(vertexContainer)
{
}
bool GetVertex(size_t index, Vertex& vertex) const override { return m_vertexContainer.GetVertex(index, vertex); }
bool UpdateVertex(size_t index, const Vertex& vertex) override { return m_vertexContainer.UpdateVertex(index, vertex); };
void AddVertex(const Vertex& vertex) override { m_vertexContainer.AddVertex(vertex); }
bool InsertVertex(size_t index, const Vertex& vertex) override { return m_vertexContainer.InsertVertex(index, vertex); }
bool RemoveVertex(size_t index) override { return m_vertexContainer.RemoveVertex(index); }
void SetVertices(const AZStd::vector<Vertex>& vertices) override { m_vertexContainer.SetVertices(vertices); };
void ClearVertices() override { m_vertexContainer.Clear(); }
size_t Size() const override { return m_vertexContainer.Size(); }
bool Empty() const override { return m_vertexContainer.Empty(); }
bool GetVertex(size_t index, Vertex& vertex) const override
{
return m_vertexContainer.GetVertex(index, vertex);
}
bool UpdateVertex(size_t index, const Vertex& vertex) override
{
return m_vertexContainer.UpdateVertex(index, vertex);
};
void AddVertex(const Vertex& vertex) override
{
m_vertexContainer.AddVertex(vertex);
}
bool InsertVertex(size_t index, const Vertex& vertex) override
{
return m_vertexContainer.InsertVertex(index, vertex);
}
bool RemoveVertex(size_t index) override
{
return m_vertexContainer.RemoveVertex(index);
}
void SetVertices(const AZStd::vector<Vertex>& vertices) override
{
m_vertexContainer.SetVertices(vertices);
};
void ClearVertices() override
{
m_vertexContainer.Clear();
}
size_t Size() const override
{
return m_vertexContainer.Size();
}
bool Empty() const override
{
return m_vertexContainer.Empty();
}
private:
AZ::VertexContainer<Vertex>& m_vertexContainer;
};
/// Concrete implementation of AZ::FixedVertices backed by an AZStd::array.
//! Concrete implementation of AZ::FixedVertices backed by an AZStd::array.
template<typename Vertex, size_t Count>
class FixedVerticesArray
: public AZ::FixedVertices<Vertex>
class FixedVerticesArray : public AZ::FixedVertices<Vertex>
{
public:
explicit FixedVerticesArray(AZStd::array<Vertex, Count>& array)
: m_array(array) {}
: m_array(array)
{
}
bool GetVertex(size_t index, Vertex& vertex) const override
{
@@ -72,22 +109,26 @@ namespace AzToolsFramework
if (index < m_array.size())
{
m_array[index] = vertex;
return true;;
return true;
;
}
return false;
}
size_t Size() const override { return m_array.size(); }
size_t Size() const override
{
return m_array.size();
}
private:
AZStd::array<Vertex, Count>& m_array;
};
/// EditorVertexSelection provides an interface for a collection of manipulators to expose
/// editing of vertices in a container/collection. EditorVertexSelection is templated on the
/// type of Vertex (Vector2/Vector3) stored in the container.
/// EditorVertexSelectionBase provides common behavior shared across Fixed and Variable selections.
//! EditorVertexSelection provides an interface for a collection of manipulators to expose
//! editing of vertices in a container/collection. EditorVertexSelection is templated on the
//! type of Vertex (Vector2/Vector3) stored in the container.
//! EditorVertexSelectionBase provides common behavior shared across Fixed and Variable selections.
template<typename Vertex>
class EditorVertexSelectionBase
: private AzFramework::EntityDebugDisplayEventBus::Handler
@@ -99,89 +140,110 @@ namespace AzToolsFramework
EditorVertexSelectionBase& operator=(EditorVertexSelectionBase&&) = default;
virtual ~EditorVertexSelectionBase() = default;
/// Setup and configure the EditorVertexSelection for operation.
//! Setup and configure the EditorVertexSelection for operation.
void Create(
const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId,
const AZ::EntityComponentIdPair& entityComponentIdPair,
ManipulatorManagerId managerId,
AZStd::unique_ptr<HoverSelection> hoverSelection,
TranslationManipulators::Dimensions dimensions,
TranslationManipulatorConfiguratorFn translationManipulatorConfigurator);
/// Create a translation manipulator for a given vertex.
//! Create a translation manipulator for a given vertex.
void CreateTranslationManipulator(
const AZ::EntityComponentIdPair& entityComponentIdPair,
ManipulatorManagerId managerId, const Vertex& vertex, size_t index);
const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId, const Vertex& vertex, size_t index);
/// Destroy all manipulators associated with the vertex selection.
//! Destroy all manipulators associated with the vertex selection.
void Destroy();
/// Set custom callback for when vertex positions are updated.
//! Set custom callback for when vertex positions are updated.
void SetVertexPositionsUpdatedCallback(const AZStd::function<void()>& callback);
/// Update manipulators based on local changes to vertex positions.
//! Update manipulators based on local changes to vertex positions.
void RefreshLocal();
/// Update the translation manipulator to be correctly positioned based
/// on the current selection (recenter it).
//! Update the translation manipulator to be correctly positioned based
//! on the current selection (recenter it).
void RefreshTranslationManipulator();
/// Update manipulators based on changes to the entity's transform and non-uniform scale.
//! Update manipulators based on changes to the entity's transform and non-uniform scale.
void RefreshSpace(const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne());
/// Set bounds dirty (need recalculating) for all owned manipulators (selection, translation, hover).
//! Set bounds dirty (need recalculating) for all owned manipulators (selection, translation, hover).
void SetBoundsDirty();
/// How should the EditorVertexSelection respond to mouse input.
virtual bool HandleMouse(
const ViewportInteraction::MouseInteractionEvent& mouseInteraction);
//! How should the EditorVertexSelection respond to mouse input.
virtual bool HandleMouse(const ViewportInteraction::MouseInteractionEvent& mouseInteraction);
/// Snap the selected vertices to the terrain.
/// Note: With a multi-selection the manipulator will be translated to the picked
/// terrain position with all verts moved relative to it.
void SnapVerticesToTerrain(
const ViewportInteraction::MouseInteractionEvent& mouseInteraction);
//! Snap the selected vertices to the terrain.
//! Note: With a multi-selection the manipulator will be translated to the picked
//! terrain position with all vertices moved relative to it.
void SnapVerticesToTerrain(const ViewportInteraction::MouseInteractionEvent& mouseInteraction);
/// The Actions provided by the EditorVertexSelection while it is active.
/// e.g. Vertex deletion, duplication etc.
//! The Actions provided by the EditorVertexSelection while it is active.
//! e.g. Vertex deletion, duplication etc.
AZStd::vector<ActionOverride> ActionOverrides() const;
/// Let the EditorVertexSelection know a batch movement is about to begin so it
/// can avoid certain unnecessary updates.
//! Let the EditorVertexSelection know a batch movement is about to begin so it
//! can avoid certain unnecessary updates.
void BeginBatchMovement();
/// Let the EditorVertexSelection know a batch movement has ended so it can return
/// to its normal state.
//! Let the EditorVertexSelection know a batch movement has ended so it can return
//! to its normal state.
void EndBatchMovement();
/// Set the position of the TranslationManipulators (if active).
//! Set the position of the TranslationManipulators (if active).
void SetSelectedPosition(const AZ::Vector3& localPosition);
AZ::EntityId GetEntityId() const { return m_entityComponentIdPair.GetEntityId(); }
AZ::EntityId GetEntityId() const
{
return m_entityComponentIdPair.GetEntityId();
}
protected:
/// Internal interface for EditorVertexSelection.
//! Internal interface for EditorVertexSelection.
virtual void SetupSelectionManipulator(
const AZStd::shared_ptr<SelectionManipulator>& selectionManipulator,
const AZ::EntityComponentIdPair& entityComponentIdPair,
ManipulatorManagerId managerId, size_t index) = 0;
ManipulatorManagerId managerId,
size_t index) = 0;
virtual void PrepareActions() = 0;
/// Default behavior when clicking on a selection manipulator (representing a vertex).
//! Default behavior when clicking on a selection manipulator (representing a vertex).
void SelectionManipulatorSelectCallback(
size_t index, const ViewportInteraction::MouseInteraction& interaction,
const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId);
size_t index,
const ViewportInteraction::MouseInteraction& interaction,
const AZ::EntityComponentIdPair& entityComponentIdPair,
ManipulatorManagerId managerId);
/// Destroy the translation manipulator and deselect all vertices.
//! Destroy the translation manipulator and deselect all vertices.
void ClearSelected();
AZ::ComponentId GetComponentId() const { return m_entityComponentIdPair.GetComponentId(); }
const AZ::EntityComponentIdPair& GetEntityComponentIdPair() const { return m_entityComponentIdPair; }
ManipulatorManagerId GetManipulatorManagerId() const { return m_manipulatorManagerId; }
AZ::ComponentId GetComponentId() const
{
return m_entityComponentIdPair.GetComponentId();
}
/// Is the translation vertex manipulator in 2D or 3D.
TranslationManipulators::Dimensions Dimensions() const { return m_dimensions; }
const AZ::EntityComponentIdPair& GetEntityComponentIdPair() const
{
return m_entityComponentIdPair;
}
/// How to configure the translation manipulator (view and axes).
TranslationManipulatorConfiguratorFn ConfiguratorFn() const { return m_manipulatorConfiguratorFn; }
ManipulatorManagerId GetManipulatorManagerId() const
{
return m_manipulatorManagerId;
}
/// The state we are in when editing vertices.
//! Is the translation vertex manipulator in 2D or 3D.
TranslationManipulators::Dimensions Dimensions() const
{
return m_dimensions;
}
//! How to configure the translation manipulator (view and axes).
TranslationManipulatorConfiguratorFn ConfiguratorFn() const
{
return m_manipulatorConfiguratorFn;
}
//! The state we are in when editing vertices.
enum class State
{
Selecting,
@@ -190,23 +252,22 @@ namespace AzToolsFramework
void SetState(State state);
AZStd::unique_ptr<HoverSelection> m_hoverSelection = nullptr; ///< Interface to hover selection, representing bounds that can be selected.
AZStd::shared_ptr<IndexedTranslationManipulator<Vertex>> m_translationManipulator = nullptr; ///< Manipulator when vertex is selected to translate it.
AZStd::vector<AZStd::shared_ptr<SelectionManipulator>> m_selectionManipulators; ///< Manipulators for each vertex when entity is selected.
AZStd::array<AZStd::vector<ActionOverride>, 2> m_actionOverrides; ///< Available actions corresponding to each mode.
AZStd::unique_ptr<HoverSelection> m_hoverSelection =
nullptr; //!< Interface to hover selection, representing bounds that can be selected.
AZStd::shared_ptr<IndexedTranslationManipulator<Vertex>> m_translationManipulator =
nullptr; //!< Manipulator when vertex is selected to translate it.
AZStd::vector<AZStd::shared_ptr<SelectionManipulator>>
m_selectionManipulators; //!< Manipulators for each vertex when entity is selected.
AZStd::array<AZStd::vector<ActionOverride>, 2> m_actionOverrides; //!< Available actions corresponding to each mode.
private:
// AzFramework::EntityDebugDisplayEventBus
void DisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
void DisplayEntityViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override;
// AzFramework::ViewportDebugDisplayEventBus
void DisplayViewport2d(
const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override;
void DisplayViewport2d(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override;
/// Set selected manipulator and vertices position from offset from starting position when pressed.
//! Set selected manipulator and vertices position from offset from starting position when pressed.
void UpdateManipulatorsAndVerticesFromOffset(
IndexedTranslationManipulator<Vertex>& translationManipulator,
const AZ::Vector3& localManipulatorStartPosition,
@@ -217,23 +278,24 @@ namespace AzToolsFramework
template<typename V, typename AZStd::enable_if<AZStd::is_same<V, AZ::Vector2>::value>::type* = nullptr>
void UpdateManipulatorSpace(const AzFramework::ViewportInfo& viewportInfo) const;
EditorBoxSelect m_editorBoxSelect; ///< Provide box select support for vertex selection.
AZ::EntityComponentIdPair m_entityComponentIdPair; ///< Id of the Entity and Component this editor vertex selection was created on.
ManipulatorManagerId m_manipulatorManagerId; ///< Id of the manager manipulators created from this type will be associated with.
TranslationManipulators::Dimensions m_dimensions = TranslationManipulators::Dimensions::Three; ///< The dimensions this vertex selection was created with.
TranslationManipulatorConfiguratorFn m_manipulatorConfiguratorFn = nullptr; ///< Function pointer set on Create to decide look and functionality of translation manipulator.
AZStd::function<void()> m_onVertexPositionsUpdated = nullptr; ///< Callback for when vertex positions are changed.
State m_state = State::Selecting; ///< Different states VertexSelection can be in.
bool m_worldSpace = false; ///< Are the manipulators being used in local or world space.
bool m_batchMovementInProgress = false; ///< If a batch movement operation is in progress we do not want to
///< refresh the VertexSelection during it for performance reasons.
EditorBoxSelect m_editorBoxSelect; //!< Provide box select support for vertex selection.
AZ::EntityComponentIdPair m_entityComponentIdPair; //!< Id of the Entity and Component this editor vertex selection was created on.
ManipulatorManagerId m_manipulatorManagerId; //!< Id of the manager manipulators created from this type will be associated with.
TranslationManipulators::Dimensions m_dimensions =
TranslationManipulators::Dimensions::Three; //!< The dimensions this vertex selection was created with.
TranslationManipulatorConfiguratorFn m_manipulatorConfiguratorFn =
nullptr; //!< Function pointer set on Create to decide look and functionality of translation manipulator.
AZStd::function<void()> m_onVertexPositionsUpdated = nullptr; //!< Callback for when vertex positions are changed.
State m_state = State::Selecting; //!< Different states VertexSelection can be in.
bool m_worldSpace = false; //!< Are the manipulators being used in local or world space.
bool m_batchMovementInProgress = false; //!< If a batch movement operation is in progress we do not want to
//!< refresh the VertexSelection during it for performance reasons.
};
/// EditorVertexSelectionFixed provides selection and editing for a fixed length number of
/// vertices. New vertices cannot be inserted/added or removed.
//! EditorVertexSelectionFixed provides selection and editing for a fixed length number of
//! vertices. New vertices cannot be inserted/added or removed.
template<typename Vertex>
class EditorVertexSelectionFixed
: public EditorVertexSelectionBase<Vertex>
class EditorVertexSelectionFixed : public EditorVertexSelectionBase<Vertex>
{
public:
AZ_CLASS_ALLOCATOR_DECL
@@ -247,15 +309,15 @@ namespace AzToolsFramework
void SetupSelectionManipulator(
const AZStd::shared_ptr<SelectionManipulator>& selectionManipulator,
const AZ::EntityComponentIdPair& entityComponentIdPair,
ManipulatorManagerId managerId, size_t index) override;
ManipulatorManagerId managerId,
size_t index) override;
void PrepareActions() override;
};
/// EditorVertexSelectionVariable provides selection and editing for a variable length number of
/// vertices. New vertices can be inserted/added or removed from the collection.
//! EditorVertexSelectionVariable provides selection and editing for a variable length number of
//! vertices. New vertices can be inserted/added or removed from the collection.
template<typename Vertex>
class EditorVertexSelectionVariable
: public EditorVertexSelectionBase<Vertex>
class EditorVertexSelectionVariable : public EditorVertexSelectionBase<Vertex>
{
public:
AZ_CLASS_ALLOCATOR_DECL
@@ -272,7 +334,8 @@ namespace AzToolsFramework
void SetupSelectionManipulator(
const AZStd::shared_ptr<SelectionManipulator>& selectionManipulator,
const AZ::EntityComponentIdPair& entityComponentIdPair,
ManipulatorManagerId managerId, size_t vertIndex) override;
ManipulatorManagerId managerId,
size_t vertIndex) override;
//! Presents a warning to the user that vertices will not be deleted.
//! @note Allow overriding by derived classes to make this a noop if required.
@@ -281,21 +344,18 @@ namespace AzToolsFramework
private:
void PrepareActions() override;
/// @return The center point of the selected vertices.
Vertex InsertSelectedInPlace(
AZStd::vector<typename IndexedTranslationManipulator<Vertex>::VertexLookup>& manipulators);
//! @return The center point of the selected vertices.
Vertex InsertSelectedInPlace(AZStd::vector<typename IndexedTranslationManipulator<Vertex>::VertexLookup>& manipulators);
};
/// Helper for inserting a vertex in a variable vertices container.
//! Helper for inserting a vertex in a variable vertices container.
template<typename Vertex>
void InsertVertexAfter(
const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertIndex, const Vertex& localPosition);
void InsertVertexAfter(const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertIndex, const Vertex& localPosition);
/// Helper for removing a vertex in a variable vertices container.
/// Remove a vertex from the container and ensure the associated manipulator is unset and
/// property display values are refreshed.
//! Helper for removing a vertex in a variable vertices container.
//! Remove a vertex from the container and ensure the associated manipulator is unset and
//! property display values are refreshed.
template<typename Vertex>
void SafeRemoveVertex(
const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertexIndex);
void SafeRemoveVertex(const AZ::EntityComponentIdPair& entityComponentIdPair, size_t vertexIndex);
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -16,10 +16,10 @@
namespace AzToolsFramework
{
/// HoverSelection provides an interface for manipulator/s offering selection when
/// the mouse is hovered over a particular bound. This interface is used to represent
/// a Spline manipulator bound, and a series of LineSegment manipulator bounds.
/// This generic interface allows EditorVertexSelection to use either Spline or LineSegment selection.
//! HoverSelection provides an interface for manipulator/s offering selection when
//! the mouse is hovered over a particular bound. This interface is used to represent
//! a Spline manipulator bound, and a series of LineSegment manipulator bounds.
//! This generic interface allows EditorVertexSelection to use either Spline or LineSegment selection.
class HoverSelection
{
public:
@@ -33,21 +33,37 @@ namespace AzToolsFramework
virtual void SetNonUniformScale(const AZ::Vector3& nonUniformScale) = 0;
};
/// NullHoverSelection is used when vertices cannot be inserted. This serves as a no-op
/// and is used to prevent the need for additional null checks in EditorVertexSelection.
class NullHoverSelection
: public HoverSelection
//! NullHoverSelection is used when vertices cannot be inserted. This serves as a no-op
//! and is used to prevent the need for additional null checks in EditorVertexSelection.
class NullHoverSelection : public HoverSelection
{
public:
NullHoverSelection() = default;
NullHoverSelection(const NullHoverSelection&) = delete;
NullHoverSelection& operator=(const NullHoverSelection&) = delete;
void Register(ManipulatorManagerId /*managerId*/) override {}
void Unregister() override {}
void SetBoundsDirty() override {}
void Refresh() override {}
void SetSpace(const AZ::Transform& /*worldFromLocal*/) override {}
void SetNonUniformScale([[maybe_unused]] const AZ::Vector3& nonUniformScale) override {}
void Register([[maybe_unused]] ManipulatorManagerId managerId) override
{
}
void Unregister() override
{
}
void SetBoundsDirty() override
{
}
void Refresh() override
{
}
void SetSpace([[maybe_unused]] const AZ::Transform& worldFromLocal) override
{
}
void SetNonUniformScale([[maybe_unused]] const AZ::Vector3& nonUniformScale) override
{
}
};
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LineHoverSelection.h"
@@ -22,17 +22,15 @@
namespace AzToolsFramework
{
static const AZ::Color s_lineSelectManipulatorColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
static const AZ::Color LineSelectManipulatorColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
template<typename Vertex>
static void UpdateLineSegmentPosition(
const size_t vertIndex, const AZ::EntityId entityId, LineSegmentSelectionManipulator& lineSegment)
static void UpdateLineSegmentPosition(const size_t vertIndex, const AZ::EntityId entityId, LineSegmentSelectionManipulator& lineSegment)
{
Vertex start;
bool foundStart = false;
AZ::FixedVerticesRequestBus<Vertex>::EventResult(
foundStart, entityId, &AZ::FixedVerticesRequestBus<Vertex>::Handler::GetVertex,
vertIndex, start);
foundStart, entityId, &AZ::FixedVerticesRequestBus<Vertex>::Handler::GetVertex, vertIndex, start);
if (foundStart)
{
@@ -40,14 +38,12 @@ namespace AzToolsFramework
}
size_t size = 0;
AZ::FixedVerticesRequestBus<Vertex>::EventResult(
size, entityId, &AZ::FixedVerticesRequestBus<Vertex>::Handler::Size);
AZ::FixedVerticesRequestBus<Vertex>::EventResult(size, entityId, &AZ::FixedVerticesRequestBus<Vertex>::Handler::Size);
Vertex end;
bool foundEnd = false;
AZ::FixedVerticesRequestBus<Vertex>::EventResult(
foundEnd, entityId, &AZ::FixedVerticesRequestBus<Vertex>::Handler::GetVertex,
(vertIndex + 1) % size, end);
foundEnd, entityId, &AZ::FixedVerticesRequestBus<Vertex>::Handler::GetVertex, (vertIndex + 1) % size, end);
if (foundEnd)
{
@@ -56,8 +52,7 @@ namespace AzToolsFramework
// update the view
const float lineWidth = 0.05f;
lineSegment.SetView(
CreateManipulatorViewLineSelect(lineSegment, s_lineSelectManipulatorColor, lineWidth));
lineSegment.SetView(CreateManipulatorViewLineSelect(lineSegment, LineSelectManipulatorColor, lineWidth));
}
template<typename Vertex>
@@ -66,9 +61,8 @@ namespace AzToolsFramework
: m_entityId(entityComponentIdPair.GetEntityId())
{
// create a line segment manipulator from vertex positions and setup its callback
auto setupLineSegment = [this] (
const AZ::EntityComponentIdPair& entityComponentIdPair,
const ManipulatorManagerId managerId, const size_t vertIndex)
auto setupLineSegment =
[this](const AZ::EntityComponentIdPair& entityComponentIdPair, const ManipulatorManagerId managerId, const size_t vertIndex)
{
m_lineSegmentManipulators.push_back(LineSegmentSelectionManipulator::MakeShared());
AZStd::shared_ptr<LineSegmentSelectionManipulator>& lineSegmentManipulator = m_lineSegmentManipulators.back();
@@ -81,11 +75,9 @@ namespace AzToolsFramework
lineSegmentManipulator->InstallLeftMouseUpCallback(
[vertIndex, entityComponentIdPair](const LineSegmentSelectionManipulator::Action& action)
{
InsertVertexAfter<Vertex>(
entityComponentIdPair, vertIndex,
AZ::AdaptVertexIn<Vertex>(action.m_localLineHitPosition));
});
{
InsertVertexAfter<Vertex>(entityComponentIdPair, vertIndex, AZ::AdaptVertexIn<Vertex>(action.m_localLineHitPosition));
});
};
// create all line segment manipulators for the polygon prism (used for selection bounds)
@@ -150,8 +142,7 @@ namespace AzToolsFramework
void LineSegmentHoverSelection<Vertex>::Refresh()
{
size_t vertexCount = 0;
AZ::FixedVerticesRequestBus<Vertex>::EventResult(
vertexCount, m_entityId, &AZ::FixedVerticesRequestBus<Vertex>::Handler::Size);
AZ::FixedVerticesRequestBus<Vertex>::EventResult(vertexCount, m_entityId, &AZ::FixedVerticesRequestBus<Vertex>::Handler::Size);
// update the start/end positions of all the line segment manipulators to ensure
// they stay consistent with the polygon prism shape
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -25,17 +25,14 @@ namespace AzToolsFramework
{
class LineSegmentSelectionManipulator;
/// LineSegmentHoverSelection is a concrete implementation of HoverSelection wrapping a collection/container
/// of vertices and a list of LineSegmentManipulators. The underlying manipulators are used to control selection
/// by highlighting where on the line a new vertex will be inserted.
//! LineSegmentHoverSelection is a concrete implementation of HoverSelection wrapping a collection/container
//! of vertices and a list of LineSegmentManipulators. The underlying manipulators are used to control selection
//! by highlighting where on the line a new vertex will be inserted.
template<typename Vertex>
class LineSegmentHoverSelection
: public HoverSelection
class LineSegmentHoverSelection : public HoverSelection
{
public:
explicit LineSegmentHoverSelection(
const AZ::EntityComponentIdPair& entityComponentIdPair,
ManipulatorManagerId managerId);
explicit LineSegmentHoverSelection(const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId);
LineSegmentHoverSelection(const LineSegmentHoverSelection&) = delete;
LineSegmentHoverSelection& operator=(const LineSegmentHoverSelection&) = delete;
~LineSegmentHoverSelection();
@@ -49,6 +46,6 @@ namespace AzToolsFramework
private:
AZ::EntityId m_entityId;
AZStd::vector<AZStd::shared_ptr<LineSegmentSelectionManipulator>> m_lineSegmentManipulators; ///< Manipulators for each line.
AZStd::vector<AZStd::shared_ptr<LineSegmentSelectionManipulator>> m_lineSegmentManipulators; //!< Manipulators for each line.
};
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LineSegmentSelectionManipulator.h"
@@ -20,15 +20,20 @@
namespace AzToolsFramework
{
LineSegmentSelectionManipulator::Action CalculateManipulationDataAction(
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection, const float rayLength, const AZ::Vector3& localStart, const AZ::Vector3& localEnd)
const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale,
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
const float rayLength,
const AZ::Vector3& localStart,
const AZ::Vector3& localEnd)
{
AZ::Vector3 worldClosestPositionRay, worldClosestPositionLineSegment;
float rayProportion, lineSegmentProportion;
AZ::Intersect::ClosestSegmentSegment(
rayOrigin, rayOrigin + rayDirection * rayLength,
worldFromLocal.TransformPoint(nonUniformScale * localStart), worldFromLocal.TransformPoint(nonUniformScale * localEnd),
rayProportion, lineSegmentProportion, worldClosestPositionRay, worldClosestPositionLineSegment);
rayOrigin, rayOrigin + rayDirection * rayLength, worldFromLocal.TransformPoint(nonUniformScale * localStart),
worldFromLocal.TransformPoint(nonUniformScale * localEnd), rayProportion, lineSegmentProportion, worldClosestPositionRay,
worldClosestPositionLineSegment);
AZ::Transform worldFromLocalNormalized = worldFromLocal;
const AZ::Vector3 scale = worldFromLocalNormalized.ExtractUniformScale() * nonUniformScale;
@@ -47,7 +52,9 @@ namespace AzToolsFramework
AttachLeftMouseDownImpl();
}
LineSegmentSelectionManipulator::~LineSegmentSelectionManipulator() {}
LineSegmentSelectionManipulator::~LineSegmentSelectionManipulator()
{
}
void LineSegmentSelectionManipulator::InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback)
{
@@ -112,12 +119,9 @@ namespace AzToolsFramework
if (mouseInteraction.m_keyboardModifiers.Ctrl() && !mouseInteraction.m_keyboardModifiers.Shift())
{
m_manipulatorView->Draw(
GetManipulatorManagerId(), managerState,
GetManipulatorId(), {
TransformUniformScale(GetSpace()), GetNonUniformScale(),
m_localStart, MouseOver()
},
debugDisplay, cameraState, mouseInteraction);
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ TransformUniformScale(GetSpace()), GetNonUniformScale(), m_localStart, MouseOver() }, debugDisplay, cameraState,
mouseInteraction);
}
}
@@ -135,4 +139,4 @@ namespace AzToolsFramework
{
m_manipulatorView->Invalidate(GetManipulatorManagerId());
}
}
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -20,12 +20,12 @@ namespace AzToolsFramework
{
class ManipulatorView;
/// A manipulator to expose where on a line a user is moving their mouse.
//! A manipulator to expose where on a line a user is moving their mouse.
class LineSegmentSelectionManipulator
: public BaseManipulator
, public ManipulatorSpace
{
/// Private constructor.
//! Private constructor.
LineSegmentSelectionManipulator();
public:
@@ -37,10 +37,10 @@ namespace AzToolsFramework
~LineSegmentSelectionManipulator();
/// A Manipulator must only be created and managed through a shared_ptr.
//! A Manipulator must only be created and managed through a shared_ptr.
static AZStd::shared_ptr<LineSegmentSelectionManipulator> MakeShared();
/// Mouse action data used by MouseActionCallback.
//! Mouse action data used by MouseActionCallback.
struct Action
{
AZ::Vector3 m_localLineHitPosition;
@@ -57,18 +57,31 @@ namespace AzToolsFramework
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
void SetStart(const AZ::Vector3& startLocal) { m_localStart = startLocal; }
void SetEnd(const AZ::Vector3& endLocal) { m_localEnd = endLocal; }
const AZ::Vector3& GetStart() const { return m_localStart; }
const AZ::Vector3& GetEnd() const { return m_localEnd; }
void SetStart(const AZ::Vector3& startLocal)
{
m_localStart = startLocal;
}
void SetEnd(const AZ::Vector3& endLocal)
{
m_localEnd = endLocal;
}
const AZ::Vector3& GetStart() const
{
return m_localStart;
}
const AZ::Vector3& GetEnd() const
{
return m_localEnd;
}
void SetView(AZStd::unique_ptr<ManipulatorView>&& view);
private:
void OnLeftMouseDownImpl(
const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(
const ViewportInteraction::MouseInteraction& interaction) override;
void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void InvalidateImpl() override;
void SetBoundsDirtyImpl() override;
@@ -79,12 +92,18 @@ namespace AzToolsFramework
MouseActionCallback m_onLeftMouseDownCallback = nullptr;
MouseActionCallback m_onLeftMouseUpCallback = nullptr;
ViewportInteraction::KeyboardModifiers m_keyboardModifiers; ///< What modifier keys are pressed when interacting with this manipulator.
ViewportInteraction::KeyboardModifiers
m_keyboardModifiers; //!< What modifier keys are pressed when interacting with this manipulator.
AZStd::unique_ptr<ManipulatorView> m_manipulatorView = nullptr; ///< Look of manipulator.
AZStd::unique_ptr<ManipulatorView> m_manipulatorView = nullptr; //!< Look of manipulator.
};
LineSegmentSelectionManipulator::Action CalculateManipulationDataAction(
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection, float rayLength, const AZ::Vector3& localStart, const AZ::Vector3& localEnd);
const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale,
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
float rayLength,
const AZ::Vector3& localStart,
const AZ::Vector3& localEnd);
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LinearManipulator.h"
@@ -22,13 +22,16 @@
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 LinearManipulator::Fixed& fixed,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform,
const ViewportInteraction::MouseInteraction& interaction,
const float intersectionDistance,
const AzFramework::CameraState& cameraState)
{
const ManipulatorInteraction manipulatorInteraction =
BuildManipulatorInteraction(
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction(
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
const AZ::Vector3 axis = TransformDirectionNoScaling(localTransform, fixed.m_axis);
const AZ::Vector3 rayCrossAxis = manipulatorInteraction.m_localRayDirection.Cross(axis);
@@ -47,51 +50,35 @@ namespace AzToolsFramework
manipulatorInteraction.m_localRayOrigin + manipulatorInteraction.m_localRayDirection * intersectionDistance;
Internal::CalculateRayPlaneIntersectingPoint(
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();
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, localIntersectionPoint,
startTransition.m_localNormal, start.m_localHitPosition);
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)
start.m_sign =
AZ::GetSign((start.m_localHitPosition - localTransform.GetTranslation()).Dot(axis));
start.m_sign = AZ::GetSign((start.m_localHitPosition - localTransform.GetTranslation()).Dot(axis));
startTransition.m_screenToWorldScale =
1.0f / CalculateScreenToWorldMultiplier((worldFromLocal * localTransform).GetTranslation(), cameraState);
return {startTransition, start};
return { startTransition, start };
}
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 LinearManipulator::Fixed& fixed,
const LinearManipulator::Starter& starter,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform,
const GridSnapParameters& gridSnapParams,
const ViewportInteraction::MouseInteraction& interaction)
{
const ManipulatorInteraction manipulatorInteraction =
BuildManipulatorInteraction(
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction(
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
const auto& [startTransition, start] = starter;
@@ -100,39 +87,41 @@ namespace AzToolsFramework
// if an invalid ray intersection is attempted
AZ::Vector3 localHitPosition = start.m_localHitPosition;
Internal::CalculateRayPlaneIntersectingPoint(
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection,
start.m_localHitPosition, startTransition.m_localNormal, localHitPosition);
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, start.m_localHitPosition,
startTransition.m_localNormal, localHitPosition);
localHitPosition = Internal::TryConstrainHitPositionToView(
localHitPosition, start.m_localHitPosition, worldFromLocal.GetInverse(),
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)
: unsnappedOffset;
action.m_current.m_localPositionOffset =
snapping ? 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 +160,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 +183,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 +196,8 @@ 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));
}
}
@@ -220,26 +208,25 @@ namespace AzToolsFramework
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const AZ::Transform localTransform = m_useVisualsOverride
? AZ::Transform::CreateFromQuaternionAndTranslation(
m_visualOrientationOverride, GetLocalPosition())
? AZ::Transform::CreateFromQuaternionAndTranslation(m_visualOrientationOverride, GetLocalPosition())
: GetLocalTransform();
if (cl_manipulatorDrawDebug)
{
if (PerformingAction())
{
const GridSnapParameters gridSnapParams =
GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId);
const GridSnapParameters gridSnapParams = 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(
debugDisplay, TransformUniformScale(GetSpace()) *
AZ::Transform::CreateTranslation(
action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localPositionOffset));
debugDisplay,
TransformUniformScale(GetSpace()) *
AZ::Transform::CreateTranslation(
action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localPositionOffset));
}
AZ::Transform combined = GetLocalTransform();
@@ -247,8 +234,7 @@ namespace AzToolsFramework
combined = GetSpace() * combined;
DrawTransformAxes(debugDisplay, combined);
DrawAxis(
debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(combined, m_fixed.m_axis));
DrawAxis(debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(combined, m_fixed.m_axis));
}
for (auto& view : m_manipulatorViews)
@@ -256,12 +242,9 @@ namespace AzToolsFramework
auto nonUniformScale = GetNonUniformScale();
view->Draw(
GetManipulatorManagerId(), managerState,
GetManipulatorId(), {
ApplySpace(localTransform), GetNonUniformScale(),
AZ::Vector3::CreateZero(), MouseOver()
},
debugDisplay, cameraState, mouseInteraction);
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ ApplySpace(localTransform), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay, cameraState,
mouseInteraction);
}
}
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -20,15 +20,15 @@
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.
//! LinearManipulator serves as a visual tool for users to modify values
//! in one dimension on an axis defined in 3D space.
class LinearManipulator
: public BaseManipulator
, public ManipulatorSpaceWithLocalTransform
{
/// Private constructor.
//! Private constructor.
explicit LinearManipulator(const AZ::Transform& worldFromLocal);
public:
@@ -41,70 +41,80 @@ namespace AzToolsFramework
~LinearManipulator() = default;
/// A Manipulator must only be created and managed through a shared_ptr.
/// @note worldFromLocal should not contain scale.
//! A Manipulator must only be created and managed through a shared_ptr.
//! @note worldFromLocal should not contain scale.
static AZStd::shared_ptr<LinearManipulator> MakeShared(const AZ::Transform& worldFromLocal);
/// Unchanging data set once for the linear manipulator.
//! Unchanging data set once for the linear manipulator.
struct Fixed
{
AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); ///< The axis the manipulator will move along.
AZ::Vector3 m_axis = AZ::Vector3::CreateAxisX(); //!< The axis the manipulator will move along.
};
/// Data passed between the initial press and first movement of the linear manipulator.
//! Data passed between the initial press and first movement of the linear manipulator.
struct StartTransition
{
/// The normal in local space of the manipulator when the mouse down event happens.
//! The normal in local space of the manipulator when the mouse down event happens.
AZ::Vector3 m_localNormal;
/// Used to scale movement based on camera distance if we want screen space instead
/// of world space displacement.
//! Used to scale movement based on camera distance if we want screen space instead
//! of world space displacement.
float m_screenToWorldScale;
};
/// The state of the manipulator at the start of an interaction.
//! The state of the manipulator at the start of an interaction.
struct Start
{
AZ::Vector3 m_localPosition; ///< The current position of the manipulator in local space.
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.
AZ::Vector3 m_localPosition; //!< The current position of the manipulator in local space.
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.
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.
};
/// The state of the manipulator during an interaction.
//! The state of the manipulator during an interaction.
struct Current
{
AZ::Vector3 m_localPositionOffset; ///< The current offset of the manipulator from its starting position in local space.
AZ::Vector3 m_localScaleOffset; ///< The current offset of the manipulator from its starting scale in local space.
AzFramework::ScreenPoint m_screenPosition; ///< The current position in screen space of the manipulator.
AZ::Vector3 m_localPositionOffset; //!< The current offset of the manipulator from its starting position in local space.
AZ::Vector3 m_localScaleOffset; //!< The current offset of the manipulator from its starting scale in local space.
AzFramework::ScreenPoint m_screenPosition; //!< The current position in screen space of the manipulator.
};
/// Mouse action data used by MouseActionCallback (wraps Fixed, Start and Current manipulator state).
//! Mouse action data used by MouseActionCallback (wraps Fixed, Start and Current manipulator state).
struct Action
{
Fixed m_fixed;
Start m_start;
Current m_current;
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 LocalPosition() const { return m_start.m_localPosition + m_current.m_localPositionOffset; }
AZ::Vector3 LocalPositionOffset() const { return m_current.m_localPositionOffset; }
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_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
{
return AzFramework::Vector2FromScreenVector(
m_current.m_screenPosition - m_start.m_screenPosition);
return AzFramework::Vector2FromScreenVector(m_current.m_screenPosition - m_start.m_screenPosition);
}
};
/// This is the function signature of callbacks that will be invoked whenever a manipulator
/// is clicked on or dragged.
//! This is the function signature of callbacks that will be invoked whenever a manipulator
//! is clicked on or dragged.
using MouseActionCallback = AZStd::function<void(const Action&)>;
/// Tuple of StartTransition (initial mouse down to mouse move) and Start state.
//! Tuple of StartTransition (initial mouse down to mouse move) and Start state.
using Starter = AZStd::tuple<StartTransition, Start>;
void InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback);
@@ -118,7 +128,10 @@ namespace AzToolsFramework
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
void SetAxis(const AZ::Vector3& axis);
const AZ::Vector3& GetAxis() const { return m_fixed.m_axis; }
const AZ::Vector3& GetAxis() const
{
return m_fixed.m_axis;
}
template<typename Views>
void SetViews(Views&& views)
@@ -137,12 +150,9 @@ namespace AzToolsFramework
}
private:
void OnLeftMouseDownImpl(
const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(
const ViewportInteraction::MouseInteraction& interaction) override;
void OnMouseMoveImpl(
const ViewportInteraction::MouseInteraction& interaction) override;
void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void InvalidateImpl() override;
void SetBoundsDirtyImpl() override;
@@ -157,16 +167,24 @@ namespace AzToolsFramework
MouseActionCallback m_onLeftMouseUpCallback = nullptr;
MouseActionCallback m_onMouseMoveCallback = nullptr;
ManipulatorViews m_manipulatorViews; ///< Look of manipulator.
ManipulatorViews m_manipulatorViews; //!< Look of manipulator.
};
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 LinearManipulator::Fixed& fixed,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale,
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 LinearManipulator::Fixed& fixed,
const LinearManipulator::Starter& starter,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale,
const AZ::Transform& localTransform,
const GridSnapParameters& gridSnapParams,
const ViewportInteraction::MouseInteraction& interaction);
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -26,56 +26,55 @@ namespace AzToolsFramework
using ManipulatorManagerId = IdType<struct ManipulatorManagerType>;
static const ManipulatorManagerId InvalidManipulatorManagerId = ManipulatorManagerId(0);
/// EBus interface used to send requests to ManipulatorManager.
class ManipulatorManagerRequests
: public AZ::EBusTraits
//! EBus interface used to send requests to ManipulatorManager.
class ManipulatorManagerRequests : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; /**< We can have multiple manipulator managers.
In the case where there are multiple viewports, each displaying
a different set of entities, a different manipulator manager is required
to provide a different collision space for each viewport so that mouse
hit detection can be handled properly. */
//! We can have multiple manipulator managers.
//! In the case where there are multiple viewports, each displaying
//! a different set of entities, a different manipulator manager is required
//! to provide a different collision space for each viewport so that mouse
//! hit detection can be handled properly.
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
using BusIdType = ManipulatorManagerId;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
virtual ~ManipulatorManagerRequests() = default;
/// Register a manipulator with the Manipulator Manager.
/// @param manipulator The manipulator parameter is passed as a shared_ptr so
/// that the system responsible for managing manipulators can maintain ownership
/// of the manipulator even if is destroyed while in use.
//! Register a manipulator with the Manipulator Manager.
//! @param manipulator The manipulator parameter is passed as a shared_ptr so
//! that the system responsible for managing manipulators can maintain ownership
//! of the manipulator even if is destroyed while in use.
virtual void RegisterManipulator(AZStd::shared_ptr<BaseManipulator> manipulator) = 0;
/// Unregister a manipulator from the Manipulator Manager.
/// After unregistering the manipulator, it will be excluded from mouse hit detection
/// and will not receive any mouse action events. The Manipulator Manager will also
/// relinquish ownership of the manipulator.
//! Unregister a manipulator from the Manipulator Manager.
//! After unregistering the manipulator, it will be excluded from mouse hit detection
//! and will not receive any mouse action events. The Manipulator Manager will also
//! relinquish ownership of the manipulator.
virtual void UnregisterManipulator(BaseManipulator* manipulator) = 0;
/// Delete a manipulator bound.
//! Delete a manipulator bound.
virtual void DeleteManipulatorBound(Picking::RegisteredBoundId boundId) = 0;
/// Mark the bound of a manipulator dirty so it's excluded from mouse hit detection.
/// This should be called whenever a manipulator is moved.
//! Mark the bound of a manipulator dirty so it's excluded from mouse hit detection.
//! This should be called whenever a manipulator is moved.
virtual void SetBoundDirty(Picking::RegisteredBoundId boundId) = 0;
/// Returns true if the manipulator manager is currently interacting, otherwise false.
//! Returns true if the manipulator manager is currently interacting, otherwise false.
virtual bool Interacting() const = 0;
/// Update the bound for a manipulator.
/// If \ref boundId hasn't been registered before or it's invalid, a new bound is created and set using \ref boundShapeData
/// @param manipulatorId The id of the manipulator whose bound needs to update.
/// @param boundId The id of the bound that needs to update.
/// @param boundShapeData The pointer to the new bound shape data.
/// @return If \ref boundId has been registered return the same id, otherwise create a new bound and return its id.
//! Update the bound for a manipulator.
//! If \ref boundId hasn't been registered before or it's invalid, a new bound is created and set using \ref boundShapeData.
//! @param manipulatorId The id of the manipulator whose bound needs to update.
//! @param boundId The id of the bound that needs to update.
//! @param boundShapeData The pointer to the new bound shape data.
//! @return If \ref boundId has been registered return the same id, otherwise create a new bound and return its id.
virtual Picking::RegisteredBoundId UpdateBound(
ManipulatorId manipulatorId, Picking::RegisteredBoundId boundId,
const Picking::BoundRequestShapeBase& boundShapeData) = 0;
ManipulatorId manipulatorId, Picking::RegisteredBoundId boundId, const Picking::BoundRequestShapeBase& boundShapeData) = 0;
};
/// Type to inherit to implement ManipulatorManagerRequests.
//! Type to inherit to implement ManipulatorManagerRequests.
using ManipulatorManagerRequestBus = AZ::EBus<ManipulatorManagerRequests>;
}//namespace AzToolsFramework
} // namespace AzToolsFramework
@@ -1,17 +1,17 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "BaseManipulator.h"
#include "ManipulatorManager.h"
#include "BaseManipulator.h"
#include <AzCore/std/tuple.h>
#include <AzToolsFramework/Picking/BoundInterface.h>
@@ -51,7 +51,8 @@ namespace AzToolsFramework
if (manipulator->Registered())
{
AZ_Assert(manipulator->GetManipulatorManagerId() == m_manipulatorManagerId,
AZ_Assert(
manipulator->GetManipulatorManagerId() == m_manipulatorManagerId,
"This manipulator was registered with a different manipulator manager!");
return;
}
@@ -75,8 +76,7 @@ namespace AzToolsFramework
}
Picking::RegisteredBoundId ManipulatorManager::UpdateBound(
const ManipulatorId manipulatorId, const Picking::RegisteredBoundId boundId,
const Picking::BoundRequestShapeBase& boundShapeData)
const ManipulatorId manipulatorId, const Picking::RegisteredBoundId boundId, const Picking::BoundRequestShapeBase& boundShapeData)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
@@ -99,8 +99,7 @@ namespace AzToolsFramework
AZ_Assert(boundItr->second == manipulatorId, "Manipulator and its bounds are out of synchronization!");
}
const Picking::RegisteredBoundId newBoundId =
m_boundManager.UpdateOrRegisterBound(boundShapeData, boundId);
const Picking::RegisteredBoundId newBoundId = m_boundManager.UpdateOrRegisterBound(boundShapeData, boundId);
if (newBoundId != boundId)
{
@@ -142,13 +141,6 @@ namespace AzToolsFramework
}
}
void ManipulatorManager::CheckModifierKeysChanged(
[[maybe_unused]] const ViewportInteraction::KeyboardModifiers keyboardModifiers,
const ViewportInteraction::MousePick& mousePick)
{
RefreshMouseOverState(mousePick);
}
void ManipulatorManager::DrawManipulators(
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
@@ -181,7 +173,8 @@ namespace AzToolsFramework
if (found != m_boundIdToManipulatorIdMap.end())
{
const auto manipulatorFound = m_manipulatorIdToPtrMap.find(found->second);
AZ_Assert(manipulatorFound != m_manipulatorIdToPtrMap.end(),
AZ_Assert(
manipulatorFound != m_manipulatorIdToPtrMap.end(),
"Found a bound without a corresponding Manipulator, "
"it's likely a bound was not cleaned up correctly");
rayIntersectionDistance = hitItr.second;
@@ -194,10 +187,9 @@ namespace AzToolsFramework
bool ManipulatorManager::ConsumeViewportMousePress(const ViewportInteraction::MouseInteraction& interaction)
{
if (auto pickedManipulator = PickManipulator(interaction.m_mousePick);
pickedManipulator.has_value())
if (auto pickedManipulator = PickManipulator(interaction.m_mousePick); pickedManipulator.has_value())
{
auto[manipulator, intersectionDistance] = pickedManipulator.value();
auto [manipulator, intersectionDistance] = pickedManipulator.value();
if (interaction.m_mouseButtons.Left())
{
@@ -249,24 +241,19 @@ namespace AzToolsFramework
const ViewportInteraction::MousePick& mousePick)
{
float intersectionDistance = 0.0f;
const AZStd::shared_ptr<BaseManipulator> pickedManipulator = PerformRaycast(
mousePick.m_rayOrigin, mousePick.m_rayDirection, intersectionDistance);
const AZStd::shared_ptr<BaseManipulator> pickedManipulator =
PerformRaycast(mousePick.m_rayOrigin, mousePick.m_rayDirection, intersectionDistance);
return pickedManipulator.get() != nullptr
? AZStd::make_optional(AZStd::make_tuple(pickedManipulator, intersectionDistance))
: AZStd::nullopt;
return pickedManipulator.get() != nullptr ? AZStd::make_optional(AZStd::make_tuple(pickedManipulator, intersectionDistance))
: AZStd::nullopt;
}
ManipulatorManager::PickedManipulatorId ManipulatorManager::PickManipulatorId(
const ViewportInteraction::MousePick& mousePick)
ManipulatorManager::PickedManipulatorId ManipulatorManager::PickManipulatorId(const ViewportInteraction::MousePick& mousePick)
{
auto [manipulator, intersectionDistance] =
PickManipulator(mousePick).value_or(PickedManipulator(nullptr, 0.0f));
const ManipulatorId pickedManipulatorId = manipulator
? manipulator->GetManipulatorId()
: InvalidManipulatorId;
auto [manipulator, intersectionDistance] = PickManipulator(mousePick).value_or(PickedManipulator(nullptr, 0.0f));
const ManipulatorId pickedManipulatorId = manipulator ? manipulator->GetManipulatorId() : InvalidManipulatorId;
return PickedManipulatorId{pickedManipulatorId, intersectionDistance};
return PickedManipulatorId{ pickedManipulatorId, intersectionDistance };
}
ManipulatorManager::ConsumeMouseMoveResult ManipulatorManager::ConsumeViewportMouseMove(
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -23,7 +23,7 @@ namespace AzFramework
{
struct CameraState;
class DebugDisplayRequests;
}
} // namespace AzFramework
namespace AzToolsFramework
{
@@ -40,15 +40,15 @@ namespace AzToolsFramework
class BaseManipulator;
class LinearManipulator;
/// State of overall manipulator manager.
//! State of overall manipulator manager.
struct ManipulatorManagerState
{
bool m_interacting;
};
/// This class serves to manage all relevant mouse events and coordinate all registered manipulators to function properly.
/// ManipulatorManager does not manage the life cycle of specific manipulators. The users of manipulators are responsible
/// for creating and deleting them at right time, as well as registering and unregistering accordingly.
//! This class serves to manage all relevant mouse events and coordinate all registered manipulators to function properly.
//! ManipulatorManager does not manage the life cycle of specific manipulators. The users of manipulators are responsible
//! for creating and deleting them at right time, as well as registering and unregistering accordingly.
class ManipulatorManager
: private ManipulatorManagerRequestBus::Handler
, private EditorEntityInfoNotificationBus::Handler
@@ -59,7 +59,7 @@ namespace AzToolsFramework
explicit ManipulatorManager(ManipulatorManagerId managerId);
~ManipulatorManager();
/// The result of consuming a mouse move.
//! The result of consuming a mouse move.
enum class ConsumeMouseMoveResult
{
None,
@@ -80,57 +80,52 @@ namespace AzToolsFramework
void DeleteManipulatorBound(Picking::RegisteredBoundId boundId) override;
void SetBoundDirty(Picking::RegisteredBoundId boundId) override;
Picking::RegisteredBoundId UpdateBound(
ManipulatorId manipulatorId, Picking::RegisteredBoundId boundId,
const Picking::BoundRequestShapeBase& boundShapeData) override;
bool Interacting() const override { return m_activeManipulator != nullptr; }
ManipulatorId manipulatorId, Picking::RegisteredBoundId boundId, const Picking::BoundRequestShapeBase& boundShapeData) override;
bool Interacting() const override
{
return m_activeManipulator != nullptr;
}
void DrawManipulators(
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction);
// O3DE_DEPRECATED(LY-117150)
/// Check if the modifier key state has changed - if so we may need to refresh
/// certain manipulator bounds.
AZ_DEPRECATED(
void CheckModifierKeysChanged(
ViewportInteraction::KeyboardModifiers keyboardModifiers,
const ViewportInteraction::MousePick& mousePick),
"CheckModifierKeysChanged is deprecated and will be removed in a future release");
protected:
/// @param rayOrigin The origin of the ray to test intersection with.
/// @param rayDirection The direction of the ray to test intersection with.
/// @param[out] rayIntersectionDistance The result intersecting point equals "rayOrigin + rayIntersectionDistance * rayDirection".
/// @return A pointer to a manipulator that the ray intersects. Null pointer if no intersection is detected.
//! @param rayOrigin The origin of the ray to test intersection with.
//! @param rayDirection The direction of the ray to test intersection with.
//! @param[out] rayIntersectionDistance The result intersecting point equals "rayOrigin + rayIntersectionDistance * rayDirection".
//! @return A pointer to a manipulator that the ray intersects. Null pointer if no intersection is detected.
AZStd::shared_ptr<BaseManipulator> PerformRaycast(
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, float& rayIntersectionDistance);
// EditorEntityInfoNotifications ...
void OnEntityInfoUpdatedVisibility(AZ::EntityId entityId, bool visible) override;
/// Alias for a Manipulator and intersection distance.
//! Alias for a Manipulator and intersection distance.
using PickedManipulator = AZStd::tuple<AZStd::shared_ptr<BaseManipulator>, float>;
/// Alias for a ManipulatorId and intersection distance.
//! Alias for a ManipulatorId and intersection distance.
using PickedManipulatorId = AZStd::tuple<ManipulatorId, float>;
/// Return the picked manipulator and intersection distance if a manipulator was intersected.
//! Return the picked manipulator and intersection distance if a manipulator was intersected.
AZStd::optional<PickedManipulator> PickManipulator(const ViewportInteraction::MousePick& mousePick);
/// Wrapper for PickManipulator to return the ManipulatorId directly.
//! Wrapper for PickManipulator to return the ManipulatorId directly.
PickedManipulatorId PickManipulatorId(const ViewportInteraction::MousePick& mousePick);
/// Called once per frame after all manipulators have been drawn (and their
/// bounds updated if required).
//! Called once per frame after all manipulators have been drawn (and their
//! bounds updated if required).
void RefreshMouseOverState(const ViewportInteraction::MousePick& mousePick);
ManipulatorManagerId m_manipulatorManagerId; ///< This manipulator manager's id.
ManipulatorId m_nextManipulatorIdToGenerate; ///< Id to use for the next manipulator that is registered with this manager.
ManipulatorManagerId m_manipulatorManagerId; //!< This manipulator manager's id.
ManipulatorId m_nextManipulatorIdToGenerate; //!< Id to use for the next manipulator that is registered with this manager.
AZStd::unordered_map<ManipulatorId, AZStd::shared_ptr<BaseManipulator>> m_manipulatorIdToPtrMap; ///< Mapping from a manipulatorId to the corresponding manipulator.
AZStd::unordered_map<Picking::RegisteredBoundId, ManipulatorId> m_boundIdToManipulatorIdMap; ///< Mapping from a boundId to the corresponding manipulatorId.
AZStd::unordered_map<ManipulatorId, AZStd::shared_ptr<BaseManipulator>>
m_manipulatorIdToPtrMap; //!< Mapping from a manipulatorId to the corresponding manipulator.
AZStd::unordered_map<Picking::RegisteredBoundId, ManipulatorId>
m_boundIdToManipulatorIdMap; //!< Mapping from a boundId to the corresponding manipulatorId.
AZStd::shared_ptr<BaseManipulator> m_activeManipulator; ///< The manipulator we are currently interacting with.
Picking::ManipulatorBoundManager m_boundManager; ///< All active manipulator bounds that could be interacted with.
AZStd::shared_ptr<BaseManipulator> m_activeManipulator; //!< The manipulator we are currently interacting with.
Picking::ManipulatorBoundManager m_boundManager; //!< All active manipulator bounds that could be interacted with.
};
// The main/default ManipulatorManagerId to be used for
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "ManipulatorSnapping.h"
@@ -19,19 +19,27 @@
#include <AzToolsFramework/Viewport/ViewportMessages.h>
AZ_CVAR(
AZ::Color, cl_viewportGridMainColor, AZ::Color::CreateFromRgba(26, 26, 26, 127), nullptr,
AZ::ConsoleFunctorFlags::Null, "Main color for snapping grid");
AZ::Color,
cl_viewportGridMainColor,
AZ::Color::CreateFromRgba(26, 26, 26, 127),
nullptr,
AZ::ConsoleFunctorFlags::Null,
"Main color for snapping grid");
AZ_CVAR(
AZ::Color, cl_viewportGridFadeColor, AZ::Color::CreateFromRgba(127, 127, 127, 0), nullptr,
AZ::ConsoleFunctorFlags::Null, "Fade color for snapping grid");
AZ::Color,
cl_viewportGridFadeColor,
AZ::Color::CreateFromRgba(127, 127, 127, 0),
nullptr,
AZ::ConsoleFunctorFlags::Null,
"Fade color for snapping grid");
AZ_CVAR(int, cl_viewportGridSquareCount, 20, nullptr, AZ::ConsoleFunctorFlags::Null, "Number of grid squares for snapping grid");
AZ_CVAR(float, cl_viewportGridLineWidth, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Width of grid lines for snapping grid");
AZ_CVAR(
int, cl_viewportGridSquareCount, 20, nullptr, AZ::ConsoleFunctorFlags::Null,
"Number of grid squares for snapping grid");
AZ_CVAR(
float, cl_viewportGridLineWidth, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null,
"Width of grid lines for snapping grid");
AZ_CVAR(
float, cl_viewportFadeLineDistanceScale, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null,
float,
cl_viewportFadeLineDistanceScale,
1.0f,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"The scale to be applied to the line that fades out (scales the current gridSize)");
namespace AzToolsFramework
@@ -42,39 +50,53 @@ 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)
const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale,
const AZ::Vector3& worldRayOrigin,
const AZ::Vector3& worldRayDirection)
{
const AZ::Transform worldFromLocalUniform = AzToolsFramework::TransformUniformScale(worldFromLocal);
const AZ::Transform localFromWorldUniform = worldFromLocalUniform.GetInverse();
return {localFromWorldUniform.TransformPoint(worldRayOrigin),
TransformDirectionNoScaling(localFromWorldUniform, worldRayDirection),
ScaleReciprocal(worldFromLocalUniform),
NonUniformScaleReciprocal(nonUniformScale)};
return { localFromWorldUniform.TransformPoint(worldRayOrigin),
TransformDirectionNoScaling(localFromWorldUniform, worldRayDirection), 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(
const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal,
const int viewportId, const float gridSize)
const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, const int viewportId, const float gridSize)
{
const AZ::Transform localFromWorld = worldFromLocal.GetInverse();
const AZ::Vector3 localSurfacePosition = localFromWorld.TransformPoint(worldSurfacePosition);
@@ -87,8 +109,7 @@ namespace AzToolsFramework
// find terrain height at xy snapped location
float terrainHeight = 0.0f;
ViewportInteraction::MainEditorViewportInteractionRequestBus::EventResult(
terrainHeight, viewportId,
&ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::TerrainHeight,
terrainHeight, viewportId, &ViewportInteraction::MainEditorViewportInteractionRequestBus::Events::TerrainHeight,
Vector3ToVector2(worldFromLocal.TransformPoint(localSnappedSurfacePosition)));
// set snapped z value to terrain height
@@ -102,8 +123,7 @@ namespace AzToolsFramework
{
bool snapping = false;
ViewportInteraction::ViewportInteractionRequestBus::EventResult(
snapping, viewportId,
&ViewportInteraction::ViewportInteractionRequestBus::Events::GridSnappingEnabled);
snapping, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::GridSnappingEnabled);
return snapping;
}
@@ -112,8 +132,7 @@ namespace AzToolsFramework
{
float gridSize = 0.0f;
ViewportInteraction::ViewportInteractionRequestBus::EventResult(
gridSize, viewportId,
&ViewportInteraction::ViewportInteractionRequestBus::Events::GridSize);
gridSize, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::GridSize);
return gridSize;
}
@@ -122,7 +141,8 @@ namespace AzToolsFramework
{
bool snapping = GridSnapping(viewportId);
const float gridSize = GridSize(viewportId);
if (AZ::IsClose(gridSize, 0.0f, 1e-2f)) // Same threshold value as min value for m_spinBox in SnapToWidget constructor in MainWindow.cpp
if (AZ::IsClose(
gridSize, 0.0f, 1e-2f)) // Same threshold value as min value for m_spinBox in SnapToWidget constructor in MainWindow.cpp
{
snapping = false;
}
@@ -134,8 +154,7 @@ namespace AzToolsFramework
{
bool snapping = false;
ViewportInteraction::ViewportInteractionRequestBus::EventResult(
snapping, viewportId,
&ViewportInteraction::ViewportInteractionRequestBus::Events::AngleSnappingEnabled);
snapping, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::AngleSnappingEnabled);
return snapping;
}
@@ -144,8 +163,7 @@ namespace AzToolsFramework
{
float angle = 0.0f;
ViewportInteraction::ViewportInteractionRequestBus::EventResult(
angle, viewportId,
&ViewportInteraction::ViewportInteractionRequestBus::Events::AngleStep);
angle, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::AngleStep);
return angle;
}
@@ -154,14 +172,12 @@ namespace AzToolsFramework
{
bool show = false;
ViewportInteraction::ViewportInteractionRequestBus::EventResult(
show, viewportId,
&ViewportInteraction::ViewportInteractionRequestBus::Events::ShowGrid);
show, viewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::ShowGrid);
return show;
}
void DrawSnappingGrid(
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal, const float squareSize)
void DrawSnappingGrid(AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal, const float squareSize)
{
debugDisplay.PushMatrix(worldFromLocal);
@@ -183,21 +199,17 @@ namespace AzToolsFramework
// draw the faded end parts of the grid lines
debugDisplay.DrawLine(
AZ::Vector3(lineOffset, -halfGridSize, 0.0f),
AZ::Vector3(lineOffset, -(halfGridSize + fadeLineLength), 0.0f),
AZ::Vector3(lineOffset, -halfGridSize, 0.0f), AZ::Vector3(lineOffset, -(halfGridSize + fadeLineLength), 0.0f),
gridMainColor, gridFadeColor);
debugDisplay.DrawLine(
AZ::Vector3(lineOffset, halfGridSize, 0.0f),
AZ::Vector3(lineOffset, (halfGridSize + fadeLineLength), 0.0f),
AZ::Vector3(lineOffset, halfGridSize, 0.0f), AZ::Vector3(lineOffset, (halfGridSize + fadeLineLength), 0.0f), gridMainColor,
gridFadeColor);
debugDisplay.DrawLine(
AZ::Vector3(-halfGridSize, lineOffset, 0.0f), AZ::Vector3(-(halfGridSize + fadeLineLength), lineOffset, 0.0f),
gridMainColor, gridFadeColor);
debugDisplay.DrawLine(
AZ::Vector3(-halfGridSize, lineOffset, 0.0f),
AZ::Vector3(-(halfGridSize + fadeLineLength), lineOffset, 0.0f),
gridMainColor, gridFadeColor);
debugDisplay.DrawLine(
AZ::Vector3(halfGridSize, lineOffset, 0.0f),
AZ::Vector3((halfGridSize + fadeLineLength), lineOffset, 0.0f),
gridMainColor, gridFadeColor);
AZ::Vector3(halfGridSize, lineOffset, 0.0f), AZ::Vector3((halfGridSize + fadeLineLength), lineOffset, 0.0f), gridMainColor,
gridFadeColor);
// build a vector of the main grid lines to draw (start and end positions)
lines.push_back(AZ::Vector3(lineOffset, -halfGridSize, 0.0f));
@@ -1,19 +1,19 @@
/*
* 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.
*
*/
* 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/Math/Vector3.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Vector3.h>
namespace AzFramework
{
@@ -22,7 +22,7 @@ namespace AzFramework
namespace AzToolsFramework
{
/// Structure to encapsulate grid snapping properties.
//! Structure to encapsulate grid snapping properties.
struct GridSnapParameters
{
GridSnapParameters(bool gridSnap, float gridSize);
@@ -31,100 +31,92 @@ 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.
//! 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.
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.
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.
//! Build a ManipulatorInteraction structure from the incoming viewport interaction.
ManipulatorInteraction BuildManipulatorInteraction(
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection);
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.
AZ::Vector3 CalculateSnappedOffset(
const AZ::Vector3& unsnappedPosition, const AZ::Vector3& axis, float 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);
/// 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)
//! 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(
const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal,
int viewportId, float gridSize);
const AZ::Vector3& worldSurfacePosition, const AZ::Transform& worldFromLocal, int viewportId, float gridSize);
/// Wrapper for grid snapping and grid size bus calls.
//! Wrapper for grid snapping and grid size bus calls.
GridSnapParameters GridSnapSettings(int viewportId);
/// Wrapper for angle snapping enabled bus call.
//! Wrapper for angle snapping enabled bus call.
bool AngleSnapping(int viewportId);
/// Wrapper for angle snapping increment bus call.
/// @return Angle in degrees
//! Wrapper for angle snapping increment bus call.
//! @return Angle in degrees.
float AngleStep(int viewportId);
/// Wrapper for grid rendering check call.
//! Wrapper for grid rendering check call.
bool ShowingGrid(int viewportId);
/// Render the grid used for snapping.
void DrawSnappingGrid(
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal, float squareSize);
//! Render the grid used for snapping.
void DrawSnappingGrid(AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& worldFromLocal, float squareSize);
/// Round to x number of significant digits.
/// @param value Number to round.
/// @param exponent Precision to use when rounding.
//! Round to x number of significant digits.
//! @param value Number to round.
//! @param exponent Precision to use when rounding.
inline float Round(const float value, const float exponent)
{
const float precision = std::pow(10.0f, exponent);
return roundf(value * precision) / precision;
}
/// Round to 3 significant digits (3 digits common usage).
//! Round to 3 significant digits (3 digits common usage).
inline float Round3(const float value)
{
return Round(value, 3.0f);
}
/// Util to return sign of floating point number.
/// value > 0 return 1.0
/// value < 0 return -1.0
/// value == 0 return 0.0
//! Util to return sign of floating point number.
//! value > 0 return 1.0
//! value < 0 return -1.0
//! value == 0 return 0.0
inline float Sign(const float value)
{
return static_cast<float>((0.0f < value) - (value < 0.0f));
}
/// Find the max scale element and return the reciprocal of it.
/// Note: The reciprocal will be rounded to three significant digits to eliminate
/// noise in the value returned when dealing with values far from the origin.
//! Find the max scale element and return the reciprocal of it.
//! Note: The reciprocal will be rounded to three significant digits to eliminate
//! noise in the value returned when dealing with values far from the origin.
inline float ScaleReciprocal(const AZ::Transform& transform)
{
return Round3(1.0f / transform.GetUniformScale());
}
/// Find the reciprocal of the non-uniform scale.
/// Each element will be rounded to three significant digits to eliminate noise
/// when dealing with values far from the origin.
//! Find the reciprocal of the non-uniform scale.
//! Each element will be rounded to three significant digits to eliminate noise
//! when dealing with values far from the origin.
inline AZ::Vector3 NonUniformScaleReciprocal(const AZ::Vector3& nonUniformScale)
{
AZ::Vector3 scaleReciprocal = nonUniformScale.GetReciprocal();
return AZ::Vector3(
Round3(scaleReciprocal.GetX()),
Round3(scaleReciprocal.GetY()),
Round3(scaleReciprocal.GetZ()));
return AZ::Vector3(Round3(scaleReciprocal.GetX()), Round3(scaleReciprocal.GetY()), Round3(scaleReciprocal.GetZ()));
}
} // namespace AzToolsFramework
@@ -20,7 +20,7 @@ namespace AZ
namespace AzToolsFramework
{
/// Handles location for manipulators which have a global space but no local transformation.
//! Handles location for manipulators which have a global space but no local transformation.
class ManipulatorSpace
{
public:
@@ -32,17 +32,16 @@ namespace AzToolsFramework
const AZ::Vector3& GetNonUniformScale() const;
void SetNonUniformScale(const AZ::Vector3& nonUniformScale);
/// Calculates a transform combining the space and local transform, taking non-uniform scale into account.
//! Calculates a transform combining the space and local transform, taking non-uniform scale into account.
AZ::Transform ApplySpace(const AZ::Transform& localTransform) const;
private:
AZ::Transform m_space = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in.
AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne(); ///< Handles non-uniform scale for the space the manipulator is in.
AZ::Transform m_space = AZ::Transform::CreateIdentity(); //!< Space the manipulator is in.
AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne(); //!< Handles non-uniform scale for the space the manipulator is in.
};
/// Handles location for manipulators which have a global space and a local position, but no local rotation.
class ManipulatorSpaceWithLocalPosition
: public ManipulatorSpace
//! Handles location for manipulators which have a global space and a local position, but no local rotation.
class ManipulatorSpaceWithLocalPosition : public ManipulatorSpace
{
public:
AZ_TYPE_INFO(ManipulatorSpaceWithLocalPosition, "{47BE15AF-60A8-436B-8F3F-7DDFB97220E6}")
@@ -52,12 +51,11 @@ namespace AzToolsFramework
void SetLocalPosition(const AZ::Vector3& localPosition);
private:
AZ::Vector3 m_localPosition = AZ::Vector3::CreateZero(); ///< Position in local space.
AZ::Vector3 m_localPosition = AZ::Vector3::CreateZero(); //!< Position in local space.
};
/// Handles location for manipulators which have a global space and a local transform (position and rotation).
class ManipulatorSpaceWithLocalTransform
: public ManipulatorSpace
//! Handles location for manipulators which have a global space and a local transform (position and rotation).
class ManipulatorSpaceWithLocalTransform : public ManipulatorSpace
{
public:
AZ_TYPE_INFO(ManipulatorSpaceWithLocalTransform, "{6D100797-1DD8-45B0-A21C-8893B770C0BC}")
@@ -72,6 +70,6 @@ namespace AzToolsFramework
void SetLocalOrientation(const AZ::Quaternion& localOrientation);
private:
AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); ///< Local transform.
AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); //!< Local transform.
};
} // namespace AzToolsFramework
@@ -1,26 +1,26 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "ManipulatorView.h"
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/NonUniformScaleBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Math/VectorConversions.h>
#include <AzCore/std/containers/array.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/Manipulators/AngularManipulator.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h>
#include <AzToolsFramework/Manipulators/LineSegmentSelectionManipulator.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/Manipulators/PlanarManipulator.h>
#include <AzToolsFramework/Manipulators/SplineSelectionManipulator.h>
#include <AzToolsFramework/Maths/TransformUtils.h>
@@ -33,8 +33,7 @@ namespace AzToolsFramework
AZ::Transform WorldFromLocalWithUniformScale(const AZ::EntityId entityId)
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(
worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
return TransformUniformScale(worldFromLocal);
}
@@ -56,13 +55,16 @@ namespace AzToolsFramework
return AzToolsFramework::TransformDirectionNoScaling(m_worldFromLocal, direction);
}
/// Take into account the location of the camera and orientate the axis so it faces the camera.
/// if we did correct the camera (shouldCorrect is true) then we know the axis facing us it negative.
/// we can use this to change the rendering for a flipped axis if we wish.
// Take into account the location of the camera and orientate the axis so it faces the camera.
// if we did correct the camera (shouldCorrect is true) then we know the axis facing us it negative.
// we can use this to change the rendering for a flipped axis if we wish.
static void CameraCorrectAxis(
const AZ::Vector3& axis, AZ::Vector3& correctedAxis, const ManipulatorManagerState& managerState,
const AZ::Vector3& axis,
AZ::Vector3& correctedAxis,
const ManipulatorManagerState& managerState,
const ViewportInteraction::MouseInteraction& mouseInteraction,
const AZ::Transform& worldFromLocal, const AZ::Vector3& localPosition,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& localPosition,
const AzFramework::CameraState& cameraState,
bool* shouldCorrect = nullptr)
{
@@ -74,9 +76,7 @@ namespace AzToolsFramework
const bool correcting = ShouldFlipCameraAxis(worldFromLocal, localPosition, axis, cameraState);
// the corrected axis, if no flip was required, output == input
correctedAxis = correcting
? -axis
: axis;
correctedAxis = correcting ? -axis : axis;
// optional out ref to use if we care about the result
if (shouldCorrect)
@@ -86,10 +86,13 @@ namespace AzToolsFramework
}
}
/// Calculate quad bound in world space.
// calculate quad bound in world space.
static Picking::BoundShapeQuad CalculateQuadBound(
const AZ::Vector3& localPosition, const ManipulatorState& manipulatorState,
const AZ::Vector3& axis1, const AZ::Vector3& axis2, const float size)
const AZ::Vector3& localPosition,
const ManipulatorState& manipulatorState,
const AZ::Vector3& axis1,
const AZ::Vector3& axis2,
const float size)
{
const AZ::Vector3 worldPosition = manipulatorState.TransformPoint(localPosition);
const AZ::Vector3 endAxis1World = manipulatorState.TransformDirectionNoScaling(axis1) * size;
@@ -104,8 +107,10 @@ namespace AzToolsFramework
}
static Picking::BoundShapeQuad CalculateQuadBoundBillboard(
const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal,
const float size, const AzFramework::CameraState& cameraState)
const AZ::Vector3& localPosition,
const AZ::Transform& worldFromLocal,
const float size,
const AzFramework::CameraState& cameraState)
{
const AZ::Vector3 worldPosition = worldFromLocal.TransformPoint(localPosition);
@@ -117,10 +122,13 @@ namespace AzToolsFramework
return quadBound;
}
/// Calculate line bound in world space (axis and length).
// calculate line bound in world space (axis and length).
static Picking::BoundShapeLineSegment CalculateLineBound(
const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal,
const AZ::Vector3& axis, const float length, const float width)
const AZ::Vector3& localPosition,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& axis,
const float length,
const float width)
{
Picking::BoundShapeLineSegment lineBound;
lineBound.m_start = worldFromLocal.TransformPoint(localPosition);
@@ -129,7 +137,7 @@ namespace AzToolsFramework
return lineBound;
}
/// Calculate line bound in world space (start and end point).
// calculate line bound in world space (start and end point).
static Picking::BoundShapeLineSegment CalculateLineBound(
const AZ::Vector3& localStartPosition,
const AZ::Vector3& localEndPosition,
@@ -143,10 +151,14 @@ namespace AzToolsFramework
return lineBound;
}
/// Calculate cone bound in world space.
// calculate cone bound in world space.
static Picking::BoundShapeCone CalculateConeBound(
const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal,
const AZ::Vector3& axis, const AZ::Vector3& offset, const float length, const float radius)
const AZ::Vector3& localPosition,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& axis,
const AZ::Vector3& offset,
const float length,
const float radius)
{
Picking::BoundShapeCone coneBound;
coneBound.m_radius = radius;
@@ -156,10 +168,13 @@ namespace AzToolsFramework
return coneBound;
}
/// Calculate box bound in world space.
// calculate box bound in world space.
static Picking::BoundShapeBox CalculateBoxBound(
const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal,
const AZ::Quaternion& orientation, const AZ::Vector3& offset, const AZ::Vector3& halfExtents)
const AZ::Vector3& localPosition,
const AZ::Transform& worldFromLocal,
const AZ::Quaternion& orientation,
const AZ::Vector3& offset,
const AZ::Vector3& halfExtents)
{
Picking::BoundShapeBox boxBound;
boxBound.m_halfExtents = halfExtents;
@@ -168,10 +183,13 @@ namespace AzToolsFramework
return boxBound;
}
/// Calculate cylinder bound in world space.
// calculate cylinder bound in world space.
static Picking::BoundShapeCylinder CalculateCylinderBound(
const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal,
const AZ::Vector3& axis, const float length, const float radius)
const AZ::Vector3& localPosition,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& axis,
const float length,
const float radius)
{
Picking::BoundShapeCylinder boxBound;
boxBound.m_base = worldFromLocal.TransformPoint(localPosition);
@@ -181,10 +199,9 @@ namespace AzToolsFramework
return boxBound;
}
/// Calculate sphere bound in world space.
// calculate sphere bound in world space.
static Picking::BoundShapeSphere CalculateSphereBound(
const AZ::Vector3& localPosition, const ManipulatorState& manipulatorState,
const float radius)
const AZ::Vector3& localPosition, const ManipulatorState& manipulatorState, const float radius)
{
Picking::BoundShapeSphere sphereBound;
sphereBound.m_center = manipulatorState.TransformPoint(localPosition);
@@ -192,10 +209,13 @@ namespace AzToolsFramework
return sphereBound;
}
/// Calculate torus bound in world space.
// calculate torus bound in world space.
static Picking::BoundShapeTorus CalculateTorusBound(
const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal,
const AZ::Vector3& axis, const float radius, const float width)
const AZ::Vector3& localPosition,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& axis,
const float radius,
const float width)
{
Picking::BoundShapeTorus torusBound;
torusBound.m_center = worldFromLocal.TransformPoint(localPosition);
@@ -205,7 +225,7 @@ namespace AzToolsFramework
return torusBound;
}
/// Calculate spline bound in world space.
// calculate spline bound in world space.
static Picking::BoundShapeSpline CalculateSplineBound(
const AZStd::weak_ptr<const AZ::Spline>& spline, const AZ::Transform& worldFromLocal, const float width)
{
@@ -224,8 +244,7 @@ namespace AzToolsFramework
return lineWidth[mouseOver];
}
static AZ::Color ViewColor(
const bool mouseOver, const AZ::Color& defaultColor, const AZ::Color& mouseOverColor)
static AZ::Color ViewColor(const bool mouseOver, const AZ::Color& defaultColor, const AZ::Color& mouseOverColor)
{
const AZStd::array<AZ::Color, 2> viewColor = { { defaultColor, mouseOverColor } };
return viewColor[mouseOver].GetAsVector4();
@@ -250,19 +269,16 @@ namespace AzToolsFramework
void ManipulatorView::SetBoundDirty(const ManipulatorManagerId managerId)
{
ManipulatorManagerRequestBus::Event(
managerId, &ManipulatorManagerRequestBus::Events::SetBoundDirty, m_boundId);
ManipulatorManagerRequestBus::Event(managerId, &ManipulatorManagerRequestBus::Events::SetBoundDirty, m_boundId);
m_boundDirty = true;
}
void ManipulatorView::RefreshBound(
const ManipulatorManagerId managerId, const ManipulatorId manipulatorId,
const Picking::BoundRequestShapeBase& bound)
const ManipulatorManagerId managerId, const ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound)
{
ManipulatorManagerRequestBus::EventResult(
m_boundId, managerId, &ManipulatorManagerRequestBus::Events::UpdateBound,
manipulatorId, m_boundId, bound);
m_boundId, managerId, &ManipulatorManagerRequestBus::Events::UpdateBound, manipulatorId, m_boundId, bound);
// store the manager id if we know the bound has been registered
m_managerId = managerId;
@@ -271,8 +287,7 @@ namespace AzToolsFramework
}
void ManipulatorView::RefreshBoundInternal(
const ManipulatorManagerId managerId, const ManipulatorId manipulatorId,
const Picking::BoundRequestShapeBase& bound)
const ManipulatorManagerId managerId, const ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound)
{
// update the manipulator's bounds if necessary
// if m_screenSizeFixed is true, any camera movement can potentially change the size
@@ -287,8 +302,7 @@ namespace AzToolsFramework
{
if (m_boundId != Picking::InvalidBoundId)
{
ManipulatorManagerRequestBus::Event(
managerId, &ManipulatorManagerRequestBus::Events::DeleteManipulatorBound, m_boundId);
ManipulatorManagerRequestBus::Event(managerId, &ManipulatorManagerRequestBus::Events::DeleteManipulatorBound, m_boundId);
m_boundId = Picking::InvalidBoundId;
}
@@ -297,33 +311,34 @@ namespace AzToolsFramework
float ManipulatorView::ManipulatorViewScaleMultiplier(
const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) const
{
return ScreenSizeFixed()
? CalculateScreenToWorldMultiplier(worldPosition, cameraState)
: 1.0f;
return ScreenSizeFixed() ? CalculateScreenToWorldMultiplier(worldPosition, cameraState) : 1.0f;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ManipulatorViewQuad::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const AZ::Vector3 axis1 = m_axis1;
const AZ::Vector3 axis2 = m_axis2;
CameraCorrectAxis(
axis1, m_cameraCorrectedAxis1, managerState, mouseInteraction,
manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState);
axis1, m_cameraCorrectedAxis1, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
CameraCorrectAxis(
axis2, m_cameraCorrectedAxis2, managerState, mouseInteraction,
manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState);
axis2, m_cameraCorrectedAxis2, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
const Picking::BoundShapeQuad quadBound =
CalculateQuadBound(
manipulatorState.m_localPosition, manipulatorState, m_cameraCorrectedAxis1, m_cameraCorrectedAxis2,
m_size * ManipulatorViewScaleMultiplier(
const Picking::BoundShapeQuad quadBound = CalculateQuadBound(
manipulatorState.m_localPosition, manipulatorState, m_cameraCorrectedAxis1, m_cameraCorrectedAxis2,
m_size *
ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState));
debugDisplay.SetLineWidth(defaultLineWidth(manipulatorState.m_mouseOver));
@@ -339,9 +354,7 @@ namespace AzToolsFramework
debugDisplay.SetColor(Vector3ToVector4(m_mouseOverColor.GetAsVector3(), 0.5f));
debugDisplay.CullOff();
debugDisplay.DrawQuad(
quadBound.m_corner1, quadBound.m_corner2,
quadBound.m_corner3, quadBound.m_corner4);
debugDisplay.DrawQuad(quadBound.m_corner1, quadBound.m_corner2, quadBound.m_corner3, quadBound.m_corner4);
debugDisplay.CullOn();
}
@@ -349,41 +362,46 @@ namespace AzToolsFramework
}
void ManipulatorViewQuadBillboard::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& /*mouseInteraction*/)
{
const Picking::BoundShapeQuad quadBound =
CalculateQuadBoundBillboard(manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal,
m_size * ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState), cameraState);
const Picking::BoundShapeQuad quadBound = CalculateQuadBoundBillboard(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal,
m_size *
ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState),
cameraState);
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4());
debugDisplay.DrawQuad(
quadBound.m_corner1, quadBound.m_corner2,
quadBound.m_corner3, quadBound.m_corner4);
debugDisplay.DrawQuad(quadBound.m_corner1, quadBound.m_corner2, quadBound.m_corner3, quadBound.m_corner4);
RefreshBoundInternal(managerId, manipulatorId, quadBound);
}
void ManipulatorViewLine::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const float viewScale = ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const float viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
CameraCorrectAxis(
m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction,
manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState);
m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
const Picking::BoundShapeLineSegment lineBound =
CalculateLineBound(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal,
m_cameraCorrectedAxis, m_length * viewScale, m_width * viewScale);
const Picking::BoundShapeLineSegment lineBound = CalculateLineBound(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis, m_length * viewScale,
m_width * viewScale);
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4());
debugDisplay.SetLineWidth(defaultLineWidth(manipulatorState.m_mouseOver));
@@ -393,13 +411,16 @@ namespace AzToolsFramework
}
void ManipulatorViewLineSelect::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const float viewScale = ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const float viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const Picking::BoundShapeLineSegment lineBound =
CalculateLineBound(m_localStart, m_localEnd, manipulatorState, m_width * viewScale);
@@ -407,44 +428,42 @@ namespace AzToolsFramework
if (manipulatorState.m_mouseOver)
{
const LineSegmentSelectionManipulator::Action action = CalculateManipulationDataAction(
manipulatorState.m_worldFromLocal, manipulatorState.m_nonUniformScale,
mouseInteraction.m_mousePick.m_rayOrigin, mouseInteraction.m_mousePick.m_rayDirection,
cameraState.m_farClip, m_localStart, m_localEnd);
manipulatorState.m_worldFromLocal, manipulatorState.m_nonUniformScale, mouseInteraction.m_mousePick.m_rayOrigin,
mouseInteraction.m_mousePick.m_rayDirection, cameraState.m_farClip, m_localStart, m_localEnd);
const AZ::Vector3 worldLineHitPosition = manipulatorState.TransformPoint(action.m_localLineHitPosition);
debugDisplay.SetColor(AZ::Vector4(0.0f, 1.0f, 0.0f, 1.0f));
debugDisplay.DrawBall(
worldLineHitPosition, ManipulatorViewScaleMultiplier(worldLineHitPosition, cameraState)
* g_defaultManipulatorSphereRadius, false);
worldLineHitPosition, ManipulatorViewScaleMultiplier(worldLineHitPosition, cameraState) * g_defaultManipulatorSphereRadius,
false);
}
RefreshBoundInternal(managerId, manipulatorId, lineBound);
}
void ManipulatorViewCone::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const float viewScale = ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const float viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
CameraCorrectAxis(
m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction,
manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition,
cameraState, &m_shouldCorrect);
m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState, &m_shouldCorrect);
CameraCorrectAxis(
m_offset, m_cameraCorrectedOffset, managerState, mouseInteraction,
manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState);
m_offset, m_cameraCorrectedOffset, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
const Picking::BoundShapeCone coneBound =
CalculateConeBound(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis,
m_cameraCorrectedOffset * viewScale,
m_length * viewScale,
m_radius * viewScale);
const Picking::BoundShapeCone coneBound = CalculateConeBound(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis, m_cameraCorrectedOffset * viewScale,
m_length * viewScale, m_radius * viewScale);
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4());
if (m_shouldCorrect)
@@ -460,73 +479,77 @@ namespace AzToolsFramework
}
void ManipulatorViewBox::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const float viewScale = ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const float viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const AZ::Quaternion orientation = m_orientation;
CameraCorrectAxis(
m_offset, m_cameraCorrectedOffset, managerState, mouseInteraction,
manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition,
cameraState);
m_offset, m_cameraCorrectedOffset, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
const Picking::BoundShapeBox boxBound =
CalculateBoxBound(manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, orientation,
m_cameraCorrectedOffset * viewScale,
m_halfExtents * viewScale);
const Picking::BoundShapeBox boxBound = CalculateBoxBound(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, orientation, m_cameraCorrectedOffset * viewScale,
m_halfExtents * viewScale);
const AZ::Vector3 xAxis = boxBound.m_orientation.TransformVector(AZ::Vector3::CreateAxisX());
const AZ::Vector3 yAxis = boxBound.m_orientation.TransformVector(AZ::Vector3::CreateAxisY());
const AZ::Vector3 zAxis = boxBound.m_orientation.TransformVector(AZ::Vector3::CreateAxisZ());
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4());
debugDisplay.DrawSolidOBB(boxBound.m_center,
xAxis, yAxis, zAxis, boxBound.m_halfExtents);
debugDisplay.DrawSolidOBB(boxBound.m_center, xAxis, yAxis, zAxis, boxBound.m_halfExtents);
RefreshBoundInternal(managerId, manipulatorId, boxBound);
}
void ManipulatorViewCylinder::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const float viewScale = ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const float viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
CameraCorrectAxis(
m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction,
manipulatorState.m_worldFromLocal, manipulatorState.m_localPosition, cameraState);
m_axis, m_cameraCorrectedAxis, managerState, mouseInteraction, manipulatorState.m_worldFromLocal,
manipulatorState.m_localPosition, cameraState);
const Picking::BoundShapeCylinder cylinderBound =
CalculateCylinderBound(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis,
m_length * viewScale,
m_radius * viewScale);
const Picking::BoundShapeCylinder cylinderBound = CalculateCylinderBound(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis, m_length * viewScale,
m_radius * viewScale);
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4());
debugDisplay.DrawSolidCylinder(cylinderBound.m_base + cylinderBound.m_axis * cylinderBound.m_height * 0.5f,
cylinderBound.m_axis, cylinderBound.m_radius, cylinderBound.m_height, false);
debugDisplay.DrawSolidCylinder(
cylinderBound.m_base + cylinderBound.m_axis * cylinderBound.m_height * 0.5f, cylinderBound.m_axis, cylinderBound.m_radius,
cylinderBound.m_height, false);
RefreshBoundInternal(managerId, manipulatorId, cylinderBound);
}
void ManipulatorViewSphere::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const Picking::BoundShapeSphere sphereBound =
CalculateSphereBound(manipulatorState.m_localPosition, manipulatorState,
m_radius * ManipulatorViewScaleMultiplier(
manipulatorState.TransformPoint(manipulatorState.m_localPosition), cameraState));
const Picking::BoundShapeSphere sphereBound = CalculateSphereBound(
manipulatorState.m_localPosition, manipulatorState,
m_radius * ManipulatorViewScaleMultiplier(manipulatorState.TransformPoint(manipulatorState.m_localPosition), cameraState));
if (m_depthTest)
{
@@ -545,31 +568,32 @@ namespace AzToolsFramework
}
void ManipulatorViewCircle::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& /*mouseInteraction*/)
{
const float viewScale = ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const float viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const Picking::BoundShapeTorus torusBound =
CalculateTorusBound(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_axis,
m_radius * viewScale,
m_width * viewScale);
const Picking::BoundShapeTorus torusBound = CalculateTorusBound(
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_axis, m_radius * viewScale, m_width * viewScale);
// transform circle based on delta between default z up axis and other axes
const AZ::Transform worldFromLocalWithOrientation =
AZ::Transform::CreateTranslation(manipulatorState.m_worldFromLocal.GetTranslation()) *
AZ::Transform::CreateFromQuaternion(
(QuaternionFromTransformNoScaling(manipulatorState.m_worldFromLocal) *
AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisZ(), m_axis)).GetNormalized());
AZ::Transform::CreateFromQuaternion((QuaternionFromTransformNoScaling(manipulatorState.m_worldFromLocal) *
AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisZ(), m_axis))
.GetNormalized());
debugDisplay.CullOn();
debugDisplay.PushMatrix(worldFromLocalWithOrientation);
debugDisplay.SetColor(ViewColor(manipulatorState.m_mouseOver, m_color, m_mouseOverColor).GetAsVector4());
m_drawCircleFunc(debugDisplay, manipulatorState.m_localPosition, torusBound.m_majorRadius,
m_drawCircleFunc(
debugDisplay, manipulatorState.m_localPosition, torusBound.m_majorRadius,
worldFromLocalWithOrientation.GetInverse().TransformPoint(cameraState.m_position));
debugDisplay.PopMatrix();
debugDisplay.CullOff();
@@ -578,27 +602,28 @@ namespace AzToolsFramework
}
void DrawHalfDottedCircle(
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position,
const float radius, const AZ::Vector3& viewPos)
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, const float radius, const AZ::Vector3& viewPos)
{
debugDisplay.DrawHalfDottedCircle(position, radius, viewPos);
}
void DrawFullCircle(
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position,
const float radius, const AZ::Vector3& /*viewPos*/)
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, const float radius, const AZ::Vector3& /*viewPos*/)
{
debugDisplay.DrawCircle(position, radius);
debugDisplay.DrawCircle(position, radius);
}
void ManipulatorViewSplineSelect::Draw(
const ManipulatorManagerId managerId, const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
const ManipulatorManagerId managerId,
const ManipulatorManagerState& /*managerState*/,
const ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction)
{
const float viewScale = ManipulatorViewScaleMultiplier(
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const float viewScale =
ManipulatorViewScaleMultiplier(manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
const Picking::BoundShapeSpline splineBound =
CalculateSplineBound(m_spline, manipulatorState.m_worldFromLocal, m_width * viewScale);
@@ -606,16 +631,15 @@ namespace AzToolsFramework
if (manipulatorState.m_mouseOver)
{
const SplineSelectionManipulator::Action action = CalculateManipulationDataAction(
manipulatorState.m_worldFromLocal, mouseInteraction.m_mousePick.m_rayOrigin,
mouseInteraction.m_mousePick.m_rayDirection, m_spline);
manipulatorState.m_worldFromLocal, mouseInteraction.m_mousePick.m_rayOrigin, mouseInteraction.m_mousePick.m_rayDirection,
m_spline);
const AZ::Vector3 worldSplineHitPosition =
manipulatorState.m_worldFromLocal.TransformPoint(action.m_localSplineHitPosition);
const AZ::Vector3 worldSplineHitPosition = manipulatorState.m_worldFromLocal.TransformPoint(action.m_localSplineHitPosition);
debugDisplay.SetColor(m_color.GetAsVector4());
debugDisplay.DrawBall(
worldSplineHitPosition, ManipulatorViewScaleMultiplier(worldSplineHitPosition, cameraState)
* g_defaultManipulatorSphereRadius, false);
worldSplineHitPosition,
ManipulatorViewScaleMultiplier(worldSplineHitPosition, cameraState) * g_defaultManipulatorSphereRadius, false);
}
RefreshBoundInternal(managerId, manipulatorId, splineBound);
@@ -624,8 +648,7 @@ namespace AzToolsFramework
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AZStd::unique_ptr<ManipulatorViewQuad> CreateManipulatorViewQuad(
const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color,
const AZ::Color& axis2Color, const float size)
const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const float size)
{
AZStd::unique_ptr<ManipulatorViewQuad> viewQuad = AZStd::make_unique<ManipulatorViewQuad>();
viewQuad->m_axis1 = planarManipulator.GetAxis1();
@@ -636,8 +659,7 @@ namespace AzToolsFramework
return viewQuad;
}
AZStd::unique_ptr<ManipulatorViewQuadBillboard> CreateManipulatorViewQuadBillboard(
const AZ::Color& color, const float size)
AZStd::unique_ptr<ManipulatorViewQuadBillboard> CreateManipulatorViewQuadBillboard(const AZ::Color& color, const float size)
{
AZStd::unique_ptr<ManipulatorViewQuadBillboard> viewQuad = AZStd::make_unique<ManipulatorViewQuadBillboard>();
viewQuad->m_size = size;
@@ -646,8 +668,7 @@ namespace AzToolsFramework
}
AZStd::unique_ptr<ManipulatorViewLine> CreateManipulatorViewLine(
const LinearManipulator& linearManipulator, const AZ::Color& color,
const float length, const float width)
const LinearManipulator& linearManipulator, const AZ::Color& color, const float length, const float width)
{
AZStd::unique_ptr<ManipulatorViewLine> viewLine = AZStd::make_unique<ManipulatorViewLine>();
viewLine->m_axis = linearManipulator.GetAxis();
@@ -658,8 +679,7 @@ namespace AzToolsFramework
}
AZStd::unique_ptr<ManipulatorViewLineSelect> CreateManipulatorViewLineSelect(
const LineSegmentSelectionManipulator& lineSegmentManipulator,
const AZ::Color& color, const float width)
const LineSegmentSelectionManipulator& lineSegmentManipulator, const AZ::Color& color, const float width)
{
AZStd::unique_ptr<ManipulatorViewLineSelect> viewLineSelect = AZStd::make_unique<ManipulatorViewLineSelect>();
viewLineSelect->m_localStart = lineSegmentManipulator.GetStart();
@@ -670,8 +690,11 @@ namespace AzToolsFramework
}
AZStd::unique_ptr<ManipulatorViewCone> CreateManipulatorViewCone(
const LinearManipulator& linearManipulator, const AZ::Color& color,
const AZ::Vector3& offset, const float length, const float radius)
const LinearManipulator& linearManipulator,
const AZ::Color& color,
const AZ::Vector3& offset,
const float length,
const float radius)
{
AZStd::unique_ptr<ManipulatorViewCone> viewCone = AZStd::make_unique<ManipulatorViewCone>();
viewCone->m_axis = linearManipulator.GetAxis();
@@ -683,8 +706,7 @@ namespace AzToolsFramework
}
AZStd::unique_ptr<ManipulatorViewBox> CreateManipulatorViewBox(
const AZ::Transform& transform, const AZ::Color& color,
const AZ::Vector3& offset, const AZ::Vector3& halfExtents)
const AZ::Transform& transform, const AZ::Color& color, const AZ::Vector3& offset, const AZ::Vector3& halfExtents)
{
AZStd::unique_ptr<ManipulatorViewBox> viewBox = AZStd::make_unique<ManipulatorViewBox>();
viewBox->m_orientation = transform.GetRotation();
@@ -695,8 +717,7 @@ namespace AzToolsFramework
}
AZStd::unique_ptr<ManipulatorViewCylinder> CreateManipulatorViewCylinder(
const LinearManipulator& linearManipulator, const AZ::Color& color,
const float length, const float radius)
const LinearManipulator& linearManipulator, const AZ::Color& color, const float length, const float radius)
{
AZStd::unique_ptr<ManipulatorViewCylinder> viewCylinder = AZStd::make_unique<ManipulatorViewCylinder>();
viewCylinder->m_axis = linearManipulator.GetAxis();
@@ -718,8 +739,11 @@ namespace AzToolsFramework
}
AZStd::unique_ptr<ManipulatorViewCircle> CreateManipulatorViewCircle(
const AngularManipulator& angularManipulator, const AZ::Color& color,
const float radius, const float width, const ManipulatorViewCircle::DrawCircleFunc drawFunc)
const AngularManipulator& angularManipulator,
const AZ::Color& color,
const float radius,
const float width,
const ManipulatorViewCircle::DrawCircleFunc drawFunc)
{
AZStd::unique_ptr<ManipulatorViewCircle> viewCircle = AZStd::make_unique<ManipulatorViewCircle>();
viewCircle->m_axis = angularManipulator.GetAxis();
@@ -731,8 +755,7 @@ namespace AzToolsFramework
}
AZStd::unique_ptr<ManipulatorViewSplineSelect> CreateManipulatorViewSplineSelect(
const SplineSelectionManipulator& splineManipulator,
const AZ::Color& color, const float width)
const SplineSelectionManipulator& splineManipulator, const AZ::Color& color, const float width)
{
AZStd::unique_ptr<ManipulatorViewSplineSelect> viewSplineSelect = AZStd::make_unique<ManipulatorViewSplineSelect>();
viewSplineSelect->m_spline = splineManipulator.GetSpline();
@@ -741,16 +764,12 @@ namespace AzToolsFramework
return viewSplineSelect;
}
AZ::Vector3 CalculateViewDirection(
const Manipulators& manipulators, const AZ::Vector3& worldViewPosition)
AZ::Vector3 CalculateViewDirection(const Manipulators& manipulators, const AZ::Vector3& worldViewPosition)
{
const AZ::Transform worldFromLocalWithTransform =
manipulators.GetSpace() * manipulators.GetLocalTransform();
const AZ::Transform worldFromLocalWithTransform = manipulators.GetSpace() * manipulators.GetLocalTransform();
AZ::Vector3 lookDirection =
(worldFromLocalWithTransform.GetTranslation() - worldViewPosition).GetNormalized();
AZ::Vector3 lookDirection = (worldFromLocalWithTransform.GetTranslation() - worldViewPosition).GetNormalized();
return TransformDirectionNoScaling(
worldFromLocalWithTransform.GetInverse(), lookDirection);
return TransformDirectionNoScaling(worldFromLocalWithTransform.GetInverse(), lookDirection);
}
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -26,13 +26,12 @@ namespace AzToolsFramework
class LineSegmentSelectionManipulator;
class SplineSelectionManipulator;
using DecideColorFn = AZStd::function<AZ::Color(
const ViewportInteraction::MouseInteraction&,
bool mouseOver, const AZ::Color& defaultColor)>;
using DecideColorFn =
AZStd::function<AZ::Color(const ViewportInteraction::MouseInteraction&, bool mouseOver, const AZ::Color& defaultColor)>;
extern const float g_defaultManipulatorSphereRadius;
/// State of an individual manipulator.
//! State of an individual manipulator.
struct ManipulatorState
{
AZ::Transform m_worldFromLocal;
@@ -40,18 +39,18 @@ namespace AzToolsFramework
AZ::Vector3 m_localPosition;
bool m_mouseOver;
/// Transforms a point, taking non-uniform scale into account.
//! Transforms a point, taking non-uniform scale into account.
AZ::Vector3 TransformPoint(const AZ::Vector3& point) const;
/// Rotates a direction into the space of the manipulator and normalizes it.
/// Non-uniform scaling and translation are not applied.
//! Rotates a direction into the space of the manipulator and normalizes it.
//! Non-uniform scaling and translation are not applied.
AZ::Vector3 TransformDirectionNoScaling(const AZ::Vector3& direction) const;
};
/// The base interface for the visual representation of manipulators.
/// The View represents the appearance and bounds of the manipulator for
/// the user to interact with. Any manipulator can have any view (some may
/// be more appropriate than others in certain cases).
//! The base interface for the visual representation of manipulators.
//! The View represents the appearance and bounds of the manipulator for
//! the user to interact with. Any manipulator can have any view (some may
//! be more appropriate than others in certain cases).
class ManipulatorView
{
public:
@@ -65,98 +64,107 @@ namespace AzToolsFramework
ManipulatorView& operator=(ManipulatorView&&) = default;
void SetBoundDirty(ManipulatorManagerId managerId);
void RefreshBound(
ManipulatorManagerId managerId, ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound);
void RefreshBound(ManipulatorManagerId managerId, ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound);
void Invalidate(ManipulatorManagerId managerId);
virtual void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) = 0;
bool ScreenSizeFixed() const { return m_screenSizeFixed; }
bool ScreenSizeFixed() const
{
return m_screenSizeFixed;
}
protected:
AZ::Color m_mouseOverColor = BaseManipulator::s_defaultMouseOverColor; ///< What color should the manipulator
///< be when the mouse is hovering over it.
/// Scale the manipulator based on the distance
/// from the camera if m_screenSizeFixed is true.
float ManipulatorViewScaleMultiplier(
const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) const;
AZ::Color m_mouseOverColor = BaseManipulator::s_defaultMouseOverColor; //!< What color should the manipulator
//!< be when the mouse is hovering over it.
//! Scale the manipulator based on the distance
//! from the camera if m_screenSizeFixed is true.
float ManipulatorViewScaleMultiplier(const AZ::Vector3& worldPosition, const AzFramework::CameraState& cameraState) const;
/// Wrap the logic for updating a bound.
/// Should be called at the end of the Draw function once a concrete BoundRequestShape has
/// been created to use for dimensions for rendering.
void RefreshBoundInternal(
ManipulatorManagerId managerId, ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound);
//! Wrap the logic for updating a bound.
//! Should be called at the end of the Draw function once a concrete BoundRequestShape has
//! been created to use for dimensions for rendering.
void RefreshBoundInternal(ManipulatorManagerId managerId, ManipulatorId manipulatorId, const Picking::BoundRequestShapeBase& bound);
private:
Picking::RegisteredBoundId m_boundId = Picking::InvalidBoundId; ///< Used for hit detection.
ManipulatorManagerId m_managerId = InvalidManipulatorManagerId; /// The manipulator manager this view has been registered with.
bool m_screenSizeFixed = true; ///< Should manipulator size be adjusted based on camera distance.
bool m_boundDirty = true; ///< Do the bounds need to be recalculated.
Picking::RegisteredBoundId m_boundId = Picking::InvalidBoundId; //!< Used for hit detection.
ManipulatorManagerId m_managerId = InvalidManipulatorManagerId; //! The manipulator manager this view has been registered with.
bool m_screenSizeFixed = true; //!< Should manipulator size be adjusted based on camera distance.
bool m_boundDirty = true; //!< Do the bounds need to be recalculated.
};
// A collection of views (a manipulator may have 1 - * views)
using ManipulatorViews = AZStd::vector<AZStd::shared_ptr<ManipulatorView>>;
/// Display a quad representing part of a plane, rendered as 4 lines.
class ManipulatorViewQuad
: public ManipulatorView
//! Display a quad representing part of a plane, rendered as 4 lines.
class ManipulatorViewQuad : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewQuad, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewQuad, "{D85E1B45-495E-4755-BCF2-6AE45F8BB2B0}", ManipulatorView)
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
AZ::Vector3 m_axis1 = AZ::Vector3(1.0f, 0.0f, 0.0f);
AZ::Vector3 m_axis2 = AZ::Vector3(0.0f, 1.0f, 0.0f);
AZ::Color m_axis1Color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
AZ::Color m_axis2Color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
float m_size = 0.06f; ///< size to render and do mouse ray intersection tests against.
float m_size = 0.06f; //!< size to render and do mouse ray intersection tests against.
private:
AZ::Vector3 m_cameraCorrectedAxis1;
AZ::Vector3 m_cameraCorrectedAxis2;
};
/// A screen aligned quad, centered at the position of the manipulator, display filled.
class ManipulatorViewQuadBillboard
: public ManipulatorView
//! A screen aligned quad, centered at the position of the manipulator, display filled.
class ManipulatorViewQuadBillboard : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewQuadBillboard, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewQuadBillboard, "{C205E967-E8C6-4A73-A31B-41EE5529B15B}", ManipulatorView)
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
AZ::Color m_color = AZ::Color(1.0f, 0.0f, 0.0f, 1.0f);
float m_size = 0.005f; ///< size to render and do mouse ray intersection tests against.
float m_size = 0.005f; //!< size to render and do mouse ray intersection tests against.
};
/// Displays a debug style line starting from the manipulator's transform,
/// width determines the click area.
class ManipulatorViewLine
: public ManipulatorView
//! Displays a debug style line starting from the manipulator's transform,
//! width determines the click area.
class ManipulatorViewLine : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewLine, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewLine, "{831EEF66-4A5C-450C-B152-EA4A0BC8A272}", ManipulatorView)
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
AZ::Vector3 m_axis;
@@ -168,19 +176,21 @@ namespace AzToolsFramework
AZ::Vector3 m_cameraCorrectedAxis;
};
/// Variant of ManipulatorViewLine which instead of using an axis, provides begin and end
/// points for the line. Used for selection when inserting points along a line.
class ManipulatorViewLineSelect
: public ManipulatorView
//! Variant of ManipulatorViewLine which instead of using an axis, provides begin and end
//! points for the line. Used for selection when inserting points along a line.
class ManipulatorViewLineSelect : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewLineSelect, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewLineSelect, "{BF26A947-91F8-4595-9A5B-481876EB2C48}", ManipulatorView)
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
AZ::Vector3 m_localStart;
@@ -189,20 +199,22 @@ namespace AzToolsFramework
float m_width = 0.0f;
};
/// Displays a filled cone along the specified axis, offset is local translation from
/// the manipulator transform (often used in conjunction with other views to build
/// aggregate views such as arrows - e.g. a line and cone).
class ManipulatorViewCone
: public ManipulatorView
//! Displays a filled cone along the specified axis, offset is local translation from
//! the manipulator transform (often used in conjunction with other views to build
//! aggregate views such as arrows - e.g. a line and cone).
class ManipulatorViewCone : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewCone, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewCone, "{BF042887-1F51-4FD8-8CA5-4A649B4AF356}", ManipulatorView)
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
AZ::Vector3 m_offset;
@@ -217,20 +229,22 @@ namespace AzToolsFramework
bool m_shouldCorrect = false;
};
/// Displays a filled box, offset is local translation from the manipulator
/// transform, box is often used in conjunction with other views, orientation allows
/// the box to be orientated separately from the manipulator transform.
class ManipulatorViewBox
: public ManipulatorView
//! Displays a filled box, offset is local translation from the manipulator
//! transform, box is often used in conjunction with other views, orientation allows
//! the box to be orientated separately from the manipulator transform.
class ManipulatorViewBox : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewBox, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewBox, "{2D082201-7878-4C1B-A3DD-7A629E5AD598}", ManipulatorView)
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
AZ::Vector3 m_offset;
@@ -242,18 +256,20 @@ namespace AzToolsFramework
AZ::Vector3 m_cameraCorrectedOffset;
};
/// Displays a filled cylinder along the axis provided.
class ManipulatorViewCylinder
: public ManipulatorView
//! Displays a filled cylinder along the axis provided.
class ManipulatorViewCylinder : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewCylinder, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewCylinder, "{9B8E5EF4-0F85-4CD0-A5FF-3C7097DF58AC}", ManipulatorView)
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
AZ::Vector3 m_axis;
@@ -265,20 +281,22 @@ namespace AzToolsFramework
AZ::Vector3 m_cameraCorrectedAxis;
};
/// Displays a filled sphere at the transform of the manipulator, often used as
/// a selection manipulator. DecideColorFn allows more complex logic to be used
/// to decide the color of the manipulator (based on hover state etc.)
class ManipulatorViewSphere
: public ManipulatorView
//! Displays a filled sphere at the transform of the manipulator, often used as
//! a selection manipulator. DecideColorFn allows more complex logic to be used
//! to decide the color of the manipulator (based on hover state etc.)
class ManipulatorViewSphere : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewSphere, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewSphere, "{324D8329-6E7B-4A5D-AC8A-8C0E1C984E38}", ManipulatorView)
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
float m_radius = 0.0f;
@@ -287,23 +305,24 @@ namespace AzToolsFramework
bool m_depthTest = false;
};
/// Displays a wire circle. DrawCircleFunc can be used to either draw a full
/// circle or a half dotted circle where the part of the circle facing away
/// from the camera is dotted (useful for angular/rotation manipulators).
class ManipulatorViewCircle
: public ManipulatorView
//! Displays a wire circle. DrawCircleFunc can be used to either draw a full
//! circle or a half dotted circle where the part of the circle facing away
//! from the camera is dotted (useful for angular/rotation manipulators).
class ManipulatorViewCircle : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewCircle, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewCircle, "{26563A03-3E48-49EB-9DCF-30EE4F567FCD}", ManipulatorView)
using DrawCircleFunc =
void(*)(AzFramework::DebugDisplayRequests&, const AZ::Vector3&, float, const AZ::Vector3&);
using DrawCircleFunc = void (*)(AzFramework::DebugDisplayRequests&, const AZ::Vector3&, float, const AZ::Vector3&);
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
AZ::Vector3 m_axis;
@@ -316,26 +335,26 @@ namespace AzToolsFramework
// helpers to provide consistent function pointer interface for deciding
// on type of circle to draw (see DrawCircleFunc in ManipulatorViewCircle above)
void DrawHalfDottedCircle(
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position,
float radius, const AZ::Vector3& viewPos);
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, float radius, const AZ::Vector3& viewPos);
void DrawFullCircle(
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position,
float radius, const AZ::Vector3& viewPos);
AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Vector3& position, float radius, const AZ::Vector3& viewPos);
/// Used for interaction with spline primitive - it will generate a spline bound
/// to be interacted with and will display the intersection point on the spline
/// where a user may wish to insert a point.
class ManipulatorViewSplineSelect
: public ManipulatorView
//! Used for interaction with spline primitive - it will generate a spline bound
//! to be interacted with and will display the intersection point on the spline
//! where a user may wish to insert a point.
class ManipulatorViewSplineSelect : public ManipulatorView
{
public:
AZ_CLASS_ALLOCATOR(ManipulatorViewSplineSelect, AZ::SystemAllocator, 0)
AZ_RTTI(ManipulatorViewSplineSelect, "{60996E49-D6BF-4817-BAA3-D27A407DD21A}", ManipulatorView)
void Draw(
ManipulatorManagerId managerId, const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId, const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay, const AzFramework::CameraState& cameraState,
ManipulatorManagerId managerId,
const ManipulatorManagerState& managerState,
ManipulatorId manipulatorId,
const ManipulatorState& manipulatorState,
AzFramework::DebugDisplayRequests& debugDisplay,
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
AZStd::weak_ptr<const AZ::Spline> m_spline;
@@ -343,65 +362,61 @@ namespace AzToolsFramework
AZ::Color m_color = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
};
/// Returns true if axis is pointing away from us (we should flip it).
//! Returns true if axis is pointing away from us (we should flip it).
inline bool ShouldFlipCameraAxis(
const AZ::Transform& worldFromLocal, const AZ::Vector3& localPosition,
const AZ::Vector3& axis, const AzFramework::CameraState& cameraState)
const AZ::Transform& worldFromLocal,
const AZ::Vector3& localPosition,
const AZ::Vector3& axis,
const AzFramework::CameraState& cameraState)
{
return (worldFromLocal.TransformPoint(localPosition) - cameraState.m_position).Dot(
TransformDirectionNoScaling(worldFromLocal, axis)) > 0.0f;
return (worldFromLocal.TransformPoint(localPosition) - cameraState.m_position)
.Dot(TransformDirectionNoScaling(worldFromLocal, axis)) > 0.0f;
}
/// @brief Return the world transform of the entity with uniform scale - choose
/// the largest element.
//! @brief Return the world transform of the entity with uniform scale - choose
//! the largest element.
AZ::Transform WorldFromLocalWithUniformScale(AZ::EntityId entityId);
/// Get the non-uniform scale for this entity id.
//! Get the non-uniform scale for this entity id.
AZ::Vector3 GetNonUniformScale(AZ::EntityId entityId);
// Helpers to create various manipulator views.
AZStd::unique_ptr<ManipulatorViewQuad> CreateManipulatorViewQuad(
const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color,
const AZ::Color& axis2Color, float size);
const PlanarManipulator& planarManipulator, const AZ::Color& axis1Color, const AZ::Color& axis2Color, float size);
AZStd::unique_ptr<ManipulatorViewQuadBillboard> CreateManipulatorViewQuadBillboard(
const AZ::Color& color, float size);
AZStd::unique_ptr<ManipulatorViewQuadBillboard> CreateManipulatorViewQuadBillboard(const AZ::Color& color, float size);
AZStd::unique_ptr<ManipulatorViewLine> CreateManipulatorViewLine(
const LinearManipulator& linearManipulator, const AZ::Color& color,
float length, float width);
const LinearManipulator& linearManipulator, const AZ::Color& color, float length, float width);
AZStd::unique_ptr<ManipulatorViewLineSelect> CreateManipulatorViewLineSelect(
const LineSegmentSelectionManipulator& lineSegmentManipulator, const AZ::Color& color,
float width);
const LineSegmentSelectionManipulator& lineSegmentManipulator, const AZ::Color& color, float width);
AZStd::unique_ptr<ManipulatorViewCone> CreateManipulatorViewCone(
const LinearManipulator& linearManipulator, const AZ::Color& color,
const AZ::Vector3& offset, float length, float radius);
const LinearManipulator& linearManipulator, const AZ::Color& color, const AZ::Vector3& offset, float length, float radius);
AZStd::unique_ptr<ManipulatorViewBox> CreateManipulatorViewBox(
const AZ::Transform& transform, const AZ::Color& color,
const AZ::Vector3& offset, const AZ::Vector3& halfExtents);
const AZ::Transform& transform, const AZ::Color& color, const AZ::Vector3& offset, const AZ::Vector3& halfExtents);
AZStd::unique_ptr<ManipulatorViewCylinder> CreateManipulatorViewCylinder(
const LinearManipulator& linearManipulator, const AZ::Color& color,
float length, float radius);
const LinearManipulator& linearManipulator, const AZ::Color& color, float length, float radius);
AZStd::unique_ptr<ManipulatorViewSphere> CreateManipulatorViewSphere(
const AZ::Color& color, float radius, const DecideColorFn& decideColor, bool enableDepthTest = false);
AZStd::unique_ptr<ManipulatorViewCircle> CreateManipulatorViewCircle(
const AngularManipulator& angularManipulator, const AZ::Color& color,
float radius, float width, ManipulatorViewCircle::DrawCircleFunc drawFunc);
const AngularManipulator& angularManipulator,
const AZ::Color& color,
float radius,
float width,
ManipulatorViewCircle::DrawCircleFunc drawFunc);
AZStd::unique_ptr<ManipulatorViewSplineSelect> CreateManipulatorViewSplineSelect(
const SplineSelectionManipulator& splineManipulator, const AZ::Color& color,
float width);
const SplineSelectionManipulator& splineManipulator, const AZ::Color& color, float width);
/// Returns the vector between the view (camera) and the manipulator in the space
/// of the Manipulator (manipulator space + local transform).
AZ::Vector3 CalculateViewDirection(
const Manipulators& manipulators, const AZ::Vector3& worldViewPosition);
//! Returns the vector between the view (camera) and the manipulator in the space
//! of the Manipulator (manipulator space + local transform).
AZ::Vector3 CalculateViewDirection(const Manipulators& manipulators, const AZ::Vector3& worldViewPosition);
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "MultiLinearManipulator.h"
@@ -56,20 +56,22 @@ namespace AzToolsFramework
}
static MultiLinearManipulator::Action BuildMultiLinearManipulatorAction(
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
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 +81,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 +88,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));
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, m_fixedAxes, m_starters,
gridSnapParams));
}
}
@@ -111,11 +110,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));
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, m_fixedAxes, m_starters,
gridSnapParams));
}
}
@@ -125,11 +122,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));
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(), interaction, m_fixedAxes, m_starters,
gridSnapParams));
m_starters.clear();
}
@@ -146,36 +141,31 @@ namespace AzToolsFramework
const AZ::Transform combined = TransformUniformScale(GetSpace()) * GetLocalTransform();
for (const auto& fixed : m_fixedAxes)
{
DrawAxis(
debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(combined, fixed.m_axis));
DrawAxis(debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(combined, fixed.m_axis));
}
}
for (auto& view : m_manipulatorViews)
{
view->Draw(
GetManipulatorManagerId(), managerState,
GetManipulatorId(), {
ApplySpace(GetLocalTransform()), GetNonUniformScale(),
AZ::Vector3::CreateZero(), MouseOver()
},
debugDisplay, cameraState, mouseInteraction);
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
}
}
void MultiLinearManipulator::AddAxis(const AZ::Vector3& axis)
{
m_fixedAxes.push_back(LinearManipulator::Fixed{axis});
m_fixedAxes.push_back(LinearManipulator::Fixed{ axis });
}
void MultiLinearManipulator::AddAxes(const AZStd::vector<AZ::Vector3>& axes)
{
AZStd::transform(
axes.begin(), axes.end(),
AZStd::back_inserter(m_fixedAxes),
axes.begin(), axes.end(), AZStd::back_inserter(m_fixedAxes),
[](const AZ::Vector3& axis)
{
return LinearManipulator::Fixed{axis};
return LinearManipulator::Fixed{ axis };
});
}
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -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
@@ -82,12 +80,9 @@ namespace AzToolsFramework
}
private:
void OnLeftMouseDownImpl(
const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(
const ViewportInteraction::MouseInteraction& interaction) override;
void OnMouseMoveImpl(
const ViewportInteraction::MouseInteraction& interaction) override;
void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void InvalidateImpl() override;
void SetBoundsDirtyImpl() override;
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "PlanarManipulator.h"
@@ -22,17 +22,17 @@
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 ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance)
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 =
BuildManipulatorInteraction(
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction(
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 =
@@ -40,33 +40,25 @@ namespace AzToolsFramework
StartInternal startInternal;
Internal::CalculateRayPlaneIntersectingPoint(
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection,
localIntersectionPoint, normal, startInternal.m_localHitPosition);
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 =
BuildManipulatorInteraction(
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
const ManipulatorInteraction manipulatorInteraction = BuildManipulatorInteraction(
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
const AZ::Vector3 normal = TransformDirectionNoScaling(localTransform, fixed.m_normal);
@@ -75,8 +67,8 @@ namespace AzToolsFramework
// if an invalid ray intersection is attempted
AZ::Vector3 localHitPosition = startInternal.m_localHitPosition;
Internal::CalculateRayPlaneIntersectingPoint(
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection,
startInternal.m_localHitPosition, normal, localHitPosition);
manipulatorInteraction.m_localRayOrigin, manipulatorInteraction.m_localRayDirection, startInternal.m_localHitPosition, normal,
localHitPosition);
localHitPosition = Internal::TryConstrainHitPositionToView(
localHitPosition, startInternal.m_localHitPosition, worldFromLocal.GetInverse(),
@@ -88,20 +80,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 +131,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);
m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()), 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 +153,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 +165,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,14 +182,14 @@ 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(
debugDisplay, TransformUniformScale(GetSpace()) *
AZ::Transform::CreateTranslation(
action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localOffset));
debugDisplay,
TransformUniformScale(GetSpace()) *
AZ::Transform::CreateTranslation(
action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localOffset));
}
AZ::Transform combined = GetLocalTransform();
@@ -211,23 +198,16 @@ namespace AzToolsFramework
DrawTransformAxes(debugDisplay, combined);
DrawAxis(
debugDisplay, combined.GetTranslation(),
TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis1));
DrawAxis(
debugDisplay, combined.GetTranslation(),
TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis2));
DrawAxis(debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis1));
DrawAxis(debugDisplay, combined.GetTranslation(), TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis2));
}
for (auto& view : m_manipulatorViews)
{
view->Draw(
GetManipulatorManagerId(), managerState,
GetManipulatorId(), {
ApplySpace(GetLocalTransform()), GetNonUniformScale(),
AZ::Vector3::CreateZero(), MouseOver()
},
debugDisplay, cameraState, mouseInteraction);
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ ApplySpace(GetLocalTransform()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
}
}
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -21,15 +21,15 @@
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.
//! 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.
class PlanarManipulator
: public BaseManipulator
, public ManipulatorSpaceWithLocalTransform
{
/// Private constructor.
//! Private constructor.
explicit PlanarManipulator(const AZ::Transform& worldFromLocal);
public:
@@ -42,44 +42,51 @@ namespace AzToolsFramework
~PlanarManipulator() = default;
/// A Manipulator must only be created and managed through a shared_ptr.
//! A Manipulator must only be created and managed through a shared_ptr.
static AZStd::shared_ptr<PlanarManipulator> MakeShared(const AZ::Transform& worldFromLocal);
/// Unchanging data set once for the planar manipulator.
//! Unchanging data set once for the planar manipulator.
struct Fixed
{
AZ::Vector3 m_axis1 = AZ::Vector3::CreateAxisX(); ///< m_axis1 and m_axis2 have to be orthogonal, they together define a plane in 3d space.
AZ::Vector3 m_axis1 =
AZ::Vector3::CreateAxisX(); //!< m_axis1 and m_axis2 have to be orthogonal, they together define a plane in 3d space.
AZ::Vector3 m_axis2 = AZ::Vector3::CreateAxisY();
AZ::Vector3 m_normal = AZ::Vector3::CreateAxisZ(); ///< m_normal is calculated automatically when setting the axes.
AZ::Vector3 m_normal = AZ::Vector3::CreateAxisZ(); //!< m_normal is calculated automatically when setting the axes.
};
/// The state of the manipulator at the start of an interaction.
//! The state of the manipulator at the start of an interaction.
struct Start
{
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.
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.
};
/// The state of the manipulator during an interaction.
//! The state of the manipulator during an interaction.
struct Current
{
AZ::Vector3 m_localOffset; ///< The current position of the manipulator in local space.
AZ::Vector3 m_localOffset; //!< The current position of the manipulator in local space.
};
/// Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state).
//! Mouse action data used by MouseActionCallback (wraps Start and Current manipulator state).
struct Action
{
Fixed m_fixed;
Start m_start;
Current m_current;
ViewportInteraction::KeyboardModifiers m_modifiers;
AZ::Vector3 LocalPosition() const { return m_start.m_localPosition + m_current.m_localOffset; }
AZ::Vector3 LocalPositionOffset() const { return m_current.m_localOffset; }
AZ::Vector3 LocalPosition() const
{
return m_start.m_localPosition + m_current.m_localOffset;
}
AZ::Vector3 LocalPositionOffset() const
{
return m_current.m_localOffset;
}
};
/// This is the function signature of callbacks that will be invoked whenever a manipulator
/// is being clicked on or dragged.
//! This is the function signature of callbacks that will be invoked whenever a manipulator
//! is being clicked on or dragged.
using MouseActionCallback = AZStd::function<void(const Action&)>;
void InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback);
@@ -92,11 +99,17 @@ namespace AzToolsFramework
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
/// Ensure @param axis1 and @param axis2 are not collinear.
//! Ensure @param axis1 and @param axis2 are not collinear.
void SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2);
const AZ::Vector3& GetAxis1() const { return m_fixed.m_axis1; }
const AZ::Vector3& GetAxis2() const { return m_fixed.m_axis2; }
const AZ::Vector3& GetAxis1() const
{
return m_fixed.m_axis1;
}
const AZ::Vector3& GetAxis2() const
{
return m_fixed.m_axis2;
}
template<typename Views>
void SetViews(Views&& views)
@@ -105,22 +118,19 @@ namespace AzToolsFramework
}
private:
void OnLeftMouseDownImpl(
const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(
const ViewportInteraction::MouseInteraction& interaction) override;
void OnMouseMoveImpl(
const ViewportInteraction::MouseInteraction& interaction) override;
void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void OnMouseMoveImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void InvalidateImpl() override;
void SetBoundsDirtyImpl() override;
/// Initial data recorded when a press first happens with a planar manipulator.
//! Initial data recorded when a press first happens with a planar manipulator.
struct StartInternal
{
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.
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.
};
Fixed m_fixed;
@@ -130,16 +140,23 @@ namespace AzToolsFramework
MouseActionCallback m_onLeftMouseUpCallback = nullptr;
MouseActionCallback m_onMouseMoveCallback = nullptr;
ManipulatorViews m_manipulatorViews; ///< Look of manipulator.
ManipulatorViews m_manipulatorViews; //!< Look of manipulator.
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 Fixed& fixed,
const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale,
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
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "RotationManipulators.h"
@@ -28,8 +28,7 @@ namespace AzToolsFramework
m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal);
}
void RotationManipulators::InstallLeftMouseDownCallback(
const AngularManipulator::MouseActionCallback& onMouseDownCallback)
void RotationManipulators::InstallLeftMouseDownCallback(const AngularManipulator::MouseActionCallback& onMouseDownCallback)
{
for (AZStd::shared_ptr<AngularManipulator>& manipulator : m_localAngularManipulators)
{
@@ -39,8 +38,7 @@ namespace AzToolsFramework
m_viewAngularManipulator->InstallLeftMouseDownCallback(onMouseDownCallback);
}
void RotationManipulators::InstallMouseMoveCallback(
const AngularManipulator::MouseActionCallback& onMouseMoveCallback)
void RotationManipulators::InstallMouseMoveCallback(const AngularManipulator::MouseActionCallback& onMouseMoveCallback)
{
for (AZStd::shared_ptr<AngularManipulator>& manipulator : m_localAngularManipulators)
{
@@ -50,8 +48,7 @@ namespace AzToolsFramework
m_viewAngularManipulator->InstallMouseMoveCallback(onMouseMoveCallback);
}
void RotationManipulators::InstallLeftMouseUpCallback(
const AngularManipulator::MouseActionCallback& onMouseUpCallback)
void RotationManipulators::InstallLeftMouseUpCallback(const AngularManipulator::MouseActionCallback& onMouseUpCallback)
{
for (AZStd::shared_ptr<AngularManipulator>& manipulator : m_localAngularManipulators)
{
@@ -109,14 +106,13 @@ namespace AzToolsFramework
m_viewAngularManipulator->SetSpace(worldFromLocal);
}
void RotationManipulators::SetLocalAxes(
const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3)
void RotationManipulators::SetLocalAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3)
{
const AZ::Vector3 axes[] = { axis1, axis2, axis3 };
for (size_t manipulatorIndex = 0; manipulatorIndex < m_localAngularManipulators.size(); ++manipulatorIndex)
{
m_localAngularManipulators[manipulatorIndex]->SetAxis(axes[manipulatorIndex]);
m_localAngularManipulators[manipulatorIndex]->SetAxis(axes[manipulatorIndex]);
}
}
@@ -124,34 +120,25 @@ namespace AzToolsFramework
{
m_viewAngularManipulator->SetAxis(axis);
if (auto circleView = azrtti_cast<ManipulatorViewCircle*>(
m_viewAngularManipulator->GetView()))
if (auto circleView = azrtti_cast<ManipulatorViewCircle*>(m_viewAngularManipulator->GetView()))
{
circleView->m_axis = axis;
}
}
void RotationManipulators::ConfigureView(
const float radius, const AZ::Color& axis1Color,
const AZ::Color& axis2Color, const AZ::Color& axis3Color)
const float radius, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color)
{
const AZ::Color colors[] = {
axis1Color, axis2Color, axis3Color
};
const AZ::Color colors[] = { axis1Color, axis2Color, axis3Color };
for (size_t manipulatorIndex = 0; manipulatorIndex < m_localAngularManipulators.size(); ++manipulatorIndex)
{
m_localAngularManipulators[manipulatorIndex]->SetView(
CreateManipulatorViewCircle(
*m_localAngularManipulators[manipulatorIndex], colors[manipulatorIndex],
radius, 0.05f, DrawHalfDottedCircle));
m_localAngularManipulators[manipulatorIndex]->SetView(CreateManipulatorViewCircle(
*m_localAngularManipulators[manipulatorIndex], colors[manipulatorIndex], radius, 0.05f, DrawHalfDottedCircle));
}
m_viewAngularManipulator->SetView(
CreateManipulatorViewCircle(
*m_viewAngularManipulator,
AZ::Color(1.0f, 1.0f, 1.0f, 1.0f),
radius + (radius * 0.12f), 0.05f, DrawFullCircle));
m_viewAngularManipulator->SetView(CreateManipulatorViewCircle(
*m_viewAngularManipulator, AZ::Color(1.0f, 1.0f, 1.0f, 1.0f), radius + (radius * 0.12f), 0.05f, DrawFullCircle));
}
bool RotationManipulators::PerformingActionViewAxis() const
@@ -1,27 +1,26 @@
/*
* 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.
*
*/
* 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/Memory/SystemAllocator.h>
#include <AzToolsFramework/Manipulators/AngularManipulator.h>
#include <AzToolsFramework/API/EditorCameraBus.h>
#include <AzToolsFramework/Manipulators/AngularManipulator.h>
namespace AzToolsFramework
{
/// RotationManipulators is an aggregation of 3 angular manipulators who share the same origin
/// in addition to a view aligned angular manipulator (facing the camera).
class RotationManipulators
: public Manipulators
//! RotationManipulators is an aggregation of 3 angular manipulators who share the same origin
//! in addition to a view aligned angular manipulator (facing the camera).
class RotationManipulators : public Manipulators
{
public:
AZ_RTTI(RotationManipulators, "{5D1F1D47-1D5B-4E42-B47E-23F108F8BF7D}")
@@ -40,12 +39,10 @@ namespace AzToolsFramework
void SetLocalOrientationImpl(const AZ::Quaternion& localOrientation) override;
void RefreshView(const AZ::Vector3& worldViewPosition) override;
void SetLocalAxes(
const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3);
void SetLocalAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3);
void SetViewAxis(const AZ::Vector3& axis);
void ConfigureView(
float radius, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color);
void ConfigureView(float radius, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color);
bool PerformingActionViewAxis() const;
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "ScaleManipulators.h"
@@ -28,8 +28,7 @@ namespace AzToolsFramework
m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal);
}
void ScaleManipulators::InstallAxisLeftMouseDownCallback(
const LinearManipulator::MouseActionCallback& onMouseDownCallback)
void ScaleManipulators::InstallAxisLeftMouseDownCallback(const LinearManipulator::MouseActionCallback& onMouseDownCallback)
{
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_axisScaleManipulators)
{
@@ -37,8 +36,7 @@ namespace AzToolsFramework
}
}
void ScaleManipulators::InstallAxisMouseMoveCallback(
const LinearManipulator::MouseActionCallback& onMouseMoveCallback)
void ScaleManipulators::InstallAxisMouseMoveCallback(const LinearManipulator::MouseActionCallback& onMouseMoveCallback)
{
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_axisScaleManipulators)
{
@@ -46,8 +44,7 @@ namespace AzToolsFramework
}
}
void ScaleManipulators::InstallAxisLeftMouseUpCallback(
const LinearManipulator::MouseActionCallback& onMouseUpCallback)
void ScaleManipulators::InstallAxisLeftMouseUpCallback(const LinearManipulator::MouseActionCallback& onMouseUpCallback)
{
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_axisScaleManipulators)
{
@@ -55,22 +52,19 @@ namespace AzToolsFramework
}
}
void ScaleManipulators::InstallUniformLeftMouseDownCallback(
const LinearManipulator::MouseActionCallback& onMouseDownCallback)
void ScaleManipulators::InstallUniformLeftMouseDownCallback(const LinearManipulator::MouseActionCallback& onMouseDownCallback)
{
m_uniformScaleManipulator->InstallLeftMouseDownCallback(onMouseDownCallback);
}
void ScaleManipulators::InstallUniformMouseMoveCallback(
const LinearManipulator::MouseActionCallback& onMouseMoveCallback)
void ScaleManipulators::InstallUniformMouseMoveCallback(const LinearManipulator::MouseActionCallback& onMouseMoveCallback)
{
m_uniformScaleManipulator->InstallMouseMoveCallback(onMouseMoveCallback);
m_uniformScaleManipulator->InstallMouseMoveCallback(onMouseMoveCallback);
}
void ScaleManipulators::InstallUniformLeftMouseUpCallback(
const LinearManipulator::MouseActionCallback& onMouseUpCallback)
void ScaleManipulators::InstallUniformLeftMouseUpCallback(const LinearManipulator::MouseActionCallback& onMouseUpCallback)
{
m_uniformScaleManipulator->InstallLeftMouseUpCallback(onMouseUpCallback);
m_uniformScaleManipulator->InstallLeftMouseUpCallback(onMouseUpCallback);
}
void ScaleManipulators::SetLocalTransformImpl(const AZ::Transform& localTransform)
@@ -80,8 +74,7 @@ namespace AzToolsFramework
manipulator->SetLocalTransform(localTransform);
}
m_uniformScaleManipulator->SetVisualOrientationOverride(
QuaternionFromTransformNoScaling(localTransform));
m_uniformScaleManipulator->SetVisualOrientationOverride(QuaternionFromTransformNoScaling(localTransform));
m_uniformScaleManipulator->SetLocalOrientation(AZ::Quaternion::CreateIdentity());
}
@@ -113,14 +106,13 @@ namespace AzToolsFramework
m_uniformScaleManipulator->SetSpace(worldFromLocal);
}
void ScaleManipulators::SetAxes(
const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3)
void ScaleManipulators::SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3)
{
AZ::Vector3 axes[] = { axis1, axis2, axis3 };
AZ::Vector3 axes[] = { axis1, axis2, axis3 };
for (size_t manipulatorIndex = 0; manipulatorIndex < m_axisScaleManipulators.size(); ++manipulatorIndex)
{
m_axisScaleManipulators[manipulatorIndex]->SetAxis(axes[manipulatorIndex]);
m_axisScaleManipulators[manipulatorIndex]->SetAxis(axes[manipulatorIndex]);
}
// uniform scale manipulator uses Z axis for scaling (always in world space)
@@ -129,32 +121,27 @@ namespace AzToolsFramework
}
void ScaleManipulators::ConfigureView(
const float axisLength, const AZ::Color& axis1Color,
const AZ::Color& axis2Color, const AZ::Color& axis3Color)
const float axisLength, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color)
{
const float boxSize = 0.1f;
const float lineWidth = 0.05f;
const AZ::Color colors[] = {
axis1Color, axis2Color, axis3Color
};
const AZ::Color colors[] = { axis1Color, axis2Color, axis3Color };
for (size_t manipulatorIndex = 0; manipulatorIndex < m_axisScaleManipulators.size(); ++manipulatorIndex)
{
ManipulatorViews views;
views.emplace_back(CreateManipulatorViewLine(
*m_axisScaleManipulators[manipulatorIndex], colors[manipulatorIndex], axisLength, lineWidth));
views.emplace_back(
CreateManipulatorViewLine(*m_axisScaleManipulators[manipulatorIndex], colors[manipulatorIndex], axisLength, lineWidth));
views.emplace_back(CreateManipulatorViewBox(
AZ::Transform::CreateIdentity(), colors[manipulatorIndex],
m_axisScaleManipulators[manipulatorIndex]->GetAxis() * (axisLength - boxSize),
AZ::Vector3(boxSize)));
m_axisScaleManipulators[manipulatorIndex]->GetAxis() * (axisLength - boxSize), AZ::Vector3(boxSize)));
m_axisScaleManipulators[manipulatorIndex]->SetViews(AZStd::move(views));
}
ManipulatorViews views;
views.emplace_back(CreateManipulatorViewBox(
AZ::Transform::CreateIdentity(), AZ::Color::CreateOne(),
AZ::Vector3::CreateZero(), AZ::Vector3(boxSize)));
AZ::Transform::CreateIdentity(), AZ::Color::CreateOne(), AZ::Vector3::CreateZero(), AZ::Vector3(boxSize)));
m_uniformScaleManipulator->SetViews(AZStd::move(views));
}
@@ -167,4 +154,4 @@ namespace AzToolsFramework
manipulatorFn(m_uniformScaleManipulator.get());
}
}
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -17,11 +17,10 @@
namespace AzToolsFramework
{
/// ScaleManipulators is an aggregation of 3 linear manipulators for each basis axis who share
/// the same transform, and a single linear manipulator at the center of the transform whose
/// axis is world up (z).
class ScaleManipulators
: public Manipulators
//! ScaleManipulators is an aggregation of 3 linear manipulators for each basis axis who share
//! the same transform, and a single linear manipulator at the center of the transform whose
//! axis is world up (z).
class ScaleManipulators : public Manipulators
{
public:
AZ_RTTI(ScaleManipulators, "{C6350CE0-7B7A-46F8-B65F-D4A54DD9A7D9}")
@@ -42,16 +41,9 @@ namespace AzToolsFramework
void SetLocalPositionImpl(const AZ::Vector3& localPosition) override;
void SetLocalOrientationImpl(const AZ::Quaternion& localOrientation) override;
void SetAxes(
const AZ::Vector3& axis1,
const AZ::Vector3& axis2,
const AZ::Vector3& axis3);
void SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2, const AZ::Vector3& axis3);
void ConfigureView(
float axisLength,
const AZ::Color& axis1Color,
const AZ::Color& axis2Color,
const AZ::Color& axis3Color);
void ConfigureView(float axisLength, const AZ::Color& axis1Color, const AZ::Color& axis2Color, const AZ::Color& axis3Color);
private:
AZ_DISABLE_COPY_MOVE(ScaleManipulators)
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "SelectionManipulator.h"
@@ -16,8 +16,8 @@
namespace AzToolsFramework
{
AZStd::shared_ptr<SelectionManipulator> SelectionManipulator::MakeShared(const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale)
AZStd::shared_ptr<SelectionManipulator> SelectionManipulator::MakeShared(
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale)
{
return AZStd::shared_ptr<SelectionManipulator>(aznew SelectionManipulator(worldFromLocal, nonUniformScale));
}
@@ -93,12 +93,9 @@ namespace AzToolsFramework
for (auto& view : m_manipulatorViews)
{
view->Draw(
GetManipulatorManagerId(), managerState,
GetManipulatorId(), {
TransformUniformScale(GetSpace()), GetNonUniformScale(),
GetLocalPosition(), MouseOver()
},
debugDisplay, cameraState, mouseInteraction);
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalPosition(), MouseOver() }, debugDisplay, cameraState,
mouseInteraction);
}
}
@@ -117,4 +114,4 @@ namespace AzToolsFramework
view->Invalidate(GetManipulatorManagerId());
}
}
}
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -20,13 +20,13 @@ namespace AzToolsFramework
{
class ManipulatorView;
/// Represents a sphere that can be clicked on to trigger a particular behavior
/// For example clicking a preview point to create a translation manipulator.
//! Represents a sphere that can be clicked on to trigger a particular behavior.
//! For example clicking a preview point to create a translation manipulator.
class SelectionManipulator
: public BaseManipulator
, public ManipulatorSpaceWithLocalPosition
{
/// Private constructor.
//! Private constructor.
SelectionManipulator(const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne());
public:
@@ -39,12 +39,12 @@ namespace AzToolsFramework
~SelectionManipulator() = default;
/// A Manipulator must only be created and managed through a shared_ptr.
static AZStd::shared_ptr<SelectionManipulator> MakeShared(const AZ::Transform& worldFromLocal,
const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne());
//! A Manipulator must only be created and managed through a shared_ptr.
static AZStd::shared_ptr<SelectionManipulator> MakeShared(
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne());
/// This is the function signature of callbacks that will be invoked
/// whenever a selection manipulator is clicked on.
//! This is the function signature of callbacks that will be invoked
//! whenever a selection manipulator is clicked on.
using MouseActionCallback = AZStd::function<void(const ViewportInteraction::MouseInteraction&)>;
void InstallLeftMouseDownCallback(const MouseActionCallback& onMouseDownCallback);
@@ -58,10 +58,25 @@ namespace AzToolsFramework
const AzFramework::CameraState& cameraState,
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
bool Selected() const { return m_selected; }
void Select() { m_selected = true; }
void Deselect() { m_selected = false; }
void ToggleSelected() { m_selected = !m_selected; }
bool Selected() const
{
return m_selected;
}
void Select()
{
m_selected = true;
}
void Deselect()
{
m_selected = false;
}
void ToggleSelected()
{
m_selected = !m_selected;
}
template<typename Views>
void SetViews(Views&& views)
@@ -70,13 +85,9 @@ namespace AzToolsFramework
}
private:
void OnLeftMouseDownImpl(
const ViewportInteraction::MouseInteraction& interaction,
float rayIntersectionDistance) override;
void OnLeftMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnLeftMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void OnRightMouseDownImpl(
const ViewportInteraction::MouseInteraction& interaction,
float rayIntersectionDistance) override;
void OnRightMouseDownImpl(const ViewportInteraction::MouseInteraction& interaction, float rayIntersectionDistance) override;
void OnRightMouseUpImpl(const ViewportInteraction::MouseInteraction& interaction) override;
void InvalidateImpl() override;
@@ -89,6 +100,6 @@ namespace AzToolsFramework
MouseActionCallback m_onRightMouseDownCallback = nullptr;
MouseActionCallback m_onRightMouseUpCallback = nullptr;
ManipulatorViews m_manipulatorViews; ///< Look of manipulator.
ManipulatorViews m_manipulatorViews; //!< Look of manipulator.
};
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "SplineHoverSelection.h"
@@ -20,11 +20,12 @@
namespace AzToolsFramework
{
static const AZ::Color s_splineSelectManipulatorColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
static const AZ::Color SplineSelectManipulatorColor = AZ::Color(0.0f, 1.0f, 0.0f, 1.0f);
SplineHoverSelection::SplineHoverSelection(
const AZ::EntityComponentIdPair& entityComponentIdPair,
const ManipulatorManagerId managerId, const AZStd::shared_ptr<AZ::Spline>& spline)
const ManipulatorManagerId managerId,
const AZStd::shared_ptr<AZ::Spline>& spline)
{
m_splineSelectionManipulator = SplineSelectionManipulator::MakeShared();
m_splineSelectionManipulator->Register(managerId);
@@ -33,16 +34,14 @@ namespace AzToolsFramework
const float splineWidth = 0.05f;
m_splineSelectionManipulator->SetSpline(spline);
m_splineSelectionManipulator->SetView(CreateManipulatorViewSplineSelect(
*m_splineSelectionManipulator, s_splineSelectManipulatorColor, splineWidth));
m_splineSelectionManipulator->SetView(
CreateManipulatorViewSplineSelect(*m_splineSelectionManipulator, SplineSelectManipulatorColor, splineWidth));
m_splineSelectionManipulator->InstallLeftMouseUpCallback(
[entityComponentIdPair](const SplineSelectionManipulator::Action& action)
{
InsertVertexAfter(
entityComponentIdPair, action.m_splineAddress.m_segmentIndex,
action.m_localSplineHitPosition);
});
{
InsertVertexAfter(entityComponentIdPair, action.m_splineAddress.m_segmentIndex, action.m_localSplineHitPosition);
});
}
SplineHoverSelection::~SplineHoverSelection()
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* 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
@@ -19,20 +19,20 @@ namespace AZ
{
class Spline;
class EntityComponentIdPair;
}
} // namespace AZ
namespace AzToolsFramework
{
class SplineSelectionManipulator;
/// SplineHoverSelection is a concrete implementation of HoverSelection wrapping a Spline and
/// SplineManipulator. The underlying manipulators are used to control selection.
class SplineHoverSelection
: public HoverSelection
//! SplineHoverSelection is a concrete implementation of HoverSelection wrapping a Spline and
//! SplineManipulator. The underlying manipulators are used to control selection.
class SplineHoverSelection : public HoverSelection
{
public:
explicit SplineHoverSelection(
const AZ::EntityComponentIdPair& entityComponentIdPair, ManipulatorManagerId managerId,
const AZ::EntityComponentIdPair& entityComponentIdPair,
ManipulatorManagerId managerId,
const AZStd::shared_ptr<AZ::Spline>& spline);
SplineHoverSelection(const SplineHoverSelection&) = delete;
SplineHoverSelection& operator=(const SplineHoverSelection&) = delete;
@@ -46,6 +46,6 @@ namespace AzToolsFramework
void SetNonUniformScale(const AZ::Vector3& nonUniformScale) override;
private:
AZStd::shared_ptr<SplineSelectionManipulator> m_splineSelectionManipulator; ///< Manipulator for adding points to spline.
AZStd::shared_ptr<SplineSelectionManipulator> m_splineSelectionManipulator; //!< Manipulator for adding points to spline.
};
} // namespace AzToolsFramework
@@ -1,14 +1,14 @@
/*
* 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.
*
*/
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "SplineSelectionManipulator.h"
@@ -18,8 +18,10 @@
namespace AzToolsFramework
{
SplineSelectionManipulator::Action CalculateManipulationDataAction(
const AZ::Transform& worldFromLocal, const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection, const AZStd::weak_ptr<const AZ::Spline>& spline)
const AZ::Transform& worldFromLocal,
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
const AZStd::weak_ptr<const AZ::Spline>& spline)
{
SplineSelectionManipulator::Action action;
if (const AZStd::shared_ptr<const AZ::Spline> splinePtr = spline.lock())
@@ -65,9 +67,7 @@ namespace AzToolsFramework
if (m_onLeftMouseDownCallback)
{
m_onLeftMouseDownCallback(CalculateManipulationDataAction(
TransformUniformScale(GetSpace()),
interaction.m_mousePick.m_rayOrigin,
interaction.m_mousePick.m_rayDirection, m_spline));
TransformUniformScale(GetSpace()), interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, m_spline));
}
}
@@ -76,9 +76,7 @@ namespace AzToolsFramework
if (MouseOver() && m_onLeftMouseUpCallback)
{
m_onLeftMouseUpCallback(CalculateManipulationDataAction(
TransformUniformScale(GetSpace()),
interaction.m_mousePick.m_rayOrigin,
interaction.m_mousePick.m_rayDirection, m_spline));
TransformUniformScale(GetSpace()), interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection, m_spline));
}
}
@@ -99,12 +97,9 @@ namespace AzToolsFramework
if (mouseInteraction.m_keyboardModifiers.Ctrl() && !mouseInteraction.m_keyboardModifiers.Shift())
{
m_manipulatorView->Draw(
GetManipulatorManagerId(), managerState,
GetManipulatorId(), {
TransformUniformScale(GetSpace()), GetNonUniformScale(),
AZ::Vector3::CreateZero(), MouseOver()
},
debugDisplay, cameraState, mouseInteraction);
GetManipulatorManagerId(), managerState, GetManipulatorId(),
{ TransformUniformScale(GetSpace()), GetNonUniformScale(), AZ::Vector3::CreateZero(), MouseOver() }, debugDisplay,
cameraState, mouseInteraction);
}
}
@@ -122,4 +117,4 @@ namespace AzToolsFramework
{
m_manipulatorView->Invalidate(GetManipulatorManagerId());
}
}
} // namespace AzToolsFramework

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