Browse Source

Do not premultiply modify image node

Krzysztof Krysiński 1 month ago
parent
commit
1993b88841

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit a9fa6e00850ed1ec88eb57e0af7e36179ef3b24c
+Subproject commit f89aba0bedd4d7800bdd32c4095ee5ec5e5432dd

+ 2 - 14
src/PixiEditor.ChangeableDocument/Changeables/Graph/Context/FuncContext.cs

@@ -56,10 +56,10 @@ public class FuncContext
         SamplePosition = Builder.ConstructFloat2(OriginalPosition.X, OriginalPosition.Y);
     }
 
-    public Half4 SampleSurface(DrawingSurface surface, Expression pos, ColorSampleMode sampleMode)
+    public Half4 SampleSurface(DrawingSurface surface, Expression pos, ColorSampleMode sampleMode, bool normalizedCoordinates)
     {
         SurfaceSampler texName = Builder.AddOrGetSurface(surface, sampleMode);
-        return Builder.Sample(texName, pos);
+        return Builder.Sample(texName, pos, normalizedCoordinates);
     }
 
     public Float2 NewFloat2(Expression x, Expression y)
@@ -388,16 +388,4 @@ public class FuncContext
 
         return Builder.AssignNewFloat3x3(matrixExpression);
     }
-
-    public void AssignTo<T>(T variable, Expression assignment) where T : ShaderExpressionVariable
-    {
-        if (!HasContext) throw new NoNodeFuncContextException();
-
-        if (assignment is null)
-        {
-            throw new ArgumentNullException(nameof(assignment));
-        }
-
-        Builder.AssignVariable(variable, assignment);
-    }
 }

+ 11 - 6
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/OffsetNode.cs

@@ -22,20 +22,25 @@ public class OffsetNode : Matrix3X3BaseNode
         Float1 one = new Float1("") { ConstantValue = 1.0 };
         Float1 zero = new Float1("") { ConstantValue = 0.0 };
 
-        var translationMatrix = ctx.NewFloat3x3(
-            one, zero, translation.X,
-            zero, one, translation.Y,
-            zero, zero, one
-        );
 
         if (ctx.HasContext)
         {
+            var translationMatrix = ctx.NewFloat3x3(
+                one, zero, zero,
+                zero, one, zero,
+                translation.X, translation.Y, one
+            );
+
             return ctx.NewFloat3x3(ShaderMath.PostConcat(input, translationMatrix));
         }
 
+        Matrix3X3 contextlessTranslationMatrix = Matrix3X3.CreateTranslation(
+            (float)(translation.X.GetConstant() as double? ?? 0.0),
+            (float)(translation.Y.GetConstant() as double? ?? 0.0)
+        );
         return new Float3x3("")
         {
-            ConstantValue = input.ConstantValue.PostConcat(translationMatrix.ConstantValue)
+            ConstantValue = input.ConstantValue.PostConcat(contextlessTranslationMatrix)
         };
     }
 

+ 3 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ModifyImageLeftNode.cs

@@ -21,6 +21,7 @@ public class ModifyImageLeftNode : Node, IPairNode, IPreviewRenderable
     public FuncOutputProperty<Half4> Color { get; }
     
     public InputProperty<ColorSampleMode> SampleMode { get; }
+    public InputProperty<bool> NormalizeCoordinates { get; }
 
     public Guid OtherNode { get; set; }
     
@@ -30,6 +31,7 @@ public class ModifyImageLeftNode : Node, IPairNode, IPreviewRenderable
         Coordinate = CreateFuncOutput("Coordinate", "UV", ctx => ctx.OriginalPosition ?? new Float2(""));
         Color = CreateFuncOutput("Color", "COLOR", GetColor);
         SampleMode = CreateInput("SampleMode", "COLOR_SAMPLE_MODE", ColorSampleMode.ColorManaged);
+        NormalizeCoordinates = CreateInput("NormalizeCoordinates", "NORMALIZE_COORDINATES", true);
     }
     
     private Half4 GetColor(FuncContext context)
@@ -41,7 +43,7 @@ public class ModifyImageLeftNode : Node, IPairNode, IPreviewRenderable
             return new Half4("") { ConstantValue = Colors.Transparent };
         }
 
-        return context.SampleSurface(Image.Value.DrawingSurface, context.SamplePosition, SampleMode.Value);
+        return context.SampleSurface(Image.Value.DrawingSurface, context.SamplePosition, SampleMode.Value, NormalizeCoordinates.Value);
     }
 
     protected override void OnExecute(RenderContext context)

+ 3 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ModifyImageRightNode.cs

@@ -63,7 +63,7 @@ public class ModifyImageRightNode : RenderNode, IPairNode, ICustomShaderNode
 
         size = imgSize;
 
-        ShaderBuilder builder = new(size.Value);
+        ShaderBuilder builder = new(size.Value, startNode.NormalizeCoordinates.Value);
         FuncContext context = new(renderContext, builder);
 
         if (Coordinate.Connection != null)
@@ -88,14 +88,14 @@ public class ModifyImageRightNode : RenderNode, IPairNode, ICustomShaderNode
 
         if (Color.Connection != null)
         {
-            builder.ReturnVar(Color.Value(context));
+            builder.ReturnVar(Color.Value(context), false);
         }
         else
         {
             Half4 color = Color.NonOverridenValue(FuncContext.NoContext);
             color.VariableName = "color";
             builder.AddUniform(color.VariableName, color.ConstantValue);
-            builder.ReturnVar(color);
+            builder.ReturnVar(color, false); // Do not premultiply, since we are modifying already premultiplied image
         }
 
         string sksl = builder.ToSkSl();

+ 18 - 6
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/SampleImageNode.cs

@@ -20,12 +20,15 @@ public class SampleImageNode : Node
 
     public InputProperty<ColorSampleMode> SampleMode { get; }
 
+    public InputProperty<bool> NormalizedCoordinates { get; }
+
     public SampleImageNode()
     {
-        Image = CreateInput<Texture>(nameof(Texture), "IMAGE", null);
-        Coordinate = CreateFuncInput<Float2>(nameof(Coordinate), "UV", VecD.Zero);
-        Color = CreateFuncOutput(nameof(Color), "COLOR", GetColor);
-        SampleMode = CreateInput(nameof(SampleMode), "COLOR_SAMPLE_MODE", ColorSampleMode.ColorManaged);
+        Image = CreateInput<Texture>("Texture", "IMAGE", null);
+        Coordinate = CreateFuncInput<Float2>("Coordinate", "UV", VecD.Zero);
+        Color = CreateFuncOutput("Color", "COLOR", GetColor);
+        SampleMode = CreateInput("SampleMode", "COLOR_SAMPLE_MODE", ColorSampleMode.ColorManaged);
+        NormalizedCoordinates = CreateInput("NormalizedCoordinates", "NORMALIZED_COORDINATES", true);
     }
 
     private Half4 GetColor(FuncContext context)
@@ -39,11 +42,20 @@ public class SampleImageNode : Node
         {
             Expression uv = context.GetValue(Coordinate);
 
-            return context.SampleSurface(Image.Value.DrawingSurface, uv, SampleMode.Value);
+            return context.SampleSurface(Image.Value.DrawingSurface, uv, SampleMode.Value, NormalizedCoordinates.Value);
         }
 
         Color color;
-        VecI pixelCoordinate = (VecI)context.GetValue(Coordinate).ConstantValue.Round();
+
+        VecD coordinate = context.GetValue(Coordinate).ConstantValue;
+        VecI pixelCoordinate = (VecI)coordinate.Round();
+
+        if(NormalizedCoordinates.Value)
+        {
+            VecD size = Image.Value.Size;
+            pixelCoordinate = (VecI)(new VecD(coordinate.X * size.X, coordinate.Y * size.Y)).Round();
+        }
+
         if (SampleMode.Value == ColorSampleMode.ColorManaged)
         {
             color = Image.Value.GetSRGBPixel(pixelCoordinate);

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

@@ -1087,5 +1087,7 @@
   "PERSPECTIVE_1": "Perspective 1",
   "PERSPECTIVE_2": "Perspective 2",
   "COMPOSE_MATRIX": "Compose Matrix",
-  "DECOMPOSE_MATRIX": "Decompose Matrix"
+  "DECOMPOSE_MATRIX": "Decompose Matrix",
+  "NORMALIZE_COORDINATES": "Normalize Coordinates",
+  "TRANSFORMED_POSITION": "Transformed Position"
 }

+ 13 - 3
tests/PixiEditor.Tests/RenderTests.cs

@@ -35,7 +35,12 @@ public class RenderTests : FullPixiEditorTest
     [InlineData("VectorWithSepiaFilter")]
     [InlineData("VectorWithSepiaFilterSrgb")]
     [InlineData("VectorWithSepiaFilterChained")]
-    public void TestThatPixiFilesRenderTheSameResultAsSavedPng(string fileName)
+    [InlineData("Offset")]
+    [InlineData("Scale")]
+    [InlineData("Rotation")]
+    [InlineData("MatrixChain")]
+    [InlineData("GpuOffset", "Offset")]
+    public void TestThatPixiFilesRenderTheSameResultAsSavedPng(string fileName, string? resultName = null)
     {
         if (!DrawingBackendApi.Current.IsHardwareAccelerated)
         {
@@ -44,7 +49,7 @@ public class RenderTests : FullPixiEditorTest
         }
 
         string pixiFile = Path.Combine("TestFiles", "RenderTests", fileName + ".pixi");
-        string pngFile = Path.Combine("TestFiles", "RenderTests", fileName + ".png");
+        string pngFile = Path.Combine("TestFiles", "RenderTests", (resultName ?? fileName) + ".png");
         var document = Importer.ImportDocument(pixiFile);
 
         Assert.NotNull(pngFile);
@@ -55,11 +60,16 @@ public class RenderTests : FullPixiEditorTest
 
         using var image = result.AsT1;
 
+        using var snapshot = image.DrawingSurface.Snapshot();
+        using var encoded = snapshot.Encode();
+
+        using var renderedToCompare = Surface.Load(encoded.AsSpan().ToArray());
+
         using var toCompareTo = Importer.ImportImage(pngFile, document.SizeBindable);
 
         Assert.NotNull(toCompareTo);
 
-        Assert.True(PixelCompare(image, toCompareTo));
+        Assert.True(PixelCompare(renderedToCompare, toCompareTo));
     }
 
     [AvaloniaTheory]

BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/ComposeMatrix.pixi


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/ComposeMatrix.png


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/GpuOffset.pixi


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/MatrixChain.pixi


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/MatrixChain.png


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/Offset.pixi


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/Offset.png


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/Rotation.pixi


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/Rotation.png


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/Scale.pixi


BIN
tests/PixiEditor.Tests/TestFiles/RenderTests/Scale.png