Merge branch 'FlaxEngine:master' into material_import
This commit is contained in:
@@ -1251,7 +1251,7 @@ void VisualScriptExecutor::ProcessGroupFlow(Box* boxBase, Node* node, Value& val
|
||||
boxBase = node->GetBox(3);
|
||||
if (boxBase->HasConnection())
|
||||
eatBox(node, boxBase->FirstConnection());
|
||||
Dictionary<Variant, Variant>::Iterator it(dictionary, iteratorValue.Value.AsInt);
|
||||
Dictionary<Variant, Variant>::Iterator it(&dictionary, iteratorValue.Value.AsInt);
|
||||
++it;
|
||||
iteratorValue.Value.AsInt = it.Index();
|
||||
}
|
||||
@@ -1269,12 +1269,12 @@ void VisualScriptExecutor::ProcessGroupFlow(Box* boxBase, Node* node, Value& val
|
||||
// Key
|
||||
case 1:
|
||||
if (iteratorIndex != scope->ReturnedValues.Count() && dictionaryIndex != scope->ReturnedValues.Count())
|
||||
value = Dictionary<Variant, Variant>::Iterator(*scope->ReturnedValues[dictionaryIndex].Value.AsDictionary, scope->ReturnedValues[iteratorIndex].Value.AsInt)->Key;
|
||||
value = Dictionary<Variant, Variant>::Iterator(scope->ReturnedValues[dictionaryIndex].Value.AsDictionary, scope->ReturnedValues[iteratorIndex].Value.AsInt)->Key;
|
||||
break;
|
||||
// Value
|
||||
case 2:
|
||||
if (iteratorIndex != scope->ReturnedValues.Count() && dictionaryIndex != scope->ReturnedValues.Count())
|
||||
value = Dictionary<Variant, Variant>::Iterator(*scope->ReturnedValues[dictionaryIndex].Value.AsDictionary, scope->ReturnedValues[iteratorIndex].Value.AsInt)->Value;
|
||||
value = Dictionary<Variant, Variant>::Iterator(scope->ReturnedValues[dictionaryIndex].Value.AsDictionary, scope->ReturnedValues[iteratorIndex].Value.AsInt)->Value;
|
||||
break;
|
||||
// Break
|
||||
case 5:
|
||||
|
||||
@@ -938,12 +938,12 @@ public:
|
||||
|
||||
FORCE_INLINE bool IsEnd() const
|
||||
{
|
||||
return _index == _array->Count();
|
||||
return _index == _array->_count;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool IsNotEnd() const
|
||||
{
|
||||
return _index != _array->Count();
|
||||
return _index != _array->_count;
|
||||
}
|
||||
|
||||
FORCE_INLINE T& operator*() const
|
||||
@@ -975,7 +975,7 @@ public:
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
if (_index != _array->Count())
|
||||
if (_index != _array->_count)
|
||||
_index++;
|
||||
return *this;
|
||||
}
|
||||
@@ -983,7 +983,7 @@ public:
|
||||
Iterator operator++(int)
|
||||
{
|
||||
Iterator temp = *this;
|
||||
if (_index != _array->Count())
|
||||
if (_index != _array->_count)
|
||||
_index++;
|
||||
return temp;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,6 @@ public:
|
||||
struct Iterator
|
||||
{
|
||||
friend ChunkedArray;
|
||||
|
||||
private:
|
||||
ChunkedArray* _collection;
|
||||
int32 _chunkIndex;
|
||||
|
||||
@@ -237,22 +237,28 @@ public:
|
||||
{
|
||||
friend Dictionary;
|
||||
private:
|
||||
Dictionary& _collection;
|
||||
Dictionary* _collection;
|
||||
int32 _index;
|
||||
|
||||
public:
|
||||
Iterator(Dictionary& collection, const int32 index)
|
||||
Iterator(Dictionary* collection, const int32 index)
|
||||
: _collection(collection)
|
||||
, _index(index)
|
||||
{
|
||||
}
|
||||
|
||||
Iterator(Dictionary const& collection, const int32 index)
|
||||
: _collection((Dictionary&)collection)
|
||||
Iterator(Dictionary const* collection, const int32 index)
|
||||
: _collection(const_cast<Dictionary*>(collection))
|
||||
, _index(index)
|
||||
{
|
||||
}
|
||||
|
||||
Iterator()
|
||||
: _collection(nullptr)
|
||||
, _index(-1)
|
||||
{
|
||||
}
|
||||
|
||||
Iterator(const Iterator& i)
|
||||
: _collection(i._collection)
|
||||
, _index(i._index)
|
||||
@@ -273,27 +279,27 @@ public:
|
||||
|
||||
FORCE_INLINE bool IsEnd() const
|
||||
{
|
||||
return _index == _collection._size;
|
||||
return _index == _collection->_size;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool IsNotEnd() const
|
||||
{
|
||||
return _index != _collection._size;
|
||||
return _index != _collection->_size;
|
||||
}
|
||||
|
||||
FORCE_INLINE Bucket& operator*() const
|
||||
{
|
||||
return _collection._allocation.Get()[_index];
|
||||
return _collection->_allocation.Get()[_index];
|
||||
}
|
||||
|
||||
FORCE_INLINE Bucket* operator->() const
|
||||
{
|
||||
return &_collection._allocation.Get()[_index];
|
||||
return &_collection->_allocation.Get()[_index];
|
||||
}
|
||||
|
||||
FORCE_INLINE explicit operator bool() const
|
||||
{
|
||||
return _index >= 0 && _index < _collection._size;
|
||||
return _index >= 0 && _index < _collection->_size;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool operator!() const
|
||||
@@ -308,7 +314,7 @@ public:
|
||||
|
||||
FORCE_INLINE bool operator!=(const Iterator& v) const
|
||||
{
|
||||
return _index != v._index || &_collection != &v._collection;
|
||||
return _index != v._index || _collection != v._collection;
|
||||
}
|
||||
|
||||
Iterator& operator=(const Iterator& v)
|
||||
@@ -320,10 +326,10 @@ public:
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
const int32 capacity = _collection.Capacity();
|
||||
const int32 capacity = _collection->_size;
|
||||
if (_index != capacity)
|
||||
{
|
||||
const Bucket* data = _collection._allocation.Get();
|
||||
const Bucket* data = _collection->_allocation.Get();
|
||||
do
|
||||
{
|
||||
_index++;
|
||||
@@ -343,7 +349,7 @@ public:
|
||||
{
|
||||
if (_index > 0)
|
||||
{
|
||||
const Bucket* data = _collection._allocation.Get();
|
||||
const Bucket* data = _collection->_allocation.Get();
|
||||
do
|
||||
{
|
||||
_index--;
|
||||
@@ -633,7 +639,7 @@ public:
|
||||
/// <param name="i">Iterator with key and value.</param>
|
||||
void Add(const Iterator& i)
|
||||
{
|
||||
ASSERT(&i._collection != this && i);
|
||||
ASSERT(i._collection != this && i);
|
||||
const Bucket& bucket = *i;
|
||||
Add(bucket.Key, bucket.Value);
|
||||
}
|
||||
@@ -667,7 +673,7 @@ public:
|
||||
/// <returns>True if cannot remove item from the collection because cannot find it, otherwise false.</returns>
|
||||
bool Remove(const Iterator& i)
|
||||
{
|
||||
ASSERT(&i._collection == this);
|
||||
ASSERT(i._collection == this);
|
||||
if (i)
|
||||
{
|
||||
ASSERT(_allocation.Get()[i._index].IsOccupied());
|
||||
@@ -711,7 +717,7 @@ public:
|
||||
return End();
|
||||
FindPositionResult pos;
|
||||
FindPosition(key, pos);
|
||||
return pos.ObjectIndex != -1 ? Iterator(*this, pos.ObjectIndex) : End();
|
||||
return pos.ObjectIndex != -1 ? Iterator(this, pos.ObjectIndex) : End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -812,38 +818,38 @@ public:
|
||||
public:
|
||||
Iterator Begin() const
|
||||
{
|
||||
Iterator i(*this, -1);
|
||||
Iterator i(this, -1);
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
Iterator End() const
|
||||
{
|
||||
return Iterator(*this, _size);
|
||||
return Iterator(this, _size);
|
||||
}
|
||||
|
||||
Iterator begin()
|
||||
{
|
||||
Iterator i(*this, -1);
|
||||
Iterator i(this, -1);
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
FORCE_INLINE Iterator end()
|
||||
{
|
||||
return Iterator(*this, _size);
|
||||
return Iterator(this, _size);
|
||||
}
|
||||
|
||||
const Iterator begin() const
|
||||
{
|
||||
Iterator i(*this, -1);
|
||||
Iterator i(this, -1);
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
FORCE_INLINE const Iterator end() const
|
||||
{
|
||||
return Iterator(*this, _size);
|
||||
return Iterator(this, _size);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -213,17 +213,17 @@ public:
|
||||
{
|
||||
friend HashSet;
|
||||
private:
|
||||
HashSet& _collection;
|
||||
HashSet* _collection;
|
||||
int32 _index;
|
||||
|
||||
Iterator(HashSet& collection, const int32 index)
|
||||
Iterator(HashSet* collection, const int32 index)
|
||||
: _collection(collection)
|
||||
, _index(index)
|
||||
{
|
||||
}
|
||||
|
||||
Iterator(HashSet const& collection, const int32 index)
|
||||
: _collection((HashSet&)collection)
|
||||
Iterator(HashSet const* collection, const int32 index)
|
||||
: _collection(const_cast<HashSet*>(collection))
|
||||
, _index(index)
|
||||
{
|
||||
}
|
||||
@@ -244,27 +244,27 @@ public:
|
||||
public:
|
||||
FORCE_INLINE bool IsEnd() const
|
||||
{
|
||||
return _index == _collection.Capacity();
|
||||
return _index == _collection->_size;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool IsNotEnd() const
|
||||
{
|
||||
return _index != _collection.Capacity();
|
||||
return _index != _collection->_size;
|
||||
}
|
||||
|
||||
FORCE_INLINE Bucket& operator*() const
|
||||
{
|
||||
return _collection._allocation.Get()[_index];
|
||||
return _collection->_allocation.Get()[_index];
|
||||
}
|
||||
|
||||
FORCE_INLINE Bucket* operator->() const
|
||||
{
|
||||
return &_collection._allocation.Get()[_index];
|
||||
return &_collection->_allocation.Get()[_index];
|
||||
}
|
||||
|
||||
FORCE_INLINE explicit operator bool() const
|
||||
{
|
||||
return _index >= 0 && _index < _collection._size;
|
||||
return _index >= 0 && _index < _collection->_size;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool operator !() const
|
||||
@@ -274,12 +274,12 @@ public:
|
||||
|
||||
FORCE_INLINE bool operator==(const Iterator& v) const
|
||||
{
|
||||
return _index == v._index && &_collection == &v._collection;
|
||||
return _index == v._index && _collection == v._collection;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool operator!=(const Iterator& v) const
|
||||
{
|
||||
return _index != v._index || &_collection != &v._collection;
|
||||
return _index != v._index || _collection != v._collection;
|
||||
}
|
||||
|
||||
Iterator& operator=(const Iterator& v)
|
||||
@@ -291,10 +291,10 @@ public:
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
const int32 capacity = _collection.Capacity();
|
||||
const int32 capacity = _collection->_size;
|
||||
if (_index != capacity)
|
||||
{
|
||||
const Bucket* data = _collection._allocation.Get();
|
||||
const Bucket* data = _collection->_allocation.Get();
|
||||
do
|
||||
{
|
||||
_index++;
|
||||
@@ -314,7 +314,7 @@ public:
|
||||
{
|
||||
if (_index > 0)
|
||||
{
|
||||
const Bucket* data = _collection._allocation.Get();
|
||||
const Bucket* data = _collection->_allocation.Get();
|
||||
do
|
||||
{
|
||||
_index--;
|
||||
@@ -464,7 +464,7 @@ public:
|
||||
/// <param name="i">Iterator with item to add</param>
|
||||
void Add(const Iterator& i)
|
||||
{
|
||||
ASSERT(&i._collection != this && i);
|
||||
ASSERT(i._collection != this && i);
|
||||
const Bucket& bucket = *i;
|
||||
Add(bucket.Item);
|
||||
}
|
||||
@@ -498,7 +498,7 @@ public:
|
||||
/// <returns>True if cannot remove item from the collection because cannot find it, otherwise false.</returns>
|
||||
bool Remove(const Iterator& i)
|
||||
{
|
||||
ASSERT(&i._collection == this);
|
||||
ASSERT(i._collection == this);
|
||||
if (i)
|
||||
{
|
||||
ASSERT(_allocation.Get()[i._index].IsOccupied());
|
||||
@@ -523,7 +523,7 @@ public:
|
||||
return End();
|
||||
FindPositionResult pos;
|
||||
FindPosition(item, pos);
|
||||
return pos.ObjectIndex != -1 ? Iterator(*this, pos.ObjectIndex) : End();
|
||||
return pos.ObjectIndex != -1 ? Iterator(this, pos.ObjectIndex) : End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -559,38 +559,38 @@ public:
|
||||
public:
|
||||
Iterator Begin() const
|
||||
{
|
||||
Iterator i(*this, -1);
|
||||
Iterator i(this, -1);
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
Iterator End() const
|
||||
{
|
||||
return Iterator(*this, _size);
|
||||
return Iterator(this, _size);
|
||||
}
|
||||
|
||||
Iterator begin()
|
||||
{
|
||||
Iterator i(*this, -1);
|
||||
Iterator i(this, -1);
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
FORCE_INLINE Iterator end()
|
||||
{
|
||||
return Iterator(*this, _size);
|
||||
return Iterator(this, _size);
|
||||
}
|
||||
|
||||
const Iterator begin() const
|
||||
{
|
||||
Iterator i(*this, -1);
|
||||
Iterator i(this, -1);
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
FORCE_INLINE const Iterator end() const
|
||||
{
|
||||
return Iterator(*this, _size);
|
||||
return Iterator(this, _size);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -920,6 +920,11 @@ void DebugDraw::DrawActors(Actor** selectedActors, int32 selectedActorsCount, bo
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDraw::DrawRay(const Vector3& origin, const Vector3& direction, const Color& color, float duration, bool depthTest)
|
||||
{
|
||||
DrawLine(origin, origin + direction, color, duration, depthTest);
|
||||
}
|
||||
|
||||
void DebugDraw::DrawLine(const Vector3& start, const Vector3& end, const Color& color, float duration, bool depthTest)
|
||||
{
|
||||
const Float3 startF = start - Context->Origin, endF = end - Context->Origin;
|
||||
|
||||
@@ -31,6 +31,18 @@ namespace FlaxEngine
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the line in a direction.
|
||||
/// </summary>
|
||||
/// <param name="origin">The origin of the line.</param>
|
||||
/// <param name="direction">The direction of the line.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
public static void DrawRay(Vector3 origin, Vector3 direction, Color color, float duration = 0.0f, bool depthTest = true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the line.
|
||||
/// </summary>
|
||||
|
||||
@@ -69,6 +69,16 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// <param name="drawScenes">True if draw all debug shapes from scenes too or false if draw just from specified actor list.</param>
|
||||
API_FUNCTION() static void DrawActors(Actor** selectedActors, int32 selectedActorsCount, bool drawScenes);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the line in a direction.
|
||||
/// </summary>
|
||||
/// <param name="origin">The origin of the line.</param>
|
||||
/// <param name="direction">The direction of the line.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
API_FUNCTION() static void DrawRay(const Vector3& origin, const Vector3& direction, const Color& color, float duration = 0.0f, bool depthTest = true);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the line.
|
||||
/// </summary>
|
||||
@@ -604,6 +614,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
API_FUNCTION() static void DrawText(const StringView& text, const Transform& transform, const Color& color, int32 size = 32, float duration = 0.0f);
|
||||
};
|
||||
|
||||
#define DEBUG_DRAW_RAY(origin, direction, color, duration, depthTest) DebugDraw::DrawRay(origin, direction, color, duration, depthTest)
|
||||
#define DEBUG_DRAW_LINE(start, end, color, duration, depthTest) DebugDraw::DrawLine(start, end, color, duration, depthTest)
|
||||
#define DEBUG_DRAW_LINES(lines, transform, color, duration, depthTest) DebugDraw::DrawLines(lines, transform, color, duration, depthTest)
|
||||
#define DEBUG_DRAW_BEZIER(p1, p2, p3, p4, color, duration, depthTest) DebugDraw::DrawBezier(p1, p2, p3, p4, color, duration, depthTest)
|
||||
|
||||
@@ -371,7 +371,6 @@ namespace FlaxEngine.Interop
|
||||
{
|
||||
if (handle == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
ManagedHandlePool.FreeHandle(handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
@@ -183,6 +183,9 @@ namespace FlaxEngine.Interop
|
||||
public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.Free(unmanaged);
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
[CustomMarshaller(typeof(Array), MarshalMode.ManagedToUnmanagedIn, typeof(SystemArrayMarshaller.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(Array), MarshalMode.UnmanagedToManagedOut, typeof(SystemArrayMarshaller.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(Array), MarshalMode.ManagedToUnmanagedOut, typeof(SystemArrayMarshaller.NativeToManaged))]
|
||||
@@ -251,6 +254,74 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
[CustomMarshaller(typeof(object[]), MarshalMode.ManagedToUnmanagedIn, typeof(SystemObjectArrayMarshaller.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(object[]), MarshalMode.UnmanagedToManagedOut, typeof(SystemObjectArrayMarshaller.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(object[]), MarshalMode.ManagedToUnmanagedOut, typeof(SystemObjectArrayMarshaller.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(object[]), MarshalMode.UnmanagedToManagedIn, typeof(SystemObjectArrayMarshaller.NativeToManaged))]
|
||||
public static unsafe class SystemObjectArrayMarshaller
|
||||
{
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public struct ManagedToNative
|
||||
{
|
||||
ManagedHandle handle;
|
||||
|
||||
public void FromManaged(object[] managed)
|
||||
{
|
||||
if (managed != null)
|
||||
{
|
||||
var managedArray = NativeInterop.ManagedArrayToGCHandleWrappedArray(managed);
|
||||
handle = ManagedHandle.Alloc(managedArray, GCHandleType.Weak);
|
||||
}
|
||||
}
|
||||
|
||||
public IntPtr ToUnmanaged()
|
||||
{
|
||||
return ManagedHandle.ToIntPtr(handle);
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public struct NativeToManaged
|
||||
{
|
||||
ManagedHandle handle;
|
||||
|
||||
public void FromUnmanaged(IntPtr unmanaged)
|
||||
{
|
||||
if (unmanaged == IntPtr.Zero)
|
||||
return;
|
||||
handle = ManagedHandle.FromIntPtr(unmanaged);
|
||||
}
|
||||
|
||||
public object[] ToManaged()
|
||||
{
|
||||
object[] result = null;
|
||||
if (handle.IsAllocated)
|
||||
{
|
||||
var managedArray = Unsafe.As<ManagedArray>(handle.Target);
|
||||
result = NativeInterop.GCHandleArrayToManagedArray<object>(managedArray);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
|
||||
@@ -581,9 +581,9 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static IntPtr NewStringLength(sbyte* text, int length)
|
||||
internal static IntPtr NewStringUTF8(sbyte* text, int length)
|
||||
{
|
||||
return ManagedString.ToNativeWeak(new string(text, 0, length));
|
||||
return ManagedString.ToNativeWeak(new string(text, 0, length, System.Text.Encoding.UTF8));
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
|
||||
@@ -456,6 +456,19 @@ void Actor::SetLayerName(const StringView& value)
|
||||
LOG(Warning, "Unknown layer name '{0}'", value);
|
||||
}
|
||||
|
||||
void Actor::SetLayerNameRecursive(const StringView& value)
|
||||
{
|
||||
for (int32 i = 0; i < 32; i++)
|
||||
{
|
||||
if (Level::Layers[i] == value)
|
||||
{
|
||||
SetLayerRecursive(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG(Warning, "Unknown layer name '{0}'", value);
|
||||
}
|
||||
|
||||
bool Actor::HasTag() const
|
||||
{
|
||||
return Tags.Count() != 0;
|
||||
@@ -476,6 +489,18 @@ void Actor::AddTag(const Tag& tag)
|
||||
Tags.AddUnique(tag);
|
||||
}
|
||||
|
||||
void Actor::AddTagRecursive(const Tag& tag)
|
||||
{
|
||||
for (const auto& child : Children)
|
||||
child->AddTagRecursive(tag);
|
||||
Tags.AddUnique(tag);
|
||||
}
|
||||
|
||||
void Actor::RemoveTag(const Tag& tag)
|
||||
{
|
||||
Tags.Remove(tag);
|
||||
}
|
||||
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
const String& Actor::GetTag() const
|
||||
@@ -500,6 +525,17 @@ void Actor::SetLayer(int32 layerIndex)
|
||||
OnLayerChanged();
|
||||
}
|
||||
|
||||
void Actor::SetLayerRecursive(int32 layerIndex)
|
||||
{
|
||||
layerIndex = Math::Clamp(layerIndex, 0, 31);
|
||||
for (const auto& child : Children)
|
||||
child->SetLayerRecursive(layerIndex);
|
||||
if (layerIndex == _layer)
|
||||
return;
|
||||
_layer = layerIndex;
|
||||
OnLayerChanged();
|
||||
}
|
||||
|
||||
void Actor::SetName(const StringView& value)
|
||||
{
|
||||
if (_name == value)
|
||||
|
||||
@@ -102,6 +102,12 @@ public:
|
||||
/// <param name="layerIndex">The index of the layer.</param>
|
||||
API_PROPERTY() void SetLayer(int32 layerIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the layer recursively for all underlying children.
|
||||
/// </summary>
|
||||
/// <param name="layerIndex">The index of the layer.</param>
|
||||
API_FUNCTION() void SetLayerRecursive(int32 layerIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the layer.
|
||||
/// </summary>
|
||||
@@ -113,6 +119,11 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetLayerName(const StringView& value);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the name of the layer recursively for actor and for all underlying child actors.
|
||||
/// </summary>
|
||||
API_FUNCTION() void SetLayerNameRecursive(const StringView& value);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this actor has any tag assigned.
|
||||
/// </summary>
|
||||
@@ -136,6 +147,18 @@ public:
|
||||
/// <param name="tag">The tag to add.</param>
|
||||
API_FUNCTION() void AddTag(const Tag& tag);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a tag to the actor and for all underlying child actors.
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag to add.</param>
|
||||
API_FUNCTION() void AddTagRecursive(const Tag& tag);
|
||||
|
||||
/// <summary>
|
||||
/// Removes a tag to the actor
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag to remove.</param>
|
||||
API_FUNCTION() void RemoveTag(const Tag& tag);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the tag.
|
||||
/// [Deprecated in v1.5]
|
||||
|
||||
@@ -484,8 +484,7 @@ namespace
|
||||
|
||||
void Spline::OnDebugDraw()
|
||||
{
|
||||
const Color color = GetSplineColor();
|
||||
DrawSpline(this, color.AlphaMultiplied(0.7f), _transform, true);
|
||||
DrawSpline(this, GetSplineColor().AlphaMultiplied(0.7f), _transform, true);
|
||||
|
||||
// Base
|
||||
Actor::OnDebugDraw();
|
||||
@@ -493,8 +492,7 @@ void Spline::OnDebugDraw()
|
||||
|
||||
void Spline::OnDebugDrawSelected()
|
||||
{
|
||||
const Color color = GetSplineColor();
|
||||
DrawSpline(this, color.AlphaMultiplied(0.3f), _transform, false);
|
||||
DrawSpline(this, Color::White, _transform, false);
|
||||
|
||||
// Base
|
||||
Actor::OnDebugDrawSelected();
|
||||
|
||||
@@ -354,6 +354,7 @@ public:
|
||||
|
||||
protected:
|
||||
#if USE_EDITOR
|
||||
// Spline color getter for debug drawing, can be overriden by custom spline types.
|
||||
virtual Color GetSplineColor()
|
||||
{
|
||||
return Color::White;
|
||||
|
||||
@@ -1255,20 +1255,19 @@ void Prefab::SyncNestedPrefabs(const NestedPrefabsList& allPrefabs, Array<Prefab
|
||||
auto nestedPrefab = allPrefabs[i].Get();
|
||||
if (nestedPrefab)
|
||||
{
|
||||
if (WaitForLoaded())
|
||||
if (nestedPrefab->WaitForLoaded())
|
||||
{
|
||||
LOG(Warning, "Waiting for prefab asset load failed.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sync only if prefab is used by this prefab (directly) and it has been captured before
|
||||
const int32 nestedPrefabIndex = nestedPrefab->NestedPrefabs.Find(GetID());
|
||||
if (nestedPrefabIndex != -1)
|
||||
{
|
||||
if (nestedPrefab->SyncChangesInternal(allPrefabsInstancesData[nestedPrefabIndex]))
|
||||
if (nestedPrefab->SyncChangesInternal(allPrefabsInstancesData[i]))
|
||||
continue;
|
||||
|
||||
nestedPrefab->SyncNestedPrefabs(allPrefabs, allPrefabsInstancesData);
|
||||
|
||||
ObjectsRemovalService::Flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,6 +331,12 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* node
|
||||
value = GET_PARTICLE_ATTRIBUTE(0, float);
|
||||
break;
|
||||
}
|
||||
// Particle Scale
|
||||
case 112:
|
||||
{
|
||||
value = GET_PARTICLE_ATTRIBUTE(0, Float3);
|
||||
break;
|
||||
}
|
||||
// Effect Position
|
||||
case 200:
|
||||
{
|
||||
|
||||
@@ -331,6 +331,10 @@ void ParticleEmitterGPUGenerator::ProcessGroupParticles(Box* box, Node* node, Va
|
||||
case 111:
|
||||
value = AccessParticleAttribute(node, TEXT("Radius"), ParticleAttribute::ValueTypes::Float, AccessMode::Read);
|
||||
break;
|
||||
// Particle Scale
|
||||
case 112:
|
||||
value = AccessParticleAttribute(node, TEXT("Scale"), ParticleAttribute::ValueTypes::Float3, AccessMode::Read);
|
||||
break;
|
||||
// Effect Position
|
||||
case 200:
|
||||
value = Value(VariantType::Float3, TEXT("EffectPosition"));
|
||||
|
||||
@@ -269,13 +269,20 @@ public:
|
||||
USE_ATTRIBUTE(Lifetime, Float, 1);
|
||||
break;
|
||||
}
|
||||
// Particle Mass
|
||||
// Particle Radius
|
||||
case GRAPH_NODE_MAKE_TYPE(14, 111):
|
||||
{
|
||||
node->UsesParticleData = true;
|
||||
USE_ATTRIBUTE(Radius, Float, 0);
|
||||
break;
|
||||
}
|
||||
// Particle Scale
|
||||
case GRAPH_NODE_MAKE_TYPE(14, 112):
|
||||
{
|
||||
node->UsesParticleData = true;
|
||||
USE_ATTRIBUTE(Scale, Float3, 0);
|
||||
break;
|
||||
}
|
||||
// Random
|
||||
case GRAPH_NODE_MAKE_TYPE(14, 208):
|
||||
case GRAPH_NODE_MAKE_TYPE(14, 209):
|
||||
|
||||
@@ -223,9 +223,10 @@ void WheeledVehicle::Setup()
|
||||
return;
|
||||
|
||||
// Release previous
|
||||
void* scene = GetPhysicsScene()->GetPhysicsScene();
|
||||
if (_vehicle)
|
||||
{
|
||||
PhysicsBackend::RemoveVehicle(GetPhysicsScene()->GetPhysicsScene(), this);
|
||||
PhysicsBackend::RemoveVehicle(scene, this);
|
||||
PhysicsBackend::DestroyVehicle(_vehicle, (int32)_driveTypeCurrent);
|
||||
_vehicle = nullptr;
|
||||
}
|
||||
@@ -236,7 +237,7 @@ void WheeledVehicle::Setup()
|
||||
if (!_vehicle)
|
||||
return;
|
||||
_driveTypeCurrent = _driveType;
|
||||
PhysicsBackend::AddVehicle(GetPhysicsScene()->GetPhysicsScene(), this);
|
||||
PhysicsBackend::AddVehicle(scene, this);
|
||||
PhysicsBackend::SetRigidDynamicActorSolverIterationCounts(_actor, 12, 4);
|
||||
#else
|
||||
LOG(Fatal, "Vehicles are not supported.");
|
||||
@@ -358,8 +359,23 @@ void WheeledVehicle::OnColliderChanged(Collider* c)
|
||||
{
|
||||
RigidBody::OnColliderChanged(c);
|
||||
|
||||
// Rebuild vehicle when someone adds/removed wheels
|
||||
Setup();
|
||||
if (_useWheelsUpdates)
|
||||
{
|
||||
// Rebuild vehicle when someone adds/removed wheels
|
||||
Setup();
|
||||
}
|
||||
}
|
||||
|
||||
void WheeledVehicle::OnActiveInTreeChanged()
|
||||
{
|
||||
// Skip rebuilds from per-wheel OnColliderChanged when whole vehicle is toggled
|
||||
_useWheelsUpdates = false;
|
||||
RigidBody::OnActiveInTreeChanged();
|
||||
_useWheelsUpdates = true;
|
||||
|
||||
// Perform whole rebuild when it gets activated
|
||||
if (IsActiveInHierarchy())
|
||||
Setup();
|
||||
}
|
||||
|
||||
void WheeledVehicle::OnPhysicsSceneChanged(PhysicsScene* previous)
|
||||
|
||||
@@ -329,6 +329,7 @@ private:
|
||||
DifferentialSettings _differential;
|
||||
GearboxSettings _gearbox;
|
||||
bool _fixInvalidForwardDir = false; // [Deprecated on 13.06.2023, expires on 13.06.2025]
|
||||
bool _useWheelsUpdates = true;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -484,6 +485,7 @@ public:
|
||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||
void OnColliderChanged(Collider* c) override;
|
||||
void OnActiveInTreeChanged() override;
|
||||
|
||||
protected:
|
||||
void OnPhysicsSceneChanged(PhysicsScene* previous) override;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
|
||||
#define CC_MIN_SIZE 0.001f
|
||||
|
||||
CharacterController::CharacterController(const SpawnParams& params)
|
||||
: Collider(params)
|
||||
, _controller(nullptr)
|
||||
@@ -100,10 +102,9 @@ void CharacterController::SetStepOffset(float value)
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float contactOffset = Math::Max(_contactOffset, ZeroTolerance);
|
||||
const float minSize = 0.001f;
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling - contactOffset, minSize);
|
||||
PhysicsBackend::SetControllerStepOffset(_controller, Math::Min(value, height + radius * 2.0f - minSize));
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling - contactOffset, CC_MIN_SIZE);
|
||||
PhysicsBackend::SetControllerStepOffset(_controller, Math::Min(value, height + radius * 2.0f - CC_MIN_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,9 +176,8 @@ CharacterController::CollisionFlags CharacterController::Move(const Vector3& dis
|
||||
void CharacterController::DrawPhysicsDebug(RenderView& view)
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float minSize = 0.001f;
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, CC_MIN_SIZE);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
const Vector3 position = _transform.LocalToWorld(_center);
|
||||
if (view.Mode == ViewMode::PhysicsColliders)
|
||||
DEBUG_DRAW_TUBE(position, Quaternion::Euler(90, 0, 0), radius, height, Color::LightYellow, 0, true);
|
||||
@@ -188,9 +188,8 @@ void CharacterController::DrawPhysicsDebug(RenderView& view)
|
||||
void CharacterController::OnDebugDrawSelected()
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float minSize = 0.001f;
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, CC_MIN_SIZE);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
const Vector3 position = _transform.LocalToWorld(_center);
|
||||
DEBUG_DRAW_WIRE_TUBE(position, Quaternion::Euler(90, 0, 0), radius, height, Color::GreenYellow, 0, false);
|
||||
|
||||
@@ -231,9 +230,8 @@ void CharacterController::UpdateSize() const
|
||||
if (_controller)
|
||||
{
|
||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||
const float minSize = 0.001f;
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling - Math::Max(_contactOffset, ZeroTolerance), minSize);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling - Math::Max(_contactOffset, ZeroTolerance), CC_MIN_SIZE);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
PhysicsBackend::SetControllerSize(_controller, radius, height);
|
||||
}
|
||||
}
|
||||
@@ -245,11 +243,12 @@ void CharacterController::CreateShape()
|
||||
|
||||
void CharacterController::UpdateBounds()
|
||||
{
|
||||
void* actor = _shape ? PhysicsBackend::GetShapeActor(_shape) : nullptr;
|
||||
if (actor)
|
||||
PhysicsBackend::GetActorBounds(actor, _box);
|
||||
else
|
||||
_box = BoundingBox(_transform.Translation);
|
||||
const float scaling = GetScale().GetAbsolute().MaxValue();
|
||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, CC_MIN_SIZE);
|
||||
const float height = Math::Max(Math::Abs(_height) * scaling, CC_MIN_SIZE);
|
||||
const Vector3 position = _transform.LocalToWorld(_center);
|
||||
const Vector3 extent(radius, height * 0.5f + radius, radius);
|
||||
_box = BoundingBox(position - extent, position + extent);
|
||||
BoundingSphere::FromBox(_box, _sphere);
|
||||
}
|
||||
|
||||
|
||||
@@ -889,18 +889,42 @@ void* PhysicsBackend::CreateScene(const PhysicsSettings& settings)
|
||||
PxSceneDesc sceneDesc(ToleranceScale);
|
||||
sceneDesc.gravity = C2P(settings.DefaultGravity);
|
||||
sceneDesc.flags |= PxSceneFlag::eENABLE_ACTIVE_ACTORS;
|
||||
sceneDesc.flags |= PxSceneFlag::eENABLE_PCM;
|
||||
if (!settings.DisableCCD)
|
||||
sceneDesc.flags |= PxSceneFlag::eENABLE_CCD;
|
||||
sceneDesc.simulationEventCallback = &scenePhysX->EventsCallback;
|
||||
sceneDesc.filterShader = FilterShader;
|
||||
sceneDesc.bounceThresholdVelocity = settings.BounceThresholdVelocity;
|
||||
sceneDesc.solverType = PxSolverType::ePGS;
|
||||
switch (settings.SolverType)
|
||||
{
|
||||
case PhysicsSolverType::ProjectedGaussSeidelIterativeSolver:
|
||||
sceneDesc.solverType = PxSolverType::ePGS;
|
||||
break;
|
||||
case PhysicsSolverType::TemporalGaussSeidelSolver:
|
||||
sceneDesc.solverType = PxSolverType::eTGS;
|
||||
break;
|
||||
}
|
||||
if (sceneDesc.cpuDispatcher == nullptr)
|
||||
{
|
||||
scenePhysX->CpuDispatcher = PxDefaultCpuDispatcherCreate(Math::Clamp<uint32>(Platform::GetCPUInfo().ProcessorCoreCount - 1, 1, 4));
|
||||
CHECK_INIT(scenePhysX->CpuDispatcher, "PxDefaultCpuDispatcherCreate failed!");
|
||||
sceneDesc.cpuDispatcher = scenePhysX->CpuDispatcher;
|
||||
}
|
||||
switch (settings.BroadPhaseType)
|
||||
{
|
||||
case PhysicsBroadPhaseType::SweepAndPrune:
|
||||
sceneDesc.broadPhaseType = PxBroadPhaseType::eSAP;
|
||||
break;
|
||||
case PhysicsBroadPhaseType::MultiBoxPruning:
|
||||
sceneDesc.broadPhaseType = PxBroadPhaseType::eMBP;
|
||||
break;
|
||||
case PhysicsBroadPhaseType::AutomaticBoxPruning:
|
||||
sceneDesc.broadPhaseType = PxBroadPhaseType::eABP;
|
||||
break;
|
||||
case PhysicsBroadPhaseType::ParallelAutomaticBoxPruning:
|
||||
sceneDesc.broadPhaseType = PxBroadPhaseType::ePABP;
|
||||
break;
|
||||
}
|
||||
|
||||
// Create scene
|
||||
scenePhysX->Scene = PhysX->createScene(sceneDesc);
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
void ClearColliderFromCollection(PhysicsColliderActor* collider, Array<SimulationEventCallback::CollidersPair>& collection)
|
||||
void ClearColliderFromCollection(const PhysicsColliderActor* collider, Array<SimulationEventCallback::CollidersPair>& collection)
|
||||
{
|
||||
if (collection.IsEmpty())
|
||||
return;
|
||||
for (int32 i = 0; i < collection.Count(); i++)
|
||||
{
|
||||
if (collection[i].First == collider || collection[i].Second == collider)
|
||||
@@ -24,8 +26,10 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void ClearColliderFromCollection(PhysicsColliderActor* collider, SimulationEventCallback::CollisionsPool& collection)
|
||||
void ClearColliderFromCollection(const PhysicsColliderActor* collider, SimulationEventCallback::CollisionsPool& collection)
|
||||
{
|
||||
if (collection.IsEmpty())
|
||||
return;
|
||||
for (auto i = collection.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (i->Key.First == collider || i->Key.Second == collider)
|
||||
|
||||
@@ -57,6 +57,8 @@ void PhysicsSettings::Deserialize(DeserializeStream& stream, ISerializeModifier*
|
||||
DESERIALIZE(FrictionCombineMode);
|
||||
DESERIALIZE(RestitutionCombineMode);
|
||||
DESERIALIZE(DisableCCD);
|
||||
DESERIALIZE(BroadPhaseType);
|
||||
DESERIALIZE(SolverType);
|
||||
DESERIALIZE(MaxDeltaTime);
|
||||
DESERIALIZE(EnableSubstepping);
|
||||
DESERIALIZE(SubstepDeltaTime);
|
||||
|
||||
@@ -6,6 +6,50 @@
|
||||
#include "Engine/Core/Math/Vector3.h"
|
||||
#include "Types.h"
|
||||
|
||||
/// <summary>
|
||||
/// Broad phase algorithm used in the simulation.
|
||||
/// <see href="https://nvidia-omniverse.github.io/PhysX/physx/5.1.0/_build/physx/latest/struct_px_broad_phase_type.html"/>
|
||||
/// </summary>
|
||||
API_ENUM() enum class PhysicsBroadPhaseType
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-axes sweep-and-prune. Good generic choice with great performance when many objects are sleeping.
|
||||
/// </summary>
|
||||
SweepAndPrune = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Alternative broad phase algorithm that does not suffer from the same performance issues as SAP when all objects are moving or when inserting large numbers of objects.
|
||||
/// </summary>
|
||||
MultiBoxPruning = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Revisited implementation of MBP, which automatically manages broad-phase regions.
|
||||
/// </summary>
|
||||
AutomaticBoxPruning = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Parallel implementation of ABP. It can often be the fastest (CPU) broadphase, but it can use more memory than ABP.
|
||||
/// </summary>
|
||||
ParallelAutomaticBoxPruning = 3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The type of solver used in the simulation.
|
||||
/// <see href="https://nvidia-omniverse.github.io/PhysX/physx/5.1.0/_build/physx/latest/struct_px_solver_type.html"/>
|
||||
/// </summary>
|
||||
API_ENUM() enum class PhysicsSolverType
|
||||
{
|
||||
/// <summary>
|
||||
/// The iterative sequential impulse solver.
|
||||
/// </summary>
|
||||
ProjectedGaussSeidelIterativeSolver = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Non linear iterative solver. This kind of solver can lead to improved convergence and handle large mass ratios, long chains and jointed systems better. It is slightly more expensive than the default solver and can introduce more energy to correct joint and contact errors.
|
||||
/// </summary>
|
||||
TemporalGaussSeidelSolver = 1,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Physics simulation settings container.
|
||||
/// </summary>
|
||||
@@ -43,6 +87,18 @@ public:
|
||||
API_FIELD(Attributes="EditorOrder(70), EditorDisplay(\"Simulation\")")
|
||||
bool DisableCCD = false;
|
||||
|
||||
/// <summary>
|
||||
/// Broad phase algorithm to use in the simulation.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(71), EditorDisplay(\"Simulation\")")
|
||||
PhysicsBroadPhaseType BroadPhaseType = PhysicsBroadPhaseType::ParallelAutomaticBoxPruning;
|
||||
|
||||
/// <summary>
|
||||
/// The solver type to use in the simulation.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(72), EditorDisplay(\"Simulation\")")
|
||||
PhysicsSolverType SolverType = PhysicsSolverType::ProjectedGaussSeidelIterativeSolver;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum allowed delta time (in seconds) for the physics simulation step.
|
||||
/// </summary>
|
||||
|
||||
@@ -405,6 +405,7 @@ void WindowBase::OnResize(int32 width, int32 height)
|
||||
_swapChain->Resize(width, height);
|
||||
if (RenderTask)
|
||||
RenderTask->Resize(width, height);
|
||||
Resized({ static_cast<float>(width), static_cast<float>(height) });
|
||||
INVOKE_EVENT_PARAMS_2(OnResize, &width, &height);
|
||||
}
|
||||
|
||||
|
||||
@@ -315,6 +315,11 @@ public:
|
||||
/// </summary>
|
||||
Action Closed;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when window gets resized.
|
||||
/// </summary>
|
||||
Delegate<Float2> Resized;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when window gets focused.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "MTypes.h"
|
||||
#include "MClass.h"
|
||||
#include "MCore.h"
|
||||
#include "Engine/Core/Types/StringView.h"
|
||||
#include "Engine/Core/Types/DataContainer.h"
|
||||
@@ -354,7 +355,7 @@ struct MConverter<Array<T>>
|
||||
{
|
||||
if (!klass)
|
||||
return nullptr;
|
||||
MArray* result = MCore::Array::New(klass, data.Count());
|
||||
MArray* result = MCore::Array::New(klass->GetElementClass(), data.Count());
|
||||
MConverter<T> converter;
|
||||
converter.ToManagedArray(result, Span<T>(data.Get(), data.Count()));
|
||||
return (MObject*)result;
|
||||
|
||||
@@ -365,8 +365,8 @@ MString* MCore::String::GetEmpty(MDomain* domain)
|
||||
|
||||
MString* MCore::String::New(const char* str, int32 length, MDomain* domain)
|
||||
{
|
||||
static void* NewStringLengthPtr = GetStaticMethodPointer(TEXT("NewStringLength"));
|
||||
return (MString*)CallStaticMethod<void*, const char*, int>(NewStringLengthPtr, str, length);
|
||||
static void* NewStringUTF8Ptr = GetStaticMethodPointer(TEXT("NewStringUTF8"));
|
||||
return (MString*)CallStaticMethod<void*, const char*, int>(NewStringUTF8Ptr, str, length);
|
||||
}
|
||||
|
||||
MString* MCore::String::New(const Char* str, int32 length, MDomain* domain)
|
||||
|
||||
@@ -205,6 +205,13 @@ namespace FlaxEngine
|
||||
|
||||
internal static void AddDictionaryItem(IDictionary dictionary, object key, object value)
|
||||
{
|
||||
// TODO: more generic approach to properly add value that is of custom boxed type? (eg. via NativeInterop.MarshalToManaged)
|
||||
if (value is ManagedArray managedArray)
|
||||
{
|
||||
var managedArrayHandle = ManagedHandle.Alloc(managedArray, GCHandleType.Normal);
|
||||
value = NativeInterop.MarshalToManaged((IntPtr)managedArrayHandle, managedArray.ArrayType);
|
||||
managedArrayHandle.Free();
|
||||
}
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -384,6 +384,8 @@ void ModelTool::Options::Serialize(SerializeStream& stream, const void* otherObj
|
||||
SERIALIZE(BaseLOD);
|
||||
SERIALIZE(LODCount);
|
||||
SERIALIZE(TriangleReduction);
|
||||
SERIALIZE(SloppyOptimization);
|
||||
SERIALIZE(LODTargetError);
|
||||
SERIALIZE(ImportMaterials);
|
||||
SERIALIZE(ImportMaterialsAsInstances);
|
||||
SERIALIZE(InstanceToImportAs);
|
||||
@@ -427,6 +429,8 @@ void ModelTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifi
|
||||
DESERIALIZE(BaseLOD);
|
||||
DESERIALIZE(LODCount);
|
||||
DESERIALIZE(TriangleReduction);
|
||||
DESERIALIZE(SloppyOptimization);
|
||||
DESERIALIZE(LODTargetError);
|
||||
DESERIALIZE(ImportMaterials);
|
||||
DESERIALIZE(ImportMaterialsAsInstances);
|
||||
DESERIALIZE(InstanceToImportAs);
|
||||
@@ -1556,7 +1560,11 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op
|
||||
int32 dstMeshIndexCountTarget = int32(srcMeshIndexCount * triangleReduction) / 3 * 3;
|
||||
Array<unsigned int> indices;
|
||||
indices.Resize(dstMeshIndexCountTarget);
|
||||
int32 dstMeshIndexCount = (int32)meshopt_simplifySloppy(indices.Get(), srcMesh->Indices.Get(), srcMeshIndexCount, (const float*)srcMesh->Positions.Get(), srcMeshVertexCount, sizeof(Float3), dstMeshIndexCountTarget);
|
||||
int32 dstMeshIndexCount = {};
|
||||
if (options.SloppyOptimization)
|
||||
dstMeshIndexCount = (int32)meshopt_simplifySloppy(indices.Get(), srcMesh->Indices.Get(), srcMeshIndexCount, (const float*)srcMesh->Positions.Get(), srcMeshVertexCount, sizeof(Float3), dstMeshIndexCountTarget);
|
||||
else
|
||||
dstMeshIndexCount = (int32)meshopt_simplify(indices.Get(), srcMesh->Indices.Get(), srcMeshIndexCount, (const float*)srcMesh->Positions.Get(), srcMeshVertexCount, sizeof(Float3), dstMeshIndexCountTarget, options.LODTargetError);
|
||||
indices.Resize(dstMeshIndexCount);
|
||||
if (dstMeshIndexCount == 0)
|
||||
continue;
|
||||
|
||||
@@ -324,6 +324,12 @@ public:
|
||||
// The target amount of triangles for the generated LOD (based on the higher LOD). Normalized to range 0-1. For instance 0.4 cuts the triangle count to 40%.
|
||||
API_FIELD(Attributes="EditorOrder(1130), EditorDisplay(\"Level Of Detail\"), VisibleIf(nameof(ShowGeometry)), Limit(0, 1, 0.001f)")
|
||||
float TriangleReduction = 0.5f;
|
||||
// Whether to do a sloppy mesh optimization. This is faster but does not follow the topology of the original mesh.
|
||||
API_FIELD(Attributes="EditorOrder(1140), EditorDisplay(\"Level Of Detail\"), VisibleIf(nameof(ShowGeometry))")
|
||||
bool SloppyOptimization = true;
|
||||
// Only used if Sloppy is false. Target error is an approximate measure of the deviation from the original mesh using distance normalized to [0..1] range (e.g. 1e-2f means that simplifier will try to maintain the error to be below 1% of the mesh extents).
|
||||
API_FIELD(Attributes="EditorOrder(1150), EditorDisplay(\"Level Of Detail\"), VisibleIf(nameof(SloppyOptimization), true), Limit(0.01f, 1, 0.001f)")
|
||||
float LODTargetError = 0.1f;
|
||||
|
||||
public: // Materials
|
||||
|
||||
|
||||
@@ -199,11 +199,11 @@ namespace FlaxEngine.GUI
|
||||
// UI navigation
|
||||
if (_canvas.ReceivesEvents)
|
||||
{
|
||||
UpdateNavigation(deltaTime, _canvas.NavigationInputActionUp, NavDirection.Up, ref _navigationHeldTimeUp, ref _navigationRateTimeUp);
|
||||
UpdateNavigation(deltaTime, _canvas.NavigationInputActionDown, NavDirection.Down, ref _navigationHeldTimeDown, ref _navigationRateTimeDown);
|
||||
UpdateNavigation(deltaTime, _canvas.NavigationInputActionLeft, NavDirection.Left, ref _navigationHeldTimeLeft, ref _navigationRateTimeLeft);
|
||||
UpdateNavigation(deltaTime, _canvas.NavigationInputActionRight, NavDirection.Right, ref _navigationHeldTimeRight, ref _navigationRateTimeRight);
|
||||
UpdateNavigation(deltaTime, _canvas.NavigationInputActionSubmit, ref _navigationHeldTimeSubmit, ref _navigationRateTimeSubmit, SubmitFocused);
|
||||
UpdateNavigation(deltaTime, _canvas.NavigateUp.Name, NavDirection.Up, ref _navigationHeldTimeUp, ref _navigationRateTimeUp);
|
||||
UpdateNavigation(deltaTime, _canvas.NavigateDown.Name, NavDirection.Down, ref _navigationHeldTimeDown, ref _navigationRateTimeDown);
|
||||
UpdateNavigation(deltaTime, _canvas.NavigateLeft.Name, NavDirection.Left, ref _navigationHeldTimeLeft, ref _navigationRateTimeLeft);
|
||||
UpdateNavigation(deltaTime, _canvas.NavigateRight.Name, NavDirection.Right, ref _navigationHeldTimeRight, ref _navigationRateTimeRight);
|
||||
UpdateNavigation(deltaTime, _canvas.NavigateSubmit.Name, ref _navigationHeldTimeSubmit, ref _navigationRateTimeSubmit, SubmitFocused);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
using System;
|
||||
|
||||
namespace FlaxEngine.GUI;
|
||||
|
||||
/// <summary>
|
||||
/// The slider control.
|
||||
/// </summary>
|
||||
public class Slider : ContainerControl
|
||||
{
|
||||
/// <summary>
|
||||
/// The minimum value.
|
||||
/// </summary>
|
||||
protected float _minimum;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum value.
|
||||
/// </summary>
|
||||
protected float _maximum = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum value.
|
||||
/// </summary>
|
||||
[EditorOrder(20), Tooltip("The minimum value.")]
|
||||
public float Minimum
|
||||
{
|
||||
get => _minimum;
|
||||
set
|
||||
{
|
||||
if (value > _maximum)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
if (WholeNumbers)
|
||||
value = Mathf.RoundToInt(value);
|
||||
_minimum = value;
|
||||
if (Value < _minimum)
|
||||
Value = _minimum;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum value.
|
||||
/// </summary>
|
||||
[EditorOrder(30), Tooltip("The maximum value.")]
|
||||
public float Maximum
|
||||
{
|
||||
get => _maximum;
|
||||
set
|
||||
{
|
||||
if (value < _minimum || Mathf.IsZero(value))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
if (WholeNumbers)
|
||||
value = Mathf.RoundToInt(value);
|
||||
_maximum = value;
|
||||
if (Value > _maximum)
|
||||
Value = _maximum;
|
||||
}
|
||||
}
|
||||
|
||||
private float _value = 100f;
|
||||
private Rectangle _thumbRect;
|
||||
private float _thumbCenter;
|
||||
private Float2 _thumbSize = new Float2(16, 16);
|
||||
private bool _isSliding;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value (normalized to range 0-100).
|
||||
/// </summary>
|
||||
[EditorOrder(10), Tooltip("The current value.")]
|
||||
public float Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, Minimum, Maximum);
|
||||
if (WholeNumbers)
|
||||
value = Mathf.RoundToInt(value);
|
||||
if (!Mathf.NearEqual(value, _value))
|
||||
{
|
||||
_value = value;
|
||||
|
||||
// Update
|
||||
UpdateThumb();
|
||||
ValueChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The local position of the thumb center
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public Float2 ThumbCenter => new(_thumbCenter, Height / 2);
|
||||
|
||||
/// <summary>
|
||||
/// The local position of the beginning of the track.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public Float2 TrackBeginning => new(_thumbSize.X / 2, Height / 2);
|
||||
|
||||
/// <summary>
|
||||
/// The local position of the end of the track.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public Float2 TrackEnd => new(Width - _thumbSize.X / 2, Height / 2);
|
||||
|
||||
/// <summary>
|
||||
/// The height of the track.
|
||||
/// </summary>
|
||||
[EditorOrder(40), Tooltip("The track height.")]
|
||||
public int TrackHeight { get; set; } = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The thumb size.
|
||||
/// </summary>
|
||||
[EditorOrder(41), Tooltip("The size of the thumb.")]
|
||||
public Float2 ThumbSize {
|
||||
get => _thumbSize;
|
||||
set
|
||||
{
|
||||
_thumbSize = value;
|
||||
UpdateThumb();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether to fill the track.
|
||||
/// </summary>
|
||||
[EditorOrder(42), Tooltip("Fill the track.")]
|
||||
public bool FillTrack = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use whole numbers.
|
||||
/// </summary>
|
||||
[EditorOrder(43), Tooltip("Use whole numbers.")]
|
||||
public bool WholeNumbers = false;
|
||||
|
||||
/// <summary>
|
||||
/// The color of the slider track line
|
||||
/// </summary>
|
||||
[EditorDisplay("Track Style"), EditorOrder(2010), Tooltip("The color of the slider track line."), ExpandGroups]
|
||||
public Color TrackLineColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The color of the slider fill track line
|
||||
/// </summary>
|
||||
[EditorDisplay("Track Style"), EditorOrder(2011), VisibleIf(nameof(FillTrack)), Tooltip("The color of the slider fill track line.")]
|
||||
public Color TrackFillLineColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the track.
|
||||
/// </summary>
|
||||
private float TrackWidth => Width;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush used for slider track drawing.
|
||||
/// </summary>
|
||||
[EditorDisplay("Track Style"), EditorOrder(2012), Tooltip("The brush used for slider track drawing.")]
|
||||
public IBrush TrackBrush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush used for slider fill track drawing.
|
||||
/// </summary>
|
||||
[EditorDisplay("Track Style"), EditorOrder(2013), VisibleIf(nameof(FillTrack)), Tooltip("The brush used for slider fill track drawing.")]
|
||||
public IBrush FillTrackBrush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The color of the slider thumb when it's not selected
|
||||
/// </summary>
|
||||
[EditorDisplay("Thumb Style"), EditorOrder(2030), Tooltip("The color of the slider thumb when it's not selected."), ExpandGroups]
|
||||
public Color ThumbColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The color of the slider thumb when it's selected
|
||||
/// </summary>
|
||||
[EditorDisplay("Thumb Style"), EditorOrder(2031), Tooltip("The color of the slider thumb when it's selected.")]
|
||||
public Color ThumbColorSelected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush used for slider thumb drawing.
|
||||
/// </summary>
|
||||
[EditorDisplay("Thumb Style"), EditorOrder(2032), Tooltip("The brush of the slider thumb.")]
|
||||
public IBrush ThumbBrush { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user is using a slider.
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public bool IsSliding => _isSliding;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when sliding starts.
|
||||
/// </summary>
|
||||
public event Action SlidingStart;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when sliding ends.
|
||||
/// </summary>
|
||||
public event Action SlidingEnd;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when value gets changed.
|
||||
/// </summary>
|
||||
public event Action ValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Slider"/> class.
|
||||
/// </summary>
|
||||
public Slider()
|
||||
: this(120, 30)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Slider"/> class.
|
||||
/// </summary>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
public Slider(float width, float height)
|
||||
: base(0, 0, width, height)
|
||||
{
|
||||
var style = Style.Current;
|
||||
TrackLineColor = style.BackgroundHighlighted;
|
||||
TrackFillLineColor = style.LightBackground;
|
||||
ThumbColor = style.BackgroundNormal;
|
||||
ThumbColorSelected = style.BackgroundSelected;
|
||||
UpdateThumb();
|
||||
}
|
||||
|
||||
private void UpdateThumb()
|
||||
{
|
||||
// Cache data
|
||||
float trackSize = TrackWidth;
|
||||
float range = Maximum - Minimum;
|
||||
float pixelRange = trackSize - _thumbSize.X;
|
||||
float perc = (_value - Minimum) / range;
|
||||
float thumbPosition = (int)(perc * pixelRange);
|
||||
_thumbCenter = thumbPosition + _thumbSize.X / 2;
|
||||
_thumbRect = new Rectangle(thumbPosition, (Height - _thumbSize.Y) / 2, _thumbSize.X, _thumbSize.Y);
|
||||
}
|
||||
|
||||
private void EndSliding()
|
||||
{
|
||||
_isSliding = false;
|
||||
EndMouseCapture();
|
||||
SlidingEnd?.Invoke();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
// Draw track line
|
||||
//var lineRect = new Rectangle(4, (Height - TrackHeight) / 2, Width - 8, TrackHeight);
|
||||
var lineRect = new Rectangle(_thumbSize.X / 2, (Height - TrackHeight) / 2, Width - _thumbSize.X, TrackHeight);
|
||||
if (TrackBrush != null)
|
||||
TrackBrush.Draw(lineRect, TrackLineColor);
|
||||
else
|
||||
Render2D.FillRectangle(lineRect, TrackLineColor);
|
||||
|
||||
// Draw track fill
|
||||
if (FillTrack)
|
||||
{
|
||||
var fillLineRect = new Rectangle(_thumbSize.X / 2, (Height - TrackHeight - 2) / 2, Width - (Width - _thumbCenter) - _thumbSize.X / 2, TrackHeight + 2);
|
||||
Render2D.PushClip(ref fillLineRect);
|
||||
if (FillTrackBrush != null)
|
||||
FillTrackBrush.Draw(lineRect, TrackFillLineColor);
|
||||
else
|
||||
Render2D.FillRectangle(lineRect, TrackFillLineColor);
|
||||
Render2D.PopClip();
|
||||
}
|
||||
|
||||
// Draw thumb
|
||||
var thumbColor = _isSliding ? ThumbColorSelected : ThumbColor;
|
||||
if (ThumbBrush != null)
|
||||
ThumbBrush.Draw(_thumbRect, thumbColor);
|
||||
else
|
||||
Render2D.FillRectangle(_thumbRect, thumbColor);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
if (_isSliding)
|
||||
{
|
||||
EndSliding();
|
||||
}
|
||||
|
||||
base.OnLostFocus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
Focus();
|
||||
float mousePosition = location.X;
|
||||
|
||||
if (_thumbRect.Contains(ref location))
|
||||
{
|
||||
// Start sliding
|
||||
_isSliding = true;
|
||||
StartMouseCapture();
|
||||
SlidingStart?.Invoke();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Click change
|
||||
Value += (mousePosition < _thumbCenter ? -1 : 1) * 10;
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
if (_isSliding)
|
||||
{
|
||||
// Update sliding
|
||||
var slidePosition = location + Root.TrackingMouseOffset;
|
||||
Value = Mathf.Remap(slidePosition.X, 4, TrackWidth - 4, Minimum, Maximum);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _isSliding)
|
||||
{
|
||||
EndSliding();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnEndMouseCapture()
|
||||
{
|
||||
// Check if was sliding
|
||||
if (_isSliding)
|
||||
{
|
||||
EndSliding();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnEndMouseCapture();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSizeChanged()
|
||||
{
|
||||
base.OnSizeChanged();
|
||||
|
||||
UpdateThumb();
|
||||
}
|
||||
}
|
||||
@@ -263,39 +263,39 @@ namespace FlaxEngine
|
||||
public float NavigationInputRepeatRate { get; set; } = 0.05f;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the input action for performing UI navigation Up (from Input Settings).
|
||||
/// The input action for performing UI navigation Up (from Input Settings).
|
||||
/// </summary>
|
||||
[EditorOrder(510), EditorDisplay("Navigation", "Navigate Up")]
|
||||
[Tooltip("The name of the input action for performing UI navigation Up (from Input Settings).")]
|
||||
public string NavigationInputActionUp { get; set; } = "NavigateUp";
|
||||
[Tooltip("The input action for performing UI navigation Up (from Input Settings).")]
|
||||
public InputEvent NavigateUp { get; set; } = new InputEvent("NavigateUp");
|
||||
|
||||
/// <summary>
|
||||
/// The name of the input action for performing UI navigation Down (from Input Settings).
|
||||
/// The input action for performing UI navigation Down (from Input Settings).
|
||||
/// </summary>
|
||||
[EditorOrder(520), EditorDisplay("Navigation", "Navigate Down")]
|
||||
[Tooltip("The name of the input action for performing UI navigation Down (from Input Settings).")]
|
||||
public string NavigationInputActionDown { get; set; } = "NavigateDown";
|
||||
[Tooltip("The input action for performing UI navigation Down (from Input Settings).")]
|
||||
public InputEvent NavigateDown { get; set; } = new InputEvent("NavigateDown");
|
||||
|
||||
/// <summary>
|
||||
/// The name of the input action for performing UI navigation Left (from Input Settings).
|
||||
/// The input action for performing UI navigation Left (from Input Settings).
|
||||
/// </summary>
|
||||
[EditorOrder(530), EditorDisplay("Navigation", "Navigate Left")]
|
||||
[Tooltip("The name of the input action for performing UI navigation Left (from Input Settings).")]
|
||||
public string NavigationInputActionLeft { get; set; } = "NavigateLeft";
|
||||
[Tooltip("The input action for performing UI navigation Left (from Input Settings).")]
|
||||
public InputEvent NavigateLeft { get; set; } = new InputEvent("NavigateLeft");
|
||||
|
||||
/// <summary>
|
||||
/// The name of the input action for performing UI navigation Right (from Input Settings).
|
||||
/// The input action for performing UI navigation Right (from Input Settings).
|
||||
/// </summary>
|
||||
[EditorOrder(540), EditorDisplay("Navigation", "Navigate Right")]
|
||||
[Tooltip("The name of the input action for performing UI navigation Right (from Input Settings).")]
|
||||
public string NavigationInputActionRight { get; set; } = "NavigateRight";
|
||||
[Tooltip("The input action for performing UI navigation Right (from Input Settings).")]
|
||||
public InputEvent NavigateRight { get; set; } = new InputEvent("NavigateRight");
|
||||
|
||||
/// <summary>
|
||||
/// The name of the input action for performing UI navigation Submit (from Input Settings).
|
||||
/// The input action for performing UI navigation Submit (from Input Settings).
|
||||
/// </summary>
|
||||
[EditorOrder(540), EditorDisplay("Navigation", "Navigate Submit")]
|
||||
[Tooltip("The name of the input action for performing UI navigation Submit (from Input Settings).")]
|
||||
public string NavigationInputActionSubmit { get; set; } = "NavigateSubmit";
|
||||
[EditorOrder(550), EditorDisplay("Navigation", "Navigate Submit")]
|
||||
[Tooltip("The input action for performing UI navigation Submit (from Input Settings).")]
|
||||
public InputEvent NavigateSubmit { get; set; } = new InputEvent("NavigateSubmit");
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -620,14 +620,36 @@ namespace FlaxEngine
|
||||
jsonWriter.WriteValue(NavigationInputRepeatDelay);
|
||||
jsonWriter.WritePropertyName("NavigationInputRepeatRate");
|
||||
jsonWriter.WriteValue(NavigationInputRepeatRate);
|
||||
jsonWriter.WritePropertyName("NavigationInputActionUp");
|
||||
jsonWriter.WriteValue(NavigationInputActionUp);
|
||||
jsonWriter.WritePropertyName("NavigationInputActionDown");
|
||||
jsonWriter.WriteValue(NavigationInputActionDown);
|
||||
jsonWriter.WritePropertyName("NavigationInputActionLeft");
|
||||
jsonWriter.WriteValue(NavigationInputActionLeft);
|
||||
jsonWriter.WritePropertyName("NavigationInputActionRight");
|
||||
jsonWriter.WriteValue(NavigationInputActionRight);
|
||||
|
||||
jsonWriter.WritePropertyName("NavigateUp");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateUp.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
|
||||
jsonWriter.WritePropertyName("NavigateDown");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateDown.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
|
||||
jsonWriter.WritePropertyName("NavigateLeft");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateLeft.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
|
||||
jsonWriter.WritePropertyName("NavigateRight");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateRight.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
|
||||
jsonWriter.WritePropertyName("NavigateSubmit");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateSubmit.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
|
||||
jsonWriter.WriteEndObject();
|
||||
}
|
||||
@@ -713,25 +735,45 @@ namespace FlaxEngine
|
||||
jsonWriter.WritePropertyName("NavigationInputRepeatRate");
|
||||
jsonWriter.WriteValue(NavigationInputRepeatRate);
|
||||
}
|
||||
if (NavigationInputActionUp != other.NavigationInputActionUp)
|
||||
if (NavigateUp.Name != other.NavigateUp.Name)
|
||||
{
|
||||
jsonWriter.WritePropertyName("NavigationInputActionUp");
|
||||
jsonWriter.WriteValue(NavigationInputActionUp);
|
||||
jsonWriter.WritePropertyName("NavigateUp");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateUp.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
}
|
||||
if (NavigationInputActionDown != other.NavigationInputActionDown)
|
||||
if (NavigateDown.Name != other.NavigateDown.Name)
|
||||
{
|
||||
jsonWriter.WritePropertyName("NavigationInputActionDown");
|
||||
jsonWriter.WriteValue(NavigationInputActionDown);
|
||||
jsonWriter.WritePropertyName("NavigateDown");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateDown.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
}
|
||||
if (NavigationInputActionLeft != other.NavigationInputActionLeft)
|
||||
if (NavigateLeft.Name != other.NavigateLeft.Name)
|
||||
{
|
||||
jsonWriter.WritePropertyName("NavigationInputActionLeft");
|
||||
jsonWriter.WriteValue(NavigationInputActionLeft);
|
||||
jsonWriter.WritePropertyName("NavigateLeft");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateLeft.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
}
|
||||
if (NavigationInputActionRight != other.NavigationInputActionRight)
|
||||
if (NavigateRight.Name != other.NavigateRight.Name)
|
||||
{
|
||||
jsonWriter.WritePropertyName("NavigationInputActionRight");
|
||||
jsonWriter.WriteValue(NavigationInputActionRight);
|
||||
jsonWriter.WritePropertyName("NavigateRight");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateRight.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
}
|
||||
if (NavigateSubmit.Name != other.NavigateSubmit.Name)
|
||||
{
|
||||
jsonWriter.WritePropertyName("NavigateSubmit");
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WritePropertyName("Name");
|
||||
jsonWriter.WriteValue(NavigateSubmit.Name);
|
||||
jsonWriter.WriteEndObject();
|
||||
}
|
||||
|
||||
jsonWriter.WriteEndObject();
|
||||
|
||||
@@ -1279,16 +1279,16 @@ void VisjectExecutor::ProcessGroupParticles(Box* box, Node* node, Value& value)
|
||||
// Random Float Range
|
||||
case 213:
|
||||
{
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat;
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat;
|
||||
auto a = (float)tryGetValue(node->TryGetBox(1), node->Values[0]);
|
||||
auto b = (float)tryGetValue(node->TryGetBox(2), node->Values[1]);
|
||||
value = Math::Lerp(a, b, RAND);
|
||||
break;
|
||||
}
|
||||
// Random Vector2 Range
|
||||
case 214:
|
||||
{
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat2();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat2();
|
||||
auto a = (Float2)tryGetValue(node->TryGetBox(1), node->Values[0]);
|
||||
auto b = (Float2)tryGetValue(node->TryGetBox(2), node->Values[1]);
|
||||
value = Float2(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND)
|
||||
@@ -1298,8 +1298,8 @@ void VisjectExecutor::ProcessGroupParticles(Box* box, Node* node, Value& value)
|
||||
// Random Vector3 Range
|
||||
case 215:
|
||||
{
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat3();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat3();
|
||||
auto a = (Float3)tryGetValue(node->TryGetBox(1), node->Values[0]);
|
||||
auto b = (Float3)tryGetValue(node->TryGetBox(2), node->Values[1]);
|
||||
value = Float3(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND),
|
||||
@@ -1310,8 +1310,8 @@ void VisjectExecutor::ProcessGroupParticles(Box* box, Node* node, Value& value)
|
||||
// Random Vector4 Range
|
||||
case 216:
|
||||
{
|
||||
auto a = tryGetValue(node->TryGetBox(1), node->Values[0]).AsFloat4();
|
||||
auto b = tryGetValue(node->TryGetBox(2), node->Values[1]).AsFloat4();
|
||||
auto a = (Float4)tryGetValue(node->TryGetBox(1), node->Values[0]);
|
||||
auto b = (Float4)tryGetValue(node->TryGetBox(2), node->Values[1]);
|
||||
value = Float4(
|
||||
Math::Lerp(a.X, b.X, RAND),
|
||||
Math::Lerp(a.Y, b.Y, RAND),
|
||||
|
||||
Reference in New Issue
Block a user