Browse Source

Added compose and decompose matrix nodes, func matrix

Krzysztof Krysiński 1 month ago
parent
commit
785601b629

+ 59 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Context/FuncContext.cs

@@ -4,6 +4,7 @@ using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 using PixiEditor.ChangeableDocument.Rendering;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core.ColorsImpl;
+using Drawie.Backend.Core.Numerics;
 using Drawie.Backend.Core.Shaders.Generation;
 using Drawie.Backend.Core.Shaders.Generation.Expressions;
 using Drawie.Backend.Core.Surfaces;
@@ -329,4 +330,62 @@ public class FuncContext
 
         return val;
     }
+
+    public Float3x3 GetValue(FuncInputProperty<Float3x3> getFrom)
+    {
+        if (HasContext)
+        {
+            if (getFrom.Connection == null || !IsFuncType(getFrom))
+            {
+                Float3x3 value = getFrom.Value(this);
+                value.VariableName = $"float3x3_{Builder.GetUniqueNameNumber()}";
+                Builder.AddUniform(value.VariableName, value.ConstantValue);
+                return value;
+            }
+
+            if (_cachedValues.TryGetValue(getFrom, out ShaderExpressionVariable cachedValue))
+            {
+                if (cachedValue is Float3x3 float3x3)
+                {
+                    return float3x3;
+                }
+            }
+        }
+
+        var val = getFrom.Value(this);
+        _cachedValues[getFrom] = val;
+
+        return val;
+    }
+
+    public Float3x3 NewFloat3x3(Expression m00, Expression m01, Expression m02,
+        Expression m10, Expression m11, Expression m12,
+        Expression m20, Expression m21, Expression m22)
+    {
+        if (!HasContext && m00 is Float1 firstFloat && m01 is Float1 secondFloat && m02 is Float1 thirdFloat &&
+            m10 is Float1 fourthFloat && m11 is Float1 fifthFloat && m12 is Float1 sixthFloat &&
+            m20 is Float1 seventhFloat && m21 is Float1 eighthFloat && m22 is Float1 ninthFloat)
+        {
+            Float3x3 constantMatrix = new Float3x3("");
+            constantMatrix.ConstantValue = new Matrix3X3(
+                (float)firstFloat.ConstantValue, (float)secondFloat.ConstantValue, (float)thirdFloat.ConstantValue,
+                (float)fourthFloat.ConstantValue, (float)fifthFloat.ConstantValue, (float)sixthFloat.ConstantValue,
+                (float)seventhFloat.ConstantValue, (float)eighthFloat.ConstantValue, (float)ninthFloat.ConstantValue);
+            return constantMatrix;
+        }
+
+        return Builder.ConstructFloat3x3(m00, m01, m02, m10, m11, m12, m20, m21, m22);
+    }
+
+    public Float3x3 NewFloat3x3(Expression matrixExpression)
+    {
+        if (!HasContext && matrixExpression is Float3x3 float3x3)
+        {
+            Float3x3 constantMatrix = new Float3x3("");
+            constantMatrix.ConstantValue = float3x3.ConstantValue;
+            return constantMatrix;
+        }
+
+        return Builder.AssignNewFloat3x3(matrixExpression);
+    }
 }

+ 99 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/ComposeMatrixNode.cs

@@ -0,0 +1,99 @@
+using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Shaders.Generation.Expressions;
+using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
+using PixiEditor.ChangeableDocument.Rendering;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
+
+[NodeInfo("ComposeMatrix")]
+public class ComposeMatrixNode : Node
+{
+    public FuncInputProperty<Float3x3> MatrixInput { get; }
+    public FuncInputProperty<Float1> ScaleX { get; }
+    public FuncInputProperty<Float1> SkewX { get; }
+    public FuncInputProperty<Float1> TransX { get; }
+    public FuncInputProperty<Float1> SkewY { get; }
+    public FuncInputProperty<Float1> ScaleY { get; }
+    public FuncInputProperty<Float1> TransY { get; }
+    public FuncInputProperty<Float1> Persp0 { get; }
+    public FuncInputProperty<Float1> Persp1 { get; }
+    public FuncInputProperty<Float1> Persp2 { get; }
+
+    public FuncOutputProperty<Float3x3> Matrix { get; }
+
+    public ComposeMatrixNode()
+    {
+        MatrixInput = CreateFuncInput<Float3x3>("MatrixInput", "INPUT_MATRIX",
+            new Float3x3("") { ConstantValue = Matrix3X3.Identity });
+
+        ScaleX = CreateFuncInput<Float1>("ScaleX", "SCALE_X", 1.0f);
+        ScaleY = CreateFuncInput<Float1>("ScaleY", "SCALE_Y", 1.0f);
+        SkewX = CreateFuncInput<Float1>("SkewX", "SKEW_X", 0.0f);
+        SkewY = CreateFuncInput<Float1>("SkewY", "SKEW_Y", 0.0f);
+        TransX = CreateFuncInput<Float1>("TranslateX", "TRANSLATE_X", 0.0f);
+        TransY = CreateFuncInput<Float1>("TranslateY", "TRANSLATE_Y", 0.0f);
+        Persp0 = CreateFuncInput<Float1>("Perspective0", "PERSPECTIVE_0", 0.0f);
+        Persp1 = CreateFuncInput<Float1>("Perspective1", "PERSPECTIVE_1", 0.0f);
+        Persp2 = CreateFuncInput<Float1>("Perspective2", "PERSPECTIVE_2", 1.0f);
+
+        Matrix = CreateFuncOutput<Float3x3>("Matrix", "MATRIX", ComposeMatrix);
+    }
+
+    private Float3x3 ComposeMatrix(FuncContext context)
+    {
+        if (context.HasContext)
+        {
+            var composed = context.NewFloat3x3(
+                context.GetValue(ScaleX),
+                context.GetValue(SkewX),
+                context.GetValue(TransX),
+                context.GetValue(SkewY),
+                context.GetValue(ScaleY),
+                context.GetValue(TransY),
+                context.GetValue(Persp0),
+                context.GetValue(Persp1),
+                context.GetValue(Persp2)
+            );
+
+            if (MatrixInput.Connection != null)
+            {
+                return context.NewFloat3x3(ShaderMath.PostConcat(context.GetValue(MatrixInput), composed));
+            }
+
+            return composed;
+        }
+
+        var mtx = new Float3x3("")
+        {
+            ConstantValue
+                = new Matrix3X3(
+                    (float)(context.GetValue(ScaleX).GetConstant() as double? ?? 1.0),
+                    (float)(context.GetValue(SkewX).GetConstant() as double? ?? 0.0),
+                    (float)(context.GetValue(TransX).GetConstant() as double? ?? 0.0),
+                    (float)(context.GetValue(SkewY).GetConstant() as double? ?? 0.0),
+                    (float)(context.GetValue(ScaleY).GetConstant() as double? ?? 1.0),
+                    (float)(context.GetValue(TransY).GetConstant() as double? ?? 0.0),
+                    (float)(context.GetValue(Persp0).GetConstant() as double? ?? 0.0),
+                    (float)(context.GetValue(Persp1).GetConstant() as double? ?? 0.0),
+                    (float)(context.GetValue(Persp2).GetConstant() as double? ?? 1.0))
+        };
+
+        if (MatrixInput.Connection != null)
+        {
+            mtx.ConstantValue = mtx.ConstantValue.PostConcat(
+                (context.GetValue(MatrixInput).ConstantValue as Matrix3X3?) ?? Matrix3X3.Identity);
+        }
+
+        return mtx;
+    }
+
+    protected override void OnExecute(RenderContext context)
+    {
+    }
+
+    public override Node CreateCopy()
+    {
+        return new ComposeMatrixNode();
+    }
+}

+ 47 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/DecomposeMatrixNode.cs

@@ -0,0 +1,47 @@
+using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Shaders.Generation.Expressions;
+using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Rendering;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
+
+[NodeInfo("DecomposeMatrix")]
+public class DecomposeMatrixNode : Node
+{
+    public FuncInputProperty<Float3x3> Matrix { get; }
+
+    public FuncOutputProperty<Float1> ScaleX { get; }
+    public FuncOutputProperty<Float1> SkewX { get; }
+    public FuncOutputProperty<Float1> TransX { get; }
+    public FuncOutputProperty<Float1> SkewY { get; }
+    public FuncOutputProperty<Float1> ScaleY { get; }
+    public FuncOutputProperty<Float1> TransY { get; }
+    public FuncOutputProperty<Float1> Persp0 { get; }
+    public FuncOutputProperty<Float1> Persp1 { get; }
+    public FuncOutputProperty<Float1> Persp2 { get; }
+
+    public DecomposeMatrixNode()
+    {
+        Matrix = CreateFuncInput<Float3x3>("Matrix", "MATRIX",
+            new Float3x3("") { ConstantValue = Matrix3X3.Identity });
+        ScaleX = CreateFuncOutput<Float1>("ScaleX", "SCALE_X", context => context.GetValue(Matrix).M11);
+        ScaleY = CreateFuncOutput<Float1>("ScaleY", "SCALE_Y", context => context.GetValue(Matrix).M22);
+        SkewX = CreateFuncOutput<Float1>("SkewX", "SKEW_X", context => context.GetValue(Matrix).M12);
+        SkewY = CreateFuncOutput<Float1>("SkewY", "SKEW_Y", context => context.GetValue(Matrix).M21);
+        TransX = CreateFuncOutput<Float1>("TranslateX", "TRANSLATE_X", context => context.GetValue(Matrix).M13);
+        TransY = CreateFuncOutput<Float1>("TranslateY", "TRANSLATE_Y", context => context.GetValue(Matrix).M23);
+        Persp0 = CreateFuncOutput<Float1>("Perspective0", "PERSPECTIVE_0", context => context.GetValue(Matrix).M31);
+        Persp1 = CreateFuncOutput<Float1>("Perspective1", "PERSPECTIVE_1", context => context.GetValue(Matrix).M32);
+        Persp2 = CreateFuncOutput<Float1>("Perspective2", "PERSPECTIVE_2", context => context.GetValue(Matrix).M33);
+    }
+
+    protected override void OnExecute(RenderContext context)
+    {
+
+    }
+
+    public override Node CreateCopy()
+    {
+        return new DecomposeMatrixNode();
+    }
+}

+ 12 - 7
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/Matrix3X3BaseNode.cs

@@ -1,7 +1,9 @@
 using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Shaders.Generation.Expressions;
 using Drawie.Backend.Core.Surfaces;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 using PixiEditor.ChangeableDocument.Rendering;
 
@@ -10,21 +12,22 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
 public abstract class Matrix3X3BaseNode : RenderNode, IRenderInput
 {
     public RenderInputProperty Background { get; }
-    public InputProperty<Matrix3X3> Input { get; }
-    public OutputProperty<Matrix3X3> Matrix { get; }
+    public FuncInputProperty<Float3x3> Input { get; }
+    public FuncOutputProperty<Float3x3> Matrix { get; }
 
     public Matrix3X3BaseNode()
     {
         Background = CreateRenderInput("Background", "IMAGE");
-        Input = CreateInput("Input", "INPUT_MATRIX", Matrix3X3.Identity);
-        Matrix = CreateOutput("Matrix", "OUTPUT_MATRIX", Matrix3X3.Identity);
+        Input = CreateFuncInput<Float3x3>("Input", "INPUT_MATRIX",
+            new Float3x3("") { ConstantValue = Matrix3X3.Identity });
+        Matrix = CreateFuncOutput<Float3x3>("Matrix", "OUTPUT_MATRIX",
+            (c) => CalculateMatrix(c, c.GetValue(Input)));
         Output.FirstInChain = null;
         AllowHighDpiRendering = true;
     }
 
     protected override void OnExecute(RenderContext context)
     {
-        Matrix.Value = CalculateMatrix(Input.Value);
         if (Background.Value == null)
             return;
 
@@ -35,7 +38,9 @@ public abstract class Matrix3X3BaseNode : RenderNode, IRenderInput
     {
         int layer = surface.Canvas.Save();
 
-        surface.Canvas.SetMatrix(surface.Canvas.TotalMatrix.Concat(Matrix.Value));
+        Float3x3 mtx = Matrix.Value.Invoke(FuncContext.NoContext);
+
+        surface.Canvas.SetMatrix(surface.Canvas.TotalMatrix.Concat(mtx.GetConstant() as Matrix3X3? ?? Matrix3X3.Identity));
         if (!surface.LocalClipBounds.IsZeroOrNegativeArea)
         {
             Background.Value?.Paint(context, surface);
@@ -44,5 +49,5 @@ public abstract class Matrix3X3BaseNode : RenderNode, IRenderInput
         surface.Canvas.RestoreToCount(layer);
     }
 
-    protected abstract Matrix3X3 CalculateMatrix(Matrix3X3 input);
+    protected abstract Float3x3 CalculateMatrix(FuncContext ctx, Float3x3 input);
 }

+ 0 - 6
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/MatrixNode.cs

@@ -1,6 +0,0 @@
-namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
-
-public class MatrixNode
-{
-
-}

+ 25 - 5
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/OffsetNode.cs

@@ -1,22 +1,42 @@
 using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Shaders.Generation.Expressions;
 using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
 
 [NodeInfo("Offset")]
 public class OffsetNode : Matrix3X3BaseNode
 {
-    public InputProperty<VecD> Translation { get; }
+    public FuncInputProperty<Float2> Translation { get; }
 
     public OffsetNode()
     {
-        Translation = CreateInput("Offset", "OFFSET", VecD.Zero);
+        Translation = CreateFuncInput<Float2>("Offset", "OFFSET", VecD.Zero);
     }
 
-    protected override Matrix3X3 CalculateMatrix(Matrix3X3 input)
+    protected override Float3x3 CalculateMatrix(FuncContext ctx, Float3x3 input)
     {
-        Matrix3X3 matrix = Matrix3X3.CreateTranslation((float)(Translation.Value.X), (float)(Translation.Value.Y));
-        return input.PostConcat(matrix);
+        Float2 translation = ctx.GetValue(Translation);
+
+        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)
+        {
+            return ctx.NewFloat3x3(ShaderMath.PostConcat(input, translationMatrix));
+        }
+
+        return new Float3x3("")
+        {
+            ConstantValue = input.ConstantValue.PostConcat(translationMatrix.ConstantValue)
+        };
     }
 
     public override Node CreateCopy()

+ 27 - 10
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/RotateNode.cs

@@ -1,5 +1,7 @@
 using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Shaders.Generation.Expressions;
 using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
 
@@ -7,27 +9,42 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
 public class RotateNode : Matrix3X3BaseNode
 {
     public InputProperty<RotationType> RotationType { get; }
-    public InputProperty<double> Angle { get; }
-    public InputProperty<VecD> Center { get; }
+    public FuncInputProperty<Float1> Angle { get; }
+    public FuncInputProperty<Float2> Center { get; }
 
     public RotateNode()
     {
         RotationType = CreateInput("RotationType", "UNIT", Nodes.Matrix.RotationType.Degrees);
-        Angle = CreateInput("Angle", "ANGLE", 0.0);
-        Center = CreateInput("Center", "CENTER", new VecD(0, 0));
+        Angle = CreateFuncInput<Float1>("Angle", "ANGLE", 0.0);
+        Center = CreateFuncInput<Float2>("Center", "CENTER", new VecD(0, 0));
     }
 
-    protected override Matrix3X3 CalculateMatrix(Matrix3X3 input)
+    protected override Float3x3 CalculateMatrix(FuncContext ctx, Float3x3 input)
     {
-        VecD scaledCenter = new VecD(Center.Value.X, Center.Value.Y);
-        Matrix3X3 rotated = RotationType.Value switch
+        Float1 angle = ctx.GetValue(Angle);
+        Float2 center = ctx.GetValue(Center);
+
+        Float1 one = new Float1("") { ConstantValue = 1.0 };
+        Float1 zero = new Float1("") { ConstantValue = 0.0 };
+
+        if (ctx.HasContext)
+        {
+            var rotationMatrix = ctx.NewFloat3x3(
+                ShaderMath.Cos(angle), new Expression($"-{ShaderMath.Sin(angle).ExpressionValue}"), new Expression($"{center.X.ExpressionValue} * (1.0 - {ShaderMath.Cos(angle)}) + {center.Y.ExpressionValue} * {ShaderMath.Sin(angle)}"),
+                ShaderMath.Sin(angle), ShaderMath.Cos(angle), new Expression($"{center.Y.ExpressionValue} * (1.0 - {ShaderMath.Cos(angle)}) - {center.X.ExpressionValue} * {ShaderMath.Sin(angle)}"),
+                zero, zero, one
+            );
+            return ctx.NewFloat3x3(ShaderMath.PostConcat(input, rotationMatrix));
+        }
+
+        Matrix3X3 rotationContextlessMatrix = RotationType.Value switch
         {
-            Nodes.Matrix.RotationType.Degrees => Matrix3X3.CreateRotationDegrees((float)Angle.Value, (float)scaledCenter.X, (float)scaledCenter.Y),
-            Nodes.Matrix.RotationType.Radians => Matrix3X3.CreateRotation((float)Angle.Value, (float)scaledCenter.X, (float)scaledCenter.Y),
+            Nodes.Matrix.RotationType.Degrees => Matrix3X3.CreateRotationDegrees((float)(angle.GetConstant() as double? ?? 0.0), (float)(center.X.GetConstant() as double? ?? 0), (float)(center.Y.GetConstant() as double? ?? 0)),
+            Nodes.Matrix.RotationType.Radians => Matrix3X3.CreateRotation((float)(angle.GetConstant() as double? ?? 0.0), (float)(center.X.GetConstant() as double? ?? 0), (float)(center.Y.GetConstant() as double? ?? 0)),
             _ => throw new ArgumentOutOfRangeException()
         };
 
-        return input.PostConcat(rotated);
+        return new Float3x3("") { ConstantValue = input.ConstantValue.PostConcat(rotationContextlessMatrix) };
     }
 
     public override Node CreateCopy()

+ 36 - 6
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/ScaleNode.cs

@@ -1,25 +1,55 @@
 using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Shaders.Generation.Expressions;
 using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
 
 [NodeInfo("Scale")]
 public class ScaleNode : Matrix3X3BaseNode
 {
-    public InputProperty<VecD> Scale { get; }
-    public InputProperty<VecD> Center { get; }
+    public FuncInputProperty<Float2> Scale { get; }
+    public FuncInputProperty<Float2> Center { get; }
 
     public ScaleNode()
     {
-        Scale = CreateInput("Scale", "SCALE", new VecD(1, 1));
-        Center = CreateInput("Center", "CENTER", new VecD(0, 0));
+        Scale = CreateFuncInput<Float2>("Scale", "SCALE", new VecD(1, 1));
+        Center = CreateFuncInput<Float2>("Center", "CENTER", new VecD(0, 0));
     }
 
-    protected override Matrix3X3 CalculateMatrix(Matrix3X3 input)
+    protected override Float3x3 CalculateMatrix(FuncContext ctx, Float3x3 input)
+    {
+        Float2 scale = ctx.GetValue(Scale);
+        Float2 center = ctx.GetValue(Center);
+
+        Float1 one = new Float1("") { ConstantValue = 1.0 };
+        Float1 zero = new Float1("") { ConstantValue = 0.0 };
+
+        if (ctx.HasContext)
+        {
+            var scaleMatrix = ctx.NewFloat3x3(
+                scale.X, zero, new Expression($"{center.X.ExpressionValue} * (1.0 - {scale.X.ExpressionValue})"),
+                zero, scale.Y, new Expression($"{center.Y.ExpressionValue} * (1.0 - {scale.Y.ExpressionValue})"),
+                zero, zero, one
+            );
+            return ctx.NewFloat3x3(ShaderMath.PostConcat(input, scaleMatrix));
+        }
+
+        Matrix3X3 scaleContextlessMatrix = Matrix3X3.CreateScale(
+            (float)(scale.X.GetConstant() as double? ?? 1.0f),
+            (float)(scale.Y.GetConstant() as double? ?? 1.0f),
+            (float)(center.X.GetConstant() as double? ?? 0.0f),
+            (float)(center.Y.GetConstant() as double? ?? 0.0f)
+        );
+
+        return new Float3x3("") { ConstantValue = input.ConstantValue.PostConcat(scaleContextlessMatrix) };
+    }
+
+    /*protected override Matrix3X3 CalculateMatrix(Matrix3X3 input)
     {
         Matrix3X3 scaled = Matrix3X3.CreateScale((float)Scale.Value.X, (float)Scale.Value.Y, (float)Center.Value.X, (float)Center.Value.Y);
         return input.PostConcat(scaled);
-    }
+    }*/
 
     public override Node CreateCopy()
     {

+ 25 - 5
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/SkewNode.cs

@@ -1,22 +1,42 @@
 using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Shaders.Generation.Expressions;
 using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
 
 [NodeInfo("Skew")]
 public class SkewNode : Matrix3X3BaseNode
 {
-    public InputProperty<VecD> Skew { get; }
+    public FuncInputProperty<Float2> Skew { get; }
 
     public SkewNode()
     {
-        Skew = CreateInput("Skew", "SKEW", VecD.Zero);
+        Skew = CreateFuncInput<Float2>("Skew", "SKEW", VecD.Zero);
     }
 
-    protected override Matrix3X3 CalculateMatrix(Matrix3X3 input)
+    protected override Float3x3 CalculateMatrix(FuncContext ctx, Float3x3 input)
     {
-        Matrix3X3 matrix = Matrix3X3.CreateSkew((float)Skew.Value.X, (float)Skew.Value.Y);
-        return input.PostConcat(matrix);
+        Float2 skew = ctx.GetValue(Skew);
+
+        Float1 one = new Float1("") { ConstantValue = 1.0 };
+        Float1 zero = new Float1("") { ConstantValue = 0.0 };
+
+        var skewMatrix = ctx.NewFloat3x3(
+            one, skew.X, zero,
+            skew.Y, one, zero,
+            zero, zero, one
+        );
+
+        if (ctx.HasContext)
+        {
+            return ctx.NewFloat3x3(ShaderMath.PostConcat(input, skewMatrix));
+        }
+
+        return new Float3x3("")
+        {
+            ConstantValue = input.ConstantValue.PostConcat(skewMatrix.ConstantValue)
+        };
     }
 
     public override Node CreateCopy()

+ 6 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/TransformNode.cs

@@ -1,6 +1,8 @@
 using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Shaders.Generation.Expressions;
 using Drawie.Backend.Core.Surfaces;
 using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 using PixiEditor.ChangeableDocument.Rendering;
 
@@ -9,13 +11,13 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
 [NodeInfo("Transform")]
 public class TransformNode : Matrix3X3BaseNode
 {
-    protected override Matrix3X3 CalculateMatrix(Matrix3X3 input)
+    public override Node CreateCopy()
     {
-        return Input.Value;
+        return new TransformNode();
     }
 
-    public override Node CreateCopy()
+    protected override Float3x3 CalculateMatrix(FuncContext ctx, Float3x3 input)
     {
-        return new TransformNode();
+        return input;
     }
 }

+ 1 - 0
src/PixiEditor.UI.Common/Accents/Base.axaml

@@ -165,6 +165,7 @@
             <SolidColorBrush x:Key="Int1SocketBrush" Color="{StaticResource IntSocketColor}" />
             <SolidColorBrush x:Key="StringSocketBrush" Color="{StaticResource StringSocketColor}" />
             <SolidColorBrush x:Key="Matrix3X3SocketBrush" Color="{StaticResource Matrix3X3SocketColor}" />
+            <SolidColorBrush x:Key="Float3x3SocketBrush" Color="{StaticResource Matrix3X3SocketColor}" />
 
             <ConicGradientBrush x:Key="ShapeVectorDataSocketBrush"
                                 GradientStops="{StaticResource ShapeDataSocketGradient}" />

BIN
src/PixiEditor.UI.Common/Fonts/PixiPerfect.ttf


+ 2 - 0
src/PixiEditor.UI.Common/Fonts/PixiPerfectIcons.axaml

@@ -102,6 +102,7 @@
             <system:String x:Key="icon-layers-bottom">&#xE96A;</system:String>
             <system:String x:Key="icon-layers-double">&#xE909;</system:String>
             <system:String x:Key="icon-layers-top">&#xE994;</system:String>
+            <system:String x:Key="icon-leafy-green">&#xE9C8;</system:String>
             <system:String x:Key="icon-letter-spacing">&#xE9B2;</system:String>
             <system:String x:Key="icon-line">&#xE95A;</system:String>
             <system:String x:Key="icon-line-height">&#xE9B3;</system:String>
@@ -150,6 +151,7 @@
             <system:String x:Key="icon-reset">&#xE9AA;</system:String>
             <system:String x:Key="icon-resize">&#xE96B;</system:String>
             <system:String x:Key="icon-rotate-view">&#xE96C;</system:String>
+            <system:String x:Key="icon-salad">&#xE9C7;</system:String>
             <system:String x:Key="icon-save">&#xE96E;</system:String>
             <system:String x:Key="icon-scissors">&#xE96F;</system:String>
             <system:String x:Key="icon-search">&#xE996;</system:String>

+ 2 - 0
src/PixiEditor.UI.Common/Fonts/PixiPerfectIcons.axaml.cs

@@ -98,6 +98,7 @@ public static partial class PixiPerfectIcons
     public const string LayersBottom = "\uE96A";
     public const string LayersDouble = "\uE909";
     public const string LayersTop = "\uE994";
+    public const string LeafyGreen = "\uE9C8";
     public const string LetterSpacing = "\uE9B2";
     public const string Line = "\uE95A";
     public const string LineHeight = "\uE9B3";
@@ -146,6 +147,7 @@ public static partial class PixiPerfectIcons
     public const string Reset = "\uE9AA";
     public const string Resize = "\uE96B";
     public const string RotateView = "\uE96C";
+    public const string Salad = "\uE9C7";
     public const string Save = "\uE96E";
     public const string Scissors = "\uE96F";
     public const string Search = "\uE996";

File diff suppressed because it is too large
+ 0 - 0
src/PixiEditor.UI.Common/Fonts/defs.svg


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

@@ -1076,5 +1076,16 @@
   "NEW_MAX": "New Max",
   "REMAP_NODE": "Remap",
   "TEXT_TOOL_ACTION_DISPLAY": "Click on the canvas to add a new text (drag while clicking to set the size). Click on existing text to edit it.",
-  "PASTE_CELS": "Paste cels"
+  "PASTE_CELS": "Paste cels",
+  "SCALE_X": "Scale X",
+  "SCALE_Y": "Scale Y",
+  "TRANSLATE_X": "Translate X",
+  "TRANSLATE_Y": "Translate Y",
+  "SKEW_X": "Skew X",
+  "SKEW_Y": "Skew Y",
+  "PERSPECTIVE_0": "Perspective 0",
+  "PERSPECTIVE_1": "Perspective 1",
+  "PERSPECTIVE_2": "Perspective 2",
+  "COMPOSE_MATRIX": "Compose Matrix",
+  "DECOMPOSE_MATRIX": "Decompose Matrix"
 }

+ 10 - 0
src/PixiEditor/ViewModels/Document/Nodes/Matrix/ComposeMatrixNodeViewModel.cs

@@ -0,0 +1,10 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
+using PixiEditor.ViewModels.Nodes;
+
+namespace PixiEditor.ViewModels.Document.Nodes.Matrix;
+
+[NodeViewModel("COMPOSE_MATRIX", "MATRIX", PixiPerfectIcons.Salad)]
+internal class ComposeMatrixNodeViewModel : NodeViewModel<ComposeMatrixNode>
+{
+
+}

+ 10 - 0
src/PixiEditor/ViewModels/Document/Nodes/Matrix/DecomposeMatrixNodeViewModel.cs

@@ -0,0 +1,10 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Matrix;
+using PixiEditor.ViewModels.Nodes;
+
+namespace PixiEditor.ViewModels.Document.Nodes.Matrix;
+
+[NodeViewModel("DECOMPOSE_MATRIX", "MATRIX", PixiPerfectIcons.LeafyGreen)]
+internal class DecomposeMatrixNodeViewModel : NodeViewModel<DecomposeMatrixNode>
+{
+
+}

Some files were not shown because too many files changed in this diff