@@ -166,7 +166,13 @@ fn main(
166166 var p1 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 3u ], scene [dd + 4u ]));
167167 var r0 = bitcast <f32 >(scene [dd + 5u ]);
168168 var r1 = bitcast <f32 >(scene [dd + 6u ]);
169- let user_to_gradient = transform_inverse (transform );
169+ let scale_x = length (transform . matrx . xy );
170+ let scale_y = length (transform . matrx . zw );
171+ let average_scale = 0 .5 * (scale_x + scale_y );
172+ p0 = transform_apply (transform , p0 );
173+ p1 = transform_apply (transform , p1 );
174+ r0 *= average_scale ;
175+ r1 *= average_scale ;
170176 // Output variables
171177 var xform = Transform ();
172178 var focal_x = 0 .0 ;
@@ -177,10 +183,7 @@ fn main(
177183 // When the radii are the same, emit a strip gradient
178184 kind = RAD_GRAD_KIND_STRIP ;
179185 let scaled = r0 / distance (p0 , p1 );
180- xform = transform_mul (
181- two_point_to_unit_line (p0 , p1 ),
182- user_to_gradient
183- );
186+ xform = two_point_to_unit_line (p0 , p1 );
184187 radius = scaled * scaled ;
185188 } else {
186189 // Assume a two point conical gradient unless the centers
@@ -204,10 +207,7 @@ fn main(
204207 focal_x = r0 / (r0 - r1 );
205208 let cf = (1 .0 - focal_x ) * p0 + focal_x * p1 ;
206209 radius = r1 / (distance (cf , p1 ));
207- let user_to_unit_line = transform_mul (
208- two_point_to_unit_line (cf , p1 ),
209- user_to_gradient
210- );
210+ let user_to_unit_line = two_point_to_unit_line (cf , p1 );
211211 var user_to_scaled = user_to_unit_line ;
212212 // When r == 1.0, focal point is on circle
213213 if abs (radius - 1 .0 ) <= GRADIENT_EPSILON {
@@ -241,15 +241,24 @@ fn main(
241241 }
242242 case DRAWTAG_FILL_ELLIPTIC_GRADIENT : {
243243 info [di ] = draw_flags ;
244- var center = bitcast <vec2 <f32 >>(vec2 (scene [dd + 1u ], scene [dd + 2u ]));
245- var axis_end = bitcast <vec2 <f32 >>(vec2 (scene [dd + 3u ], scene [dd + 4u ]));
244+ let local_center = bitcast <vec2 <f32 >>(vec2 (scene [dd + 1u ], scene [dd + 2u ]));
245+ let local_axis_end = bitcast <vec2 <f32 >>(vec2 (scene [dd + 3u ], scene [dd + 4u ]));
246246 let axis_ratio = bitcast <f32 >(scene [dd + 5u ]);
247- center = transform_apply (transform , center );
248- axis_end = transform_apply (transform , axis_end );
247+
248+ var center = transform_apply (transform , local_center );
249+ var axis_end = transform_apply (transform , local_axis_end );
249250 let dxy = axis_end - center ;
250251 let axis = length (dxy );
251252 let inv_axis = 1 .0 / axis ;
252- let inv_second_axis = inv_axis / axis_ratio ;
253+ let local_axis = local_axis_end - local_center ;
254+ let local_axis_len = length (local_axis );
255+ let local_second_end = local_center + vec2 (
256+ (- local_axis . y / local_axis_len ) * (local_axis_len * axis_ratio ),
257+ (local_axis . x / local_axis_len ) * (local_axis_len * axis_ratio ));
258+ let second_end = transform_apply (transform , local_second_end );
259+ let second_axis = length (second_end - center );
260+ let transformed_axis_ratio = select (axis_ratio , second_axis / axis , axis > 0 .0 );
261+ let inv_second_axis = inv_axis / transformed_axis_ratio ;
253262 let cos_theta = dxy . x * inv_axis ;
254263 let sin_theta = dxy . y * inv_axis ;
255264 // Map the ellipse to the unit circle so the fill parameter is length(local_xy).
@@ -268,17 +277,55 @@ fn main(
268277 }
269278 case DRAWTAG_FILL_SWEEP_GRADIENT : {
270279 info [di ] = draw_flags ;
271- let p0 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 1u ], scene [dd + 2u ]));
272- let xform = transform_mul (transform , Transform (vec4 (1 .0 , 0 .0 , 0 .0 , 1 .0 ), p0 , vec3 (0 .0 , 0 .0 , 1 .0 )));
273- let inv = transform_inverse (xform );
274- info [di + 1u ] = bitcast <u32 >(inv . matrx . x );
275- info [di + 2u ] = bitcast <u32 >(inv . matrx . y );
276- info [di + 3u ] = bitcast <u32 >(inv . matrx . z );
277- info [di + 4u ] = bitcast <u32 >(inv . matrx . w );
278- info [di + 5u ] = bitcast <u32 >(inv . translate . x );
279- info [di + 6u ] = bitcast <u32 >(inv . translate . y );
280- info [di + 7u ] = scene [dd + 3u ];
281- info [di + 8u ] = scene [dd + 4u ];
280+ let center = bitcast <vec2 <f32 >>(vec2 (scene [dd + 1u ], scene [dd + 2u ]));
281+ let t0 = bitcast <f32 >(scene [dd + 3u ]);
282+ let t1 = bitcast <f32 >(scene [dd + 4u ]);
283+ let tau = 6 .2831855 ;
284+ let transformed_center = transform_apply (transform , center );
285+ let start_dir = transform_apply (transform , center + vec2 (cos (t0 * tau ), - sin (t0 * tau )));
286+ let end_dir = transform_apply (transform , center + vec2 (cos (t1 * tau ), - sin (t1 * tau )));
287+ let start_xy = start_dir - transformed_center ;
288+ let end_xy = end_dir - transformed_center ;
289+ let transformed_t0 = fract ((atan2 (- start_xy . y , start_xy . x ) / tau ) + 1 .0 );
290+ let transformed_end = fract ((atan2 (- end_xy . y , end_xy . x ) / tau ) + 1 .0 );
291+ let minimum_magnitude = abs (t1 - t0 );
292+ let determinant = (transform . matrx . x * transform . matrx . w ) - (transform . matrx . y * transform . matrx . z );
293+ var direction_hint = sign (t1 - t0 );
294+ if direction_hint == 0 .0 {
295+ direction_hint = 1 .0 ;
296+ }
297+
298+ if determinant < 0 .0 {
299+ direction_hint = - direction_hint ;
300+ }
301+
302+ var delta = transformed_end - transformed_t0 ;
303+ if direction_hint >= 0 .0 {
304+ while delta < 0 .0 {
305+ delta += 1 .0 ;
306+ }
307+
308+ if abs (delta ) < 1e-6 && minimum_magnitude >= 1 .0 - 1e-6 {
309+ delta = 1 .0 ;
310+ }
311+ } else {
312+ while delta > 0 .0 {
313+ delta -= 1 .0 ;
314+ }
315+
316+ if abs (delta ) < 1e-6 && minimum_magnitude >= 1 .0 - 1e-6 {
317+ delta = - 1 .0 ;
318+ }
319+ }
320+
321+ info [di + 1u ] = bitcast <u32 >(1 .0 );
322+ info [di + 2u ] = bitcast <u32 >(0 .0 );
323+ info [di + 3u ] = bitcast <u32 >(0 .0 );
324+ info [di + 4u ] = bitcast <u32 >(1 .0 );
325+ info [di + 5u ] = bitcast <u32 >(- transformed_center . x );
326+ info [di + 6u ] = bitcast <u32 >(- transformed_center . y );
327+ info [di + 7u ] = bitcast <u32 >(transformed_t0 );
328+ info [di + 8u ] = bitcast <u32 >(transformed_t0 + delta );
282329 }
283330 case DRAWTAG_FILL_IMAGE : {
284331 info [di ] = draw_flags ;
0 commit comments