BuiltInFunctions.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. using System.Collections.Generic;
  2. using System.Text;
  3. using PixiEditor.DrawingApi.Core.Shaders.Generation.Expressions;
  4. namespace PixiEditor.DrawingApi.Core.Shaders.Generation;
  5. public class BuiltInFunctions
  6. {
  7. private readonly List<IBuiltInFunction> usedFunctions = new(6);
  8. public Expression GetRgbToHsv(Expression rgba) => Call(RgbToHsv, rgba);
  9. public Expression GetRgbToHsl(Expression rgba) => Call(RgbToHsl, rgba);
  10. public Expression GetHsvToRgb(Expression hsva) => Call(HsvToRgb, hsva);
  11. public Expression GetHsvToRgb(Expression h, Expression s, Expression v, Expression a) =>
  12. GetHsvToRgb(Half4Float1Accessor.GetOrConstructorExpressionHalf4(h, s, v, a));
  13. public Expression GetHslToRgb(Expression hsla) => Call(HslToRgb, hsla);
  14. public Expression GetHslToRgb(Expression h, Expression s, Expression l, Expression a) =>
  15. GetHslToRgb(Half4Float1Accessor.GetOrConstructorExpressionHalf4(h, s, l, a));
  16. public string BuildFunctions()
  17. {
  18. var builder = new StringBuilder();
  19. foreach (var function in usedFunctions)
  20. {
  21. builder.AppendLine(function.FullSource);
  22. }
  23. return builder.ToString();
  24. }
  25. private Expression Call(IBuiltInFunction function, Expression expression)
  26. {
  27. Require(function);
  28. return new Expression(function.Call(expression.ExpressionValue));
  29. }
  30. private void Require(IBuiltInFunction function)
  31. {
  32. if (usedFunctions.Contains(function))
  33. {
  34. return;
  35. }
  36. foreach (var dependency in function.Dependencies)
  37. {
  38. Require(dependency);
  39. }
  40. usedFunctions.Add(function);
  41. }
  42. // Taken from here https://www.shadertoy.com/view/4dKcWK
  43. private static readonly BuiltInFunction<Half3> HueToRgb = new(
  44. "float hue",
  45. nameof(HueToRgb),
  46. """
  47. half3 rgb = abs(hue * 6. - half3(3, 2, 4)) * half3(1, -1, -1) + half3(-1, 2, 2);
  48. return clamp(rgb, 0., 1.);
  49. """);
  50. private static readonly BuiltInFunction<Half3> RgbToHcv = new(
  51. "half3 rgba",
  52. nameof(RgbToHcv),
  53. """
  54. half4 p = (rgba.g < rgba.b) ? half4(rgba.bg, -1., 2. / 3.) : half4(rgba.gb, 0., -1. / 3.);
  55. half4 q = (rgba.r < p.x) ? half4(p.xyw, rgba.r) : half4(rgba.r, p.yzx);
  56. float c = q.x - min(q.w, q.y);
  57. float h = abs((q.w - q.y) / (6. * c) + q.z);
  58. return half3(h, c, q.x);
  59. """);
  60. private static readonly BuiltInFunction<Half4> RgbToHsv = new(
  61. "half4 rgba",
  62. nameof(RgbToHsv),
  63. $"""
  64. half3 hcv = {RgbToHcv.Call("rgba.rgb")};
  65. float s = hcv.y / (hcv.z);
  66. return half4(hcv.x, s, hcv.z, rgba.w);
  67. """,
  68. RgbToHcv);
  69. private static readonly BuiltInFunction<Half4> HsvToRgb = new(
  70. "half4 hsva",
  71. nameof(HsvToRgb),
  72. $"""
  73. half3 rgb = {HueToRgb.Call("hsva.r")};
  74. return half4(((rgb - 1.) * hsva.y + 1.) * hsva.z, hsva.w);
  75. """,
  76. HueToRgb);
  77. private static readonly BuiltInFunction<Half4> RgbToHsl = new(
  78. "half4 rgba",
  79. nameof(RgbToHsl),
  80. $"""
  81. half3 hcv = {RgbToHcv.Call("rgba.rgb")};
  82. half z = hcv.z - hcv.y * 0.5;
  83. half s = hcv.y / (1. - abs(z * 2. - 1.));
  84. return half4(hcv.x, s, z, rgba.w);
  85. """,
  86. RgbToHcv);
  87. private static readonly BuiltInFunction<Half4> HslToRgb = new(
  88. "half4 hsla",
  89. nameof(HslToRgb),
  90. $"""
  91. half3 rgb = {HueToRgb.Call("hsla.r")};
  92. float c = (1. - abs(2. * hsla.z - 1.)) * hsla.y;
  93. return half4((rgb - 0.5) * c + hsla.z, hsla.w);
  94. """,
  95. HueToRgb);
  96. private class BuiltInFunction<TReturn>(string argumentList, string name, string body, params IBuiltInFunction[] dependencies) : IBuiltInFunction where TReturn : ShaderExpressionVariable
  97. {
  98. public string ArgumentList { get; } = argumentList;
  99. public string Name { get; } = name;
  100. public string Body { get; } = body;
  101. public IBuiltInFunction[] Dependencies { get; } = dependencies;
  102. public string FullSource =>
  103. $$"""
  104. {{typeof(TReturn).Name.ToLower()}} {{Name}}({{ArgumentList}}) {
  105. {{Body}}
  106. }
  107. """;
  108. public string Call(string arguments) => $"{Name}({arguments})";
  109. }
  110. private interface IBuiltInFunction
  111. {
  112. IBuiltInFunction[] Dependencies { get; }
  113. string Name { get; }
  114. string FullSource { get; }
  115. string Call(string arguments);
  116. }
  117. }