Browse Source

Merge pull request #679 from PixiEditor/fixes/03.12.2024

Nodes fixes and optimizations
Krzysztof Krysiński 8 months ago
parent
commit
2616da9a0e

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit 3470bee10ed28168e63d19f03a1260f9a0aae2d3
+Subproject commit 73622d14f4a7e89f036ecec5bfe74cae15708348

+ 104 - 24
src/PixiEditor.ChangeableDocument/Changeables/Graph/Context/FuncContext.cs

@@ -20,17 +20,20 @@ public class FuncContext
     ///     Original position of the pixel in the image. This is the input argument of the main function.
     /// </summary>
     public Float2 OriginalPosition { get; private set; }
-    
+
     /// <summary>
     ///     Modified position of the pixel. This should be used to sample the texture, unless you want to sample the texture at the original position only.
     /// </summary>
     public Float2 SamplePosition { get; private set; }
+
     public VecI Size { get; private set; }
     public bool HasContext { get; private set; }
     public RenderContext RenderContext { get; set; }
 
     public ShaderBuilder Builder { get; set; }
 
+    private Dictionary<IFuncInputProperty, ShaderExpressionVariable> _cachedValues = new();
+
     public void ThrowOnMissingContext()
     {
         if (!HasContext)
@@ -49,10 +52,10 @@ public class FuncContext
         Builder = builder;
         HasContext = true;
         OriginalPosition = new Float2("coords"); // input argument 'half4 main(float2 coords)'
-        SamplePosition = Builder.ConstructFloat2(OriginalPosition.X, OriginalPosition.Y); 
+        SamplePosition = Builder.ConstructFloat2(OriginalPosition.X, OriginalPosition.Y);
     }
 
-    public Half4 SampleSurface(DrawingSurface surface, Float2 pos)
+    public Half4 SampleSurface(DrawingSurface surface, Expression pos)
     {
         SurfaceSampler texName = Builder.AddOrGetSurface(surface);
         return Builder.Sample(texName, pos);
@@ -66,7 +69,7 @@ public class FuncContext
             constantFloat.ConstantValue = new VecD(firstFloat.ConstantValue, secondFloat.ConstantValue);
             return constantFloat;
         }
-        
+
         return Builder.ConstructFloat2(x, y);
     }
 
@@ -78,7 +81,7 @@ public class FuncContext
             constantFloat.ConstantValue = float1.ConstantValue;
             return constantFloat;
         }
-        
+
         return Builder.ConstructFloat1(result);
     }
 
@@ -91,13 +94,14 @@ public class FuncContext
             constantInt.ConstantValue = new VecI(firstInt.ConstantValue, secondInt.ConstantValue);
             return constantInt;
         }
-        
+
         return Builder.ConstructInt2(first, second);
     }
 
     public Half4 NewHalf4(Expression r, Expression g, Expression b, Expression a)
     {
-        if (!HasContext && r is Float1 firstFloat && g is Float1 secondFloat && b is Float1 thirdFloat && a is Float1 fourthFloat)
+        if (!HasContext && r is Float1 firstFloat && g is Float1 secondFloat && b is Float1 thirdFloat &&
+            a is Float1 fourthFloat)
         {
             Half4 constantHalf4 = new Half4("");
             byte rByte = firstFloat.AsConstantColorByte();
@@ -107,13 +111,14 @@ public class FuncContext
             constantHalf4.ConstantValue = new Color(rByte, gByte, bByte, aByte);
             return constantHalf4;
         }
-        
+
         return Builder.ConstructHalf4(r, g, b, a);
     }
 
     public Half4 HsvaToRgba(Expression h, Expression s, Expression v, Expression a)
     {
-        if (!HasContext && h is Float1 firstFloat && s is Float1 secondFloat && v is Float1 thirdFloat && a is Float1 fourthFloat)
+        if (!HasContext && h is Float1 firstFloat && s is Float1 secondFloat && v is Float1 thirdFloat &&
+            a is Float1 fourthFloat)
         {
             Half4 constantHalf4 = new Half4("");
             var hValue = firstFloat.ConstantValue * 360;
@@ -129,7 +134,8 @@ public class FuncContext
 
     public Half4 HslaToRgba(Expression h, Expression s, Expression l, Expression a)
     {
-        if (!HasContext && h is Float1 firstFloat && s is Float1 secondFloat && l is Float1 thirdFloat && a is Float1 fourthFloat)
+        if (!HasContext && h is Float1 firstFloat && s is Float1 secondFloat && l is Float1 thirdFloat &&
+            a is Float1 fourthFloat)
         {
             Half4 constantHalf4 = new Half4("");
             var hValue = firstFloat.ConstantValue * 360;
@@ -142,29 +148,31 @@ public class FuncContext
 
         return Builder.AssignNewHalf4(Builder.Functions.GetHslToRgb(h, s, l, a));
     }
-    
+
     public Half4 RgbaToHsva(Expression color)
     {
         if (!HasContext && color is Half4 constantColor)
         {
             var variable = new Half4(string.Empty);
             constantColor.ConstantValue.ToHsv(out float h, out float s, out float l);
-            variable.ConstantValue = new Color((byte)(h * 255), (byte)(s * 255), (byte)(l * 255), constantColor.ConstantValue.A);
-            
+            variable.ConstantValue = new Color((byte)(h * 255), (byte)(s * 255), (byte)(l * 255),
+                constantColor.ConstantValue.A);
+
             return variable;
         }
 
         return Builder.AssignNewHalf4(Builder.Functions.GetRgbToHsv(color));
     }
-    
+
     public Half4 RgbaToHsla(Expression color)
     {
         if (!HasContext && color is Half4 constantColor)
         {
             var variable = new Half4(string.Empty);
             constantColor.ConstantValue.ToHsl(out float h, out float s, out float l);
-            variable.ConstantValue = new Color((byte)(h * 255), (byte)(s * 255), (byte)(l * 255), constantColor.ConstantValue.A);
-            
+            variable.ConstantValue = new Color((byte)(h * 255), (byte)(s * 255), (byte)(l * 255),
+                constantColor.ConstantValue.A);
+
             return variable;
         }
 
@@ -179,7 +187,7 @@ public class FuncContext
             constantHalf4.ConstantValue = half4.ConstantValue;
             return constantHalf4;
         }
-        
+
         return Builder.AssignNewHalf4(assignment);
     }
 
@@ -193,12 +201,24 @@ public class FuncContext
                 Builder.AddUniform(uniformName, (float)getFrom.Value(this).ConstantValue);
                 return new Float1(uniformName);
             }
+
+            if (_cachedValues.TryGetValue(getFrom, out ShaderExpressionVariable cachedValue))
+            {
+                if (cachedValue is Float1 float1)
+                {
+                    return float1;
+                }
+            }
         }
 
-        return getFrom.Value(this);
+
+        var val = getFrom.Value(this);
+        _cachedValues[getFrom] = val;
+
+        return val;
     }
 
-    public Expression GetValue(FuncInputProperty<Int1> getFrom)
+    public Int1 GetValue(FuncInputProperty<Int1> getFrom)
     {
         if (HasContext)
         {
@@ -206,11 +226,22 @@ public class FuncContext
             {
                 string uniformName = $"int_{Builder.GetUniqueNameNumber()}";
                 Builder.AddUniform(uniformName, (int)getFrom.Value(this).ConstantValue);
-                return new Expression(uniformName);
+                return new Int1(uniformName);
+            }
+
+            if (_cachedValues.TryGetValue(getFrom, out ShaderExpressionVariable cachedValue))
+            {
+                if (cachedValue is Int1 int1)
+                {
+                    return int1;
+                }
             }
         }
 
-        return getFrom.Value(this);
+        var val = getFrom.Value(this);
+        _cachedValues[getFrom] = val;
+
+        return val;
     }
 
     private static bool IsFuncType<T>(FuncInputProperty<T> getFrom)
@@ -218,7 +249,7 @@ public class FuncContext
         return getFrom.Connection.ValueType.IsAssignableTo(typeof(Delegate));
     }
 
-    public ShaderExpressionVariable GetValue(FuncInputProperty<Half4> getFrom)
+    public Half4 GetValue(FuncInputProperty<Half4> getFrom)
     {
         if (HasContext)
         {
@@ -229,9 +260,20 @@ public class FuncContext
                 Builder.AddUniform(color.VariableName, color.ConstantValue);
                 return color;
             }
+
+            if (_cachedValues.TryGetValue(getFrom, out ShaderExpressionVariable cachedValue))
+            {
+                if (cachedValue is Half4 half4)
+                {
+                    return half4;
+                }
+            }
         }
 
-        return getFrom.Value(this);
+        var val = getFrom.Value(this);
+        _cachedValues[getFrom] = val;
+
+        return val;
     }
 
     public Float2 GetValue(FuncInputProperty<Float2> getFrom)
@@ -245,8 +287,46 @@ public class FuncContext
                 Builder.AddUniform(value.VariableName, value.ConstantValue);
                 return value;
             }
+
+            if (_cachedValues.TryGetValue(getFrom, out ShaderExpressionVariable cachedValue))
+            {
+                if (cachedValue is Float2 float2)
+                {
+                    return float2;
+                }
+            }
+        }
+
+        var val = getFrom.Value(this);
+        _cachedValues[getFrom] = val;
+
+        return val;
+    }
+
+    public Int2 GetValue(FuncInputProperty<Int2>? getFrom)
+    {
+        if (HasContext)
+        {
+            if (getFrom?.Connection == null || !IsFuncType(getFrom))
+            {
+                Int2 value = getFrom.Value(this);
+                value.VariableName = $"int2_{Builder.GetUniqueNameNumber()}";
+                Builder.AddUniform(value.VariableName, value.ConstantValue);
+                return value;
+            }
+
+            if (_cachedValues.TryGetValue(getFrom, out ShaderExpressionVariable cachedValue))
+            {
+                if (cachedValue is Int2 int2)
+                {
+                    return int2;
+                }
+            }
         }
 
-        return getFrom.Value(this);
+        var val = getFrom.Value(this);
+        _cachedValues[getFrom] = val;
+
+        return val;
     }
 }

+ 42 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/FuncInputProperty.cs

@@ -57,7 +57,12 @@ public class FuncInputProperty<T> : InputProperty<Func<FuncContext, T>>, IFuncIn
                 }
                 else if (sourceObj is Expression expression)
                 {
-                    ((ShaderExpressionVariable)toReturn).OverrideExpression = Adjust(expression, toReturn);
+                    ShaderExpressionVariable shaderExpressionVariable = (ShaderExpressionVariable)toReturn;
+                    shaderExpressionVariable.OverrideExpression = Adjust(expression, toReturn, out var adjustNested);
+                    if (adjustNested)
+                    {
+                        AdjustNested(((IMultiValueVariable)toReturn), expression);
+                    }
                 }
 
                 return (T)toReturn;
@@ -68,15 +73,50 @@ public class FuncInputProperty<T> : InputProperty<Func<FuncContext, T>>, IFuncIn
         return func;
     }
     
-    private Expression Adjust(Expression expression, object toReturn)
+    private Expression Adjust(Expression expression, object toReturn, out bool adjustNestedVariables)
     {
+        adjustNestedVariables = false;
         if (expression is IMultiValueVariable multiVal && toReturn is not IMultiValueVariable)
         {
             return multiVal.GetValueAt(0);
         }
 
+        if (toReturn is IMultiValueVariable)
+        {
+            adjustNestedVariables = true;
+            return expression;
+        }
+
         return expression;
     }
+    
+    private void AdjustNested(IMultiValueVariable toReturn, Expression expression)
+    {
+        if (toReturn is not ShaderExpressionVariable shaderExpressionVariable)
+        {
+            return;
+        }
+
+        if (expression is not IMultiValueVariable multiVal)
+        {
+            int count = toReturn.GetValuesCount();
+            for (int i = 0; i < count; i++)
+            {
+                toReturn.OverrideExpressionAt(i, expression);
+            }
+        }
+        else
+        {
+            int sourceCount = multiVal.GetValuesCount();
+            int targetCount = toReturn.GetValuesCount();
+
+            int count = Math.Min(sourceCount, targetCount);
+            for (int i = 0; i < count; i++)
+            {
+                toReturn.OverrideExpressionAt(i, multiVal.GetValueAt(i));
+            }
+        }
+    }
 
     object? IFuncInputProperty.GetFuncConstantValue() => constantNonOverrideValue;
 

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateColorNode.cs

@@ -56,7 +56,7 @@ public class SeparateColorNode : Node
         };
 
     private Half4 GetRgba(FuncContext ctx) => 
-        contextVariables.GetOrAttachNew(ctx, Color, () => Color.Value(ctx));
+        contextVariables.GetOrAttachNew(ctx, Color, () => ctx.GetValue(Color));
 
     private Half4 GetHsva(FuncContext ctx) =>
         contextVariables.GetOrAttachNew(ctx, Color, () => ctx.RgbaToHsva(ctx.GetValue(Color)));

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateVecDNode.cs

@@ -17,8 +17,8 @@ public class SeparateVecDNode : Node
     
     public SeparateVecDNode()
     {
-        X = CreateFuncOutput("X", "X", ctx => Vector.Value(ctx).X);
-        Y = CreateFuncOutput("Y", "Y", ctx => Vector.Value(ctx).Y);
+        X = CreateFuncOutput<Float1>("X", "X", ctx => ctx.GetValue(Vector).X);
+        Y = CreateFuncOutput("Y", "Y", ctx => ctx.GetValue(Vector).Y);
         Vector = CreateFuncInput<Float2>("Vector", "VECTOR", VecD.Zero);
     }
 

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateVecINode.cs

@@ -16,8 +16,8 @@ public class SeparateVecINode : Node
     
     public SeparateVecINode()
     {
-        X = CreateFuncOutput<Int1>("X", "X", ctx => Vector.Value(ctx).X);
-        Y = CreateFuncOutput<Int1>("Y", "Y", ctx => Vector.Value(ctx).Y);
+        X = CreateFuncOutput<Int1>("X", "X", ctx => ctx.GetValue(Vector).X);
+        Y = CreateFuncOutput<Int1>("Y", "Y", ctx => ctx.GetValue(Vector).Y);
         Vector = CreateFuncInput<Int2>("Vector", "VECTOR", new VecI(0, 0));
     }
 

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/MathNode.cs

@@ -4,6 +4,7 @@ using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.ChangeableDocument.Rendering;
 using Drawie.Backend.Core;
+using Drawie.Backend.Core.Shaders.Generation;
 using Drawie.Backend.Core.Shaders.Generation.Expressions;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;

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

@@ -33,7 +33,7 @@ public class SampleImageNode : Node
             return new Half4("");
         }
 
-        Float2 uv = context.GetValue(Coordinate);
+        Expression uv = context.GetValue(Coordinate);
 
         return context.SampleSurface(Image.Value.DrawingSurface, uv);
     }