Merge remote-tracking branch 'origin/gi' into large-worlds
# Conflicts: # Source/Engine/Core/Math/Vector3.h
This commit is contained in:
@@ -381,10 +381,10 @@ public:
|
||||
|
||||
// Insert
|
||||
ASSERT(pos.FreeSlotIndex != -1);
|
||||
auto bucket = &_allocation.Get()[pos.FreeSlotIndex];
|
||||
bucket->Occupy(key);
|
||||
Bucket& bucket = _allocation.Get()[pos.FreeSlotIndex];
|
||||
bucket.Occupy(key);
|
||||
_elementsCount++;
|
||||
return bucket->Value;
|
||||
return bucket.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -484,7 +484,7 @@ public:
|
||||
#endif
|
||||
void ClearDelete()
|
||||
{
|
||||
for (auto i = Begin(); i.IsNotEnd(); ++i)
|
||||
for (Iterator i = Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (i->Value)
|
||||
Delete(i->Value);
|
||||
@@ -547,22 +547,15 @@ public:
|
||||
/// Ensures that collection has given capacity.
|
||||
/// </summary>
|
||||
/// <param name="minCapacity">The minimum required capacity.</param>
|
||||
void EnsureCapacity(int32 minCapacity)
|
||||
/// <param name="preserveContents">True if preserve collection data when changing its size, otherwise collection after resize will be empty.</param>
|
||||
void EnsureCapacity(int32 minCapacity, bool preserveContents = true)
|
||||
{
|
||||
if (_size >= minCapacity)
|
||||
return;
|
||||
if (minCapacity < DICTIONARY_DEFAULT_CAPACITY)
|
||||
minCapacity = DICTIONARY_DEFAULT_CAPACITY;
|
||||
const int32 capacity = _allocation.CalculateCapacityGrow(_size, minCapacity);
|
||||
SetCapacity(capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup collection data (changes size to 0 without data preserving).
|
||||
/// </summary>
|
||||
FORCE_INLINE void Cleanup()
|
||||
{
|
||||
SetCapacity(0, false);
|
||||
SetCapacity(capacity, preserveContents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -642,7 +635,7 @@ public:
|
||||
void Add(const Iterator& i)
|
||||
{
|
||||
ASSERT(&i._collection != this && i);
|
||||
Bucket& bucket = *i;
|
||||
const Bucket& bucket = *i;
|
||||
Add(bucket.Key, bucket.Value);
|
||||
}
|
||||
|
||||
@@ -655,11 +648,9 @@ public:
|
||||
bool Remove(const KeyComparableType& key)
|
||||
{
|
||||
if (IsEmpty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
FindPositionResult pos;
|
||||
FindPosition(key, pos);
|
||||
|
||||
if (pos.ObjectIndex != -1)
|
||||
{
|
||||
_allocation.Get()[pos.ObjectIndex].Delete();
|
||||
@@ -697,7 +688,7 @@ public:
|
||||
int32 RemoveValue(const ValueType& value)
|
||||
{
|
||||
int32 result = 0;
|
||||
for (auto i = Begin(); i.IsNotEnd(); ++i)
|
||||
for (Iterator i = Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (i->Value == value)
|
||||
{
|
||||
@@ -718,16 +709,11 @@ public:
|
||||
template<typename KeyComparableType>
|
||||
Iterator Find(const KeyComparableType& key) const
|
||||
{
|
||||
if (HasItems())
|
||||
{
|
||||
const Bucket* data = _allocation.Get();
|
||||
for (int32 i = 0; i < _size; i++)
|
||||
{
|
||||
if (data[i].IsOccupied() && data[i].Key == key)
|
||||
return Iterator(*this, i);
|
||||
}
|
||||
}
|
||||
return End();
|
||||
if (IsEmpty())
|
||||
return End();
|
||||
FindPositionResult pos;
|
||||
FindPosition(key, pos);
|
||||
return pos.ObjectIndex != -1 ? Iterator(*this, pos.ObjectIndex) : End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -798,7 +784,7 @@ public:
|
||||
{
|
||||
Clear();
|
||||
SetCapacity(other.Capacity(), false);
|
||||
for (auto i = other.Begin(); i != other.End(); ++i)
|
||||
for (Iterator i = other.Begin(); i != other.End(); ++i)
|
||||
Add(i);
|
||||
ASSERT(Count() == other.Count());
|
||||
ASSERT(Capacity() == other.Capacity());
|
||||
@@ -811,7 +797,7 @@ public:
|
||||
template<typename ArrayAllocation>
|
||||
void GetKeys(Array<KeyType, ArrayAllocation>& result) const
|
||||
{
|
||||
for (auto i = Begin(); i.IsNotEnd(); ++i)
|
||||
for (Iterator i = Begin(); i.IsNotEnd(); ++i)
|
||||
result.Add(i->Key);
|
||||
}
|
||||
|
||||
@@ -822,7 +808,7 @@ public:
|
||||
template<typename ArrayAllocation>
|
||||
void GetValues(Array<ValueType, ArrayAllocation>& result) const
|
||||
{
|
||||
for (auto i = Begin(); i.IsNotEnd(); ++i)
|
||||
for (Iterator i = Begin(); i.IsNotEnd(); ++i)
|
||||
result.Add(i->Value);
|
||||
}
|
||||
|
||||
@@ -897,7 +883,7 @@ protected:
|
||||
while (checksCount < _size)
|
||||
{
|
||||
// Empty bucket
|
||||
auto& bucket = data[bucketIndex];
|
||||
const Bucket& bucket = data[bucketIndex];
|
||||
if (bucket.IsEmpty())
|
||||
{
|
||||
// Found place to insert
|
||||
|
||||
@@ -2,78 +2,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Core.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
#include "HashFunctions.h"
|
||||
#include "Config.h"
|
||||
#include "Engine/Core/Memory/Memory.h"
|
||||
#include "Engine/Core/Memory/Allocation.h"
|
||||
#include "Engine/Core/Collections/HashFunctions.h"
|
||||
#include "Engine/Core/Collections/Config.h"
|
||||
|
||||
/// <summary>
|
||||
/// Template for unordered set of values (without duplicates with O(1) lookup access).
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements in the set.</typeparam>
|
||||
template<typename T>
|
||||
/// <typeparam name="AllocationType">The type of memory allocator.</typeparam>
|
||||
template<typename T, typename AllocationType = HeapAllocation>
|
||||
API_CLASS(InBuild) class HashSet
|
||||
{
|
||||
friend HashSet;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Describes single portion of space for the item in a hash map
|
||||
/// Describes single portion of space for the item in a hash map.
|
||||
/// </summary>
|
||||
struct Bucket
|
||||
{
|
||||
friend HashSet;
|
||||
|
||||
public:
|
||||
|
||||
enum State : byte
|
||||
{
|
||||
Empty,
|
||||
Deleted,
|
||||
Occupied,
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/// <summary>The item.</summary>
|
||||
T Item;
|
||||
|
||||
private:
|
||||
|
||||
State _state;
|
||||
|
||||
public:
|
||||
|
||||
Bucket()
|
||||
: _state(Empty)
|
||||
{
|
||||
}
|
||||
|
||||
~Bucket()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void Free()
|
||||
{
|
||||
if (_state == Occupied)
|
||||
Memory::DestructItem(&Item);
|
||||
_state = Empty;
|
||||
}
|
||||
|
||||
void Delete()
|
||||
{
|
||||
_state = Deleted;
|
||||
Memory::DestructItem(&Item);
|
||||
}
|
||||
|
||||
void Occupy(const T& item)
|
||||
template<typename ItemType>
|
||||
void Occupy(const ItemType& item)
|
||||
{
|
||||
Item = item;
|
||||
Memory::ConstructItems(&Item, &item, 1);
|
||||
_state = Occupied;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
FORCE_INLINE bool IsEmpty() const
|
||||
{
|
||||
return _state == Empty;
|
||||
@@ -94,13 +78,15 @@ public:
|
||||
return _state != Occupied;
|
||||
}
|
||||
};
|
||||
|
||||
typedef typename AllocationType::template Data<Bucket> AllocationData;
|
||||
|
||||
private:
|
||||
|
||||
int32 _elementsCount = 0;
|
||||
int32 _deletedCount = 0;
|
||||
int32 _tableSize = 0;
|
||||
Bucket* _table = nullptr;
|
||||
int32 _size = 0;
|
||||
AllocationData _allocation;
|
||||
|
||||
public:
|
||||
|
||||
@@ -117,10 +103,27 @@ public:
|
||||
/// <param name="capacity">The initial capacity.</param>
|
||||
HashSet(int32 capacity)
|
||||
{
|
||||
ASSERT(capacity >= 0);
|
||||
SetCapacity(capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HashSet"/> class.
|
||||
/// </summary>
|
||||
/// <param name="other">The other collection to move.</param>
|
||||
HashSet(HashSet&& other) noexcept
|
||||
: _elementsCount(other._elementsCount)
|
||||
, _deletedCount(other._deletedCount)
|
||||
, _size(other._size)
|
||||
{
|
||||
_elementsCount = other._elementsCount;
|
||||
_deletedCount = other._deletedCount;
|
||||
_size = other._size;
|
||||
other._elementsCount = 0;
|
||||
other._deletedCount = 0;
|
||||
other._size = 0;
|
||||
_allocation.Swap(other._allocation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HashSet"/> class.
|
||||
/// </summary>
|
||||
@@ -137,18 +140,39 @@ public:
|
||||
/// <returns>The reference to this.</returns>
|
||||
HashSet& operator=(const HashSet& other)
|
||||
{
|
||||
// Ensure we're not trying to set to itself
|
||||
if (this != &other)
|
||||
Clone(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the data from the other collection.
|
||||
/// </summary>
|
||||
/// <param name="other">The other collection to move.</param>
|
||||
/// <returns>The reference to this.</returns>
|
||||
HashSet& operator=(HashSet&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
Clear();
|
||||
_allocation.Free();
|
||||
_elementsCount = other._elementsCount;
|
||||
_deletedCount = other._deletedCount;
|
||||
_size = other._size;
|
||||
other._elementsCount = 0;
|
||||
other._deletedCount = 0;
|
||||
other._size = 0;
|
||||
_allocation.Swap(other._allocation);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="HashSet"/> class.
|
||||
/// </summary>
|
||||
~HashSet()
|
||||
{
|
||||
Cleanup();
|
||||
SetCapacity(0, false);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -156,7 +180,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the amount of the elements in the collection.
|
||||
/// </summary>
|
||||
/// <returns>The amount of elements in the collection.</returns>
|
||||
FORCE_INLINE int32 Count() const
|
||||
{
|
||||
return _elementsCount;
|
||||
@@ -165,16 +188,14 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the amount of the elements that can be contained by the collection.
|
||||
/// </summary>
|
||||
/// <returns>The capacity of the collection.</returns>
|
||||
FORCE_INLINE int32 Capacity() const
|
||||
{
|
||||
return _tableSize;
|
||||
return _size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if collection is empty.
|
||||
/// </summary>
|
||||
/// <returns>True if is empty, otherwise false.</returns>
|
||||
FORCE_INLINE bool IsEmpty() const
|
||||
{
|
||||
return _elementsCount == 0;
|
||||
@@ -183,7 +204,6 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if collection has one or more elements.
|
||||
/// </summary>
|
||||
/// <returns>True if isn't empty, otherwise false.</returns>
|
||||
FORCE_INLINE bool HasItems() const
|
||||
{
|
||||
return _elementsCount != 0;
|
||||
@@ -197,9 +217,7 @@ public:
|
||||
struct Iterator
|
||||
{
|
||||
friend HashSet;
|
||||
|
||||
private:
|
||||
|
||||
HashSet& _collection;
|
||||
int32 _index;
|
||||
|
||||
@@ -223,41 +241,37 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
Iterator(Iterator&& i)
|
||||
: _collection(i._collection)
|
||||
, _index(i._index)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Checks if iterator is in the end of the collection
|
||||
/// </summary>
|
||||
/// <returns>True if is in the end, otherwise false</returns>
|
||||
FORCE_INLINE bool IsEnd() const
|
||||
{
|
||||
return _index == _collection.Capacity();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if iterator is not in the end of the collection
|
||||
/// </summary>
|
||||
/// <returns>True if is not in the end, otherwise false</returns>
|
||||
FORCE_INLINE bool IsNotEnd() const
|
||||
{
|
||||
return _index != _collection.Capacity();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
FORCE_INLINE Bucket& operator*() const
|
||||
{
|
||||
return _collection._table[_index];
|
||||
return _collection._allocation.Get()[_index];
|
||||
}
|
||||
|
||||
FORCE_INLINE Bucket* operator->() const
|
||||
{
|
||||
return &_collection._table[_index];
|
||||
return &_collection._allocation.Get()[_index];
|
||||
}
|
||||
|
||||
FORCE_INLINE explicit operator bool() const
|
||||
{
|
||||
return _index >= 0 && _index < _collection._tableSize;
|
||||
return _index >= 0 && _index < _collection._size;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool operator !() const
|
||||
@@ -275,17 +289,16 @@ public:
|
||||
return _index != v._index || &_collection != &v._collection;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
const int32 capacity = _collection.Capacity();
|
||||
if (_index != capacity)
|
||||
{
|
||||
const Bucket* data = _collection._allocation.Get();
|
||||
do
|
||||
{
|
||||
_index++;
|
||||
} while (_index != capacity && _collection._table[_index].IsNotOccupied());
|
||||
} while (_index != capacity && data[_index].IsNotOccupied());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -301,10 +314,11 @@ public:
|
||||
{
|
||||
if (_index > 0)
|
||||
{
|
||||
const Bucket* data = _collection._allocation.Get();
|
||||
do
|
||||
{
|
||||
_index--;
|
||||
} while (_index > 0 && _collection._table[_index].IsNotOccupied());
|
||||
} while (_index > 0 && data[_index].IsNotOccupied());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -324,22 +338,25 @@ public:
|
||||
/// </summary>
|
||||
void Clear()
|
||||
{
|
||||
if (_table)
|
||||
if (_elementsCount + _deletedCount != 0)
|
||||
{
|
||||
// Free all buckets
|
||||
// Note: this will not clear allocated objects space!
|
||||
for (int32 i = 0; i < _tableSize; i++)
|
||||
_table[i].Free();
|
||||
Bucket* data = _allocation.Get();
|
||||
for (int32 i = 0; i < _size; i++)
|
||||
data[i].Free();
|
||||
_elementsCount = _deletedCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the collection and delete value objects.
|
||||
/// Clears the collection and delete value objects.
|
||||
/// Note: collection must contain pointers to the objects that have public destructor and be allocated using New method.
|
||||
/// </summary>
|
||||
#if defined(_MSC_VER)
|
||||
template<typename = typename TEnableIf<TIsPointer<T>::Value>::Type>
|
||||
#endif
|
||||
void ClearDelete()
|
||||
{
|
||||
for (auto i = Begin(); i.IsNotEnd(); ++i)
|
||||
for (Iterator i = Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (i->Value)
|
||||
::Delete(i->Value);
|
||||
@@ -354,86 +371,63 @@ public:
|
||||
/// <param name="preserveContents">Enable/disable preserving collection contents during resizing</param>
|
||||
void SetCapacity(int32 capacity, bool preserveContents = true)
|
||||
{
|
||||
// Validate input
|
||||
ASSERT(capacity >= 0);
|
||||
|
||||
// Check if capacity won't change
|
||||
if (capacity == Capacity())
|
||||
return;
|
||||
|
||||
// Cache previous state
|
||||
auto oldTable = _table;
|
||||
auto oldTableSize = _tableSize;
|
||||
|
||||
// Clear elements counters
|
||||
const auto oldElementsCount = _elementsCount;
|
||||
ASSERT(capacity >= 0);
|
||||
AllocationData oldAllocation;
|
||||
oldAllocation.Swap(_allocation);
|
||||
const int32 oldSize = _size;
|
||||
const int32 oldElementsCount = _elementsCount;
|
||||
_deletedCount = _elementsCount = 0;
|
||||
|
||||
// Check if need to create a new table
|
||||
if (capacity > 0)
|
||||
if (capacity != 0 && (capacity & (capacity - 1)) != 0)
|
||||
{
|
||||
// Align capacity value
|
||||
if (Math::IsPowerOfTwo(capacity) == false)
|
||||
capacity = Math::RoundUpToPowerOf2(capacity);
|
||||
|
||||
// Allocate new table
|
||||
_table = NewArray<Bucket>(capacity);
|
||||
_tableSize = capacity;
|
||||
|
||||
// Check if preserve content
|
||||
if (oldElementsCount != 0 && preserveContents)
|
||||
// Align capacity value to the next power of two (if it's not)
|
||||
capacity++;
|
||||
capacity |= capacity >> 1;
|
||||
capacity |= capacity >> 2;
|
||||
capacity |= capacity >> 4;
|
||||
capacity |= capacity >> 8;
|
||||
capacity |= capacity >> 16;
|
||||
capacity = capacity + 1;
|
||||
}
|
||||
if (capacity)
|
||||
{
|
||||
_allocation.Allocate(capacity);
|
||||
Bucket* data = _allocation.Get();
|
||||
for (int32 i = 0; i < capacity; i++)
|
||||
data[i]._state = Bucket::Empty;
|
||||
}
|
||||
_size = capacity;
|
||||
Bucket* oldData = oldAllocation.Get();
|
||||
if (oldElementsCount != 0 && preserveContents)
|
||||
{
|
||||
// TODO; move keys and values on realloc
|
||||
for (int32 i = 0; i < oldSize; i++)
|
||||
{
|
||||
// Try to preserve all values in the collection
|
||||
for (int32 i = 0; i < oldTableSize; i++)
|
||||
{
|
||||
if (oldTable[i].IsOccupied())
|
||||
Add(oldTable[i].Item);
|
||||
}
|
||||
if (oldData[i].IsOccupied())
|
||||
Add(oldData[i].Item);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (oldElementsCount != 0)
|
||||
{
|
||||
// Clear data
|
||||
_table = nullptr;
|
||||
_tableSize = 0;
|
||||
}
|
||||
ASSERT(preserveContents == false || _elementsCount == oldElementsCount);
|
||||
|
||||
// Delete old table
|
||||
if (oldTable)
|
||||
{
|
||||
DeleteArray(oldTable, oldTableSize);
|
||||
for (int32 i = 0; i < oldSize; i++)
|
||||
oldData[i].Free();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increases collection capacity by given extra size (content will be preserved)
|
||||
/// Ensures that collection has given capacity.
|
||||
/// </summary>
|
||||
/// <param name="extraSize">Extra size to enlarge collection</param>
|
||||
FORCE_INLINE void IncreaseCapacity(int32 extraSize)
|
||||
{
|
||||
ASSERT(extraSize >= 0);
|
||||
SetCapacity(Capacity() + extraSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that collection has given capacity
|
||||
/// </summary>
|
||||
/// <param name="minCapacity">Minimum required capacity</param>
|
||||
void EnsureCapacity(int32 minCapacity)
|
||||
/// <param name="minCapacity">The minimum required capacity.</param>
|
||||
/// <param name="preserveContents">True if preserve collection data when changing its size, otherwise collection after resize will be empty.</param>
|
||||
void EnsureCapacity(int32 minCapacity, bool preserveContents = true)
|
||||
{
|
||||
if (Capacity() >= minCapacity)
|
||||
return;
|
||||
int32 num = Capacity() == 0 ? DICTIONARY_DEFAULT_CAPACITY : Capacity() * 2;
|
||||
SetCapacity(Math::Clamp<int32>(num, minCapacity, MAX_int32 - 1410));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup collection data (changes size to 0 without data preserving)
|
||||
/// </summary>
|
||||
FORCE_INLINE void Cleanup()
|
||||
{
|
||||
SetCapacity(0, false);
|
||||
if (minCapacity < DICTIONARY_DEFAULT_CAPACITY)
|
||||
minCapacity = DICTIONARY_DEFAULT_CAPACITY;
|
||||
const int32 capacity = _allocation.CalculateCapacityGrow(_size, minCapacity);
|
||||
SetCapacity(capacity, preserveContents);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -443,7 +437,8 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="item">The element to add to the set.</param>
|
||||
/// <returns>True if element has been added to the collection, otherwise false if the element is already present.</returns>
|
||||
bool Add(const T& item)
|
||||
template<typename ItemType>
|
||||
bool Add(const ItemType& item)
|
||||
{
|
||||
// Ensure to have enough memory for the next item (in case of new element insertion)
|
||||
EnsureCapacity(_elementsCount + _deletedCount + 1);
|
||||
@@ -453,12 +448,12 @@ public:
|
||||
FindPosition(item, pos);
|
||||
|
||||
// Check if object has been already added
|
||||
if (pos.ObjectIndex != INVALID_INDEX)
|
||||
if (pos.ObjectIndex != -1)
|
||||
return false;
|
||||
|
||||
// Insert
|
||||
ASSERT(pos.FreeSlotIndex != INVALID_INDEX);
|
||||
auto bucket = &_table[pos.FreeSlotIndex];
|
||||
ASSERT(pos.FreeSlotIndex != -1);
|
||||
Bucket* bucket = &_allocation.Get()[pos.FreeSlotIndex];
|
||||
bucket->Occupy(item);
|
||||
_elementsCount++;
|
||||
|
||||
@@ -472,7 +467,7 @@ public:
|
||||
void Add(const Iterator& i)
|
||||
{
|
||||
ASSERT(&i._collection != this && i);
|
||||
Bucket& bucket = *i;
|
||||
const Bucket& bucket = *i;
|
||||
Add(bucket.Item);
|
||||
}
|
||||
|
||||
@@ -481,22 +476,20 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="item">The element to remove.</param>
|
||||
/// <returns>True if cannot remove item from the collection because cannot find it, otherwise false.</returns>
|
||||
bool Remove(const T& item)
|
||||
template<typename ItemType>
|
||||
bool Remove(const ItemType& item)
|
||||
{
|
||||
if (IsEmpty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
FindPositionResult pos;
|
||||
FindPosition(item, pos);
|
||||
|
||||
if (pos.ObjectIndex != INVALID_INDEX)
|
||||
if (pos.ObjectIndex != -1)
|
||||
{
|
||||
_table[pos.ObjectIndex].Delete();
|
||||
_allocation.Get()[pos.ObjectIndex].Delete();
|
||||
_elementsCount--;
|
||||
_deletedCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -510,8 +503,8 @@ public:
|
||||
ASSERT(&i._collection == this);
|
||||
if (i)
|
||||
{
|
||||
ASSERT(_table[i._index].IsOccupied());
|
||||
_table[i._index].Delete();
|
||||
ASSERT(_allocation.Get()[i._index].IsOccupied());
|
||||
_allocation.Get()[i._index].Delete();
|
||||
_elementsCount--;
|
||||
_deletedCount++;
|
||||
return true;
|
||||
@@ -526,15 +519,14 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="item">Item to find</param>
|
||||
/// <returns>Iterator for the found element or End if cannot find it</returns>
|
||||
Iterator Find(const T& item) const
|
||||
template<typename ItemType>
|
||||
Iterator Find(const ItemType& item) const
|
||||
{
|
||||
if (IsEmpty())
|
||||
return End();
|
||||
|
||||
FindPositionResult pos;
|
||||
FindPosition(item, pos);
|
||||
|
||||
return pos.ObjectIndex != INVALID_INDEX ? Iterator(*this, pos.ObjectIndex) : End();
|
||||
return pos.ObjectIndex != -1 ? Iterator(*this, pos.ObjectIndex) : End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -542,15 +534,14 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="item">The item to locate.</param>
|
||||
/// <returns>True if value has been found in a collection, otherwise false</returns>
|
||||
bool Contains(const T& item) const
|
||||
template<typename ItemType>
|
||||
bool Contains(const ItemType& item) const
|
||||
{
|
||||
if (IsEmpty())
|
||||
return false;
|
||||
|
||||
FindPositionResult pos;
|
||||
FindPosition(item, pos);
|
||||
|
||||
return pos.ObjectIndex != INVALID_INDEX;
|
||||
return pos.ObjectIndex != -1;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -561,41 +552,26 @@ public:
|
||||
/// <param name="other">Other collection to clone</param>
|
||||
void Clone(const HashSet& other)
|
||||
{
|
||||
// Clear previous data
|
||||
Clear();
|
||||
|
||||
// Update capacity
|
||||
SetCapacity(other.Capacity(), false);
|
||||
|
||||
// Clone items
|
||||
for (auto i = other.Begin(); i != other.End(); ++i)
|
||||
for (Iterator i = other.Begin(); i != other.End(); ++i)
|
||||
Add(i);
|
||||
|
||||
// Check
|
||||
ASSERT(Count() == other.Count());
|
||||
ASSERT(Capacity() == other.Capacity());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets iterator for beginning of the collection.
|
||||
/// </summary>
|
||||
/// <returns>Iterator for beginning of the collection.</returns>
|
||||
Iterator Begin() const
|
||||
{
|
||||
Iterator i(*this, INVALID_INDEX);
|
||||
Iterator i(*this, -1);
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets iterator for ending of the collection.
|
||||
/// </summary>
|
||||
/// <returns>Iterator for ending of the collection.</returns>
|
||||
Iterator End() const
|
||||
{
|
||||
return Iterator(*this, _tableSize);
|
||||
return Iterator(*this, _size);
|
||||
}
|
||||
|
||||
Iterator begin()
|
||||
@@ -607,7 +583,7 @@ public:
|
||||
|
||||
FORCE_INLINE Iterator end()
|
||||
{
|
||||
return Iterator(*this, _tableSize);
|
||||
return Iterator(*this, _size);
|
||||
}
|
||||
|
||||
const Iterator begin() const
|
||||
@@ -619,11 +595,14 @@ public:
|
||||
|
||||
FORCE_INLINE const Iterator end() const
|
||||
{
|
||||
return Iterator(*this, _tableSize);
|
||||
return Iterator(*this, _size);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// <summary>
|
||||
/// The result container of the set item lookup searching.
|
||||
/// </summary>
|
||||
struct FindPositionResult
|
||||
{
|
||||
int32 ObjectIndex;
|
||||
@@ -632,42 +611,43 @@ protected:
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pair of positions: 1st where the object is, 2nd where
|
||||
/// it would go if you wanted to insert it. 1st is INVALID_INDEX
|
||||
/// if object is not found; 2nd is INVALID_INDEX if it is.
|
||||
/// it would go if you wanted to insert it. 1st is -1
|
||||
/// if object is not found; 2nd is -1 if it is.
|
||||
/// Note: because of deletions where-to-insert is not trivial: it's the
|
||||
/// first deleted bucket we see, as long as we don't find the item later
|
||||
/// </summary>
|
||||
/// <param name="item">The item to find</param>
|
||||
/// <param name="result">Pair of values: where the object is and where it would go if you wanted to insert it</param>
|
||||
void FindPosition(const T& item, FindPositionResult& result) const
|
||||
template<typename ItemType>
|
||||
void FindPosition(const ItemType& item, FindPositionResult& result) const
|
||||
{
|
||||
ASSERT(_table);
|
||||
|
||||
const int32 tableSizeMinusOne = _tableSize - 1;
|
||||
ASSERT(_size);
|
||||
const int32 tableSizeMinusOne = _size - 1;
|
||||
int32 bucketIndex = GetHash(item) & tableSizeMinusOne;
|
||||
int32 insertPos = INVALID_INDEX;
|
||||
int32 insertPos = -1;
|
||||
int32 numChecks = 0;
|
||||
result.FreeSlotIndex = INVALID_INDEX;
|
||||
|
||||
while (numChecks < _tableSize)
|
||||
const Bucket* data = _allocation.Get();
|
||||
result.FreeSlotIndex = -1;
|
||||
while (numChecks < _size)
|
||||
{
|
||||
// Empty bucket
|
||||
if (_table[bucketIndex].IsEmpty())
|
||||
const Bucket& bucket = data[bucketIndex];
|
||||
if (bucket.IsEmpty())
|
||||
{
|
||||
// Found place to insert
|
||||
result.ObjectIndex = INVALID_INDEX;
|
||||
result.FreeSlotIndex = insertPos == INVALID_INDEX ? bucketIndex : insertPos;
|
||||
result.ObjectIndex = -1;
|
||||
result.FreeSlotIndex = insertPos == -1 ? bucketIndex : insertPos;
|
||||
return;
|
||||
}
|
||||
// Deleted bucket
|
||||
if (_table[bucketIndex].IsDeleted())
|
||||
if (bucket.IsDeleted())
|
||||
{
|
||||
// Keep searching but mark to insert
|
||||
if (insertPos == INVALID_INDEX)
|
||||
if (insertPos == -1)
|
||||
insertPos = bucketIndex;
|
||||
}
|
||||
// Occupied bucket by target item
|
||||
else if (_table[bucketIndex].Item == item)
|
||||
else if (bucket.Item == item)
|
||||
{
|
||||
// Found item
|
||||
result.ObjectIndex = bucketIndex;
|
||||
@@ -675,10 +655,9 @@ protected:
|
||||
}
|
||||
|
||||
numChecks++;
|
||||
bucketIndex = (bucketIndex + DICTIONARY_PROB_FUNC(_tableSize, numChecks)) & tableSizeMinusOne;
|
||||
bucketIndex = (bucketIndex + DICTIONARY_PROB_FUNC(_size, numChecks)) & tableSizeMinusOne;
|
||||
}
|
||||
|
||||
result.ObjectIndex = INVALID_INDEX;
|
||||
result.ObjectIndex = -1;
|
||||
result.FreeSlotIndex = insertPos;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -334,7 +334,7 @@ namespace FlaxEditor.Content.Settings
|
||||
}
|
||||
|
||||
// Create new settings asset and link it to the game settings
|
||||
var path = StringUtils.CombinePaths(Globals.ProjectContentFolder, "Settings", CustomEditors.CustomEditorsUtil.GetPropertyNameUI(typeof(T).Name) + ".json");
|
||||
var path = StringUtils.CombinePaths(Globals.ProjectContentFolder, "Settings", Utilities.Utils.GetPropertyNameUI(typeof(T).Name) + ".json");
|
||||
if (Editor.SaveJsonAsset(path, obj))
|
||||
return true;
|
||||
asset = FlaxEngine.Content.LoadAsync<JsonAsset>(path);
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
/// </summary>
|
||||
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API GraphicsSettings : public SettingsBase
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(GraphicsSettings);
|
||||
API_AUTO_SERIALIZATION();
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(GraphicsSettings);
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Enables rendering synchronization with the refresh rate of the display device to avoid "tearing" artifacts.
|
||||
/// </summary>
|
||||
@@ -62,8 +62,21 @@ public:
|
||||
API_FIELD(Attributes="EditorOrder(1320), DefaultValue(false), EditorDisplay(\"Quality\", \"Allow CSM Blending\")")
|
||||
bool AllowCSMBlending = false;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// If checked, enables Global SDF rendering. This can be used in materials, shaders, and particles.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(2000), EditorDisplay(\"Global SDF\")")
|
||||
bool EnableGlobalSDF = false;
|
||||
|
||||
#if USE_EDITOR
|
||||
/// <summary>
|
||||
/// If checked, the 'Generate SDF' option will be checked on model import options by default. Use it if your project uses Global SDF (eg. for Global Illumination or particles).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(2010), EditorDisplay(\"Global SDF\")")
|
||||
bool GenerateSDFOnModelImport = false;
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use.
|
||||
/// </summary>
|
||||
@@ -71,15 +84,4 @@ public:
|
||||
|
||||
// [SettingsBase]
|
||||
void Apply() override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) final override
|
||||
{
|
||||
DESERIALIZE(UseVSync);
|
||||
DESERIALIZE(AAQuality);
|
||||
DESERIALIZE(SSRQuality);
|
||||
DESERIALIZE(SSAOQuality);
|
||||
DESERIALIZE(VolumetricFogQuality);
|
||||
DESERIALIZE(ShadowsQuality);
|
||||
DESERIALIZE(ShadowMapsQuality);
|
||||
DESERIALIZE(AllowCSMBlending);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,6 +13,26 @@ String BoundingBox::ToString() const
|
||||
return String::Format(TEXT("{}"), *this);
|
||||
}
|
||||
|
||||
void BoundingBox::GetCorners(Vector3 corners[8]) const
|
||||
{
|
||||
corners[0] = Vector3(Minimum.X, Maximum.Y, Maximum.Z);
|
||||
corners[1] = Vector3(Maximum.X, Maximum.Y, Maximum.Z);
|
||||
corners[2] = Vector3(Maximum.X, Minimum.Y, Maximum.Z);
|
||||
corners[3] = Vector3(Minimum.X, Minimum.Y, Maximum.Z);
|
||||
corners[4] = Vector3(Minimum.X, Maximum.Y, Minimum.Z);
|
||||
corners[5] = Vector3(Maximum.X, Maximum.Y, Minimum.Z);
|
||||
corners[6] = Vector3(Maximum.X, Minimum.Y, Minimum.Z);
|
||||
corners[7] = Vector3(Minimum.X, Minimum.Y, Minimum.Z);
|
||||
}
|
||||
|
||||
BoundingBox BoundingBox::MakeOffsetted(const Vector3& offset) const
|
||||
{
|
||||
BoundingBox result;
|
||||
result.Minimum = Minimum + offset;
|
||||
result.Maximum = Maximum + offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
void BoundingBox::FromPoints(const Vector3* points, int32 pointsCount, BoundingBox& result)
|
||||
{
|
||||
ASSERT(points && pointsCount > 0);
|
||||
|
||||
@@ -76,17 +76,7 @@ public:
|
||||
/// Gets the eight corners of the bounding box.
|
||||
/// </summary>
|
||||
/// <param name="corners">An array of points representing the eight corners of the bounding box.</param>
|
||||
void GetCorners(Vector3 corners[8]) const
|
||||
{
|
||||
corners[0] = Vector3(Minimum.X, Maximum.Y, Maximum.Z);
|
||||
corners[1] = Vector3(Maximum.X, Maximum.Y, Maximum.Z);
|
||||
corners[2] = Vector3(Maximum.X, Minimum.Y, Maximum.Z);
|
||||
corners[3] = Vector3(Minimum.X, Minimum.Y, Maximum.Z);
|
||||
corners[4] = Vector3(Minimum.X, Maximum.Y, Minimum.Z);
|
||||
corners[5] = Vector3(Maximum.X, Maximum.Y, Minimum.Z);
|
||||
corners[6] = Vector3(Maximum.X, Minimum.Y, Minimum.Z);
|
||||
corners[7] = Vector3(Minimum.X, Minimum.Y, Minimum.Z);
|
||||
}
|
||||
void GetCorners(Vector3 corners[8]) const;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates volume of the box.
|
||||
@@ -200,13 +190,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset.</param>
|
||||
/// <returns>The result.</returns>
|
||||
BoundingBox MakeOffsetted(const Vector3& offset) const
|
||||
{
|
||||
BoundingBox result;
|
||||
result.Minimum = Minimum + offset;
|
||||
result.Maximum = Maximum + offset;
|
||||
return result;
|
||||
}
|
||||
BoundingBox MakeOffsetted(const Vector3& offset) const;
|
||||
|
||||
public:
|
||||
|
||||
@@ -421,6 +405,26 @@ public:
|
||||
{
|
||||
return CollisionsHelper::BoxContainsSphere(*this, sphere);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the distance between a Bounding Box and a point.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test.</param>
|
||||
/// <returns>The distance between bounding box and a point.</returns>
|
||||
FORCE_INLINE float Distance(const Vector3& point) const
|
||||
{
|
||||
return CollisionsHelper::DistanceBoxPoint(*this, point);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the distance between two Bounding Boxed.
|
||||
/// </summary>
|
||||
/// <param name="box">The bounding box to test.</param>
|
||||
/// <returns>The distance between bounding boxes.</returns>
|
||||
FORCE_INLINE float Distance(const BoundingBox& box) const
|
||||
{
|
||||
return CollisionsHelper::DistanceBoxBox(*this, box);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -1124,7 +1124,6 @@ bool CollisionsHelper::BoxIntersectsSphere(const BoundingBox& box, const Boundin
|
||||
Vector3 vector;
|
||||
Vector3::Clamp(sphere.Center, box.Minimum, box.Maximum, vector);
|
||||
const float distance = Vector3::DistanceSquared(sphere.Center, vector);
|
||||
|
||||
return distance <= sphere.Radius * sphere.Radius;
|
||||
}
|
||||
|
||||
@@ -1438,6 +1437,16 @@ bool CollisionsHelper::LineIntersectsRect(const Vector2& p1, const Vector2& p2,
|
||||
return (topoverlap < botoverlap) && (!((botoverlap < t) || (topoverlap > b)));*/
|
||||
}
|
||||
|
||||
Vector2 CollisionsHelper::LineHitsBox(const Vector3& lineStart, const Vector3& lineEnd, const Vector3& boxMin, const Vector3& boxMax)
|
||||
{
|
||||
const Vector3 invDirection = 1.0f / (lineEnd - lineStart);
|
||||
const Vector3 enterIntersection = (boxMin - lineStart) * invDirection;
|
||||
const Vector3 exitIntersection = (boxMax - lineStart) * invDirection;
|
||||
const Vector3 minIntersections = Vector3::Min(enterIntersection, exitIntersection);
|
||||
const Vector3 maxIntersections = Vector3::Max(enterIntersection, exitIntersection);
|
||||
return Vector2(Math::Saturate(minIntersections.MaxValue()), Math::Saturate(maxIntersections.MinValue()));
|
||||
}
|
||||
|
||||
bool CollisionsHelper::IsPointInTriangle(const Vector2& point, const Vector2& a, const Vector2& b, const Vector2& c)
|
||||
{
|
||||
const Vector2 an = a - point;
|
||||
|
||||
@@ -569,6 +569,12 @@ public:
|
||||
/// <returns>True if line intersects with the rectangle</returns>
|
||||
static bool LineIntersectsRect(const Vector2& p1, const Vector2& p2, const Rectangle& rect);
|
||||
|
||||
// Hits axis-aligned box (boxMin, boxMax) with a line (lineStart, lineEnd).
|
||||
// Returns the intersections on the line (x - closest, y - furthest).
|
||||
// Line hits the box if: intersections.x < intersections.y.
|
||||
// Hit point is: hitPoint = lineStart + (lineEnd - lineStart) * intersections.x/y.
|
||||
static Vector2 LineHitsBox(const Vector3& lineStart, const Vector3& lineEnd, const Vector3& boxMin, const Vector3& boxMax);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the given 2D point is inside the specified triangle.
|
||||
/// </summary>
|
||||
|
||||
@@ -12,9 +12,9 @@ static_assert(sizeof(Half2) == 4, "Invalid Half2 type size.");
|
||||
static_assert(sizeof(Half3) == 6, "Invalid Half3 type size.");
|
||||
static_assert(sizeof(Half4) == 8, "Invalid Half4 type size.");
|
||||
|
||||
Half2 Half2::Zero(0, 0);
|
||||
Half3 Half3::Zero(0, 0, 0);
|
||||
Half4 Half4::Zero(0, 0, 0, 0);
|
||||
Half2 Half2::Zero(0.0f, 0.0f);
|
||||
Half3 Half3::Zero(0.0f, 0.0f, 0.0f);
|
||||
Half4 Half4::Zero(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
Half2::Half2(const Vector2& v)
|
||||
{
|
||||
|
||||
@@ -45,7 +45,6 @@ class FLAXENGINE_API Float16Compressor
|
||||
static const int32 minD = minC - subC - 1;
|
||||
|
||||
public:
|
||||
|
||||
static Half Compress(const float value)
|
||||
{
|
||||
#if USE_SSE_HALF_CONVERSION
|
||||
@@ -102,14 +101,12 @@ public:
|
||||
struct FLAXENGINE_API Half2
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Zero vector
|
||||
/// </summary>
|
||||
static Half2 Zero;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the X component of the vector.
|
||||
/// </summary>
|
||||
@@ -121,7 +118,6 @@ public:
|
||||
Half Y;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
@@ -129,6 +125,17 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="x">X component</param>
|
||||
/// <param name="y">Y component</param>
|
||||
Half2(Half x, Half y)
|
||||
: X(x)
|
||||
, Y(y)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init
|
||||
/// </summary>
|
||||
@@ -147,7 +154,6 @@ public:
|
||||
Half2(const Vector2& v);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Convert to Vector2
|
||||
/// </summary>
|
||||
@@ -161,14 +167,12 @@ public:
|
||||
struct FLAXENGINE_API Half3
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Zero vector
|
||||
/// </summary>
|
||||
static Half3 Zero;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the X component of the vector.
|
||||
/// </summary>
|
||||
@@ -185,11 +189,17 @@ public:
|
||||
Half Z;
|
||||
|
||||
public:
|
||||
|
||||
Half3()
|
||||
{
|
||||
}
|
||||
|
||||
Half3(Half x, Half y, Half z)
|
||||
: X(x)
|
||||
, Y(y)
|
||||
, Z(z)
|
||||
{
|
||||
}
|
||||
|
||||
Half3(const float x, const float y, const float z)
|
||||
{
|
||||
X = Float16Compressor::Compress(x);
|
||||
@@ -200,7 +210,6 @@ public:
|
||||
Half3(const Vector3& v);
|
||||
|
||||
public:
|
||||
|
||||
Vector3 ToVector3() const;
|
||||
};
|
||||
|
||||
@@ -210,14 +219,12 @@ public:
|
||||
struct FLAXENGINE_API Half4
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Zero vector
|
||||
/// </summary>
|
||||
static Half4 Zero;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the X component of the vector.
|
||||
/// </summary>
|
||||
@@ -239,11 +246,18 @@ public:
|
||||
Half W;
|
||||
|
||||
public:
|
||||
|
||||
Half4()
|
||||
{
|
||||
}
|
||||
|
||||
Half4(Half x, Half y, Half z, Half w)
|
||||
: X(x)
|
||||
, Y(y)
|
||||
, Z(z)
|
||||
, W(w)
|
||||
{
|
||||
}
|
||||
|
||||
Half4(const float x, const float y, const float z)
|
||||
{
|
||||
X = Float16Compressor::Compress(x);
|
||||
@@ -265,7 +279,6 @@ public:
|
||||
explicit Half4(const Rectangle& rect);
|
||||
|
||||
public:
|
||||
|
||||
Vector2 ToVector2() const;
|
||||
Vector3 ToVector3() const;
|
||||
Vector4 ToVector4() const;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Matrix.h"
|
||||
#include "Matrix3x3.h"
|
||||
#include "Vector2.h"
|
||||
#include "Quaternion.h"
|
||||
#include "Transform.h"
|
||||
@@ -15,6 +16,17 @@ const Matrix Matrix::Identity(
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
Matrix::Matrix(const Matrix3x3& matrix)
|
||||
{
|
||||
Platform::MemoryCopy(&M11, &matrix.M11, sizeof(Vector3));
|
||||
Platform::MemoryCopy(&M21, &matrix.M21, sizeof(Vector3));
|
||||
Platform::MemoryCopy(&M31, &matrix.M31, sizeof(Vector3));
|
||||
M14 = 0.0f;
|
||||
M24 = 0.0f;
|
||||
M34 = 0.0f;
|
||||
M44 = 1.0f;
|
||||
}
|
||||
|
||||
String Matrix::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("{}"), *this);
|
||||
@@ -284,8 +296,6 @@ void Matrix::LookAt(const Vector3& eye, const Vector3& target, const Vector3& up
|
||||
xaxis.Normalize();
|
||||
Vector3::Cross(zaxis, xaxis, yaxis);
|
||||
|
||||
result = Identity;
|
||||
|
||||
result.M11 = xaxis.X;
|
||||
result.M21 = xaxis.Y;
|
||||
result.M31 = xaxis.Z;
|
||||
@@ -298,9 +308,14 @@ void Matrix::LookAt(const Vector3& eye, const Vector3& target, const Vector3& up
|
||||
result.M23 = zaxis.Y;
|
||||
result.M33 = zaxis.Z;
|
||||
|
||||
result.M14 = 0.0f;
|
||||
result.M24 = 0.0f;
|
||||
result.M34 = 0.0f;
|
||||
|
||||
result.M41 = -Vector3::Dot(xaxis, eye);
|
||||
result.M42 = -Vector3::Dot(yaxis, eye);
|
||||
result.M43 = -Vector3::Dot(zaxis, eye);
|
||||
result.M44 = 1.0f;
|
||||
}
|
||||
|
||||
void Matrix::OrthoOffCenter(float left, float right, float bottom, float top, float zNear, float zFar, Matrix& result)
|
||||
@@ -587,33 +602,7 @@ void Matrix::Transformation2D(Vector2& scalingCenter, float scalingRotation, con
|
||||
Matrix Matrix::CreateWorld(const Vector3& position, const Vector3& forward, const Vector3& up)
|
||||
{
|
||||
Matrix result;
|
||||
Vector3 vector3, vector31, vector32;
|
||||
|
||||
Vector3::Normalize(forward, vector3);
|
||||
vector3.Negate();
|
||||
Vector3::Normalize(Vector3::Cross(up, vector3), vector31);
|
||||
Vector3::Cross(vector3, vector31, vector32);
|
||||
|
||||
result.M11 = vector31.X;
|
||||
result.M12 = vector31.Y;
|
||||
result.M13 = vector31.Z;
|
||||
result.M14 = 0.0f;
|
||||
|
||||
result.M21 = vector32.X;
|
||||
result.M22 = vector32.Y;
|
||||
result.M23 = vector32.Z;
|
||||
result.M24 = 0.0f;
|
||||
|
||||
result.M31 = vector3.X;
|
||||
result.M32 = vector3.Y;
|
||||
result.M33 = vector3.Z;
|
||||
result.M34 = 0.0f;
|
||||
|
||||
result.M41 = position.X;
|
||||
result.M42 = position.Y;
|
||||
result.M43 = position.Z;
|
||||
result.M44 = 1.0f;
|
||||
|
||||
CreateWorld(position, forward, up, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -649,41 +638,9 @@ void Matrix::CreateWorld(const Vector3& position, const Vector3& forward, const
|
||||
|
||||
Matrix Matrix::CreateFromAxisAngle(const Vector3& axis, float angle)
|
||||
{
|
||||
Matrix matrix;
|
||||
|
||||
const float x = axis.X;
|
||||
const float y = axis.Y;
|
||||
const float z = axis.Z;
|
||||
const float single = Math::Sin(angle);
|
||||
const float single1 = Math::Cos(angle);
|
||||
const float single2 = x * x;
|
||||
const float single3 = y * y;
|
||||
const float single4 = z * z;
|
||||
const float single5 = x * y;
|
||||
const float single6 = x * z;
|
||||
const float single7 = y * z;
|
||||
|
||||
matrix.M11 = single2 + single1 * (1.0f - single2);
|
||||
matrix.M12 = single5 - single1 * single5 + single * z;
|
||||
matrix.M13 = single6 - single1 * single6 - single * y;
|
||||
matrix.M14 = 0.0f;
|
||||
|
||||
matrix.M21 = single5 - single1 * single5 - single * z;
|
||||
matrix.M22 = single3 + single1 * (1.0f - single3);
|
||||
matrix.M23 = single7 - single1 * single7 + single * x;
|
||||
matrix.M24 = 0.0f;
|
||||
|
||||
matrix.M31 = single6 - single1 * single6 + single * y;
|
||||
matrix.M32 = single7 - single1 * single7 - single * x;
|
||||
matrix.M33 = single4 + single1 * (1.0f - single4);
|
||||
matrix.M34 = 0.0f;
|
||||
|
||||
matrix.M41 = 0.0f;
|
||||
matrix.M42 = 0.0f;
|
||||
matrix.M43 = 0.0f;
|
||||
matrix.M44 = 1.0f;
|
||||
|
||||
return matrix;
|
||||
Matrix result;
|
||||
CreateFromAxisAngle(axis, angle, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Matrix::CreateFromAxisAngle(const Vector3& axis, float angle, Matrix& result)
|
||||
|
||||
@@ -150,6 +150,8 @@ public:
|
||||
Platform::MemoryCopy(Raw, values, sizeof(float) * 16);
|
||||
}
|
||||
|
||||
explicit Matrix(const Matrix3x3& matrix);
|
||||
|
||||
public:
|
||||
|
||||
String ToString() const;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Matrix3x3.h"
|
||||
#include "../Types/String.h"
|
||||
#include "Matrix.h"
|
||||
#include "Quaternion.h"
|
||||
#include "../Types/String.h"
|
||||
|
||||
const Matrix3x3 Matrix3x3::Zero(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
const Matrix3x3 Matrix3x3::Identity(
|
||||
@@ -10,11 +11,37 @@ const Matrix3x3 Matrix3x3::Identity(
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f);
|
||||
|
||||
Matrix3x3::Matrix3x3(const Matrix& matrix)
|
||||
{
|
||||
Platform::MemoryCopy(&M11, &matrix.M11, sizeof(Vector3));
|
||||
Platform::MemoryCopy(&M21, &matrix.M21, sizeof(Vector3));
|
||||
Platform::MemoryCopy(&M31, &matrix.M31, sizeof(Vector3));
|
||||
}
|
||||
|
||||
String Matrix3x3::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("{}"), *this);
|
||||
}
|
||||
|
||||
void Matrix3x3::NormalizeScale()
|
||||
{
|
||||
const float scaleX = 1.0f / Vector3(M11, M21, M31).Length();
|
||||
const float scaleY = 1.0f / Vector3(M12, M22, M32).Length();
|
||||
const float scaleZ = 1.0f / Vector3(M13, M23, M33).Length();
|
||||
|
||||
M11 *= scaleX;
|
||||
M21 *= scaleX;
|
||||
M31 *= scaleX;
|
||||
|
||||
M12 *= scaleY;
|
||||
M22 *= scaleY;
|
||||
M32 *= scaleY;
|
||||
|
||||
M13 *= scaleZ;
|
||||
M23 *= scaleZ;
|
||||
M33 *= scaleZ;
|
||||
}
|
||||
|
||||
void Matrix3x3::Invert(const Matrix3x3& value, Matrix3x3& result)
|
||||
{
|
||||
const float d11 = value.M22 * value.M33 + value.M23 * -value.M32;
|
||||
|
||||
@@ -113,6 +113,12 @@ public:
|
||||
Platform::MemoryCopy(Raw, values, sizeof(float) * 9);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Matrix3x3"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="matrix">The 4 by 4 matrix to initialize from with rotation and scale (translation is skipped).</param>
|
||||
explicit Matrix3x3(const Matrix& matrix);
|
||||
|
||||
public:
|
||||
|
||||
String ToString() const;
|
||||
@@ -255,6 +261,11 @@ public:
|
||||
Transpose(*this, *this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes any scaling from the matrix by performing the normalization (each row magnitude is 1).
|
||||
/// </summary>
|
||||
void NormalizeScale();
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,11 +8,18 @@
|
||||
|
||||
OrientedBoundingBox::OrientedBoundingBox(const BoundingBox& bb)
|
||||
{
|
||||
const Vector3 center = bb.Minimum + (bb.Maximum - bb.Minimum) / 2.0f;
|
||||
const Vector3 center = bb.Minimum + (bb.Maximum - bb.Minimum) * 0.5f;
|
||||
Extents = bb.Maximum - center;
|
||||
Matrix::Translation(center, Transformation);
|
||||
}
|
||||
|
||||
OrientedBoundingBox::OrientedBoundingBox(const Vector3& extents, const Matrix3x3& rotationScale, const Vector3& translation)
|
||||
: Extents(extents)
|
||||
, Transformation(rotationScale)
|
||||
{
|
||||
Transformation.SetTranslation(translation);
|
||||
}
|
||||
|
||||
OrientedBoundingBox::OrientedBoundingBox(Vector3 points[], int32 pointCount)
|
||||
{
|
||||
ASSERT(points && pointCount > 0);
|
||||
@@ -104,6 +111,12 @@ void OrientedBoundingBox::GetBoundingBox(BoundingBox& result) const
|
||||
BoundingBox::FromPoints(corners, 8, result);
|
||||
}
|
||||
|
||||
void OrientedBoundingBox::Transform(const Matrix& matrix)
|
||||
{
|
||||
const Matrix tmp = Transformation;
|
||||
Matrix::Multiply(tmp, matrix, Transformation);
|
||||
}
|
||||
|
||||
ContainmentType OrientedBoundingBox::Contains(const Vector3& point, float* distance) const
|
||||
{
|
||||
// Transform the point into the obb coordinates
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
Transformation = transformation;
|
||||
}
|
||||
|
||||
OrientedBoundingBox(const Vector3& extents, const Matrix3x3& rotationScale, const Vector3& translation);
|
||||
|
||||
// Init
|
||||
// @param minimum The minimum vertex of the bounding box.
|
||||
// @param maximum The maximum vertex of the bounding box.
|
||||
@@ -99,10 +101,7 @@ public:
|
||||
|
||||
// Transforms this box using a transformation matrix.
|
||||
// @param mat The transformation matrix.
|
||||
void Transform(const Matrix& mat)
|
||||
{
|
||||
Transformation *= mat;
|
||||
}
|
||||
void Transform(const Matrix& matrix);
|
||||
|
||||
// Scales the OBB by scaling its Extents without affecting the Transformation matrix.
|
||||
// By keeping Transformation matrix scaling-free, the collision detection methods will be more accurate.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Vector3.h"
|
||||
#include "Vector4.h"
|
||||
#include "Matrix.h"
|
||||
#include "Matrix3x3.h"
|
||||
#include "Math.h"
|
||||
#include "../Types/String.h"
|
||||
|
||||
@@ -208,6 +209,59 @@ void Quaternion::RotationMatrix(const Matrix& matrix, Quaternion& result)
|
||||
result.Normalize();
|
||||
}
|
||||
|
||||
void Quaternion::RotationMatrix(const Matrix3x3& matrix, Quaternion& result)
|
||||
{
|
||||
float sqrtV;
|
||||
float half;
|
||||
const float scale = matrix.M11 + matrix.M22 + matrix.M33;
|
||||
|
||||
if (scale > 0.0f)
|
||||
{
|
||||
sqrtV = Math::Sqrt(scale + 1.0f);
|
||||
result.W = sqrtV * 0.5f;
|
||||
sqrtV = 0.5f / sqrtV;
|
||||
|
||||
result.X = (matrix.M23 - matrix.M32) * sqrtV;
|
||||
result.Y = (matrix.M31 - matrix.M13) * sqrtV;
|
||||
result.Z = (matrix.M12 - matrix.M21) * sqrtV;
|
||||
}
|
||||
else if (matrix.M11 >= matrix.M22 && matrix.M11 >= matrix.M33)
|
||||
{
|
||||
sqrtV = Math::Sqrt(1.0f + matrix.M11 - matrix.M22 - matrix.M33);
|
||||
half = 0.5f / sqrtV;
|
||||
|
||||
result = Quaternion(
|
||||
0.5f * sqrtV,
|
||||
(matrix.M12 + matrix.M21) * half,
|
||||
(matrix.M13 + matrix.M31) * half,
|
||||
(matrix.M23 - matrix.M32) * half);
|
||||
}
|
||||
else if (matrix.M22 > matrix.M33)
|
||||
{
|
||||
sqrtV = Math::Sqrt(1.0f + matrix.M22 - matrix.M11 - matrix.M33);
|
||||
half = 0.5f / sqrtV;
|
||||
|
||||
result = Quaternion(
|
||||
(matrix.M21 + matrix.M12) * half,
|
||||
0.5f * sqrtV,
|
||||
(matrix.M32 + matrix.M23) * half,
|
||||
(matrix.M31 - matrix.M13) * half);
|
||||
}
|
||||
else
|
||||
{
|
||||
sqrtV = Math::Sqrt(1.0f + matrix.M33 - matrix.M11 - matrix.M22);
|
||||
half = 0.5f / sqrtV;
|
||||
|
||||
result = Quaternion(
|
||||
(matrix.M31 + matrix.M13) * half,
|
||||
(matrix.M32 + matrix.M23) * half,
|
||||
0.5f * sqrtV,
|
||||
(matrix.M12 - matrix.M21) * half);
|
||||
}
|
||||
|
||||
result.Normalize();
|
||||
}
|
||||
|
||||
void Quaternion::LookAt(const Vector3& eye, const Vector3& target, const Vector3& up, Quaternion& result)
|
||||
{
|
||||
Matrix matrix;
|
||||
|
||||
@@ -10,6 +10,7 @@ struct Vector2;
|
||||
struct Vector3;
|
||||
struct Vector4;
|
||||
struct Matrix;
|
||||
struct Matrix3x3;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a four dimensional mathematical quaternion. Euler angles are stored in: pitch, yaw, roll order (x, y, z).
|
||||
@@ -566,6 +567,11 @@ public:
|
||||
// @param result When the method completes, contains the newly created quaternion
|
||||
static void RotationMatrix(const Matrix& matrix, Quaternion& result);
|
||||
|
||||
// Creates a quaternion given a rotation matrix
|
||||
// @param matrix The rotation matrix
|
||||
// @param result When the method completes, contains the newly created quaternion
|
||||
static void RotationMatrix(const Matrix3x3& matrix, Quaternion& result);
|
||||
|
||||
// Creates a left-handed, look-at quaternion
|
||||
// @param eye The position of the viewer's eye
|
||||
// @param target The camera look-at target
|
||||
|
||||
@@ -49,6 +49,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Vector3 GetNormal() const
|
||||
{
|
||||
return Vector3::Normalize((V1 - V0) ^ (V2 - V0));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Determines if there is an intersection between the current object and a Ray
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Color.h"
|
||||
#include "Quaternion.h"
|
||||
#include "Matrix.h"
|
||||
#include "Matrix3x3.h"
|
||||
#include "Int2.h"
|
||||
#include "Int3.h"
|
||||
#include "Int4.h"
|
||||
@@ -215,9 +216,15 @@ void Vector3::Transform(const Vector3& vector, const Matrix& transform, Vector3&
|
||||
void Vector3::Transform(const Vector3* vectors, const Matrix& transform, Vector3* results, int32 vectorsCount)
|
||||
{
|
||||
for (int32 i = 0; i < vectorsCount; i++)
|
||||
{
|
||||
Transform(vectors[i], transform, results[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Vector3::Transform(const Vector3& vector, const Matrix3x3& transform, Vector3& result)
|
||||
{
|
||||
result = Vector3(
|
||||
vector.X * transform.M11 + vector.Y * transform.M21 + vector.Z * transform.M31,
|
||||
vector.X * transform.M12 + vector.Y * transform.M22 + vector.Z * transform.M32,
|
||||
vector.X * transform.M13 + vector.Y * transform.M23 + vector.Z * transform.M33);
|
||||
}
|
||||
|
||||
Vector3 Vector3::Transform(const Vector3& vector, const Matrix& transform)
|
||||
|
||||
@@ -11,6 +11,7 @@ struct Double3;
|
||||
struct Double4;
|
||||
struct Quaternion;
|
||||
struct Matrix;
|
||||
struct Matrix3x3;
|
||||
struct Vector2;
|
||||
struct Vector4;
|
||||
struct Color;
|
||||
@@ -215,7 +216,7 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns average arithmetic of all the components
|
||||
/// Returns the average arithmetic of all the components.
|
||||
/// </summary>
|
||||
float AverageArithmetic() const
|
||||
{
|
||||
@@ -223,7 +224,7 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets sum of all vector components values.
|
||||
/// Gets the sum of all vector components values.
|
||||
/// </summary>
|
||||
float SumValues() const
|
||||
{
|
||||
@@ -231,7 +232,7 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns minimum value of all the components.
|
||||
/// Returns the minimum value of all the components.
|
||||
/// </summary>
|
||||
float MinValue() const
|
||||
{
|
||||
@@ -239,7 +240,7 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns maximum value of all the components.
|
||||
/// Returns the maximum value of all the components.
|
||||
/// </summary>
|
||||
float MaxValue() const
|
||||
{
|
||||
@@ -255,9 +256,8 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if vector has one or more components equal to +/- infinity
|
||||
/// Returns true if vector has one or more components equal to +/- infinity.
|
||||
/// </summary>
|
||||
/// <returns>True if one or more components equal to +/- infinity</returns>
|
||||
bool IsInfinity() const
|
||||
{
|
||||
return isinf(X) || isinf(Y) || isinf(Z);
|
||||
@@ -714,6 +714,12 @@ public:
|
||||
// @param vectorsCount Amount of vectors to transform
|
||||
static void Transform(const Vector3* vectors, const Matrix& transform, Vector3* results, int32 vectorsCount);
|
||||
|
||||
// Transforms a 3D vector by the given matrix
|
||||
// @param vector The source vector
|
||||
// @param transform The transformation matrix
|
||||
// @param result When the method completes, contains the transformed Vector3
|
||||
static void Transform(const Vector3& vector, const Matrix3x3& transform, Vector3& result);
|
||||
|
||||
// Transforms a 3D vector by the given matrix
|
||||
// @param vector The source vector
|
||||
// @param transform The transformation matrix
|
||||
|
||||
Reference in New Issue
Block a user