ModifyImageRightNode.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
  2. using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
  3. using PixiEditor.ChangeableDocument.Rendering;
  4. using Drawie.Backend.Core;
  5. using Drawie.Backend.Core.Numerics;
  6. using Drawie.Backend.Core.Shaders.Generation;
  7. using Drawie.Backend.Core.Shaders.Generation.Expressions;
  8. using Drawie.Backend.Core.Surfaces;
  9. using Drawie.Backend.Core.Surfaces.PaintImpl;
  10. using Drawie.Numerics;
  11. namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
  12. [NodeInfo("ModifyImageRight")]
  13. [PairNode(typeof(ModifyImageLeftNode), "ModifyImageZone")]
  14. public class ModifyImageRightNode : RenderNode, IPairNode, ICustomShaderNode
  15. {
  16. public Guid OtherNode { get; set; }
  17. private Paint drawingPaint = new Paint() { BlendMode = BlendMode.SrcOver };
  18. public FuncInputProperty<Float2> Coordinate { get; }
  19. public FuncInputProperty<Half4> Color { get; }
  20. private string _lastSksl;
  21. private VecI? size;
  22. // TODO: Add caching
  23. // Caching requires a way to check if any connected node changed, checking inputs for this node works
  24. // Also gather uniforms without doing full string builder generation of the shader
  25. public ModifyImageRightNode()
  26. {
  27. Coordinate = CreateFuncInput(nameof(Coordinate), "UV", new Float2("coords"));
  28. Color = CreateFuncInput(nameof(Color), "COLOR", new Half4(""));
  29. RendersInAbsoluteCoordinates = true;
  30. }
  31. protected override void OnPaint(RenderContext renderContext, Canvas targetSurface)
  32. {
  33. if (OtherNode == null || OtherNode == default)
  34. {
  35. OtherNode = FindStartNode()?.Id ?? default;
  36. if (OtherNode == null || OtherNode == default)
  37. {
  38. return;
  39. }
  40. }
  41. var startNode = FindStartNode();
  42. if (startNode == null)
  43. {
  44. return;
  45. }
  46. OtherNode = startNode.Id;
  47. if (startNode.Image.Value is not { Size: var imgSize })
  48. {
  49. return;
  50. }
  51. size = imgSize;
  52. ShaderBuilder builder = new(size.Value, startNode.NormalizeCoordinates.Value);
  53. FuncContext context = new(renderContext, builder);
  54. if (Coordinate.Connection != null)
  55. {
  56. var coordinate = Coordinate.Value(context);
  57. if (string.IsNullOrEmpty(coordinate.VariableName))
  58. {
  59. builder.SetConstant(context.SamplePosition, coordinate);
  60. }
  61. else
  62. {
  63. builder.Set(context.SamplePosition, coordinate);
  64. }
  65. }
  66. else
  67. {
  68. var constCoords = Coordinate.NonOverridenValue(FuncContext.NoContext);
  69. constCoords.VariableName = "constCords";
  70. builder.AddUniform(constCoords.VariableName, constCoords.ConstantValue);
  71. builder.Set(context.SamplePosition, constCoords);
  72. }
  73. if (Color.Connection != null)
  74. {
  75. builder.ReturnVar(Color.Value(context), false);
  76. }
  77. else
  78. {
  79. Half4 color = Color.NonOverridenValue(FuncContext.NoContext);
  80. color.VariableName = "color";
  81. builder.AddUniform(color.VariableName, color.ConstantValue);
  82. builder.ReturnVar(color, false);
  83. }
  84. string sksl = builder.ToSkSl();
  85. if (sksl != _lastSksl)
  86. {
  87. _lastSksl = sksl;
  88. drawingPaint?.Shader?.Dispose();
  89. drawingPaint.Shader = builder.BuildShader();
  90. }
  91. else
  92. {
  93. drawingPaint.Shader = drawingPaint.Shader.WithUpdatedUniforms(builder.Uniforms);
  94. }
  95. targetSurface.DrawRect(0, 0, size.Value.X, size.Value.Y, drawingPaint);
  96. builder.Dispose();
  97. }
  98. public override RectD? GetPreviewBounds(RenderContext ctx, string elementToRenderName)
  99. {
  100. return size.HasValue ? new RectD(0, 0, size.Value.X, size.Value.Y) : null;
  101. }
  102. public override void RenderPreview(DrawingSurface renderOn, RenderContext context, string elementToRenderName)
  103. {
  104. var startNode = FindStartNode();
  105. if (drawingPaint != null && startNode is { Image.Value: not null })
  106. {
  107. using var tmpTex = Texture.ForProcessing(startNode.Image.Value.Size, context.ProcessingColorSpace);
  108. tmpTex.DrawingSurface.Canvas.DrawRect(0, 0, startNode.Image.Value.Size.X, startNode.Image.Value.Size.Y, drawingPaint);
  109. renderOn.Canvas.DrawSurface(tmpTex.DrawingSurface, 0, 0);
  110. }
  111. }
  112. public override void Dispose()
  113. {
  114. base.Dispose();
  115. drawingPaint?.Dispose();
  116. }
  117. private ModifyImageLeftNode FindStartNode()
  118. {
  119. ModifyImageLeftNode startNode = null;
  120. TraverseBackwards(node =>
  121. {
  122. if (node is ModifyImageLeftNode leftNode)
  123. {
  124. startNode = leftNode;
  125. return false;
  126. }
  127. return true;
  128. });
  129. return startNode;
  130. }
  131. public override Node CreateCopy() => new ModifyImageRightNode();
  132. }