fix(hatch): radial gradients and correct gradient stop colours

A gradient hatch was drawn linear from the entity colour to its second
stop, so a red->yellow spherical fill came out as a pale linear wash. Two
fixes:
- Colour: start from the gradient's first stop, not the entity colour.
  hatch_model_from_dxf already baked stop-0 in; stop synced_hatch_models
  from clobbering it with the entity's resolved colour for gradient fills.
- Shape: spherical / hemispherical / curved gradient names now render as a
  radial fill (new shader mode 3, centred on the boundary with radius to the
  farthest vertex) instead of linear. Native and web shaders both updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-18 22:01:22 +03:00
1 parent 69354eca07
commit fc29139056
8 files changed
+93 -23

No files matched your search

+18 -3
View File
@@ -110,9 +110,14 @@ impl HatchWebGpu {
let (mode, color2, grad_cos, grad_sin) = match &model.pattern {
HatchPattern::Solid => (1u32, [0.0f32; 4], 0.0f32, 0.0f32),
HatchPattern::Pattern(_) => (0u32, [0.0f32; 4], 0.0f32, 0.0f32),
HatchPattern::Gradient { angle_deg, color2 } => {
let r = angle_deg.to_radians();
(2u32, *color2, r.cos(), r.sin())
HatchPattern::Gradient { angle_deg, color2, radial } => {
if *radial {
// Radial: centre is the local origin; grad_cos/sin unused.
(3u32, *color2, 0.0, 0.0)
} else {
let r = angle_deg.to_radians();
(2u32, *color2, r.cos(), r.sin())
}
}
};
@@ -181,6 +186,16 @@ impl HatchWebGpu {
// Floor matches the desktop hatch renderer (hatch_gpu.rs).
(proj_min, (proj_max - proj_min).max(1.0))
}
} else if mode == 3 {
// Radial: range = the farthest boundary vertex from the centre.
let radius = model
.boundary
.iter()
.filter(|v| v[0].is_finite() && v[1].is_finite())
.map(|&[x, y]| (x * x + y * y).sqrt())
.fold(0.0_f32, f32::max)
.max(1.0);
(0.0, radius)
} else {
(0.0, 1.0)
};