Browse Source

Added hsl to separate color

CPKreuz 11 months ago
parent
commit
3d3792c3ae

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

@@ -1,5 +1,6 @@
 using System.Linq.Expressions;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core.ColorsImpl;

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

@@ -11,6 +11,8 @@ public class SeparateColorNode : Node
 {
     public FuncInputProperty<Half4> Color { get; }
     
+    public InputProperty<CombineSeparateColorMode> Mode { get; }
+
     public FuncOutputProperty<Float1> R { get; }
     
     public FuncOutputProperty<Float1> G { get; }
@@ -25,11 +27,12 @@ public class SeparateColorNode : Node
 
     public SeparateColorNode()
     {
-        Color = CreateFuncInput<Half4>(nameof(Color), "COLOR", new Color());
         R = CreateFuncOutput<Float1>(nameof(R), "R", ctx => GetColor(ctx).R);
         G = CreateFuncOutput<Float1>(nameof(G), "G", ctx => GetColor(ctx).G);
         B = CreateFuncOutput<Float1>(nameof(B), "B", ctx => GetColor(ctx).B);
         A = CreateFuncOutput<Float1>(nameof(A), "A", ctx => GetColor(ctx).A);
+        Mode = CreateInput("Mode", "MODE", CombineSeparateColorMode.RGB);
+        Color = CreateFuncInput<Half4>(nameof(Color), "COLOR", new Color());
     }
 
     protected override Texture? OnExecute(RenderingContext context)
@@ -39,6 +42,11 @@ public class SeparateColorNode : Node
     
     private Half4 GetColor(FuncContext ctx)
     {
+        if (Mode.Value == CombineSeparateColorMode.HSL)
+        {
+            return GetHsla(ctx);
+        }
+        
         Half4 target = null;
         if (lastContext == ctx)
         {
@@ -54,5 +62,21 @@ public class SeparateColorNode : Node
         return lastColor;
     }
 
+    private Half4 GetHsla(FuncContext ctx)
+    {
+        if (!ctx.HasContext && ctx.GetValue(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);
+            
+            return variable;
+        }
+
+        return ctx.Builder.GetOrNewAttachedHalf4(this.GetHashCode(), Color.GetHashCode(), RgbToHslGetter);
+
+        Expression RgbToHslGetter() => ctx.Builder.Functions.GetRgbToHsl(ctx.GetValue(Color));
+    }
+
     public override Node CreateCopy() => new SeparateColorNode();
 }

+ 43 - 27
src/PixiEditor.DrawingApi.Core/Shaders/Generation/BuiltInFunctions.cs

@@ -17,6 +17,13 @@ public class BuiltInFunctions
         return new Expression($"{nameof(HslToRgb)}({hsla.ExpressionValue})");
     }
 
+    public Expression GetRgbToHsl(Expression rgba)
+    {
+        Require(BuiltInFunctionType.RgbToHsl);
+
+        return new Expression($"{nameof(RgbToHsl)}({rgba.ExpressionValue})");
+    }
+
     public Expression GetHslToRgb(Expression h, Expression s, Expression l, Expression a) =>
         GetHslToRgb(Half4.Constructor(h, s, l, a));
     
@@ -25,7 +32,10 @@ public class BuiltInFunctions
         var builder = new StringBuilder();
 
         AppendIf(BuiltInFunctionType.HueToRgb, HueToRgb);
+        AppendIf(BuiltInFunctionType.RgbToHcv, RgbToHcv);
+        
         AppendIf(BuiltInFunctionType.HslToRgb, HslToRgb);
+        AppendIf(BuiltInFunctionType.RgbToHsl, RgbToHsl);
         
         return builder.ToString();
 
@@ -33,7 +43,7 @@ public class BuiltInFunctions
         {
             if (usedFunctions.Contains(type))
             {
-                builder.Append(source);
+                builder.AppendLine(source);
             }
         }
     }
@@ -45,11 +55,16 @@ public class BuiltInFunctions
             return;
         }
 
-        if (type is BuiltInFunctionType.HslToRgb)
+        switch (type)
         {
-            Require(BuiltInFunctionType.HueToRgb);
+            case BuiltInFunctionType.HslToRgb:
+                Require(BuiltInFunctionType.HueToRgb);
+                break;
+            case BuiltInFunctionType.RgbToHsl:
+                Require(BuiltInFunctionType.RgbToHcv);
+                break;
         }
-            
+
         usedFunctions.Add(type);
     }
 
@@ -73,33 +88,34 @@ public class BuiltInFunctions
         }
         """;
     
-    // private const string RgbToHcv = 
-    //     """
-    //     half4 RGBtoHSL(half4 rgba)
-    //     {
-    //         half4 p = (rgba.g < rgba.b) ? half4(rgba.bg, -1., 2. / 3.) : half4(rgba.gb, 0., -1. / 3.);
-    //         half4 q = (rgba.r < p.x) ? half4(p.xyw, rgba.r) : half4(rgba.r, p.yzx);
-    //         float c = q.x - min(q.w, q.y);
-    //         float h = abs((q.w - q.y) / (6. * c + EPSILON) + q.z);
-    //         return half4(h, c, q.x, rgba.w);
-    //     }
-    //     """;
-    //
-    // private const string RgbToHsl = 
-    //     """
-    //     half4 RGBtoHSL(half4 rgba)
-    //     {
-    //         // RGB [0..1] to Hue-Saturation-Lightness [0..1]
-    //         half3 hcv = RGBtoHCV(rgba.xyz);
-    //         half z = hcv.z - hcv.y * 0.5;
-    //         half s = hcv.y / (1. - abs(z * 2. - 1.) + EPSILON);
-    //         return half4(hcv.x, s, z, rgba.w);
-    //     }
-    //     """;
+    private const string RgbToHcv = 
+        $$"""
+        half3 {{nameof(RgbToHcv)}}(half3 rgba)
+        {
+            half4 p = (rgba.g < rgba.b) ? half4(rgba.bg, -1., 2. / 3.) : half4(rgba.gb, 0., -1. / 3.);
+            half4 q = (rgba.r < p.x) ? half4(p.xyw, rgba.r) : half4(rgba.r, p.yzx);
+            float c = q.x - min(q.w, q.y);
+            float h = abs((q.w - q.y) / (6. * c) + q.z);
+            return half3(h, c, q.x);
+        }
+        """;
+
+    private const string RgbToHsl = 
+        $$"""
+        half4 {{nameof(RgbToHsl)}}(half4 rgba)
+        {
+            half3 hcv = {{nameof(RgbToHcv)}}(rgba.xyz);
+            half z = hcv.z - hcv.y * 0.5;
+            half s = hcv.y / (1. - abs(z * 2. - 1.));
+            return half4(hcv.x, s, z, rgba.w);
+        }
+        """;
     
     enum BuiltInFunctionType
     {
         HueToRgb,
+        RgbToHcv,
+
         RgbToHsl,
         HslToRgb,
         RgbToHsv,

+ 20 - 3
src/PixiEditor.DrawingApi.Core/Shaders/Generation/ShaderBuilder.cs

@@ -1,4 +1,6 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Linq;
 using System.Text;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Shaders.Generation.Expressions;
@@ -162,9 +164,10 @@ public class ShaderBuilder
     }
 
 
-    public Half4 AssignNewHalf4(Expression assignment)
+    public Half4 AssignNewHalf4(Expression assignment) => AssignNewHalf4($"color_{GetUniqueNameNumber()}", assignment);
+
+    public Half4 AssignNewHalf4(string name, Expression assignment)
     {
-        string name = $"color_{GetUniqueNameNumber()}";
         Half4 result = new Half4(name);
         _variables.Add(result);
 
@@ -172,6 +175,20 @@ public class ShaderBuilder
         return result;
     }
 
+    public Half4 GetOrNewAttachedHalf4(int hash1, int hash2, Func<Expression> assignment)
+    {
+        var name = $"color_attached_{hash1}_{hash2}";
+        
+        var result = _variables.FirstOrDefault(x => x.VariableName == name);
+
+        if (result == null)
+        {
+            return AssignNewHalf4(name, assignment());
+        }
+
+        return (Half4)result;
+    }
+
     public void Dispose()
     {
         _bodyBuilder.Clear();