|
@@ -7,6 +7,7 @@ using Drawie.Backend.Core.Surfaces.ImageData;
|
|
|
using Drawie.Backend.Core.Surfaces.PaintImpl;
|
|
using Drawie.Backend.Core.Surfaces.PaintImpl;
|
|
|
using Drawie.Backend.Core.Vector;
|
|
using Drawie.Backend.Core.Vector;
|
|
|
using Drawie.Numerics;
|
|
using Drawie.Numerics;
|
|
|
|
|
+using PixiEditor.ChangeableDocument.Changeables.Animations;
|
|
|
using PixiEditor.ChangeableDocument.Changeables.Brushes;
|
|
using PixiEditor.ChangeableDocument.Changeables.Brushes;
|
|
|
using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
|
|
using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
|
|
|
using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
|
|
using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
|
|
@@ -25,7 +26,9 @@ public class BrushOutputNode : Node
|
|
|
public const string NodeId = "BrushOutput";
|
|
public const string NodeId = "BrushOutput";
|
|
|
public const string BrushNameProperty = "BrushName";
|
|
public const string BrushNameProperty = "BrushName";
|
|
|
public const string FitToStrokeSizeProperty = "FitToStrokeSize";
|
|
public const string FitToStrokeSizeProperty = "FitToStrokeSize";
|
|
|
- public const int AutoGeneratedPreviewSize = 128;
|
|
|
|
|
|
|
+ public const int PointPreviewSize = 50;
|
|
|
|
|
+ public const int StrokePreviewSizeX = 200;
|
|
|
|
|
+ public const int StrokePreviewSizeY = 50;
|
|
|
|
|
|
|
|
public InputProperty<string> BrushName { get; }
|
|
public InputProperty<string> BrushName { get; }
|
|
|
public InputProperty<ShapeVectorData> VectorShape { get; }
|
|
public InputProperty<ShapeVectorData> VectorShape { get; }
|
|
@@ -45,7 +48,8 @@ public class BrushOutputNode : Node
|
|
|
|
|
|
|
|
public InputProperty<IReadOnlyNodeGraph> Previous { get; }
|
|
public InputProperty<IReadOnlyNodeGraph> Previous { get; }
|
|
|
|
|
|
|
|
- public Texture AutoGeneratedPreview { get; private set; }
|
|
|
|
|
|
|
+ public Texture PointPreviewTexture { get; private set; }
|
|
|
|
|
+ public Texture StrokePreviewTexture { get; private set; }
|
|
|
|
|
|
|
|
internal Texture ContentTexture;
|
|
internal Texture ContentTexture;
|
|
|
|
|
|
|
@@ -133,24 +137,18 @@ public class BrushOutputNode : Node
|
|
|
previewChunkyImage = new ChunkyImage(new VecI(200, 200), context.ProcessingColorSpace);
|
|
previewChunkyImage = new ChunkyImage(new VecI(200, 200), context.ProcessingColorSpace);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (previewVectorPath == null)
|
|
|
|
|
- {
|
|
|
|
|
- previewVectorPath = VectorPath.FromSvgPath(previewSvg);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
RectI rect;
|
|
RectI rect;
|
|
|
|
|
|
|
|
previewChunkyImage.EnqueueClear();
|
|
previewChunkyImage.EnqueueClear();
|
|
|
previewChunkyImage.CommitChanges();
|
|
previewChunkyImage.CommitChanges();
|
|
|
|
|
|
|
|
- float pressure;
|
|
|
|
|
int maxSize = 50;
|
|
int maxSize = 50;
|
|
|
float offset = 0;
|
|
float offset = 0;
|
|
|
|
|
|
|
|
int[] sizes = new int[] { 10, 25, 50 };
|
|
int[] sizes = new int[] { 10, 25, 50 };
|
|
|
const int spacing = 10;
|
|
const int spacing = 10;
|
|
|
const int marginEdges = 30;
|
|
const int marginEdges = 30;
|
|
|
- VecD pos;
|
|
|
|
|
|
|
+ VecD pos = VecD.Zero;
|
|
|
for (var i = 0; i < sizes.Length; i++)
|
|
for (var i = 0; i < sizes.Length; i++)
|
|
|
{
|
|
{
|
|
|
var size = sizes[i];
|
|
var size = sizes[i];
|
|
@@ -165,14 +163,31 @@ public class BrushOutputNode : Node
|
|
|
new EditorData(Colors.White, Colors.Black));
|
|
new EditorData(Colors.White, Colors.Black));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- while (offset <= previewChunkyImage.CommittedSize.X)
|
|
|
|
|
|
|
+ DrawStrokePreview(previewChunkyImage, context, maxSize);
|
|
|
|
|
+
|
|
|
|
|
+ previewChunkyImage.CommitChanges();
|
|
|
|
|
+ previewChunkyImage.DrawCommittedChunkOn(
|
|
|
|
|
+ VecI.Zero, ChunkResolution.Full, surface.Canvas, VecD.Zero);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void DrawStrokePreview(ChunkyImage target, RenderContext context, int maxSize, VecD shift = default)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (previewVectorPath == null)
|
|
|
|
|
+ {
|
|
|
|
|
+ previewVectorPath = VectorPath.FromSvgPath(previewSvg);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ float offset = 0;
|
|
|
|
|
+ float pressure;
|
|
|
|
|
+ VecD pos;
|
|
|
|
|
+ while (offset <= target.CommittedSize.X)
|
|
|
{
|
|
{
|
|
|
- pressure = (float)Math.Sin((offset / previewChunkyImage.CommittedSize.X) * Math.PI);
|
|
|
|
|
|
|
+ pressure = (float)Math.Sin((offset / target.CommittedSize.X) * Math.PI);
|
|
|
var vec4D = previewVectorPath.GetPositionAndTangentAtDistance(offset, false);
|
|
var vec4D = previewVectorPath.GetPositionAndTangentAtDistance(offset, false);
|
|
|
pos = vec4D.XY;
|
|
pos = vec4D.XY;
|
|
|
- pos = new VecD(pos.X, pos.Y + maxSize / 2f);
|
|
|
|
|
|
|
+ pos = new VecD(pos.X, pos.Y + maxSize / 2f) + shift;
|
|
|
|
|
|
|
|
- previewEngine.ExecuteBrush(previewChunkyImage,
|
|
|
|
|
|
|
+ previewEngine.ExecuteBrush(target,
|
|
|
new BrushData(context.Graph, Id) { StrokeWidth = maxSize, AntiAliasing = true },
|
|
new BrushData(context.Graph, Id) { StrokeWidth = maxSize, AntiAliasing = true },
|
|
|
[(VecI)pos], context.FrameTime, context.ProcessingColorSpace, context.DesiredSamplingOptions,
|
|
[(VecI)pos], context.FrameTime, context.ProcessingColorSpace, context.DesiredSamplingOptions,
|
|
|
new PointerInfo(pos, pressure, 0, VecD.Zero, vec4D.ZW),
|
|
new PointerInfo(pos, pressure, 0, VecD.Zero, vec4D.ZW),
|
|
@@ -181,40 +196,80 @@ public class BrushOutputNode : Node
|
|
|
|
|
|
|
|
offset += 1;
|
|
offset += 1;
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- previewChunkyImage.CommitChanges();
|
|
|
|
|
- previewChunkyImage.DrawCommittedChunkOn(
|
|
|
|
|
- VecI.Zero, ChunkResolution.Full, surface.Canvas, VecD.Zero);
|
|
|
|
|
|
|
+ private void DrawPointPreview(ChunkyImage img, RenderContext context, int size, VecD pos)
|
|
|
|
|
+ {
|
|
|
|
|
+ previewEngine.ExecuteBrush(img,
|
|
|
|
|
+ new BrushData(context.Graph, Id) { StrokeWidth = size, AntiAliasing = true },
|
|
|
|
|
+ pos, context.FrameTime, context.ProcessingColorSpace, context.DesiredSamplingOptions,
|
|
|
|
|
+ new PointerInfo(pos, 1, 0, VecD.Zero, new VecD(0, 1)),
|
|
|
|
|
+ new KeyboardInfo(),
|
|
|
|
|
+ new EditorData(Colors.White, Colors.Black));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (AutoGeneratedPreview == null || AutoGeneratedPreview.Size.X != AutoGeneratedPreviewSize ||
|
|
|
|
|
- AutoGeneratedPreview.Size.Y != AutoGeneratedPreviewSize)
|
|
|
|
|
|
|
+ private void GeneratePreviews(IReadOnlyDocument doc)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (PointPreviewTexture == null || PointPreviewTexture.Size.X != PointPreviewSize ||
|
|
|
|
|
+ PointPreviewTexture.Size.Y != PointPreviewSize)
|
|
|
{
|
|
{
|
|
|
- AutoGeneratedPreview?.Dispose();
|
|
|
|
|
- AutoGeneratedPreview = Texture.ForDisplay(new VecI(AutoGeneratedPreviewSize));
|
|
|
|
|
|
|
+ PointPreviewTexture?.Dispose();
|
|
|
|
|
+ PointPreviewTexture = Texture.ForDisplay(new VecI(PointPreviewSize, PointPreviewSize));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- AutoGeneratedPreview.DrawingSurface.Canvas.Clear();
|
|
|
|
|
- AutoGeneratedPreview.DrawingSurface.Canvas.Save();
|
|
|
|
|
- AutoGeneratedPreview.DrawingSurface.Canvas.Scale(
|
|
|
|
|
- AutoGeneratedPreviewSize / (float)previewChunkyImage.CommittedSize.X,
|
|
|
|
|
- AutoGeneratedPreviewSize / (float)previewChunkyImage.CommittedSize.Y);
|
|
|
|
|
- previewChunkyImage.DrawCommittedChunkOn(
|
|
|
|
|
- VecI.Zero, ChunkResolution.Full, AutoGeneratedPreview.DrawingSurface.Canvas, VecD.Zero, null, SamplingOptions.Bilinear);
|
|
|
|
|
- AutoGeneratedPreview.DrawingSurface.Canvas.Restore();
|
|
|
|
|
|
|
+ if (StrokePreviewTexture == null || StrokePreviewTexture.Size.X != StrokePreviewSizeX ||
|
|
|
|
|
+ StrokePreviewTexture.Size.Y != StrokePreviewSizeY)
|
|
|
|
|
+ {
|
|
|
|
|
+ StrokePreviewTexture?.Dispose();
|
|
|
|
|
+ StrokePreviewTexture = Texture.ForDisplay(new VecI(StrokePreviewSizeX, StrokePreviewSizeY));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ PointPreviewTexture.DrawingSurface.Canvas.Clear();
|
|
|
|
|
+ StrokePreviewTexture.DrawingSurface.Canvas.Clear();
|
|
|
|
|
+
|
|
|
|
|
+ RenderContext context = new RenderContext(PointPreviewTexture.DrawingSurface.Canvas, 0, ChunkResolution.Full,
|
|
|
|
|
+ new VecI(PointPreviewSize, PointPreviewSize), new VecI(PointPreviewSize), ColorSpace.CreateSrgb(),
|
|
|
|
|
+ SamplingOptions.Default,
|
|
|
|
|
+ doc.NodeGraph);
|
|
|
|
|
+
|
|
|
|
|
+ using var chunkyImage = new ChunkyImage(new VecI(PointPreviewSize, PointPreviewSize), context.ProcessingColorSpace);
|
|
|
|
|
+
|
|
|
|
|
+ DrawPointPreview(chunkyImage, context, PointPreviewSize, new VecD(PointPreviewSize / 2f, PointPreviewSize / 2f));
|
|
|
|
|
+ chunkyImage.CommitChanges();
|
|
|
|
|
+ chunkyImage.DrawCommittedChunkOn(
|
|
|
|
|
+ VecI.Zero, ChunkResolution.Full, PointPreviewTexture.DrawingSurface.Canvas, VecD.Zero);
|
|
|
|
|
+
|
|
|
|
|
+ context.RenderOutputSize = new VecI(StrokePreviewSizeX, StrokePreviewSizeY);
|
|
|
|
|
+ context.DocumentSize = new VecI(StrokePreviewSizeX, StrokePreviewSizeY);
|
|
|
|
|
+ context.RenderSurface = StrokePreviewTexture.DrawingSurface.Canvas;
|
|
|
|
|
+
|
|
|
|
|
+ using var strokeChunkyImage = new ChunkyImage(new VecI(StrokePreviewSizeX, StrokePreviewSizeY), context.ProcessingColorSpace);
|
|
|
|
|
+ DrawStrokePreview(strokeChunkyImage, context, StrokePreviewSizeY / 2, new VecD(0, -88));
|
|
|
|
|
+ strokeChunkyImage.CommitChanges();
|
|
|
|
|
+ strokeChunkyImage.DrawCommittedChunkOn(
|
|
|
|
|
+ VecI.Zero, ChunkResolution.Full, StrokePreviewTexture.DrawingSurface.Canvas, VecD.Zero);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public override void SerializeAdditionalData(Dictionary<string, object> additionalData)
|
|
|
|
|
|
|
+ public override void SerializeAdditionalData(IReadOnlyDocument target, Dictionary<string, object> additionalData)
|
|
|
{
|
|
{
|
|
|
- base.SerializeAdditionalData(additionalData);
|
|
|
|
|
- additionalData["PreviewTexture"] = AutoGeneratedPreview;
|
|
|
|
|
|
|
+ base.SerializeAdditionalData(target, additionalData);
|
|
|
|
|
+ GeneratePreviews(target);
|
|
|
|
|
+ additionalData["PointPreviewTexture"] = PointPreviewTexture;
|
|
|
|
|
+ additionalData["StrokePreviewTexture"] = StrokePreviewTexture;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- internal override void DeserializeAdditionalData(IReadOnlyDocument target, IReadOnlyDictionary<string, object> data, List<IChangeInfo> infos)
|
|
|
|
|
|
|
+ internal override void DeserializeAdditionalData(IReadOnlyDocument target, IReadOnlyDictionary<string, object> data,
|
|
|
|
|
+ List<IChangeInfo> infos)
|
|
|
{
|
|
{
|
|
|
base.DeserializeAdditionalData(target, data, infos);
|
|
base.DeserializeAdditionalData(target, data, infos);
|
|
|
- if (data.TryGetValue("PreviewTexture", out var texObj) && texObj is Texture tex)
|
|
|
|
|
|
|
+ if (data.TryGetValue("PointPreviewTexture", out var texObj) && texObj is Texture tex)
|
|
|
{
|
|
{
|
|
|
- AutoGeneratedPreview = tex;
|
|
|
|
|
|
|
+ PointPreviewTexture = tex;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (data.TryGetValue("StrokePreviewTexture", out var strokeTexObj) && strokeTexObj is Texture strokeTex)
|
|
|
|
|
+ {
|
|
|
|
|
+ StrokePreviewTexture = strokeTex;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -227,6 +282,11 @@ public class BrushOutputNode : Node
|
|
|
public override void Dispose()
|
|
public override void Dispose()
|
|
|
{
|
|
{
|
|
|
previewEngine.Dispose();
|
|
previewEngine.Dispose();
|
|
|
|
|
+ previewChunkyImage?.Dispose();
|
|
|
|
|
+ previewChunkyImage = null;
|
|
|
|
|
+
|
|
|
|
|
+ previewVectorPath?.Dispose();
|
|
|
|
|
+ previewVectorPath = null;
|
|
|
cache.Dispose();
|
|
cache.Dispose();
|
|
|
base.Dispose();
|
|
base.Dispose();
|
|
|
}
|
|
}
|