Merge remote-tracking branch 'origin/master' into 1.9
# Conflicts: # Content/Editor/Camera/M_Camera.flax # Content/Editor/CubeTexturePreviewMaterial.flax # Content/Editor/DebugMaterials/DDGIDebugProbes.flax # Content/Editor/DebugMaterials/SingleColor/Decal.flax # Content/Editor/DebugMaterials/SingleColor/Particle.flax # Content/Editor/DebugMaterials/SingleColor/Surface.flax # Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax # Content/Editor/DebugMaterials/SingleColor/Terrain.flax # Content/Editor/DefaultFontMaterial.flax # Content/Editor/Gizmo/FoliageBrushMaterial.flax # Content/Editor/Gizmo/Material.flax # Content/Editor/Gizmo/MaterialWire.flax # Content/Editor/Gizmo/SelectionOutlineMaterial.flax # Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax # Content/Editor/Highlight Material.flax # Content/Editor/Icons/IconsMaterial.flax # Content/Editor/IesProfilePreviewMaterial.flax # Content/Editor/Particles/Particle Material Color.flax # Content/Editor/Particles/Smoke Material.flax # Content/Editor/SpriteMaterial.flax # Content/Editor/Terrain/Circle Brush Material.flax # Content/Editor/Terrain/Highlight Terrain Material.flax # Content/Editor/TexturePreviewMaterial.flax # Content/Editor/Wires Debug Material.flax # Content/Engine/DefaultDeformableMaterial.flax # Content/Engine/DefaultMaterial.flax # Content/Engine/DefaultTerrainMaterial.flax # Content/Engine/SingleColorMaterial.flax # Content/Engine/SkyboxMaterial.flax # Source/Engine/Graphics/Materials/MaterialShader.h
This commit is contained in:
@@ -249,6 +249,7 @@ namespace FlaxEditor.Content
|
||||
private ScriptMemberInfo[] _parameters;
|
||||
private ScriptMemberInfo[] _methods;
|
||||
private object[] _attributes;
|
||||
private List<Action<ScriptType>> _disposing;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Visual Script asset that contains this type.
|
||||
@@ -310,6 +311,13 @@ namespace FlaxEditor.Content
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
if (_disposing != null)
|
||||
{
|
||||
foreach (var e in _disposing)
|
||||
e(new ScriptType(this));
|
||||
_disposing.Clear();
|
||||
_disposing = null;
|
||||
}
|
||||
if (_parameters != null)
|
||||
{
|
||||
OnAssetReloading(_asset);
|
||||
@@ -510,6 +518,14 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
return _methods;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void TrackLifetime(Action<ScriptType> disposing)
|
||||
{
|
||||
if (_disposing == null)
|
||||
_disposing = new List<Action<ScriptType>>();
|
||||
_disposing.Add(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -209,16 +209,15 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
public override DragDropEffect OnDragMove(ref Float2 location, DragData data)
|
||||
{
|
||||
var result = base.OnDragMove(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
if (result != DragDropEffect.None || _dragHandlers == null)
|
||||
return result;
|
||||
|
||||
return _dragHandlers.Effect;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDragLeave()
|
||||
{
|
||||
_dragHandlers.OnDragLeave();
|
||||
_dragHandlers?.OnDragLeave();
|
||||
|
||||
base.OnDragLeave();
|
||||
}
|
||||
|
||||
@@ -585,7 +585,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public override DragDropEffect OnDragMove(ref Float2 location, DragData data)
|
||||
{
|
||||
var result = base.OnDragMove(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
if (result != DragDropEffect.None || _dragHandlers == null)
|
||||
return result;
|
||||
|
||||
return _dragHandlers.Effect;
|
||||
@@ -594,7 +594,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void OnDragLeave()
|
||||
{
|
||||
_dragHandlers.OnDragLeave();
|
||||
_dragHandlers?.OnDragLeave();
|
||||
|
||||
base.OnDragLeave();
|
||||
}
|
||||
|
||||
@@ -554,7 +554,7 @@ namespace FlaxEditor.GUI
|
||||
// Check if has selected item
|
||||
if (_selectedIndices != null && _selectedIndices.Count > 0)
|
||||
{
|
||||
string text = _selectedIndices.Count == 1 ? _items[_selectedIndices[0]] : "Multiple Values";
|
||||
string text = _selectedIndices.Count == 1 ? (_selectedIndices[0] >= 0 && _selectedIndices[0] < _items.Count ? _items[_selectedIndices[0]] : "") : "Multiple Values";
|
||||
|
||||
// Draw text of the selected item
|
||||
float textScale = Height / DefaultHeight;
|
||||
|
||||
@@ -42,15 +42,14 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
|
||||
// Arrange controls
|
||||
Margin margin = _menu._itemsMargin;
|
||||
float y = margin.Top;
|
||||
float x = margin.Left;
|
||||
float y = 0;
|
||||
float width = Width - margin.Width;
|
||||
for (int i = 0; i < _children.Count; i++)
|
||||
{
|
||||
if (_children[i] is ContextMenuItem item && item.Visible)
|
||||
{
|
||||
var height = item.Height;
|
||||
item.Bounds = new Rectangle(x, y, width, height);
|
||||
item.Bounds = new Rectangle(margin.Left, y, width, height);
|
||||
y += height + margin.Height;
|
||||
}
|
||||
}
|
||||
@@ -300,7 +299,6 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
if (_panel.Children[i] is ContextMenuChildMenu menu && menu.Text == text)
|
||||
return menu;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -319,7 +317,6 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
Parent = _panel
|
||||
};
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -396,10 +393,12 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
float height = _itemsAreaMargin.Height;
|
||||
int itemsLeft = MaximumItemsInViewCount;
|
||||
int overflowItemCount = 0;
|
||||
int itemsCount = 0;
|
||||
for (int i = 0; i < _panel.Children.Count; i++)
|
||||
{
|
||||
if (_panel.Children[i] is ContextMenuItem item && item.Visible)
|
||||
{
|
||||
itemsCount++;
|
||||
if (itemsLeft > 0)
|
||||
{
|
||||
height += item.Height + _itemsMargin.Height;
|
||||
@@ -412,6 +411,8 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
maxWidth = Mathf.Max(maxWidth, item.MinimumWidth);
|
||||
}
|
||||
}
|
||||
if (itemsCount != 0)
|
||||
height -= _itemsMargin.Height; // Remove item margin from top and bottom
|
||||
maxWidth = Mathf.Max(maxWidth + 20, MinimumWidth);
|
||||
|
||||
// Move child arrows to accommodate scroll bar showing
|
||||
|
||||
@@ -29,6 +29,15 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
CloseMenuOnClick = false;
|
||||
}
|
||||
|
||||
private void ShowChild(ContextMenu parentContextMenu)
|
||||
{
|
||||
// Hide parent CM popups and set itself as child
|
||||
var vAlign = parentContextMenu.ItemsAreaMargin.Top;
|
||||
var location = new Float2(Width, -vAlign);
|
||||
location = PointToParent(parentContextMenu, location);
|
||||
parentContextMenu.ShowChild(ContextMenu, location);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
@@ -58,14 +67,12 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
var parentContextMenu = ParentContextMenu;
|
||||
if (parentContextMenu == ContextMenu)
|
||||
return;
|
||||
|
||||
if (ContextMenu.IsOpened)
|
||||
return;
|
||||
|
||||
base.OnMouseEnter(location);
|
||||
|
||||
// Hide parent CM popups and set itself as child
|
||||
parentContextMenu.ShowChild(ContextMenu, PointToParent(ParentContextMenu, new Float2(Width, 0)));
|
||||
ShowChild(parentContextMenu);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -78,8 +85,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
if (ContextMenu.IsOpened)
|
||||
return true;
|
||||
|
||||
// Hide parent CM popups and set itself as child
|
||||
parentContextMenu.ShowChild(ContextMenu, PointToParent(ParentContextMenu, new Float2(Width, 0)));
|
||||
ShowChild(parentContextMenu);
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
if (Type == ScriptType.Null)
|
||||
{
|
||||
Editor.LogError("Missing anim event type " + _instanceTypeName);
|
||||
InitMissing();
|
||||
return;
|
||||
}
|
||||
Instance = (AnimEvent)Type.CreateInstance();
|
||||
@@ -125,20 +126,37 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
_isRegisteredForScriptsReload = true;
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
}
|
||||
Type.TrackLifetime(OnTypeDisposing);
|
||||
}
|
||||
|
||||
private void OnTypeDisposing(ScriptType type)
|
||||
{
|
||||
if (Type == type && !IsDisposing)
|
||||
{
|
||||
// Turn into missing script
|
||||
OnScriptsReloadBegin();
|
||||
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||
InitMissing();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitMissing()
|
||||
{
|
||||
CanDelete = true;
|
||||
CanSplit = false;
|
||||
CanResize = false;
|
||||
TooltipText = $"Missing Anim Event Type '{_instanceTypeName}'";
|
||||
BackgroundColor = Color.Red;
|
||||
Type = ScriptType.Null;
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
internal void InitMissing(string typeName, byte[] data)
|
||||
{
|
||||
Type = ScriptType.Null;
|
||||
IsContinuous = false;
|
||||
CanDelete = true;
|
||||
CanSplit = false;
|
||||
CanResize = false;
|
||||
TooltipText = $"Missing Anim Event Type '{typeName}'";
|
||||
Instance = null;
|
||||
BackgroundColor = Color.Red;
|
||||
_instanceTypeName = typeName;
|
||||
_instanceData = data;
|
||||
InitMissing();
|
||||
}
|
||||
|
||||
internal void Load(BinaryReader stream)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include "Engine/Renderer/ProbesRenderer.h"
|
||||
#include "Engine/Animations/Graph/AnimGraph.h"
|
||||
#include "Engine/Core/ObjectsRemovalService.h"
|
||||
|
||||
ManagedEditor::InternalOptions ManagedEditor::ManagedEditorOptions;
|
||||
|
||||
@@ -572,6 +573,29 @@ bool ManagedEditor::EvaluateVisualScriptLocal(VisualScript* script, VisualScript
|
||||
return false;
|
||||
}
|
||||
|
||||
void ManagedEditor::WipeOutLeftoverSceneObjects()
|
||||
{
|
||||
Array<ScriptingObject*> objects = Scripting::GetObjects();
|
||||
bool removedAny = false;
|
||||
for (ScriptingObject* object : objects)
|
||||
{
|
||||
if (EnumHasAllFlags(object->Flags, ObjectFlags::IsDuringPlay) && EnumHasNoneFlags(object->Flags, ObjectFlags::WasMarkedToDelete))
|
||||
{
|
||||
if (auto* sceneObject = Cast<SceneObject>(object))
|
||||
{
|
||||
if (sceneObject->HasParent())
|
||||
continue; // Skip sub-objects
|
||||
|
||||
LOG(Error, "Object '{}' (ID={}, Type={}) is still in memory after play end but should be destroyed (memory leak).", sceneObject->GetNamePath(), sceneObject->GetID(), sceneObject->GetType().ToString());
|
||||
sceneObject->DeleteObject();
|
||||
removedAny = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (removedAny)
|
||||
ObjectsRemovalService::Flush();
|
||||
}
|
||||
|
||||
void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly)
|
||||
{
|
||||
ASSERT(!HasManagedInstance());
|
||||
|
||||
@@ -241,6 +241,7 @@ public:
|
||||
API_FUNCTION(Internal) static VisualScriptStackFrame GetVisualScriptPreviousScopeFrame();
|
||||
API_FUNCTION(Internal) static Array<VisualScriptLocal> GetVisualScriptLocals();
|
||||
API_FUNCTION(Internal) static bool EvaluateVisualScriptLocal(VisualScript* script, API_PARAM(Ref) VisualScriptLocal& local);
|
||||
API_FUNCTION(Internal) static void WipeOutLeftoverSceneObjects();
|
||||
|
||||
private:
|
||||
void OnEditorAssemblyLoaded(MAssembly* assembly);
|
||||
|
||||
@@ -144,5 +144,11 @@ namespace FlaxEditor.Scripting
|
||||
{
|
||||
return Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void TrackLifetime(Action<ScriptType> disposing)
|
||||
{
|
||||
ElementType.TrackLifetime(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +167,12 @@ namespace FlaxEditor.Scripting
|
||||
/// <param name="bindingAttr">A bitmask comprised of one or more <see cref="T:System.Reflection.BindingFlags" /> that specify how the search is conducted.-or- Zero (<see cref="F:System.Reflection.BindingFlags.Default" />), to return an empty array.</param>
|
||||
/// <returns>An array of member objects representing all methods defined for the current type that match the specified binding constraints.-or- An empty array of type member, if no methods are defined for the current type, or if none of the defined methods match the binding constraints.</returns>
|
||||
ScriptMemberInfo[] GetMethods(BindingFlags bindingAttr);
|
||||
|
||||
/// <summary>
|
||||
/// Registers delegate to be invoked upon script type disposal (except hot-reload in Editor via <see cref="ScriptsBuilder.ScriptsReload"/>). For example, can happen when user deleted Visual Script asset.
|
||||
/// </summary>
|
||||
/// <param name="disposing">Event to call when script type gets disposed (eg. removed asset).</param>
|
||||
void TrackLifetime(Action<ScriptType> disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1395,11 +1395,21 @@ namespace FlaxEditor.Scripting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic check to see if a type could be casted to another type
|
||||
/// Registers delegate to be invoked upon script type disposal (except hot-reload in Editor via <see cref="ScriptsBuilder.ScriptsReload"/>). For example, can happen when user deleted Visual Script asset.
|
||||
/// </summary>
|
||||
/// <param name="disposing">Event to call when script type gets disposed (eg. removed asset).</param>
|
||||
public void TrackLifetime(Action<ScriptType> disposing)
|
||||
{
|
||||
if (_custom != null)
|
||||
_custom.TrackLifetime(disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic check to see if a type could be cast to another type
|
||||
/// </summary>
|
||||
/// <param name="from">Source type</param>
|
||||
/// <param name="to">Target type</param>
|
||||
/// <returns>True if the type can be casted</returns>
|
||||
/// <returns>True if the type can be cast.</returns>
|
||||
public static bool CanCast(ScriptType from, ScriptType to)
|
||||
{
|
||||
if (from == to)
|
||||
@@ -1412,10 +1422,10 @@ namespace FlaxEditor.Scripting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic check to see if this type could be casted to another type
|
||||
/// Basic check to see if this type could be cast to another type
|
||||
/// </summary>
|
||||
/// <param name="to">Target type</param>
|
||||
/// <returns>True if the type can be casted</returns>
|
||||
/// <returns>True if the type can be cast.</returns>
|
||||
public bool CanCastTo(ScriptType to)
|
||||
{
|
||||
return CanCast(this, to);
|
||||
|
||||
@@ -163,6 +163,8 @@ namespace FlaxEditor.States
|
||||
Editor.OnPlayBegin();
|
||||
IsPlayModeStarting = false;
|
||||
Profiler.EndEvent();
|
||||
|
||||
Time.Synchronize();
|
||||
}
|
||||
|
||||
private void SetupEditorEnvOptions()
|
||||
@@ -192,7 +194,7 @@ namespace FlaxEditor.States
|
||||
|
||||
// Restore editor scene
|
||||
SceneRestoring?.Invoke();
|
||||
_duplicateScenes.DeletedScenes();
|
||||
_duplicateScenes.UnloadScenes();
|
||||
PluginManager.Internal_DeinitializeGamePlugins();
|
||||
Editor.Internal_SetPlayMode(false);
|
||||
_duplicateScenes.RestoreSceneData();
|
||||
@@ -209,6 +211,8 @@ namespace FlaxEditor.States
|
||||
Editor.OnPlayEnd();
|
||||
IsPlayModeEnding = false;
|
||||
Profiler.EndEvent();
|
||||
|
||||
Time.Synchronize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.IO;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Surface.Undo;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
@@ -16,14 +17,13 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
|
||||
[HideInEditor]
|
||||
public abstract class BlendPointsEditor : ContainerControl
|
||||
public class BlendPointsEditor : ContainerControl
|
||||
{
|
||||
private readonly Animation.MultiBlend _node;
|
||||
private readonly bool _is2D;
|
||||
private Float2 _rangeX;
|
||||
private Float2 _rangeY;
|
||||
private readonly BlendPoint[] _blendPoints = new BlendPoint[Animation.MultiBlend.MaxAnimationsCount];
|
||||
private readonly Guid[] _pointsAnims = new Guid[Animation.MultiBlend.MaxAnimationsCount];
|
||||
private readonly Float2[] _pointsLocations = new Float2[Animation.MultiBlend.MaxAnimationsCount];
|
||||
private Float2 _rangeX, _rangeY;
|
||||
private Float2 _debugPos = Float2.Minimum;
|
||||
private readonly List<BlendPoint> _blendPoints = new List<BlendPoint>();
|
||||
|
||||
/// <summary>
|
||||
/// Represents single blend point.
|
||||
@@ -31,16 +31,22 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <seealso cref="FlaxEngine.GUI.Control" />
|
||||
protected class BlendPoint : Control
|
||||
{
|
||||
private static Matrix3x3 _transform = Matrix3x3.RotationZ(45.0f * Mathf.DegreesToRadians) * Matrix3x3.Translation2D(4.0f, 0.5f);
|
||||
private readonly BlendPointsEditor _editor;
|
||||
private readonly int _index;
|
||||
private bool _isMouseDown;
|
||||
private Float2 _mousePosOffset;
|
||||
private bool _isMouseDown, _mouseMoved;
|
||||
private object[] _mouseMoveStartValues;
|
||||
|
||||
/// <summary>
|
||||
/// The default size for the blend points.
|
||||
/// </summary>
|
||||
public const float DefaultSize = 8.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Blend point index.
|
||||
/// </summary>
|
||||
public int Index => _index;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BlendPoint"/> class.
|
||||
/// </summary>
|
||||
@@ -53,24 +59,45 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
_index = index;
|
||||
}
|
||||
|
||||
private void EndMove()
|
||||
{
|
||||
_isMouseDown = false;
|
||||
EndMouseCapture();
|
||||
if (_mouseMoveStartValues != null)
|
||||
{
|
||||
// Add undo action
|
||||
_editor._node.Surface.AddBatchedUndoAction(new EditNodeValuesAction(_editor._node, _mouseMoveStartValues, true));
|
||||
_mouseMoveStartValues = null;
|
||||
}
|
||||
if (_mouseMoved)
|
||||
_editor._node.Surface.MarkAsEdited();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnGotFocus()
|
||||
{
|
||||
base.OnGotFocus();
|
||||
|
||||
_editor.SelectedIndex = _index;
|
||||
_editor._node.SelectedAnimationIndex = _index;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
// Cache data
|
||||
var isSelected = _editor.SelectedIndex == _index;
|
||||
|
||||
// Draw rotated rectangle
|
||||
Render2D.PushTransform(ref _transform);
|
||||
Render2D.FillRectangle(new Rectangle(0, 0, 5, 5), isSelected ? Color.Orange : Color.BlueViolet);
|
||||
Render2D.PopTransform();
|
||||
// Draw dot with outline
|
||||
var style = Style.Current;
|
||||
var icon = Editor.Instance.Icons.VisjectBoxClosed32;
|
||||
var size = Height;
|
||||
var rect = new Rectangle(new Float2(size * -0.5f) + Size * 0.5f, new Float2(size));
|
||||
var outline = Color.Black; // Shadow
|
||||
if (_isMouseDown)
|
||||
outline = style.SelectionBorder;
|
||||
else if (IsMouseOver)
|
||||
outline = style.BorderHighlighted;
|
||||
else if (_editor._node.SelectedAnimationIndex == _index)
|
||||
outline = style.BackgroundSelected;
|
||||
Render2D.DrawSprite(icon, rect.MakeExpanded(4.0f), outline);
|
||||
Render2D.DrawSprite(icon, rect, style.Foreground);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -80,6 +107,9 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
Focus();
|
||||
_isMouseDown = true;
|
||||
_mouseMoved = false;
|
||||
_mouseMoveStartValues = null;
|
||||
_mousePosOffset = -location;
|
||||
StartMouseCapture();
|
||||
return true;
|
||||
}
|
||||
@@ -92,8 +122,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
if (button == MouseButton.Left && _isMouseDown)
|
||||
{
|
||||
_isMouseDown = false;
|
||||
EndMouseCapture();
|
||||
EndMove();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -103,9 +132,26 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
if (_isMouseDown)
|
||||
if (_isMouseDown && (_mouseMoved || Float2.DistanceSquared(location, _mousePosOffset) > 16.0f))
|
||||
{
|
||||
_editor.SetLocation(_index, _editor.BlendPointPosToBlendSpacePos(Location + location));
|
||||
if (!_mouseMoved)
|
||||
{
|
||||
// Capture initial state for undo
|
||||
_mouseMoved = true;
|
||||
_mouseMoveStartValues = _editor._node.Surface.Undo != null ? (object[])_editor._node.Values.Clone() : null;
|
||||
}
|
||||
|
||||
var newLocation = Location + location + _mousePosOffset;
|
||||
newLocation = _editor.BlendPointPosToBlendSpacePos(newLocation);
|
||||
if (Root != null && Root.GetKey(KeyboardKeys.Control))
|
||||
{
|
||||
var data0 = (Float4)_editor._node.Values[0];
|
||||
var rangeX = new Float2(data0.X, data0.Y);
|
||||
var rangeY = _editor._is2D ? new Float2(data0.Z, data0.W) : Float2.One;
|
||||
var grid = new Float2(Mathf.Abs(rangeX.Y - rangeX.X) * 0.01f, Mathf.Abs(rangeY.X - rangeY.Y) * 0.01f);
|
||||
newLocation = Float2.SnapToGrid(newLocation, grid);
|
||||
}
|
||||
_editor.SetLocation(_index, newLocation);
|
||||
}
|
||||
|
||||
base.OnMouseMove(location);
|
||||
@@ -116,8 +162,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
if (_isMouseDown)
|
||||
{
|
||||
_isMouseDown = false;
|
||||
EndMouseCapture();
|
||||
EndMove();
|
||||
}
|
||||
|
||||
base.OnMouseLeave();
|
||||
@@ -128,8 +173,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
if (_isMouseDown)
|
||||
{
|
||||
_isMouseDown = false;
|
||||
EndMouseCapture();
|
||||
EndMove();
|
||||
}
|
||||
|
||||
base.OnLostFocus();
|
||||
@@ -149,40 +193,130 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// </summary>
|
||||
public bool Is2D => _is2D;
|
||||
|
||||
/// <summary>
|
||||
/// Blend points count.
|
||||
/// </summary>
|
||||
public int PointsCount => (_node.Values.Length - 4) / 2; // 4 node values + 2 per blend point
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BlendPointsEditor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="node">The node.</param>
|
||||
/// <param name="is2D">The value indicating whether blend space is 2D, otherwise it is 1D.</param>
|
||||
/// <param name="x">The X location.</param>
|
||||
/// <param name="y">The Y location.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
public BlendPointsEditor(bool is2D, float x, float y, float width, float height)
|
||||
public BlendPointsEditor(Animation.MultiBlend node, bool is2D, float x, float y, float width, float height)
|
||||
: base(x, y, width, height)
|
||||
{
|
||||
_node = node;
|
||||
_is2D = is2D;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the blend space data.
|
||||
/// </summary>
|
||||
/// <param name="rangeX">The space range for X axis (X-width, Y-height).</param>
|
||||
/// <param name="rangeY">The space range for Y axis (X-width, Y-height).</param>
|
||||
/// <param name="pointsAnims">The points anims (input array to fill of size equal 14).</param>
|
||||
/// <param name="pointsLocations">The points locations (input array to fill of size equal 14).</param>
|
||||
public abstract void GetData(out Float2 rangeX, out Float2 rangeY, Guid[] pointsAnims, Float2[] pointsLocations);
|
||||
internal void AddPoint()
|
||||
{
|
||||
// Add random point within range
|
||||
var rand = new Float2(Mathf.Frac((float)Platform.TimeSeconds), (Platform.TimeCycles % 10000) / 10000.0f);
|
||||
AddPoint(Float2.Lerp(new Float2(_rangeX.X, _rangeY.X), new Float2(_rangeX.Y, _rangeY.Y), rand));
|
||||
}
|
||||
|
||||
private void AddPoint(Float2 location)
|
||||
{
|
||||
// Reuse existing animation
|
||||
var count = PointsCount;
|
||||
Guid id = Guid.Empty;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
id = (Guid)_node.Values[5 + i * 2];
|
||||
if (id != Guid.Empty)
|
||||
break;
|
||||
}
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
// Just use the first anim from project, user will change it
|
||||
var ids = FlaxEngine.Content.GetAllAssetsByType(typeof(FlaxEngine.Animation));
|
||||
if (ids.Length != 0)
|
||||
id = ids[0];
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
AddPoint(id, location);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the index of the selected blend point.
|
||||
/// Sets the blend point asset.
|
||||
/// </summary>
|
||||
public abstract int SelectedIndex { get; set; }
|
||||
/// <param name="asset">The asset.</param>
|
||||
/// <param name="location">The location.</param>
|
||||
public void AddPoint(Guid asset, Float2 location)
|
||||
{
|
||||
// Find the first free slot
|
||||
var count = PointsCount;
|
||||
if (count == Animation.MultiBlend.MaxAnimationsCount)
|
||||
return;
|
||||
var values = (object[])_node.Values.Clone();
|
||||
var index = 0;
|
||||
for (; index < count; index++)
|
||||
{
|
||||
var dataB = (Guid)_node.Values[5 + index * 2];
|
||||
if (dataB == Guid.Empty)
|
||||
break;
|
||||
}
|
||||
if (index == count)
|
||||
{
|
||||
// Add another blend point
|
||||
Array.Resize(ref values, values.Length + 2);
|
||||
}
|
||||
|
||||
values[4 + index * 2] = new Float4(location.X, _is2D ? location.Y : 0.0f, 0, 1.0f);
|
||||
values[5 + index * 2] = asset;
|
||||
_node.SetValues(values);
|
||||
|
||||
// Auto-select
|
||||
_node.SelectedAnimationIndex = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the blend point asset.
|
||||
/// </summary>
|
||||
/// <param name="index">The index.</param>
|
||||
/// <param name="asset">The asset.</param>
|
||||
/// <param name="withUndo">True to use undo action.</param>
|
||||
public void SetAsset(int index, Guid asset, bool withUndo = true)
|
||||
{
|
||||
if (withUndo)
|
||||
{
|
||||
_node.SetValue(5 + index * 2, asset);
|
||||
}
|
||||
else
|
||||
{
|
||||
_node.Values[5 + index * 2] = asset;
|
||||
_node.Surface.MarkAsEdited();
|
||||
}
|
||||
|
||||
_node.UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the blend point location.
|
||||
/// </summary>
|
||||
/// <param name="index">The index.</param>
|
||||
/// <param name="location">The location.</param>
|
||||
public abstract void SetLocation(int index, Float2 location);
|
||||
public void SetLocation(int index, Float2 location)
|
||||
{
|
||||
var dataA = (Float4)_node.Values[4 + index * 2];
|
||||
var ranges = (Float4)_node.Values[0];
|
||||
|
||||
dataA.X = Mathf.Clamp(location.X, ranges.X, ranges.Y);
|
||||
if (_is2D)
|
||||
dataA.Y = Mathf.Clamp(location.Y, ranges.Z, ranges.W);
|
||||
|
||||
_node.Values[4 + index * 2] = dataA;
|
||||
|
||||
_node.UpdateUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the blend points area.
|
||||
@@ -249,10 +383,23 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
// Synchronize blend points collection
|
||||
GetData(out _rangeX, out _rangeY, _pointsAnims, _pointsLocations);
|
||||
for (int i = 0; i < Animation.MultiBlend.MaxAnimationsCount; i++)
|
||||
var data0 = (Float4)_node.Values[0];
|
||||
_rangeX = new Float2(data0.X, data0.Y);
|
||||
_rangeY = _is2D ? new Float2(data0.Z, data0.W) : Float2.Zero;
|
||||
var count = PointsCount;
|
||||
while (_blendPoints.Count > count)
|
||||
{
|
||||
if (_pointsAnims[i] != Guid.Empty)
|
||||
_blendPoints[count].Dispose();
|
||||
_blendPoints.RemoveAt(count);
|
||||
}
|
||||
while (_blendPoints.Count < count)
|
||||
_blendPoints.Add(null);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var animId = (Guid)_node.Values[5 + i * 2];
|
||||
var dataA = (Float4)_node.Values[4 + i * 2];
|
||||
var location = new Float2(Mathf.Clamp(dataA.X, _rangeX.X, _rangeX.Y), _is2D ? Mathf.Clamp(dataA.Y, _rangeY.X, _rangeY.Y) : 0.0f);
|
||||
if (animId != Guid.Empty)
|
||||
{
|
||||
if (_blendPoints[i] == null)
|
||||
{
|
||||
@@ -264,7 +411,13 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
|
||||
// Update blend point
|
||||
_blendPoints[i].Location = BlendSpacePosToBlendPointPos(_pointsLocations[i]);
|
||||
_blendPoints[i].Location = BlendSpacePosToBlendPointPos(location);
|
||||
var asset = Editor.Instance.ContentDatabase.FindAsset(animId);
|
||||
var tooltip = asset?.ShortName ?? string.Empty;
|
||||
tooltip += "\nX: " + location.X;
|
||||
if (_is2D)
|
||||
tooltip += "\nY: " + location.Y;
|
||||
_blendPoints[i].TooltipText = tooltip;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -277,6 +430,26 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
|
||||
// Debug current playback position
|
||||
if (((AnimGraphSurface)_node.Surface).TryGetTraceEvent(_node, out var traceEvent))
|
||||
{
|
||||
if (_is2D)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
// Unpack xy from 32-bits
|
||||
Half2 packed = *(Half2*)&traceEvent.Value;
|
||||
_debugPos = (Float2)packed;
|
||||
}
|
||||
}
|
||||
else
|
||||
_debugPos = new Float2(traceEvent.Value, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
_debugPos = Float2.Minimum;
|
||||
}
|
||||
|
||||
base.Update(deltaTime);
|
||||
}
|
||||
|
||||
@@ -293,14 +466,90 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseDown(location, button))
|
||||
return true;
|
||||
|
||||
Focus();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseUp(location, button))
|
||||
return true;
|
||||
|
||||
if (button == MouseButton.Right)
|
||||
{
|
||||
// Show context menu
|
||||
var menu = new FlaxEditor.GUI.ContextMenu.ContextMenu();
|
||||
var b = menu.AddButton("Add point", OnAddPoint);
|
||||
b.Tag = location;
|
||||
b.Enabled = PointsCount < Animation.MultiBlend.MaxAnimationsCount;
|
||||
if (GetChildAt(location) is BlendPoint blendPoint)
|
||||
{
|
||||
b = menu.AddButton("Remove point", OnRemovePoint);
|
||||
b.Tag = blendPoint.Index;
|
||||
b.TooltipText = blendPoint.TooltipText;
|
||||
}
|
||||
menu.Show(this, location);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnAddPoint(FlaxEditor.GUI.ContextMenu.ContextMenuButton b)
|
||||
{
|
||||
AddPoint(BlendPointPosToBlendSpacePos((Float2)b.Tag));
|
||||
}
|
||||
|
||||
private void OnRemovePoint(FlaxEditor.GUI.ContextMenu.ContextMenuButton b)
|
||||
{
|
||||
SetAsset((int)b.Tag, Guid.Empty);
|
||||
}
|
||||
|
||||
private void DrawAxis(bool vertical, Float2 start, Float2 end, ref Color gridColor, ref Color labelColor, Font labelFont, float value, bool isLast)
|
||||
{
|
||||
// Draw line
|
||||
Render2D.DrawLine(start, end, gridColor);
|
||||
|
||||
// Draw label
|
||||
var labelWidth = 50.0f;
|
||||
var labelHeight = 10.0f;
|
||||
var labelMargin = 2.0f;
|
||||
string label = Utils.RoundTo2DecimalPlaces(value).ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||
var hAlign = TextAlignment.Near;
|
||||
Rectangle labelRect;
|
||||
if (vertical)
|
||||
{
|
||||
labelRect = new Rectangle(start.X + labelMargin * 2, start.Y, labelWidth, labelHeight);
|
||||
if (isLast)
|
||||
return; // Don't overlap with the first horizontal label
|
||||
}
|
||||
else
|
||||
{
|
||||
labelRect = new Rectangle(start.X + labelMargin, start.Y - labelHeight - labelMargin, labelWidth, labelHeight);
|
||||
if (isLast)
|
||||
{
|
||||
labelRect.X = start.X - labelMargin - labelRect.Width;
|
||||
hAlign = TextAlignment.Far;
|
||||
}
|
||||
}
|
||||
Render2D.DrawText(labelFont, label, labelRect, labelColor, hAlign, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, 0.7f);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
// Cache data
|
||||
var style = Style.Current;
|
||||
var rect = new Rectangle(Float2.Zero, Size);
|
||||
var containsFocus = ContainsFocus;
|
||||
GetPointsArea(out var pointsArea);
|
||||
var data0 = (Float4)_node.Values[0];
|
||||
var rangeX = new Float2(data0.X, data0.Y);
|
||||
|
||||
// Background
|
||||
Render2D.DrawRectangle(rect, IsMouseOver ? style.TextBoxBackgroundSelected : style.TextBoxBackground);
|
||||
@@ -309,19 +558,27 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
// Grid
|
||||
int splits = 10;
|
||||
var gridColor = style.TextBoxBackgroundSelected * 1.1f;
|
||||
var labelColor = style.ForegroundDisabled;
|
||||
var labelFont = style.FontSmall;
|
||||
//var blendArea = BlendAreaRect;
|
||||
var blendArea = pointsArea;
|
||||
for (int i = 0; i < splits; i++)
|
||||
|
||||
for (int i = 0; i <= splits; i++)
|
||||
{
|
||||
float x = blendArea.Left + blendArea.Width * i / splits;
|
||||
Render2D.DrawLine(new Float2(x, 1), new Float2(x, rect.Height - 2), gridColor);
|
||||
float alpha = (float)i / splits;
|
||||
float x = blendArea.Left + blendArea.Width * alpha;
|
||||
float value = Mathf.Lerp(rangeX.X, rangeX.Y, alpha);
|
||||
DrawAxis(false, new Float2(x, rect.Height - 2), new Float2(x, 1), ref gridColor, ref labelColor, labelFont, value, i == splits);
|
||||
}
|
||||
if (_is2D)
|
||||
{
|
||||
for (int i = 0; i < splits; i++)
|
||||
var rangeY = new Float2(data0.Z, data0.W);
|
||||
for (int i = 0; i <= splits; i++)
|
||||
{
|
||||
float y = blendArea.Top + blendArea.Height * i / splits;
|
||||
Render2D.DrawLine(new Float2(1, y), new Float2(rect.Width - 2, y), gridColor);
|
||||
float alpha = (float)i / splits;
|
||||
float y = blendArea.Top + blendArea.Height * alpha;
|
||||
float value = Mathf.Lerp(rangeY.X, rangeY.Y, alpha);
|
||||
DrawAxis(true, new Float2(1, y), new Float2(rect.Width - 2, y), ref gridColor, ref labelColor, labelFont, value, i == splits);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -330,11 +587,24 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Render2D.DrawLine(new Float2(1, y), new Float2(rect.Width - 2, y), gridColor);
|
||||
}
|
||||
|
||||
// Base
|
||||
base.Draw();
|
||||
|
||||
// Draw debug position
|
||||
if (_debugPos.X > float.MinValue)
|
||||
{
|
||||
// Draw dot with outline
|
||||
var icon = Editor.Instance.Icons.VisjectBoxOpen32;
|
||||
var size = BlendPoint.DefaultSize;
|
||||
var debugPos = BlendSpacePosToBlendPointPos(_debugPos);
|
||||
var debugRect = new Rectangle(debugPos + new Float2(size * -0.5f) + size * 0.5f, new Float2(size));
|
||||
var outline = Color.Black; // Shadow
|
||||
Render2D.DrawSprite(icon, debugRect.MakeExpanded(2.0f), outline);
|
||||
Render2D.DrawSprite(icon, debugRect, style.ProgressNormal);
|
||||
}
|
||||
|
||||
// Frame
|
||||
Render2D.DrawRectangle(new Rectangle(1, 1, rect.Width - 2, rect.Height - 2), containsFocus ? style.ProgressNormal : style.BackgroundSelected);
|
||||
var frameColor = containsFocus ? style.BackgroundSelected : (IsMouseOver ? style.ForegroundGrey : style.ForegroundDisabled);
|
||||
Render2D.DrawRectangle(new Rectangle(1, 1, rect.Width - 2, rect.Height - 2), frameColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,6 +616,14 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <seealso cref="FlaxEditor.Surface.SurfaceNode" />
|
||||
public abstract class MultiBlend : SurfaceNode
|
||||
{
|
||||
private Button _addButton;
|
||||
private Button _removeButton;
|
||||
|
||||
/// <summary>
|
||||
/// The blend space editor.
|
||||
/// </summary>
|
||||
protected BlendPointsEditor _editor;
|
||||
|
||||
/// <summary>
|
||||
/// The selected animation label.
|
||||
/// </summary>
|
||||
@@ -379,7 +657,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <summary>
|
||||
/// The maximum animations amount to blend per node.
|
||||
/// </summary>
|
||||
public const int MaxAnimationsCount = 14;
|
||||
public const int MaxAnimationsCount = 255;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the index of the selected animation.
|
||||
@@ -387,7 +665,12 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
public int SelectedAnimationIndex
|
||||
{
|
||||
get => _selectedAnimation.SelectedIndex;
|
||||
set => _selectedAnimation.SelectedIndex = value;
|
||||
set
|
||||
{
|
||||
OnSelectedAnimationPopupShowing(_selectedAnimation);
|
||||
_selectedAnimation.SelectedIndex = value;
|
||||
UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -402,20 +685,14 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Text = "Selected Animation:",
|
||||
Parent = this
|
||||
};
|
||||
|
||||
_selectedAnimation = new ComboBox(_selectedAnimationLabel.X, 4 * layoutOffsetY, _selectedAnimationLabel.Width)
|
||||
{
|
||||
TooltipText = "Select blend point to view and edit it",
|
||||
Parent = this
|
||||
};
|
||||
|
||||
_selectedAnimation.PopupShowing += OnSelectedAnimationPopupShowing;
|
||||
_selectedAnimation.SelectedIndexChanged += OnSelectedAnimationChanged;
|
||||
|
||||
var items = new List<string>(MaxAnimationsCount);
|
||||
while (items.Count < MaxAnimationsCount)
|
||||
items.Add(string.Empty);
|
||||
_selectedAnimation.Items = items;
|
||||
|
||||
_animationPicker = new AssetPicker(new ScriptType(typeof(FlaxEngine.Animation)), new Float2(_selectedAnimation.Left, _selectedAnimation.Bottom + 4))
|
||||
{
|
||||
Parent = this
|
||||
@@ -428,20 +705,36 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Text = "Speed:",
|
||||
Parent = this
|
||||
};
|
||||
|
||||
_animationSpeed = new FloatValueBox(1.0f, _animationSpeedLabel.Right + 4, _animationSpeedLabel.Y, _selectedAnimation.Right - _animationSpeedLabel.Right - 4)
|
||||
{
|
||||
SlideSpeed = 0.01f,
|
||||
Parent = this
|
||||
};
|
||||
_animationSpeed.ValueChanged += OnAnimationSpeedValueChanged;
|
||||
|
||||
var buttonsSize = 12;
|
||||
_addButton = new Button(_selectedAnimation.Right - buttonsSize, _selectedAnimation.Bottom + 4, buttonsSize, buttonsSize)
|
||||
{
|
||||
Text = "+",
|
||||
TooltipText = "Add a new blend point",
|
||||
Parent = this
|
||||
};
|
||||
_addButton.Clicked += OnAddButtonClicked;
|
||||
_removeButton = new Button(_addButton.Left - buttonsSize - 4, _addButton.Y, buttonsSize, buttonsSize)
|
||||
{
|
||||
Text = "-",
|
||||
TooltipText = "Remove selected blend point",
|
||||
Parent = this
|
||||
};
|
||||
_removeButton.Clicked += OnRemoveButtonClicked;
|
||||
}
|
||||
|
||||
private void OnSelectedAnimationPopupShowing(ComboBox comboBox)
|
||||
{
|
||||
var items = comboBox.Items;
|
||||
items.Clear();
|
||||
for (var i = 0; i < MaxAnimationsCount; i++)
|
||||
var count = _editor.PointsCount;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var animId = (Guid)Values[5 + i * 2];
|
||||
var path = string.Empty;
|
||||
@@ -484,6 +777,16 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddButtonClicked()
|
||||
{
|
||||
_editor.AddPoint();
|
||||
}
|
||||
|
||||
private void OnRemoveButtonClicked()
|
||||
{
|
||||
_editor.SetAsset(SelectedAnimationIndex, Guid.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the editor UI.
|
||||
/// </summary>
|
||||
@@ -491,7 +794,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <param name="isValid">if set to <c>true</c> is selection valid.</param>
|
||||
/// <param name="data0">The packed data 0.</param>
|
||||
/// <param name="data1">The packed data 1.</param>
|
||||
protected virtual void UpdateUI(int selectedIndex, bool isValid, ref Float4 data0, ref Guid data1)
|
||||
public virtual void UpdateUI(int selectedIndex, bool isValid, ref Float4 data0, ref Guid data1)
|
||||
{
|
||||
if (isValid)
|
||||
{
|
||||
@@ -511,19 +814,21 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
_animationPicker.Enabled = isValid;
|
||||
_animationSpeedLabel.Enabled = isValid;
|
||||
_animationSpeed.Enabled = isValid;
|
||||
_addButton.Enabled = _editor.PointsCount < MaxAnimationsCount;
|
||||
_removeButton.Enabled = isValid && data1 != Guid.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the editor UI.
|
||||
/// </summary>
|
||||
protected void UpdateUI()
|
||||
public void UpdateUI()
|
||||
{
|
||||
if (_isUpdatingUI)
|
||||
return;
|
||||
_isUpdatingUI = true;
|
||||
|
||||
var selectedIndex = _selectedAnimation.SelectedIndex;
|
||||
var isValid = selectedIndex != -1;
|
||||
var isValid = selectedIndex >= 0 && selectedIndex < _editor.PointsCount;
|
||||
Float4 data0;
|
||||
Guid data1;
|
||||
if (isValid)
|
||||
@@ -549,6 +854,16 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSpawned(SurfaceNodeActions action)
|
||||
{
|
||||
base.OnSpawned(action);
|
||||
|
||||
// Select the first animation to make setup easier
|
||||
OnSelectedAnimationPopupShowing(_selectedAnimation);
|
||||
_selectedAnimation.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnValuesChanged()
|
||||
{
|
||||
@@ -566,67 +881,6 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
private readonly Label _animationXLabel;
|
||||
private readonly FloatValueBox _animationX;
|
||||
private readonly Editor _editor;
|
||||
|
||||
/// <summary>
|
||||
/// The Multi Blend 1D blend space editor.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Surface.Archetypes.BlendPointsEditor" />
|
||||
protected class Editor : BlendPointsEditor
|
||||
{
|
||||
private MultiBlend1D _node;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Editor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="node">The parent Visject Node node.</param>
|
||||
/// <param name="x">The X location.</param>
|
||||
/// <param name="y">The Y location.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
public Editor(MultiBlend1D node, float x, float y, float width, float height)
|
||||
: base(false, x, y, width, height)
|
||||
{
|
||||
_node = node;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void GetData(out Float2 rangeX, out Float2 rangeY, Guid[] pointsAnims, Float2[] pointsLocations)
|
||||
{
|
||||
var data0 = (Float4)_node.Values[0];
|
||||
rangeX = new Float2(data0.X, data0.Y);
|
||||
rangeY = Float2.Zero;
|
||||
for (int i = 0; i < MaxAnimationsCount; i++)
|
||||
{
|
||||
var dataA = (Float4)_node.Values[4 + i * 2];
|
||||
var dataB = (Guid)_node.Values[5 + i * 2];
|
||||
|
||||
pointsAnims[i] = dataB;
|
||||
pointsLocations[i] = new Float2(Mathf.Clamp(dataA.X, rangeX.X, rangeX.Y), 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int SelectedIndex
|
||||
{
|
||||
get => _node.SelectedAnimationIndex;
|
||||
set => _node.SelectedAnimationIndex = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void SetLocation(int index, Float2 location)
|
||||
{
|
||||
var dataA = (Float4)_node.Values[4 + index * 2];
|
||||
var ranges = (Float4)_node.Values[0];
|
||||
|
||||
dataA.X = Mathf.Clamp(location.X, ranges.X, ranges.Y);
|
||||
|
||||
_node.Values[4 + index * 2] = dataA;
|
||||
_node.Surface.MarkAsEdited();
|
||||
|
||||
_node.UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public MultiBlend1D(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
@@ -646,11 +900,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
};
|
||||
_animationX.ValueChanged += OnAnimationXChanged;
|
||||
|
||||
_editor = new Editor(this,
|
||||
FlaxEditor.Surface.Constants.NodeMarginX,
|
||||
_animationX.Bottom + 4.0f,
|
||||
Width - FlaxEditor.Surface.Constants.NodeMarginX * 2.0f,
|
||||
120.0f);
|
||||
var size = Width - FlaxEditor.Surface.Constants.NodeMarginX * 2.0f;
|
||||
_editor = new BlendPointsEditor(this, false, FlaxEditor.Surface.Constants.NodeMarginX, _animationX.Bottom + 4.0f, size, 120.0f);
|
||||
_editor.Parent = this;
|
||||
}
|
||||
|
||||
@@ -670,7 +921,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateUI(int selectedIndex, bool isValid, ref Float4 data0, ref Guid data1)
|
||||
public override void UpdateUI(int selectedIndex, bool isValid, ref Float4 data0, ref Guid data1)
|
||||
{
|
||||
base.UpdateUI(selectedIndex, isValid, ref data0, ref data1);
|
||||
|
||||
@@ -700,68 +951,6 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
private readonly FloatValueBox _animationX;
|
||||
private readonly Label _animationYLabel;
|
||||
private readonly FloatValueBox _animationY;
|
||||
private readonly Editor _editor;
|
||||
|
||||
/// <summary>
|
||||
/// The Multi Blend 2D blend space editor.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Surface.Archetypes.BlendPointsEditor" />
|
||||
protected class Editor : BlendPointsEditor
|
||||
{
|
||||
private MultiBlend2D _node;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Editor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="node">The parent Visject Node node.</param>
|
||||
/// <param name="x">The X location.</param>
|
||||
/// <param name="y">The Y location.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
public Editor(MultiBlend2D node, float x, float y, float width, float height)
|
||||
: base(true, x, y, width, height)
|
||||
{
|
||||
_node = node;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void GetData(out Float2 rangeX, out Float2 rangeY, Guid[] pointsAnims, Float2[] pointsLocations)
|
||||
{
|
||||
var data0 = (Float4)_node.Values[0];
|
||||
rangeX = new Float2(data0.X, data0.Y);
|
||||
rangeY = new Float2(data0.Z, data0.W);
|
||||
for (int i = 0; i < MaxAnimationsCount; i++)
|
||||
{
|
||||
var dataA = (Float4)_node.Values[4 + i * 2];
|
||||
var dataB = (Guid)_node.Values[5 + i * 2];
|
||||
|
||||
pointsAnims[i] = dataB;
|
||||
pointsLocations[i] = new Float2(Mathf.Clamp(dataA.X, rangeX.X, rangeX.Y), Mathf.Clamp(dataA.Y, rangeY.X, rangeY.Y));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int SelectedIndex
|
||||
{
|
||||
get => _node.SelectedAnimationIndex;
|
||||
set => _node.SelectedAnimationIndex = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void SetLocation(int index, Float2 location)
|
||||
{
|
||||
var dataA = (Float4)_node.Values[4 + index * 2];
|
||||
var ranges = (Float4)_node.Values[0];
|
||||
|
||||
dataA.X = Mathf.Clamp(location.X, ranges.X, ranges.Y);
|
||||
dataA.Y = Mathf.Clamp(location.Y, ranges.Z, ranges.W);
|
||||
|
||||
_node.Values[4 + index * 2] = dataA;
|
||||
_node.Surface.MarkAsEdited();
|
||||
|
||||
_node.UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public MultiBlend2D(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
@@ -795,11 +984,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
};
|
||||
_animationY.ValueChanged += OnAnimationYChanged;
|
||||
|
||||
_editor = new Editor(this,
|
||||
FlaxEditor.Surface.Constants.NodeMarginX,
|
||||
_animationY.Bottom + 4.0f,
|
||||
Width - FlaxEditor.Surface.Constants.NodeMarginX * 2.0f,
|
||||
120.0f);
|
||||
var size = Width - FlaxEditor.Surface.Constants.NodeMarginX * 2.0f;
|
||||
_editor = new BlendPointsEditor(this, true, FlaxEditor.Surface.Constants.NodeMarginX, _animationY.Bottom + 4.0f, size, size);
|
||||
_editor.Parent = this;
|
||||
}
|
||||
|
||||
@@ -834,7 +1020,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void UpdateUI(int selectedIndex, bool isValid, ref Float4 data0, ref Guid data1)
|
||||
public override void UpdateUI(int selectedIndex, bool isValid, ref Float4 data0, ref Guid data1)
|
||||
{
|
||||
base.UpdateUI(selectedIndex, isValid, ref data0, ref data1);
|
||||
|
||||
|
||||
@@ -621,7 +621,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Create = (id, context, arch, groupArch) => new MultiBlend1D(id, context, arch, groupArch),
|
||||
Title = "Multi Blend 1D",
|
||||
Description = "Animation blending in 1D",
|
||||
Flags = NodeFlags.AnimGraph,
|
||||
Flags = NodeFlags.AnimGraph | NodeFlags.VariableValuesSize,
|
||||
Size = new Float2(420, 300),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
@@ -633,19 +633,6 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
// Per blend sample data
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
@@ -658,10 +645,10 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Input(2, "Start Position", true, typeof(float), 3, 3),
|
||||
|
||||
// Axis X
|
||||
NodeElementArchetype.Factory.Input(4, "X", true, typeof(float), 4),
|
||||
NodeElementArchetype.Factory.Text(30, 4 * Surface.Constants.LayoutOffsetY, "(min: max: )"),
|
||||
NodeElementArchetype.Factory.Float(60, 4 * Surface.Constants.LayoutOffsetY, 0, 0),
|
||||
NodeElementArchetype.Factory.Float(145, 4 * Surface.Constants.LayoutOffsetY, 0, 1),
|
||||
NodeElementArchetype.Factory.Input(3, "X", true, typeof(float), 4),
|
||||
NodeElementArchetype.Factory.Text(30, 3 * Surface.Constants.LayoutOffsetY + 2, "(min: max: )"),
|
||||
NodeElementArchetype.Factory.Float(60, 3 * Surface.Constants.LayoutOffsetY + 2, 0, 0),
|
||||
NodeElementArchetype.Factory.Float(145, 3 * Surface.Constants.LayoutOffsetY + 2, 0, 1),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
@@ -670,8 +657,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Create = (id, context, arch, groupArch) => new MultiBlend2D(id, context, arch, groupArch),
|
||||
Title = "Multi Blend 2D",
|
||||
Description = "Animation blending in 2D",
|
||||
Flags = NodeFlags.AnimGraph,
|
||||
Size = new Float2(420, 320),
|
||||
Flags = NodeFlags.AnimGraph | NodeFlags.VariableValuesSize,
|
||||
Size = new Float2(420, 620),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
// Node data
|
||||
@@ -682,19 +669,6 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
// Per blend sample data
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
new Float4(0, 0, 0, 1.0f), Guid.Empty,
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
@@ -707,16 +681,16 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Input(2, "Start Position", true, typeof(float), 3, 3),
|
||||
|
||||
// Axis X
|
||||
NodeElementArchetype.Factory.Input(4, "X", true, typeof(float), 4),
|
||||
NodeElementArchetype.Factory.Text(30, 4 * Surface.Constants.LayoutOffsetY, "(min: max: )"),
|
||||
NodeElementArchetype.Factory.Float(60, 4 * Surface.Constants.LayoutOffsetY, 0, 0),
|
||||
NodeElementArchetype.Factory.Float(145, 4 * Surface.Constants.LayoutOffsetY, 0, 1),
|
||||
NodeElementArchetype.Factory.Input(3, "X", true, typeof(float), 4),
|
||||
NodeElementArchetype.Factory.Text(30, 3 * Surface.Constants.LayoutOffsetY + 2, "(min: max: )"),
|
||||
NodeElementArchetype.Factory.Float(60, 3 * Surface.Constants.LayoutOffsetY + 2, 0, 0),
|
||||
NodeElementArchetype.Factory.Float(145, 3 * Surface.Constants.LayoutOffsetY + 2, 0, 1),
|
||||
|
||||
// Axis Y
|
||||
NodeElementArchetype.Factory.Input(5, "Y", true, typeof(float), 5),
|
||||
NodeElementArchetype.Factory.Text(30, 5 * Surface.Constants.LayoutOffsetY, "(min: max: )"),
|
||||
NodeElementArchetype.Factory.Float(60, 5 * Surface.Constants.LayoutOffsetY, 0, 2),
|
||||
NodeElementArchetype.Factory.Float(145, 5 * Surface.Constants.LayoutOffsetY, 0, 3),
|
||||
NodeElementArchetype.Factory.Input(4, "Y", true, typeof(float), 5),
|
||||
NodeElementArchetype.Factory.Text(30, 4 * Surface.Constants.LayoutOffsetY + 2, "(min: max: )"),
|
||||
NodeElementArchetype.Factory.Float(60, 4 * Surface.Constants.LayoutOffsetY + 2, 0, 2),
|
||||
NodeElementArchetype.Factory.Float(145, 4 * Surface.Constants.LayoutOffsetY + 2, 0, 3),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
|
||||
@@ -104,6 +104,16 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTypeDisposing(ScriptType type)
|
||||
{
|
||||
if (_type == type && !IsDisposing)
|
||||
{
|
||||
// Turn into missing script
|
||||
_type = ScriptType.Null;
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnLoaded(SurfaceNodeActions action)
|
||||
{
|
||||
base.OnLoaded(action);
|
||||
@@ -113,6 +123,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
_type = TypeUtils.GetType(typeName);
|
||||
if (_type != null)
|
||||
{
|
||||
_type.TrackLifetime(OnTypeDisposing);
|
||||
TooltipText = Editor.Instance.CodeDocs.GetTooltip(_type);
|
||||
try
|
||||
{
|
||||
|
||||
@@ -73,6 +73,11 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
BehaviorTreeGraph = 1024,
|
||||
|
||||
/// <summary>
|
||||
/// Node can have different amount of items in values array.
|
||||
/// </summary>
|
||||
VariableValuesSize = 2048,
|
||||
|
||||
/// <summary>
|
||||
/// Node can be used in the all visual graphs.
|
||||
/// </summary>
|
||||
|
||||
@@ -951,15 +951,20 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
if (_isDuringValuesEditing || !Surface.CanEdit)
|
||||
return;
|
||||
|
||||
if (values == null || Values == null || values.Length != Values.Length)
|
||||
if (values == null || Values == null)
|
||||
throw new ArgumentException();
|
||||
bool resize = values.Length != Values.Length;
|
||||
if (resize && (Archetype.Flags & NodeFlags.VariableValuesSize) == 0)
|
||||
throw new ArgumentException();
|
||||
|
||||
_isDuringValuesEditing = true;
|
||||
|
||||
var before = Surface.Undo != null ? (object[])Values.Clone() : null;
|
||||
|
||||
Array.Copy(values, Values, values.Length);
|
||||
if (resize)
|
||||
Values = (object[])values.Clone();
|
||||
else
|
||||
Array.Copy(values, Values, values.Length);
|
||||
OnValuesChanged();
|
||||
Surface.MarkAsEdited(graphEdited);
|
||||
|
||||
@@ -1057,6 +1062,20 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseDown(location, button))
|
||||
return true;
|
||||
|
||||
if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
|
||||
return true;
|
||||
if (button == MouseButton.Right)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
@@ -1064,13 +1083,10 @@ namespace FlaxEditor.Surface
|
||||
return true;
|
||||
|
||||
// Close
|
||||
if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0)
|
||||
if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
|
||||
{
|
||||
if (_closeButtonRect.Contains(ref location))
|
||||
{
|
||||
Surface.Delete(this);
|
||||
return true;
|
||||
}
|
||||
Surface.Delete(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Secondary Context Menu
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace FlaxEditor.Surface.Undo
|
||||
private ContextHandle _context;
|
||||
private readonly uint _nodeId;
|
||||
private readonly bool _graphEdited;
|
||||
private readonly bool _resize;
|
||||
private object[] _before;
|
||||
private object[] _after;
|
||||
|
||||
@@ -23,7 +24,8 @@ namespace FlaxEditor.Surface.Undo
|
||||
throw new ArgumentNullException(nameof(before));
|
||||
if (node?.Values == null)
|
||||
throw new ArgumentNullException(nameof(node));
|
||||
if (before.Length != node.Values.Length)
|
||||
_resize = before.Length != node.Values.Length;
|
||||
if (_resize && (node.Archetype.Flags & NodeFlags.VariableValuesSize) == 0)
|
||||
throw new ArgumentException(nameof(before));
|
||||
|
||||
_surface = node.Surface;
|
||||
@@ -48,7 +50,10 @@ namespace FlaxEditor.Surface.Undo
|
||||
throw new Exception("Missing node.");
|
||||
|
||||
node.SetIsDuringValuesEditing(true);
|
||||
Array.Copy(_after, node.Values, _after.Length);
|
||||
if (_resize)
|
||||
node.Values = (object[])_after.Clone();
|
||||
else
|
||||
Array.Copy(_after, node.Values, _after.Length);
|
||||
node.OnValuesChanged();
|
||||
context.MarkAsModified(_graphEdited);
|
||||
node.SetIsDuringValuesEditing(false);
|
||||
@@ -65,7 +70,10 @@ namespace FlaxEditor.Surface.Undo
|
||||
throw new Exception("Missing node.");
|
||||
|
||||
node.SetIsDuringValuesEditing(true);
|
||||
Array.Copy(_before, node.Values, _before.Length);
|
||||
if (_resize)
|
||||
node.Values = (object[])_before.Clone();
|
||||
else
|
||||
Array.Copy(_before, node.Values, _before.Length);
|
||||
node.OnValuesChanged();
|
||||
context.MarkAsModified(_graphEdited);
|
||||
node.SetIsDuringValuesEditing(false);
|
||||
|
||||
@@ -630,6 +630,15 @@ namespace FlaxEditor.Surface
|
||||
stream.ReadCommonValue(ref node.Values[j]);
|
||||
}
|
||||
}
|
||||
else if ((node.Archetype.Flags & NodeFlags.VariableValuesSize) != 0)
|
||||
{
|
||||
node.Values = new object[valuesCnt];
|
||||
for (int j = firstValueReadIdx; j < valuesCnt; j++)
|
||||
{
|
||||
// ReSharper disable once PossibleNullReferenceException
|
||||
stream.ReadCommonValue(ref node.Values[j]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Editor.LogWarning(string.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID));
|
||||
@@ -795,6 +804,12 @@ namespace FlaxEditor.Surface
|
||||
for (int j = firstValueReadIdx; j < valuesCnt; j++)
|
||||
node.Values[j] = stream.ReadVariant();
|
||||
}
|
||||
else if ((node.Archetype.Flags & NodeFlags.VariableValuesSize) != 0)
|
||||
{
|
||||
node.Values = new object[valuesCnt];
|
||||
for (int j = firstValueReadIdx; j < valuesCnt; j++)
|
||||
node.Values[j] = stream.ReadVariant();
|
||||
}
|
||||
else
|
||||
{
|
||||
Editor.LogWarning(string.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID));
|
||||
|
||||
@@ -120,9 +120,9 @@ namespace FlaxEditor.Utilities
|
||||
/// <summary>
|
||||
/// Deletes the creates scenes for the simulation.
|
||||
/// </summary>
|
||||
public void DeletedScenes()
|
||||
public void UnloadScenes()
|
||||
{
|
||||
Profiler.BeginEvent("DuplicateScenes.DeletedScenes");
|
||||
Profiler.BeginEvent("DuplicateScenes.UnloadScenes");
|
||||
Editor.Log("Restoring scene data");
|
||||
|
||||
// TODO: here we can keep changes for actors marked to keep their state after simulation
|
||||
@@ -134,6 +134,8 @@ namespace FlaxEditor.Utilities
|
||||
throw new Exception("Failed to unload scenes.");
|
||||
}
|
||||
FlaxEngine.Scripting.FlushRemovedObjects();
|
||||
Editor.WipeOutLeftoverSceneObjects();
|
||||
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
|
||||
@@ -210,12 +210,17 @@ namespace FlaxEditor.Utilities
|
||||
/// <returns>The duplicated value.</returns>
|
||||
internal static object CloneValue(object value)
|
||||
{
|
||||
// For object references just clone it
|
||||
if (value is FlaxEngine.Object)
|
||||
return value;
|
||||
|
||||
// For objects (eg. arrays) we need to clone them to prevent editing default/reference value within editor
|
||||
if (value != null && (!value.GetType().IsValueType || !value.GetType().IsClass))
|
||||
{
|
||||
var json = JsonSerializer.Serialize(value);
|
||||
value = JsonSerializer.Deserialize(json, value.GetType());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,12 @@ namespace FlaxEditor.Viewport.Previews
|
||||
_hasUILinked = true;
|
||||
}
|
||||
else if (_uiControlLinked != null)
|
||||
{
|
||||
if (_uiControlLinked.Control != null &&
|
||||
_uiControlLinked.Control.Parent == null)
|
||||
_uiControlLinked.Control.Parent = _uiParentLink;
|
||||
_hasUILinked = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void LinkCanvas(Actor actor)
|
||||
|
||||
Reference in New Issue
Block a user