@@ -31,7 +31,7 @@ struct GradientVertexOutput {
31
31
@location (0 ) uv : vec2 <f32 >,
32
32
@location (1 ) @interpolate (flat ) size : vec2 <f32 >,
33
33
@location (2 ) @interpolate (flat ) flags : u32 ,
34
- @location (3 ) @interpolate (flat ) radius : vec4 <f32 >,
34
+ @location (3 ) @interpolate (flat ) radius : vec4 <f32 >,
35
35
@location (4 ) @interpolate (flat ) border : vec4 <f32 >,
36
36
37
37
// Position relative to the center of the rectangle.
@@ -114,27 +114,27 @@ fn fragment(in: GradientVertexOutput) -> @location(0) vec4<f32> {
114
114
}
115
115
}
116
116
117
- // This function converts two linear rgb colors to srgb space, mixes them, and then converts the result back to linear rgb space.
118
- fn mix_linear_rgb_in_srgb_space (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
117
+ // This function converts two linear rgba colors to srgba space, mixes them, and then converts the result back to linear rgb space.
118
+ fn mix_linear_rgba_in_srgba_space (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
119
119
let a_srgb = pow (a . rgb , vec3 (1 . / 2 .2 ));
120
120
let b_srgb = pow (b . rgb , vec3 (1 . / 2 .2 ));
121
121
let mixed_srgb = mix (a_srgb , b_srgb , t );
122
122
return vec4 (pow (mixed_srgb , vec3 (2 .2 )), mix (a . a , b . a , t ));
123
123
}
124
124
125
- fn linear_rgb_to_oklab (c : vec4 <f32 >) -> vec4 <f32 > {
125
+ fn linear_rgba_to_oklaba (c : vec4 <f32 >) -> vec4 <f32 > {
126
126
let l = pow (0 .41222146 * c . x + 0 .53633255 * c . y + 0 .051445995 * c . z , 1 . / 3 . );
127
127
let m = pow (0 .2119035 * c . x + 0 .6806995 * c . y + 0 .10739696 * c . z , 1 . / 3 . );
128
128
let s = pow (0 .08830246 * c . x + 0 .28171885 * c . y + 0 .6299787 * c . z , 1 . / 3 . );
129
129
return vec4 (
130
130
0 .21045426 * l + 0 .7936178 * m - 0 .004072047 * s ,
131
131
1 .9779985 * l - 2 .4285922 * m + 0 .4505937 * s ,
132
- 0 .025904037 * l + 0 .78277177 * m - 0 .80867577 * s ,
133
- c . w
132
+ 0 .025904037 * l + 0 .78277177 * m - 0 .80867577 * s ,
133
+ c . a
134
134
);
135
135
}
136
136
137
- fn oklab_to_linear_rgba (c : vec4 <f32 >) -> vec4 <f32 > {
137
+ fn oklaba_to_linear_rgba (c : vec4 <f32 >) -> vec4 <f32 > {
138
138
let l_ = c . x + 0 .39633778 * c . y + 0 .21580376 * c . z ;
139
139
let m_ = c . x - 0 .105561346 * c . y - 0 .06385417 * c . z ;
140
140
let s_ = c . x - 0 .08948418 * c . y - 1 .2914855 * c . z ;
@@ -145,26 +145,127 @@ fn oklab_to_linear_rgba(c: vec4<f32>) -> vec4<f32> {
145
145
4 .0767417 * l - 3 .3077116 * m + 0 .23096994 * s ,
146
146
- 1 .268438 * l + 2 .6097574 * m - 0 .34131938 * s ,
147
147
- 0 .0041960863 * l - 0 .7034186 * m + 1 .7076147 * s ,
148
- c . w
148
+ c . a
149
149
);
150
150
}
151
151
152
- fn mix_linear_rgb_in_oklab_space (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
153
- return oklab_to_linear_rgba (mix (linear_rgb_to_oklab (a ), linear_rgb_to_oklab (b ), t ));
152
+ fn mix_linear_rgba_in_oklaba_space (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
153
+ return oklaba_to_linear_rgba (mix (linear_rgba_to_oklaba (a ), linear_rgba_to_oklaba (b ), t ));
154
+ }
155
+
156
+ fn linear_rgba_to_hsla (c : vec4 <f32 >) -> vec4 <f32 > {
157
+ let maxc = max (max (c . r , c . g ), c . b );
158
+ let minc = min (min (c . r , c . g ), c . b );
159
+ let delta = maxc - minc ;
160
+ let l = (maxc + minc ) * 0 .5 ;
161
+ var h : f32 = 0 .0 ;
162
+ var s : f32 = 0 .0 ;
163
+ if delta != 0 .0 {
164
+ s = delta / (1 .0 - abs (2 .0 * l - 1 .0 ));
165
+ if maxc == c . r {
166
+ h = ((c . g - c . b ) / delta ) % 6 .0 ;
167
+ } else if maxc == c . g {
168
+ h = ((c . b - c . r ) / delta ) + 2 .0 ;
169
+ } else {
170
+ h = ((c . r - c . g ) / delta ) + 4 .0 ;
171
+ }
172
+ h = h / 6 .0 ;
173
+ if h < 0 .0 {
174
+ h = h + 1 .0 ;
175
+ }
176
+ }
177
+ return vec4 <f32 >(h , s , l , c . a );
178
+ }
179
+
180
+ fn hsla_to_linear_rgba (hsl : vec4 <f32 >) -> vec4 <f32 > {
181
+ let h = hsl . x ;
182
+ let s = hsl . y ;
183
+ let l = hsl . z ;
184
+ let c = (1 .0 - abs (2 .0 * l - 1 .0 )) * s ;
185
+ let hp = h * 6 .0 ;
186
+ let x = c * (1 .0 - abs (hp % 2 .0 - 1 .0 ));
187
+ var r : f32 = 0 .0 ;
188
+ var g : f32 = 0 .0 ;
189
+ var b : f32 = 0 .0 ;
190
+ if 0 .0 <= hp && hp < 1 .0 {
191
+ r = c ; g = x ; b = 0 .0 ;
192
+ } else if 1 .0 <= hp && hp < 2 .0 {
193
+ r = x ; g = c ; b = 0 .0 ;
194
+ } else if 2 .0 <= hp && hp < 3 .0 {
195
+ r = 0 .0 ; g = c ; b = x ;
196
+ } else if 3 .0 <= hp && hp < 4 .0 {
197
+ r = 0 .0 ; g = x ; b = c ;
198
+ } else if 4 .0 <= hp && hp < 5 .0 {
199
+ r = x ; g = 0 .0 ; b = c ;
200
+ } else if 5 .0 <= hp && hp < 6 .0 {
201
+ r = c ; g = 0 .0 ; b = x ;
202
+ }
203
+ let m = l - 0 .5 * c ;
204
+ return vec4 <f32 >(r + m , g + m , b + m , hsl . a );
205
+ }
206
+
207
+ fn linear_rgba_to_hsva (c : vec4 <f32 >) -> vec4 <f32 > {
208
+ let maxc = max (max (c . r , c . g ), c . b );
209
+ let minc = min (min (c . r , c . g ), c . b );
210
+ let delta = maxc - minc ;
211
+ var h : f32 = 0 .0 ;
212
+ var s : f32 = 0 .0 ;
213
+ let v : f32 = maxc ;
214
+ if delta != 0 .0 {
215
+ s = delta / maxc ;
216
+ if maxc == c . r {
217
+ h = ((c . g - c . b ) / delta ) % 6 .0 ;
218
+ } else if maxc == c . g {
219
+ h = ((c . b - c . r ) / delta ) + 2 .0 ;
220
+ } else {
221
+ h = ((c . r - c . g ) / delta ) + 4 .0 ;
222
+ }
223
+ h = h / 6 .0 ;
224
+ if h < 0 .0 {
225
+ h = h + 1 .0 ;
226
+ }
227
+ }
228
+ return vec4 <f32 >(h , s , v , c . a );
229
+ }
230
+
231
+ fn hsva_to_linear_rgba (hsva : vec4 <f32 >) -> vec4 <f32 > {
232
+ let h = hsva . x * 6 .0 ;
233
+ let s = hsva . y ;
234
+ let v = hsva . z ;
235
+ let c = v * s ;
236
+ let x = c * (1 .0 - abs (h % 2 .0 - 1 .0 ));
237
+ let m = v - c ;
238
+ var r : f32 = 0 .0 ;
239
+ var g : f32 = 0 .0 ;
240
+ var b : f32 = 0 .0 ;
241
+ if 0 .0 <= h && h < 1 .0 {
242
+ r = c ; g = x ; b = 0 .0 ;
243
+ } else if 1 .0 <= h && h < 2 .0 {
244
+ r = x ; g = c ; b = 0 .0 ;
245
+ } else if 2 .0 <= h && h < 3 .0 {
246
+ r = 0 .0 ; g = c ; b = x ;
247
+ } else if 3 .0 <= h && h < 4 .0 {
248
+ r = 0 .0 ; g = x ; b = c ;
249
+ } else if 4 .0 <= h && h < 5 .0 {
250
+ r = x ; g = 0 .0 ; b = c ;
251
+ } else if 5 .0 <= h && h < 6 .0 {
252
+ r = c ; g = 0 .0 ; b = x ;
253
+ }
254
+ return vec4 <f32 >(r + m , g + m , b + m , hsva . a );
154
255
}
155
256
156
257
/// hue is left in radians and not converted to degrees
157
- fn linear_rgb_to_oklch (c : vec4 <f32 >) -> vec4 <f32 > {
158
- let o = linear_rgb_to_oklab (c );
258
+ fn linear_rgba_to_oklcha (c : vec4 <f32 >) -> vec4 <f32 > {
259
+ let o = linear_rgba_to_oklaba (c );
159
260
let chroma = sqrt (o . y * o . y + o . z * o . z );
160
261
let hue = atan2 (o . z , o . y );
161
- return vec4 (o . x , chroma , select (hue + TAU , hue , hue < 0 .0 ), o . w );
262
+ return vec4 (o . x , chroma , select (hue + TAU , hue , hue < 0 .0 ), o . a );
162
263
}
163
264
164
- fn oklch_to_linear_rgb (c : vec4 <f32 >) -> vec4 <f32 > {
265
+ fn oklcha_to_linear_rgba (c : vec4 <f32 >) -> vec4 <f32 > {
165
266
let a = c . y * cos (c . z );
166
267
let b = c . y * sin (c . z );
167
- return oklab_to_linear_rgba (vec4 (c . x , a , b , c . w ));
268
+ return oklaba_to_linear_rgba (vec4 (c . x , a , b , c . a ));
168
269
}
169
270
170
271
fn rem_euclid (a : f32 , b : f32 ) -> f32 {
@@ -181,28 +282,75 @@ fn lerp_hue_long(a: f32, b: f32, t: f32) -> f32 {
181
282
return rem_euclid (a + select (diff - TAU , diff + TAU , 0 . < diff ) * t , TAU );
182
283
}
183
284
184
- fn mix_oklch (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
285
+ fn mix_oklcha (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
185
286
return vec4 (
186
287
mix (a . xy , b . xy , t ),
187
288
lerp_hue (a . z , b . z , t ),
188
- mix (a . w , b . w , t )
289
+ mix (a . a , b . a , t )
189
290
);
190
291
}
191
292
192
- fn mix_oklch_long (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
293
+ fn mix_oklcha_long (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
193
294
return vec4 (
194
295
mix (a . xy , b . xy , t ),
195
296
lerp_hue_long (a . z , b . z , t ),
196
- mix (a . w , b . w , t )
297
+ mix (a . a , b . a , t )
197
298
);
198
299
}
199
300
200
- fn mix_linear_rgb_in_oklch_space (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
201
- return oklch_to_linear_rgb (mix_oklch (linear_rgb_to_oklch (a ), linear_rgb_to_oklch (b ), t ));
301
+ fn mix_linear_rgba_in_oklcha_space (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
302
+ return oklcha_to_linear_rgba (mix_oklcha (linear_rgba_to_oklcha (a ), linear_rgba_to_oklcha (b ), t ));
303
+ }
304
+
305
+ fn mix_linear_rgba_in_oklcha_space_long (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
306
+ return oklcha_to_linear_rgba (mix_oklcha_long (linear_rgba_to_oklcha (a ), linear_rgba_to_oklcha (b ), t ));
307
+ }
308
+
309
+ fn mix_linear_rgba_in_hsva_space (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
310
+ let ha = linear_rgba_to_hsva (a );
311
+ let hb = linear_rgba_to_hsva (b );
312
+ var h : f32 ;
313
+ if ha . y == 0 . {
314
+ h = hb . x ;
315
+ } else if hb . y == 0 . {
316
+ h = ha . x ;
317
+ } else {
318
+ h = lerp_hue (ha . x * TAU , hb . x * TAU , t ) / TAU ;
319
+ }
320
+ let s = mix (ha . y , hb . y , t );
321
+ let v = mix (ha . z , hb . z , t );
322
+ let a_alpha = mix (ha . a , hb . a , t );
323
+ return hsva_to_linear_rgba (vec4 <f32 >(h , s , v , a_alpha ));
324
+ }
325
+
326
+ fn mix_linear_rgba_in_hsva_space_long (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
327
+ let ha = linear_rgba_to_hsva (a );
328
+ let hb = linear_rgba_to_hsva (b );
329
+ let h = lerp_hue_long (ha . x * TAU , hb . x * TAU , t ) / TAU ;
330
+ let s = mix (ha . y , hb . y , t );
331
+ let v = mix (ha . z , hb . z , t );
332
+ let a_alpha = mix (ha . a , hb . a , t );
333
+ return hsva_to_linear_rgba (vec4 <f32 >(h , s , v , a_alpha ));
334
+ }
335
+
336
+ fn mix_linear_rgba_in_hsla_space (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
337
+ let ha = linear_rgba_to_hsla (a );
338
+ let hb = linear_rgba_to_hsla (b );
339
+ let h = lerp_hue (ha . x * TAU , hb . x * TAU , t ) / TAU ;
340
+ let s = mix (ha . y , hb . y , t );
341
+ let l = mix (ha . z , hb . z , t );
342
+ let a_alpha = mix (ha . a , hb . a , t );
343
+ return hsla_to_linear_rgba (vec4 <f32 >(h , s , l , a_alpha ));
202
344
}
203
345
204
- fn mix_linear_rgb_in_oklch_space_long (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
205
- return oklch_to_linear_rgb (mix_oklch_long (linear_rgb_to_oklch (a ), linear_rgb_to_oklch (b ), t ));
346
+ fn mix_linear_rgba_in_hsla_space_long (a : vec4 <f32 >, b : vec4 <f32 >, t : f32 ) -> vec4 <f32 > {
347
+ let ha = linear_rgba_to_hsla (a );
348
+ let hb = linear_rgba_to_hsla (b );
349
+ let h = lerp_hue_long (ha . x * TAU , hb . x * TAU , t ) / TAU ;
350
+ let s = mix (ha . y , hb . y , t );
351
+ let l = mix (ha . z , hb . z , t );
352
+ let a_alpha = mix (ha . a , hb . a , t );
353
+ return hsla_to_linear_rgba (vec4 <f32 >(h , s , l , a_alpha ));
206
354
}
207
355
208
356
// These functions are used to calculate the distance in gradient space from the start of the gradient to the point.
@@ -277,13 +425,21 @@ fn interpolate_gradient(
277
425
}
278
426
279
427
#ifdef IN_SRGB
280
- return mix_linear_rgb_in_srgb_space (start_color , end_color , t );
428
+ return mix_linear_rgba_in_srgba_space (start_color , end_color , t );
281
429
#else ifdef IN_OKLAB
282
- return mix_linear_rgb_in_oklab_space (start_color , end_color , t );
430
+ return mix_linear_rgba_in_oklaba_space (start_color , end_color , t );
283
431
#else ifdef IN_OKLCH
284
- return mix_linear_rgb_in_oklch_space (start_color , end_color , t );
432
+ return mix_linear_rgba_in_oklcha_space (start_color , end_color , t );
285
433
#else ifdef IN_OKLCH_LONG
286
- return mix_linear_rgb_in_oklch_space_long (start_color , end_color , t );
434
+ return mix_linear_rgba_in_oklcha_space_long (start_color , end_color , t );
435
+ #else ifdef IN_HSV
436
+ return mix_linear_rgba_in_hsva_space (start_color , end_color , t );
437
+ #else ifdef IN_HSV_LONG
438
+ return mix_linear_rgba_in_hsva_space_long (start_color , end_color , t );
439
+ #else ifdef IN_HSL
440
+ return mix_linear_rgba_in_hsla_space (start_color , end_color , t );
441
+ #else ifdef IN_HSL_LONG
442
+ return mix_linear_rgba_in_hsla_space_long (start_color , end_color , t );
287
443
#else
288
444
return mix (start_color , end_color , t );
289
445
#endif
0 commit comments