Merge remote-tracking branch 'origin/master' into 1.6

This commit is contained in:
Wojtek Figat
2023-06-10 23:29:22 +02:00
21 changed files with 438 additions and 45 deletions

View File

@@ -85,18 +85,18 @@ Keyboard* Input::Keyboard = nullptr;
Array<Gamepad*, FixedAllocation<MAX_GAMEPADS>> Input::Gamepads;
Action Input::GamepadsChanged;
Array<InputDevice*, InlinedAllocation<16>> Input::CustomDevices;
Input::CharDelegate Input::CharInput;
Input::KeyboardDelegate Input::KeyDown;
Input::KeyboardDelegate Input::KeyUp;
Input::MouseButtonDelegate Input::MouseDown;
Input::MouseButtonDelegate Input::MouseUp;
Input::MouseButtonDelegate Input::MouseDoubleClick;
Input::MouseWheelDelegate Input::MouseWheel;
Input::MouseDelegate Input::MouseMove;
Delegate<Char> Input::CharInput;
Delegate<KeyboardKeys> Input::KeyDown;
Delegate<KeyboardKeys> Input::KeyUp;
Delegate<const Float2&, MouseButton> Input::MouseDown;
Delegate<const Float2&, MouseButton> Input::MouseUp;
Delegate<const Float2&, MouseButton> Input::MouseDoubleClick;
Delegate<const Float2&, float> Input::MouseWheel;
Delegate<const Float2&> Input::MouseMove;
Action Input::MouseLeave;
Input::TouchDelegate Input::TouchDown;
Input::TouchDelegate Input::TouchMove;
Input::TouchDelegate Input::TouchUp;
Delegate<const Float2&, int32> Input::TouchDown;
Delegate<const Float2&, int32> Input::TouchMove;
Delegate<const Float2&, int32> Input::TouchUp;
Delegate<StringView> Input::ActionTriggered;
Array<ActionConfig> Input::ActionMappings;
Array<AxisConfig> Input::AxisMappings;

View File

@@ -66,72 +66,66 @@ API_CLASS(Static) class FLAXENGINE_API Input
static Array<InputDevice*, InlinedAllocation<16>> CustomDevices;
public:
typedef Delegate<Char> CharDelegate;
typedef Delegate<KeyboardKeys> KeyboardDelegate;
typedef Delegate<const Float2&> MouseDelegate;
typedef Delegate<const Float2&, MouseButton> MouseButtonDelegate;
typedef Delegate<const Float2&, float> MouseWheelDelegate;
typedef Delegate<const Float2&, int32> TouchDelegate;
/// <summary>
/// Event fired on character input.
/// </summary>
static CharDelegate CharInput;
API_EVENT() static Delegate<Char> CharInput;
/// <summary>
/// Event fired on key pressed.
/// </summary>
static KeyboardDelegate KeyDown;
API_EVENT() static Delegate<KeyboardKeys> KeyDown;
/// <summary>
/// Event fired on key released.
/// </summary>
static KeyboardDelegate KeyUp;
API_EVENT() static Delegate<KeyboardKeys> KeyUp;
/// <summary>
/// Event fired when mouse button goes down.
/// </summary>
static MouseButtonDelegate MouseDown;
API_EVENT() static Delegate<const Float2&, MouseButton> MouseDown;
/// <summary>
/// Event fired when mouse button goes up.
/// </summary>
static MouseButtonDelegate MouseUp;
API_EVENT() static Delegate<const Float2&, MouseButton> MouseUp;
/// <summary>
/// Event fired when mouse button double clicks.
/// </summary>
static MouseButtonDelegate MouseDoubleClick;
API_EVENT() static Delegate<const Float2&, MouseButton> MouseDoubleClick;
/// <summary>
/// Event fired when mouse wheel is scrolling (wheel delta is normalized).
/// </summary>
static MouseWheelDelegate MouseWheel;
API_EVENT() static Delegate<const Float2&, float> MouseWheel;
/// <summary>
/// Event fired when mouse moves.
/// </summary>
static MouseDelegate MouseMove;
API_EVENT() static Delegate<const Float2&> MouseMove;
/// <summary>
/// Event fired when mouse leaves window.
/// </summary>
static Action MouseLeave;
API_EVENT() static Action MouseLeave;
/// <summary>
/// Event fired when touch action begins.
/// </summary>
static TouchDelegate TouchDown;
API_EVENT() static Delegate<const Float2&, int32> TouchDown;
/// <summary>
/// Event fired when touch action moves.
/// </summary>
static TouchDelegate TouchMove;
API_EVENT() static Delegate<const Float2&, int32> TouchMove;
/// <summary>
/// Event fired when touch action ends.
/// </summary>
static TouchDelegate TouchUp;
API_EVENT() static Delegate<const Float2&, int32> TouchUp;
public:
/// <summary>

View File

@@ -1323,6 +1323,20 @@ Actor* Actor::FindActor(const MClass* type) const
return nullptr;
}
Actor* Actor::FindActor(const MClass* type, const StringView& name) const
{
CHECK_RETURN(type, nullptr);
if (GetClass()->IsSubClassOf(type) && StringUtils::Compare(*_name, *name) == 0)
return const_cast<Actor*>(this);
for (auto child : Children)
{
const auto actor = child->FindActor(type, name);
if (actor)
return actor;
}
return nullptr;
}
Script* Actor::FindScript(const MClass* type) const
{
CHECK_RETURN(type, nullptr);

View File

@@ -259,6 +259,17 @@ namespace FlaxEngine
return FindActor(typeof(T)) as T;
}
/// <summary>
/// Tries to find the actor of the given type and name in this actor hierarchy (checks this actor and all children hierarchy).
/// </summary>
/// <param name="name">Name of the object.</param>
/// <typeparam name="T">Type of the object.</typeparam>
/// <returns>Actor instance if found, null otherwise.</returns>
public T FindActor<T>(string name) where T : Actor
{
return FindActor(typeof(T), name) as T;
}
/// <summary>
/// Searches for all actors of a specific type in this actor children list.
/// </summary>

View File

@@ -734,6 +734,14 @@ public:
/// <returns>Actor instance if found, null otherwise.</returns>
API_FUNCTION() Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type) const;
/// <summary>
/// Tries to find the actor of the given type and name in this actor hierarchy (checks this actor and all children hierarchy).
/// </summary>
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
/// <param name="name">The name of the actor.</param>
/// <returns>Actor instance if found, null otherwise.</returns>
API_FUNCTION() Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, const StringView& name) const;
/// <summary>
/// Tries to find the actor of the given type in this actor hierarchy (checks this actor and all children hierarchy).
/// </summary>
@@ -744,6 +752,17 @@ public:
return (T*)FindActor(T::GetStaticClass());
}
/// <summary>
/// Tries to find the actor of the given type and name in this actor hierarchy (checks this actor and all children hierarchy).
/// </summary>
/// <param name="name">The name of the actor.</param>
/// <returns>Actor instance if found, null otherwise.</returns>
template<typename T>
FORCE_INLINE T* FindActor(const StringView& name) const
{
return (T*)FindActor(T::GetStaticClass(), name);
}
/// <summary>
/// Tries to find the script of the given type in this actor hierarchy (checks this actor and all children hierarchy).
/// </summary>

View File

@@ -748,6 +748,20 @@ void FindActorsRecursive(Actor* node, const Tag& tag, Array<Actor*>& result)
FindActorsRecursive(child, tag, result);
}
void FindActorsRecursiveByParentTags(Actor* node, const Array<Tag>& tags, Array<Actor*>& result)
{
for (Tag tag : tags)
{
if (node->HasTag(tag))
{
result.Add(node);
break;
}
}
for (Actor* child : node->Children)
FindActorsRecursiveByParentTags(child, tags, result);
}
Actor* Level::FindActor(const Tag& tag, Actor* root)
{
PROFILE_CPU();
@@ -781,12 +795,43 @@ Array<Actor*> Level::FindActors(const Tag& tag, Actor* root)
}
else
{
ScopeLock lock(ScenesLock);
for (Scene* scene : Scenes)
FindActorsRecursive(scene, tag, result);
}
return result;
}
Array<Actor*> Level::FindActorsByParentTag(const Tag& parentTag, Actor* root)
{
PROFILE_CPU();
Array<Actor*> result;
const Array<Tag> subTags = Tags::GetSubTags(parentTag);
if (subTags.Count() == 0)
{
return result;
}
if (subTags.Count() == 1)
{
result = FindActors(subTags[0], root);
return result;
}
if (root)
{
FindActorsRecursiveByParentTags(root, subTags, result);
}
else
{
ScopeLock lock(ScenesLock);
for (Scene* scene : Scenes)
FindActorsRecursiveByParentTags(scene, subTags, result);
}
return result;
}
void Level::callActorEvent(ActorEventType eventType, Actor* a, Actor* b)
{
PROFILE_CPU();
@@ -1266,7 +1311,7 @@ bool Level::SaveSceneToBytes(Scene* scene, rapidjson_flax::StringBuffer& outData
}
// Info
LOG(Info, "Scene saved! Time {0} ms", Math::CeilToInt(static_cast<float>((DateTime::NowUTC()- startTime).GetTotalMilliseconds())));
LOG(Info, "Scene saved! Time {0} ms", Math::CeilToInt(static_cast<float>((DateTime::NowUTC() - startTime).GetTotalMilliseconds())));
// Fire event
CallSceneEvent(SceneEventType::OnSceneSaved, scene, scene->GetID());
@@ -1446,6 +1491,16 @@ Actor* Level::FindActor(const MClass* type)
return result;
}
Actor* Level::FindActor(const MClass* type, const StringView& name)
{
CHECK_RETURN(type, nullptr);
Actor* result = nullptr;
ScopeLock lock(ScenesLock);
for (int32 i = 0; result == nullptr && i < Scenes.Count(); i++)
result = Scenes[i]->FindActor(type, name);
return result;
}
Script* Level::FindScript(const MClass* type)
{
CHECK_RETURN(type, nullptr);

View File

@@ -66,6 +66,17 @@ namespace FlaxEngine
{
return FindActor(typeof(T)) as T;
}
/// <summary>
/// Tries to find actor of the given type and name in all loaded scenes.
/// </summary>
/// <param name="name">Name of the object.</param>
/// <typeparam name="T">Type of the object.</typeparam>
/// <returns>Found actor or null.</returns>
public static T FindActor<T>(string name) where T : Actor
{
return FindActor(typeof(T), name) as T;
}
/// <summary>
/// Tries to find actor with the given ID in all loaded scenes. It's very fast O(1) lookup.

View File

@@ -363,6 +363,14 @@ public:
/// <returns>Found actor or null.</returns>
API_FUNCTION() static Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type);
/// <summary>
/// Tries to find the actor of the given type and name in all the loaded scenes.
/// </summary>
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
/// <param name="name">The name of the actor.</param>
/// <returns>Actor instance if found, null otherwise.</returns>
API_FUNCTION() static Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, const StringView& name);
/// <summary>
/// Tries to find the actor of the given type in all the loaded scenes.
/// </summary>
@@ -373,6 +381,17 @@ public:
return (T*)FindActor(T::GetStaticClass());
}
/// <summary>
/// Tries to find the actor of the given type and name in all the loaded scenes.
/// </summary>
/// <param name="name">The name of the actor.</param>
/// <returns>Actor instance if found, null otherwise.</returns>
template<typename T>
FORCE_INLINE static T* FindActor(const StringView& name)
{
return (T*)FindActor(T::GetStaticClass(), name);
}
/// <summary>
/// Tries to find the script of the given type in all the loaded scenes.
/// </summary>
@@ -479,6 +498,14 @@ public:
/// <returns>Found actors or empty if none.</returns>
API_FUNCTION() static Array<Actor*> FindActors(const Tag& tag, Actor* root = nullptr);
/// <summary>
/// Search actors using a parent parentTag.
/// </summary>
/// <param name="parentTag">The tag to search actors with subtags belonging to this tag</param>
/// <param name="root">The custom root actor to start searching from (hierarchical), otherwise null to search all loaded scenes.</param>
/// <returns>Returns all actors that have subtags belonging to the given parent parentTag</returns>
API_FUNCTION() static Array<Actor*> FindActorsByParentTag(const Tag& parentTag, Actor* root = nullptr);
private:
// Actor API
enum class ActorEventType

View File

@@ -127,7 +127,7 @@ public:
/// <summary>
/// Gets the character up vector.
/// </summary>
API_PROPERTY(Attributes="EditorOrder(240), DefaultValue(typeof(Vector3), \"0,1,0\"), EditorDisplay(\"Character Controller\")")
API_PROPERTY(Attributes="EditorOrder(240), DefaultValue(typeof(Vector3), \"0,1,0\"), EditorDisplay(\"Character Controller\"), Limit(-1, 1)")
Vector3 GetUpDirection() const;
/// <summary>

View File

@@ -218,6 +218,21 @@ void Physics::FlushRequests()
PhysicsBackend::FlushRequests();
}
bool Physics::LineCast(const Vector3& start, const Vector3& end, uint32 layerMask, bool hitTriggers)
{
return DefaultScene->LineCast(start, end, layerMask, hitTriggers);
}
bool Physics::LineCast(const Vector3& start, const Vector3& end, RayCastHit& hitInfo, uint32 layerMask, bool hitTriggers)
{
return DefaultScene->LineCast(start, end, hitInfo, layerMask, hitTriggers);
}
bool Physics::LineCastAll(const Vector3& start, const Vector3& end, Array<RayCastHit>& results, uint32 layerMask, bool hitTriggers)
{
return DefaultScene->LineCastAll(start, end, results, layerMask, hitTriggers);
}
bool Physics::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
{
return DefaultScene->RayCast(origin, direction, maxDistance, layerMask, hitTriggers);
@@ -461,6 +476,33 @@ void PhysicsScene::CollectResults()
_isDuringSimulation = false;
}
bool PhysicsScene::LineCast(const Vector3& start, const Vector3& end, uint32 layerMask, bool hitTriggers)
{
Vector3 directionToEnd = end - start;
const float distanceToEnd = directionToEnd.Length();
if (distanceToEnd >= ZeroTolerance)
directionToEnd /= distanceToEnd;
return PhysicsBackend::RayCast(_scene, start, directionToEnd, distanceToEnd, layerMask, hitTriggers);
}
bool PhysicsScene::LineCast(const Vector3& start, const Vector3& end, RayCastHit& hitInfo, uint32 layerMask, bool hitTriggers)
{
Vector3 directionToEnd = end - start;
const float distanceToEnd = directionToEnd.Length();
if (distanceToEnd >= ZeroTolerance)
directionToEnd /= distanceToEnd;
return PhysicsBackend::RayCast(_scene, start, directionToEnd, hitInfo, distanceToEnd, layerMask, hitTriggers);
}
bool PhysicsScene::LineCastAll(const Vector3& start, const Vector3& end, Array<RayCastHit>& results, uint32 layerMask, bool hitTriggers)
{
Vector3 directionToEnd = end - start;
const float distanceToEnd = directionToEnd.Length();
if (distanceToEnd >= ZeroTolerance)
directionToEnd /= distanceToEnd;
return PhysicsBackend::RayCastAll(_scene, start, directionToEnd, results, distanceToEnd, layerMask, hitTriggers);
}
bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
{
return PhysicsBackend::RayCast(_scene, origin, direction, maxDistance, layerMask, hitTriggers);

View File

@@ -95,6 +95,38 @@ public:
API_FUNCTION() static void FlushRequests();
public:
/// <summary>
/// Performs a line between two points in the scene.
/// </summary>
/// <param name="start">The start position of the line.</param>
/// <param name="end">The end position of the line.</param>
/// <param name="layerMask">The layer mask used to filter the results.</param>
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
/// <returns>True if ray hits an matching object, otherwise false.</returns>
API_FUNCTION() static bool LineCast(const Vector3& start, const Vector3& end, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
/// <summary>
/// Performs a line between two points in the scene.
/// </summary>
/// <param name="start">The start position of the line.</param>
/// <param name="end">The end position of the line.</param>
/// <param name="hitInfo">The result hit information. Valid only when method returns true.</param>
/// <param name="layerMask">The layer mask used to filter the results.</param>
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
/// <returns>True if ray hits an matching object, otherwise false.</returns>
API_FUNCTION() static bool LineCast(const Vector3& start, const Vector3& end, API_PARAM(Out) RayCastHit& hitInfo, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
// <summary>
/// Performs a line between two points in the scene, returns all hitpoints infos.
/// </summary>
/// <param name="start">The origin of the ray.</param>
/// <param name="end">The normalized direction of the ray.</param>
/// <param name="results">The result hits. Valid only when method returns true.</param>
/// <param name="layerMask">The layer mask used to filter the results.</param>
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
/// <returns>True if ray hits an matching object, otherwise false.</returns>
API_FUNCTION() static bool LineCastAll(const Vector3& start, const Vector3& end, API_PARAM(Out) Array<RayCastHit, HeapAllocation>& results, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
/// <summary>
/// Performs a raycast against objects in the scene.
/// </summary>

View File

@@ -133,6 +133,38 @@ public:
API_FUNCTION() void CollectResults();
public:
/// <summary>
/// Performs a line between two points in the scene.
/// </summary>
/// <param name="start">The start position of the line.</param>
/// <param name="end">The end position of the line.</param>
/// <param name="layerMask">The layer mask used to filter the results.</param>
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
/// <returns>True if ray hits an matching object, otherwise false.</returns>
API_FUNCTION() bool LineCast(const Vector3& start, const Vector3& end, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
/// <summary>
/// Performs a line between two points in the scene.
/// </summary>
/// <param name="start">The start position of the line.</param>
/// <param name="end">The end position of the line.</param>
/// <param name="hitInfo">The result hit information. Valid only when method returns true.</param>
/// <param name="layerMask">The layer mask used to filter the results.</param>
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
/// <returns>True if ray hits an matching object, otherwise false.</returns>
API_FUNCTION() bool LineCast(const Vector3& start, const Vector3& end, API_PARAM(Out) RayCastHit& hitInfo, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
// <summary>
/// Performs a line between two points in the scene, returns all hitpoints infos.
/// </summary>
/// <param name="start">The origin of the ray.</param>
/// <param name="end">The normalized direction of the ray.</param>
/// <param name="results">The result hits. Valid only when method returns true.</param>
/// <param name="layerMask">The layer mask used to filter the results.</param>
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
/// <returns>True if ray hits an matching object, otherwise false.</returns>
API_FUNCTION() bool LineCastAll(const Vector3& start, const Vector3& end, API_PARAM(Out) Array<RayCastHit, HeapAllocation>& results, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
/// <summary>
/// Performs a raycast against objects in the scene.
/// </summary>

View File

@@ -1380,7 +1380,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op
}
// Automatic LOD generation
if (options.GenerateLODs && data.LODs.HasItems() && options.TriangleReduction < 1.0f - ZeroTolerance)
if (options.GenerateLODs && options.LODCount > 1 && data.LODs.HasItems() && options.TriangleReduction < 1.0f - ZeroTolerance)
{
auto lodStartTime = DateTime::NowUTC();
meshopt_setAllocator(MeshOptAllocate, MeshOptDeallocate);

View File

@@ -169,6 +169,16 @@ namespace FlaxEngine.GUI
set => Bounds = new Rectangle(value + (_parent != null ? _parent.Bounds.Size * (_anchorMax + _anchorMin) * 0.5f : Float2.Zero) - _bounds.Size * _pivot, _bounds.Size);
}
/// <summary>
/// Whether to resize the UI Control based on where the pivot is rather than just the top-left.
/// </summary>
[NoSerialize, HideInEditor]
public bool PivotRelative
{
get => _pivotRelativeSizing;
set => _pivotRelativeSizing = value;
}
/// <summary>
/// Gets or sets width of the control.
/// </summary>
@@ -181,6 +191,11 @@ namespace FlaxEngine.GUI
if (Mathf.NearEqual(_bounds.Size.X, value))
return;
var bounds = new Rectangle(_bounds.Location, value, _bounds.Size.Y);
if (_pivotRelativeSizing)
{
var delta = _bounds.Size.X - value;
bounds.Location.X += delta * Pivot.X;
}
SetBounds(ref bounds);
}
}
@@ -197,6 +212,11 @@ namespace FlaxEngine.GUI
if (Mathf.NearEqual(_bounds.Size.Y, value))
return;
var bounds = new Rectangle(_bounds.Location, _bounds.Size.X, value);
if (_pivotRelativeSizing)
{
var delta = _bounds.Size.Y - value;
bounds.Location.Y += delta * Pivot.Y;
}
SetBounds(ref bounds);
}
}

View File

@@ -61,6 +61,7 @@ namespace FlaxEngine.GUI
private bool _isVisible = true;
private bool _isEnabled = true;
private bool _autoFocus = true;
private bool _pivotRelativeSizing = false;
private List<int> _touchOvers;
private RootControl.UpdateDelegate _tooltipUpdate;