BuiltInFunctions.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using PixiEditor.DrawingApi.Core.Shaders.Generation.Expressions;
  6. namespace PixiEditor.DrawingApi.Core.Shaders.Generation;
  7. public class BuiltInFunctions
  8. {
  9. private readonly List<BuiltInFunctionType> usedFunctions = new(Enum.GetValues(typeof(BuiltInFunctionType)).Length);
  10. public Expression GetHslToRgb(Expression hsla)
  11. {
  12. Require(BuiltInFunctionType.HslToRgb);
  13. return new Expression($"{nameof(HslToRgb)}({hsla.ExpressionValue})");
  14. }
  15. public Expression GetRgbToHsl(Expression rgba)
  16. {
  17. Require(BuiltInFunctionType.RgbToHsl);
  18. return new Expression($"{nameof(RgbToHsl)}({rgba.ExpressionValue})");
  19. }
  20. public Expression GetHslToRgb(Expression h, Expression s, Expression l, Expression a) =>
  21. GetHslToRgb(Half4.Constructor(h, s, l, a));
  22. public string BuildFunctions()
  23. {
  24. var builder = new StringBuilder();
  25. AppendIf(BuiltInFunctionType.HueToRgb, HueToRgb);
  26. AppendIf(BuiltInFunctionType.RgbToHcv, RgbToHcv);
  27. AppendIf(BuiltInFunctionType.HslToRgb, HslToRgb);
  28. AppendIf(BuiltInFunctionType.RgbToHsl, RgbToHsl);
  29. return builder.ToString();
  30. void AppendIf(BuiltInFunctionType type, string source)
  31. {
  32. if (usedFunctions.Contains(type))
  33. {
  34. builder.AppendLine(source);
  35. }
  36. }
  37. }
  38. private void Require(BuiltInFunctionType type)
  39. {
  40. if (usedFunctions.Contains(type))
  41. {
  42. return;
  43. }
  44. switch (type)
  45. {
  46. case BuiltInFunctionType.HslToRgb:
  47. Require(BuiltInFunctionType.HueToRgb);
  48. break;
  49. case BuiltInFunctionType.RgbToHsl:
  50. Require(BuiltInFunctionType.RgbToHcv);
  51. break;
  52. }
  53. usedFunctions.Add(type);
  54. }
  55. // Taken from here https://www.shadertoy.com/view/4dKcWK
  56. private const string HueToRgb =
  57. $$"""
  58. half3 {{nameof(HueToRgb)}}(float hue)
  59. {
  60. vec3 rgb = abs(hue * 6. - vec3(3, 2, 4)) * vec3(1, -1, -1) + vec3(-1, 2, 2);
  61. return clamp(rgb, 0., 1.);
  62. }
  63. """;
  64. private const string HslToRgb =
  65. $$"""
  66. half4 {{nameof(HslToRgb)}}(half4 hsla)
  67. {
  68. half3 rgb = {{nameof(HueToRgb)}}(hsla.x);
  69. float c = (1. - abs(2. * hsla.z - 1.)) * hsla.y;
  70. return half4((rgb - 0.5) * c + hsla.z, hsla.w);
  71. }
  72. """;
  73. private const string RgbToHcv =
  74. $$"""
  75. half3 {{nameof(RgbToHcv)}}(half3 rgba)
  76. {
  77. half4 p = (rgba.g < rgba.b) ? half4(rgba.bg, -1., 2. / 3.) : half4(rgba.gb, 0., -1. / 3.);
  78. half4 q = (rgba.r < p.x) ? half4(p.xyw, rgba.r) : half4(rgba.r, p.yzx);
  79. float c = q.x - min(q.w, q.y);
  80. float h = abs((q.w - q.y) / (6. * c) + q.z);
  81. return half3(h, c, q.x);
  82. }
  83. """;
  84. private const string RgbToHsl =
  85. $$"""
  86. half4 {{nameof(RgbToHsl)}}(half4 rgba)
  87. {
  88. half3 hcv = {{nameof(RgbToHcv)}}(rgba.xyz);
  89. half z = hcv.z - hcv.y * 0.5;
  90. half s = hcv.y / (1. - abs(z * 2. - 1.));
  91. return half4(hcv.x, s, z, rgba.w);
  92. }
  93. """;
  94. enum BuiltInFunctionType
  95. {
  96. HueToRgb,
  97. RgbToHcv,
  98. RgbToHsl,
  99. HslToRgb,
  100. RgbToHsv,
  101. HsvToRgb
  102. }
  103. }