Browse Source

Ellipse node proper algorithm

flabbet 1 year ago
parent
commit
43153f18ba

+ 1 - 1
src/PixiEditor.AvaloniaUI/Data/Localization/Languages/en.json

@@ -644,7 +644,7 @@
   "PIXEL_COORDINATE": "Pixel Coordinate",
   "OUTPUT_NODE": "Output",
   "NOISE_NODE": "Noise",
-  "CIRCLE_NODE": "Circle",
+  "ELLIPSE_NODE": "Ellipse",
   "CREATE_IMAGE_NODE": "Create Image",
   "FOLDER_NODE": "Folder",
   "IMAGE_LAYER_NODE": "Image Layer",

+ 0 - 62
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CircleNode.cs

@@ -1,62 +0,0 @@
-using PixiEditor.ChangeableDocument.Rendering;
-using PixiEditor.DrawingApi.Core.ColorsImpl;
-using PixiEditor.DrawingApi.Core.Surface;
-using PixiEditor.DrawingApi.Core.Surface.PaintImpl;
-using PixiEditor.Numerics;
-
-namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
-
-public class CircleNode : Node
-{
-    public InputProperty<VecI> Radius { get; }
-    public InputProperty<Color> StrokeColor { get; }
-    public InputProperty<Color> FillColor { get; }
-    public InputProperty<int> StrokeWidth { get; }
-    public OutputProperty<Surface> Output { get; }
-    
-    public CircleNode()
-    {
-        Radius = CreateInput<VecI>("Radius", "RADIUS", new VecI(32, 32));
-        StrokeColor = CreateInput<Color>("StrokeColor", "STROKE_COLOR", new Color(0, 0, 0, 255));
-        FillColor = CreateInput<Color>("FillColor", "FILL_COLOR", new Color(0, 0, 0, 255));
-        StrokeWidth = CreateInput<int>("StrokeWidth", "STROKE_WIDTH", 1);
-        Output = CreateOutput<Surface?>("Output", "OUTPUT", null);
-    }
-
-    protected override string NodeUniqueName => "Circle";
-
-    protected override Surface? OnExecute(RenderingContext context)
-    {
-        /*TODO: ChunkyImage*/
-        var radius = Radius.Value / 2;
-        var strokeWidth = StrokeWidth.Value;
-        var strokeOffset = new VecI(strokeWidth / 2);
-        
-        Surface workingSurface = new Surface(Radius.Value + strokeOffset * 2);
-        
-        using Paint paint = new Paint();
-        paint.Color = FillColor.Value;
-        paint.Style = PaintStyle.Fill;
-        
-        workingSurface.DrawingSurface.Canvas.DrawOval(radius + strokeOffset, radius, paint);
-        
-        paint.Color = StrokeColor.Value;
-        paint.StrokeWidth = strokeWidth;
-        paint.Style = PaintStyle.Stroke;
-
-        workingSurface.DrawingSurface.Canvas.DrawOval(radius + strokeOffset, radius, paint);
-
-        Output.Value = workingSurface;
-        
-        return Output.Value;
-    }
-
-    public override string DisplayName { get; set; } = "CIRCLE_NODE";
-
-    public override bool AreInputsLegal()
-    {
-        return Radius.Value is { X: > 0, Y: > 0 } && StrokeWidth.Value > 0;
-    }
-
-    public override Node CreateCopy() => new CircleNode();
-}

+ 79 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/EllipseNode.cs

@@ -0,0 +1,79 @@
+using PixiEditor.ChangeableDocument.Rendering;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.PaintImpl;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
+
+public class EllipseNode : Node
+{
+    public InputProperty<VecI> Radius { get; }
+    public InputProperty<Color> StrokeColor { get; }
+    public InputProperty<Color> FillColor { get; }
+    public InputProperty<int> StrokeWidth { get; }
+    public OutputProperty<Surface> Output { get; }
+
+    private ChunkyImage? workingImage;
+    private Surface? targetSurface;
+
+    private VecI _lastRadius = new VecI(-1, -1);
+    private Color _lastStrokeColor = new Color(0, 0, 0, 0);
+    private Color _lastFillColor = new Color(0, 0, 0, 0);
+    private int _lastStrokeWidth = -1;
+    private Paint replacingPaint = new Paint() { BlendMode = BlendMode.Src };
+
+    public EllipseNode()
+    {
+        Radius = CreateInput<VecI>("Radius", "RADIUS", new VecI(32, 32));
+        StrokeColor = CreateInput<Color>("StrokeColor", "STROKE_COLOR", new Color(0, 0, 0, 255));
+        FillColor = CreateInput<Color>("FillColor", "FILL_COLOR", new Color(0, 0, 0, 255));
+        StrokeWidth = CreateInput<int>("StrokeWidth", "STROKE_WIDTH", 1);
+        Output = CreateOutput<Surface?>("Output", "OUTPUT", null);
+    }
+
+    protected override string NodeUniqueName => "Ellipse";
+
+    protected override Surface? OnExecute(RenderingContext context)
+    {
+        var radius = Radius.Value;
+        VecI targetDimensions = radius * 2;
+
+        if (workingImage is null || workingImage.LatestSize.X != targetDimensions.X ||
+            workingImage.LatestSize.Y != targetDimensions.Y)
+        {
+            workingImage?.Dispose();
+            workingImage = new ChunkyImage(targetDimensions);
+
+            targetSurface = new Surface(targetDimensions);
+        }
+
+        if (radius != _lastRadius || StrokeColor.Value != _lastStrokeColor || FillColor.Value != _lastFillColor ||
+            StrokeWidth.Value != _lastStrokeWidth)
+        {
+            _lastRadius = radius;
+            _lastStrokeColor = StrokeColor.Value;
+            _lastFillColor = FillColor.Value;
+            _lastStrokeWidth = StrokeWidth.Value;
+
+            RectI location = new RectI(VecI.Zero, targetDimensions);
+            workingImage.EnqueueDrawEllipse(location, StrokeColor.Value, FillColor.Value, StrokeWidth.Value);
+            workingImage.CommitChanges();
+        }
+
+        workingImage.DrawMostUpToDateChunkOn(context.ChunkToUpdate, context.ChunkResolution, targetSurface.DrawingSurface, VecI.Zero,
+            replacingPaint);
+
+        Output.Value = targetSurface;
+        return targetSurface;
+    }
+
+    public override string DisplayName { get; set; } = "ELLIPSE_NODE";
+
+    public override bool AreInputsLegal()
+    {
+        return Radius.Value is { X: > 0, Y: > 0 } && StrokeWidth.Value > 0;
+    }
+
+    public override Node CreateCopy() => new EllipseNode();
+}