Merge remote-tracking branch 'origin/master' into 1.6
This commit is contained in:
@@ -408,6 +408,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
private Type _cachedType;
|
||||
private bool _anchorDropDownClosed = true;
|
||||
private Button _pivotRelativeButton;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -484,13 +485,54 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
horDown.CustomControl.Height = TextBoxBase.DefaultHeight;
|
||||
|
||||
GetAnchorEquality(out _cachedXEq, out _cachedYEq, valueTypes);
|
||||
|
||||
BuildLocationSizeOffsets(horUp, horDown, _cachedXEq, _cachedYEq, valueTypes);
|
||||
BuildExtraButtons(group);
|
||||
|
||||
main.Space(10);
|
||||
BuildAnchorsDropper(main, valueTypes);
|
||||
}
|
||||
|
||||
private void BuildExtraButtons(VerticalPanelElement group)
|
||||
{
|
||||
var control = (Control)Values[0];
|
||||
var pivotRelative = Editor.Instance.Windows.PropertiesWin.UIPivotRelative;
|
||||
control.PivotRelative = pivotRelative;
|
||||
|
||||
var panel = group.CustomContainer<Panel>();
|
||||
panel.CustomControl.Height = TextBoxBase.DefaultHeight;
|
||||
panel.CustomControl.ClipChildren = false;
|
||||
panel.CustomControl.Parent = group.ContainerControl;
|
||||
|
||||
_pivotRelativeButton = new Button
|
||||
{
|
||||
TooltipText = "Toggles UI control resizing based on where the pivot is rather than just the top-left.",
|
||||
Size = new Float2(18),
|
||||
Parent = panel.ContainerControl,
|
||||
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Scale32),
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
X = 77,
|
||||
};
|
||||
|
||||
SetStyle(pivotRelative);
|
||||
_pivotRelativeButton.Clicked += PivotRelativeClicked;
|
||||
}
|
||||
|
||||
private void PivotRelativeClicked()
|
||||
{
|
||||
var control = (Control)Values[0];
|
||||
var pivotRelative = control.PivotRelative;
|
||||
control.PivotRelative = !pivotRelative;
|
||||
Editor.Instance.Windows.PropertiesWin.UIPivotRelative = !pivotRelative;
|
||||
SetStyle(control.PivotRelative);
|
||||
}
|
||||
|
||||
private void SetStyle(bool current)
|
||||
{
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
var backgroundColor = current ? style.Foreground : style.ForegroundDisabled;
|
||||
_pivotRelativeButton.SetColors(backgroundColor);
|
||||
}
|
||||
|
||||
private void BuildAnchorsDropper(LayoutElementsContainer main, ScriptType[] valueTypes)
|
||||
{
|
||||
ScriptMemberInfo minInfo = valueTypes[0].GetProperty("AnchorMin");
|
||||
|
||||
@@ -97,6 +97,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
AnchorPreset = AnchorPresets.TopLeft,
|
||||
};
|
||||
_linkButton.Clicked += ToggleLink;
|
||||
ToggleEnabled();
|
||||
SetLinkStyle();
|
||||
var x = LinkedLabel.Text.Value.Length * 7 + 5;
|
||||
_linkButton.LocalX += x;
|
||||
@@ -128,9 +129,38 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
LinkValues = !LinkValues;
|
||||
Editor.Instance.Windows.PropertiesWin.ScaleLinked = LinkValues;
|
||||
ToggleEnabled();
|
||||
SetLinkStyle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles enables on value boxes.
|
||||
/// </summary>
|
||||
public void ToggleEnabled()
|
||||
{
|
||||
if (LinkValues)
|
||||
{
|
||||
if (Mathf.NearEqual(((Float3)Values[0]).X, 0))
|
||||
{
|
||||
XElement.ValueBox.Enabled = false;
|
||||
}
|
||||
if (Mathf.NearEqual(((Float3)Values[0]).Y, 0))
|
||||
{
|
||||
YElement.ValueBox.Enabled = false;
|
||||
}
|
||||
if (Mathf.NearEqual(((Float3)Values[0]).Z, 0))
|
||||
{
|
||||
ZElement.ValueBox.Enabled = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XElement.ValueBox.Enabled = true;
|
||||
YElement.ValueBox.Enabled = true;
|
||||
ZElement.ValueBox.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetLinkStyle()
|
||||
{
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
|
||||
@@ -129,25 +129,39 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
if (LinkValues)
|
||||
{
|
||||
var valueChange = 0.0f;
|
||||
var valueRatio = 0.0f;
|
||||
switch (_valueChanged)
|
||||
{
|
||||
case ValueChanged.X:
|
||||
valueChange = xValue - ((Float3)Values[0]).X;
|
||||
yValue += valueChange;
|
||||
zValue += valueChange;
|
||||
valueRatio = GetRatio(xValue, ((Float3)Values[0]).X);
|
||||
if (Mathf.NearEqual(valueRatio, 0))
|
||||
{
|
||||
XElement.ValueBox.Enabled = false;
|
||||
valueRatio = 1;
|
||||
}
|
||||
yValue = NewLinkedValue(yValue, valueRatio);
|
||||
zValue = NewLinkedValue(zValue, valueRatio);
|
||||
break;
|
||||
case ValueChanged.Y:
|
||||
valueChange = yValue - ((Float3)Values[0]).Y;
|
||||
xValue += valueChange;
|
||||
zValue += valueChange;
|
||||
valueRatio = GetRatio(yValue, ((Float3)Values[0]).Y);
|
||||
if (Mathf.NearEqual(valueRatio, 0))
|
||||
{
|
||||
YElement.ValueBox.Enabled = false;
|
||||
valueRatio = 1;
|
||||
}
|
||||
xValue = NewLinkedValue(xValue, valueRatio);
|
||||
zValue = NewLinkedValue(zValue, valueRatio);
|
||||
break;
|
||||
case ValueChanged.Z:
|
||||
valueChange = zValue - ((Float3)Values[0]).Z;
|
||||
xValue += valueChange;
|
||||
yValue += valueChange;
|
||||
valueRatio = GetRatio(zValue, ((Float3)Values[0]).Z);
|
||||
if (Mathf.NearEqual(valueRatio, 0))
|
||||
{
|
||||
ZElement.ValueBox.Enabled = false;
|
||||
valueRatio = 1;
|
||||
}
|
||||
xValue = NewLinkedValue(xValue, valueRatio);
|
||||
yValue = NewLinkedValue(yValue, valueRatio);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +178,16 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
SetValue(v, token);
|
||||
}
|
||||
|
||||
private float GetRatio(float value, float initialValue)
|
||||
{
|
||||
return Mathf.NearEqual(initialValue, 0) ? 0 : value / initialValue;
|
||||
}
|
||||
|
||||
private float NewLinkedValue(float value, float valueRatio)
|
||||
{
|
||||
return Mathf.NearEqual(value, 0) ? value : value * valueRatio;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace FlaxEditor.Gizmo
|
||||
: base(owner)
|
||||
{
|
||||
InitDrawing();
|
||||
ModeChanged += ResetTranslationScale;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -326,6 +327,11 @@ namespace FlaxEditor.Gizmo
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetTranslationScale()
|
||||
{
|
||||
_translationScaleSnapDelta.Normalize();
|
||||
}
|
||||
|
||||
private void UpdateRotate(float dt)
|
||||
{
|
||||
float mouseDelta = _activeAxis == Axis.Y ? -Owner.MouseDelta.X : Owner.MouseDelta.X;
|
||||
|
||||
@@ -146,7 +146,18 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
Time = newTime,
|
||||
Value = actor.GetSplineLocalTransform(Index),
|
||||
};
|
||||
|
||||
var oldkeyframe = actor.GetSplineKeyframe(Index);
|
||||
var newKeyframe = new BezierCurve<Transform>.Keyframe();
|
||||
|
||||
// copy old curve point data to new curve point
|
||||
newKeyframe.Value = oldkeyframe.Value;
|
||||
newKeyframe.TangentIn = oldkeyframe.TangentIn;
|
||||
newKeyframe.TangentOut = oldkeyframe.TangentOut;
|
||||
|
||||
actor.InsertSplineLocalPoint(newIndex, newTime, action.Value);
|
||||
actor.SetSplineKeyframe(newIndex, newKeyframe);
|
||||
|
||||
undoAction = action;
|
||||
var splineNode = (SplineNode)SceneGraphFactory.FindNode(action.SplineId);
|
||||
splineNode.OnUpdate();
|
||||
@@ -317,6 +328,20 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
var spline = (Spline)Actor;
|
||||
spline.AddSplineLocalPoint(Vector3.Zero, false);
|
||||
spline.AddSplineLocalPoint(new Vector3(0, 0, 100.0f));
|
||||
|
||||
spline.SetSplineKeyframe(0, new BezierCurve<Transform>.Keyframe()
|
||||
{
|
||||
Value = new Transform(Vector3.Zero, Quaternion.Identity, Vector3.One),
|
||||
TangentIn = new Transform(Vector3.Backward * 100, Quaternion.Identity, Vector3.One),
|
||||
TangentOut = new Transform(Vector3.Forward * 100, Quaternion.Identity, Vector3.One),
|
||||
});
|
||||
|
||||
spline.SetSplineKeyframe(1, new BezierCurve<Transform>.Keyframe()
|
||||
{
|
||||
Value = new Transform(Vector3.Forward * 100, Quaternion.Identity, Vector3.One),
|
||||
TangentIn = new Transform(Vector3.Backward * 100, Quaternion.Identity, Vector3.One),
|
||||
TangentOut = new Transform(Vector3.Forward * 100, Quaternion.Identity, Vector3.One),
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -30,6 +30,11 @@ namespace FlaxEditor.Windows
|
||||
/// </summary>
|
||||
public bool ScaleLinked = false;
|
||||
|
||||
/// <summary>
|
||||
/// Indication of if UI elements should size relative to the pivot point.
|
||||
/// </summary>
|
||||
public bool UIPivotRelative = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PropertiesWindow"/> class.
|
||||
/// </summary>
|
||||
@@ -66,13 +71,16 @@ namespace FlaxEditor.Windows
|
||||
public override void OnLayoutSerialize(XmlWriter writer)
|
||||
{
|
||||
writer.WriteAttributeString("ScaleLinked", ScaleLinked.ToString());
|
||||
writer.WriteAttributeString("UIPivotRelative", UIPivotRelative.ToString());
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLayoutDeserialize(XmlElement node)
|
||||
{
|
||||
if (bool.TryParse(node.GetAttribute("ScaleLinked"), out bool value1))
|
||||
ScaleLinked = value1;
|
||||
if (bool.TryParse(node.GetAttribute("UIPivotRelative"), out value1))
|
||||
UIPivotRelative = value1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user