ModifyImageRightNode.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. using PixiEditor.ChangeableDocument.Changeables.Animations;
  2. using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
  3. using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
  4. using PixiEditor.ChangeableDocument.Changeables.Interfaces;
  5. using PixiEditor.ChangeableDocument.Rendering;
  6. using PixiEditor.DrawingApi.Core;
  7. using PixiEditor.DrawingApi.Core.ColorsImpl;
  8. using PixiEditor.DrawingApi.Core.Shaders;
  9. using PixiEditor.DrawingApi.Core.Surfaces;
  10. using PixiEditor.DrawingApi.Core.Surfaces.PaintImpl;
  11. using PixiEditor.Numerics;
  12. namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
  13. [NodeInfo("ModifyImageRight")]
  14. [PairNode(typeof(ModifyImageLeftNode), "ModifyImageZone")]
  15. public class ModifyImageRightNode : Node, IPairNodeEnd
  16. {
  17. public Node StartNode { get; set; }
  18. private Paint drawingPaint = new Paint() { BlendMode = BlendMode.Src };
  19. public FuncInputProperty<VecD> Coordinate { get; }
  20. public FuncInputProperty<Color> Color { get; }
  21. public OutputProperty<Texture> Output { get; }
  22. public override string DisplayName { get; set; } = "MODIFY_IMAGE_RIGHT_NODE";
  23. private Texture surface;
  24. private string _lastSksl;
  25. public ModifyImageRightNode()
  26. {
  27. Coordinate = CreateFuncInput(nameof(Coordinate), "UV", new VecD());
  28. Color = CreateFuncInput(nameof(Color), "COLOR", new Color());
  29. Output = CreateOutput<Texture>(nameof(Output), "OUTPUT", null);
  30. }
  31. protected override Texture? OnExecute(RenderingContext renderingContext)
  32. {
  33. if (StartNode == null)
  34. {
  35. FindStartNode();
  36. if (StartNode == null)
  37. {
  38. return null;
  39. }
  40. }
  41. var startNode = StartNode as ModifyImageLeftNode;
  42. if (startNode.Image.Value is not { Size: var size })
  43. {
  44. return null;
  45. }
  46. var width = size.X;
  47. var height = size.Y;
  48. if (surface == null || surface.Size != size)
  49. {
  50. surface?.Dispose();
  51. surface = new Texture(size);
  52. surface.DrawingSurface.Canvas.Clear();
  53. }
  54. if (!surface.IsHardwareAccelerated)
  55. {
  56. startNode.PreparePixmap(renderingContext);
  57. using Pixmap targetPixmap = surface.PeekReadOnlyPixels();
  58. ModifyImageInParallel(renderingContext, targetPixmap, width, height);
  59. startNode.DisposePixmap(renderingContext);
  60. }
  61. else
  62. {
  63. ShaderBuilder builder = new();
  64. builder.WithTexture("original", startNode.Image.Value);
  65. string sksl = builder.ToSkSl();
  66. if (sksl != _lastSksl)
  67. {
  68. _lastSksl = sksl;
  69. drawingPaint.Shader = builder.BuildShader();
  70. }
  71. surface.DrawingSurface.Canvas.DrawPaint(drawingPaint);
  72. }
  73. Output.Value = surface;
  74. return Output.Value;
  75. }
  76. private unsafe void ModifyImageInParallel(RenderingContext renderingContext, Pixmap targetPixmap, int width, int height)
  77. {
  78. int threads = Environment.ProcessorCount;
  79. int chunkHeight = height / threads;
  80. Parallel.For(0, threads, i =>
  81. {
  82. FuncContext context = new(renderingContext);
  83. int startY = i * chunkHeight;
  84. int endY = (i + 1) * chunkHeight;
  85. if (i == threads - 1)
  86. {
  87. endY = height;
  88. }
  89. Half* drawArray = (Half*)targetPixmap.GetPixels();
  90. for (int y = startY; y < endY; y++)
  91. {
  92. for (int x = 0; x < width; x++)
  93. {
  94. context.UpdateContext(new VecD((double)x / width, (double)y / height), new VecI(width, height));
  95. var coordinate = Coordinate.Value(context);
  96. context.UpdateContext(coordinate, new VecI(width, height));
  97. var color = Color.Value(context);
  98. ulong colorBits = color.ToULong();
  99. int pixelOffset = (y * width + x) * 4;
  100. Half* drawPixel = drawArray + pixelOffset;
  101. *(ulong*)drawPixel = colorBits;
  102. }
  103. }
  104. });
  105. }
  106. private void FindStartNode()
  107. {
  108. TraverseBackwards(node =>
  109. {
  110. if (node is ModifyImageLeftNode leftNode)
  111. {
  112. StartNode = leftNode;
  113. return false;
  114. }
  115. return true;
  116. });
  117. }
  118. public override Node CreateCopy() => new ModifyImageRightNode();
  119. }