|
|
@@ -1,10 +1,15 @@
|
|
|
using Avalonia;
|
|
|
-using ChunkyImageLib.Operations;
|
|
|
-using Drawie.Backend.Core.Numerics;
|
|
|
+using Avalonia.Input;
|
|
|
+using Drawie.Backend.Core.Surfaces;
|
|
|
+using Drawie.Backend.Core.Surfaces.ImageData;
|
|
|
using Drawie.Backend.Core.Surfaces.PaintImpl;
|
|
|
using Drawie.Backend.Core.Vector;
|
|
|
using PixiEditor.Extensions.UI.Overlays;
|
|
|
using Drawie.Numerics;
|
|
|
+using PixiEditor.ChangeableDocument.Changeables.Animations;
|
|
|
+using PixiEditor.ChangeableDocument.Changeables.Brushes;
|
|
|
+using PixiEditor.ChangeableDocument.Rendering.ContextData;
|
|
|
+using PixiEditor.UI.Common.Extensions;
|
|
|
using PixiEditor.Views.Rendering;
|
|
|
using Canvas = Drawie.Backend.Core.Surfaces.Canvas;
|
|
|
using Colors = Drawie.Backend.Core.ColorsImpl.Colors;
|
|
|
@@ -13,10 +18,6 @@ namespace PixiEditor.Views.Overlays.BrushShapeOverlay;
|
|
|
#nullable enable
|
|
|
internal class BrushShapeOverlay : Overlay
|
|
|
{
|
|
|
- public static readonly StyledProperty<float> BrushSizeProperty =
|
|
|
- AvaloniaProperty.Register<BrushShapeOverlay, float>(nameof(BrushSize), defaultValue: 1);
|
|
|
-
|
|
|
-
|
|
|
public static readonly StyledProperty<Scene> SceneProperty = AvaloniaProperty.Register<BrushShapeOverlay, Scene>(
|
|
|
nameof(Scene));
|
|
|
|
|
|
@@ -24,6 +25,36 @@ internal class BrushShapeOverlay : Overlay
|
|
|
AvaloniaProperty.Register<BrushShapeOverlay, VectorPath?>(
|
|
|
nameof(BrushShape));
|
|
|
|
|
|
+ public static readonly StyledProperty<KeyFrameTime> ActiveFrameTimeProperty =
|
|
|
+ AvaloniaProperty.Register<BrushShapeOverlay, KeyFrameTime>(
|
|
|
+ nameof(ActiveFrameTime));
|
|
|
+
|
|
|
+ public static readonly StyledProperty<Func<EditorData>> EditorDataProperty =
|
|
|
+ AvaloniaProperty.Register<BrushShapeOverlay, Func<EditorData>>(
|
|
|
+ nameof(EditorData));
|
|
|
+
|
|
|
+ public Func<EditorData> EditorData
|
|
|
+ {
|
|
|
+ get => GetValue(EditorDataProperty);
|
|
|
+ set => SetValue(EditorDataProperty, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ public KeyFrameTime ActiveFrameTime
|
|
|
+ {
|
|
|
+ get => GetValue(ActiveFrameTimeProperty);
|
|
|
+ set => SetValue(ActiveFrameTimeProperty, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static readonly StyledProperty<BrushData> BrushDataProperty =
|
|
|
+ AvaloniaProperty.Register<BrushShapeOverlay, BrushData>(
|
|
|
+ nameof(BrushData));
|
|
|
+
|
|
|
+ public BrushData BrushData
|
|
|
+ {
|
|
|
+ get => GetValue(BrushDataProperty);
|
|
|
+ set => SetValue(BrushDataProperty, value);
|
|
|
+ }
|
|
|
+
|
|
|
public VectorPath? BrushShape
|
|
|
{
|
|
|
get => GetValue(BrushShapeProperty);
|
|
|
@@ -36,22 +67,20 @@ internal class BrushShapeOverlay : Overlay
|
|
|
set => SetValue(SceneProperty, value);
|
|
|
}
|
|
|
|
|
|
- public float BrushSize
|
|
|
- {
|
|
|
- get => (float)GetValue(BrushSizeProperty);
|
|
|
- set => SetValue(BrushSizeProperty, value);
|
|
|
- }
|
|
|
-
|
|
|
private Paint paint = new Paint() { Color = Colors.LightGray, StrokeWidth = 1, Style = PaintStyle.Stroke };
|
|
|
- private VecD lastMousePos = new();
|
|
|
|
|
|
+ private VecD lastDirCalculationPoint;
|
|
|
private float lastSize;
|
|
|
- private VectorPath lastNonTranslatedCircle;
|
|
|
+ private PointerInfo lastPointerInfo;
|
|
|
|
|
|
+ private ChangeableDocument.Changeables.Brushes.BrushEngine engine = new();
|
|
|
|
|
|
static BrushShapeOverlay()
|
|
|
{
|
|
|
- AffectsOverlayRender(BrushShapeProperty, BrushSizeProperty);
|
|
|
+ AffectsOverlayRender(BrushShapeProperty, BrushDataProperty, ActiveFrameTimeProperty, EditorDataProperty);
|
|
|
+ BrushDataProperty.Changed.AddClassHandler<BrushShapeOverlay>((overlay, args) => UpdateBrush(args));
|
|
|
+ ActiveFrameTimeProperty.Changed.AddClassHandler<BrushShapeOverlay>((overlay, args) => UpdateBrush(args));
|
|
|
+ EditorDataProperty.Changed.AddClassHandler<BrushShapeOverlay>((overlay, args) => UpdateBrush(args));
|
|
|
}
|
|
|
|
|
|
public BrushShapeOverlay()
|
|
|
@@ -59,16 +88,56 @@ internal class BrushShapeOverlay : Overlay
|
|
|
IsHitTestVisible = false;
|
|
|
}
|
|
|
|
|
|
+ private static void UpdateBrush(AvaloniaPropertyChangedEventArgs args)
|
|
|
+ {
|
|
|
+ BrushShapeOverlay overlay = args.Sender as BrushShapeOverlay;
|
|
|
+ if (overlay == null) return;
|
|
|
+ overlay.UpdateBrushShape(overlay.lastDirCalculationPoint);
|
|
|
+ overlay.Refresh();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ExecuteBrush(VecD pos)
|
|
|
+ {
|
|
|
+ if (VecD.Distance(lastDirCalculationPoint, pos) > 1)
|
|
|
+ {
|
|
|
+ lastDirCalculationPoint = lastDirCalculationPoint.Lerp(pos, 0.5f);
|
|
|
+ }
|
|
|
+
|
|
|
+ VecD dir = lastDirCalculationPoint - pos;
|
|
|
+ VecD vecDir = new VecD(dir.X, dir.Y);
|
|
|
+ VecD dirNormalized = vecDir.Length > 0 ? vecDir.Normalize() : lastPointerInfo.MovementDirection;
|
|
|
+
|
|
|
+ PointerInfo pointer = new PointerInfo(pos, 1, 0, VecD.Zero, dirNormalized);
|
|
|
+
|
|
|
+ engine.ExecuteBrush(null, BrushData, pos, ActiveFrameTime,
|
|
|
+ ColorSpace.CreateSrgb(), SamplingOptions.Default, pointer, new KeyboardInfo(), EditorData?.Invoke() ?? new EditorData(Colors.White, Colors.Black));
|
|
|
+ }
|
|
|
+
|
|
|
protected override void OnOverlayPointerMoved(OverlayPointerArgs args)
|
|
|
{
|
|
|
- if (BrushShape == null)
|
|
|
- return;
|
|
|
+ if (!args.Properties.IsLeftButtonPressed && BrushData.BrushGraph != null)
|
|
|
+ {
|
|
|
+ ExecuteBrush(args.Point);
|
|
|
+ }
|
|
|
|
|
|
- VecD rawPoint = args.Point;
|
|
|
- lastMousePos = rawPoint;
|
|
|
+ UpdateBrushShape(args.Point);
|
|
|
+
|
|
|
+ Refresh();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void OnKeyPressed(KeyEventArgs args)
|
|
|
+ {
|
|
|
+ UpdateBrushShape(lastDirCalculationPoint);
|
|
|
Refresh();
|
|
|
}
|
|
|
|
|
|
+ private void UpdateBrushShape(VecD pos)
|
|
|
+ {
|
|
|
+ if (BrushData.BrushGraph == null) return;
|
|
|
+
|
|
|
+ BrushShape = engine.EvaluateShape(pos, BrushData);
|
|
|
+ }
|
|
|
+
|
|
|
protected override void OnRenderOverlay(Canvas context, RectD canvasBounds) => Render(context);
|
|
|
|
|
|
public void Render(Canvas targetCanvas)
|