123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- using System.Collections.Generic;
- using System.Text;
- using PixiEditor.DrawingApi.Core.Shaders.Generation.Expressions;
- namespace PixiEditor.DrawingApi.Core.Shaders.Generation;
- public class BuiltInFunctions
- {
- private readonly List<IBuiltInFunction> usedFunctions = new(6);
- public Expression GetRgbToHsv(Expression rgba) => Call(RgbToHsv, rgba);
- public Expression GetRgbToHsl(Expression rgba) => Call(RgbToHsl, rgba);
- public Expression GetHsvToRgb(Expression hsva) => Call(HsvToRgb, hsva);
- public Expression GetHsvToRgb(Expression h, Expression s, Expression v, Expression a) =>
- GetHsvToRgb(Half4Float1Accessor.GetOrConstructorExpressionHalf4(h, s, v, a));
- public Expression GetHslToRgb(Expression hsla) => Call(HslToRgb, hsla);
- public Expression GetHslToRgb(Expression h, Expression s, Expression l, Expression a) =>
- GetHslToRgb(Half4Float1Accessor.GetOrConstructorExpressionHalf4(h, s, l, a));
- public string BuildFunctions()
- {
- var builder = new StringBuilder();
- foreach (var function in usedFunctions)
- {
- builder.AppendLine(function.FullSource);
- }
- return builder.ToString();
- }
- private Expression Call(IBuiltInFunction function, Expression expression)
- {
- Require(function);
- return new Expression(function.Call(expression.ExpressionValue));
- }
- private void Require(IBuiltInFunction function)
- {
- if (usedFunctions.Contains(function))
- {
- return;
- }
- foreach (var dependency in function.Dependencies)
- {
- Require(dependency);
- }
- usedFunctions.Add(function);
- }
- // Taken from here https://www.shadertoy.com/view/4dKcWK
- private static readonly BuiltInFunction<Half3> HueToRgb = new(
- "float hue",
- nameof(HueToRgb),
- """
- half3 rgb = abs(hue * 6. - half3(3, 2, 4)) * half3(1, -1, -1) + half3(-1, 2, 2);
- return clamp(rgb, 0., 1.);
- """);
- private static readonly BuiltInFunction<Half3> RgbToHcv = new(
- "half3 rgba",
- nameof(RgbToHcv),
- """
- 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 static readonly BuiltInFunction<Half4> RgbToHsv = new(
- "half4 rgba",
- nameof(RgbToHsv),
- $"""
- half3 hcv = {RgbToHcv.Call("rgba.rgb")};
- float s = hcv.y / (hcv.z);
- return half4(hcv.x, s, hcv.z, rgba.w);
- """,
- RgbToHcv);
- private static readonly BuiltInFunction<Half4> HsvToRgb = new(
- "half4 hsva",
- nameof(HsvToRgb),
- $"""
- half3 rgb = {HueToRgb.Call("hsva.r")};
- return half4(((rgb - 1.) * hsva.y + 1.) * hsva.z, hsva.w);
- """,
- HueToRgb);
- private static readonly BuiltInFunction<Half4> RgbToHsl = new(
- "half4 rgba",
- nameof(RgbToHsl),
- $"""
- half3 hcv = {RgbToHcv.Call("rgba.rgb")};
- 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);
- """,
- RgbToHcv);
- private static readonly BuiltInFunction<Half4> HslToRgb = new(
- "half4 hsla",
- nameof(HslToRgb),
- $"""
- half3 rgb = {HueToRgb.Call("hsla.r")};
- float c = (1. - abs(2. * hsla.z - 1.)) * hsla.y;
- return half4((rgb - 0.5) * c + hsla.z, hsla.w);
- """,
- HueToRgb);
- private class BuiltInFunction<TReturn>(string argumentList, string name, string body, params IBuiltInFunction[] dependencies) : IBuiltInFunction where TReturn : ShaderExpressionVariable
- {
- public string ArgumentList { get; } = argumentList;
- public string Name { get; } = name;
- public string Body { get; } = body;
- public IBuiltInFunction[] Dependencies { get; } = dependencies;
- public string FullSource =>
- $$"""
- {{typeof(TReturn).Name.ToLower()}} {{Name}}({{ArgumentList}}) {
- {{Body}}
- }
- """;
- public string Call(string arguments) => $"{Name}({arguments})";
- }
-
- private interface IBuiltInFunction
- {
- IBuiltInFunction[] Dependencies { get; }
-
- string Name { get; }
-
- string FullSource { get; }
- string Call(string arguments);
- }
- }
|