CreateImageNode.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. using PixiEditor.ChangeableDocument.Rendering;
  2. using Drawie.Backend.Core;
  3. using Drawie.Backend.Core.Bridge;
  4. using Drawie.Backend.Core.ColorsImpl;
  5. using Drawie.Backend.Core.ColorsImpl.Paintables;
  6. using Drawie.Backend.Core.Numerics;
  7. using Drawie.Backend.Core.Surfaces;
  8. using Drawie.Backend.Core.Surfaces.ImageData;
  9. using Drawie.Backend.Core.Surfaces.PaintImpl;
  10. using Drawie.Numerics;
  11. using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
  12. namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
  13. [NodeInfo("CreateImage")]
  14. public class CreateImageNode : Node
  15. {
  16. public OutputProperty<Texture> Output { get; }
  17. public InputProperty<VecI> Size { get; }
  18. public InputProperty<Paintable> Fill { get; }
  19. public RenderInputProperty Content { get; }
  20. public InputProperty<Matrix3X3> ContentMatrix { get; }
  21. public RenderOutputProperty RenderOutput { get; }
  22. private TextureCache textureCache = new();
  23. protected override bool ExecuteOnlyOnCacheChange => true;
  24. protected override CacheTriggerFlags CacheTrigger => CacheTriggerFlags.Inputs;
  25. public CreateImageNode()
  26. {
  27. Output = CreateOutput<Texture>(nameof(Output), "IMAGE", null);
  28. Size = CreateInput(nameof(Size), "SIZE", new VecI(32, 32)).WithRules(v => v.Min(VecI.One));
  29. Fill = CreateInput<Paintable>(nameof(Fill), "FILL", new ColorPaintable(Colors.Transparent));
  30. Content = CreateRenderInput(nameof(Content), "CONTENT");
  31. ContentMatrix = CreateInput<Matrix3X3>(nameof(ContentMatrix), "MATRIX", Matrix3X3.Identity);
  32. RenderOutput = CreateRenderOutput("RenderOutput", "RENDER_OUTPUT", () => new Painter(OnPaint));
  33. }
  34. protected override void OnExecute(RenderContext context)
  35. {
  36. if (Size.Value.X <= 0 || Size.Value.Y <= 0)
  37. {
  38. return;
  39. }
  40. var surface = Render(context);
  41. RenderPreviews(surface, context);
  42. Output.Value = surface;
  43. RenderOutput.ChainToPainterValue();
  44. }
  45. private Texture? Render(RenderContext context)
  46. {
  47. var size = (VecI)(Size.Value * context.ChunkResolution.Multiplier());
  48. if (size.X <= 0 || size.Y <= 0)
  49. {
  50. return null;
  51. }
  52. int id = (Size.Value * context.ChunkResolution.Multiplier()).GetHashCode();
  53. var surface = textureCache.RequestTexture(id, (VecI)(Size.Value * context.ChunkResolution.Multiplier()), context.ProcessingColorSpace, false);
  54. surface.DrawingSurface.Canvas.SetMatrix(Matrix3X3.Identity);
  55. if (Fill.Value is ColorPaintable colorPaintable)
  56. {
  57. surface.DrawingSurface.Canvas.Clear(colorPaintable.Color);
  58. }
  59. else
  60. {
  61. using Paint paint = new Paint();
  62. paint.SetPaintable(Fill.Value);
  63. paint.BlendMode = BlendMode.Src;
  64. surface.DrawingSurface.Canvas.DrawRect(0, 0, Size.Value.X, Size.Value.Y, paint);
  65. }
  66. int saved = surface.DrawingSurface.Canvas.Save();
  67. RenderContext ctx = context.Clone();
  68. ctx.RenderSurface = surface.DrawingSurface.Canvas;
  69. ctx.RenderOutputSize = surface.Size;
  70. ctx.VisibleDocumentRegion = null;
  71. float chunkMultiplier = (float)context.ChunkResolution.Multiplier();
  72. surface.DrawingSurface.Canvas.SetMatrix(
  73. surface.DrawingSurface.Canvas.TotalMatrix.Concat(
  74. Matrix3X3.CreateScale(chunkMultiplier, chunkMultiplier).Concat(ContentMatrix.Value)));
  75. Content.Value?.Paint(ctx, surface.DrawingSurface.Canvas);
  76. surface.DrawingSurface.Canvas.RestoreToCount(saved);
  77. return surface;
  78. }
  79. private void OnPaint(RenderContext context, Canvas surface)
  80. {
  81. if (Output.Value == null || Output.Value.IsDisposed) return;
  82. int saved = surface.Save();
  83. surface.Scale((float)context.ChunkResolution.InvertedMultiplier());
  84. surface.DrawSurface(Output.Value.DrawingSurface, 0, 0);
  85. surface.RestoreToCount(saved);
  86. }
  87. private void RenderPreviews(Texture surface, RenderContext context)
  88. {
  89. var previews = context.GetPreviewTexturesForNode(Id);
  90. if (previews is null) return;
  91. foreach (var request in previews)
  92. {
  93. var texture = request.Texture;
  94. if (texture is null) continue;
  95. int saved = texture.DrawingSurface.Canvas.Save();
  96. VecD scaling = PreviewUtility.CalculateUniformScaling(surface.Size, texture.Size);
  97. VecD offset = PreviewUtility.CalculateCenteringOffset(surface.Size, texture.Size, scaling);
  98. texture.DrawingSurface.Canvas.Translate((float)offset.X, (float)offset.Y);
  99. texture.DrawingSurface.Canvas.Scale((float)scaling.X, (float)scaling.Y);
  100. var previewCtx =
  101. PreviewUtility.CreatePreviewContext(context, scaling, context.RenderOutputSize, texture.Size);
  102. texture.DrawingSurface.Canvas.Clear();
  103. texture.DrawingSurface.Canvas.DrawSurface(surface.DrawingSurface, 0, 0);
  104. texture.DrawingSurface.Canvas.RestoreToCount(saved);
  105. }
  106. }
  107. public override Node CreateCopy() => new CreateImageNode();
  108. public override void Dispose()
  109. {
  110. base.Dispose();
  111. textureCache.Dispose();
  112. }
  113. }