Merge branch 'master' into Visject-DescriptionPanel
This commit is contained in:
@@ -111,6 +111,11 @@ namespace FlaxEditor.CustomEditors
|
||||
/// </summary>
|
||||
public PropertyNameLabel LinkedLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layout for this editor. Used to calculate bounds.
|
||||
/// </summary>
|
||||
public LayoutElementsContainer Layout => _layout;
|
||||
|
||||
internal virtual void Initialize(CustomEditorPresenter presenter, LayoutElementsContainer layout, ValueContainer values)
|
||||
{
|
||||
_layout = layout;
|
||||
|
||||
@@ -38,6 +38,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// </summary>
|
||||
public readonly int Index;
|
||||
|
||||
private Rectangle _arrangeButtonRect;
|
||||
private bool _arrangeButtonInUse;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CollectionItemLabel"/> class.
|
||||
/// </summary>
|
||||
@@ -50,6 +53,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Index = index;
|
||||
|
||||
SetupContextMenu += OnSetupContextMenu;
|
||||
_arrangeButtonRect = new Rectangle(2, 3, 12, 12);
|
||||
|
||||
// Extend margin of the label to support a dragging handle.
|
||||
Margin m = Margin;
|
||||
m.Left += 16;
|
||||
Margin = m;
|
||||
}
|
||||
|
||||
private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkedEditor)
|
||||
@@ -71,6 +80,107 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
b.Enabled = !Editor._readOnly;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnEndMouseCapture()
|
||||
{
|
||||
base.OnEndMouseCapture();
|
||||
|
||||
_arrangeButtonInUse = false;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
|
||||
var mousePosition = PointFromScreen(Input.MouseScreenPosition);
|
||||
var dragBarColor = _arrangeButtonRect.Contains(mousePosition) ? style.Foreground : style.ForegroundGrey;
|
||||
Render2D.DrawSprite(FlaxEditor.Editor.Instance.Icons.DragBar12, _arrangeButtonRect, _arrangeButtonInUse ? Color.Orange : dragBarColor);
|
||||
if (_arrangeButtonInUse && ArrangeAreaCheck(out _, out var arrangeTargetRect))
|
||||
{
|
||||
Render2D.FillRectangle(arrangeTargetRect, style.Selection);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ArrangeAreaCheck(out int index, out Rectangle rect)
|
||||
{
|
||||
var child = Editor.ChildrenEditors[0];
|
||||
var container = child.Layout.ContainerControl;
|
||||
var mousePosition = container.PointFromScreen(Input.MouseScreenPosition);
|
||||
var barSidesExtend = 20.0f;
|
||||
var barHeight = 5.0f;
|
||||
var barCheckAreaHeight = 40.0f;
|
||||
var pos = mousePosition.Y + barCheckAreaHeight * 0.5f;
|
||||
|
||||
for (int i = 0; i < container.Children.Count / 2; i++)
|
||||
{
|
||||
var containerChild = container.Children[i * 2]; // times 2 to skip the value editor
|
||||
if (Mathf.IsInRange(pos, containerChild.Top, containerChild.Top + barCheckAreaHeight) || (i == 0 && pos < containerChild.Top))
|
||||
{
|
||||
index = i;
|
||||
var p1 = containerChild.UpperLeft;
|
||||
rect = new Rectangle(PointFromParent(p1) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var p2 = container.Children[((container.Children.Count / 2) - 1) * 2].BottomLeft;
|
||||
if (pos > p2.Y)
|
||||
{
|
||||
index = (container.Children.Count / 2) - 1;
|
||||
rect = new Rectangle(PointFromParent(p2) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
rect = Rectangle.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonRect.Contains(ref location))
|
||||
{
|
||||
_arrangeButtonInUse = true;
|
||||
Focus();
|
||||
StartMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
if (ArrangeAreaCheck(out var index, out _))
|
||||
{
|
||||
Editor.Shift(Index, index);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
if (_arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
}
|
||||
|
||||
base.OnLostFocus();
|
||||
}
|
||||
|
||||
private void OnMoveUpClicked()
|
||||
{
|
||||
Editor.Move(Index, Index - 1);
|
||||
@@ -106,6 +216,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
private bool _canReorder = true;
|
||||
|
||||
private Rectangle _arrangeButtonRect;
|
||||
private bool _arrangeButtonInUse;
|
||||
|
||||
public void Setup(CollectionEditor editor, int index, bool canReorder = true)
|
||||
{
|
||||
HeaderHeight = 18;
|
||||
@@ -123,10 +236,92 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
MouseButtonRightClicked += OnMouseButtonRightClicked;
|
||||
if (_canReorder)
|
||||
{
|
||||
// TODO: Drag drop
|
||||
HeaderTextMargin = new Margin(18, 0, 0, 0);
|
||||
_arrangeButtonRect = new Rectangle(16, 3, 12, 12);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ArrangeAreaCheck(out int index, out Rectangle rect)
|
||||
{
|
||||
var container = Parent;
|
||||
var mousePosition = container.PointFromScreen(Input.MouseScreenPosition);
|
||||
var barSidesExtend = 20.0f;
|
||||
var barHeight = 5.0f;
|
||||
var barCheckAreaHeight = 40.0f;
|
||||
var pos = mousePosition.Y + barCheckAreaHeight * 0.5f;
|
||||
|
||||
for (int i = 0; i < (container.Children.Count + 1) / 2; i++) // Add 1 to pretend there is a spacer at the end.
|
||||
{
|
||||
var containerChild = container.Children[i * 2]; // times 2 to skip the value editor
|
||||
if (Mathf.IsInRange(pos, containerChild.Top, containerChild.Top + barCheckAreaHeight) || (i == 0 && pos < containerChild.Top))
|
||||
{
|
||||
index = i;
|
||||
var p1 = containerChild.UpperLeft;
|
||||
rect = new Rectangle(PointFromParent(p1) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var p2 = container.Children[container.Children.Count - 1].BottomLeft;
|
||||
if (pos > p2.Y)
|
||||
{
|
||||
index = ((container.Children.Count + 1) / 2) - 1;
|
||||
rect = new Rectangle(PointFromParent(p2) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
rect = Rectangle.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
if (_canReorder)
|
||||
{
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
|
||||
var mousePosition = PointFromScreen(Input.MouseScreenPosition);
|
||||
var dragBarColor = _arrangeButtonRect.Contains(mousePosition) ? style.Foreground : style.ForegroundGrey;
|
||||
Render2D.DrawSprite(FlaxEditor.Editor.Instance.Icons.DragBar12, _arrangeButtonRect, _arrangeButtonInUse ? Color.Orange : dragBarColor);
|
||||
if (_arrangeButtonInUse && ArrangeAreaCheck(out _, out var arrangeTargetRect))
|
||||
{
|
||||
Render2D.FillRectangle(arrangeTargetRect, style.Selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonRect.Contains(ref location))
|
||||
{
|
||||
_arrangeButtonInUse = true;
|
||||
Focus();
|
||||
StartMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
if (ArrangeAreaCheck(out var index, out _))
|
||||
{
|
||||
Editor.Shift(Index, index);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
private void OnMouseButtonRightClicked(DropPanel panel, Float2 location)
|
||||
{
|
||||
if (LinkedEditor == null)
|
||||
@@ -324,7 +519,6 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
(elementType.GetProperties().Length == 1 && elementType.GetFields().Length == 0) ||
|
||||
elementType.Equals(new ScriptType(typeof(JsonAsset))) ||
|
||||
elementType.Equals(new ScriptType(typeof(SettingsBase)));
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
// Apply spacing
|
||||
@@ -440,6 +634,39 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
SetValue(cloned);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shifts the specified item at the given index and moves it through the list to the other item. It supports undo.
|
||||
/// </summary>
|
||||
/// <param name="srcIndex">Index of the source item.</param>
|
||||
/// <param name="dstIndex">Index of the destination to move to.</param>
|
||||
private void Shift(int srcIndex, int dstIndex)
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
|
||||
var cloned = CloneValues();
|
||||
if (dstIndex > srcIndex)
|
||||
{
|
||||
for (int i = srcIndex; i < dstIndex; i++)
|
||||
{
|
||||
var tmp = cloned[i + 1];
|
||||
cloned[i + 1] = cloned[i];
|
||||
cloned[i] = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = srcIndex; i > dstIndex; i--)
|
||||
{
|
||||
var tmp = cloned[i - 1];
|
||||
cloned[i - 1] = cloned[i];
|
||||
cloned[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
SetValue(cloned);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the item at the specified index. It supports undo.
|
||||
/// </summary>
|
||||
|
||||
@@ -1364,6 +1364,7 @@ namespace FlaxEditor
|
||||
public byte AutoReloadScriptsOnMainWindowFocus;
|
||||
public byte ForceScriptCompilationOnStartup;
|
||||
public byte UseAssetImportPathRelative;
|
||||
public byte EnableParticlesPreview;
|
||||
public byte AutoRebuildCSG;
|
||||
public float AutoRebuildCSGTimeoutMs;
|
||||
public byte AutoRebuildNavMesh;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace FlaxEditor.Gizmo
|
||||
{
|
||||
@@ -15,91 +16,120 @@ namespace FlaxEditor.Gizmo
|
||||
[HideInEditor]
|
||||
private sealed class Renderer : PostProcessEffect
|
||||
{
|
||||
private IntPtr _debugDrawContext;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct Data
|
||||
{
|
||||
public Matrix WorldMatrix;
|
||||
public Matrix ViewProjectionMatrix;
|
||||
public Float4 GridColor;
|
||||
public Float3 ViewPos;
|
||||
public float Far;
|
||||
public Float3 Padding;
|
||||
public float GridSize;
|
||||
}
|
||||
|
||||
private static readonly uint[] _triangles =
|
||||
{
|
||||
0, 2, 1, // Face front
|
||||
1, 3, 0,
|
||||
};
|
||||
|
||||
private GPUBuffer[] _vbs = new GPUBuffer[1];
|
||||
private GPUBuffer _vertexBuffer;
|
||||
private GPUBuffer _indexBuffer;
|
||||
private GPUPipelineState _psGrid;
|
||||
private Shader _shader;
|
||||
|
||||
public Renderer()
|
||||
{
|
||||
Order = -100;
|
||||
UseSingleTarget = true;
|
||||
Location = PostProcessEffectLocation.BeforeForwardPass;
|
||||
Location = PostProcessEffectLocation.Default;
|
||||
_shader = FlaxEngine.Content.LoadAsyncInternal<Shader>("Shaders/Editor/Grid");
|
||||
}
|
||||
|
||||
~Renderer()
|
||||
{
|
||||
if (_debugDrawContext != IntPtr.Zero)
|
||||
{
|
||||
DebugDraw.FreeContext(_debugDrawContext);
|
||||
_debugDrawContext = IntPtr.Zero;
|
||||
}
|
||||
Destroy(ref _psGrid);
|
||||
Destroy(ref _vertexBuffer);
|
||||
Destroy(ref _indexBuffer);
|
||||
_shader = null;
|
||||
}
|
||||
|
||||
public override void Render(GPUContext context, ref RenderContext renderContext, GPUTexture input, GPUTexture output)
|
||||
public override unsafe void Render(GPUContext context, ref RenderContext renderContext, GPUTexture input, GPUTexture output)
|
||||
{
|
||||
if (_shader == null)
|
||||
return;
|
||||
Profiler.BeginEventGPU("Editor Grid");
|
||||
|
||||
if (_debugDrawContext == IntPtr.Zero)
|
||||
_debugDrawContext = DebugDraw.AllocateContext();
|
||||
DebugDraw.SetContext(_debugDrawContext);
|
||||
DebugDraw.UpdateContext(_debugDrawContext, 1.0f / Mathf.Max(Engine.FramesPerSecond, 1));
|
||||
|
||||
var viewPos = (Vector3)renderContext.View.Position;
|
||||
var plane = new Plane(Vector3.Zero, Vector3.UnitY);
|
||||
var dst = CollisionsHelper.DistancePlanePoint(ref plane, ref viewPos);
|
||||
|
||||
var options = Editor.Instance.Options.Options;
|
||||
float space = options.Viewport.ViewportGridScale, size;
|
||||
if (dst <= 500.0f)
|
||||
Float3 camPos = renderContext.View.WorldPosition;
|
||||
float gridSize = renderContext.View.Far + 20000;
|
||||
|
||||
// Lazy-init resources
|
||||
if (_vertexBuffer == null)
|
||||
{
|
||||
size = 8000;
|
||||
_vertexBuffer = new GPUBuffer();
|
||||
var desc = GPUBufferDescription.Vertex(sizeof(Float3), 4);
|
||||
_vertexBuffer.Init(ref desc);
|
||||
}
|
||||
else if (dst <= 2000.0f)
|
||||
if (_indexBuffer == null)
|
||||
{
|
||||
space *= 2;
|
||||
size = 8000;
|
||||
_indexBuffer = new GPUBuffer();
|
||||
fixed (uint* ptr = _triangles)
|
||||
{
|
||||
var desc = GPUBufferDescription.Index(sizeof(uint), _triangles.Length, new IntPtr(ptr));
|
||||
_indexBuffer.Init(ref desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (_psGrid == null)
|
||||
{
|
||||
space *= 20;
|
||||
size = 100000;
|
||||
_psGrid = new GPUPipelineState();
|
||||
var desc = GPUPipelineState.Description.Default;
|
||||
desc.BlendMode = BlendingMode.AlphaBlend;
|
||||
desc.CullMode = CullMode.TwoSided;
|
||||
desc.VS = _shader.GPU.GetVS("VS_Grid");
|
||||
desc.PS = _shader.GPU.GetPS("PS_Grid");
|
||||
_psGrid.Init(ref desc);
|
||||
}
|
||||
|
||||
float bigLineIntensity = 0.8f;
|
||||
Color bigColor = Color.Gray * bigLineIntensity;
|
||||
Color color = bigColor * 0.8f;
|
||||
int count = (int)(size / space);
|
||||
int midLine = count / 2;
|
||||
int bigLinesMod = count / 8;
|
||||
|
||||
Vector3 start = new Vector3(0, 0, size * -0.5f);
|
||||
Vector3 end = new Vector3(0, 0, size * 0.5f);
|
||||
|
||||
for (int i = 0; i <= count; i++)
|
||||
// Update vertices of the plane
|
||||
// TODO: perf this operation in a Vertex Shader
|
||||
float y = 1.5f; // Add small bias to reduce Z-fighting with geometry at scene origin
|
||||
var vertices = new Float3[]
|
||||
{
|
||||
start.X = end.X = i * space + start.Z;
|
||||
Color lineColor = color;
|
||||
if (i == midLine)
|
||||
lineColor = Color.Blue * bigLineIntensity;
|
||||
else if (i % bigLinesMod == 0)
|
||||
lineColor = bigColor;
|
||||
DebugDraw.DrawLine(start, end, lineColor);
|
||||
new Float3(-gridSize + camPos.X, y, -gridSize + camPos.Z),
|
||||
new Float3(gridSize + camPos.X, y, gridSize + camPos.Z),
|
||||
new Float3(-gridSize + camPos.X, y, gridSize + camPos.Z),
|
||||
new Float3(gridSize + camPos.X, y, -gridSize + camPos.Z),
|
||||
};
|
||||
fixed (Float3* ptr = vertices)
|
||||
{
|
||||
context.UpdateBuffer(_vertexBuffer, new IntPtr(ptr), (uint)(sizeof(Float3) * vertices.Length));
|
||||
}
|
||||
|
||||
start = new Vector3(size * -0.5f, 0, 0);
|
||||
end = new Vector3(size * 0.5f, 0, 0);
|
||||
|
||||
for (int i = 0; i <= count; i++)
|
||||
// Update constant buffer data
|
||||
var cb = _shader.GPU.GetCB(0);
|
||||
if (cb != IntPtr.Zero)
|
||||
{
|
||||
start.Z = end.Z = i * space + start.X;
|
||||
Color lineColor = color;
|
||||
if (i == midLine)
|
||||
lineColor = Color.Red * bigLineIntensity;
|
||||
else if (i % bigLinesMod == 0)
|
||||
lineColor = bigColor;
|
||||
DebugDraw.DrawLine(start, end, lineColor);
|
||||
var data = new Data();
|
||||
Matrix.Multiply(ref renderContext.View.View, ref renderContext.View.Projection, out var viewProjection);
|
||||
data.WorldMatrix = Matrix.Identity;
|
||||
Matrix.Transpose(ref viewProjection, out data.ViewProjectionMatrix);
|
||||
data.ViewPos = renderContext.View.WorldPosition;
|
||||
data.GridColor = options.Viewport.ViewportGridColor;
|
||||
data.Far = renderContext.View.Far;
|
||||
data.GridSize = options.Viewport.ViewportGridViewDistance;
|
||||
context.UpdateCB(cb, new IntPtr(&data));
|
||||
}
|
||||
|
||||
DebugDraw.Draw(ref renderContext, input.View(), null, true);
|
||||
DebugDraw.SetContext(IntPtr.Zero);
|
||||
// Draw geometry using custom Pixel Shader and Vertex Shader
|
||||
context.BindCB(0, cb);
|
||||
context.BindIB(_indexBuffer);
|
||||
_vbs[0] = _vertexBuffer;
|
||||
context.BindVB(_vbs);
|
||||
context.SetState(_psGrid);
|
||||
context.SetRenderTarget(renderContext.Buffers.DepthBuffer.View(), input.View());
|
||||
context.DrawIndexed((uint)_triangles.Length);
|
||||
|
||||
Profiler.EndEventGPU();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ API_CLASS(Namespace="FlaxEditor", Name="Editor", NoSpawn, NoConstructor) class M
|
||||
byte AutoReloadScriptsOnMainWindowFocus = 1;
|
||||
byte ForceScriptCompilationOnStartup = 1;
|
||||
byte UseAssetImportPathRelative = 1;
|
||||
byte EnableParticlesPreview = 1;
|
||||
byte AutoRebuildCSG = 1;
|
||||
float AutoRebuildCSGTimeoutMs = 50;
|
||||
byte AutoRebuildNavMesh = 1;
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace FlaxEditor.Modules
|
||||
new SearchResult { Name = item.ShortName, Type = assetItem.TypeName, Item = item }
|
||||
};
|
||||
}
|
||||
var actor = FlaxEngine.Object.Find<Actor>(ref id);
|
||||
var actor = FlaxEngine.Object.Find<Actor>(ref id, true);
|
||||
if (actor != null)
|
||||
{
|
||||
return new List<SearchResult>
|
||||
@@ -236,6 +236,16 @@ namespace FlaxEditor.Modules
|
||||
new SearchResult { Name = actor.Name, Type = actor.TypeName, Item = actor }
|
||||
};
|
||||
}
|
||||
var script = FlaxEngine.Object.Find<Script>(ref id, true);
|
||||
if (script != null && script.Actor != null)
|
||||
{
|
||||
string actorPathStart = $"{script.Actor.Name}/";
|
||||
|
||||
return new List<SearchResult>
|
||||
{
|
||||
new SearchResult { Name = $"{actorPathStart}{script.TypeName}", Type = script.TypeName, Item = script }
|
||||
};
|
||||
}
|
||||
}
|
||||
Profiler.BeginEvent("ContentFinding.Search");
|
||||
|
||||
@@ -388,6 +398,13 @@ namespace FlaxEditor.Modules
|
||||
Editor.Instance.SceneEditing.Select(actor);
|
||||
Editor.Instance.Windows.EditWin.Viewport.FocusSelection();
|
||||
break;
|
||||
case Script script:
|
||||
if (script.Actor != null)
|
||||
{
|
||||
Editor.Instance.SceneEditing.Select(script.Actor);
|
||||
Editor.Instance.Windows.EditWin.Viewport.FocusSelection();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -192,6 +192,7 @@ namespace FlaxEditor.Options
|
||||
internalOptions.AutoReloadScriptsOnMainWindowFocus = (byte)(Options.General.AutoReloadScriptsOnMainWindowFocus ? 1 : 0);
|
||||
internalOptions.ForceScriptCompilationOnStartup = (byte)(Options.General.ForceScriptCompilationOnStartup ? 1 : 0);
|
||||
internalOptions.UseAssetImportPathRelative = (byte)(Options.General.UseAssetImportPathRelative ? 1 : 0);
|
||||
internalOptions.EnableParticlesPreview = (byte)(Options.Visual.EnableParticlesPreview ? 1 : 0);
|
||||
internalOptions.AutoRebuildCSG = (byte)(Options.General.AutoRebuildCSG ? 1 : 0);
|
||||
internalOptions.AutoRebuildCSGTimeoutMs = Options.General.AutoRebuildCSGTimeoutMs;
|
||||
internalOptions.AutoRebuildNavMesh = (byte)(Options.General.AutoRebuildNavMesh ? 1 : 0);
|
||||
|
||||
@@ -129,5 +129,19 @@ namespace FlaxEditor.Options
|
||||
[DefaultValue(50.0f), Limit(25.0f, 500.0f, 5.0f)]
|
||||
[EditorDisplay("Defaults"), EditorOrder(220), Tooltip("The default editor viewport grid scale.")]
|
||||
public float ViewportGridScale { get; set; } = 50.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the view distance you can see the grid.
|
||||
/// </summary>
|
||||
[DefaultValue(2500.0f)]
|
||||
[EditorDisplay("Grid"), EditorOrder(300), Tooltip("The maximum distance you will be able to see the grid.")]
|
||||
public float ViewportGridViewDistance { get; set; } = 2500.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the grid color.
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "0.5,0.5,0.5,1.0")]
|
||||
[EditorDisplay("Grid"), EditorOrder(310), Tooltip("The color for the viewport grid.")]
|
||||
public Color ViewportGridColor { get; set; } = new Color(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,5 +59,12 @@ namespace FlaxEditor.Options
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Quality", "Enable MSAA For Debug Draw"), EditorOrder(500), Tooltip("Determines whether enable MSAA for DebugDraw primitives rendering. Helps with pixel aliasing but reduces performance.")]
|
||||
public bool EnableMSAAForDebugDraw { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether show looping particle effects in Editor viewport to simulate in-game look.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Preview"), EditorOrder(1000)]
|
||||
public bool EnableParticlesPreview { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -936,6 +936,142 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 43,
|
||||
Title = "Rotate UV",
|
||||
Description = "Rotates 2D vector by given angle around (0,0) origin",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(250, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float2), 2),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 44,
|
||||
Title = "Cone Gradient",
|
||||
Description = "Creates cone gradient around normalized UVs (range [-1; 1]), angle is in radians (range [0; TwoPi])",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 45,
|
||||
Title = "Cycle Gradient",
|
||||
Description = "Creates 2D sphere mask gradient around normalized UVs (range [-1; 1])",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 20),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 1),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 46,
|
||||
Title = "Falloff and Offset",
|
||||
Description = "",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 60),
|
||||
ConnectionsHints = ConnectionsHint.Numeric,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
0.9f
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "Value", true, typeof(float), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Offset", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(2, "Falloff", true, typeof(float), 2, 1),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 3),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 47,
|
||||
Title = "Linear Gradient",
|
||||
Description = "x = Gradient along X axis, y = Gradient along Y axis",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 60),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
false
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(2, "Mirror", true, typeof(bool), 2, 1),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float2), 3),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 48,
|
||||
Title = "Radial Gradient",
|
||||
Description = "",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 49,
|
||||
Title = "Ring Gradient",
|
||||
Description = "x = InnerMask,y = OuterMask,z = Mask",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 80),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
1.0f,
|
||||
0.8f,
|
||||
0.05f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "OuterBounds", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(2, "InnerBounds", true, typeof(float), 2, 1),
|
||||
NodeElementArchetype.Factory.Input(3, "Falloff", true, typeof(float), 3, 2),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float3), 4),
|
||||
]
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,12 @@ namespace FlaxEditor.Surface
|
||||
return RootContext.GetParameter(name);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnParamReordered()
|
||||
{
|
||||
MarkAsEdited();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnParamCreated(SurfaceParameter param)
|
||||
{
|
||||
|
||||
@@ -350,6 +350,213 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ReorderParamAction : IUndoAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The window reference.
|
||||
/// </summary>
|
||||
public IVisjectSurfaceWindow Window;
|
||||
|
||||
/// <summary>
|
||||
/// The parameters editor for this action.
|
||||
/// </summary>
|
||||
public ParametersEditor Editor;
|
||||
|
||||
/// <summary>
|
||||
/// The old index the parameter was at.
|
||||
/// </summary>
|
||||
public int OldIndex;
|
||||
|
||||
/// <summary>
|
||||
/// The new index the parameter will be at.
|
||||
/// </summary>
|
||||
public int NewIndex;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ActionString => "Reorder Parameter";
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
Window = null;
|
||||
Editor = null;
|
||||
}
|
||||
|
||||
public void Swap(int oldIdx, int newIdx)
|
||||
{
|
||||
if (oldIdx == newIdx)
|
||||
return; // ?
|
||||
|
||||
var parameters = Window.VisjectSurface.Parameters;
|
||||
if (newIdx > oldIdx)
|
||||
{
|
||||
for (int i = oldIdx; i < newIdx; i++)
|
||||
{
|
||||
SurfaceParameter old = parameters[i + 1];
|
||||
parameters[i + 1] = parameters[i];
|
||||
parameters[i] = old;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = oldIdx; i > newIdx; i--)
|
||||
{
|
||||
SurfaceParameter old = parameters[i - 1];
|
||||
parameters[i - 1] = parameters[i];
|
||||
parameters[i] = old;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Do()
|
||||
{
|
||||
Swap(OldIndex, NewIndex);
|
||||
Window.VisjectSurface.OnParamReordered();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Undo()
|
||||
{
|
||||
Swap(NewIndex, OldIndex);
|
||||
Window.VisjectSurface.OnParamReordered();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom draggable property name label that handles reordering visject parameters.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.CustomEditors.GUI.DraggablePropertyNameLabel" />
|
||||
[HideInEditor]
|
||||
public class ParameterPropertyNameLabel : DraggablePropertyNameLabel
|
||||
{
|
||||
private ParametersEditor _editor;
|
||||
private IVisjectSurfaceWindow _window;
|
||||
private Rectangle _arrangeButtonRect;
|
||||
private bool _arrangeButtonInUse;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ParameterPropertyNameLabel(string name, ParametersEditor editor)
|
||||
: base(name)
|
||||
{
|
||||
_editor = editor;
|
||||
_window = _editor.Values[0] as IVisjectSurfaceWindow;
|
||||
_arrangeButtonRect = new Rectangle(2, 3, 12, 12);
|
||||
|
||||
// Extend margin of the label to support a dragging handle
|
||||
Margin m = Margin;
|
||||
m.Left += 16;
|
||||
Margin = m;
|
||||
}
|
||||
|
||||
private bool ArrangeAreaCheck(out int index, out Rectangle rect)
|
||||
{
|
||||
var child = _editor.ChildrenEditors[0];
|
||||
var container = child.Layout.ContainerControl;
|
||||
var mousePosition = container.PointFromScreen(Input.MouseScreenPosition);
|
||||
var barSidesExtend = 20.0f;
|
||||
var barHeight = 5.0f;
|
||||
var barCheckAreaHeight = 40.0f;
|
||||
var pos = mousePosition.Y + barCheckAreaHeight * 0.5f;
|
||||
|
||||
for (int i = 0; i < container.Children.Count / 2; i++)
|
||||
{
|
||||
var containerChild = container.Children[i * 2]; // times 2 to skip the value editor
|
||||
if (Mathf.IsInRange(pos, containerChild.Top, containerChild.Top + barCheckAreaHeight) || (i == 0 && pos < containerChild.Top))
|
||||
{
|
||||
index = i;
|
||||
var p1 = containerChild.UpperLeft;
|
||||
rect = new Rectangle(PointFromParent(p1) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var p2 = container.Children[((container.Children.Count / 2) - 1) * 2].BottomLeft;
|
||||
if (pos > p2.Y)
|
||||
{
|
||||
index = (container.Children.Count / 2) - 1;
|
||||
rect = new Rectangle(PointFromParent(p2) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
rect = Rectangle.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
var style = Style.Current;
|
||||
var mousePosition = PointFromScreen(Input.MouseScreenPosition);
|
||||
var dragBarColor = _arrangeButtonRect.Contains(mousePosition) ? style.Foreground : style.ForegroundGrey;
|
||||
Render2D.DrawSprite(Editor.Instance.Icons.DragBar12, _arrangeButtonRect, _arrangeButtonInUse ? Color.Orange : dragBarColor);
|
||||
if (_arrangeButtonInUse && ArrangeAreaCheck(out _, out var arrangeTargetRect))
|
||||
{
|
||||
Render2D.FillRectangle(arrangeTargetRect, style.Selection);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonRect.Contains(ref location))
|
||||
{
|
||||
_arrangeButtonInUse = true;
|
||||
Focus();
|
||||
StartMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
ArrangeAreaCheck(out var index, out _);
|
||||
var action = new ReorderParamAction
|
||||
{
|
||||
OldIndex = (int)Tag,
|
||||
NewIndex = index,
|
||||
Window = _window,
|
||||
Editor = _editor
|
||||
};
|
||||
action.Do();
|
||||
_window.Undo.AddAction(action);
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
if (_arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
}
|
||||
|
||||
base.OnLostFocus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSizeChanged()
|
||||
{
|
||||
base.OnSizeChanged();
|
||||
|
||||
// Center the drag button vertically
|
||||
_arrangeButtonRect = new Rectangle(2, Mathf.Ceil((Height - 12) * 0.5f) + 1, 12, 12);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom editor for editing Visject Surface parameters collection.
|
||||
/// </summary>
|
||||
@@ -431,10 +638,10 @@ namespace FlaxEditor.Surface
|
||||
attributes
|
||||
);
|
||||
|
||||
var propertyLabel = new DraggablePropertyNameLabel(name)
|
||||
var propertyLabel = new ParameterPropertyNameLabel(name, this)
|
||||
{
|
||||
Tag = pIndex,
|
||||
Drag = OnDragParameter
|
||||
Drag = OnDragParameter,
|
||||
};
|
||||
if (!p.IsPublic)
|
||||
propertyLabel.TextColor = propertyLabel.TextColor.RGBMultiplied(0.7f);
|
||||
|
||||
Reference in New Issue
Block a user