feat(lwpolyline): render the wide-polyline band via the wire shader

A wide polyline's flat band was drawn by the hatch pipeline: a solid fill
with only draw-order depth. It ignored the entity linetype (the width
"crushed" the dash pattern) and showed through 3-D geometry in a tilted view.

Draw the band from the polyline's own centre-line wire instead. A new
`WireModel.world_width` (drawing units) makes the wire vertex shader expand
the quad by `world_half_width / world_per_pixel` (clamped to a hairline), so
the band is sized in world units and tracks zoom. Because it is now a wire:

- the GPU dash shader dashes the band by arc-length — the linetype applies;
- it is depth-tested at the polyline elevation — no draw-order see-through;
- no CPU band triangles or per-dash geometry are generated.

`world_half_width` rides in `WireConst` (native, replacing a pad) and the web
`WireInstance` (loc 14); both wire shaders branch on it. The tessellator sets
`world_width` from the LwPolyline width on the Contour / SegmentedLines arms,
and the model-space fill loop no longer emits a hatch band for any LwPolyline.
Pick still uses the band polygon (`pick_tris`).

Blocks keep the hatch band: `LocalWire` carries no `world_width` (finalize
zeroes it), so a scaled insert still scales its band correctly.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-20 14:50:27 +03:00
1 parent 3d37e1f8d8
commit bd1a5affd7
44 files changed
+158 -17

No files matched your search

+8
View File
@@ -54,6 +54,12 @@ pub struct WireModel {
pub pattern: [f32; 8],
/// Rendered line width in screen pixels (half-width = line_weight_px / 2).
pub line_weight_px: f32,
/// World-space band width (drawing units). `0.0` = a normal wire whose
/// width comes from `line_weight_px` (screen pixels). Non-zero = a wide
/// polyline: the shader expands this centre-line to `world_width` world
/// units (scaling with zoom) so the band IS the wire — the linetype dash
/// pattern then applies to the band instead of a separate hatch fill.
pub world_width: f32,
/// ACI color index (1-255). 0 means true-color or unknown (no CTB lookup).
pub aci: u8,
/// Pre-baked snap candidates (Center, Node, Quadrant, Insertion).
@@ -173,6 +179,7 @@ impl WireModel {
/// Create a solid wire (no dash pattern, 1px weight).
pub fn solid(name: String, points: Vec<[f32; 3]>, color: [f32; 4], selected: bool) -> Self {
Self {
world_width: 0.0,
fill_is_3d: false,
pick_tris: Vec::new(),
pick_tris_low: Vec::new(),
@@ -394,6 +401,7 @@ impl Default for WireModel {
pattern_length: 0.0,
pattern: [0.0; 8],
line_weight_px: 1.0,
world_width: 0.0,
aci: 0,
snap_pts: Vec::new(),
tangent_geoms: Vec::new(),