diff --git a/Source/Editor/Content/Proxy/PrefabProxy.cs b/Source/Editor/Content/Proxy/PrefabProxy.cs
index 39d77f25c..276bc0d30 100644
--- a/Source/Editor/Content/Proxy/PrefabProxy.cs
+++ b/Source/Editor/Content/Proxy/PrefabProxy.cs
@@ -162,8 +162,7 @@ namespace FlaxEditor.Content
// Auto fit actor to camera
float targetSize = 30.0f;
- BoundingBox bounds;
- Editor.GetActorEditorBox(_preview.Instance, out bounds);
+ Editor.GetActorEditorBox(_preview.Instance, out var bounds);
float maxSize = Mathf.Max(0.001f, bounds.Size.MaxValue);
_preview.Instance.Scale = new Vector3(targetSize / maxSize);
_preview.Instance.Position = Vector3.Zero;
@@ -175,6 +174,7 @@ namespace FlaxEditor.Content
///
public override void OnThumbnailDrawEnd(ThumbnailRequest request, ContainerControl guiRoot)
{
+ _preview.RemoveChildren();
_preview.Prefab = null;
_preview.Parent = null;
}
diff --git a/Source/Editor/Content/Tree/ContentTreeNode.cs b/Source/Editor/Content/Tree/ContentTreeNode.cs
index 7df407e08..4370bc8e7 100644
--- a/Source/Editor/Content/Tree/ContentTreeNode.cs
+++ b/Source/Editor/Content/Tree/ContentTreeNode.cs
@@ -295,7 +295,8 @@ namespace FlaxEditor.Content
StartRenaming();
return true;
case KeyboardKeys.Delete:
- Editor.Instance.Windows.ContentWin.Delete(Folder);
+ if (Folder.Exists)
+ Editor.Instance.Windows.ContentWin.Delete(Folder);
return true;
}
if (RootWindow.GetKey(KeyboardKeys.Control))
@@ -303,7 +304,8 @@ namespace FlaxEditor.Content
switch (key)
{
case KeyboardKeys.D:
- Editor.Instance.Windows.ContentWin.Duplicate(Folder);
+ if (Folder.Exists)
+ Editor.Instance.Windows.ContentWin.Duplicate(Folder);
return true;
}
}
diff --git a/Source/Editor/CustomEditors/CustomEditorsUtil.cs b/Source/Editor/CustomEditors/CustomEditorsUtil.cs
index 2f97da333..9b83dd820 100644
--- a/Source/Editor/CustomEditors/CustomEditorsUtil.cs
+++ b/Source/Editor/CustomEditors/CustomEditorsUtil.cs
@@ -71,7 +71,7 @@ namespace FlaxEditor.CustomEditors
// Space before word starting with uppercase letter
if (char.IsUpper(c) && i > 0)
{
- if (i + 2 < length && !char.IsUpper(name[i + 1]) && !char.IsUpper(name[i + 2]))
+ if (i + 1 < length && !char.IsUpper(name[i + 1]))
sb.Append(' ');
}
// Space instead of underscore
diff --git a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs
index 44a273ee4..6c825f46d 100644
--- a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs
+++ b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs
@@ -76,7 +76,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
upperRightCell.AddChild(new Label
{
Height = labelsHeight,
- Text = layerNames[layerIndex],
+ Text = layerNames[layerNames.Length - layerIndex - 1],
HorizontalAlignment = TextAlignment.Near,
});
bottomLeftCell.AddChild(new Label
diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs
index 59810043d..f81f81ddd 100644
--- a/Source/Editor/Editor.cs
+++ b/Source/Editor/Editor.cs
@@ -254,7 +254,7 @@ namespace FlaxEditor
if (loadingPreview != null)
{
// Link it to the prefab preview to see it in the editor
- loadingPreview.customControlLinked = control.Control;
+ loadingPreview.customControlLinked = control;
return loadingPreview;
}
return null;
diff --git a/Source/Editor/GUI/AssetPicker.cs b/Source/Editor/GUI/AssetPicker.cs
index 63c1276ab..db012ab1e 100644
--- a/Source/Editor/GUI/AssetPicker.cs
+++ b/Source/Editor/GUI/AssetPicker.cs
@@ -355,12 +355,10 @@ namespace FlaxEditor.GUI
_mousePos = location;
// Check if start drag drop
- if (_isMouseDown && Vector2.Distance(location, _mouseDownPos) > 10.0f)
+ if (_isMouseDown && Vector2.Distance(location, _mouseDownPos) > 10.0f && IconRect.Contains(_mouseDownPos))
{
- // Clear flag
- _isMouseDown = false;
-
// Do the drag
+ _isMouseDown = false;
DoDrag();
}
@@ -370,35 +368,35 @@ namespace FlaxEditor.GUI
///
public override bool OnMouseUp(Vector2 location, MouseButton button)
{
- if (button == MouseButton.Left)
+ if (button == MouseButton.Left && _isMouseDown)
{
_isMouseDown = false;
- }
- // Buttons logic
- if (Button1Rect.Contains(location))
- {
- // Show asset picker popup
- Focus();
- AssetSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, assetItem =>
+ // Buttons logic
+ if (Button1Rect.Contains(location))
{
- SelectedItem = assetItem;
- RootWindow.Focus();
+ // Show asset picker popup
Focus();
- });
- }
- else if (_selected != null || _selectedItem != null)
- {
- if (Button2Rect.Contains(location) && _selectedItem != null)
- {
- // Select asset
- Editor.Instance.Windows.ContentWin.Select(_selectedItem);
+ AssetSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, assetItem =>
+ {
+ SelectedItem = assetItem;
+ RootWindow.Focus();
+ Focus();
+ });
}
- else if (Button3Rect.Contains(location))
+ else if (_selected != null || _selectedItem != null)
{
- // Deselect asset
- Focus();
- SelectedItem = null;
+ if (Button2Rect.Contains(location) && _selectedItem != null)
+ {
+ // Select asset
+ Editor.Instance.Windows.ContentWin.Select(_selectedItem);
+ }
+ else if (Button3Rect.Contains(location))
+ {
+ // Deselect asset
+ Focus();
+ SelectedItem = null;
+ }
}
}
@@ -409,8 +407,7 @@ namespace FlaxEditor.GUI
///
public override bool OnMouseDown(Vector2 location, MouseButton button)
{
- // Set flag for dragging asset
- if (button == MouseButton.Left && IconRect.Contains(location))
+ if (button == MouseButton.Left)
{
_isMouseDown = true;
_mouseDownPos = location;
diff --git a/Source/Editor/GUI/Docking/DockWindow.cs b/Source/Editor/GUI/Docking/DockWindow.cs
index aa6d94ca8..56c78efed 100644
--- a/Source/Editor/GUI/Docking/DockWindow.cs
+++ b/Source/Editor/GUI/Docking/DockWindow.cs
@@ -307,6 +307,14 @@ namespace FlaxEditor.GUI.Docking
_dockedTo?.SelectTab(this, autoFocus);
}
+ ///
+ /// Brings the window to the front of the Z order.
+ ///
+ public void BringToFront()
+ {
+ _dockedTo?.RootWindow?.BringToFront();
+ }
+
internal void OnUnlinkInternal()
{
OnUnlink();
@@ -412,6 +420,7 @@ namespace FlaxEditor.GUI.Docking
base.Focus();
SelectTab();
+ BringToFront();
}
///
diff --git a/Source/Editor/GUI/Input/ValueBox.cs b/Source/Editor/GUI/Input/ValueBox.cs
index 8ee1c3887..d34acd17b 100644
--- a/Source/Editor/GUI/Input/ValueBox.cs
+++ b/Source/Editor/GUI/Input/ValueBox.cs
@@ -49,6 +49,11 @@ namespace FlaxEditor.GUI.Input
///
protected T _startSlideValue;
+ ///
+ /// The text cached on editing start. Used to compare with the end result to detect changes.
+ ///
+ protected string _startEditText;
+
private Vector2 _startSlideLocation;
///
@@ -257,11 +262,23 @@ namespace FlaxEditor.GUI.Input
return base.OnMouseUp(location, button);
}
+ ///
+ protected override void OnEditBegin()
+ {
+ base.OnEditBegin();
+
+ _startEditText = _text;
+ }
+
///
protected override void OnEditEnd()
{
- // Update value
- TryGetValue();
+ if (_startEditText != _text)
+ {
+ // Update value
+ TryGetValue();
+ }
+ _startEditText = null;
base.OnEditEnd();
}
diff --git a/Source/Editor/GUI/Timeline/Track.cs b/Source/Editor/GUI/Timeline/Track.cs
index 4f5278251..6ba8191d6 100644
--- a/Source/Editor/GUI/Timeline/Track.cs
+++ b/Source/Editor/GUI/Timeline/Track.cs
@@ -16,6 +16,7 @@ namespace FlaxEditor.GUI.Timeline
/// The Timeline track that contains a header and custom timeline events/media.
///
///
+ [HideInEditor]
public class Track : ContainerControl
{
///
diff --git a/Source/Editor/GUI/Tree/TreeNode.cs b/Source/Editor/GUI/Tree/TreeNode.cs
index 727da3edd..f7e5f115a 100644
--- a/Source/Editor/GUI/Tree/TreeNode.cs
+++ b/Source/Editor/GUI/Tree/TreeNode.cs
@@ -21,7 +21,7 @@ namespace FlaxEditor.GUI.Tree
///
/// The default node offset on Y axis.
///
- public const float DefaultNodeOffsetY = 1;
+ public const float DefaultNodeOffsetY = 0;
private Tree _tree;
@@ -539,7 +539,7 @@ namespace FlaxEditor.GUI.Tree
{
if (new Rectangle(_headerRect.X, _headerRect.Y - DefaultDragInsertPositionMargin - DefaultNodeOffsetY, _headerRect.Width, DefaultDragInsertPositionMargin * 2.0f).Contains(location))
_dragOverMode = DragItemPositioning.Above;
- else if (IsCollapsed && new Rectangle(_headerRect.X, _headerRect.Bottom - DefaultDragInsertPositionMargin, _headerRect.Width, DefaultDragInsertPositionMargin * 2.0f).Contains(location))
+ else if ((IsCollapsed || !HasAnyVisibleChild) && new Rectangle(_headerRect.X, _headerRect.Bottom - DefaultDragInsertPositionMargin, _headerRect.Width, DefaultDragInsertPositionMargin * 2.0f).Contains(location))
_dragOverMode = DragItemPositioning.Below;
else
_dragOverMode = DragItemPositioning.At;
diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs
index 93dbeddaa..014143685 100644
--- a/Source/Editor/Gizmo/TransformGizmoBase.cs
+++ b/Source/Editor/Gizmo/TransformGizmoBase.cs
@@ -196,12 +196,10 @@ namespace FlaxEditor.Gizmo
private void UpdateTranslateScale()
{
bool isScaling = _activeMode == Mode.Scale;
-
Vector3 delta = Vector3.Zero;
Ray ray = Owner.MouseRay;
- Matrix invRotationMatrix;
- Matrix.Invert(ref _rotationMatrix, out invRotationMatrix);
+ Matrix.Invert(ref _rotationMatrix, out var invRotationMatrix);
ray.Position = Vector3.Transform(ray.Position, invRotationMatrix);
Vector3.TransformNormal(ref ray.Direction, ref invRotationMatrix, out ray.Direction);
@@ -211,9 +209,7 @@ namespace FlaxEditor.Gizmo
case Axis.X:
{
var plane = new Plane(Vector3.Backward, Vector3.Transform(Position, invRotationMatrix).Z);
-
- float intersection;
- if (ray.Intersects(ref plane, out intersection))
+ if (ray.Intersects(ref plane, out float intersection))
{
_intersectPosition = ray.Position + ray.Direction * intersection;
if (_lastIntersectionPosition != Vector3.Zero)
@@ -222,18 +218,14 @@ namespace FlaxEditor.Gizmo
? new Vector3(_tDelta.X, 0, 0)
: new Vector3(_tDelta.X, _tDelta.Y, 0);
}
-
break;
}
-
case Axis.Z:
case Axis.YZ:
case Axis.Y:
{
var plane = new Plane(Vector3.Left, Vector3.Transform(Position, invRotationMatrix).X);
-
- float intersection;
- if (ray.Intersects(ref plane, out intersection))
+ if (ray.Intersects(ref plane, out float intersection))
{
_intersectPosition = ray.Position + ray.Direction * intersection;
if (_lastIntersectionPosition != Vector3.Zero)
@@ -251,41 +243,31 @@ namespace FlaxEditor.Gizmo
break;
}
}
-
break;
}
-
case Axis.ZX:
{
var plane = new Plane(Vector3.Down, Vector3.Transform(Position, invRotationMatrix).Y);
-
- float intersection;
- if (ray.Intersects(ref plane, out intersection))
+ if (ray.Intersects(ref plane, out float intersection))
{
_intersectPosition = ray.Position + ray.Direction * intersection;
if (_lastIntersectionPosition != Vector3.Zero)
_tDelta = _intersectPosition - _lastIntersectionPosition;
delta = new Vector3(_tDelta.X, 0, _tDelta.Z);
}
-
break;
}
-
case Axis.Center:
{
- Vector3 gizmoToView = Position - Owner.ViewPosition;
+ var gizmoToView = Position - Owner.ViewPosition;
var plane = new Plane(-Vector3.Normalize(gizmoToView), gizmoToView.Length);
-
- float intersection;
- if (ray.Intersects(ref plane, out intersection))
+ if (ray.Intersects(ref plane, out float intersection))
{
_intersectPosition = ray.Position + ray.Direction * intersection;
if (_lastIntersectionPosition != Vector3.Zero)
_tDelta = _intersectPosition - _lastIntersectionPosition;
}
-
delta = _tDelta;
-
break;
}
}
@@ -299,14 +281,11 @@ namespace FlaxEditor.Gizmo
if ((isScaling ? ScaleSnapEnabled : TranslationSnapEnable) || Owner.UseSnapping)
{
float snapValue = isScaling ? ScaleSnapValue : TranslationSnapValue;
-
_translationScaleSnapDelta += delta;
-
delta = new Vector3(
(int)(_translationScaleSnapDelta.X / snapValue) * snapValue,
(int)(_translationScaleSnapDelta.Y / snapValue) * snapValue,
(int)(_translationScaleSnapDelta.Z / snapValue) * snapValue);
-
_translationScaleSnapDelta -= delta;
}
@@ -318,7 +297,30 @@ namespace FlaxEditor.Gizmo
}
else if (_activeMode == Mode.Scale)
{
- // Apply scale
+ // Scale
+ if (_activeTransformSpace == TransformSpace.World && _activeAxis != Axis.Center)
+ {
+ var deltaLocal = delta;
+ Quaternion orientation = GetSelectedObject(0).Orientation;
+ delta = Vector3.Transform(delta, orientation);
+
+ // Fix axis sign of delta movement for rotated object in some cases (eg. rotated object by 90 deg on Y axis and scale in world space with Red/X axis)
+ switch (_activeAxis)
+ {
+ case Axis.X:
+ if (deltaLocal.X < 0)
+ delta *= -1;
+ break;
+ case Axis.Y:
+ if (deltaLocal.Y < 0)
+ delta *= -1;
+ break;
+ case Axis.Z:
+ if (deltaLocal.Z < 0)
+ delta *= -1;
+ break;
+ }
+ }
_scaleDelta = delta;
}
}
@@ -382,7 +384,7 @@ namespace FlaxEditor.Gizmo
// Snap to ground
if (_activeAxis == Axis.None && SelectionCount != 0 && Owner.SnapToGround)
{
- if (Physics.RayCast(Position, Vector3.Down, out var hit, float.MaxValue, int.MaxValue, false))
+ if (Physics.RayCast(Position, Vector3.Down, out var hit, float.MaxValue, uint.MaxValue, false))
{
StartTransforming();
var translationDelta = hit.Point - Position;
@@ -408,7 +410,6 @@ namespace FlaxEditor.Gizmo
case Mode.Translate:
UpdateTranslateScale();
break;
-
case Mode.Rotate:
UpdateRotate(dt);
break;
@@ -437,7 +438,7 @@ namespace FlaxEditor.Gizmo
translationDelta = _translationDelta;
_translationDelta = Vector3.Zero;
- // Prevent from moving objects too far away, like to different galaxy or sth
+ // Prevent from moving objects too far away, like to a different galaxy or sth
Vector3 prevMoveDelta = _accMoveDelta;
_accMoveDelta += _translationDelta;
if (_accMoveDelta.Length > Owner.ViewFarPlane * 0.7f)
diff --git a/Source/Editor/Surface/Archetypes/Material.cs b/Source/Editor/Surface/Archetypes/Material.cs
index 9edbedcfb..4d65c760c 100644
--- a/Source/Editor/Surface/Archetypes/Material.cs
+++ b/Source/Editor/Surface/Archetypes/Material.cs
@@ -726,7 +726,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 30,
Title = "DDX",
- Description = "Returns the partial derivative of the specified value with respect to the screen-space x-coordinate.",
+ Description = "Returns the partial derivative of the specified value with respect to the screen-space x-coordinate",
Flags = NodeFlags.MaterialGraph,
Size = new Vector2(90, 25),
ConnectionsHints = ConnectionsHint.Numeric,
@@ -742,7 +742,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 31,
Title = "DDY",
- Description = "Returns the partial derivative of the specified value with respect to the screen-space y-coordinate.",
+ Description = "Returns the partial derivative of the specified value with respect to the screen-space y-coordinate",
Flags = NodeFlags.MaterialGraph,
Size = new Vector2(90, 25),
ConnectionsHints = ConnectionsHint.Numeric,
@@ -754,6 +754,68 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Output(0, string.Empty, null, 1),
}
},
+ new NodeArchetype
+ {
+ TypeID = 32,
+ Title = "Sign",
+ Description = "Returns -1 if value is less than zero; 0 if value equals zero; and 1 if value is greater than zero",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(90, 25),
+ ConnectionsHints = ConnectionsHint.Numeric,
+ IndependentBoxes = new[] { 0 },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 1),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 33,
+ Title = "Any",
+ Description = "True if any components of value are non-zero; otherwise, false",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(90, 25),
+ ConnectionsHints = ConnectionsHint.Numeric,
+ IndependentBoxes = new[] { 0 },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(bool), 1),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 34,
+ Title = "All",
+ Description = "Determines if all components of the specified value are non-zero",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(90, 25),
+ ConnectionsHints = ConnectionsHint.Numeric,
+ IndependentBoxes = new[] { 0 },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(bool), 1),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 35,
+ Title = "Black Body",
+ Description = "Simulates black body radiation via a given temperature in kelvin",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(120, 25),
+ DefaultValues = new object[]
+ {
+ 0.0f,
+ },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Temp", true, typeof(float), 0, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Vector3), 1),
+ }
+ },
};
}
}
diff --git a/Source/Editor/Tools/Foliage/FoliageTools.cpp b/Source/Editor/Tools/Foliage/FoliageTools.cpp
index a0cbf8e14..3354be0b3 100644
--- a/Source/Editor/Tools/Foliage/FoliageTools.cpp
+++ b/Source/Editor/Tools/Foliage/FoliageTools.cpp
@@ -67,7 +67,7 @@ struct GeometryLookup
static bool Search(Actor* actor, GeometryLookup& lookup)
{
// Early out if object is not intersecting with the foliage brush bounds
- if (!actor->GetBox().Intersects(lookup.Brush))
+ if (!actor->GetIsActive() || !actor->GetBox().Intersects(lookup.Brush))
return true;
const auto brush = lookup.Brush;
diff --git a/Source/Editor/Utilities/EditorUtilities.cpp b/Source/Editor/Utilities/EditorUtilities.cpp
index 451fc09a0..aaa0ed34c 100644
--- a/Source/Editor/Utilities/EditorUtilities.cpp
+++ b/Source/Editor/Utilities/EditorUtilities.cpp
@@ -745,6 +745,59 @@ bool EditorUtilities::GenerateCertificate(const String& name, const String& outp
return false;
}
+bool EditorUtilities::IsInvalidPathChar(Char c)
+{
+ char illegalChars[] =
+ {
+ '?',
+ '\\',
+ '/',
+ '\"',
+ '<',
+ '>',
+ '|',
+ ':',
+ '*',
+ '\u0001',
+ '\u0002',
+ '\u0003',
+ '\u0004',
+ '\u0005',
+ '\u0006',
+ '\a',
+ '\b',
+ '\t',
+ '\n',
+ '\v',
+ '\f',
+ '\r',
+ '\u000E',
+ '\u000F',
+ '\u0010',
+ '\u0011',
+ '\u0012',
+ '\u0013',
+ '\u0014',
+ '\u0015',
+ '\u0016',
+ '\u0017',
+ '\u0018',
+ '\u0019',
+ '\u001A',
+ '\u001B',
+ '\u001C',
+ '\u001D',
+ '\u001E',
+ '\u001F'
+ };
+ for (auto i : illegalChars)
+ {
+ if (c == i)
+ return true;
+ }
+ return false;
+}
+
bool EditorUtilities::ReplaceInFiles(const String& folderPath, const Char* searchPattern, DirectorySearchOption searchOption, const String& findWhat, const String& replaceWith)
{
Array files;
diff --git a/Source/Editor/Utilities/EditorUtilities.h b/Source/Editor/Utilities/EditorUtilities.h
index 236d10e6f..a5f129c1b 100644
--- a/Source/Editor/Utilities/EditorUtilities.h
+++ b/Source/Editor/Utilities/EditorUtilities.h
@@ -42,6 +42,13 @@ public:
public:
+ ///
+ /// Determines whether the specified path character is invalid.
+ ///
+ /// The path character.
+ /// true if the given character cannot be used as a path because it is illegal character; otherwise, false.
+ static bool IsInvalidPathChar(Char c);
+
///
/// Replaces the given text with other one in the files.
///
diff --git a/Source/Editor/Utilities/ShuntingYardParser.cs b/Source/Editor/Utilities/ShuntingYardParser.cs
index 100c5c3d7..a07026d1c 100644
--- a/Source/Editor/Utilities/ShuntingYardParser.cs
+++ b/Source/Editor/Utilities/ShuntingYardParser.cs
@@ -193,6 +193,7 @@ namespace FlaxEditor.Utilities
{
case 'x':
case 'X':
+ {
// Hexadecimal value
i++;
token.Clear();
@@ -200,22 +201,35 @@ namespace FlaxEditor.Utilities
throw new ParsingException("invalid hexadecimal number");
while (i + 1 < text.Length && StringUtils.IsHexDigit(text[i + 1]))
{
- i++;
- token.Append(text[i]);
+ token.Append(text[++i]);
}
var value = ulong.Parse(token.ToString(), NumberStyles.HexNumber);
token.Clear();
token.Append(value.ToString());
break;
+ }
default:
+ {
// Decimal value
while (i + 1 < text.Length && DetermineType(text[i + 1]) == TokenType.Number)
{
- i++;
- token.Append(text[i]);
+ token.Append(text[++i]);
+ }
+
+ // Exponential notation
+ if (i + 2 < text.Length && (text[i + 1] == 'e' || text[i + 1] == 'E'))
+ {
+ token.Append(text[++i]);
+ if (text[i + 1] == '-' || text[i + 1] == '+')
+ token.Append(text[++i]);
+ while (i + 1 < text.Length && DetermineType(text[i + 1]) == TokenType.Number)
+ {
+ token.Append(text[++i]);
+ }
}
break;
}
+ }
}
// Discard solo '-'
diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs
index 9a5a3079a..6de74e6ea 100644
--- a/Source/Editor/Utilities/Utils.cs
+++ b/Source/Editor/Utilities/Utils.cs
@@ -533,6 +533,8 @@ namespace FlaxEditor.Utilities
break;
case VariantType.Enum:
case VariantType.Structure:
+ case VariantType.ManagedObject:
+ case VariantType.Typename:
stream.Write(int.MaxValue);
stream.WriteStrAnsi(type.FullName, 77);
break;
@@ -762,7 +764,7 @@ namespace FlaxEditor.Utilities
data[i] = (byte)(c ^ 77);
}
var typeName = System.Text.Encoding.ASCII.GetString(data);
- return TypeUtils.GetType(typeName).Type;
+ return TypeUtils.GetManagedType(typeName);
}
if (typeNameLength > 0)
{
@@ -774,7 +776,7 @@ namespace FlaxEditor.Utilities
data[i] = (char)(c ^ 77);
}
var typeName = new string(data);
- return TypeUtils.GetType(typeName).Type;
+ return TypeUtils.GetManagedType(typeName);
}
switch (variantType)
{
@@ -827,7 +829,7 @@ namespace FlaxEditor.Utilities
data[i] = (byte)(c ^ 77);
}
var typeName = System.Text.Encoding.ASCII.GetString(data);
- type = TypeUtils.GetType(typeName).Type;
+ type = TypeUtils.GetManagedType(typeName);
}
else if (typeNameLength > 0)
{
@@ -839,7 +841,7 @@ namespace FlaxEditor.Utilities
data[i] = (char)(c ^ 77);
}
var typeName = new string(data);
- type = TypeUtils.GetType(typeName).Type;
+ type = TypeUtils.GetManagedType(typeName);
}
switch (variantType)
{
diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs
index b5a19b1ec..1276fc56d 100644
--- a/Source/Editor/Viewport/PrefabWindowViewport.cs
+++ b/Source/Editor/Viewport/PrefabWindowViewport.cs
@@ -485,6 +485,23 @@ namespace FlaxEditor.Viewport
}
}
+ ///
+ public override void Draw()
+ {
+ base.Draw();
+
+ // Selected UI controls outline
+ for (var i = 0; i < _window.Selection.Count; i++)
+ {
+ if (_window.Selection[i].EditableObject is UIControl controlActor && controlActor.Control != null)
+ {
+ var control = controlActor.Control;
+ var bounds = Rectangle.FromPoints(control.PointToParent(this, Vector2.Zero), control.PointToParent(this, control.Size));
+ Render2D.DrawRectangle(bounds, Editor.Instance.Options.Options.Visual.SelectionOutlineColor0, Editor.Instance.Options.Options.Visual.UISelectionOutlineSize);
+ }
+ }
+ }
+
///
protected override void OnLeftMouseButtonUp()
{
diff --git a/Source/Editor/Viewport/Previews/PrefabPreview.cs b/Source/Editor/Viewport/Previews/PrefabPreview.cs
index d0ed8a0c2..066e98456 100644
--- a/Source/Editor/Viewport/Previews/PrefabPreview.cs
+++ b/Source/Editor/Viewport/Previews/PrefabPreview.cs
@@ -1,7 +1,6 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using FlaxEngine;
-using FlaxEngine.GUI;
using Object = FlaxEngine.Object;
namespace FlaxEditor.Viewport.Previews
@@ -19,7 +18,7 @@ namespace FlaxEditor.Viewport.Previews
private Prefab _prefab;
private Actor _instance;
- internal Control customControlLinked;
+ internal UIControl customControlLinked;
///
/// Gets or sets the prefab asset to preview.
@@ -29,39 +28,37 @@ namespace FlaxEditor.Viewport.Previews
get => _prefab;
set
{
- if (_prefab != value)
+ if (_prefab == value)
+ return;
+
+ // Unset and cleanup spawned instance
+ if (_instance)
{
- if (_instance)
+ var instance = _instance;
+ Instance = null;
+ Object.Destroy(instance);
+ }
+
+ _prefab = value;
+
+ if (_prefab)
+ {
+ // Load prefab
+ _prefab.WaitForLoaded();
+
+ // Spawn prefab
+ var prevPreview = LoadingPreview;
+ LoadingPreview = this;
+ var instance = PrefabManager.SpawnPrefab(_prefab, null);
+ LoadingPreview = prevPreview;
+ if (instance == null)
{
- if (customControlLinked != null)
- {
- customControlLinked.Parent = null;
- customControlLinked = null;
- }
- Task.RemoveCustomActor(_instance);
- Object.Destroy(_instance);
+ _prefab = null;
+ throw new FlaxException("Failed to spawn a prefab for the preview.");
}
- _prefab = value;
-
- if (_prefab)
- {
- _prefab.WaitForLoaded(); // TODO: use lazy prefab spawning to reduce stalls
-
- var prevPreview = LoadingPreview;
- LoadingPreview = this;
-
- _instance = PrefabManager.SpawnPrefab(_prefab, null);
-
- LoadingPreview = prevPreview;
-
- if (_instance == null)
- {
- _prefab = null;
- throw new FlaxException("Failed to spawn a prefab for the preview.");
- }
- Task.AddCustomActor(_instance);
- }
+ // Set instance
+ Instance = instance;
}
}
}
@@ -72,7 +69,47 @@ namespace FlaxEditor.Viewport.Previews
public Actor Instance
{
get => _instance;
- internal set => _instance = value;
+ internal set
+ {
+ if (_instance == value)
+ return;
+
+ if (_instance)
+ {
+ // Unlink UI control
+ if (customControlLinked)
+ {
+ if (customControlLinked.Control?.Parent == this)
+ customControlLinked.Control.Parent = null;
+ customControlLinked = null;
+ }
+
+ // Remove for the preview
+ Task.RemoveCustomActor(_instance);
+ }
+
+ _instance = value;
+
+ if (_instance)
+ {
+ // Add to the preview
+ Task.AddCustomActor(_instance);
+
+ // Link UI canvases to the preview
+ LinkCanvas(_instance);
+ }
+ }
+ }
+
+ private void LinkCanvas(Actor actor)
+ {
+ if (actor is UICanvas uiCanvas)
+ uiCanvas.EditorOverride(Task, this);
+ var children = actor.ChildrenCount;
+ for (int i = 0; i < children; i++)
+ {
+ LinkCanvas(actor.GetChild(i));
+ }
}
///
@@ -87,7 +124,6 @@ namespace FlaxEditor.Viewport.Previews
///
public override void OnDestroy()
{
- // Cleanup
Prefab = null;
base.OnDestroy();
diff --git a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
index 08621f2ec..bded7e147 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
@@ -69,6 +69,7 @@ namespace FlaxEditor.Windows.Assets
bool hasSthSelected = Selection.Count > 0;
bool isSingleActorSelected = Selection.Count == 1 && Selection[0] is ActorNode;
bool isRootSelected = isSingleActorSelected && Selection[0] == Graph.Main;
+ bool hasPrefabLink = isSingleActorSelected && (Selection[0] as ActorNode).HasPrefabLink;
// Create popup
@@ -97,7 +98,7 @@ namespace FlaxEditor.Windows.Assets
b.Enabled = hasSthSelected && !isRootSelected;
b = contextMenu.AddButton("Set Root", SetRoot);
- b.Enabled = isSingleActorSelected && !isRootSelected;
+ b.Enabled = isSingleActorSelected && !isRootSelected && hasPrefabLink;
// Prefab options
@@ -108,8 +109,6 @@ namespace FlaxEditor.Windows.Assets
(Selection[0] as ActorNode).CanCreatePrefab &&
Editor.Windows.ContentWin.CurrentViewFolder.CanHaveAssets;
- bool hasPrefabLink = isSingleActorSelected && (Selection[0] as ActorNode).HasPrefabLink;
-
b = contextMenu.AddButton("Select Prefab", Editor.Prefabs.SelectPrefab);
b.Enabled = hasPrefabLink;
diff --git a/Source/Editor/Windows/Assets/PrefabWindow.cs b/Source/Editor/Windows/Assets/PrefabWindow.cs
index a8b3e24a4..4cc7898ee 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.cs
@@ -284,6 +284,9 @@ namespace FlaxEditor.Windows.Assets
{
// Simply update changes
Editor.Prefabs.ApplyAll(_viewport.Instance);
+
+ // Refresh properties panel to sync new prefab default values
+ _propertiesEditor.BuildLayout();
}
catch (Exception)
{
diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs
index 66ed50daf..145c0d972 100644
--- a/Source/Editor/Windows/ContentWindow.cs
+++ b/Source/Editor/Windows/ContentWindow.cs
@@ -396,7 +396,7 @@ namespace FlaxEditor.Windows
/// The item to delete.
public void Delete(ContentItem item)
{
- Delete(new List { item });
+ Delete(new List(1) { item });
}
///
@@ -405,36 +405,18 @@ namespace FlaxEditor.Windows
/// The items to delete.
public void Delete(List items)
{
+ if (items.Count == 0) return;
+
// TODO: remove items that depend on different items in the list: use wants to remove `folderA` and `folderA/asset.x`, we should just remove `folderA`
var toDelete = new List(items);
+ string msg = toDelete.Count == 1 ?
+ string.Format("Are you sure to delete \'{0}\'?\nThis action cannot be undone. Files will be deleted permanently.", items[0].Path)
+ : string.Format("Are you sure to delete {0} selected items?\nThis action cannot be undone. Files will be deleted permanently.", items.Count);
+
// Ask user
- if (toDelete.Count == 1)
- {
- // Single item
- if (MessageBox.Show(string.Format("Are you sure to delete \'{0}\'?\nThis action cannot be undone. Files will be deleted permanently.", items[0].Path),
- "Delete asset(s)",
- MessageBoxButtons.OKCancel,
- MessageBoxIcon.Question)
- != DialogResult.OK)
- {
- // Break
- return;
- }
- }
- else
- {
- // Many items
- if (MessageBox.Show(string.Format("Are you sure to delete {0} selected items?\nThis action cannot be undone. Files will be deleted permanently.", items.Count),
- "Delete asset(s)",
- MessageBoxButtons.OKCancel,
- MessageBoxIcon.Question)
- != DialogResult.OK)
- {
- // Break
- return;
- }
- }
+ if (MessageBox.Show(msg, "Delete asset(s)", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK)
+ return;
// Clear navigation
// TODO: just remove invalid locations from the history (those are removed)
diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs
index 2f9be0254..858f0e0ba 100644
--- a/Source/Editor/Windows/GameWindow.cs
+++ b/Source/Editor/Windows/GameWindow.cs
@@ -294,7 +294,9 @@ namespace FlaxEditor.Windows
{
if (Editor.Instance.SceneEditing.Selection[i].EditableObject is UIControl controlActor && controlActor.Control != null)
{
- Render2D.DrawRectangle(controlActor.Control.Bounds, Editor.Instance.Options.Options.Visual.SelectionOutlineColor0, Editor.Instance.Options.Options.Visual.UISelectionOutlineSize);
+ var control = controlActor.Control;
+ var bounds = Rectangle.FromPoints(control.PointToParent(_viewport, Vector2.Zero), control.PointToParent(_viewport, control.Size));
+ Render2D.DrawRectangle(bounds, Editor.Instance.Options.Options.Visual.SelectionOutlineColor0, Editor.Instance.Options.Options.Visual.UISelectionOutlineSize);
}
}
diff --git a/Source/Editor/Windows/SplashScreen.cpp b/Source/Editor/Windows/SplashScreen.cpp
index b05c73761..bc92a8d2a 100644
--- a/Source/Editor/Windows/SplashScreen.cpp
+++ b/Source/Editor/Windows/SplashScreen.cpp
@@ -115,6 +115,7 @@ const Char* SplashScreenQuotes[] =
TEXT("That's what she said"),
TEXT("Compiling Shaders (93,788)"),
TEXT("Hi There"),
+ TEXT("BAGUETTE"),
};
SplashScreen::~SplashScreen()
diff --git a/Source/Engine/Content/JsonAsset.h b/Source/Engine/Content/JsonAsset.h
index b9edd67ea..d865e8b96 100644
--- a/Source/Engine/Content/JsonAsset.h
+++ b/Source/Engine/Content/JsonAsset.h
@@ -74,7 +74,8 @@ protected:
///
/// Generic type of Json-format asset. It provides the managed representation of this resource data so it can be accessed via C# API.
///
-API_CLASS(NoSpawn) class JsonAsset : public JsonAssetBase
+///
+API_CLASS(NoSpawn) class FLAXENGINE_API JsonAsset : public JsonAssetBase
{
DECLARE_ASSET_HEADER(JsonAsset);
private:
diff --git a/Source/Engine/ContentImporters/AssetsImportingManager.cpp b/Source/Engine/ContentImporters/AssetsImportingManager.cpp
index 3a39bd64b..f1d048ca5 100644
--- a/Source/Engine/ContentImporters/AssetsImportingManager.cpp
+++ b/Source/Engine/ContentImporters/AssetsImportingManager.cpp
@@ -178,7 +178,7 @@ void CreateAssetContext::ApplyChanges()
// Move file
if (FileSystem::MoveFile(TargetAssetPath, OutputPath, true))
{
- LOG(Warning, "Cannot move imported file to the destination path.");
+ LOG(Warning, "Cannot move imported file {0} to the destination path {1}.", OutputPath, TargetAssetPath);
_applyChangesResult = CreateAssetResult::CannotSaveFile;
return;
}
diff --git a/Source/Engine/Core/Config/LayersTagsSettings.h b/Source/Engine/Core/Config/LayersTagsSettings.h
index 44bca9231..945a24fbf 100644
--- a/Source/Engine/Core/Config/LayersTagsSettings.h
+++ b/Source/Engine/Core/Config/LayersTagsSettings.h
@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Core/Config/Settings.h"
+#include "Engine/Serialization/Json.h"
///
/// Layers and objects tags settings.
diff --git a/Source/Engine/Core/Math/Vector3.cs b/Source/Engine/Core/Math/Vector3.cs
index db27cf8ed..a57fcb224 100644
--- a/Source/Engine/Core/Math/Vector3.cs
+++ b/Source/Engine/Core/Math/Vector3.cs
@@ -1221,7 +1221,7 @@ namespace FlaxEngine
float dot = Mathf.Clamp(Dot(from.Normalized, to.Normalized), -1F, 1F);
if (Mathf.Abs(dot) > (1F - Mathf.Epsilon))
return dot > 0F ? 0F : 180F;
- return Mathf.Acos(dot) * Mathf.DegreesToRadians;
+ return Mathf.Acos(dot) * Mathf.RadiansToDegrees;
}
///
diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp
index afc2311ff..e394b31f4 100644
--- a/Source/Engine/Debug/DebugDraw.cpp
+++ b/Source/Engine/Debug/DebugDraw.cpp
@@ -19,6 +19,7 @@
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Animations/AnimationUtils.h"
#include "Engine/Profiler/Profiler.h"
+#include "Engine/Debug/DebugLog.h"
// Debug draw service configuration
#define DEBUG_DRAW_INITIAL_VB_CAPACITY (4 * 1024)
@@ -674,7 +675,11 @@ void DebugDraw::DrawLine(const Vector3& start, const Vector3& end, const Color&
void DebugDraw::DrawLines(const Span& lines, const Matrix& transform, const Color& color, float duration, bool depthTest)
{
- ASSERT(lines.Length() % 2 == 0);
+ if (lines.Length() % 2 != 0)
+ {
+ DebugLog::ThrowException("Cannot draw debug lines with uneven amount of items in array");
+ return;
+ }
// Create draw call entry
DebugLine l = { Vector3::Zero, Vector3::Zero, Color32(color), duration };
@@ -682,10 +687,12 @@ void DebugDraw::DrawLines(const Span& lines, const Matrix& transform, c
// Add lines
const Vector3* p = lines.Get();
Array* list;
- if (depthTest)
+
+ if (depthTest)
list = duration > 0 ? &DebugDrawDepthTest.DefaultLines : &DebugDrawDepthTest.OneFrameLines;
else
list = duration > 0 ? &DebugDrawDefault.DefaultLines : &DebugDrawDefault.OneFrameLines;
+
list->EnsureCapacity(list->Count() + lines.Length());
for (int32 i = 0; i < lines.Length(); i += 2)
{
diff --git a/Source/Engine/Graphics/RenderTask.cpp b/Source/Engine/Graphics/RenderTask.cpp
index d30e8e37c..405e0fe45 100644
--- a/Source/Engine/Graphics/RenderTask.cpp
+++ b/Source/Engine/Graphics/RenderTask.cpp
@@ -283,11 +283,10 @@ Viewport SceneRenderTask::GetViewport() const
GPUTextureView* SceneRenderTask::GetOutputView() const
{
- if (Output)
+ if (Output && Output->IsAllocated())
return Output->View();
if (SwapChain)
return SwapChain->GetBackBufferView();
- CRASH;
return nullptr;
}
diff --git a/Source/Engine/Graphics/Textures/GPUTexture.cpp b/Source/Engine/Graphics/Textures/GPUTexture.cpp
index e51d2e510..29268e721 100644
--- a/Source/Engine/Graphics/Textures/GPUTexture.cpp
+++ b/Source/Engine/Graphics/Textures/GPUTexture.cpp
@@ -458,43 +458,13 @@ protected:
// [ThreadPoolTask]
bool Run() override
{
- // Check resources
auto texture = _texture.Get();
if (texture == nullptr || _staging == nullptr || _data == nullptr)
{
LOG(Warning, "Cannot download texture data. Missing objects.");
return true;
}
-
- const auto arraySize = texture->ArraySize();
- const auto mipLevels = texture->MipLevels();
-
- // Get all mip maps for each array slice
- auto& rawResultData = _data->Items;
- rawResultData.Resize(arraySize, false);
- for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
- {
- auto& arraySlice = rawResultData[arrayIndex];
- arraySlice.Mips.Resize(mipLevels);
-
- for (int32 mipMapIndex = 0; mipMapIndex < mipLevels; mipMapIndex++)
- {
- auto& mip = arraySlice.Mips[mipMapIndex];
- const int32 mipWidth = _data->Width >> mipMapIndex;
- const int32 mipHeight = _data->Height >> mipMapIndex;
- uint32 mipRowPitch, mipSlicePitch;
- RenderTools::ComputePitch(_data->Format, mipWidth, mipHeight, mipRowPitch, mipSlicePitch);
-
- // Gather data
- if (_staging->GetData(arrayIndex, mipMapIndex, mip, mipRowPitch))
- {
- LOG(Warning, "Staging resource of \'{0}\' get data failed.", texture->ToString());
- return true;
- }
- }
- }
-
- return false;
+ return _staging->DownloadData(*_data);
}
void OnEnd() override
@@ -508,6 +478,57 @@ protected:
bool GPUTexture::DownloadData(TextureData& result)
{
+ // Skip for empty ones
+ if (MipLevels() == 0)
+ {
+ LOG(Warning, "Cannot download GPU texture data from an empty texture.");
+ return true;
+ }
+ if (Depth() != 1)
+ {
+ MISSING_CODE("support volume texture data downloading.");
+ }
+
+ // Use faster path for staging resources
+ if (IsStaging())
+ {
+ const auto arraySize = ArraySize();
+ const auto mipLevels = MipLevels();
+
+ // Set texture info
+ result.Width = Width();
+ result.Height = Height();
+ result.Depth = Depth();
+ result.Format = Format();
+
+ // Get all mip maps for each array slice
+ auto& rawResultData = result.Items;
+ rawResultData.Resize(arraySize, false);
+ for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
+ {
+ auto& arraySlice = rawResultData[arrayIndex];
+ arraySlice.Mips.Resize(mipLevels);
+
+ for (int32 mipMapIndex = 0; mipMapIndex < mipLevels; mipMapIndex++)
+ {
+ auto& mip = arraySlice.Mips[mipMapIndex];
+ const int32 mipWidth = result.Width >> mipMapIndex;
+ const int32 mipHeight = result.Height >> mipMapIndex;
+ uint32 mipRowPitch, mipSlicePitch;
+ RenderTools::ComputePitch(result.Format, mipWidth, mipHeight, mipRowPitch, mipSlicePitch);
+
+ // Gather data
+ if (GetData(arrayIndex, mipMapIndex, mip, mipRowPitch))
+ {
+ LOG(Warning, "Staging resource of \'{0}\' get data failed.", ToString());
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
const auto name = ToString();
// Ensure not running on main thread - we support DownloadData from textures only on a worker threads (Thread Pool Workers or Content Loaders)
@@ -538,7 +559,8 @@ bool GPUTexture::DownloadData(TextureData& result)
Task* GPUTexture::DownloadDataAsync(TextureData& result)
{
- if (!IsAllocated())
+ // Skip for empty ones
+ if (MipLevels() == 0)
{
LOG(Warning, "Cannot download texture data. It has not ben created yet.");
return nullptr;
@@ -548,19 +570,12 @@ Task* GPUTexture::DownloadDataAsync(TextureData& result)
MISSING_CODE("support volume texture data downloading.");
}
- // Set texture info
- result.Width = Width();
- result.Height = Height();
- result.Depth = Depth();
- result.Format = Format();
-
- // Quicker path if texture is already readback
- if (_desc.Usage == GPUResourceUsage::StagingReadback)
+ // Use faster path for staging resources
+ if (IsStaging())
{
// Create task to copy downloaded data to TextureData container
auto getDataTask = ::New(this, this, result);
ASSERT(getDataTask->HasReference(this));
-
return getDataTask;
}
diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp
index 0f2bdf4e5..73d5316eb 100644
--- a/Source/Engine/Input/Input.cpp
+++ b/Source/Engine/Input/Input.cpp
@@ -197,6 +197,7 @@ bool Mouse::Update(EventQueue& queue)
}
case EventType::MouseDoubleClick:
{
+ _state.MouseButtons[static_cast(e.MouseData.Button)] = true;
break;
}
case EventType::MouseWheel:
diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp
index ce3bcdb65..509fae98a 100644
--- a/Source/Engine/Level/Actor.cpp
+++ b/Source/Engine/Level/Actor.cpp
@@ -42,6 +42,8 @@ Actor::Actor(const SpawnParams& params)
, _staticFlags(StaticFlags::FullyStatic)
, _localTransform(Transform::Identity)
, _transform(Transform::Identity)
+ , _sphere(BoundingSphere::Empty)
+ , _box(BoundingBox::Empty)
, HideFlags(HideFlags::None)
{
}
diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h
index 6416fd33a..dea13cd4f 100644
--- a/Source/Engine/Level/Actor.h
+++ b/Source/Engine/Level/Actor.h
@@ -445,13 +445,13 @@ public:
}
///
- /// Sets actor orientation in 3D space
+ /// Sets actor orientation in 3D space.
///
/// The value to set.
API_PROPERTY() void SetOrientation(const Quaternion& value);
///
- /// Gets actor scale in 3D space
+ /// Gets actor scale in 3D space.
///
API_PROPERTY(Attributes="HideInEditor, NoSerialize")
FORCE_INLINE Vector3 GetScale() const
@@ -466,13 +466,13 @@ public:
API_PROPERTY() void SetScale(const Vector3& value);
///
- /// Gets actor rotation matrix
+ /// Gets actor rotation matrix.
///
API_PROPERTY(Attributes="HideInEditor, NoSerialize")
Matrix GetRotation() const;
///
- /// Sets actor rotation matrix
+ /// Sets actor rotation matrix.
///
/// The value to set.
API_PROPERTY() void SetRotation(const Matrix& value);
diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp
index 53e400009..ba4ce4014 100644
--- a/Source/Engine/Level/Level.cpp
+++ b/Source/Engine/Level/Level.cpp
@@ -1005,7 +1005,7 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, bool autoI
if (obj && obj->GetParent() == nullptr)
{
sceneObjects->At(i) = nullptr;
- LOG(Warning, "Scene object {0} {1} has missing parent object after scene load. Removing it.", obj->GetID(), obj->ToString());
+ LOG(Warning, "Scene object {0} {1} has missing parent object after load. Removing it.", obj->GetID(), obj->ToString());
obj->DeleteObject();
}
}
@@ -1358,12 +1358,8 @@ Actor* Level::FindActor(const MClass* type)
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);
- }
-
return result;
}
@@ -1372,25 +1368,57 @@ Script* Level::FindScript(const MClass* type)
CHECK_RETURN(type, nullptr);
Script* result = nullptr;
ScopeLock lock(ScenesLock);
-
for (int32 i = 0; result == nullptr && i < Scenes.Count(); i++)
- {
result = Scenes[i]->FindScript(type);
+ return result;
+}
+
+namespace
+{
+ void GetActors(const MClass* type, Actor* actor, Array& result)
+ {
+ if (actor->GetClass()->IsSubClassOf(type))
+ result.Add(actor);
+ for (auto child : actor->Children)
+ GetActors(type, child, result);
}
+ void GetScripts(const MClass* type, Actor* actor, Array