1#define_import_path bevy_ui_render::color_space2#import bevy_render::maths::PI4const TAU: f32 = 2. * PI;5const HUE_GUARD: f32 = 0.0001;7// https://en.wikipedia.org/wiki/SRGB8fn gamma(value: f32) -> f32 {9 if value <= 0.0 {10 return value;11 }12 if value <= 0.04045 {13 return value / 12.92; // linear falloff in dark values14 } else {15 return pow((value + 0.055) / 1.055, 2.4); // gamma curve in other area16 }17}19// https://en.wikipedia.org/wiki/SRGB20fn inverse_gamma(value: f32) -> f32 {21 if value <= 0.0 {22 return value;23 }25 if value <= 0.0031308 {26 return value * 12.92; // linear falloff in dark values27 } else {28 return 1.055 * pow(value, 1.0 / 2.4) - 0.055; // gamma curve in other area29 }30}32fn srgb_to_linear_rgb(color: vec3<f32>) -> vec3<f32> {33 return vec3(34 gamma(color.x),35 gamma(color.y),36 gamma(color.z)37 );38}40fn linear_rgb_to_srgb(color: vec3<f32>) -> vec3<f32> {41 return vec3(42 inverse_gamma(color.x),43 inverse_gamma(color.y),44 inverse_gamma(color.z)45 );46}48fn oklab_to_linear_rgb(c: vec3<f32>) -> vec3<f32> {49 let l_ = c.x + 0.39633778 * c.y + 0.21580376 * c.z;50 let m_ = c.x - 0.105561346 * c.y - 0.06385417 * c.z;51 let s_ = c.x - 0.08948418 * c.y - 1.2914855 * c.z;52 let l = l_ * l_ * l_;53 let m = m_ * m_ * m_;54 let s = s_ * s_ * s_;55 return vec3(56 4.0767417 * l - 3.3077116 * m + 0.23096994 * s,57 -1.268438 * l + 2.6097574 * m - 0.34131938 * s,58 -0.0041960863 * l - 0.7034186 * m + 1.7076147 * s,59 );60}62fn hsl_to_linear_rgb(hsl: vec3<f32>) -> vec3<f32> {63 let h = hsl.x;64 let s = hsl.y;65 let l = hsl.z;66 let c = (1.0 - abs(2.0 * l - 1.0)) * s;67 let hp = h * 6.0;68 let x = c * (1.0 - abs(hp % 2.0 - 1.0));69 var r: f32 = 0.0;70 var g: f32 = 0.0;71 var b: f32 = 0.0;72 if 0.0 <= hp && hp < 1.0 {73 r = c; g = x; b = 0.0;74 } else if 1.0 <= hp && hp < 2.0 {75 r = x; g = c; b = 0.0;76 } else if 2.0 <= hp && hp < 3.0 {77 r = 0.0; g = c; b = x;78 } else if 3.0 <= hp && hp < 4.0 {79 r = 0.0; g = x; b = c;80 } else if 4.0 <= hp && hp < 5.0 {81 r = x; g = 0.0; b = c;82 } else if 5.0 <= hp && hp < 6.0 {83 r = c; g = 0.0; b = x;84 }85 let m = l - 0.5 * c;86 return srgb_to_linear_rgb(vec3(r + m, g + m, b + m));87}89fn hsv_to_linear_rgb(hsva: vec3<f32>) -> vec3<f32> {90 let h = hsva.x * 6.0;91 let s = hsva.y;92 let v = hsva.z;93 let c = v * s;94 let x = c * (1.0 - abs(h % 2.0 - 1.0));95 let m = v - c;96 var r: f32 = 0.0;97 var g: f32 = 0.0;98 var b: f32 = 0.0;99 if 0.0 <= h && h < 1.0 {100 r = c; g = x; b = 0.0;101 } else if 1.0 <= h && h < 2.0 {102 r = x; g = c; b = 0.0;103 } else if 2.0 <= h && h < 3.0 {104 r = 0.0; g = c; b = x;105 } else if 3.0 <= h && h < 4.0 {106 r = 0.0; g = x; b = c;107 } else if 4.0 <= h && h < 5.0 {108 r = x; g = 0.0; b = c;109 } else if 5.0 <= h && h < 6.0 {110 r = c; g = 0.0; b = x;111 }112 return srgb_to_linear_rgb(vec3(r + m, g + m, b + m));113}115fn oklch_to_linear_rgb(c: vec3<f32>) -> vec3<f32> {116 let hue = c.z * TAU;117 return oklab_to_linear_rgb(vec3(c.x, c.y * cos(hue), c.y * sin(hue)));118}120fn mix_oklch(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {121 // If the chroma is close to zero for one of the endpoints, don't interpolate 122 // the hue and instead use the hue of the other endpoint. This allows gradients that smoothly 123 // transition from black or white to a target color without passing through unrelated hues.124 var h = a.z;125 var g = b.z;126 if a.y < HUE_GUARD {127 h = g;128 } else if b.y < HUE_GUARD {129 g = h;130 }132 let hue_diff = g - h;133 if abs(hue_diff) > 0.5 {134 if hue_diff > 0.0 {135 h += (hue_diff - 1.) * t;136 } else {137 h += (hue_diff + 1.) * t;138 }139 } else {140 h += hue_diff * t;141 }142 return vec3(143 mix(a.x, b.x, t),144 mix(a.y, b.y, t),145 fract(h),146 );147}149fn mix_oklch_long(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {150 var h = a.z;151 var g = b.z;152 if a.y < HUE_GUARD {153 h = g;154 } else if b.y < HUE_GUARD {155 g = h;156 }158 let hue_diff = g - h;159 if abs(hue_diff) < 0.5 {160 if hue_diff >= 0.0 {161 h += (hue_diff - 1.) * t;162 } else {163 h += (hue_diff + 1.) * t;164 }165 } else {166 h += hue_diff * t;167 }168 return vec3(169 mix(a.x, b.x, t),170 mix(a.y, b.y, t),171 fract(h),172 );173}175fn mix_hsl(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {176 // If the saturation is close to zero for one of the endpoints, don't interpolate 177 // the hue and instead use the hue of the other endpoint. This allows gradients that smoothly 178 // transition from black or white to a target color without passing through unrelated hues.179 var h = a.x; 180 var g = b.x;181 if a.y < HUE_GUARD {182 h = g;183 } else if b.y < HUE_GUARD {184 g = h;185 }187 return vec3(188 fract(h + (fract(g - h + 0.5) - 0.5) * t),189 mix(a.y, b.y, t),190 mix(a.z, b.z, t),191 );192}194fn mix_hsl_long(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {195 var h = a.x;196 var g = b.x;197 if a.y < HUE_GUARD {198 h = g;199 } else if b.y < HUE_GUARD {200 g = h;201 }203 let d = fract(g - h + 0.5) - 0.5;204 return vec3(205 fract(h + (d + select(1., -1., 0. < d)) * t),206 mix(a.y, b.y, t),207 mix(a.z, b.z, t),208 );209}211fn mix_hsv(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {212 // If the saturation is close to zero for one of the endpoints, don't interpolate 213 // the hue and instead use the hue of the other endpoint. This allows gradients that smoothly 214 // transition from black or white to a target color without passing through unrelated hues.215 var h = a.x;216 var g = b.x;217 if a.y < HUE_GUARD {218 h = g;219 } else if b.y < HUE_GUARD {220 g = h;221 }223 let hue_diff = g - h;224 if abs(hue_diff) > 0.5 {225 if hue_diff > 0.0 {226 h += (hue_diff - 1.0) * t;227 } else {228 h += (hue_diff + 1.0) * t;229 }230 } else {231 h += hue_diff * t;232 }233 return vec3(234 fract(h),235 mix(a.y, b.y, t),236 mix(a.z, b.z, t),237 );238}240fn mix_hsv_long(a: vec3<f32>, b: vec3<f32>, t: f32) -> vec3<f32> {241 var h = a.x;242 var g = b.x;243 if a.y < HUE_GUARD {244 h = g;245 } else if b.y < HUE_GUARD {246 g = h;247 }249 let hue_diff = g - h;250 if abs(hue_diff) < 0.5 {251 if hue_diff >= 0.0 {252 h += (hue_diff - 1.0) * t;253 } else {254 h += (hue_diff + 1.0) * t;255 }256 } else {257 h += hue_diff * t;258 }259 return vec3(260 fract(h),261 mix(a.y, b.y, t),262 mix(a.z, b.z, t),263 );264}