Merge remote-tracking branch 'upstream/development' into nvsickle/GenericDomDocument
This commit is contained in:
@@ -254,13 +254,13 @@ namespace AZ
|
||||
Method("CreateFromMatrix3x3", &Quaternion::CreateFromMatrix3x3)->
|
||||
Method("CreateFromMatrix4x4", &Quaternion::CreateFromMatrix4x4)->
|
||||
Method("CreateFromAxisAngle", &Quaternion::CreateFromAxisAngle)->
|
||||
Method("CreateFromScaledAxisAngle", &Quaternion::CreateFromScaledAxisAngle)->
|
||||
Method("CreateShortestArc", &Quaternion::CreateShortestArc)->
|
||||
Method("CreateFromEulerAnglesDegrees", &Quaternion::CreateFromEulerAnglesDegrees)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Quaternion Quaternion::CreateFromMatrix3x3(const Matrix3x3& m)
|
||||
{
|
||||
return CreateFromBasis(m.GetBasisX(), m.GetBasisY(), m.GetBasisZ());
|
||||
@@ -430,4 +430,24 @@ namespace AZ
|
||||
outAngle = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vector3 Quaternion::ConvertToScaledAxisAngle() const
|
||||
{
|
||||
// Take the log of the quaternion to convert it to the exponential map
|
||||
// and multiply it by 2.0 to bring it into the scaled axis-angle representation.
|
||||
const AZ::Vector3 imaginary = GetImaginary();
|
||||
const float length = imaginary.GetLength();
|
||||
if (length < AZ::Constants::FloatEpsilon)
|
||||
{
|
||||
return imaginary * 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float halfAngle = acosf(AZ::GetClamp(GetW(), -1.0f, 1.0f));
|
||||
|
||||
// Multiply by 2.0 to convert the half angle into the full one.
|
||||
return halfAngle * 2.0f * (imaginary / length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,9 @@ namespace AZ
|
||||
|
||||
static Quaternion CreateFromAxisAngle(const Vector3& axis, float angle);
|
||||
|
||||
//! Create a quaternion from a scaled axis-angle representation.
|
||||
static Quaternion CreateFromScaledAxisAngle(const Vector3& scaledAxisAngle);
|
||||
|
||||
static Quaternion CreateShortestArc(const Vector3& v1, const Vector3& v2);
|
||||
|
||||
//! Creates a quaternion using rotation in degrees about the axes. First rotated about the X axis, followed by the Y axis, then the Z axis.
|
||||
@@ -231,6 +234,9 @@ namespace AZ
|
||||
//! @param[out] outAngle A float rotation angle around the axis in radians.
|
||||
void ConvertToAxisAngle(Vector3& outAxis, float& outAngle) const;
|
||||
|
||||
//! Convert the quaternion into scaled axis-angle representation.
|
||||
Vector3 ConvertToScaledAxisAngle() const;
|
||||
|
||||
//! Returns the imaginary (X/Y/Z) portion of the quaternion.
|
||||
Vector3 GetImaginary() const;
|
||||
|
||||
|
||||
@@ -109,6 +109,24 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Quaternion Quaternion::CreateFromScaledAxisAngle(const Vector3& scaledAxisAngle)
|
||||
{
|
||||
const AZ::Vector3 exponentialMap = scaledAxisAngle / 2.0f;
|
||||
const float halfAngle = exponentialMap.GetLength();
|
||||
|
||||
if (halfAngle < AZ::Constants::FloatEpsilon)
|
||||
{
|
||||
return AZ::Quaternion::CreateFromVector3AndValue(exponentialMap, 1.0f).GetNormalized();
|
||||
}
|
||||
else
|
||||
{
|
||||
float sin, cos;
|
||||
SinCos(halfAngle, sin, cos);
|
||||
return AZ::Quaternion::CreateFromVector3AndValue((sin / halfAngle) * exponentialMap, cos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Quaternion::StoreToFloat4(float* values) const
|
||||
{
|
||||
Simd::Vec4::StoreUnaligned(values, m_value);
|
||||
|
||||
@@ -16,438 +16,421 @@
|
||||
|
||||
#include <AzCore/Debug/StackTracer.h>
|
||||
|
||||
using namespace AZ;
|
||||
using namespace AZ::Debug;
|
||||
namespace AZ::Debug
|
||||
{
|
||||
// Many PC tools break with alloc/free size mismatches when the memory guard is enabled. Disable for now
|
||||
//#define ENABLE_MEMORY_GUARD
|
||||
|
||||
// Many PC tools break with alloc/free size mismatches when the memory guard is enabled. Disable for now
|
||||
//#define ENABLE_MEMORY_GUARD
|
||||
|
||||
//=========================================================================
|
||||
// AllocationRecords
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
AllocationRecords::AllocationRecords(unsigned char stackRecordLevels, [[maybe_unused]] bool isMemoryGuard, bool isMarkUnallocatedMemory, const char* allocatorName)
|
||||
: m_mode(AllocatorManager::Instance().m_defaultTrackingRecordMode)
|
||||
, m_isAutoIntegrityCheck(false)
|
||||
, m_isMarkUnallocatedMemory(isMarkUnallocatedMemory)
|
||||
, m_saveNames(false)
|
||||
, m_decodeImmediately(false)
|
||||
, m_numStackLevels(stackRecordLevels)
|
||||
//=========================================================================
|
||||
// AllocationRecords
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
AllocationRecords::AllocationRecords(
|
||||
unsigned char stackRecordLevels, [[maybe_unused]] bool isMemoryGuard, bool isMarkUnallocatedMemory, const char* allocatorName)
|
||||
: m_mode(AllocatorManager::Instance().m_defaultTrackingRecordMode)
|
||||
, m_isAutoIntegrityCheck(false)
|
||||
, m_isMarkUnallocatedMemory(isMarkUnallocatedMemory)
|
||||
, m_saveNames(false)
|
||||
, m_decodeImmediately(false)
|
||||
, m_numStackLevels(stackRecordLevels)
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
, m_memoryGuardSize(isMemoryGuard ? sizeof(Debug::GuardValue) : 0)
|
||||
, m_memoryGuardSize(isMemoryGuard ? sizeof(Debug::GuardValue) : 0)
|
||||
#else
|
||||
, m_memoryGuardSize(0)
|
||||
, m_memoryGuardSize(0)
|
||||
#endif
|
||||
, m_requestedAllocs(0)
|
||||
, m_requestedBytes(0)
|
||||
, m_requestedBytesPeak(0)
|
||||
, m_allocatorName(allocatorName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~AllocationRecords
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
AllocationRecords::~AllocationRecords()
|
||||
{
|
||||
if (!AllocatorManager::Instance().m_isAllocatorLeaking)
|
||||
, m_requestedAllocs(0)
|
||||
, m_requestedBytes(0)
|
||||
, m_requestedBytesPeak(0)
|
||||
, m_allocatorName(allocatorName)
|
||||
{
|
||||
// dump all allocation (we should not have any at this point).
|
||||
bool includeNameAndFilename = (m_saveNames || m_mode == RECORD_FULL);
|
||||
EnumerateAllocations(PrintAllocationsCB(true, includeNameAndFilename));
|
||||
AZ_Error("Memory", m_records.empty(), "We still have %d allocations on record! They must be freed prior to destroy!", m_records.size());
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// lock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::lock()
|
||||
{
|
||||
m_recordsMutex.lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// try_lock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
bool AllocationRecords::try_lock()
|
||||
{
|
||||
return m_recordsMutex.try_lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// unlock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::unlock()
|
||||
{
|
||||
m_recordsMutex.unlock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// RegisterAllocation
|
||||
// [9/11/2009]
|
||||
//=========================================================================
|
||||
const AllocationInfo*
|
||||
AllocationRecords::RegisterAllocation(void* address, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, unsigned int stackSuppressCount)
|
||||
{
|
||||
(void)stackSuppressCount;
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (address == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// memory guard
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
//=========================================================================
|
||||
// ~AllocationRecords
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
AllocationRecords::~AllocationRecords()
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
if (!AllocatorManager::Instance().m_isAllocatorLeaking)
|
||||
{
|
||||
IntegrityCheck();
|
||||
// dump all allocation (we should not have any at this point).
|
||||
bool includeNameAndFilename = (m_saveNames || m_mode == RECORD_FULL);
|
||||
EnumerateAllocations(PrintAllocationsCB(true, includeNameAndFilename));
|
||||
AZ_Error(
|
||||
"Memory", m_records.empty(), "We still have %d allocations on record! They must be freed prior to destroy!",
|
||||
m_records.size());
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// lock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::lock()
|
||||
{
|
||||
m_recordsMutex.lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// try_lock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
bool AllocationRecords::try_lock()
|
||||
{
|
||||
return m_recordsMutex.try_lock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// unlock
|
||||
// [9/16/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::unlock()
|
||||
{
|
||||
m_recordsMutex.unlock();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// RegisterAllocation
|
||||
// [9/11/2009]
|
||||
//=========================================================================
|
||||
const AllocationInfo* AllocationRecords::RegisterAllocation(
|
||||
void* address,
|
||||
size_t byteSize,
|
||||
size_t alignment,
|
||||
const char* name,
|
||||
const char* fileName,
|
||||
int lineNum,
|
||||
unsigned int stackSuppressCount)
|
||||
{
|
||||
(void)stackSuppressCount;
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (address == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AZ_Assert(byteSize>sizeof(Debug::GuardValue), "Did you forget to add the extra MemoryGuardSize() bytes?");
|
||||
byteSize -= sizeof(Debug::GuardValue);
|
||||
new(reinterpret_cast<char*>(address)+byteSize) Debug::GuardValue();
|
||||
}
|
||||
|
||||
Debug::AllocationRecordsType::pair_iter_bool iterBool;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
iterBool = m_records.insert_key(address);
|
||||
}
|
||||
|
||||
if (!iterBool.second)
|
||||
{
|
||||
// If that memory address was already registered, print the stack trace of the previous registration
|
||||
PrintAllocationsCB(true, (m_saveNames || m_mode == RECORD_FULL))(address, iterBool.first->second, m_numStackLevels);
|
||||
AZ_Assert(iterBool.second, "Memory address 0x%p is already allocated and in the records!", address);
|
||||
}
|
||||
|
||||
Debug::AllocationInfo& ai = iterBool.first->second;
|
||||
ai.m_byteSize = byteSize;
|
||||
ai.m_alignment = static_cast<unsigned int>(alignment);
|
||||
if ((m_saveNames || m_mode == RECORD_FULL) && name && fileName)
|
||||
{
|
||||
// In RECORD_FULL mode or when specifically enabled in app descriptor with
|
||||
// m_allocationRecordsSaveNames, we allocate our own memory to save off name and fileName.
|
||||
// When testing for memory leaks, on process shutdown AllocationRecords::~AllocationRecords
|
||||
// gets called to enumerate the remaining (leaked) allocations. Unfortunately, any names
|
||||
// referenced in dynamic module memory whose modules are unloaded won't be valid
|
||||
// references anymore and we won't get useful information from the enumeration print.
|
||||
// This code block ensures we keep our name/fileName valid for when we need it.
|
||||
const size_t nameLength = strlen(name);
|
||||
const size_t fileNameLength = strlen(fileName);
|
||||
const size_t totalLength = nameLength + fileNameLength + 2; // + 2 for terminating null characters
|
||||
ai.m_namesBlock = m_records.get_allocator().allocate(totalLength, 1);
|
||||
ai.m_namesBlockSize = totalLength;
|
||||
char* savedName = reinterpret_cast<char*>(ai.m_namesBlock);
|
||||
char* savedFileName = savedName + nameLength + 1;
|
||||
memcpy(reinterpret_cast<void*>(savedName), reinterpret_cast<const void*>(name), nameLength + 1);
|
||||
memcpy(reinterpret_cast<void*>(savedFileName), reinterpret_cast<const void*>(fileName), fileNameLength + 1);
|
||||
ai.m_name = savedName;
|
||||
ai.m_fileName = savedFileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
ai.m_name = name;
|
||||
ai.m_fileName = fileName;
|
||||
ai.m_namesBlock = nullptr;
|
||||
ai.m_namesBlockSize = 0;
|
||||
}
|
||||
ai.m_lineNum = lineNum;
|
||||
ai.m_timeStamp = AZStd::GetTimeNowMicroSecond();
|
||||
|
||||
// if we don't have a fileName,lineNum record the stack or if the user requested it.
|
||||
if ((fileName == nullptr && m_mode == RECORD_STACK_IF_NO_FILE_LINE) || m_mode == RECORD_FULL)
|
||||
{
|
||||
ai.m_stackFrames = m_numStackLevels ? reinterpret_cast<AZ::Debug::StackFrame*>(m_records.get_allocator().allocate(sizeof(AZ::Debug::StackFrame)*m_numStackLevels, 1)) : nullptr;
|
||||
if (ai.m_stackFrames)
|
||||
// memory guard
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
Debug::StackRecorder::Record(ai.m_stackFrames, m_numStackLevels, stackSuppressCount + 1);
|
||||
|
||||
if (m_decodeImmediately)
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// OPTIONAL DEBUGGING CODE - enable in app descriptor m_allocationRecordsAttemptDecodeImmediately
|
||||
// This is optionally-enabled code for tracking down memory allocations
|
||||
// that fail to be decoded. DecodeFrames() typically runs at the end of
|
||||
// your application when leaks were found. Sometimes you have stack prints
|
||||
// full of "(module-name not available)" and "(function-name not available)"
|
||||
// that are not actionable. If you have those, enable this code. It'll slow
|
||||
// down your process significantly because for every allocation recorded
|
||||
// we get the stack trace on the spot. Put a breakpoint in DecodeFrames()
|
||||
// at the "(module-name not available)" and "(function-name not available)"
|
||||
// locations and now at the moment those allocations happen you'll have the
|
||||
// full stack trace available and the ability to debug what could be causing it
|
||||
IntegrityCheck();
|
||||
}
|
||||
|
||||
AZ_Assert(byteSize > sizeof(Debug::GuardValue), "Did you forget to add the extra MemoryGuardSize() bytes?");
|
||||
byteSize -= sizeof(Debug::GuardValue);
|
||||
new (reinterpret_cast<char*>(address) + byteSize) Debug::GuardValue();
|
||||
}
|
||||
|
||||
Debug::AllocationRecordsType::pair_iter_bool iterBool;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
iterBool = m_records.insert_key(address);
|
||||
}
|
||||
|
||||
if (!iterBool.second)
|
||||
{
|
||||
// If that memory address was already registered, print the stack trace of the previous registration
|
||||
PrintAllocationsCB(true, (m_saveNames || m_mode == RECORD_FULL))(address, iterBool.first->second, m_numStackLevels);
|
||||
AZ_Assert(iterBool.second, "Memory address 0x%p is already allocated and in the records!", address);
|
||||
}
|
||||
|
||||
Debug::AllocationInfo& ai = iterBool.first->second;
|
||||
ai.m_byteSize = byteSize;
|
||||
ai.m_alignment = static_cast<unsigned int>(alignment);
|
||||
if ((m_saveNames || m_mode == RECORD_FULL) && name && fileName)
|
||||
{
|
||||
// In RECORD_FULL mode or when specifically enabled in app descriptor with
|
||||
// m_allocationRecordsSaveNames, we allocate our own memory to save off name and fileName.
|
||||
// When testing for memory leaks, on process shutdown AllocationRecords::~AllocationRecords
|
||||
// gets called to enumerate the remaining (leaked) allocations. Unfortunately, any names
|
||||
// referenced in dynamic module memory whose modules are unloaded won't be valid
|
||||
// references anymore and we won't get useful information from the enumeration print.
|
||||
// This code block ensures we keep our name/fileName valid for when we need it.
|
||||
const size_t nameLength = strlen(name);
|
||||
const size_t fileNameLength = strlen(fileName);
|
||||
const size_t totalLength = nameLength + fileNameLength + 2; // + 2 for terminating null characters
|
||||
ai.m_namesBlock = m_records.get_allocator().allocate(totalLength, 1);
|
||||
ai.m_namesBlockSize = totalLength;
|
||||
char* savedName = reinterpret_cast<char*>(ai.m_namesBlock);
|
||||
char* savedFileName = savedName + nameLength + 1;
|
||||
memcpy(reinterpret_cast<void*>(savedName), reinterpret_cast<const void*>(name), nameLength + 1);
|
||||
memcpy(reinterpret_cast<void*>(savedFileName), reinterpret_cast<const void*>(fileName), fileNameLength + 1);
|
||||
ai.m_name = savedName;
|
||||
ai.m_fileName = savedFileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
ai.m_name = name;
|
||||
ai.m_fileName = fileName;
|
||||
ai.m_namesBlock = nullptr;
|
||||
ai.m_namesBlockSize = 0;
|
||||
}
|
||||
ai.m_lineNum = lineNum;
|
||||
ai.m_timeStamp = AZStd::GetTimeNowMicroSecond();
|
||||
|
||||
// if we don't have a fileName,lineNum record the stack or if the user requested it.
|
||||
if ((fileName == nullptr && m_mode == RECORD_STACK_IF_NO_FILE_LINE) || m_mode == RECORD_FULL)
|
||||
{
|
||||
ai.m_stackFrames = m_numStackLevels ? reinterpret_cast<AZ::Debug::StackFrame*>(m_records.get_allocator().allocate(
|
||||
sizeof(AZ::Debug::StackFrame) * m_numStackLevels, 1))
|
||||
: nullptr;
|
||||
if (ai.m_stackFrames)
|
||||
{
|
||||
Debug::StackRecorder::Record(ai.m_stackFrames, m_numStackLevels, stackSuppressCount + 1);
|
||||
|
||||
if (m_decodeImmediately)
|
||||
{
|
||||
const unsigned char decodeStep = 40;
|
||||
Debug::SymbolStorage::StackLine lines[decodeStep];
|
||||
unsigned char iFrame = 0;
|
||||
unsigned char numStackLevels = m_numStackLevels;
|
||||
while (numStackLevels > 0)
|
||||
// OPTIONAL DEBUGGING CODE - enable in app descriptor m_allocationRecordsAttemptDecodeImmediately
|
||||
// This is optionally-enabled code for tracking down memory allocations
|
||||
// that fail to be decoded. DecodeFrames() typically runs at the end of
|
||||
// your application when leaks were found. Sometimes you have stack prints
|
||||
// full of "(module-name not available)" and "(function-name not available)"
|
||||
// that are not actionable. If you have those, enable this code. It'll slow
|
||||
// down your process significantly because for every allocation recorded
|
||||
// we get the stack trace on the spot. Put a breakpoint in DecodeFrames()
|
||||
// at the "(module-name not available)" and "(function-name not available)"
|
||||
// locations and now at the moment those allocations happen you'll have the
|
||||
// full stack trace available and the ability to debug what could be causing it
|
||||
{
|
||||
unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
|
||||
Debug::SymbolStorage::DecodeFrames(&ai.m_stackFrames[iFrame], numToDecode, lines);
|
||||
numStackLevels -= numToDecode;
|
||||
iFrame += numToDecode;
|
||||
const unsigned char decodeStep = 40;
|
||||
Debug::SymbolStorage::StackLine lines[decodeStep];
|
||||
unsigned char iFrame = 0;
|
||||
unsigned char numStackLevels = m_numStackLevels;
|
||||
while (numStackLevels > 0)
|
||||
{
|
||||
unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
|
||||
Debug::SymbolStorage::DecodeFrames(&ai.m_stackFrames[iFrame], numToDecode, lines);
|
||||
numStackLevels -= numToDecode;
|
||||
iFrame += numToDecode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AllocatorManager::Instance().DebugBreak(address, ai);
|
||||
|
||||
// statistics
|
||||
m_requestedBytes += byteSize;
|
||||
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
|
||||
++m_requestedAllocs;
|
||||
|
||||
return &ai;
|
||||
}
|
||||
|
||||
AllocatorManager::Instance().DebugBreak(address, ai);
|
||||
|
||||
// statistics
|
||||
m_requestedBytes += byteSize;
|
||||
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
//=========================================================================
|
||||
// UnregisterAllocation
|
||||
// [9/11/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t alignment, AllocationInfo* info)
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
|
||||
++m_requestedAllocs;
|
||||
|
||||
return &ai;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// UnregisterAllocation
|
||||
// [9/11/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t alignment, AllocationInfo* info)
|
||||
{
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (address == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AllocationInfo allocationInfo;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
// We cannot assert if an allocation does not exist because allocations may have been made before tracking was enabled.
|
||||
// It is currently impossible to actually track all allocations that happen before a certain point
|
||||
// AZ_Assert(iter!=m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
if (iter == m_records.end())
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
allocationInfo = iter->second;
|
||||
m_records.erase(iter);
|
||||
|
||||
// try to be more aggressive and keep the memory footprint low.
|
||||
// \todo store the load factor at the last rehash to avoid unnecessary rehash
|
||||
if (m_records.load_factor() < 0.9f)
|
||||
if (address == nullptr)
|
||||
{
|
||||
m_records.rehash(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AllocatorManager::Instance().DebugBreak(address, allocationInfo);
|
||||
|
||||
(void)byteSize;
|
||||
(void)alignment;
|
||||
AZ_Assert(byteSize==0||byteSize==allocationInfo.m_byteSize, "Mismatched byteSize at deallocation! You supplied an invalid value!");
|
||||
AZ_Assert(alignment==0||alignment==allocationInfo.m_alignment, "Mismatched alignment at deallocation! You supplied an invalid value!");
|
||||
|
||||
// statistics
|
||||
m_requestedBytes -= allocationInfo.m_byteSize;
|
||||
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
// memory guard
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check current allocation
|
||||
char* guardAddress = reinterpret_cast<char*>(address)+allocationInfo.m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(address, allocationInfo, m_numStackLevels);
|
||||
AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
guard->~GuardValue();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// delete allocation record
|
||||
if (allocationInfo.m_namesBlock)
|
||||
{
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_namesBlock, allocationInfo.m_namesBlockSize, 1);
|
||||
allocationInfo.m_namesBlock = nullptr;
|
||||
allocationInfo.m_namesBlockSize = 0;
|
||||
allocationInfo.m_name = nullptr;
|
||||
allocationInfo.m_fileName = nullptr;
|
||||
}
|
||||
if (allocationInfo.m_stackFrames)
|
||||
{
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_stackFrames, sizeof(AZ::Debug::StackFrame)*m_numStackLevels, 1);
|
||||
allocationInfo.m_stackFrames = nullptr;
|
||||
}
|
||||
|
||||
if (info)
|
||||
{
|
||||
*info = allocationInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if requested set memory to a specific value.
|
||||
if (m_isMarkUnallocatedMemory)
|
||||
{
|
||||
memset(address, GetUnallocatedMarkValue(), byteSize);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ResizeAllocation
|
||||
// [9/20/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::ResizeAllocation(void* address, size_t newSize)
|
||||
{
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AllocationInfo* allocationInfo;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
AZ_Assert(iter != m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
allocationInfo = &iter->second;
|
||||
}
|
||||
AllocatorManager::Instance().DebugBreak(address, *allocationInfo);
|
||||
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check memory guard
|
||||
char* guardAddress = reinterpret_cast<char*>(address) + allocationInfo->m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(address, iter->second, m_numStackLevels);
|
||||
AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
guard->~GuardValue();
|
||||
}
|
||||
// init the new memory guard
|
||||
newSize -= sizeof(Debug::GuardValue);
|
||||
new(reinterpret_cast<char*>(address)+newSize) Debug::GuardValue();
|
||||
}
|
||||
#endif
|
||||
|
||||
// statistics
|
||||
m_requestedBytes -= allocationInfo->m_byteSize;
|
||||
m_requestedBytes += newSize;
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
++m_requestedAllocs;
|
||||
|
||||
// update allocation size
|
||||
allocationInfo->m_byteSize = newSize;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// EnumerateAllocations
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::SetMode(Mode mode)
|
||||
{
|
||||
if (mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
AllocationInfo allocationInfo;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
m_records.clear();
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
// We cannot assert if an allocation does not exist because allocations may have been made before tracking was enabled.
|
||||
// It is currently impossible to actually track all allocations that happen before a certain point
|
||||
// AZ_Assert(iter!=m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
if (iter == m_records.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
allocationInfo = iter->second;
|
||||
m_records.erase(iter);
|
||||
|
||||
// try to be more aggressive and keep the memory footprint low.
|
||||
// \todo store the load factor at the last rehash to avoid unnecessary rehash
|
||||
if (m_records.load_factor() < 0.9f)
|
||||
{
|
||||
m_records.rehash(0);
|
||||
}
|
||||
}
|
||||
m_requestedBytes = 0;
|
||||
m_requestedBytesPeak = 0;
|
||||
m_requestedAllocs = 0;
|
||||
}
|
||||
|
||||
AZ_Warning("Memory", m_mode != RECORD_NO_RECORDS || mode == RECORD_NO_RECORDS, "Records recording was disabled and now it's enabled! You might get assert when you free memory, if a you have allocations which were not recorded!");
|
||||
AllocatorManager::Instance().DebugBreak(address, allocationInfo);
|
||||
|
||||
m_mode = mode;
|
||||
}
|
||||
(void)byteSize;
|
||||
(void)alignment;
|
||||
AZ_Assert(
|
||||
byteSize == 0 || byteSize == allocationInfo.m_byteSize, "Mismatched byteSize at deallocation! You supplied an invalid value!");
|
||||
AZ_Assert(
|
||||
alignment == 0 || alignment == allocationInfo.m_alignment,
|
||||
"Mismatched alignment at deallocation! You supplied an invalid value!");
|
||||
|
||||
//=========================================================================
|
||||
// EnumerateAllocations
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::EnumerateAllocations(AllocationInfoCBType cb)
|
||||
{
|
||||
// enumerate all allocations and stop if requested.
|
||||
// Since allocations can change during the iteration (code that prints out the records could allocate, which will
|
||||
// mutate m_records), we are going to make a copy and iterate the copy.
|
||||
Debug::AllocationRecordsType recordsCopy;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
recordsCopy = m_records;
|
||||
}
|
||||
for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
|
||||
{
|
||||
if (!cb(iter->first, iter->second, m_numStackLevels))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// statistics
|
||||
m_requestedBytes -= allocationInfo.m_byteSize;
|
||||
|
||||
//=========================================================================
|
||||
// IntegrityCheck
|
||||
// [9/9/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
AllocationRecords::IntegrityCheck() const
|
||||
{
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
// memory guard
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check current allocation
|
||||
char* guardAddress = reinterpret_cast<char*>(address) + allocationInfo.m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(address, allocationInfo, m_numStackLevels);
|
||||
AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
guard->~GuardValue();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// delete allocation record
|
||||
if (allocationInfo.m_namesBlock)
|
||||
{
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_namesBlock, allocationInfo.m_namesBlockSize, 1);
|
||||
allocationInfo.m_namesBlock = nullptr;
|
||||
allocationInfo.m_namesBlockSize = 0;
|
||||
allocationInfo.m_name = nullptr;
|
||||
allocationInfo.m_fileName = nullptr;
|
||||
}
|
||||
if (allocationInfo.m_stackFrames)
|
||||
{
|
||||
m_records.get_allocator().deallocate(allocationInfo.m_stackFrames, sizeof(AZ::Debug::StackFrame) * m_numStackLevels, 1);
|
||||
allocationInfo.m_stackFrames = nullptr;
|
||||
}
|
||||
|
||||
if (info)
|
||||
{
|
||||
*info = allocationInfo;
|
||||
}
|
||||
|
||||
// if requested set memory to a specific value.
|
||||
if (m_isMarkUnallocatedMemory)
|
||||
{
|
||||
memset(address, GetUnallocatedMarkValue(), byteSize);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ResizeAllocation
|
||||
// [9/20/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::ResizeAllocation(void* address, size_t newSize)
|
||||
{
|
||||
if (m_mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AllocationInfo* allocationInfo;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
Debug::AllocationRecordsType::iterator iter = m_records.find(address);
|
||||
AZ_Assert(iter != m_records.end(), "Could not find address 0x%p in the allocator!", address);
|
||||
allocationInfo = &iter->second;
|
||||
}
|
||||
AllocatorManager::Instance().DebugBreak(address, *allocationInfo);
|
||||
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
if (m_isAutoIntegrityCheck)
|
||||
{
|
||||
// full integrity check
|
||||
IntegrityCheck();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check memory guard
|
||||
char* guardAddress = reinterpret_cast<char*>(address) + allocationInfo->m_byteSize;
|
||||
Debug::GuardValue* guard = reinterpret_cast<Debug::GuardValue*>(guardAddress);
|
||||
if (!guard->Validate())
|
||||
{
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(address, iter->second, m_numStackLevels);
|
||||
AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
guard->~GuardValue();
|
||||
}
|
||||
// init the new memory guard
|
||||
newSize -= sizeof(Debug::GuardValue);
|
||||
new (reinterpret_cast<char*>(address) + newSize) Debug::GuardValue();
|
||||
}
|
||||
#endif
|
||||
|
||||
// statistics
|
||||
m_requestedBytes -= allocationInfo->m_byteSize;
|
||||
m_requestedBytes += newSize;
|
||||
size_t currentRequestedBytePeak;
|
||||
size_t newRequestedBytePeak;
|
||||
do
|
||||
{
|
||||
currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
|
||||
newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
|
||||
} while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
|
||||
++m_requestedAllocs;
|
||||
|
||||
// update allocation size
|
||||
allocationInfo->m_byteSize = newSize;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// EnumerateAllocations
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::SetMode(Mode mode)
|
||||
{
|
||||
if (mode == RECORD_NO_RECORDS)
|
||||
{
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
m_records.clear();
|
||||
}
|
||||
m_requestedBytes = 0;
|
||||
m_requestedBytesPeak = 0;
|
||||
m_requestedAllocs = 0;
|
||||
}
|
||||
|
||||
AZ_Warning(
|
||||
"Memory", m_mode != RECORD_NO_RECORDS || mode == RECORD_NO_RECORDS,
|
||||
"Records recording was disabled and now it's enabled! You might get assert when you free memory, if a you have allocations "
|
||||
"which were not recorded!");
|
||||
|
||||
m_mode = mode;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// EnumerateAllocations
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
void AllocationRecords::EnumerateAllocations(AllocationInfoCBType cb)
|
||||
{
|
||||
// enumerate all allocations and stop if requested.
|
||||
// Since allocations can change during the iteration (code that prints out the records could allocate, which will
|
||||
// mutate m_records), we are going to make a copy and iterate the copy.
|
||||
Debug::AllocationRecordsType recordsCopy;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
@@ -455,67 +438,93 @@ AllocationRecords::IntegrityCheck() const
|
||||
}
|
||||
for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
|
||||
{
|
||||
// check memory guard
|
||||
const char* guardAddress = reinterpret_cast<const char*>(iter->first)+ iter->second.m_byteSize;
|
||||
if (!reinterpret_cast<const Debug::GuardValue*>(guardAddress)->Validate())
|
||||
if (!cb(iter->first, iter->second, m_numStackLevels))
|
||||
{
|
||||
// We have to turn off the integrity check at this point if we want to succesfully report the memory
|
||||
// stomp we just found. If we don't turn this off, the printf just winds off the stack as each memory
|
||||
// allocation done therein recurses this same code.
|
||||
*const_cast<bool*>(&m_isAutoIntegrityCheck) = false;
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(iter->first, iter->second, m_numStackLevels);
|
||||
AZ_Error("Memory", false, "MEMORY STOMP DETECTED!!!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// operator()
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
bool
|
||||
PrintAllocationsCB::operator()(void* address, const AllocationInfo& info, unsigned char numStackLevels)
|
||||
{
|
||||
if (m_includeNameAndFilename && info.m_name)
|
||||
//=========================================================================
|
||||
// IntegrityCheck
|
||||
// [9/9/2011]
|
||||
//=========================================================================
|
||||
void AllocationRecords::IntegrityCheck() const
|
||||
{
|
||||
AZ_Printf("Memory", "Allocation Name: \"%s\" Addr: 0%p Size: %d Alignment: %d\n", info.m_name, address, info.m_byteSize, info.m_alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Printf("Memory", "Allocation Addr: 0%p Size: %d Alignment: %d\n", address, info.m_byteSize, info.m_alignment);
|
||||
}
|
||||
|
||||
if (m_isDetailed)
|
||||
{
|
||||
if (!info.m_stackFrames)
|
||||
#if defined(ENABLE_MEMORY_GUARD)
|
||||
if (m_memoryGuardSize == sizeof(Debug::GuardValue))
|
||||
{
|
||||
AZ_Printf("Memory", " %s (%d)\n", info.m_fileName, info.m_lineNum);
|
||||
Debug::AllocationRecordsType recordsCopy;
|
||||
{
|
||||
AZStd::scoped_lock lock(m_recordsMutex);
|
||||
recordsCopy = m_records;
|
||||
}
|
||||
for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
|
||||
{
|
||||
// check memory guard
|
||||
const char* guardAddress = reinterpret_cast<const char*>(iter->first) + iter->second.m_byteSize;
|
||||
if (!reinterpret_cast<const Debug::GuardValue*>(guardAddress)->Validate())
|
||||
{
|
||||
// We have to turn off the integrity check at this point if we want to succesfully report the memory
|
||||
// stomp we just found. If we don't turn this off, the printf just winds off the stack as each memory
|
||||
// allocation done therein recurses this same code.
|
||||
*const_cast<bool*>(&m_isAutoIntegrityCheck) = false;
|
||||
AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
|
||||
PrintAllocationsCB printAlloc(true);
|
||||
printAlloc(iter->first, iter->second, m_numStackLevels);
|
||||
AZ_Error("Memory", false, "MEMORY STOMP DETECTED!!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// operator()
|
||||
// [9/29/2009]
|
||||
//=========================================================================
|
||||
bool PrintAllocationsCB::operator()(void* address, const AllocationInfo& info, unsigned char numStackLevels)
|
||||
{
|
||||
if (m_includeNameAndFilename && info.m_name)
|
||||
{
|
||||
AZ_Printf(
|
||||
"Memory", "Allocation Name: \"%s\" Addr: 0%p Size: %d Alignment: %d\n", info.m_name, address, info.m_byteSize,
|
||||
info.m_alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allocation callstack
|
||||
const unsigned char decodeStep = 40;
|
||||
Debug::SymbolStorage::StackLine lines[decodeStep];
|
||||
unsigned char iFrame = 0;
|
||||
while (numStackLevels>0)
|
||||
AZ_Printf("Memory", "Allocation Addr: 0%p Size: %d Alignment: %d\n", address, info.m_byteSize, info.m_alignment);
|
||||
}
|
||||
|
||||
if (m_isDetailed)
|
||||
{
|
||||
if (!info.m_stackFrames)
|
||||
{
|
||||
unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
|
||||
Debug::SymbolStorage::DecodeFrames(&info.m_stackFrames[iFrame], numToDecode, lines);
|
||||
for (unsigned char i = 0; i < numToDecode; ++i)
|
||||
AZ_Printf("Memory", " %s (%d)\n", info.m_fileName, info.m_lineNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allocation callstack
|
||||
const unsigned char decodeStep = 40;
|
||||
Debug::SymbolStorage::StackLine lines[decodeStep];
|
||||
unsigned char iFrame = 0;
|
||||
while (numStackLevels > 0)
|
||||
{
|
||||
if (info.m_stackFrames[iFrame+i].IsValid())
|
||||
unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
|
||||
Debug::SymbolStorage::DecodeFrames(&info.m_stackFrames[iFrame], numToDecode, lines);
|
||||
for (unsigned char i = 0; i < numToDecode; ++i)
|
||||
{
|
||||
AZ_Printf("Memory", " %s\n", lines[i]);
|
||||
if (info.m_stackFrames[iFrame + i].IsValid())
|
||||
{
|
||||
AZ_Printf("Memory", " %s\n", lines[i]);
|
||||
}
|
||||
}
|
||||
numStackLevels -= numToDecode;
|
||||
iFrame += numToDecode;
|
||||
}
|
||||
numStackLevels -= numToDecode;
|
||||
iFrame += numToDecode;
|
||||
}
|
||||
}
|
||||
return true; // continue enumerating
|
||||
}
|
||||
return true; // continue enumerating
|
||||
}
|
||||
|
||||
} // namespace AZ::Debug
|
||||
|
||||
@@ -6,194 +6,203 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Memory/AllocatorManager.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
AllocatorBase::AllocatorBase(IAllocatorAllocate* allocationSource, const char* name, const char* desc) :
|
||||
IAllocator(allocationSource),
|
||||
m_name(name),
|
||||
m_desc(desc)
|
||||
namespace AZ
|
||||
{
|
||||
}
|
||||
|
||||
AllocatorBase::~AllocatorBase()
|
||||
{
|
||||
AZ_Assert(!m_isReady, "Allocator %s (%s) is being destructed without first having gone through proper calls to PreDestroy() and Destroy(). Use AllocatorInstance<> for global allocators or AllocatorWrapper<> for local allocators.", m_name, m_desc);
|
||||
}
|
||||
|
||||
const char* AllocatorBase::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const char* AllocatorBase::GetDescription() const
|
||||
{
|
||||
return m_desc;
|
||||
}
|
||||
|
||||
IAllocatorAllocate* AllocatorBase::GetSchema()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Debug::AllocationRecords* AllocatorBase::GetRecords()
|
||||
{
|
||||
return m_records;
|
||||
}
|
||||
|
||||
void AllocatorBase::SetRecords(Debug::AllocationRecords* records)
|
||||
{
|
||||
m_records = records;
|
||||
m_memoryGuardSize = records ? records->MemoryGuardSize() : 0;
|
||||
}
|
||||
|
||||
bool AllocatorBase::IsReady() const
|
||||
{
|
||||
return m_isReady;
|
||||
}
|
||||
|
||||
bool AllocatorBase::CanBeOverridden() const
|
||||
{
|
||||
return m_canBeOverridden;
|
||||
}
|
||||
|
||||
void AllocatorBase::PostCreate()
|
||||
{
|
||||
if (m_registrationEnabled)
|
||||
AllocatorBase::AllocatorBase(IAllocatorAllocate* allocationSource, const char* name, const char* desc)
|
||||
: IAllocator(allocationSource)
|
||||
, m_name(name)
|
||||
, m_desc(desc)
|
||||
{
|
||||
if (AZ::Environment::IsReady())
|
||||
}
|
||||
|
||||
AllocatorBase::~AllocatorBase()
|
||||
{
|
||||
AZ_Assert(
|
||||
!m_isReady,
|
||||
"Allocator %s (%s) is being destructed without first having gone through proper calls to PreDestroy() and Destroy(). Use "
|
||||
"AllocatorInstance<> for global allocators or AllocatorWrapper<> for local allocators.",
|
||||
m_name, m_desc);
|
||||
}
|
||||
|
||||
const char* AllocatorBase::GetName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const char* AllocatorBase::GetDescription() const
|
||||
{
|
||||
return m_desc;
|
||||
}
|
||||
|
||||
IAllocatorAllocate* AllocatorBase::GetSchema()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Debug::AllocationRecords* AllocatorBase::GetRecords()
|
||||
{
|
||||
return m_records;
|
||||
}
|
||||
|
||||
void AllocatorBase::SetRecords(Debug::AllocationRecords* records)
|
||||
{
|
||||
m_records = records;
|
||||
m_memoryGuardSize = records ? records->MemoryGuardSize() : 0;
|
||||
}
|
||||
|
||||
bool AllocatorBase::IsReady() const
|
||||
{
|
||||
return m_isReady;
|
||||
}
|
||||
|
||||
bool AllocatorBase::CanBeOverridden() const
|
||||
{
|
||||
return m_canBeOverridden;
|
||||
}
|
||||
|
||||
void AllocatorBase::PostCreate()
|
||||
{
|
||||
if (m_registrationEnabled)
|
||||
{
|
||||
AllocatorManager::Instance().RegisterAllocator(this);
|
||||
if (AZ::Environment::IsReady())
|
||||
{
|
||||
AllocatorManager::Instance().RegisterAllocator(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
AllocatorManager::PreRegisterAllocator(this);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
const auto debugConfig = GetDebugConfig();
|
||||
if (!debugConfig.m_excludeFromDebugging)
|
||||
{
|
||||
AllocatorManager::PreRegisterAllocator(this);
|
||||
SetRecords(aznew Debug::AllocationRecords(
|
||||
(unsigned char)debugConfig.m_stackRecordLevels, debugConfig.m_usesMemoryGuards, debugConfig.m_marksUnallocatedMemory,
|
||||
GetName()));
|
||||
}
|
||||
|
||||
m_isReady = true;
|
||||
}
|
||||
|
||||
const auto debugConfig = GetDebugConfig();
|
||||
if (!debugConfig.m_excludeFromDebugging)
|
||||
void AllocatorBase::PreDestroy()
|
||||
{
|
||||
SetRecords(aznew Debug::AllocationRecords((unsigned char)debugConfig.m_stackRecordLevels, debugConfig.m_usesMemoryGuards, debugConfig.m_marksUnallocatedMemory, GetName()));
|
||||
Debug::AllocationRecords* allocatorRecords = GetRecords();
|
||||
if (allocatorRecords)
|
||||
{
|
||||
delete allocatorRecords;
|
||||
SetRecords(nullptr);
|
||||
}
|
||||
|
||||
if (m_registrationEnabled && AZ::AllocatorManager::IsReady())
|
||||
{
|
||||
AllocatorManager::Instance().UnRegisterAllocator(this);
|
||||
}
|
||||
|
||||
m_isReady = false;
|
||||
}
|
||||
|
||||
m_isReady = true;
|
||||
}
|
||||
|
||||
void AllocatorBase::PreDestroy()
|
||||
{
|
||||
Debug::AllocationRecords* allocatorRecords = GetRecords();
|
||||
if(allocatorRecords)
|
||||
void AllocatorBase::SetLazilyCreated(bool lazy)
|
||||
{
|
||||
delete allocatorRecords;
|
||||
SetRecords(nullptr);
|
||||
m_isLazilyCreated = lazy;
|
||||
}
|
||||
|
||||
if (m_registrationEnabled && AZ::AllocatorManager::IsReady())
|
||||
bool AllocatorBase::IsLazilyCreated() const
|
||||
{
|
||||
AllocatorManager::Instance().UnRegisterAllocator(this);
|
||||
return m_isLazilyCreated;
|
||||
}
|
||||
|
||||
m_isReady = false;
|
||||
}
|
||||
void AllocatorBase::SetProfilingActive(bool active)
|
||||
{
|
||||
m_isProfilingActive = active;
|
||||
}
|
||||
|
||||
void AllocatorBase::SetLazilyCreated(bool lazy)
|
||||
{
|
||||
m_isLazilyCreated = lazy;
|
||||
}
|
||||
bool AllocatorBase::IsProfilingActive() const
|
||||
{
|
||||
return m_isProfilingActive;
|
||||
}
|
||||
|
||||
bool AllocatorBase::IsLazilyCreated() const
|
||||
{
|
||||
return m_isLazilyCreated;
|
||||
}
|
||||
void AllocatorBase::DisableOverriding()
|
||||
{
|
||||
m_canBeOverridden = false;
|
||||
}
|
||||
|
||||
void AllocatorBase::SetProfilingActive(bool active)
|
||||
{
|
||||
m_isProfilingActive = active;
|
||||
}
|
||||
void AllocatorBase::DisableRegistration()
|
||||
{
|
||||
m_registrationEnabled = false;
|
||||
}
|
||||
|
||||
bool AllocatorBase::IsProfilingActive() const
|
||||
{
|
||||
return m_isProfilingActive;
|
||||
}
|
||||
|
||||
void AllocatorBase::DisableOverriding()
|
||||
{
|
||||
m_canBeOverridden = false;
|
||||
}
|
||||
|
||||
void AllocatorBase::DisableRegistration()
|
||||
{
|
||||
m_registrationEnabled = false;
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileAllocation(void* ptr, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, int suppressStackRecord)
|
||||
{
|
||||
void AllocatorBase::ProfileAllocation(
|
||||
void* ptr, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, int suppressStackRecord)
|
||||
{
|
||||
#if defined(AZ_HAS_VARIADIC_TEMPLATES) && defined(AZ_DEBUG_BUILD)
|
||||
++suppressStackRecord; // one more for the fact the ebus is a function
|
||||
++suppressStackRecord; // one more for the fact the ebus is a function
|
||||
#endif // AZ_HAS_VARIADIC_TEMPLATES
|
||||
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
records->RegisterAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->RegisterAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileDeallocation(void* ptr, size_t byteSize, size_t alignment, Debug::AllocationInfo* info)
|
||||
{
|
||||
if (m_isProfilingActive)
|
||||
void AllocatorBase::ProfileDeallocation(void* ptr, size_t byteSize, size_t alignment, Debug::AllocationInfo* info)
|
||||
{
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
records->UnregisterAllocation(ptr, byteSize, alignment, info);
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->UnregisterAllocation(ptr, byteSize, alignment, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocationBegin([[maybe_unused]] void* ptr, [[maybe_unused]] size_t newSize)
|
||||
{
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocationEnd(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
if (m_isProfilingActive)
|
||||
void AllocatorBase::ProfileReallocationBegin([[maybe_unused]] void* ptr, [[maybe_unused]] size_t newSize)
|
||||
{
|
||||
Debug::AllocationInfo info;
|
||||
ProfileDeallocation(ptr, 0, 0, &info);
|
||||
ProfileAllocation(newPtr, newSize, newAlignment, info.m_name, info.m_fileName, info.m_lineNum, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileReallocation(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment);
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileResize(void* ptr, size_t newSize)
|
||||
{
|
||||
if (newSize && m_isProfilingActive)
|
||||
void AllocatorBase::ProfileReallocationEnd(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
if (m_isProfilingActive)
|
||||
{
|
||||
records->ResizeAllocation(ptr, newSize);
|
||||
Debug::AllocationInfo info;
|
||||
ProfileDeallocation(ptr, 0, 0, &info);
|
||||
ProfileAllocation(newPtr, newSize, newAlignment, info.m_name, info.m_fileName, info.m_lineNum, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AllocatorBase::OnOutOfMemory(size_t byteSize, size_t alignment, int flags, const char* name, const char* fileName, int lineNum)
|
||||
{
|
||||
if (AllocatorManager::IsReady() && AllocatorManager::Instance().m_outOfMemoryListener)
|
||||
void AllocatorBase::ProfileReallocation(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
|
||||
{
|
||||
AllocatorManager::Instance().m_outOfMemoryListener(this, byteSize, alignment, flags, name, fileName, lineNum);
|
||||
return true;
|
||||
ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AllocatorBase::ProfileResize(void* ptr, size_t newSize)
|
||||
{
|
||||
if (newSize && m_isProfilingActive)
|
||||
{
|
||||
auto records = GetRecords();
|
||||
if (records)
|
||||
{
|
||||
records->ResizeAllocation(ptr, newSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AllocatorBase::OnOutOfMemory(size_t byteSize, size_t alignment, int flags, const char* name, const char* fileName, int lineNum)
|
||||
{
|
||||
if (AllocatorManager::IsReady() && AllocatorManager::Instance().m_outOfMemoryListener)
|
||||
{
|
||||
AllocatorManager::Instance().m_outOfMemoryListener(this, byteSize, alignment, flags, name, fileName, lineNum);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
@@ -13,186 +13,182 @@
|
||||
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
//=========================================================================
|
||||
// BestFitExternalMapAllocator
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::BestFitExternalMapAllocator()
|
||||
: AllocatorBase(this, "BestFitExternalMapAllocator", "Best fit allocator with external tracking storage!")
|
||||
, m_schema(nullptr)
|
||||
{}
|
||||
|
||||
//=========================================================================
|
||||
// Create
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
bool
|
||||
BestFitExternalMapAllocator::Create(const Descriptor& desc)
|
||||
namespace AZ
|
||||
{
|
||||
AZ_Assert(IsReady() == false, "BestFitExternalMapAllocator was already created!");
|
||||
if (IsReady())
|
||||
//=========================================================================
|
||||
// BestFitExternalMapAllocator
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::BestFitExternalMapAllocator()
|
||||
: AllocatorBase(this, "BestFitExternalMapAllocator", "Best fit allocator with external tracking storage!")
|
||||
, m_schema(nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isReady = true;
|
||||
|
||||
m_desc = desc;
|
||||
BestFitExternalMapSchema::Descriptor schemaDesc;
|
||||
schemaDesc.m_mapAllocator = desc.m_mapAllocator;
|
||||
schemaDesc.m_memoryBlock = desc.m_memoryBlock;
|
||||
schemaDesc.m_memoryBlockByteSize = desc.m_memoryBlockByteSize;
|
||||
|
||||
m_schema = azcreate(BestFitExternalMapSchema, (schemaDesc), SystemAllocator);
|
||||
if (m_schema == nullptr)
|
||||
//=========================================================================
|
||||
// Create
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
bool BestFitExternalMapAllocator::Create(const Descriptor& desc)
|
||||
{
|
||||
isReady = false;
|
||||
AZ_Assert(IsReady() == false, "BestFitExternalMapAllocator was already created!");
|
||||
if (IsReady())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isReady = true;
|
||||
|
||||
m_desc = desc;
|
||||
BestFitExternalMapSchema::Descriptor schemaDesc;
|
||||
schemaDesc.m_mapAllocator = desc.m_mapAllocator;
|
||||
schemaDesc.m_memoryBlock = desc.m_memoryBlock;
|
||||
schemaDesc.m_memoryBlockByteSize = desc.m_memoryBlockByteSize;
|
||||
|
||||
m_schema = azcreate(BestFitExternalMapSchema, (schemaDesc), SystemAllocator);
|
||||
if (m_schema == nullptr)
|
||||
{
|
||||
isReady = false;
|
||||
}
|
||||
|
||||
return isReady;
|
||||
}
|
||||
|
||||
return isReady;
|
||||
}
|
||||
//=========================================================================
|
||||
// Destroy
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void BestFitExternalMapAllocator::Destroy()
|
||||
{
|
||||
azdestroy(m_schema, SystemAllocator);
|
||||
m_schema = nullptr;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Destroy
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
BestFitExternalMapAllocator::Destroy()
|
||||
{
|
||||
azdestroy(m_schema, SystemAllocator);
|
||||
m_schema = nullptr;
|
||||
}
|
||||
AllocatorDebugConfig BestFitExternalMapAllocator::GetDebugConfig()
|
||||
{
|
||||
return AllocatorDebugConfig()
|
||||
.ExcludeFromDebugging(!m_desc.m_allocationRecords)
|
||||
.StackRecordLevels(m_desc.m_stackRecordLevels)
|
||||
.MarksUnallocatedMemory(false)
|
||||
.UsesMemoryGuards(false);
|
||||
}
|
||||
|
||||
AllocatorDebugConfig BestFitExternalMapAllocator::GetDebugConfig()
|
||||
{
|
||||
return AllocatorDebugConfig()
|
||||
.ExcludeFromDebugging(!m_desc.m_allocationRecords)
|
||||
.StackRecordLevels(m_desc.m_stackRecordLevels)
|
||||
.MarksUnallocatedMemory(false)
|
||||
.UsesMemoryGuards(false);
|
||||
}
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::Allocate(
|
||||
size_type byteSize,
|
||||
size_type alignment,
|
||||
int flags,
|
||||
[[maybe_unused]] const char* name,
|
||||
[[maybe_unused]] const char* fileName,
|
||||
[[maybe_unused]] int lineNum,
|
||||
unsigned int suppressStackRecord)
|
||||
{
|
||||
(void)suppressStackRecord;
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::Allocate(
|
||||
size_type byteSize,
|
||||
size_type alignment,
|
||||
int flags,
|
||||
[[maybe_unused]] const char* name,
|
||||
[[maybe_unused]] const char* fileName,
|
||||
[[maybe_unused]] int lineNum,
|
||||
unsigned int suppressStackRecord)
|
||||
{
|
||||
(void)suppressStackRecord;
|
||||
AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
|
||||
AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
|
||||
AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
|
||||
AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
BestFitExternalMapAllocator::pointer_type address = m_schema->Allocate(byteSize, alignment, flags);
|
||||
AZ_Assert(
|
||||
address != nullptr, "BestFitExternalMapAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!",
|
||||
byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
|
||||
|
||||
BestFitExternalMapAllocator::pointer_type address = m_schema->Allocate(byteSize, alignment, flags);
|
||||
AZ_Assert(address != nullptr, "BestFitExternalMapAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!", byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
|
||||
return address;
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void BestFitExternalMapAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
|
||||
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
BestFitExternalMapAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
|
||||
(void)byteSize;
|
||||
(void)alignment;
|
||||
m_schema->DeAllocate(ptr);
|
||||
}
|
||||
|
||||
(void)byteSize;
|
||||
(void)alignment;
|
||||
m_schema->DeAllocate(ptr);
|
||||
}
|
||||
//=========================================================================
|
||||
// Resize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::Resize(pointer_type ptr, size_type newSize)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)newSize;
|
||||
/* todo */
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Resize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::Resize(pointer_type ptr, size_type newSize)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)newSize;
|
||||
/* todo */
|
||||
return 0;
|
||||
}
|
||||
//=========================================================================
|
||||
// ReAllocate
|
||||
// [9/13/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::ReAllocate(
|
||||
pointer_type ptr, size_type newSize, size_type newAlignment)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)newSize;
|
||||
(void)newAlignment;
|
||||
AZ_Assert(false, "Not supported!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReAllocate
|
||||
// [9/13/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::pointer_type
|
||||
BestFitExternalMapAllocator::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)newSize;
|
||||
(void)newAlignment;
|
||||
AZ_Assert(false, "Not supported!");
|
||||
return nullptr;
|
||||
}
|
||||
//=========================================================================
|
||||
// AllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
return MemorySizeAdjustedDown(m_schema->AllocationSize(ptr));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
return MemorySizeAdjustedDown(m_schema->AllocationSize(ptr));
|
||||
}
|
||||
//=========================================================================
|
||||
// NumAllocatedBytes
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::NumAllocatedBytes() const
|
||||
{
|
||||
return m_schema->NumAllocatedBytes();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// NumAllocatedBytes
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::NumAllocatedBytes() const
|
||||
{
|
||||
return m_schema->NumAllocatedBytes();
|
||||
}
|
||||
//=========================================================================
|
||||
// Capacity
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::Capacity() const
|
||||
{
|
||||
return m_schema->Capacity();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Capacity
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::Capacity() const
|
||||
{
|
||||
return m_schema->Capacity();
|
||||
}
|
||||
//=========================================================================
|
||||
// GetMaxAllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::GetMaxAllocationSize() const
|
||||
{
|
||||
return m_schema->GetMaxAllocationSize();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetMaxAllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapAllocator::size_type
|
||||
BestFitExternalMapAllocator::GetMaxAllocationSize() const
|
||||
{
|
||||
return m_schema->GetMaxAllocationSize();
|
||||
}
|
||||
auto BestFitExternalMapAllocator::GetMaxContiguousAllocationSize() const -> size_type
|
||||
{
|
||||
return m_schema->GetMaxContiguousAllocationSize();
|
||||
}
|
||||
|
||||
auto BestFitExternalMapAllocator::GetMaxContiguousAllocationSize() const -> size_type
|
||||
{
|
||||
return m_schema->GetMaxContiguousAllocationSize();
|
||||
}
|
||||
//=========================================================================
|
||||
// GetSubAllocator
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
IAllocatorAllocate* BestFitExternalMapAllocator::GetSubAllocator()
|
||||
{
|
||||
return m_schema->GetSubAllocator();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetSubAllocator
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
IAllocatorAllocate*
|
||||
BestFitExternalMapAllocator::GetSubAllocator()
|
||||
{
|
||||
return m_schema->GetSubAllocator();
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#ifndef AZ_BEST_FIT_EXT_MAP_ALLOCATOR_H
|
||||
#define AZ_BEST_FIT_EXT_MAP_ALLOCATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
|
||||
@@ -76,7 +75,3 @@ namespace AZ
|
||||
};
|
||||
}
|
||||
|
||||
#endif // AZ_BEST_FIT_EXT_MAP_ALLOCATOR_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
@@ -9,194 +9,199 @@
|
||||
#include <AzCore/Memory/BestFitExternalMapSchema.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
//=========================================================================
|
||||
// BestFitExternalMapSchema
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::BestFitExternalMapSchema(const Descriptor& desc)
|
||||
: m_desc(desc)
|
||||
, m_used(0)
|
||||
, m_freeChunksMap(FreeMapType::key_compare(), AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance<SystemAllocator>::Get()))
|
||||
, m_allocChunksMap(AllocMapType::hasher(), AllocMapType::key_eq(), AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance<SystemAllocator>::Get()))
|
||||
namespace AZ
|
||||
{
|
||||
if (m_desc.m_mapAllocator == nullptr)
|
||||
//=========================================================================
|
||||
// BestFitExternalMapSchema
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::BestFitExternalMapSchema(const Descriptor& desc)
|
||||
: m_desc(desc)
|
||||
, m_used(0)
|
||||
, m_freeChunksMap(
|
||||
FreeMapType::key_compare(),
|
||||
AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance<SystemAllocator>::Get()))
|
||||
, m_allocChunksMap(
|
||||
AllocMapType::hasher(),
|
||||
AllocMapType::key_eq(),
|
||||
AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance<SystemAllocator>::Get()))
|
||||
{
|
||||
m_desc.m_mapAllocator = &AllocatorInstance<SystemAllocator>::Get(); // used as our sub allocator
|
||||
}
|
||||
AZ_Assert(m_desc.m_memoryBlockByteSize > 0, "You must provide memory block size!");
|
||||
AZ_Assert(m_desc.m_memoryBlock != nullptr, "You must provide memory block allocated as you with!");
|
||||
//if( m_desc.m_memoryBlock == NULL) there is no point to automate this cause we need to flag this memory special, otherwise there is no point to use this allocator at all
|
||||
// m_desc.m_memoryBlock = azmalloc(SystemAllocator,m_desc.m_memoryBlockByteSize,16);
|
||||
m_freeChunksMap.insert(AZStd::make_pair(m_desc.m_memoryBlockByteSize, reinterpret_cast<char*>(m_desc.m_memoryBlock)));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::pointer_type
|
||||
BestFitExternalMapSchema::Allocate(size_type byteSize, size_type alignment, int flags)
|
||||
{
|
||||
(void)flags;
|
||||
char* address = nullptr;
|
||||
AZ_Assert(alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be >0 and power of 2!");
|
||||
for (int i = 0; i < 2; ++i) // max 2 attempts to allocate
|
||||
{
|
||||
FreeMapType::iterator iter = m_freeChunksMap.find(byteSize);
|
||||
size_t blockSize = 0;
|
||||
char* blockAddress = nullptr;
|
||||
size_t preAllocBlockSize = 0;
|
||||
while (iter != m_freeChunksMap.end())
|
||||
if (m_desc.m_mapAllocator == nullptr)
|
||||
{
|
||||
blockSize = iter->first;
|
||||
blockAddress = iter->second;
|
||||
char* alignedAddr = PointerAlignUp(blockAddress, alignment);
|
||||
preAllocBlockSize = alignedAddr - blockAddress;
|
||||
if (preAllocBlockSize + byteSize <= blockSize)
|
||||
{
|
||||
m_freeChunksMap.erase(iter); // we have our allocation
|
||||
m_used += byteSize;
|
||||
address = alignedAddr;
|
||||
m_allocChunksMap.insert(AZStd::make_pair(address, byteSize));
|
||||
break;
|
||||
}
|
||||
++iter;
|
||||
m_desc.m_mapAllocator = &AllocatorInstance<SystemAllocator>::Get(); // used as our sub allocator
|
||||
}
|
||||
if (address != nullptr)
|
||||
AZ_Assert(m_desc.m_memoryBlockByteSize > 0, "You must provide memory block size!");
|
||||
AZ_Assert(m_desc.m_memoryBlock != nullptr, "You must provide memory block allocated as you with!");
|
||||
// if( m_desc.m_memoryBlock == NULL) there is no point to automate this cause we need to flag this memory special, otherwise there
|
||||
// is no point to use this allocator at all
|
||||
// m_desc.m_memoryBlock = azmalloc(SystemAllocator,m_desc.m_memoryBlockByteSize,16);
|
||||
m_freeChunksMap.insert(AZStd::make_pair(m_desc.m_memoryBlockByteSize, reinterpret_cast<char*>(m_desc.m_memoryBlock)));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::pointer_type BestFitExternalMapSchema::Allocate(size_type byteSize, size_type alignment, int flags)
|
||||
{
|
||||
(void)flags;
|
||||
char* address = nullptr;
|
||||
AZ_Assert(alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be >0 and power of 2!");
|
||||
for (int i = 0; i < 2; ++i) // max 2 attempts to allocate
|
||||
{
|
||||
// split blocks
|
||||
if (preAllocBlockSize) // if we have a block before the alignment
|
||||
FreeMapType::iterator iter = m_freeChunksMap.find(byteSize);
|
||||
size_t blockSize = 0;
|
||||
char* blockAddress = nullptr;
|
||||
size_t preAllocBlockSize = 0;
|
||||
while (iter != m_freeChunksMap.end())
|
||||
{
|
||||
m_freeChunksMap.insert(AZStd::make_pair(preAllocBlockSize, blockAddress));
|
||||
}
|
||||
size_t postAllocBlockSize = blockSize - preAllocBlockSize - byteSize;
|
||||
if (postAllocBlockSize)
|
||||
{
|
||||
m_freeChunksMap.insert(AZStd::make_pair(postAllocBlockSize, address + byteSize));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
GarbageCollect();
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
BestFitExternalMapSchema::DeAllocate(pointer_type ptr)
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast<char*>(ptr));
|
||||
if (iter != m_allocChunksMap.end())
|
||||
{
|
||||
m_used -= iter->second;
|
||||
m_freeChunksMap.insert(AZStd::make_pair(iter->second, iter->first));
|
||||
m_allocChunksMap.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::size_type
|
||||
BestFitExternalMapSchema::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast<char*>(ptr));
|
||||
if (iter != m_allocChunksMap.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetMaxAllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::size_type
|
||||
BestFitExternalMapSchema::GetMaxAllocationSize() const
|
||||
{
|
||||
if (!m_freeChunksMap.empty())
|
||||
{
|
||||
return m_freeChunksMap.rbegin()->first;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto BestFitExternalMapSchema::GetMaxContiguousAllocationSize() const -> size_type
|
||||
{
|
||||
// Return the maximum size of any single allocation
|
||||
return AZ_CORE_MAX_ALLOCATOR_SIZE;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GarbageCollect
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void
|
||||
BestFitExternalMapSchema::GarbageCollect()
|
||||
{
|
||||
for (FreeMapType::iterator curBlock = m_freeChunksMap.begin(); curBlock != m_freeChunksMap.end(); )
|
||||
{
|
||||
char* curStart = curBlock->second;
|
||||
char* curEnd = curStart + curBlock->first;
|
||||
bool isMerge = false;
|
||||
for (FreeMapType::iterator nextBlock = curBlock++; nextBlock != m_freeChunksMap.end(); )
|
||||
{
|
||||
char* nextStart = nextBlock->second;
|
||||
char* nextEnd = nextStart + nextBlock->first;
|
||||
if (curStart == nextEnd)
|
||||
{
|
||||
// merge
|
||||
size_t newBlockSize = curBlock->first + nextBlock->first;
|
||||
char* newBlockAddress = nextStart;
|
||||
m_freeChunksMap.erase(nextBlock);
|
||||
FreeMapType::iterator toErase = curBlock;
|
||||
++curBlock;
|
||||
m_freeChunksMap.erase(toErase);
|
||||
FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
|
||||
if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first) // if the newBlock in before the next in the list, update next in the list to current
|
||||
blockSize = iter->first;
|
||||
blockAddress = iter->second;
|
||||
char* alignedAddr = PointerAlignUp(blockAddress, alignment);
|
||||
preAllocBlockSize = alignedAddr - blockAddress;
|
||||
if (preAllocBlockSize + byteSize <= blockSize)
|
||||
{
|
||||
curBlock = newBlock;
|
||||
m_freeChunksMap.erase(iter); // we have our allocation
|
||||
m_used += byteSize;
|
||||
address = alignedAddr;
|
||||
m_allocChunksMap.insert(AZStd::make_pair(address, byteSize));
|
||||
break;
|
||||
}
|
||||
isMerge = true;
|
||||
break;
|
||||
++iter;
|
||||
}
|
||||
else if (curEnd == nextStart)
|
||||
if (address != nullptr)
|
||||
{
|
||||
// merge
|
||||
size_t newBlockSize = curBlock->first + nextBlock->first;
|
||||
char* newBlockAddress = curStart;
|
||||
m_freeChunksMap.erase(nextBlock);
|
||||
FreeMapType::iterator toErase = curBlock;
|
||||
++curBlock;
|
||||
m_freeChunksMap.erase(toErase);
|
||||
FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
|
||||
if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first) // if the newBlock in before the next in the list, update next in the list to current
|
||||
// split blocks
|
||||
if (preAllocBlockSize) // if we have a block before the alignment
|
||||
{
|
||||
curBlock = newBlock;
|
||||
m_freeChunksMap.insert(AZStd::make_pair(preAllocBlockSize, blockAddress));
|
||||
}
|
||||
isMerge = true;
|
||||
size_t postAllocBlockSize = blockSize - preAllocBlockSize - byteSize;
|
||||
if (postAllocBlockSize)
|
||||
{
|
||||
m_freeChunksMap.insert(AZStd::make_pair(postAllocBlockSize, address + byteSize));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
++nextBlock;
|
||||
else
|
||||
{
|
||||
GarbageCollect();
|
||||
}
|
||||
}
|
||||
if (!isMerge)
|
||||
return address;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void BestFitExternalMapSchema::DeAllocate(pointer_type ptr)
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
++curBlock;
|
||||
return;
|
||||
}
|
||||
AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast<char*>(ptr));
|
||||
if (iter != m_allocChunksMap.end())
|
||||
{
|
||||
m_used -= iter->second;
|
||||
m_freeChunksMap.insert(AZStd::make_pair(iter->second, iter->first));
|
||||
m_allocChunksMap.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::size_type BestFitExternalMapSchema::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast<char*>(ptr));
|
||||
if (iter != m_allocChunksMap.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetMaxAllocationSize
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
BestFitExternalMapSchema::size_type BestFitExternalMapSchema::GetMaxAllocationSize() const
|
||||
{
|
||||
if (!m_freeChunksMap.empty())
|
||||
{
|
||||
return m_freeChunksMap.rbegin()->first;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto BestFitExternalMapSchema::GetMaxContiguousAllocationSize() const -> size_type
|
||||
{
|
||||
// Return the maximum size of any single allocation
|
||||
return AZ_CORE_MAX_ALLOCATOR_SIZE;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GarbageCollect
|
||||
// [1/28/2011]
|
||||
//=========================================================================
|
||||
void BestFitExternalMapSchema::GarbageCollect()
|
||||
{
|
||||
for (FreeMapType::iterator curBlock = m_freeChunksMap.begin(); curBlock != m_freeChunksMap.end();)
|
||||
{
|
||||
char* curStart = curBlock->second;
|
||||
char* curEnd = curStart + curBlock->first;
|
||||
bool isMerge = false;
|
||||
for (FreeMapType::iterator nextBlock = curBlock++; nextBlock != m_freeChunksMap.end();)
|
||||
{
|
||||
char* nextStart = nextBlock->second;
|
||||
char* nextEnd = nextStart + nextBlock->first;
|
||||
if (curStart == nextEnd)
|
||||
{
|
||||
// merge
|
||||
size_t newBlockSize = curBlock->first + nextBlock->first;
|
||||
char* newBlockAddress = nextStart;
|
||||
m_freeChunksMap.erase(nextBlock);
|
||||
FreeMapType::iterator toErase = curBlock;
|
||||
++curBlock;
|
||||
m_freeChunksMap.erase(toErase);
|
||||
FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
|
||||
// if the newBlock in before the next in the list, update next in the list to current
|
||||
if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first)
|
||||
{
|
||||
curBlock = newBlock;
|
||||
}
|
||||
isMerge = true;
|
||||
break;
|
||||
}
|
||||
else if (curEnd == nextStart)
|
||||
{
|
||||
// merge
|
||||
size_t newBlockSize = curBlock->first + nextBlock->first;
|
||||
char* newBlockAddress = curStart;
|
||||
m_freeChunksMap.erase(nextBlock);
|
||||
FreeMapType::iterator toErase = curBlock;
|
||||
++curBlock;
|
||||
m_freeChunksMap.erase(toErase);
|
||||
FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
|
||||
// if the newBlock in before the next in the list, update next in the list to current
|
||||
if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first)
|
||||
{
|
||||
curBlock = newBlock;
|
||||
}
|
||||
isMerge = true;
|
||||
break;
|
||||
}
|
||||
++nextBlock;
|
||||
}
|
||||
if (!isMerge)
|
||||
{
|
||||
++curBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#ifndef AZ_BEST_FIT_EXT_MAP_ALLOCATION_SCHEME_H
|
||||
#define AZ_BEST_FIT_EXT_MAP_ALLOCATION_SCHEME_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
@@ -77,8 +76,3 @@ namespace AZ
|
||||
AllocMapType m_allocChunksMap;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // AZ_BEST_FIT_EXT_MAP_ALLOCATION_SCHEME_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,8 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#ifndef AZ_POOL_ALLOCATION_SCHEME_H
|
||||
#define AZ_POOL_ALLOCATION_SCHEME_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
@@ -164,8 +163,3 @@ namespace AZ
|
||||
template<class Allocator>
|
||||
AZ_THREAD_LOCAL ThreadPoolData* ThreadPoolSchemaHelper<Allocator>::m_threadData = 0;
|
||||
}
|
||||
|
||||
#endif // AZ_POOL_ALLOCATION_SCHEME_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#define AZCORE_SYSTEM_ALLOCATOR_HEAP 3
|
||||
|
||||
#if !defined(AZCORE_SYSTEM_ALLOCATOR)
|
||||
// define the default
|
||||
#define AZCORE_SYSTEM_ALLOCATOR AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
// define the default
|
||||
#define AZCORE_SYSTEM_ALLOCATOR AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
#endif
|
||||
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
@@ -35,12 +35,11 @@
|
||||
#error "Invalid allocator selected for SystemAllocator"
|
||||
#endif
|
||||
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Globals - we use global storage for the first memory schema, since we can't use dynamic memory!
|
||||
static bool g_isSystemSchemaUsed = false;
|
||||
namespace AZ
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Globals - we use global storage for the first memory schema, since we can't use dynamic memory!
|
||||
static bool g_isSystemSchemaUsed = false;
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
static AZStd::aligned_storage<sizeof(HphaSchema), AZStd::alignment_of<HphaSchema>::value>::type g_systemSchema;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
@@ -49,268 +48,275 @@ static bool g_isSystemSchemaUsed = false;
|
||||
static AZStd::aligned_storage<sizeof(HeapSchema), AZStd::alignment_of<HeapSchema>::value>::type g_systemSchema;
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//=========================================================================
|
||||
// SystemAllocator
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
SystemAllocator::SystemAllocator()
|
||||
: AllocatorBase(this, "SystemAllocator", "Fundamental generic memory allocator")
|
||||
, m_isCustom(false)
|
||||
, m_allocator(nullptr)
|
||||
, m_ownsOSAllocator(false)
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~SystemAllocator
|
||||
//=========================================================================
|
||||
SystemAllocator::~SystemAllocator()
|
||||
{
|
||||
if (IsReady())
|
||||
//=========================================================================
|
||||
// SystemAllocator
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
SystemAllocator::SystemAllocator()
|
||||
: AllocatorBase(this, "SystemAllocator", "Fundamental generic memory allocator")
|
||||
, m_isCustom(false)
|
||||
, m_allocator(nullptr)
|
||||
, m_ownsOSAllocator(false)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~Create
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
bool
|
||||
SystemAllocator::Create(const Descriptor& desc)
|
||||
{
|
||||
AZ_Assert(IsReady() == false, "System allocator was already created!");
|
||||
if (IsReady())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_desc = desc;
|
||||
|
||||
if (!AllocatorInstance<OSAllocator>::IsReady())
|
||||
//=========================================================================
|
||||
// ~SystemAllocator
|
||||
//=========================================================================
|
||||
SystemAllocator::~SystemAllocator()
|
||||
{
|
||||
m_ownsOSAllocator = true;
|
||||
AllocatorInstance<OSAllocator>::Create();
|
||||
}
|
||||
bool isReady = false;
|
||||
if (desc.m_custom)
|
||||
{
|
||||
m_isCustom = true;
|
||||
m_allocator = desc.m_custom;
|
||||
isReady = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_isCustom = false;
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
HphaSchema::Descriptor heapDesc;
|
||||
heapDesc.m_pageSize = desc.m_heap.m_pageSize;
|
||||
heapDesc.m_poolPageSize = desc.m_heap.m_poolPageSize;
|
||||
AZ_Assert(desc.m_heap.m_numFixedMemoryBlocks <= 1, "We support max1 memory block at the moment!");
|
||||
if (desc.m_heap.m_numFixedMemoryBlocks > 0)
|
||||
if (IsReady())
|
||||
{
|
||||
heapDesc.m_fixedMemoryBlock = desc.m_heap.m_fixedMemoryBlocks[0];
|
||||
heapDesc.m_fixedMemoryBlockByteSize = desc.m_heap.m_fixedMemoryBlocksByteSize[0];
|
||||
Destroy();
|
||||
}
|
||||
heapDesc.m_subAllocator = desc.m_heap.m_subAllocator;
|
||||
heapDesc.m_isPoolAllocations = desc.m_heap.m_isPoolAllocations;
|
||||
// Fix SystemAllocator from growing in small chunks
|
||||
heapDesc.m_systemChunkSize = desc.m_heap.m_systemChunkSize;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
MallocSchema::Descriptor heapDesc;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
HeapSchema::Descriptor heapDesc;
|
||||
memcpy(heapDesc.m_memoryBlocks, desc.m_heap.m_memoryBlocks, sizeof(heapDesc.m_memoryBlocks));
|
||||
memcpy(heapDesc.m_memoryBlocksByteSize, desc.m_heap.m_memoryBlocksByteSize, sizeof(heapDesc.m_memoryBlocksByteSize));
|
||||
heapDesc.m_numMemoryBlocks = desc.m_heap.m_numMemoryBlocks;
|
||||
#endif
|
||||
if (&AllocatorInstance<SystemAllocator>::Get() == this) // if we are the system allocator
|
||||
{
|
||||
AZ_Assert(!g_isSystemSchemaUsed, "AZ::SystemAllocator MUST be created first! It's the source of all allocations!");
|
||||
}
|
||||
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
m_allocator = new(&g_systemSchema)HphaSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
m_allocator = new(&g_systemSchema)MallocSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
m_allocator = new(&g_systemSchema)HeapSchema(heapDesc);
|
||||
#endif
|
||||
g_isSystemSchemaUsed = true;
|
||||
//=========================================================================
|
||||
// ~Create
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
bool SystemAllocator::Create(const Descriptor& desc)
|
||||
{
|
||||
AZ_Assert(IsReady() == false, "System allocator was already created!");
|
||||
if (IsReady())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_desc = desc;
|
||||
|
||||
if (!AllocatorInstance<OSAllocator>::IsReady())
|
||||
{
|
||||
m_ownsOSAllocator = true;
|
||||
AllocatorInstance<OSAllocator>::Create();
|
||||
}
|
||||
bool isReady = false;
|
||||
if (desc.m_custom)
|
||||
{
|
||||
m_isCustom = true;
|
||||
m_allocator = desc.m_custom;
|
||||
isReady = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this class should be inheriting from SystemAllocator
|
||||
AZ_Assert(AllocatorInstance<SystemAllocator>::IsReady(), "System allocator must be created before any other allocator! They allocate from it.");
|
||||
m_isCustom = false;
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
HphaSchema::Descriptor heapDesc;
|
||||
heapDesc.m_pageSize = desc.m_heap.m_pageSize;
|
||||
heapDesc.m_poolPageSize = desc.m_heap.m_poolPageSize;
|
||||
AZ_Assert(desc.m_heap.m_numFixedMemoryBlocks <= 1, "We support max1 memory block at the moment!");
|
||||
if (desc.m_heap.m_numFixedMemoryBlocks > 0)
|
||||
{
|
||||
heapDesc.m_fixedMemoryBlock = desc.m_heap.m_fixedMemoryBlocks[0];
|
||||
heapDesc.m_fixedMemoryBlockByteSize = desc.m_heap.m_fixedMemoryBlocksByteSize[0];
|
||||
}
|
||||
heapDesc.m_subAllocator = desc.m_heap.m_subAllocator;
|
||||
heapDesc.m_isPoolAllocations = desc.m_heap.m_isPoolAllocations;
|
||||
// Fix SystemAllocator from growing in small chunks
|
||||
heapDesc.m_systemChunkSize = desc.m_heap.m_systemChunkSize;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
MallocSchema::Descriptor heapDesc;
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
HeapSchema::Descriptor heapDesc;
|
||||
memcpy(heapDesc.m_memoryBlocks, desc.m_heap.m_memoryBlocks, sizeof(heapDesc.m_memoryBlocks));
|
||||
memcpy(heapDesc.m_memoryBlocksByteSize, desc.m_heap.m_memoryBlocksByteSize, sizeof(heapDesc.m_memoryBlocksByteSize));
|
||||
heapDesc.m_numMemoryBlocks = desc.m_heap.m_numMemoryBlocks;
|
||||
#endif
|
||||
if (&AllocatorInstance<SystemAllocator>::Get() == this) // if we are the system allocator
|
||||
{
|
||||
AZ_Assert(!g_isSystemSchemaUsed, "AZ::SystemAllocator MUST be created first! It's the source of all allocations!");
|
||||
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
m_allocator = azcreate(HphaSchema, (heapDesc), SystemAllocator);
|
||||
m_allocator = new (&g_systemSchema) HphaSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
m_allocator = azcreate(MallocSchema, (heapDesc), SystemAllocator);
|
||||
m_allocator = new (&g_systemSchema) MallocSchema(heapDesc);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
m_allocator = azcreate(HeapSchema, (heapDesc), SystemAllocator);
|
||||
m_allocator = new (&g_systemSchema) HeapSchema(heapDesc);
|
||||
#endif
|
||||
if (m_allocator == nullptr)
|
||||
{
|
||||
isReady = false;
|
||||
g_isSystemSchemaUsed = true;
|
||||
isReady = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isReady = true;
|
||||
// this class should be inheriting from SystemAllocator
|
||||
AZ_Assert(
|
||||
AllocatorInstance<SystemAllocator>::IsReady(),
|
||||
"System allocator must be created before any other allocator! They allocate from it.");
|
||||
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
m_allocator = azcreate(HphaSchema, (heapDesc), SystemAllocator);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
m_allocator = azcreate(MallocSchema, (heapDesc), SystemAllocator);
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
m_allocator = azcreate(HeapSchema, (heapDesc), SystemAllocator);
|
||||
#endif
|
||||
if (m_allocator == nullptr)
|
||||
{
|
||||
isReady = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isReady;
|
||||
}
|
||||
|
||||
return isReady;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
SystemAllocator::Destroy()
|
||||
{
|
||||
if (g_isSystemSchemaUsed)
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
void SystemAllocator::Destroy()
|
||||
{
|
||||
int dummy;
|
||||
(void)dummy;
|
||||
}
|
||||
|
||||
if (!m_isCustom)
|
||||
{
|
||||
if ((void*)m_allocator == (void*)&g_systemSchema)
|
||||
if (g_isSystemSchemaUsed)
|
||||
{
|
||||
int dummy;
|
||||
(void)dummy;
|
||||
}
|
||||
|
||||
if (!m_isCustom)
|
||||
{
|
||||
if ((void*)m_allocator == (void*)&g_systemSchema)
|
||||
{
|
||||
#if AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HPHA
|
||||
static_cast<HphaSchema*>(m_allocator)->~HphaSchema();
|
||||
static_cast<HphaSchema*>(m_allocator)->~HphaSchema();
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_MALLOC
|
||||
static_cast<MallocSchema*>(m_allocator)->~MallocSchema();
|
||||
static_cast<MallocSchema*>(m_allocator)->~MallocSchema();
|
||||
#elif AZCORE_SYSTEM_ALLOCATOR == AZCORE_SYSTEM_ALLOCATOR_HEAP
|
||||
static_cast<HeapSchema*>(m_allocator)->~HeapSchema();
|
||||
static_cast<HeapSchema*>(m_allocator)->~HeapSchema();
|
||||
#endif
|
||||
g_isSystemSchemaUsed = false;
|
||||
g_isSystemSchemaUsed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
azdestroy(m_allocator);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (m_ownsOSAllocator)
|
||||
{
|
||||
azdestroy(m_allocator);
|
||||
AllocatorInstance<OSAllocator>::Destroy();
|
||||
m_ownsOSAllocator = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ownsOSAllocator)
|
||||
AllocatorDebugConfig SystemAllocator::GetDebugConfig()
|
||||
{
|
||||
AllocatorInstance<OSAllocator>::Destroy();
|
||||
m_ownsOSAllocator = false;
|
||||
}
|
||||
}
|
||||
|
||||
AllocatorDebugConfig SystemAllocator::GetDebugConfig()
|
||||
{
|
||||
return AllocatorDebugConfig()
|
||||
.StackRecordLevels(m_desc.m_stackRecordLevels)
|
||||
.UsesMemoryGuards(!m_isCustom)
|
||||
.MarksUnallocatedMemory(!m_isCustom)
|
||||
.ExcludeFromDebugging(!m_desc.m_allocationRecords);
|
||||
}
|
||||
|
||||
IAllocatorAllocate* SystemAllocator::GetSchema()
|
||||
{
|
||||
return m_allocator;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
SystemAllocator::pointer_type
|
||||
SystemAllocator::Allocate(size_type byteSize, size_type alignment, int flags, const char* name, const char* fileName, int lineNum, unsigned int suppressStackRecord)
|
||||
{
|
||||
if (byteSize == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
|
||||
AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
|
||||
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
SystemAllocator::pointer_type address = m_allocator->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
|
||||
if (address == nullptr)
|
||||
{
|
||||
// Free all memory we can and try again!
|
||||
AllocatorManager::Instance().GarbageCollect();
|
||||
|
||||
address = m_allocator->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
return AllocatorDebugConfig()
|
||||
.StackRecordLevels(m_desc.m_stackRecordLevels)
|
||||
.UsesMemoryGuards(!m_isCustom)
|
||||
.MarksUnallocatedMemory(!m_isCustom)
|
||||
.ExcludeFromDebugging(!m_desc.m_allocationRecords);
|
||||
}
|
||||
|
||||
if (address == nullptr)
|
||||
IAllocatorAllocate* SystemAllocator::GetSchema()
|
||||
{
|
||||
byteSize = MemorySizeAdjustedDown(byteSize); // restore original size
|
||||
return m_allocator;
|
||||
}
|
||||
|
||||
AZ_Assert(address != nullptr, "SystemAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!", byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
//=========================================================================
|
||||
// Allocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
SystemAllocator::pointer_type SystemAllocator::Allocate(
|
||||
size_type byteSize,
|
||||
size_type alignment,
|
||||
int flags,
|
||||
const char* name,
|
||||
const char* fileName,
|
||||
int lineNum,
|
||||
unsigned int suppressStackRecord)
|
||||
{
|
||||
if (byteSize == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
|
||||
AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
|
||||
|
||||
AZ_PROFILE_MEMORY_ALLOC_EX(MemoryReserved, fileName, lineNum, address, byteSize, name);
|
||||
AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
SystemAllocator::pointer_type address =
|
||||
m_allocator->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
|
||||
return address;
|
||||
}
|
||||
if (address == nullptr)
|
||||
{
|
||||
// Free all memory we can and try again!
|
||||
AllocatorManager::Instance().GarbageCollect();
|
||||
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
void
|
||||
SystemAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
AZ_PROFILE_MEMORY_FREE(MemoryReserved, ptr);
|
||||
AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
|
||||
m_allocator->DeAllocate(ptr, byteSize, alignment);
|
||||
}
|
||||
address = m_allocator->Allocate(byteSize, alignment, flags, name, fileName, lineNum, suppressStackRecord + 1);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReAllocate
|
||||
// [9/13/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::pointer_type
|
||||
SystemAllocator::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment)
|
||||
{
|
||||
newSize = MemorySizeAdjustedUp(newSize);
|
||||
if (address == nullptr)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedDown(byteSize); // restore original size
|
||||
}
|
||||
|
||||
AZ_MEMORY_PROFILE(ProfileReallocationBegin(ptr, newSize));
|
||||
AZ_PROFILE_MEMORY_FREE(MemoryReserved, ptr);
|
||||
pointer_type newAddress = m_allocator->ReAllocate(ptr, newSize, newAlignment);
|
||||
AZ_PROFILE_MEMORY_ALLOC(MemoryReserved, newAddress, newSize, "SystemAllocator realloc");
|
||||
AZ_MEMORY_PROFILE(ProfileReallocationEnd(ptr, newAddress, newSize, newAlignment));
|
||||
AZ_Assert(
|
||||
address != nullptr, "SystemAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!", byteSize,
|
||||
alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
|
||||
|
||||
return newAddress;
|
||||
}
|
||||
AZ_PROFILE_MEMORY_ALLOC_EX(MemoryReserved, fileName, lineNum, address, byteSize, name);
|
||||
AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
|
||||
|
||||
//=========================================================================
|
||||
// Resize
|
||||
// [8/12/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::size_type
|
||||
SystemAllocator::Resize(pointer_type ptr, size_type newSize)
|
||||
{
|
||||
newSize = MemorySizeAdjustedUp(newSize);
|
||||
size_type resizedSize = m_allocator->Resize(ptr, newSize);
|
||||
return address;
|
||||
}
|
||||
|
||||
AZ_MEMORY_PROFILE(ProfileResize(ptr, resizedSize));
|
||||
//=========================================================================
|
||||
// DeAllocate
|
||||
// [9/2/2009]
|
||||
//=========================================================================
|
||||
void SystemAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
|
||||
{
|
||||
byteSize = MemorySizeAdjustedUp(byteSize);
|
||||
AZ_PROFILE_MEMORY_FREE(MemoryReserved, ptr);
|
||||
AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
|
||||
m_allocator->DeAllocate(ptr, byteSize, alignment);
|
||||
}
|
||||
|
||||
return MemorySizeAdjustedDown(resizedSize);
|
||||
}
|
||||
//=========================================================================
|
||||
// ReAllocate
|
||||
// [9/13/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::pointer_type SystemAllocator::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment)
|
||||
{
|
||||
newSize = MemorySizeAdjustedUp(newSize);
|
||||
|
||||
//=========================================================================
|
||||
//
|
||||
// [8/12/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::size_type
|
||||
SystemAllocator::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
size_type allocSize = MemorySizeAdjustedDown(m_allocator->AllocationSize(ptr));
|
||||
AZ_MEMORY_PROFILE(ProfileReallocationBegin(ptr, newSize));
|
||||
AZ_PROFILE_MEMORY_FREE(MemoryReserved, ptr);
|
||||
pointer_type newAddress = m_allocator->ReAllocate(ptr, newSize, newAlignment);
|
||||
AZ_PROFILE_MEMORY_ALLOC(MemoryReserved, newAddress, newSize, "SystemAllocator realloc");
|
||||
AZ_MEMORY_PROFILE(ProfileReallocationEnd(ptr, newAddress, newSize, newAlignment));
|
||||
|
||||
return allocSize;
|
||||
}
|
||||
return newAddress;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Resize
|
||||
// [8/12/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::size_type SystemAllocator::Resize(pointer_type ptr, size_type newSize)
|
||||
{
|
||||
newSize = MemorySizeAdjustedUp(newSize);
|
||||
size_type resizedSize = m_allocator->Resize(ptr, newSize);
|
||||
|
||||
AZ_MEMORY_PROFILE(ProfileResize(ptr, resizedSize));
|
||||
|
||||
return MemorySizeAdjustedDown(resizedSize);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
//
|
||||
// [8/12/2011]
|
||||
//=========================================================================
|
||||
SystemAllocator::size_type SystemAllocator::AllocationSize(pointer_type ptr)
|
||||
{
|
||||
size_type allocSize = MemorySizeAdjustedDown(m_allocator->AllocationSize(ptr));
|
||||
|
||||
return allocSize;
|
||||
}
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_SYS_ALLOCATOR_H
|
||||
#define AZCORE_SYS_ALLOCATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
|
||||
@@ -120,7 +119,5 @@ namespace AZ
|
||||
};
|
||||
}
|
||||
|
||||
#endif // AZCORE_SYS_ALLOCATOR_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
@@ -23,11 +23,11 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void cvar_t_simulationTickDeltaOverride_Changed(const float& value)
|
||||
void cvar_t_simulationTickDeltaOverride_Changed(const int64_t& value)
|
||||
{
|
||||
if (auto* timeSystem = AZ::Interface<ITime>::Get())
|
||||
{
|
||||
timeSystem->SetSimulationTickDeltaOverride(AZ::SecondsToTimeMs(value));
|
||||
timeSystem->SetSimulationTickDeltaOverride(static_cast<AZ::TimeMs>(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ namespace AZ
|
||||
AZ_CVAR(float, t_simulationTickScale, 1.0f, cvar_t_simulationTickScale_Changed, AZ::ConsoleFunctorFlags::Null,
|
||||
"A scalar amount to adjust time passage by, 1.0 == realtime, 0.5 == half realtime, 2.0 == doubletime");
|
||||
|
||||
AZ_CVAR(float, t_simulationTickDeltaOverride, 0.0f, cvar_t_simulationTickDeltaOverride_Changed, AZ::ConsoleFunctorFlags::Null,
|
||||
"If > 0, overrides the simulation tick delta time with the provided value (Seconds) and ignores any t_simulationTickScale value.");
|
||||
AZ_CVAR(int64_t, t_simulationTickDeltaOverride, 0, cvar_t_simulationTickDeltaOverride_Changed, AZ::ConsoleFunctorFlags::Null,
|
||||
"If > 0, overrides the simulation tick delta time with the provided value (Milliseconds) and ignores any t_simulationTickScale value.");
|
||||
|
||||
AZ_CVAR(int, t_simulationTickRate, 0, cvar_t_simulationTickRate_Changed, AZ::ConsoleFunctorFlags::Null,
|
||||
"The minimum rate to force the game simulation tick to run. 0 for as fast as possible. 30 = ~33ms, 60 = ~16ms");
|
||||
@@ -176,7 +176,7 @@ namespace AZ
|
||||
if (timeUs != m_simulationTickDeltaOverride)
|
||||
{
|
||||
m_simulationTickDeltaOverride = timeUs;
|
||||
t_simulationTickDeltaOverride = AZ::TimeUsToSeconds(timeUs); //update the cvar
|
||||
t_simulationTickDeltaOverride = static_cast <int64_t>(timeMs); // update the cvar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -408,4 +408,106 @@ namespace UnitTest
|
||||
Matrix4x4 m = Matrix4x4::CreateFromQuaternion(rotQuat);
|
||||
AZ_TEST_ASSERT(m.IsClose(rotMatrix));
|
||||
}
|
||||
|
||||
class QuaternionScaledAxisAngleConversionFixture
|
||||
: public ::testing::TestWithParam<AZ::Quaternion>
|
||||
{
|
||||
public:
|
||||
AZ::Quaternion GetAbs(const AZ::Quaternion& in)
|
||||
{
|
||||
// Take the shortest path for quaternions containing rotations bigger than 180.0°.
|
||||
if (in.GetW() < 0.0f)
|
||||
{
|
||||
return -in;
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
};
|
||||
|
||||
static const AZ::Quaternion RotationRepresentationConversionTestQuats[] =
|
||||
{
|
||||
AZ::Quaternion::CreateIdentity(),
|
||||
-AZ::Quaternion::CreateIdentity(),
|
||||
AZ::Quaternion::CreateRotationX(AZ::Constants::TwoPi),
|
||||
AZ::Quaternion::CreateRotationY(AZ::Constants::Pi),
|
||||
AZ::Quaternion::CreateRotationZ(AZ::Constants::HalfPi),
|
||||
AZ::Quaternion::CreateRotationX(AZ::Constants::QuarterPi),
|
||||
AZ::Quaternion(0.64f, 0.36f, 0.48f, 0.48f),
|
||||
AZ::Quaternion(0.70f, -0.34f, 0.10f, 0.62f),
|
||||
AZ::Quaternion(-0.38f, 0.34f, 0.70f, -0.50f),
|
||||
AZ::Quaternion(0.70f, -0.34f, -0.38f, 0.50f),
|
||||
AZ::Quaternion(0.00f, 0.00f, -0.28f, 0.96f),
|
||||
AZ::Quaternion(0.24f, -0.64f, 0.72f, 0.12f),
|
||||
AZ::Quaternion(-0.66f, 0.62f, 0.42f, 0.06f)
|
||||
};
|
||||
|
||||
TEST_P(QuaternionScaledAxisAngleConversionFixture, ScaledAxisAngleQuatRoundtripTests)
|
||||
{
|
||||
const AZ::Quaternion testQuat = GetAbs(GetParam());
|
||||
|
||||
// Convert test quaternion to scaled axis-angle representation.
|
||||
const AZ::Vector3 scaledAxisAngle = testQuat.ConvertToScaledAxisAngle();
|
||||
|
||||
// Convert the scaled axis-angle back into a quaternion.
|
||||
AZ::Quaternion backFromScaledAxisAngle = AZ::Quaternion::CreateFromScaledAxisAngle(scaledAxisAngle);
|
||||
|
||||
// Compare the original quaternion with the one after the conversion.
|
||||
EXPECT_TRUE(testQuat.IsClose(backFromScaledAxisAngle, 1e-6f));
|
||||
}
|
||||
|
||||
TEST_P(QuaternionScaledAxisAngleConversionFixture, AxisAngleQuatRoundtripTests)
|
||||
{
|
||||
const AZ::Quaternion testQuat = GetAbs(GetParam());
|
||||
|
||||
// Convert test quaternion to axis-angle representation.
|
||||
AZ::Vector3 axis;
|
||||
float angle;
|
||||
testQuat.ConvertToAxisAngle(axis, angle);
|
||||
|
||||
// Convert the axis-angle back into a quaternion and compare the original quaternion with the one after the conversion.
|
||||
const AZ::Quaternion backFromAxisAngle = AZ::Quaternion::CreateFromAxisAngle(axis, angle);
|
||||
EXPECT_TRUE(testQuat.IsClose(backFromAxisAngle, 1e-6f));
|
||||
}
|
||||
|
||||
TEST_P(QuaternionScaledAxisAngleConversionFixture, CompareAxisAngleConversionTests)
|
||||
{
|
||||
const AZ::Quaternion testQuat = GetAbs(GetParam());
|
||||
|
||||
// Convert test quaternion to scaled axis-angle representation.
|
||||
const AZ::Vector3 scaledAxisAngle = testQuat.ConvertToScaledAxisAngle();
|
||||
|
||||
// Convert test quaternion to axis-angle representation and scale it manually.
|
||||
AZ::Vector3 axis;
|
||||
float angle;
|
||||
testQuat.ConvertToAxisAngle(axis, angle);
|
||||
|
||||
// Compare the scaled result to the version from the helper that directly converts it to scaled axis-angle.
|
||||
AZ::Vector3 scaledResult = axis*angle;
|
||||
EXPECT_TRUE(scaledResult.IsClose(scaledAxisAngle, 1e-5f));
|
||||
}
|
||||
|
||||
TEST_P(QuaternionScaledAxisAngleConversionFixture, CompareScaledAxisAngleConversionTests)
|
||||
{
|
||||
const AZ::Quaternion testQuat = GetAbs(GetParam());
|
||||
|
||||
// Convert test quaternion to axis-angle representation and scale it manually.
|
||||
AZ::Vector3 axis;
|
||||
float angle;
|
||||
testQuat.ConvertToAxisAngle(axis, angle);
|
||||
AZ::Vector3 scaledResult = axis*angle;
|
||||
|
||||
// Special case handling for identity rotation.
|
||||
AZ::Vector3 axisFromScaledResult = scaledResult.GetNormalized();
|
||||
float angleFromScaledResult = scaledResult.GetLength();
|
||||
if (AZ::IsClose(angleFromScaledResult, 0.0f))
|
||||
{
|
||||
axisFromScaledResult = AZ::Vector3::CreateAxisY();
|
||||
}
|
||||
|
||||
const AZ::Quaternion backFromAxisAngle = AZ::Quaternion::CreateFromAxisAngle(axisFromScaledResult, angleFromScaledResult);
|
||||
EXPECT_TRUE(testQuat.IsClose(backFromAxisAngle, 1e-6f));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MATH_Quaternion, QuaternionScaledAxisAngleConversionFixture, ::testing::ValuesIn(RotationRepresentationConversionTestQuats));
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class TimeTests
|
||||
: public AllocatorsFixture
|
||||
class TimeTests : public AllocatorsFixture
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
@@ -77,4 +76,192 @@ namespace UnitTest
|
||||
int64_t delta = static_cast<int64_t>(timeMs) - static_cast<int64_t>(timeUsToMs);
|
||||
EXPECT_LT(abs(delta), 1);
|
||||
}
|
||||
}
|
||||
|
||||
class TimeSystemTests : public AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
SetupAllocator();
|
||||
m_controlTime = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond());
|
||||
m_timeSystem = AZStd::make_unique<AZ::TimeSystem>();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_controlTime = AZ::Time::ZeroTimeUs;
|
||||
m_timeSystem.reset();
|
||||
TeardownAllocator();
|
||||
}
|
||||
|
||||
AZ::TimeUs GetDiff(AZ::TimeUs time1, AZ::TimeUs time2) const
|
||||
{
|
||||
// AZ::TimeUs is unsigned so make sure to not underflow.
|
||||
return time1 > time2 ? time1 - time2 : time2 - time1;
|
||||
}
|
||||
|
||||
AZ::TimeUs m_controlTime;
|
||||
AZStd::unique_ptr<AZ::TimeSystem> m_timeSystem;
|
||||
};
|
||||
|
||||
TEST_F(TimeSystemTests, GetRealElapsedTimeUs)
|
||||
{
|
||||
// sleep for a bit to advance time.
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(2));
|
||||
|
||||
// find the delta for the control and from GetRealElapsedTimeUs
|
||||
const AZ::TimeUs baseline = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond()) - m_controlTime;
|
||||
const AZ::TimeUs elapsedTime = m_timeSystem->GetRealElapsedTimeUs();
|
||||
|
||||
const AZ::TimeUs diff = GetDiff(baseline, elapsedTime);
|
||||
|
||||
// elapsedTime should be within 10 microseconds from baseline.
|
||||
EXPECT_LT(diff, AZ::TimeUs{ 10 });
|
||||
}
|
||||
|
||||
TEST_F(TimeSystemTests, GetElapsedTimeUs)
|
||||
{
|
||||
// sleep for a bit to advance time.
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(2));
|
||||
|
||||
// find the delta for the control and from GetElapsedTimeUs
|
||||
const AZ::TimeUs baseline = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond()) - m_controlTime;
|
||||
const AZ::TimeUs elapsedTime = m_timeSystem->GetElapsedTimeUs();
|
||||
|
||||
const AZ::TimeUs diff = GetDiff(baseline, elapsedTime);
|
||||
|
||||
// elapsedTime should be within 10 microseconds from baseline.
|
||||
EXPECT_LT(diff, AZ::TimeUs{ 10 });
|
||||
}
|
||||
|
||||
TEST_F(TimeSystemTests, ElapsedTimeScales)
|
||||
{
|
||||
// slow down 'time'
|
||||
m_timeSystem->SetSimulationTickScale(0.5f);
|
||||
|
||||
// sleep for a bit to advance time.
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(2));
|
||||
|
||||
// find the delta for the control and from GetElapsedTimeUs
|
||||
const AZ::TimeUs baseline = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond()) - m_controlTime;
|
||||
const AZ::TimeUs elapsedTime = m_timeSystem->GetElapsedTimeUs();
|
||||
const AZ::TimeUs halfBaseline = (baseline / AZ::TimeUs{ 2 });
|
||||
|
||||
// elapsedTime should be about half of the control.
|
||||
const AZ::TimeUs diff = GetDiff(halfBaseline, elapsedTime);
|
||||
|
||||
// elapsedTime should be within 10 microseconds from baseline.
|
||||
EXPECT_LT(diff, AZ::TimeUs{ 10 });
|
||||
|
||||
// reset time scale
|
||||
m_timeSystem->SetSimulationTickScale(1.0f);
|
||||
}
|
||||
|
||||
TEST_F(TimeSystemTests, AdvanceTickDeltaTimes)
|
||||
{
|
||||
// advance the tick delta to get a clean base.
|
||||
m_timeSystem->AdvanceTickDeltaTimes();
|
||||
const AZ::TimeUs baselineStart = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond());
|
||||
|
||||
// sleep for a bit to advance time.
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(2));
|
||||
|
||||
// advance the tick delta.
|
||||
const AZ::TimeUs delta = m_timeSystem->AdvanceTickDeltaTimes();
|
||||
const AZ::TimeUs baselineDelta = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond()) - baselineStart;
|
||||
|
||||
// the delta should be close to the baselineDelta.
|
||||
const AZ::TimeUs diff = GetDiff(delta, baselineDelta);
|
||||
EXPECT_LT(diff, AZ::TimeUs{ 10 });
|
||||
}
|
||||
|
||||
TEST_F(TimeSystemTests, SimulationAndRealTickDeltaTimesWithNoTimeScale)
|
||||
{
|
||||
// advance the tick delta to get a clean base.
|
||||
m_timeSystem->AdvanceTickDeltaTimes();
|
||||
const AZ::TimeUs baselineStart = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond());
|
||||
|
||||
// sleep for a bit to advance time.
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(2));
|
||||
|
||||
// advance the tick delta.
|
||||
const AZ::TimeUs delta = m_timeSystem->AdvanceTickDeltaTimes();
|
||||
const AZ::TimeUs baselineDelta = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond()) - baselineStart;
|
||||
|
||||
// the delta should be close to the baselineDelta.
|
||||
AZ::TimeUs diff = GetDiff(delta, baselineDelta);
|
||||
EXPECT_LT(diff, AZ::TimeUs{ 10 });
|
||||
|
||||
// the delta should be the same as GetSimulationTickDeltaTimeUs and near GetRealTickDeltaTimeUs
|
||||
const AZ::TimeUs simDeltaTime = m_timeSystem->GetSimulationTickDeltaTimeUs();
|
||||
EXPECT_EQ(delta, simDeltaTime);
|
||||
|
||||
const AZ::TimeUs realDeltaTime = m_timeSystem->GetRealTickDeltaTimeUs();
|
||||
diff = GetDiff(delta, realDeltaTime);
|
||||
EXPECT_LT(diff, AZ::TimeUs{ 10 });
|
||||
}
|
||||
|
||||
TEST_F(TimeSystemTests, SimulationAndRealTickDeltaTimesWithTimeScale)
|
||||
{
|
||||
// advance the tick delta to get a clean base.
|
||||
m_timeSystem->AdvanceTickDeltaTimes();
|
||||
const AZ::TimeUs baselineStart = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond());
|
||||
|
||||
// slow down 'time';
|
||||
m_timeSystem->SetSimulationTickScale(0.5f);
|
||||
|
||||
// sleep for a bit to advance time.
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(2));
|
||||
|
||||
// advance the tick delta.
|
||||
const AZ::TimeUs delta = m_timeSystem->AdvanceTickDeltaTimes();
|
||||
const AZ::TimeUs baselineDelta = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond()) - baselineStart;
|
||||
const AZ::TimeUs halfBaselineDelta = (baselineDelta / AZ::TimeUs{ 2 });
|
||||
|
||||
// the delta should be half the baselineDelta
|
||||
AZ::TimeUs diff = GetDiff(delta, halfBaselineDelta);
|
||||
EXPECT_LT(diff, AZ::TimeUs{ 10 });
|
||||
|
||||
// the delta should be the same as GetSimulationTickDeltaTimeUs
|
||||
const AZ::TimeUs simDeltaTime = m_timeSystem->GetSimulationTickDeltaTimeUs();
|
||||
EXPECT_EQ(delta, simDeltaTime);
|
||||
|
||||
// the delta should be near half the GetRealTickDeltaTimeUs
|
||||
const AZ::TimeUs realDeltaTime = m_timeSystem->GetRealTickDeltaTimeUs();
|
||||
const AZ::TimeUs halfRealDeltaTime = (realDeltaTime / AZ::TimeUs{ 2 });
|
||||
diff = GetDiff(delta, halfRealDeltaTime);
|
||||
EXPECT_LT(diff, AZ::TimeUs{ 10 });
|
||||
|
||||
// reset time scale
|
||||
m_timeSystem->SetSimulationTickScale(1.0f);
|
||||
}
|
||||
|
||||
TEST_F(TimeSystemTests, SimulationTickDeltaOverride)
|
||||
{
|
||||
// advance the tick delta to get a clean base.
|
||||
m_timeSystem->AdvanceTickDeltaTimes();
|
||||
const AZ::TimeUs baselineStart = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond());
|
||||
|
||||
// set the tick delta override
|
||||
const AZ::TimeMs tickOverride = AZ::TimeMs{ 3462 };
|
||||
m_timeSystem->SetSimulationTickDeltaOverride(tickOverride);
|
||||
|
||||
// sleep for a bit to advance time.
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(2));
|
||||
|
||||
// advance the tick delta.
|
||||
const AZ::TimeUs delta = m_timeSystem->AdvanceTickDeltaTimes();
|
||||
const AZ::TimeUs baselineDelta = static_cast<AZ::TimeUs>(AZStd::GetTimeNowMicroSecond()) - baselineStart;
|
||||
|
||||
// the delta should be equal to the tickOverride
|
||||
EXPECT_EQ(delta, AZ::TimeMsToUs(tickOverride));
|
||||
|
||||
// real tick delta should be near the baselineDelta
|
||||
const AZ::TimeUs realDeltaTime = m_timeSystem->GetRealTickDeltaTimeUs();
|
||||
const AZ::TimeUs diff = GetDiff(realDeltaTime, baselineDelta);
|
||||
EXPECT_LT(diff, AZ::TimeUs{ 10 });
|
||||
|
||||
// reset the tick delta override
|
||||
m_timeSystem->SetSimulationTickDeltaOverride(AZ::Time::ZeroTimeMs);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -213,27 +213,33 @@ namespace AzFramework
|
||||
|
||||
Camera Cameras::StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime)
|
||||
{
|
||||
for (int i = 0; i < m_idleCameraInputs.size();)
|
||||
for (int idleIndex = 0; idleIndex < m_idleCameraInputs.size();)
|
||||
{
|
||||
auto& cameraInput = m_idleCameraInputs[i];
|
||||
auto& cameraInput = m_idleCameraInputs[idleIndex];
|
||||
const bool canBegin = cameraInput->Beginning() &&
|
||||
AZStd::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(),
|
||||
[](const auto& input)
|
||||
{
|
||||
return !input->Exclusive();
|
||||
}) &&
|
||||
(!cameraInput->Exclusive() || (cameraInput->Exclusive() && m_activeCameraInputs.empty()));
|
||||
(!cameraInput->Exclusive() || m_activeCameraInputs.empty());
|
||||
|
||||
if (canBegin)
|
||||
{
|
||||
m_activeCameraInputs.push_back(cameraInput);
|
||||
using AZStd::swap;
|
||||
swap(m_idleCameraInputs[i], m_idleCameraInputs[m_idleCameraInputs.size() - 1]);
|
||||
swap(m_idleCameraInputs[idleIndex], m_idleCameraInputs[m_idleCameraInputs.size() - 1]);
|
||||
m_idleCameraInputs.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
// if a camera attempted to start but was not allowed to, ensure activation is cancelled
|
||||
if (!cameraInput->Idle())
|
||||
{
|
||||
cameraInput->CancelActivation();
|
||||
}
|
||||
|
||||
idleIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,21 +251,21 @@ namespace AzFramework
|
||||
return acc;
|
||||
});
|
||||
|
||||
for (int i = 0; i < m_activeCameraInputs.size();)
|
||||
for (int activeIndex = 0; activeIndex < m_activeCameraInputs.size();)
|
||||
{
|
||||
auto& cameraInput = m_activeCameraInputs[i];
|
||||
auto& cameraInput = m_activeCameraInputs[activeIndex];
|
||||
if (cameraInput->Ending())
|
||||
{
|
||||
cameraInput->ClearActivation();
|
||||
m_idleCameraInputs.push_back(cameraInput);
|
||||
using AZStd::swap;
|
||||
swap(m_activeCameraInputs[i], m_activeCameraInputs[m_activeCameraInputs.size() - 1]);
|
||||
swap(m_activeCameraInputs[activeIndex], m_activeCameraInputs[m_activeCameraInputs.size() - 1]);
|
||||
m_activeCameraInputs.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
cameraInput->ContinueActivation();
|
||||
i++;
|
||||
activeIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,9 +476,10 @@ namespace AzFramework
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
m_translation |= TranslationFromKey(input->m_channelId, m_translateCameraInputChannelIds);
|
||||
if (m_translation != TranslationType::Nil)
|
||||
if (auto translation = TranslationFromKey(input->m_channelId, m_translateCameraInputChannelIds);
|
||||
translation != TranslationType::Nil)
|
||||
{
|
||||
m_translation |= translation;
|
||||
BeginActivation();
|
||||
}
|
||||
|
||||
@@ -484,11 +491,16 @@ namespace AzFramework
|
||||
// ensure we don't process end events in the idle state
|
||||
else if (input->m_state == InputChannel::State::Ended && !Idle())
|
||||
{
|
||||
m_translation &= ~(TranslationFromKey(input->m_channelId, m_translateCameraInputChannelIds));
|
||||
if (m_translation == TranslationType::Nil)
|
||||
if (auto translation = TranslationFromKey(input->m_channelId, m_translateCameraInputChannelIds);
|
||||
translation != TranslationType::Nil)
|
||||
{
|
||||
EndActivation();
|
||||
m_translation &= ~translation;
|
||||
if (m_translation == TranslationType::Nil)
|
||||
{
|
||||
EndActivation();
|
||||
}
|
||||
}
|
||||
|
||||
if (input->m_channelId == m_translateCameraInputChannelIds.m_boostChannelId)
|
||||
{
|
||||
m_boost = false;
|
||||
|
||||
@@ -185,6 +185,11 @@ namespace AzFramework
|
||||
m_activation = Activation::Ending;
|
||||
}
|
||||
|
||||
void CancelActivation()
|
||||
{
|
||||
m_activation = Activation::Idle;
|
||||
}
|
||||
|
||||
void ContinueActivation()
|
||||
{
|
||||
// continue activation is called after the first step of the camera input,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/RTTI/TypeInfoSimple.h>
|
||||
#include <AzCore/base.h>
|
||||
|
||||
@@ -203,6 +204,12 @@ namespace AzFramework
|
||||
return AZ::Vector2(aznumeric_cast<float>(screenPoint.m_x), aznumeric_cast<float>(screenPoint.m_y));
|
||||
}
|
||||
|
||||
//! Return an AZ::Vector3 from a ScreenPoint (including z/depth value, defaulting to 0.0f).
|
||||
inline AZ::Vector3 Vector3FromScreenPoint(const ScreenPoint& screenPoint, const float z = 0.0f)
|
||||
{
|
||||
return AZ::Vector3(aznumeric_cast<float>(screenPoint.m_x), aznumeric_cast<float>(screenPoint.m_y), z);
|
||||
}
|
||||
|
||||
//! Return an AZ::Vector2 from a ScreenVector.
|
||||
inline AZ::Vector2 Vector2FromScreenVector(const ScreenVector& screenVector)
|
||||
{
|
||||
|
||||
@@ -416,4 +416,78 @@ namespace UnitTest
|
||||
using ::testing::FloatNear;
|
||||
EXPECT_THAT(m_camera.m_pitch, FloatNear(expectedPitch, 0.001f));
|
||||
}
|
||||
|
||||
TEST_F(CameraInputFixture, InvalidTranslationInputKeyCannotBeginTranslateCameraInputAgain)
|
||||
{
|
||||
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId,
|
||||
AzFramework::InputChannel::State::Began });
|
||||
|
||||
const bool consumed =
|
||||
m_cameraSystem->HandleEvents(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began });
|
||||
|
||||
using ::testing::IsFalse;
|
||||
using ::testing::IsTrue;
|
||||
EXPECT_THAT(consumed, IsTrue());
|
||||
EXPECT_THAT(m_firstPersonTranslateCamera->Beginning(), IsFalse());
|
||||
EXPECT_THAT(m_firstPersonTranslateCamera->Active(), IsTrue());
|
||||
}
|
||||
|
||||
TEST_F(CameraInputFixture, InvalidTranslationInputKeyDownCannotBeginTranslateCameraInputAgain)
|
||||
{
|
||||
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId,
|
||||
AzFramework::InputChannel::State::Began });
|
||||
|
||||
const bool consumed =
|
||||
m_cameraSystem->HandleEvents(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began });
|
||||
|
||||
using ::testing::IsFalse;
|
||||
using ::testing::IsTrue;
|
||||
EXPECT_THAT(consumed, IsTrue());
|
||||
EXPECT_THAT(m_firstPersonTranslateCamera->Beginning(), IsFalse());
|
||||
EXPECT_THAT(m_firstPersonTranslateCamera->Active(), IsTrue());
|
||||
}
|
||||
|
||||
TEST_F(CameraInputFixture, InvalidTranslationInputKeyUpDoesNotAffectTranslateCameraInputEnd)
|
||||
{
|
||||
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId,
|
||||
AzFramework::InputChannel::State::Began });
|
||||
|
||||
const bool consumed =
|
||||
m_cameraSystem->HandleEvents(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began });
|
||||
|
||||
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId,
|
||||
AzFramework::InputChannel::State::Ended });
|
||||
|
||||
using ::testing::IsFalse;
|
||||
using ::testing::IsTrue;
|
||||
EXPECT_THAT(consumed, IsTrue());
|
||||
EXPECT_THAT(m_firstPersonTranslateCamera->Idle(), IsTrue());
|
||||
}
|
||||
|
||||
TEST_F(CameraInputFixture, OrbitCameraInputCannotBeLeftInInvalidStateIfItCannotFullyBeginAfterInputChannelBegin)
|
||||
{
|
||||
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId,
|
||||
AzFramework::InputChannel::State::Began });
|
||||
|
||||
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began });
|
||||
|
||||
using ::testing::IsFalse;
|
||||
using ::testing::IsTrue;
|
||||
EXPECT_THAT(m_orbitCamera->Beginning(), IsFalse());
|
||||
EXPECT_THAT(m_orbitCamera->Idle(), IsTrue());
|
||||
}
|
||||
|
||||
TEST_F(CameraInputFixture, OrbitCameraInputCannotBeLeftInInvalidStateIfItCannotFullyBeginAfterInputChannelBeginAndEnd)
|
||||
{
|
||||
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_translateCameraInputChannelIds.m_forwardChannelId,
|
||||
AzFramework::InputChannel::State::Began });
|
||||
|
||||
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began });
|
||||
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Ended });
|
||||
|
||||
using ::testing::IsFalse;
|
||||
using ::testing::IsTrue;
|
||||
EXPECT_THAT(m_orbitCamera->Ending(), IsFalse());
|
||||
EXPECT_THAT(m_orbitCamera->Idle(), IsTrue());
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
+14
-10
@@ -26,29 +26,33 @@ namespace AzManipulatorTestFramework
|
||||
{
|
||||
public:
|
||||
virtual ~ViewportInteractionInterface() = default;
|
||||
//! Return the camera state.
|
||||
//! Returns the camera state.
|
||||
virtual AzFramework::CameraState GetCameraState() = 0;
|
||||
//! Set the camera state.
|
||||
//! Sets the camera state.
|
||||
virtual void SetCameraState(const AzFramework::CameraState& cameraState) = 0;
|
||||
//! Retrieve the debug display.
|
||||
//! Retrieves the debug display.
|
||||
virtual AzFramework::DebugDisplayRequests& GetDebugDisplay() = 0;
|
||||
//! Set if grid snapping is enabled or not.
|
||||
//! Sets if grid snapping is enabled or not.
|
||||
virtual void SetGridSnapping(bool enabled) = 0;
|
||||
//! Set if angular snapping is enabled or not.
|
||||
//! Sets if angular snapping is enabled or not.
|
||||
virtual void SetAngularSnapping(bool enabled) = 0;
|
||||
//! Set the grid size.
|
||||
//! Sets the grid size.
|
||||
virtual void SetGridSize(float size) = 0;
|
||||
//! Set the angular step.
|
||||
//! Sets the angular step.
|
||||
virtual void SetAngularStep(float step) = 0;
|
||||
//! Get the viewport id.
|
||||
//! Gets the viewport id.
|
||||
virtual AzFramework::ViewportId GetViewportId() const = 0;
|
||||
//! Updates the visibility state.
|
||||
//! Updates which entities are currently visible given the current camera state.
|
||||
virtual void UpdateVisibility() = 0;
|
||||
//! Set if sticky select is enabled or not.
|
||||
//! Sets if sticky select is enabled or not.
|
||||
virtual void SetStickySelect(bool enabled) = 0;
|
||||
//! Get default Editor Camera Position.
|
||||
//! Gets default Editor Camera Position.
|
||||
virtual AZ::Vector3 DefaultEditorCameraPosition() const = 0;
|
||||
//! Sets if icons are visible in the viewport.
|
||||
virtual void SetIconsVisible(bool visible) = 0;
|
||||
//! Sets if helpers are visible in the viewport.
|
||||
virtual void SetHelpersVisible(bool visible) = 0;
|
||||
};
|
||||
|
||||
//! This interface is used to simulate the manipulator manager while the manipulators are under test.
|
||||
|
||||
+1
-1
@@ -26,6 +26,7 @@ namespace UnitTest
|
||||
using IndirectCallManipulatorViewportInteraction = AzManipulatorTestFramework::IndirectCallManipulatorViewportInteraction;
|
||||
using ImmediateModeActionDispatcher = AzManipulatorTestFramework::ImmediateModeActionDispatcher;
|
||||
|
||||
public:
|
||||
void SetUpEditorFixtureImpl() override
|
||||
{
|
||||
ToolsApplicationFixtureT::SetUpEditorFixtureImpl();
|
||||
@@ -43,7 +44,6 @@ namespace UnitTest
|
||||
ToolsApplicationFixtureT::TearDownEditorFixtureImpl();
|
||||
}
|
||||
|
||||
public:
|
||||
AzFramework::CameraState m_cameraState;
|
||||
AZStd::unique_ptr<ImmediateModeActionDispatcher> m_actionDispatcher;
|
||||
AZStd::unique_ptr<IndirectCallManipulatorViewportInteraction> m_viewportManipulatorInteraction;
|
||||
|
||||
-23
@@ -27,29 +27,6 @@ namespace AzManipulatorTestFramework
|
||||
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(
|
||||
const AZ::Vector3& origin, const AZ::Vector3& direction, const AzFramework::ScreenPoint& screenPoint);
|
||||
|
||||
//! Build a mouse pick from the specified mouse position and camera state.
|
||||
AzToolsFramework::ViewportInteraction::MousePick BuildMousePick(
|
||||
const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState);
|
||||
|
||||
//! Create a mouse interaction from the specified pick, buttons, interaction id and keyboard modifiers.
|
||||
AzToolsFramework::ViewportInteraction::MouseInteraction CreateMouseInteraction(
|
||||
const AzToolsFramework::ViewportInteraction::MousePick& mousePick,
|
||||
AzToolsFramework::ViewportInteraction::MouseButtons buttons,
|
||||
AzToolsFramework::ViewportInteraction::InteractionId interactionId,
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifiers modifiers);
|
||||
|
||||
//! Create a mouse buttons from the specified mouse button.
|
||||
AzToolsFramework::ViewportInteraction::MouseButtons CreateMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton button);
|
||||
|
||||
//! Create a mouse interaction event from the specified interaction and event.
|
||||
AzToolsFramework::ViewportInteraction::MouseInteractionEvent CreateMouseInteractionEvent(
|
||||
const AzToolsFramework::ViewportInteraction::MouseInteraction& mouseInteraction,
|
||||
AzToolsFramework::ViewportInteraction::MouseEvent event);
|
||||
|
||||
//! Dispatch a mouse event to the main manipulator manager via a bus call.
|
||||
void DispatchMouseInteractionEvent(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& event);
|
||||
|
||||
|
||||
+4
-1
@@ -24,9 +24,12 @@ namespace AzManipulatorTestFramework
|
||||
explicit IndirectCallManipulatorViewportInteraction(AZStd::shared_ptr<AzFramework::DebugDisplayRequests> debugDisplayRequests);
|
||||
~IndirectCallManipulatorViewportInteraction();
|
||||
|
||||
// ManipulatorViewportInteractionInterface ...
|
||||
// ManipulatorViewportInteraction overrides ...
|
||||
const ViewportInteractionInterface& GetViewportInteraction() const override;
|
||||
const ManipulatorManagerInterface& GetManipulatorManager() const override;
|
||||
// make non-const overloads visible
|
||||
using ManipulatorViewportInteraction::GetViewportInteraction;
|
||||
using ManipulatorViewportInteraction::GetManipulatorManager;
|
||||
|
||||
private:
|
||||
AZStd::unique_ptr<ViewportInteraction> m_viewportInteraction;
|
||||
|
||||
+9
-3
@@ -39,7 +39,8 @@ namespace AzManipulatorTestFramework
|
||||
AzFramework::ViewportId GetViewportId() const override;
|
||||
void UpdateVisibility() override;
|
||||
void SetStickySelect(bool enabled) override;
|
||||
AZ::Vector3 DefaultEditorCameraPosition() const override;
|
||||
void SetIconsVisible(bool visible) override;
|
||||
void SetHelpersVisible(bool visible) override;
|
||||
|
||||
// ViewportInteractionRequestBus overrides ...
|
||||
AzFramework::CameraState GetCameraState() override;
|
||||
@@ -58,6 +59,9 @@ namespace AzManipulatorTestFramework
|
||||
float ManipulatorLineBoundWidth() const override;
|
||||
float ManipulatorCircleBoundWidth() const override;
|
||||
bool StickySelectEnabled() const override;
|
||||
AZ::Vector3 DefaultEditorCameraPosition() const override;
|
||||
bool IconsVisible() const override;
|
||||
bool HelpersVisible() const override;
|
||||
|
||||
// EditorEntityViewportInteractionRequestBus overrides ...
|
||||
void FindVisibleEntities(AZStd::vector<AZ::EntityId>& visibleEntities) override;
|
||||
@@ -68,10 +72,12 @@ namespace AzManipulatorTestFramework
|
||||
AzFramework::EntityVisibilityQuery m_entityVisibilityQuery;
|
||||
AZStd::shared_ptr<AzFramework::DebugDisplayRequests> m_debugDisplayRequests;
|
||||
AzFramework::CameraState m_cameraState;
|
||||
float m_gridSize = 1.0f;
|
||||
float m_angularStep = 0.0f;
|
||||
bool m_gridSnapping = false;
|
||||
bool m_angularSnapping = false;
|
||||
bool m_stickySelect = true;
|
||||
float m_gridSize = 1.0f;
|
||||
float m_angularStep = 0.0f;
|
||||
bool m_iconsVisible = true;
|
||||
bool m_helpersVisible = true;
|
||||
};
|
||||
} // namespace AzManipulatorTestFramework
|
||||
|
||||
@@ -82,49 +82,6 @@ namespace AzManipulatorTestFramework
|
||||
return manipulator;
|
||||
}
|
||||
|
||||
AzToolsFramework::ViewportInteraction::MousePick CreateMousePick(
|
||||
const AZ::Vector3& origin, const AZ::Vector3& direction, const AzFramework::ScreenPoint& screenPoint)
|
||||
{
|
||||
return { origin, direction, screenPoint };
|
||||
}
|
||||
|
||||
AzToolsFramework::ViewportInteraction::MousePick BuildMousePick(
|
||||
const AzFramework::ScreenPoint& screenPoint, const AzFramework::CameraState& cameraState)
|
||||
{
|
||||
const auto nearPlaneWorldPosition = AzFramework::ScreenToWorld(screenPoint, cameraState);
|
||||
|
||||
AzToolsFramework::ViewportInteraction::MousePick mousePick;
|
||||
mousePick.m_screenCoordinates = screenPoint;
|
||||
mousePick.m_rayOrigin = nearPlaneWorldPosition;
|
||||
mousePick.m_rayDirection = (nearPlaneWorldPosition - cameraState.m_position).GetNormalized();
|
||||
|
||||
return mousePick;
|
||||
}
|
||||
|
||||
MouseInteraction CreateMouseInteraction(
|
||||
const MousePick& mousePick, MouseButtons buttons, InteractionId interactionId, KeyboardModifiers modifiers)
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::MouseInteraction interaction;
|
||||
interaction.m_mousePick = mousePick;
|
||||
interaction.m_mouseButtons = buttons;
|
||||
interaction.m_interactionId = interactionId;
|
||||
interaction.m_keyboardModifiers = modifiers;
|
||||
|
||||
return interaction;
|
||||
}
|
||||
|
||||
MouseButtons CreateMouseButtons(MouseButton button)
|
||||
{
|
||||
MouseButtons buttons;
|
||||
buttons.m_mouseButtons = static_cast<AZ::u32>(button);
|
||||
return buttons;
|
||||
}
|
||||
|
||||
MouseInteractionEvent CreateMouseInteractionEvent(const MouseInteraction& mouseInteraction, MouseEvent event)
|
||||
{
|
||||
return MouseInteractionEvent(mouseInteraction, event, /*captured=*/false);
|
||||
}
|
||||
|
||||
void DispatchMouseInteractionEvent(const MouseInteractionEvent& event)
|
||||
{
|
||||
AzToolsFramework::EditorInteractionSystemViewportSelectionRequestBus::Event(
|
||||
|
||||
@@ -120,7 +120,8 @@ namespace AzManipulatorTestFramework
|
||||
void ImmediateModeActionDispatcher::MousePositionImpl(const AzFramework::ScreenPoint& position)
|
||||
{
|
||||
const auto cameraState = m_manipulatorViewportInteraction.GetViewportInteraction().GetCameraState();
|
||||
GetMouseInteractionEvent()->m_mouseInteraction.m_mousePick = BuildMousePick(position, cameraState);
|
||||
GetMouseInteractionEvent()->m_mouseInteraction.m_mousePick =
|
||||
AzToolsFramework::ViewportInteraction::BuildMousePick(cameraState, position);
|
||||
GetMouseInteractionEvent()->m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Move;
|
||||
m_manipulatorViewportInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*m_event);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
#include <AzManipulatorTestFramework/ViewportInteraction.h>
|
||||
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
|
||||
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
|
||||
|
||||
namespace AzManipulatorTestFramework
|
||||
{
|
||||
@@ -19,6 +20,9 @@ namespace AzManipulatorTestFramework
|
||||
AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus::Handler::BusConnect(m_viewportId);
|
||||
AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler::BusConnect(m_viewportId);
|
||||
AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusConnect(m_viewportId);
|
||||
|
||||
m_cameraState =
|
||||
AzFramework::CreateIdentityDefaultCamera(AZ::Vector3::CreateZero(), AzManipulatorTestFramework::DefaultViewportSize);
|
||||
}
|
||||
|
||||
ViewportInteraction::~ViewportInteraction()
|
||||
@@ -113,6 +117,16 @@ namespace AzManipulatorTestFramework
|
||||
m_stickySelect = enabled;
|
||||
}
|
||||
|
||||
void ViewportInteraction::SetIconsVisible(const bool visible)
|
||||
{
|
||||
m_iconsVisible = visible;
|
||||
}
|
||||
|
||||
void ViewportInteraction::SetHelpersVisible(const bool visible)
|
||||
{
|
||||
m_helpersVisible = visible;
|
||||
}
|
||||
|
||||
AZ::Vector3 ViewportInteraction::DefaultEditorCameraPosition() const
|
||||
{
|
||||
return {};
|
||||
@@ -148,4 +162,14 @@ namespace AzManipulatorTestFramework
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
bool ViewportInteraction::IconsVisible() const
|
||||
{
|
||||
return m_iconsVisible;
|
||||
}
|
||||
|
||||
bool ViewportInteraction::HelpersVisible() const
|
||||
{
|
||||
return m_helpersVisible;
|
||||
}
|
||||
} // namespace AzManipulatorTestFramework
|
||||
|
||||
+20
-19
@@ -8,21 +8,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class LinearManipulatorTestFixture
|
||||
: public ToolsApplicationFixture
|
||||
class LinearManipulatorTestFixture : public ToolsApplicationFixture
|
||||
{
|
||||
protected:
|
||||
LinearManipulatorTestFixture(const AzToolsFramework::ManipulatorManagerId& manipulatorManagerId)
|
||||
: m_manipulatorManagerId(manipulatorManagerId) {}
|
||||
: m_manipulatorManagerId(manipulatorManagerId)
|
||||
{
|
||||
}
|
||||
|
||||
void SetUpEditorFixtureImpl() override
|
||||
{
|
||||
{
|
||||
m_linearManipulator = AzManipulatorTestFramework::CreateLinearManipulator(
|
||||
m_manipulatorManagerId,
|
||||
/*position=*/AZ::Vector3::CreateZero(),
|
||||
@@ -31,21 +32,21 @@ namespace UnitTest
|
||||
// default sanity check call backs
|
||||
m_linearManipulator->InstallLeftMouseDownCallback(
|
||||
[this](const AzToolsFramework::LinearManipulator::Action& /*action*/)
|
||||
{
|
||||
m_receivedLeftMouseDown = true;
|
||||
});
|
||||
{
|
||||
m_receivedLeftMouseDown = true;
|
||||
});
|
||||
|
||||
m_linearManipulator->InstallMouseMoveCallback(
|
||||
[this](const AzToolsFramework::LinearManipulator::Action& /*action*/)
|
||||
{
|
||||
m_receivedMouseMove = true;
|
||||
});
|
||||
{
|
||||
m_receivedMouseMove = true;
|
||||
});
|
||||
|
||||
m_linearManipulator->InstallLeftMouseUpCallback(
|
||||
[this](const AzToolsFramework::LinearManipulator::Action& /*action*/)
|
||||
{
|
||||
m_receivedLeftMouseUp = true;
|
||||
});
|
||||
{
|
||||
m_receivedLeftMouseUp = true;
|
||||
});
|
||||
}
|
||||
|
||||
void TearDownEditorFixtureImpl() override
|
||||
@@ -63,16 +64,16 @@ namespace UnitTest
|
||||
bool m_receivedLeftMouseUp = false;
|
||||
|
||||
// initial world space starting position for mouse interaction
|
||||
const AzToolsFramework::ViewportInteraction::MousePick m_mouseStartingPositionRay =
|
||||
AzManipulatorTestFramework::CreateMousePick(
|
||||
AZ::Vector3(0.0f, -2.0f, 0.0f), AZ::Vector3(0.0f, 1.0f, 0.0f), AzFramework::ScreenPoint( 0,0 ));
|
||||
const AzToolsFramework::ViewportInteraction::MousePick m_mouseStartingPositionRay{ AZ::Vector3(0.0f, -2.0f, 0.0f),
|
||||
AZ::Vector3(0.0f, 1.0f, 0.0f),
|
||||
AzFramework::ScreenPoint(0, 0) };
|
||||
|
||||
// left mouse down ray in world space 2 units back from origin looking down +y axis with a null interaction
|
||||
// id and no keyboard modifiers
|
||||
AzToolsFramework::ViewportInteraction::MouseInteraction m_interaction =
|
||||
AzManipulatorTestFramework::CreateMouseInteraction(
|
||||
AzToolsFramework::ViewportInteraction::BuildMouseInteraction(
|
||||
m_mouseStartingPositionRay,
|
||||
AzManipulatorTestFramework::CreateMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::Left),
|
||||
AzToolsFramework::ViewportInteraction::BuildMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::Left),
|
||||
AzToolsFramework::ViewportInteraction::InteractionId(AZ::EntityId(0), 0),
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifiers(0));
|
||||
};
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
*/
|
||||
|
||||
#include "AzManipulatorTestFrameworkTestFixtures.h"
|
||||
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorDefaultSelection.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
|
||||
|
||||
@@ -34,8 +36,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 = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent(
|
||||
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
|
||||
|
||||
// consume the mouse down and up events
|
||||
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
|
||||
@@ -53,8 +55,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 = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent(
|
||||
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Move);
|
||||
|
||||
// consume the mouse move event
|
||||
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
|
||||
@@ -72,8 +74,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 = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent(
|
||||
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
|
||||
|
||||
// consume the mouse down event
|
||||
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
|
||||
@@ -113,8 +115,8 @@ namespace UnitTest
|
||||
});
|
||||
|
||||
// given a left mouse down ray in world space
|
||||
auto event =
|
||||
AzManipulatorTestFramework::CreateMouseInteractionEvent(m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
|
||||
auto event = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent(
|
||||
m_interaction, AzToolsFramework::ViewportInteraction::MouseEvent::Down);
|
||||
|
||||
// consume the mouse down event
|
||||
AzManipulatorTestFramework::DispatchMouseInteractionEvent(event);
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include <ostream>
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
void PrintTo(const AZ::IO::PathView& path, ::std::ostream* os)
|
||||
@@ -24,4 +27,12 @@ namespace AZ::IO
|
||||
{
|
||||
*os << "path: " << AZ::IO::FixedMaxPath(path.Native(), AZ::IO::PosixPathSeparator).MakePreferred().c_str();
|
||||
}
|
||||
}
|
||||
} // namespace AZ::IO
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
void PrintTo(const AZ::EntityId entityId, ::std::ostream* os)
|
||||
{
|
||||
*os << entityId.ToString().c_str();
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iosfwd>
|
||||
@@ -37,4 +38,11 @@ namespace AZ::IO
|
||||
void PrintTo(const AZ::IO::FixedMaxPath& path, ::std::ostream* os);
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class EntityId;
|
||||
|
||||
void PrintTo(AZ::EntityId entityId, ::std::ostream* os);
|
||||
}
|
||||
|
||||
#include <AzTest/Printers.inl>
|
||||
|
||||
@@ -878,9 +878,6 @@ namespace AzToolsFramework
|
||||
/// Return the icon texture id (from internal IconManager) for a given entity icon path.
|
||||
/// This can be passed to DrawTextureLabel to draw an entity icon.
|
||||
virtual int GetIconTextureIdFromEntityIconPath(const AZStd::string& entityIconPath) = 0;
|
||||
|
||||
/// Returns if the Display Helpers option is toggled on in the Editor.
|
||||
virtual bool DisplayHelpersVisible() = 0;
|
||||
};
|
||||
|
||||
using EditorRequestBus = AZ::EBus<EditorRequests>;
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (auto serializationContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializationContext->Class<ProceduralPrefabSystemComponent>();
|
||||
serializationContext->Class<ProceduralPrefabSystemComponent, AZ::Component>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,8 +89,8 @@ namespace AzToolsFramework
|
||||
const float rayLength)
|
||||
{
|
||||
AZ_Assert(rayLength > 0.0f, "Invalid ray length passed to RefreshRayRequest");
|
||||
rayRequest.m_startWorldPosition = viewportRay.origin;
|
||||
rayRequest.m_endWorldPosition = viewportRay.origin + viewportRay.direction * rayLength;
|
||||
rayRequest.m_startWorldPosition = viewportRay.m_origin;
|
||||
rayRequest.m_endWorldPosition = viewportRay.m_origin + viewportRay.m_direction * rayLength;
|
||||
}
|
||||
|
||||
AZ::Vector3 FindClosestPickIntersection(
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzFramework/Viewport/ClickDetector.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportTypes.h>
|
||||
|
||||
@@ -151,13 +150,6 @@ namespace AzToolsFramework
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
};
|
||||
|
||||
//! A ray projection, originating from a point and extending in a direction specified as a normal.
|
||||
struct ProjectedViewportRay
|
||||
{
|
||||
AZ::Vector3 origin;
|
||||
AZ::Vector3 direction;
|
||||
};
|
||||
|
||||
//! Requests that can be made to the viewport to query and modify its state.
|
||||
class ViewportInteractionRequests
|
||||
{
|
||||
@@ -183,15 +175,6 @@ namespace AzToolsFramework
|
||||
//! Type to inherit to implement ViewportInteractionRequests.
|
||||
using ViewportInteractionRequestBus = AZ::EBus<ViewportInteractionRequests, ViewportEBusTraits>;
|
||||
|
||||
//! Utility function to return a viewport ray.
|
||||
inline ProjectedViewportRay ViewportScreenToWorldRay(
|
||||
const AzFramework::CameraState& cameraState, const AzFramework::ScreenPoint& screenPoint)
|
||||
{
|
||||
const AZ::Vector3 rayOrigin = AzFramework::ScreenToWorld(screenPoint, cameraState);
|
||||
const AZ::Vector3 rayDirection = (rayOrigin - cameraState.m_position).GetNormalized();
|
||||
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{ rayOrigin, rayDirection };
|
||||
}
|
||||
|
||||
//! Utility function to return a viewport ray using the ViewportInteractionRequestBus.
|
||||
inline ProjectedViewportRay ViewportScreenToWorldRay(
|
||||
const AzFramework::ViewportId viewportId, const AzFramework::ScreenPoint& screenPoint)
|
||||
@@ -225,6 +208,10 @@ namespace AzToolsFramework
|
||||
virtual bool StickySelectEnabled() const = 0;
|
||||
//! Returns the default viewport camera position.
|
||||
virtual AZ::Vector3 DefaultEditorCameraPosition() const = 0;
|
||||
//! Returns if icons are visible in the viewport.
|
||||
virtual bool IconsVisible() const = 0;
|
||||
//! Returns if viewport helpers (additional debug drawing) are visible in the viewport.
|
||||
virtual bool HelpersVisible() const = 0;
|
||||
|
||||
protected:
|
||||
~ViewportSettingsRequests() = default;
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace AzToolsFramework
|
||||
constexpr AZStd::string_view ScaleManipulatorBoxHalfExtentSetting = "/Amazon/Preferences/Editor/Manipulator/ScaleManipulatorBoxHalfExtent";
|
||||
constexpr AZStd::string_view RotationManipulatorRadiusSetting = "/Amazon/Preferences/Editor/Manipulator/RotationManipulatorRadius";
|
||||
constexpr AZStd::string_view ManipulatorViewBaseScaleSetting = "/Amazon/Preferences/Editor/Manipulator/ViewBaseScale";
|
||||
constexpr AZStd::string_view IconsVisibleSetting = "/Amazon/Preferences/Editor/IconsVisible";
|
||||
constexpr AZStd::string_view HelpersVisibleSetting = "/Amazon/Preferences/Editor/HelpersVisible";
|
||||
|
||||
bool FlipManipulatorAxesTowardsView()
|
||||
{
|
||||
@@ -120,4 +122,24 @@ namespace AzToolsFramework
|
||||
{
|
||||
SetRegistry(ManipulatorViewBaseScaleSetting, scale);
|
||||
}
|
||||
|
||||
bool IconsVisible()
|
||||
{
|
||||
return GetRegistry(IconsVisibleSetting, true);
|
||||
}
|
||||
|
||||
void SetIconsVisible(const bool visible)
|
||||
{
|
||||
SetRegistry(IconsVisibleSetting, visible);
|
||||
}
|
||||
|
||||
bool HelpersVisible()
|
||||
{
|
||||
return GetRegistry(HelpersVisibleSetting, true);
|
||||
}
|
||||
|
||||
void SetHelpersVisible(const bool visible)
|
||||
{
|
||||
SetRegistry(HelpersVisibleSetting, visible);
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -66,4 +66,10 @@ namespace AzToolsFramework
|
||||
|
||||
float ManipulatorViewBaseScale();
|
||||
void SetManipulatorViewBaseScale(float scale);
|
||||
|
||||
bool IconsVisible();
|
||||
void SetIconsVisible(bool visible);
|
||||
|
||||
bool HelpersVisible();
|
||||
void SetHelpersVisible(bool visible);
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -49,5 +49,22 @@ namespace AzToolsFramework
|
||||
->Field("MouseEvent", &MouseInteractionEvent::m_mouseEvent)
|
||||
->Field("WheelDelta", &MouseInteractionEvent::m_wheelDelta);
|
||||
}
|
||||
|
||||
MouseInteraction BuildMouseInteraction(
|
||||
const MousePick& mousePick, const MouseButtons buttons, const InteractionId interactionId, const KeyboardModifiers modifiers)
|
||||
{
|
||||
MouseInteraction interaction;
|
||||
interaction.m_mousePick = mousePick;
|
||||
interaction.m_mouseButtons = buttons;
|
||||
interaction.m_interactionId = interactionId;
|
||||
interaction.m_keyboardModifiers = modifiers;
|
||||
return interaction;
|
||||
}
|
||||
|
||||
MouseInteractionEvent BuildMouseInteractionEvent(
|
||||
const MouseInteraction& mouseInteraction, const MouseEvent event, const bool cursorCaptured /*= false*/)
|
||||
{
|
||||
return MouseInteractionEvent(mouseInteraction, event, cursorCaptured);
|
||||
}
|
||||
} // namespace ViewportInteraction
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AzFramework/Viewport/ScreenGeometry.h"
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzFramework/Viewport/CameraState.h>
|
||||
#include <AzFramework/Viewport/ViewportScreen.h>
|
||||
|
||||
#include <QPoint>
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
class SerializeContext;
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -178,6 +178,12 @@ namespace AzToolsFramework
|
||||
//! @cond
|
||||
AZ_TYPE_INFO(MousePick, "{A69B9562-FC8C-4DE7-9137-0FF867B1513D}");
|
||||
MousePick() = default;
|
||||
MousePick(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection, const AzFramework::ScreenPoint& screenPoint)
|
||||
: m_rayOrigin(rayOrigin)
|
||||
, m_rayDirection(rayDirection)
|
||||
, m_screenCoordinates(screenPoint)
|
||||
{
|
||||
}
|
||||
//! @endcond
|
||||
|
||||
AZ::Vector3 m_rayOrigin = AZ::Vector3::CreateZero(); //!< World space.
|
||||
@@ -249,6 +255,22 @@ namespace AzToolsFramework
|
||||
return mouseInteractionEvent.m_wheelDelta;
|
||||
}
|
||||
|
||||
//! A ray projection, originating from a point and extending in a direction specified as a normal.
|
||||
struct ProjectedViewportRay
|
||||
{
|
||||
AZ::Vector3 m_origin;
|
||||
AZ::Vector3 m_direction;
|
||||
};
|
||||
|
||||
//! Utility function to return a viewport ray.
|
||||
inline ProjectedViewportRay ViewportScreenToWorldRay(
|
||||
const AzFramework::CameraState& cameraState, const AzFramework::ScreenPoint& screenPoint)
|
||||
{
|
||||
const AZ::Vector3 rayOrigin = AzFramework::ScreenToWorld(screenPoint, cameraState);
|
||||
const AZ::Vector3 rayDirection = (rayOrigin - cameraState.m_position).GetNormalized();
|
||||
return ProjectedViewportRay{ rayOrigin, rayDirection };
|
||||
}
|
||||
|
||||
//! Return QPoint from AzFramework::ScreenPoint.
|
||||
inline QPoint QPointFromScreenPoint(const AzFramework::ScreenPoint& screenPoint)
|
||||
{
|
||||
@@ -301,6 +323,27 @@ namespace AzToolsFramework
|
||||
return mouseButtons;
|
||||
}
|
||||
|
||||
//! Build a mouse pick from the specified mouse position and camera state.
|
||||
inline MousePick BuildMousePick(const AzFramework::CameraState& cameraState, const AzFramework::ScreenPoint& screenPoint)
|
||||
{
|
||||
const auto ray = ViewportScreenToWorldRay(cameraState, screenPoint);
|
||||
return MousePick(ray.m_origin, ray.m_direction, screenPoint);
|
||||
}
|
||||
|
||||
//! Create a mouse interaction from the specified pick, buttons, interaction id and keyboard modifiers.
|
||||
MouseInteraction BuildMouseInteraction(
|
||||
const MousePick& mousePick, MouseButtons buttons, InteractionId interactionId, KeyboardModifiers modifiers);
|
||||
|
||||
//! Create a mouse buttons from the specified mouse button.
|
||||
inline MouseButtons BuildMouseButtons(const MouseButton button)
|
||||
{
|
||||
return MouseButtons(aznumeric_cast<AZ::u32>(button));
|
||||
}
|
||||
|
||||
//! Create a mouse interaction event from the specified interaction and event.
|
||||
MouseInteractionEvent BuildMouseInteractionEvent(
|
||||
const MouseInteraction& mouseInteraction, MouseEvent event, bool cursorCaptured = false);
|
||||
|
||||
//! Reflect all viewport related types.
|
||||
void ViewportInteractionReflect(AZ::ReflectContext* context);
|
||||
} // namespace ViewportInteraction
|
||||
|
||||
+108
-61
@@ -52,34 +52,45 @@ AZ_CVAR(
|
||||
AZ::ConsoleFunctorFlags::Null,
|
||||
"Use a lock icon when the cursor is over entities that cannot be interacted with");
|
||||
|
||||
AZ_CVAR(float, ed_iconMinScale, 0.1f, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum scale for icons in the distance");
|
||||
AZ_CVAR(float, ed_iconMaxScale, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum scale for icons near the camera");
|
||||
AZ_CVAR(float, ed_iconCloseDist, 3.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Distance at which icons are at maximum scale");
|
||||
AZ_CVAR(float, ed_iconFarDist, 40.f, nullptr, AZ::ConsoleFunctorFlags::Null, "Distance at which icons are at minimum scale");
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_IMPL(EditorHelpers, AZ::SystemAllocator, 0)
|
||||
|
||||
static const int s_iconSize = 36; // icon display size (in pixels)
|
||||
static const float s_iconMinScale = 0.1f; // minimum scale for icons in the distance
|
||||
static const float s_iconMaxScale = 1.0f; // maximum scale for icons near the camera
|
||||
static const float s_iconCloseDist = 3.f; // distance at which icons are at maximum scale
|
||||
static const float s_iconFarDist = 40.f; // distance at which icons are at minimum scale
|
||||
static const int IconSize = 36; // icon display size (in pixels)
|
||||
|
||||
// helper function to wrap EBus call to check if helpers are being displayed
|
||||
// note: the ['?'] icon in the top right of the editor
|
||||
static bool HelpersVisible()
|
||||
static bool HelpersVisible(const AzFramework::ViewportId viewportId)
|
||||
{
|
||||
bool helpersVisible = false;
|
||||
EditorRequestBus::BroadcastResult(helpersVisible, &EditorRequests::DisplayHelpersVisible);
|
||||
ViewportInteraction::ViewportSettingsRequestBus::EventResult(
|
||||
helpersVisible, viewportId, &ViewportInteraction::ViewportSettingsRequestBus::Events::HelpersVisible);
|
||||
return helpersVisible;
|
||||
}
|
||||
|
||||
// calculate the icon scale based on how far away it is (distanceSq) from a given point
|
||||
// note: this is mostly likely distance from the camera
|
||||
static float GetIconScale(const float distSq)
|
||||
// helper function to wrap EBus call to check if icons are being displayed
|
||||
static bool IconsVisible(const AzFramework::ViewportId viewportId)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
bool iconsVisible = false;
|
||||
ViewportInteraction::ViewportSettingsRequestBus::EventResult(
|
||||
iconsVisible, viewportId, &ViewportInteraction::ViewportSettingsRequestBus::Events::IconsVisible);
|
||||
return iconsVisible;
|
||||
}
|
||||
|
||||
return s_iconMinScale +
|
||||
(s_iconMaxScale - s_iconMinScale) *
|
||||
(1.0f - AZ::GetClamp(AZ::GetMax(0.0f, sqrtf(distSq) - s_iconCloseDist) / s_iconFarDist, 0.0f, 1.0f));
|
||||
float GetIconScale(const float distance)
|
||||
{
|
||||
return ed_iconMinScale +
|
||||
(ed_iconMaxScale - ed_iconMinScale) *
|
||||
(1.0f - AZ::GetClamp(AZ::GetMax(0.0f, distance - ed_iconCloseDist) / (ed_iconFarDist - ed_iconCloseDist), 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
float GetIconSize(const float distance)
|
||||
{
|
||||
return GetIconScale(distance) * IconSize;
|
||||
}
|
||||
|
||||
static void DisplayComponents(
|
||||
@@ -171,11 +182,14 @@ namespace AzToolsFramework
|
||||
|
||||
const int viewportId = mouseInteraction.m_mouseInteraction.m_interactionId.m_viewportId;
|
||||
|
||||
const bool helpersVisible = HelpersVisible();
|
||||
const bool iconsVisible = IconsVisible(viewportId);
|
||||
|
||||
const AZ::Matrix3x4 cameraView = AzFramework::CameraView(cameraState);
|
||||
const AZ::Matrix4x4 cameraProjection = AzFramework::CameraProjection(cameraState);
|
||||
|
||||
// selecting new entities
|
||||
AZ::EntityId entityIdUnderCursor;
|
||||
float closestDistance = std::numeric_limits<float>::max();
|
||||
float closestDistance = AZStd::numeric_limits<float>::max();
|
||||
for (size_t entityCacheIndex = 0; entityCacheIndex < m_entityDataCache->VisibleEntityDataCount(); ++entityCacheIndex)
|
||||
{
|
||||
const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex);
|
||||
@@ -185,8 +199,7 @@ namespace AzToolsFramework
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2d screen space selection - did we click an icon
|
||||
if (helpersVisible)
|
||||
if (iconsVisible)
|
||||
{
|
||||
// some components choose to hide their icons (e.g. meshes)
|
||||
// we also do not want to test against icons that may not be showing as they're inside a 'closed' entity container
|
||||
@@ -197,17 +210,23 @@ namespace AzToolsFramework
|
||||
const AZ::Vector3& entityPosition = m_entityDataCache->GetVisibleEntityPosition(entityCacheIndex);
|
||||
|
||||
// selecting based on 2d icon - should only do it when visible and not selected
|
||||
const AzFramework::ScreenPoint screenPosition = AzFramework::WorldToScreen(entityPosition, cameraState);
|
||||
const AZ::Vector3 ndcPoint = AzFramework::WorldToScreenNdc(entityPosition, cameraView, cameraProjection);
|
||||
const AzFramework::ScreenPoint screenPosition =
|
||||
AzFramework::ScreenPointFromNdc(AZ::Vector3ToVector2(ndcPoint), cameraState.m_viewportSize);
|
||||
|
||||
const float distSqFromCamera = cameraState.m_position.GetDistanceSq(entityPosition);
|
||||
const auto iconRange = static_cast<float>(GetIconScale(distSqFromCamera) * s_iconSize * 0.5f);
|
||||
const float distanceFromCamera = cameraState.m_position.GetDistance(entityPosition);
|
||||
const auto iconRange = GetIconSize(distanceFromCamera) * 0.5f;
|
||||
const auto screenCoords = mouseInteraction.m_mouseInteraction.m_mousePick.m_screenCoordinates;
|
||||
|
||||
// 2d screen space selection - did we click an icon
|
||||
if (screenCoords.m_x >= screenPosition.m_x - iconRange && screenCoords.m_x <= screenPosition.m_x + iconRange &&
|
||||
screenCoords.m_y >= screenPosition.m_y - iconRange && screenCoords.m_y <= screenPosition.m_y + iconRange)
|
||||
screenCoords.m_y >= screenPosition.m_y - iconRange && screenCoords.m_y <= screenPosition.m_y + iconRange &&
|
||||
ndcPoint.GetZ() < closestDistance)
|
||||
{
|
||||
// use ndc z value for distance here which is in 0-1 range so will most likely 'win' when it comes to the
|
||||
// distance check (this is what we want as the cursor should always favor icons if they are hovered)
|
||||
closestDistance = ndcPoint.GetZ();
|
||||
entityIdUnderCursor = entityId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,9 +239,14 @@ namespace AzToolsFramework
|
||||
if (AabbIntersectMouseRay(mouseInteraction.m_mouseInteraction, aabb))
|
||||
{
|
||||
// if success, pick against specific component
|
||||
if (PickEntity(entityId, mouseInteraction.m_mouseInteraction, closestDistance, viewportId))
|
||||
float closestBoundDifference = AZStd::numeric_limits<float>::max();
|
||||
if (PickEntity(entityId, mouseInteraction.m_mouseInteraction, closestBoundDifference, viewportId))
|
||||
{
|
||||
entityIdUnderCursor = entityId;
|
||||
if (closestBoundDifference < closestDistance)
|
||||
{
|
||||
closestDistance = closestBoundDifference;
|
||||
entityIdUnderCursor = entityId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,55 +300,78 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
|
||||
if (HelpersVisible())
|
||||
const bool iconsVisible = IconsVisible(viewportInfo.m_viewportId);
|
||||
const bool helpersVisible = HelpersVisible(viewportInfo.m_viewportId);
|
||||
|
||||
auto displayCheck = [this](const size_t entityCacheIndex, const AZ::EntityId entityId)
|
||||
{
|
||||
if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex) || !IsSelectableInViewport(entityId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (helpersVisible)
|
||||
{
|
||||
for (size_t entityCacheIndex = 0; entityCacheIndex < m_entityDataCache->VisibleEntityDataCount(); ++entityCacheIndex)
|
||||
{
|
||||
const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex);
|
||||
|
||||
if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex) || !IsSelectableInViewport(entityId))
|
||||
if (const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex);
|
||||
displayCheck(entityCacheIndex, entityId))
|
||||
{
|
||||
continue;
|
||||
// notify components to display
|
||||
DisplayComponents(entityId, viewportInfo, debugDisplay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// notify components to display
|
||||
DisplayComponents(entityId, viewportInfo, debugDisplay);
|
||||
if (iconsVisible)
|
||||
{
|
||||
auto editorViewportIconDisplay = EditorViewportIconDisplay::Get();
|
||||
if (!editorViewportIconDisplay)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_entityDataCache->IsVisibleEntityIconHidden(entityCacheIndex) ||
|
||||
(m_entityDataCache->IsVisibleEntitySelected(entityCacheIndex) && !showIconCheck(entityId)))
|
||||
for (size_t entityCacheIndex = 0; entityCacheIndex < m_entityDataCache->VisibleEntityDataCount(); ++entityCacheIndex)
|
||||
{
|
||||
if (const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex);
|
||||
displayCheck(entityCacheIndex, entityId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int iconTextureId = 0;
|
||||
EditorEntityIconComponentRequestBus::EventResult(
|
||||
iconTextureId, entityId, &EditorEntityIconComponentRequests::GetEntityIconTextureId);
|
||||
|
||||
const AZ::Vector3& entityPosition = m_entityDataCache->GetVisibleEntityPosition(entityCacheIndex);
|
||||
const float distSqFromCamera = cameraState.m_position.GetDistanceSq(entityPosition);
|
||||
|
||||
const float iconScale = GetIconScale(distSqFromCamera);
|
||||
const float iconSize = s_iconSize * iconScale;
|
||||
|
||||
using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType;
|
||||
const AZ::Color iconHighlight = [this, entityCacheIndex]()
|
||||
{
|
||||
if (m_entityDataCache->IsVisibleEntityLocked(entityCacheIndex))
|
||||
if (m_entityDataCache->IsVisibleEntityIconHidden(entityCacheIndex) ||
|
||||
(m_entityDataCache->IsVisibleEntitySelected(entityCacheIndex) && !showIconCheck(entityId)))
|
||||
{
|
||||
return AZ::Color(AZ::u8(100), AZ::u8(100), AZ::u8(100), AZ::u8(255));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_entityDataCache->GetVisibleEntityAccent(entityCacheIndex) == ComponentEntityAccentType::Hover)
|
||||
int iconTextureId = 0;
|
||||
EditorEntityIconComponentRequestBus::EventResult(
|
||||
iconTextureId, entityId, &EditorEntityIconComponentRequests::GetEntityIconTextureId);
|
||||
|
||||
using ComponentEntityAccentType = Components::EditorSelectionAccentSystemComponent::ComponentEntityAccentType;
|
||||
const AZ::Color iconHighlight = [this, entityCacheIndex]()
|
||||
{
|
||||
return AZ::Color(AZ::u8(255), AZ::u8(120), AZ::u8(0), AZ::u8(204));
|
||||
}
|
||||
if (m_entityDataCache->IsVisibleEntityLocked(entityCacheIndex))
|
||||
{
|
||||
return AZ::Color(AZ::u8(100), AZ::u8(100), AZ::u8(100), AZ::u8(255));
|
||||
}
|
||||
|
||||
return AZ::Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}();
|
||||
if (m_entityDataCache->GetVisibleEntityAccent(entityCacheIndex) == ComponentEntityAccentType::Hover)
|
||||
{
|
||||
return AZ::Color(AZ::u8(255), AZ::u8(120), AZ::u8(0), AZ::u8(204));
|
||||
}
|
||||
|
||||
EditorViewportIconDisplay::Get()->DrawIcon({ viewportInfo.m_viewportId, iconTextureId, iconHighlight, entityPosition,
|
||||
EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace,
|
||||
AZ::Vector2{ iconSize, iconSize } });
|
||||
return AZ::Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}();
|
||||
|
||||
const AZ::Vector3& entityPosition = m_entityDataCache->GetVisibleEntityPosition(entityCacheIndex);
|
||||
const float distanceFromCamera = cameraState.m_position.GetDistance(entityPosition);
|
||||
const float iconSize = GetIconSize(distanceFromCamera);
|
||||
|
||||
editorViewportIconDisplay->DrawIcon({ viewportInfo.m_viewportId, iconTextureId, iconHighlight, entityPosition,
|
||||
EditorViewportIconDisplayInterface::CoordinateSpace::WorldSpace,
|
||||
AZ::Vector2{ iconSize, iconSize } });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,4 +106,12 @@ namespace AzToolsFramework
|
||||
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
|
||||
const FocusModeInterface* m_focusModeInterface = nullptr; //!< API to interact with focus mode functionality.
|
||||
};
|
||||
|
||||
//! Calculate the icon scale based on how far away it is from a given point.
|
||||
//! @note This is mostly likely distance from the camera.
|
||||
float GetIconScale(float distance);
|
||||
|
||||
//! Calculate the icon size based on how far away it is from a given point.
|
||||
//! @note This is the base icon size multiplied by the icon scale to give a final viewport size.
|
||||
float GetIconSize(float distance);
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+6
-7
@@ -2521,10 +2521,9 @@ namespace AzToolsFramework
|
||||
AZStd::erase_if(
|
||||
m_selectedEntityIds,
|
||||
[readOnlyEntityPublicInterface](auto entityId)
|
||||
{
|
||||
return readOnlyEntityPublicInterface->IsReadOnly(entityId);
|
||||
}
|
||||
);
|
||||
{
|
||||
return readOnlyEntityPublicInterface->IsReadOnly(entityId);
|
||||
});
|
||||
}
|
||||
|
||||
// note: create/destroy pattern to be addressed
|
||||
@@ -3285,9 +3284,9 @@ namespace AzToolsFramework
|
||||
QObject::connect(
|
||||
action, &QAction::triggered, action,
|
||||
[this]
|
||||
{
|
||||
ToggleCenterPivotSelection();
|
||||
});
|
||||
{
|
||||
ToggleCenterPivotSelection();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -32,6 +32,8 @@ namespace AzToolsFramework
|
||||
constexpr inline AZ::Crc32 EditReset = AZ_CRC_CE("com.o3de.action.editortransform.editreset");
|
||||
constexpr inline AZ::Crc32 EditResetManipulator = AZ_CRC_CE("com.o3de.action.editortransform.editresetmanipulator");
|
||||
constexpr inline AZ::Crc32 ViewportUiVisible = AZ_CRC_CE("com.o3de.action.editortransform.viewportuivisible");
|
||||
constexpr inline AZ::Crc32 Helpers = AZ_CRC_CE("com.o3de.action.editor.helpers");
|
||||
constexpr inline AZ::Crc32 Icons = AZ_CRC_CE("com.o3de.action.editor.icons");
|
||||
//@}
|
||||
|
||||
//! Provide interface for EditorTransformComponentSelection requests.
|
||||
|
||||
@@ -40,16 +40,12 @@
|
||||
|
||||
#include <Tests/BoundsTestComponent.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
std::ostream& operator<<(std::ostream& os, const EntityId entityId)
|
||||
{
|
||||
return os << entityId.ToString().c_str();
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using AzToolsFramework::ViewportInteraction::BuildMouseButtons;
|
||||
using AzToolsFramework::ViewportInteraction::BuildMouseInteraction;
|
||||
using AzToolsFramework::ViewportInteraction::BuildMousePick;
|
||||
|
||||
AzToolsFramework::EntityIdList SelectedEntities()
|
||||
{
|
||||
AzToolsFramework::EntityIdList selectedEntitiesBefore;
|
||||
@@ -137,6 +133,18 @@ namespace UnitTest
|
||||
AzToolsFramework::EntityIdList m_entityIds;
|
||||
};
|
||||
|
||||
AZ::EntityId CreateEntityWithBounds(const char* entityName)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::EntityId entityId = CreateDefaultEditorEntity(entityName, &entity);
|
||||
|
||||
entity->Deactivate();
|
||||
entity->CreateComponent<BoundsTestComponent>();
|
||||
entity->Activate();
|
||||
|
||||
return entityId;
|
||||
}
|
||||
|
||||
class EditorTransformComponentSelectionViewportPickingFixture : public ToolsApplicationFixture
|
||||
{
|
||||
public:
|
||||
@@ -146,21 +154,9 @@ namespace UnitTest
|
||||
// register a simple component implementing BoundsRequestBus and EditorComponentSelectionRequestsBus
|
||||
app->RegisterComponentDescriptor(BoundsTestComponent::CreateDescriptor());
|
||||
|
||||
auto createEntityWithBoundsFn = [](const char* entityName)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::EntityId entityId = CreateDefaultEditorEntity(entityName, &entity);
|
||||
|
||||
entity->Deactivate();
|
||||
entity->CreateComponent<BoundsTestComponent>();
|
||||
entity->Activate();
|
||||
|
||||
return entityId;
|
||||
};
|
||||
|
||||
m_entityId1 = createEntityWithBoundsFn("Entity1");
|
||||
m_entityId2 = createEntityWithBoundsFn("Entity2");
|
||||
m_entityId3 = createEntityWithBoundsFn("Entity3");
|
||||
m_entityId1 = CreateEntityWithBounds("Entity1");
|
||||
m_entityId2 = CreateEntityWithBounds("Entity2");
|
||||
m_entityId3 = CreateEntityWithBounds("Entity3");
|
||||
}
|
||||
|
||||
void PositionEntities()
|
||||
@@ -959,6 +955,9 @@ namespace UnitTest
|
||||
|
||||
const auto entity2ScreenPosition = AzFramework::WorldToScreen(AzToolsFramework::GetWorldTranslation(m_entityId2), m_cameraState);
|
||||
|
||||
// ensure icons are not enabled to avoid them interfering with bound detection
|
||||
m_viewportManipulatorInteraction->GetViewportInteraction().SetIconsVisible(false);
|
||||
|
||||
// click the entity in the viewport
|
||||
m_actionDispatcher->SetStickySelect(true)
|
||||
->CameraState(m_cameraState)
|
||||
@@ -974,6 +973,137 @@ namespace UnitTest
|
||||
EXPECT_THAT(selectedEntities, UnorderedElementsAreArray(expectedSelectedEntities));
|
||||
}
|
||||
|
||||
// entity can be selected using icon
|
||||
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, CursorOverEntityIconReturnsThatEntityId)
|
||||
{
|
||||
const AZ::EntityId boundlessEntityId = CreateDefaultEditorEntity("BoundlessEntity");
|
||||
|
||||
// camera (go to position format) -5.00, -8.00, 5.00, 0.00, 0.00
|
||||
AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateTranslation(AZ::Vector3(-5.0f, -8.0f, 5.0f)));
|
||||
// position entity in the world
|
||||
AZ::TransformBus::Event(boundlessEntityId, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-5.0f, -1.0f, 5.0f));
|
||||
|
||||
const float distanceFromCamera = m_cameraState.m_position.GetDistance(AzToolsFramework::GetWorldTranslation(boundlessEntityId));
|
||||
|
||||
const auto quaterIconSize = AzToolsFramework::GetIconSize(distanceFromCamera) * 0.25f;
|
||||
const auto entity1ScreenPosition =
|
||||
AzFramework::WorldToScreen(AzToolsFramework::GetWorldTranslation(boundlessEntityId), m_cameraState) +
|
||||
AzFramework::ScreenVectorFromVector2(AZ::Vector2(quaterIconSize));
|
||||
|
||||
AzToolsFramework::EditorVisibleEntityDataCache editorVisibleEntityDataCache;
|
||||
AzToolsFramework::EditorHelpers editorHelpers(&editorVisibleEntityDataCache);
|
||||
|
||||
const auto viewportId = m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId();
|
||||
const auto mousePick = BuildMousePick(m_cameraState, entity1ScreenPosition);
|
||||
const auto mouseInteraction = BuildMouseInteraction(
|
||||
mousePick, BuildMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::None),
|
||||
AzToolsFramework::ViewportInteraction::InteractionId(AZ::EntityId(), viewportId),
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifiers());
|
||||
const auto mouseInteractionEvent = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent(
|
||||
mouseInteraction, AzToolsFramework::ViewportInteraction::MouseEvent::Move, false);
|
||||
|
||||
// mimic mouse move
|
||||
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity1ScreenPosition);
|
||||
|
||||
// simulate hovering over an icon in the viewport
|
||||
editorVisibleEntityDataCache.CalculateVisibleEntityDatas(AzFramework::ViewportInfo{ viewportId });
|
||||
auto entityIdUnderCursor = editorHelpers.FindEntityIdUnderCursor(m_cameraState, mouseInteractionEvent);
|
||||
|
||||
using ::testing::Eq;
|
||||
EXPECT_THAT(entityIdUnderCursor.EntityIdUnderCursor(), Eq(boundlessEntityId));
|
||||
}
|
||||
|
||||
// overlapping icons, nearest is detected
|
||||
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, CursorOverOverlappingEntityIconsReturnsClosestEntityId)
|
||||
{
|
||||
const AZ::EntityId boundlessEntityId1 = CreateDefaultEditorEntity("BoundlessEntity1");
|
||||
const AZ::EntityId boundlessEntityId2 = CreateDefaultEditorEntity("BoundlessEntity2");
|
||||
|
||||
// camera (go to position format) -5.00, -8.00, 5.00, 0.00, 0.00
|
||||
AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateTranslation(AZ::Vector3(-5.0f, -8.0f, 5.0f)));
|
||||
// position entities in the world
|
||||
AZ::TransformBus::Event(boundlessEntityId1, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-5.0f, -1.0f, 5.0f));
|
||||
// note: boundlessEntityId2 is closer to the camera
|
||||
AZ::TransformBus::Event(boundlessEntityId2, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-5.0f, -3.0f, 5.0f));
|
||||
|
||||
const float distanceFromCamera = m_cameraState.m_position.GetDistance(AzToolsFramework::GetWorldTranslation(boundlessEntityId2));
|
||||
|
||||
const auto quaterIconSize = AzToolsFramework::GetIconSize(distanceFromCamera) * 0.25f;
|
||||
const auto entity2ScreenPosition =
|
||||
AzFramework::WorldToScreen(AzToolsFramework::GetWorldTranslation(boundlessEntityId2), m_cameraState) +
|
||||
AzFramework::ScreenVectorFromVector2(AZ::Vector2(quaterIconSize));
|
||||
|
||||
AzToolsFramework::EditorVisibleEntityDataCache editorVisibleEntityDataCache;
|
||||
AzToolsFramework::EditorHelpers editorHelpers(&editorVisibleEntityDataCache);
|
||||
|
||||
const auto viewportId = m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId();
|
||||
const auto mousePick = BuildMousePick(m_cameraState, entity2ScreenPosition);
|
||||
const auto mouseInteraction = BuildMouseInteraction(
|
||||
mousePick, BuildMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::None),
|
||||
AzToolsFramework::ViewportInteraction::InteractionId(AZ::EntityId(), viewportId),
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifiers());
|
||||
const auto mouseInteractionEvent = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent(
|
||||
mouseInteraction, AzToolsFramework::ViewportInteraction::MouseEvent::Move, false);
|
||||
|
||||
// mimic mouse move
|
||||
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity2ScreenPosition);
|
||||
|
||||
// simulate hovering over an icon in the viewport
|
||||
editorVisibleEntityDataCache.CalculateVisibleEntityDatas(AzFramework::ViewportInfo{ viewportId });
|
||||
auto entityIdUnderCursor = editorHelpers.FindEntityIdUnderCursor(m_cameraState, mouseInteractionEvent);
|
||||
|
||||
using ::testing::Eq;
|
||||
EXPECT_THAT(entityIdUnderCursor.EntityIdUnderCursor(), Eq(boundlessEntityId2));
|
||||
}
|
||||
|
||||
// if an entity with an icon is behind an entity with a bound, the entity with the icon will be selected
|
||||
// even if the bound is closer (this is because icons are treated as if they are on the near clip plane)
|
||||
TEST_F(
|
||||
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, FurtherAwayEntityWithIconReturnedWhenBoundEntityIsInFront)
|
||||
{
|
||||
const AZ::EntityId boundEntityId = CreateEntityWithBounds("BoundEntity");
|
||||
const AZ::EntityId boundlessEntityId = CreateDefaultEditorEntity("BoundlessEntity");
|
||||
|
||||
auto* boundTestComponent = AzToolsFramework::GetEntityById(boundEntityId)->FindComponent<BoundsTestComponent>();
|
||||
boundTestComponent->m_localBounds = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-1.5f, -0.5f, -0.5f), AZ::Vector3(1.5f, 0.5, 0.5f));
|
||||
|
||||
// camera (go to position format) -5.00, -8.00, 5.00, 0.00, 0.00
|
||||
AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateTranslation(AZ::Vector3(-5.0f, -8.0f, 5.0f)));
|
||||
// position entities in the world
|
||||
AZ::TransformBus::Event(boundEntityId, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-4.0f, -3.0f, 5.0f));
|
||||
// note: boundlessEntityId2 is closer to the camera
|
||||
AZ::TransformBus::Event(boundlessEntityId, &AZ::TransformBus::Events::SetWorldTranslation, AZ::Vector3(-5.0f, -1.0f, 5.0f));
|
||||
|
||||
const float distanceFromCamera = m_cameraState.m_position.GetDistance(AzToolsFramework::GetWorldTranslation(boundlessEntityId));
|
||||
|
||||
const auto quaterIconSize = AzToolsFramework::GetIconSize(distanceFromCamera) * 0.25f;
|
||||
const auto entity2ScreenPosition =
|
||||
AzFramework::WorldToScreen(AzToolsFramework::GetWorldTranslation(boundlessEntityId), m_cameraState) +
|
||||
AzFramework::ScreenVectorFromVector2(AZ::Vector2(quaterIconSize));
|
||||
|
||||
AzToolsFramework::EditorVisibleEntityDataCache editorVisibleEntityDataCache;
|
||||
AzToolsFramework::EditorHelpers editorHelpers(&editorVisibleEntityDataCache);
|
||||
|
||||
const auto viewportId = m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId();
|
||||
const auto mousePick = BuildMousePick(m_cameraState, entity2ScreenPosition);
|
||||
const auto mouseInteraction = BuildMouseInteraction(
|
||||
mousePick, BuildMouseButtons(AzToolsFramework::ViewportInteraction::MouseButton::None),
|
||||
AzToolsFramework::ViewportInteraction::InteractionId(AZ::EntityId(), viewportId),
|
||||
AzToolsFramework::ViewportInteraction::KeyboardModifiers());
|
||||
const auto mouseInteractionEvent = AzToolsFramework::ViewportInteraction::BuildMouseInteractionEvent(
|
||||
mouseInteraction, AzToolsFramework::ViewportInteraction::MouseEvent::Move, false);
|
||||
|
||||
// mimic mouse move
|
||||
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity2ScreenPosition);
|
||||
|
||||
// simulate hovering over an icon in the viewport
|
||||
editorVisibleEntityDataCache.CalculateVisibleEntityDatas(AzFramework::ViewportInfo{ viewportId });
|
||||
auto entityIdUnderCursor = editorHelpers.FindEntityIdUnderCursor(m_cameraState, mouseInteractionEvent);
|
||||
|
||||
using ::testing::Eq;
|
||||
EXPECT_THAT(entityIdUnderCursor.EntityIdUnderCursor(), Eq(boundlessEntityId));
|
||||
}
|
||||
|
||||
class EditorTransformComponentSelectionViewportPickingManipulatorTestFixtureParam
|
||||
: public EditorTransformComponentSelectionViewportPickingManipulatorTestFixture
|
||||
, public ::testing::WithParamInterface<bool>
|
||||
@@ -1709,8 +1839,9 @@ namespace UnitTest
|
||||
using MouseInteractionResult = AzToolsFramework::ViewportInteraction::MouseInteractionResult;
|
||||
|
||||
public:
|
||||
WheelEventWidget(QWidget* parent = nullptr)
|
||||
WheelEventWidget(const AzFramework::ViewportId viewportId, QWidget* parent = nullptr)
|
||||
: QWidget(parent)
|
||||
, m_viewportId(viewportId)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1719,7 +1850,7 @@ namespace UnitTest
|
||||
namespace vi = AzToolsFramework::ViewportInteraction;
|
||||
vi::MouseInteraction mouseInteraction;
|
||||
mouseInteraction.m_interactionId.m_cameraId = AZ::EntityId();
|
||||
mouseInteraction.m_interactionId.m_viewportId = 0;
|
||||
mouseInteraction.m_interactionId.m_viewportId = m_viewportId;
|
||||
mouseInteraction.m_mouseButtons = vi::BuildMouseButtons(ev->buttons());
|
||||
mouseInteraction.m_mousePick = vi::MousePick();
|
||||
mouseInteraction.m_keyboardModifiers = vi::BuildKeyboardModifiers(ev->modifiers());
|
||||
@@ -1731,15 +1862,15 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
MouseInteractionResult m_mouseInteractionResult;
|
||||
AzFramework::ViewportId m_viewportId;
|
||||
};
|
||||
|
||||
TEST_F(EditorTransformComponentSelectionFixture, MouseScrollWheelSwitchesTransformMode)
|
||||
TEST_F(EditorTransformComponentSelectionManipulatorTestFixture, MouseScrollWheelSwitchesTransformMode)
|
||||
{
|
||||
using ::testing::Eq;
|
||||
namespace vi = AzToolsFramework::ViewportInteraction;
|
||||
using AzToolsFramework::EditorTransformComponentSelectionRequestBus;
|
||||
|
||||
const auto transformMode = []()
|
||||
const auto transformMode = []
|
||||
{
|
||||
EditorTransformComponentSelectionRequestBus::Events::Mode transformMode;
|
||||
EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
@@ -1752,7 +1883,7 @@ namespace UnitTest
|
||||
// preconditions
|
||||
EXPECT_THAT(transformMode(), EditorTransformComponentSelectionRequestBus::Events::Mode::Translation);
|
||||
|
||||
auto wheelEventWidget = WheelEventWidget();
|
||||
auto wheelEventWidget = WheelEventWidget(m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId());
|
||||
// attach the global event filter to the placeholder widget
|
||||
AzQtComponents::GlobalEventFilter globalEventFilter(QApplication::instance());
|
||||
wheelEventWidget.installEventFilter(&globalEventFilter);
|
||||
@@ -1768,6 +1899,7 @@ namespace UnitTest
|
||||
|
||||
// then
|
||||
// transform mode has changed and mouse event was handled
|
||||
using ::testing::Eq;
|
||||
EXPECT_THAT(transformMode(), Eq(EditorTransformComponentSelectionRequestBus::Events::Mode::Rotation));
|
||||
EXPECT_THAT(wheelEventWidget.m_mouseInteractionResult, Eq(vi::MouseInteractionResult::Viewport));
|
||||
}
|
||||
@@ -3100,7 +3232,7 @@ namespace UnitTest
|
||||
const AZ::Transform finalEntityTransform = AzToolsFramework::GetWorldTransform(m_entityIdBox);
|
||||
|
||||
const auto viewportRay = AzToolsFramework::ViewportInteraction::ViewportScreenToWorldRay(m_cameraState, initialPositionScreen);
|
||||
const auto distanceAway = (finalEntityTransform.GetTranslation() - viewportRay.origin).GetLength();
|
||||
const auto distanceAway = (finalEntityTransform.GetTranslation() - viewportRay.m_origin).GetLength();
|
||||
|
||||
// ensure final world positions match
|
||||
EXPECT_THAT(finalEntityTransform, IsCloseTolerance(finalTransformWorld, 0.01f));
|
||||
|
||||
@@ -62,7 +62,6 @@ namespace UnitTest
|
||||
|
||||
void BrowseForAssets(AssetBrowser::AssetSelectionModel& /*selection*/) override {}
|
||||
int GetIconTextureIdFromEntityIconPath(const AZStd::string& entityIconPath) override { AZ_UNUSED(entityIconPath); return 0; }
|
||||
bool DisplayHelpersVisible() override { return false; }
|
||||
|
||||
void GoToSelectedEntitiesInViewports() override
|
||||
{
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
#include <Tests/FocusMode/EditorFocusModeSelectionFixture.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
namespace UnitTest
|
||||
{
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithNoContainers)
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithNoContainers)
|
||||
{
|
||||
// When no containers are in the way, the function will just return the entityId of the entity that was clicked.
|
||||
|
||||
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithClosedContainer)
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithClosedContainer)
|
||||
{
|
||||
// If a closed container is an ancestor of the queried entity, the closed container is selected.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); // Containers are closed by default
|
||||
@@ -40,7 +40,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithOpenContainer)
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithOpenContainer)
|
||||
{
|
||||
// If a closed container is an ancestor of the queried entity, the closed container is selected.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
@@ -58,7 +58,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithMultipleClosedContainers)
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithMultipleClosedContainers)
|
||||
{
|
||||
// If multiple closed containers are ancestors of the queried entity, the highest closed container is selected.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
@@ -77,7 +77,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithMultipleContainers)
|
||||
TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionFindHighestSelectableEntityWithMultipleContainers)
|
||||
{
|
||||
// If multiple containers are ancestors of the queried entity, the highest closed container is selected.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
@@ -96,4 +96,4 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
|
||||
}
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
#include <Tests/FocusMode/EditorFocusModeFixture.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
namespace UnitTest
|
||||
{
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_Register)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityRegister)
|
||||
{
|
||||
// Registering an entity is successful.
|
||||
auto outcome = m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]);
|
||||
@@ -20,7 +20,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_RegisterTwice)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityRegisterTwice)
|
||||
{
|
||||
// Registering an entity twice fails.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]);
|
||||
@@ -31,7 +31,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_Unregister)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityUnregister)
|
||||
{
|
||||
// Unregistering a container entity is successful.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]);
|
||||
@@ -39,21 +39,21 @@ namespace AzToolsFramework
|
||||
EXPECT_TRUE(outcome.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_UnregisterRegularEntity)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityUnregisterRegularEntity)
|
||||
{
|
||||
// Unregistering an entity that was not previously registered fails.
|
||||
auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]);
|
||||
EXPECT_FALSE(outcome.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_UnregisterTwice)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityUnregisterTwice)
|
||||
{
|
||||
// Unregistering a container entity twice fails.
|
||||
auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]);
|
||||
EXPECT_FALSE(outcome.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnRegularEntity)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOnRegularEntity)
|
||||
{
|
||||
// If a regular entity is passed, IsContainer returns false.
|
||||
// Note that we use a different entity than the tests above to validate a completely new EntityId.
|
||||
@@ -61,7 +61,7 @@ namespace AzToolsFramework
|
||||
EXPECT_FALSE(isContainer);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnRegisteredContainer)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOnRegisteredContainer)
|
||||
{
|
||||
// If a container entity is passed, IsContainer returns true.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
|
||||
@@ -72,7 +72,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnUnRegisteredContainer)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOnUnRegisteredContainer)
|
||||
{
|
||||
// If an entity that was previously a container but was then unregistered is passed, IsContainer returns false.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
|
||||
@@ -82,14 +82,14 @@ namespace AzToolsFramework
|
||||
EXPECT_FALSE(isContainer);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpenOnRegularEntity)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntitySetContainerOpenOnRegularEntity)
|
||||
{
|
||||
// Setting a regular entity to open should return a failure.
|
||||
auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true);
|
||||
EXPECT_FALSE(outcome.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpen)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntitySetContainerOpen)
|
||||
{
|
||||
// Set a container entity to open, and verify the operation was successful.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
@@ -100,7 +100,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpenTwice)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntitySetContainerOpenTwice)
|
||||
{
|
||||
// Set a container entity to open twice, and verify that does not cause a failure (as intended).
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
@@ -112,7 +112,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerClosed)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntitySetContainerClosed)
|
||||
{
|
||||
// Set a container entity to closed, and verify the operation was successful.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
@@ -122,16 +122,16 @@ namespace AzToolsFramework
|
||||
// Restore default state for other tests.
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnRegularEntity)
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOpenOnRegularEntity)
|
||||
{
|
||||
// Query open state on a regular entity, and verify it returns true.
|
||||
// Open containers behave exactly as regular entities, so this is the expected return value.
|
||||
bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]);
|
||||
EXPECT_TRUE(isOpen);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnDefaultContainerEntity)
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOpenOnDefaultContainerEntity)
|
||||
{
|
||||
// Query open state on a newly registered container entity, and verify it returns false.
|
||||
// Containers are registered closed by default.
|
||||
@@ -142,8 +142,8 @@ namespace AzToolsFramework
|
||||
// Restore default state for other tests.
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnOpenContainerEntity)
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOpenOnOpenContainerEntity)
|
||||
{
|
||||
// Query open state on a container entity that was opened, and verify it returns true.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
|
||||
@@ -154,8 +154,8 @@ namespace AzToolsFramework
|
||||
// Restore default state for other tests.
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnClosedContainerEntity)
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityIsContainerOpenOnClosedContainerEntity)
|
||||
{
|
||||
// Query open state on a container entity that was opened and then closed, and verify it returns false.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
|
||||
@@ -167,8 +167,8 @@ namespace AzToolsFramework
|
||||
// Restore default state for other tests.
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_ContainerOpenStateIsPreserved)
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityContainerOpenStateIsPreserved)
|
||||
{
|
||||
// Register an entity as container, open it, then unregister it.
|
||||
// When the entity is registered again, the open state should be preserved.
|
||||
@@ -184,15 +184,15 @@ namespace AzToolsFramework
|
||||
// Restore default state for other tests.
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearSucceeds)
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityClearSucceeds)
|
||||
{
|
||||
// The Clear function works if no container is registered.
|
||||
auto outcome = m_containerEntityInterface->Clear(m_editorEntityContextId);
|
||||
EXPECT_TRUE(outcome.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearFailsIfContainersAreStillRegistered)
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityClearFailsIfContainersAreStillRegistered)
|
||||
{
|
||||
// The Clear function fails if a container is registered.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
|
||||
@@ -202,8 +202,8 @@ namespace AzToolsFramework
|
||||
// Restore default state for other tests.
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearSucceedsIfContainersAreUnregistered)
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityClearSucceedsIfContainersAreUnregistered)
|
||||
{
|
||||
// The Clear function fails if a container is registered.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
|
||||
@@ -212,7 +212,7 @@ namespace AzToolsFramework
|
||||
EXPECT_TRUE(outcome.IsSuccess());
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearDeletesPreservedOpenStates)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityClearDeletesPreservedOpenStates)
|
||||
{
|
||||
// Register an entity as container, open it, unregister it, then call clear.
|
||||
// When the entity is registered again, the open state should not be preserved.
|
||||
@@ -230,14 +230,14 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithNoContainers)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithNoContainers)
|
||||
{
|
||||
// When no containers are in the way, the function will just return the entityId that was passed to it.
|
||||
AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]);
|
||||
EXPECT_EQ(selectedEntityId, m_entityMap[Passenger2EntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithClosedContainer)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithClosedContainer)
|
||||
{
|
||||
// If a closed container is an ancestor of the queried entity, the closed container is selected.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); // Containers are closed by default
|
||||
@@ -248,7 +248,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithOpenContainer)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithOpenContainer)
|
||||
{
|
||||
// If an open container is an ancestor of the queried entity, it is ignored.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
|
||||
@@ -261,7 +261,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithMultipleClosedContainers)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithMultipleClosedContainers)
|
||||
{
|
||||
// If multiple closed containers are ancestors of the queried entity, the highest closed container is selected.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
@@ -275,7 +275,7 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithMultipleContainers)
|
||||
TEST_F(EditorFocusModeFixture, ContainerEntityFindHighestSelectableEntityWithMultipleContainers)
|
||||
{
|
||||
// If multiple containers are ancestors of the queried entity, the highest closed container is selected.
|
||||
m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
@@ -289,5 +289,4 @@ namespace AzToolsFramework
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
|
||||
m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <Tests/BoundsTestComponent.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
namespace UnitTest
|
||||
{
|
||||
void ClearSelectedEntities()
|
||||
{
|
||||
@@ -31,14 +31,14 @@ namespace AzToolsFramework
|
||||
void EditorFocusModeFixture::SetUpEditorFixtureImpl()
|
||||
{
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
|
||||
m_containerEntityInterface = AZ::Interface<ContainerEntityInterface>::Get();
|
||||
m_containerEntityInterface = AZ::Interface<AzToolsFramework::ContainerEntityInterface>::Get();
|
||||
ASSERT_TRUE(m_containerEntityInterface != nullptr);
|
||||
|
||||
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
|
||||
m_focusModeInterface = AZ::Interface<AzToolsFramework::FocusModeInterface>::Get();
|
||||
ASSERT_TRUE(m_focusModeInterface != nullptr);
|
||||
|
||||
// register a simple component implementing BoundsRequestBus and EditorComponentSelectionRequestsBus
|
||||
@@ -68,26 +68,26 @@ namespace AzToolsFramework
|
||||
ClearSelectedEntities();
|
||||
}
|
||||
|
||||
void EditorFocusModeFixture::GenerateTestHierarchy()
|
||||
void EditorFocusModeFixture::GenerateTestHierarchy()
|
||||
{
|
||||
/*
|
||||
* City
|
||||
* |_ Street
|
||||
* |_ Car
|
||||
* | |_ Passenger
|
||||
* |_ SportsCar
|
||||
* |_ Passenger
|
||||
*/
|
||||
* City
|
||||
* |_ Street
|
||||
* |_ Car
|
||||
* | |_ Passenger
|
||||
* |_ SportsCar
|
||||
* |_ Passenger
|
||||
*/
|
||||
|
||||
m_entityMap[CityEntityName] = CreateEditorEntity(CityEntityName, AZ::EntityId());
|
||||
m_entityMap[StreetEntityName] = CreateEditorEntity(StreetEntityName, m_entityMap[CityEntityName]);
|
||||
m_entityMap[CarEntityName] = CreateEditorEntity(CarEntityName, m_entityMap[StreetEntityName]);
|
||||
m_entityMap[Passenger1EntityName] = CreateEditorEntity(Passenger1EntityName, m_entityMap[CarEntityName]);
|
||||
m_entityMap[SportsCarEntityName] = CreateEditorEntity(SportsCarEntityName, m_entityMap[StreetEntityName]);
|
||||
m_entityMap[Passenger2EntityName] = CreateEditorEntity(Passenger2EntityName, m_entityMap[SportsCarEntityName]);
|
||||
m_entityMap[CityEntityName] = CreateEditorEntity(CityEntityName, AZ::EntityId());
|
||||
m_entityMap[StreetEntityName] = CreateEditorEntity(StreetEntityName, m_entityMap[CityEntityName]);
|
||||
m_entityMap[CarEntityName] = CreateEditorEntity(CarEntityName, m_entityMap[StreetEntityName]);
|
||||
m_entityMap[Passenger1EntityName] = CreateEditorEntity(Passenger1EntityName, m_entityMap[CarEntityName]);
|
||||
m_entityMap[SportsCarEntityName] = CreateEditorEntity(SportsCarEntityName, m_entityMap[StreetEntityName]);
|
||||
m_entityMap[Passenger2EntityName] = CreateEditorEntity(Passenger2EntityName, m_entityMap[SportsCarEntityName]);
|
||||
|
||||
// Add a BoundsTestComponent to the Car entity.
|
||||
AZ::Entity* entity = GetEntityById(m_entityMap[CarEntityName]);
|
||||
AZ::Entity* entity = AzToolsFramework::GetEntityById(m_entityMap[CarEntityName]);
|
||||
|
||||
entity->Deactivate();
|
||||
entity->CreateComponent<UnitTest::BoundsTestComponent>();
|
||||
@@ -113,4 +113,4 @@ namespace AzToolsFramework
|
||||
|
||||
return entity->GetId();
|
||||
}
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
namespace UnitTest
|
||||
{
|
||||
class EditorFocusModeFixture
|
||||
: public UnitTest::ToolsApplicationFixture
|
||||
class EditorFocusModeFixture : public ToolsApplicationFixture
|
||||
{
|
||||
protected:
|
||||
void SetUpEditorFixtureImpl() override;
|
||||
@@ -32,8 +31,8 @@ namespace AzToolsFramework
|
||||
|
||||
AZStd::unordered_map<AZStd::string, AZ::EntityId> m_entityMap;
|
||||
|
||||
ContainerEntityInterface* m_containerEntityInterface = nullptr;
|
||||
FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
AzToolsFramework::ContainerEntityInterface* m_containerEntityInterface = nullptr;
|
||||
AzToolsFramework::FocusModeInterface* m_focusModeInterface = nullptr;
|
||||
|
||||
public:
|
||||
AzToolsFramework::EntityIdList GetSelectedEntities();
|
||||
@@ -53,4 +52,4 @@ namespace AzToolsFramework
|
||||
inline static AZ::Vector3 WorldCarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f);
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -26,11 +26,17 @@
|
||||
#include <AzToolsFramework/Manipulators/ManipulatorManager.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorVisibleEntityDataCache.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
namespace UnitTest
|
||||
{
|
||||
class EditorFocusModeSelectionFixture : public UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin<EditorFocusModeFixture>
|
||||
class EditorFocusModeSelectionFixture : public IndirectCallManipulatorViewportInteractionFixtureMixin<EditorFocusModeFixture>
|
||||
{
|
||||
public:
|
||||
void SetUpEditorFixtureImpl() override
|
||||
{
|
||||
IndirectCallManipulatorViewportInteractionFixtureMixin<EditorFocusModeFixture>::SetUpEditorFixtureImpl();
|
||||
m_viewportManipulatorInteraction->GetViewportInteraction().SetIconsVisible(false);
|
||||
}
|
||||
|
||||
void ClickAtWorldPositionOnViewport(const AZ::Vector3& worldPosition)
|
||||
{
|
||||
// Calculate the world position in screen space
|
||||
@@ -40,4 +46,4 @@ namespace AzToolsFramework
|
||||
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(carScreenPosition)->MouseLButtonDown()->MouseLButtonUp();
|
||||
}
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
#include <Tests/FocusMode/EditorFocusModeSelectionFixture.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
namespace UnitTest
|
||||
{
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnLevel)
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnLevel)
|
||||
{
|
||||
// Click on Car Entity
|
||||
ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
|
||||
@@ -21,7 +21,7 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnAncestor)
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnAncestor)
|
||||
{
|
||||
// Set the focus on the Street Entity (parent of the test entity)
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
|
||||
@@ -35,7 +35,7 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnItself)
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnItself)
|
||||
{
|
||||
// Set the focus on the Car Entity (test entity)
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]);
|
||||
@@ -49,7 +49,7 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnSibling)
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnSibling)
|
||||
{
|
||||
// Set the focus on the SportsCar Entity (sibling of the test entity)
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]);
|
||||
@@ -62,7 +62,7 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(selectedEntitiesAfter.size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnDescendant)
|
||||
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionSelectEntityWithFocusOnDescendant)
|
||||
{
|
||||
// Set the focus on the Passenger1 Entity (child of the entity)
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger1EntityName]);
|
||||
@@ -74,4 +74,4 @@ namespace AzToolsFramework
|
||||
auto selectedEntitiesAfter = GetSelectedEntities();
|
||||
EXPECT_EQ(selectedEntitiesAfter.size(), 0);
|
||||
}
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
#include <Tests/FocusMode/EditorFocusModeFixture.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
namespace UnitTest
|
||||
{
|
||||
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_SetFocus)
|
||||
TEST_F(EditorFocusModeFixture, SetFocus)
|
||||
{
|
||||
// When an entity is set as the focus root, GetFocusRoot should return its EntityId.
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]);
|
||||
@@ -20,7 +20,7 @@ namespace AzToolsFramework
|
||||
m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_ClearFocus)
|
||||
TEST_F(EditorFocusModeFixture, ClearFocus)
|
||||
{
|
||||
// Change the value from the default.
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]);
|
||||
@@ -30,7 +30,7 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(m_focusModeInterface->GetFocusRoot(m_editorEntityContextId), AZ::EntityId());
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_AncestorsDescendants)
|
||||
TEST_F(EditorFocusModeFixture, IsInFocusSubTreeAncestorsDescendants)
|
||||
{
|
||||
// When the focus is set to an entity, all its descendants are in the focus subtree while the ancestors aren't.
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
|
||||
@@ -43,7 +43,7 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Siblings)
|
||||
TEST_F(EditorFocusModeFixture, IsInFocusSubTreeSiblings)
|
||||
{
|
||||
// If the root entity has siblings, they are also outside of the focus subtree.
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]);
|
||||
@@ -56,7 +56,7 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), false);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Leaf)
|
||||
TEST_F(EditorFocusModeFixture, IsInFocusSubTreeLeaf)
|
||||
{
|
||||
// If the root is a leaf, then the focus subtree will consists of just that entity.
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger2EntityName]);
|
||||
@@ -69,7 +69,7 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true);
|
||||
}
|
||||
|
||||
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Clear)
|
||||
TEST_F(EditorFocusModeFixture, IsInFocusSubTreeClear)
|
||||
{
|
||||
// Change the value from the default.
|
||||
m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
|
||||
@@ -84,4 +84,4 @@ namespace AzToolsFramework
|
||||
EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true);
|
||||
EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true);
|
||||
}
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
-1
@@ -137,7 +137,6 @@ namespace UnitTest
|
||||
void CreateEditorRepresentation(AZ::Entity* entity) override;
|
||||
void BrowseForAssets(AzToolsFramework::AssetBrowser::AssetSelectionModel& selection) override { AZ_UNUSED(selection); }
|
||||
int GetIconTextureIdFromEntityIconPath(const AZStd::string& entityIconPath) override { AZ_UNUSED(entityIconPath); return 0; }
|
||||
bool DisplayHelpersVisible() override { return false; }
|
||||
|
||||
/*
|
||||
* AssetSystemRequestBus
|
||||
|
||||
@@ -74,10 +74,6 @@ namespace UnitTest
|
||||
AZStd::unique_ptr<AzToolsFramework::AssetBrowser::AssetBrowserFilterModel> m_filterModel;
|
||||
AZStd::unique_ptr<AzToolsFramework::AssetBrowser::AssetBrowserTableModel> m_tableModel;
|
||||
|
||||
AZStd::unique_ptr<QAbstractItemModelTester> m_modelTesterAssetBrowser;
|
||||
AZStd::unique_ptr<QAbstractItemModelTester> m_modelTesterFilterModel;
|
||||
AZStd::unique_ptr<QAbstractItemModelTester> m_modelTesterTableModel;
|
||||
|
||||
QVector<int> m_folderIds = { 13, 14, 15 };
|
||||
QVector<int> m_sourceIDs = { 1, 2, 3, 4, 5 };
|
||||
QVector<int> m_productIDs = { 1, 2, 3, 4, 5 };
|
||||
@@ -96,9 +92,6 @@ namespace UnitTest
|
||||
m_filterModel->setSourceModel(m_assetBrowserComponent->GetAssetBrowserModel());
|
||||
m_tableModel->setSourceModel(m_filterModel.get());
|
||||
|
||||
m_modelTesterAssetBrowser = AZStd::make_unique<QAbstractItemModelTester>(m_assetBrowserComponent->GetAssetBrowserModel());
|
||||
m_modelTesterFilterModel = AZStd::make_unique<QAbstractItemModelTester>(m_filterModel.get());
|
||||
m_modelTesterTableModel = AZStd::make_unique<QAbstractItemModelTester>(m_tableModel.get());
|
||||
m_searchWidget = AZStd::make_unique<AzToolsFramework::AssetBrowser::SearchWidget>();
|
||||
|
||||
// Setup String filters
|
||||
@@ -110,10 +103,6 @@ namespace UnitTest
|
||||
|
||||
void AssetBrowserTest::TearDownEditorFixtureImpl()
|
||||
{
|
||||
m_modelTesterAssetBrowser.reset();
|
||||
m_modelTesterFilterModel.reset();
|
||||
m_modelTesterTableModel.reset();
|
||||
|
||||
m_tableModel.reset();
|
||||
m_filterModel.reset();
|
||||
m_assetBrowserComponent->Deactivate();
|
||||
|
||||
@@ -243,7 +243,6 @@ namespace UnitTest
|
||||
// These are required by implementing the EditorRequestBus
|
||||
void BrowseForAssets(AssetBrowser::AssetSelectionModel& /*selection*/) override {}
|
||||
int GetIconTextureIdFromEntityIconPath([[maybe_unused]] const AZStd::string& entityIconPath) override { return 0; }
|
||||
bool DisplayHelpersVisible() override { return false; }
|
||||
|
||||
public:
|
||||
EntityPropertyEditor* m_levelEditor;
|
||||
|
||||
Reference in New Issue
Block a user