forked from 1b-agent/opencadstudio-upstream
refactor(viewport): unify content-viewport clipping on the stencil path
Rectangular paper viewports now go through the same GPU stencil clip as non-rectangular ones: viewport_clip_boundary_ndc returns the four rect corners (a full-target mask) instead of nothing, so the render path has no rect/non-rect special case — every content viewport carries a clip boundary and draws with stencil reference 0xFF. With a single clip path, the old per-wire / -image / -wipeout scissor mechanism is fully dead and removed: compute_*_scissors, the *_pixel_scissors buffers, the project_scissor helper, the per-pass set_scissor_rect blocks, the vp_scissor field threaded through WireModel / ImageModel / HatchModel and their GPU mirrors (WireGpu / ImageGpu / WipeoutGpu / HatchWebGpu), from_run's scissor parameter, the scissor grouping in build_wire_buffers, and the is_arena_eligible gate. Net -245 lines across 54 files. Rectangular viewports still clip exactly via their own render rectangle; the stencil mask is a redundant full-target no-op there, kept only so the clip code path stays uniform. XCLIP keeps its CPU wire clip. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
c97c2a8250
commit
626e8091f7
54 files changed
+32
-277
No files matched your search
@@ -1258,7 +1258,6 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
|
||||
key_vertices: vec![],
|
||||
aabb: crate::scene::WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
};
|
||||
@@ -1297,7 +1296,6 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
|
||||
key_vertices: vec![],
|
||||
aabb: crate::scene::WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
|
||||
@@ -1372,7 +1372,6 @@ fn tessellate_dimension_inner(
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -1399,7 +1398,6 @@ fn tessellate_dimension_inner(
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -1426,7 +1424,6 @@ fn tessellate_dimension_inner(
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -1454,7 +1451,6 @@ fn tessellate_dimension_inner(
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: geom.arrow_fill,
|
||||
// fill_tris_low intentionally empty: this fill renders on the top-level
|
||||
// path, where consumers (face3d_gpu, xclip) treat a short low half as
|
||||
@@ -1498,7 +1494,6 @@ fn tessellate_dimension_inner(
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: rect,
|
||||
// fill_tris_low intentionally empty: this fill renders on the
|
||||
// top-level path, where consumers (face3d_gpu, xclip) treat a
|
||||
|
||||
@@ -610,7 +610,6 @@ impl LeaderTess for Leader {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
};
|
||||
@@ -717,7 +716,6 @@ impl LeaderTess for Leader {
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris,
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -1424,7 +1424,6 @@ impl MultiLeaderTess for MultiLeader {
|
||||
key_vertices: key_verts,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: arrow_fill,
|
||||
// fill_tris_low intentionally empty: this fill renders on the
|
||||
// top-level path, where consumers (face3d_gpu, xclip) treat a short
|
||||
@@ -1717,7 +1716,6 @@ impl MultiLeaderTess for MultiLeader {
|
||||
key_vertices: vec![],
|
||||
aabb: [nx as f32, ny as f32, xx as f32, xy as f32],
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -1782,7 +1780,6 @@ impl MultiLeaderTess for MultiLeader {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris,
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -1818,7 +1815,6 @@ impl MultiLeaderTess for MultiLeader {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
|
||||
@@ -773,7 +773,6 @@ pub fn tessellate_table(
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris,
|
||||
// fill_tris_low intentionally empty: this fill renders on the
|
||||
// top-level path, where consumers (face3d_gpu, xclip) treat a
|
||||
|
||||
@@ -206,7 +206,6 @@ impl CadCommand for AlignedDimensionCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
@@ -267,7 +266,6 @@ fn preview_aligned(p1: DVec3, p2: DVec3, dim_pt: DVec3) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -150,7 +150,6 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -200,7 +200,6 @@ fn preview_line(a: Vec3, b: Vec3) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -208,7 +208,6 @@ impl CadCommand for DimBaselineCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -188,7 +188,6 @@ impl CadCommand for DimContinueCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -113,7 +113,6 @@ impl CadCommand for DimJogLineCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -129,7 +129,6 @@ impl CadCommand for DimTeditCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -183,7 +183,6 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -241,7 +241,6 @@ fn preview_wire(points: Vec<DVec3>) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -170,7 +170,6 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -478,7 +478,6 @@ fn preview_wire(pts: &[Vec3]) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -141,7 +141,6 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -110,7 +110,6 @@ impl CadCommand for QdimCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -205,7 +205,6 @@ fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -168,7 +168,6 @@ impl CadCommand for TableCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -110,7 +110,6 @@ impl CadCommand for ToleranceCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -186,7 +186,6 @@ impl CadCommand for AttdefCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -242,7 +242,6 @@ impl HatchCommand {
|
||||
scale: 1.0,
|
||||
world_origin: origin,
|
||||
boundary_wcs: Some(std::sync::Arc::new(wcs)),
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
}
|
||||
}
|
||||
@@ -403,7 +402,6 @@ impl GradientCommand {
|
||||
scale: 1.0,
|
||||
world_origin: origin,
|
||||
boundary_wcs: Some(std::sync::Arc::new(wcs)),
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
}
|
||||
}
|
||||
@@ -577,7 +575,6 @@ impl CadCommand for BoundaryCommand {
|
||||
scale: 1.0,
|
||||
world_origin: origin,
|
||||
boundary_wcs: Some(std::sync::Arc::new(wcs)),
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
};
|
||||
CmdResult::CommitHatch(model)
|
||||
|
||||
@@ -156,7 +156,6 @@ impl CadCommand for MlineCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -128,7 +128,6 @@ impl CadCommand for ImageCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -104,7 +104,6 @@ impl CadCommand for RayCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
@@ -203,7 +202,6 @@ impl CadCommand for XLineCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -109,7 +109,6 @@ impl CadCommand for RevCloudCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -140,7 +140,6 @@ impl CadCommand for WipeoutCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
@@ -181,7 +180,6 @@ impl CadCommand for WipeoutCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -89,7 +89,6 @@ impl CadCommand for AreaCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -86,7 +86,6 @@ impl CadCommand for DistCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -87,7 +87,6 @@ impl MeasureGeomCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -3079,7 +3079,6 @@ fn preview_wire(points: Vec<[f32; 3]>, color: [f32; 4], name: &str) -> WireModel
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -107,7 +107,6 @@ impl CadCommand for MviewCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -325,7 +325,6 @@ fn wire(name: &str, points: Vec<[f32; 3]>) -> WireModel {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ impl CadCommand for PlotWindowCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
@@ -91,7 +91,6 @@ impl CadCommand for ZoomWindowCommand {
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
|
||||
Vendored
-1
@@ -868,7 +868,6 @@ impl Batches {
|
||||
key_vertices: b.key_vertices,
|
||||
aabb,
|
||||
plinegen: b.plinegen,
|
||||
vp_scissor: None,
|
||||
fill_tris: b.fill_tris,
|
||||
fill_tris_low: b.fill_tris_low,
|
||||
}
|
||||
|
||||
@@ -670,7 +670,6 @@ pub(crate) fn tessellate_entity(
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
};
|
||||
@@ -1055,7 +1054,6 @@ fn lod_stub_wire(
|
||||
key_vertices: vec![[cx as f64, cy as f64, cz as f64]],
|
||||
aabb,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
@@ -1140,7 +1138,6 @@ fn lod_stub_wire_3d(
|
||||
key_vertices: vec![],
|
||||
aabb,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
|
||||
@@ -394,7 +394,6 @@ pub fn tessellate(
|
||||
key_vertices: Vec::new(),
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: false,
|
||||
vp_scissor: None,
|
||||
fill_tris: Vec::new(),
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -681,7 +680,6 @@ pub fn tessellate(
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: ft,
|
||||
fill_tris_low: ftl,
|
||||
});
|
||||
@@ -719,7 +717,6 @@ pub fn tessellate(
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -764,7 +761,6 @@ pub fn tessellate(
|
||||
key_vertices: Vec::new(),
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -790,7 +786,6 @@ pub fn tessellate(
|
||||
key_vertices,
|
||||
aabb: text_aabb,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -846,7 +841,6 @@ pub fn tessellate(
|
||||
key_vertices: keys,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -884,7 +878,6 @@ pub fn tessellate(
|
||||
key_vertices: keys,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: bin.fill_tris,
|
||||
fill_tris_low: bin.fill_tris_low,
|
||||
});
|
||||
@@ -919,7 +912,6 @@ pub fn tessellate(
|
||||
key_vertices: Vec::new(),
|
||||
aabb: text_aabb,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -947,7 +939,6 @@ pub fn tessellate(
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -1006,7 +997,6 @@ pub fn tessellate(
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
@@ -1046,7 +1036,6 @@ pub fn tessellate(
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
@@ -1086,7 +1075,6 @@ pub fn tessellate(
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
@@ -1160,7 +1148,6 @@ pub fn tessellate(
|
||||
key_vertices: keys,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -1196,7 +1183,6 @@ pub fn tessellate(
|
||||
key_vertices: keys,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris,
|
||||
fill_tris_low,
|
||||
fill_is_3d,
|
||||
@@ -1225,7 +1211,6 @@ pub fn tessellate(
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
@@ -1264,7 +1249,6 @@ pub fn tessellate(
|
||||
aci: 0,
|
||||
key_vertices,
|
||||
plinegen: false,
|
||||
vp_scissor: None,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
@@ -1334,7 +1318,6 @@ pub fn tessellate(
|
||||
key_vertices,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}]
|
||||
|
||||
@@ -727,7 +727,6 @@ impl Scene {
|
||||
angle_offset: 0.0,
|
||||
scale: 1.0,
|
||||
world_origin: fill_origin,
|
||||
vp_scissor: None,
|
||||
draw_depth: depth_map.get(&common.handle.value()).copied().unwrap_or(0.0),
|
||||
});
|
||||
}
|
||||
@@ -1002,7 +1001,6 @@ impl Scene {
|
||||
angle_offset: 0.0,
|
||||
scale: 1.0,
|
||||
world_origin: origin,
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
});
|
||||
}
|
||||
@@ -1058,7 +1056,6 @@ impl Scene {
|
||||
angle_offset: 0.0,
|
||||
scale: 1.0,
|
||||
world_origin: fill_origin,
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
});
|
||||
}
|
||||
@@ -1593,7 +1590,6 @@ impl Scene {
|
||||
angle_offset: if prebaked { 0.0 } else { dxf.pattern_angle as f32 },
|
||||
scale: if prebaked { 1.0 } else { dxf.pattern_scale as f32 },
|
||||
world_origin,
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
})
|
||||
}
|
||||
@@ -1808,7 +1804,6 @@ impl Scene {
|
||||
angle_offset: 0.0,
|
||||
scale: 1.0,
|
||||
world_origin,
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
+1
-4
@@ -886,9 +886,7 @@ pub struct Scene {
|
||||
/// Cached wipeout fill models, keyed by geometry_epoch. Same
|
||||
/// reasoning as `hatch_cache`.
|
||||
wipeout_cache: RefCell<Option<(u64, Arc<Vec<HatchModel>>)>>,
|
||||
/// Cached image models, keyed by geometry_epoch. Images do their own
|
||||
/// per-frame culling in the GPU pipeline (vp_scissor); no camera key
|
||||
/// needed here.
|
||||
/// Cached image models, keyed by geometry_epoch. No camera key needed here.
|
||||
image_cache: RefCell<Option<(u64, Arc<Vec<ImageModel>>)>>,
|
||||
/// Cached mesh models, keyed by geometry_epoch.
|
||||
mesh_cache: RefCell<Option<(u64, Arc<Vec<MeshLodSet>>)>>,
|
||||
@@ -2025,7 +2023,6 @@ impl Scene {
|
||||
color: self.paper_bg_color,
|
||||
angle_offset: 0.0,
|
||||
scale: 1.0,
|
||||
vp_scissor: None,
|
||||
// Draw-order bias is signed: entity fills/wires land in (-1, 1)
|
||||
// (0 = neutral). A value below -1 forces the sheet strictly behind
|
||||
// EVERY object, in every case, with a tiny z offset (BIAS = 0.001,
|
||||
|
||||
@@ -84,12 +84,6 @@ pub struct HatchModel {
|
||||
pub angle_offset: f32,
|
||||
/// Pattern scale multiplier (from DXF `pattern_scale`).
|
||||
pub scale: f32,
|
||||
/// Optional world-space XY rect [x0, y0, x1, y1] for paper-space
|
||||
/// viewport clipping. When `Some`, the pipeline translates it into
|
||||
/// a per-frame pixel scissor and clips this hatch's draw call to it,
|
||||
/// preventing viewport-projected content from bleeding past the
|
||||
/// viewport frame. Mirrors `WireModel.vp_scissor`.
|
||||
pub vp_scissor: Option<[f32; 4]>,
|
||||
/// Normalized draw-order depth in (0,1); higher draws on top. Fed to the
|
||||
/// hatch pipeline as a small clip-z bias so this fill orders correctly
|
||||
/// against other entity types. 0.0 for transient/preview hatches.
|
||||
|
||||
@@ -100,10 +100,6 @@ pub struct ImageModel {
|
||||
/// Low residual paired with `corners` (double-single) so the GPU keeps
|
||||
/// sub-unit precision at UTM-scale insertion points.
|
||||
pub corners_low: [[f32; 3]; 4],
|
||||
/// Optional world-space XY rect [x0, y0, x1, y1] for paper-space
|
||||
/// viewport clipping. Mirrors `WireModel.vp_scissor` /
|
||||
/// `HatchModel.vp_scissor`.
|
||||
pub vp_scissor: Option<[f32; 4]>,
|
||||
/// Normalized draw-order depth in (0,1); higher draws on top. Fed to the
|
||||
/// image pipeline as a small clip-z bias so the raster orders correctly
|
||||
/// against other entity types.
|
||||
@@ -179,7 +175,6 @@ impl ImageModel {
|
||||
opacity,
|
||||
corners,
|
||||
corners_low,
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
verts,
|
||||
})
|
||||
@@ -234,7 +229,6 @@ impl ImageModel {
|
||||
opacity: 1.0,
|
||||
corners,
|
||||
corners_low,
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
verts,
|
||||
})
|
||||
|
||||
@@ -86,9 +86,6 @@ pub struct WireModel {
|
||||
/// share one interior phase (perpendicular dashes line up) yet each still
|
||||
/// ends on a dash. `None` (the default) = per-wire A-type / from-start.
|
||||
pub dash_align_end: Option<f32>,
|
||||
/// Paper-space bounding box [x0, y0, x1, y1] for GPU scissor clipping.
|
||||
/// Set only for viewport-projected wires in paper-space layouts.
|
||||
pub vp_scissor: Option<[f32; 4]>,
|
||||
/// Pre-triangulated solid fill: flat vertex list, 3 per triangle (world-offset applied).
|
||||
/// Non-empty only for PolyfaceMesh / PolygonMesh entities.
|
||||
pub fill_tris: Vec<[f32; 3]>,
|
||||
@@ -196,7 +193,6 @@ impl WireModel {
|
||||
plinegen: true,
|
||||
dash_from_start: false,
|
||||
dash_align_end: None,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
@@ -406,7 +402,6 @@ impl Default for WireModel {
|
||||
plinegen: true,
|
||||
dash_from_start: false,
|
||||
dash_align_end: None,
|
||||
vp_scissor: None,
|
||||
fill_tris: Vec::new(),
|
||||
fill_tris_low: Vec::new(),
|
||||
fill_is_3d: false,
|
||||
|
||||
@@ -290,7 +290,6 @@ impl Scene {
|
||||
angle_offset: 0.0,
|
||||
scale: 1.0,
|
||||
world_origin: fill_origin,
|
||||
vp_scissor: None,
|
||||
draw_depth: 0.0,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,11 +58,9 @@ struct HatchWebUniform {
|
||||
pub struct HatchWebGpu {
|
||||
pub vertex_buffer: wgpu::Buffer,
|
||||
pub bind_group: wgpu::BindGroup,
|
||||
/// Reserved for viewport-clip scissor / per-frame AABB LOD (mirrors
|
||||
/// `WipeoutGpu`); not yet wired into the web hatch draw loop — the native
|
||||
/// batched path doesn't do per-hatch scissor/LOD either.
|
||||
#[allow(dead_code)]
|
||||
pub vp_scissor: Option<[f32; 4]>,
|
||||
/// Reserved for per-frame AABB LOD (mirrors `WipeoutGpu`); not yet wired
|
||||
/// into the web hatch draw loop — the native batched path doesn't do
|
||||
/// per-hatch LOD either.
|
||||
#[allow(dead_code)]
|
||||
pub world_aabb: [f32; 4],
|
||||
_uniform_buf: wgpu::Buffer,
|
||||
@@ -344,7 +342,6 @@ impl HatchWebGpu {
|
||||
Self {
|
||||
vertex_buffer,
|
||||
bind_group,
|
||||
vp_scissor: model.vp_scissor,
|
||||
world_aabb,
|
||||
_uniform_buf,
|
||||
_data_tex: data_tex,
|
||||
|
||||
@@ -66,8 +66,6 @@ pub struct ImageGpu {
|
||||
/// more when the raster is clipped to a triangulated polygon.
|
||||
pub vertex_count: u32,
|
||||
pub bind_group: wgpu::BindGroup,
|
||||
/// Mirrors `ImageModel.vp_scissor` — see `HatchGpu.vp_scissor`.
|
||||
pub vp_scissor: Option<[f32; 4]>,
|
||||
_texture: wgpu::Texture,
|
||||
_sampler: wgpu::Sampler,
|
||||
_params_buf: wgpu::Buffer,
|
||||
@@ -186,7 +184,6 @@ impl ImageGpu {
|
||||
vertex_buffer,
|
||||
vertex_count,
|
||||
bind_group,
|
||||
vp_scissor: model.vp_scissor,
|
||||
_texture: texture,
|
||||
_sampler,
|
||||
_params_buf,
|
||||
|
||||
+6
-124
@@ -169,8 +169,6 @@ pub struct Pipeline {
|
||||
/// The Model content id both arenas currently mirror (`u64::MAX` = none).
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) wire_arena_id: u64,
|
||||
/// Pixel scissor rects [x, y, w, h] for viewport-clipped wires. Recomputed each frame.
|
||||
wire_pixel_scissors: Vec<Option<[u32; 4]>>,
|
||||
/// This content viewport's non-rectangular clip boundary as a triangle-fan
|
||||
/// vertex buffer in the render target's normalized device coords (`None` =
|
||||
/// rectangular / unclipped, where the viewport's own render rectangle does
|
||||
@@ -198,11 +196,7 @@ pub struct Pipeline {
|
||||
/// when the wipeout's projected AABB sits entirely outside the
|
||||
/// viewport rect. Recomputed by `compute_wipeout_lod`.
|
||||
wipeout_skip_flags: Vec<bool>,
|
||||
/// Pixel scissor rects [x, y, w, h] for viewport-clipped wipeouts. Recomputed each frame.
|
||||
wipeout_pixel_scissors: Vec<Option<[u32; 4]>>,
|
||||
gpu_images: Vec<ImageGpu>,
|
||||
/// Pixel scissor rects [x, y, w, h] for viewport-clipped images. Recomputed each frame.
|
||||
image_pixel_scissors: Vec<Option<[u32; 4]>>,
|
||||
gpu_meshes: Vec<MeshLodGpu>,
|
||||
/// Batched mesh geometry — every solid's LOD0 concatenated into a few large
|
||||
/// buffers so the whole set draws in a handful of calls instead of one per
|
||||
@@ -1442,7 +1436,6 @@ impl Pipeline {
|
||||
wire_arena_mesh: None,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
wire_arena_id: u64::MAX,
|
||||
wire_pixel_scissors: vec![],
|
||||
clip_boundary: None,
|
||||
gpu_selected_wires: vec![],
|
||||
gpu_preview_wires: vec![],
|
||||
@@ -1451,9 +1444,7 @@ impl Pipeline {
|
||||
gpu_hatches_web: vec![],
|
||||
gpu_wipeouts: vec![],
|
||||
wipeout_skip_flags: vec![],
|
||||
wipeout_pixel_scissors: vec![],
|
||||
gpu_images: vec![],
|
||||
image_pixel_scissors: vec![],
|
||||
gpu_meshes: vec![],
|
||||
gpu_mesh_batch: vec![],
|
||||
cached_mesh_batch_epoch: u64::MAX,
|
||||
@@ -1516,16 +1507,12 @@ impl Pipeline {
|
||||
let mut batches: Vec<WireGpu> = Vec::new();
|
||||
let mut i = 0;
|
||||
while i < wires.len() {
|
||||
let scissor = wires[i].vp_scissor;
|
||||
let mesh_edge = is_mesh_edge(&wires[i]);
|
||||
let mut j = i + 1;
|
||||
while j < wires.len()
|
||||
&& wires[j].vp_scissor == scissor
|
||||
&& is_mesh_edge(&wires[j]) == mesh_edge
|
||||
{
|
||||
while j < wires.len() && is_mesh_edge(&wires[j]) == mesh_edge {
|
||||
j += 1;
|
||||
}
|
||||
batches.extend(WireGpu::from_run(device, &wires[i..j], depth_map, scissor, mesh_edge, self.wire_const_bgl.as_ref()));
|
||||
batches.extend(WireGpu::from_run(device, &wires[i..j], depth_map, mesh_edge, self.wire_const_bgl.as_ref()));
|
||||
i = j;
|
||||
}
|
||||
|
||||
@@ -1587,7 +1574,7 @@ impl Pipeline {
|
||||
push(h.value(), WireModel::HOVER, wires, &mut out);
|
||||
}
|
||||
self.gpu_selected_wires =
|
||||
WireGpu::from_run(device, &out, depth_map, None, false, self.wire_const_bgl.as_ref());
|
||||
WireGpu::from_run(device, &out, depth_map, false, self.wire_const_bgl.as_ref());
|
||||
}
|
||||
|
||||
/// Build the text-highlight overlay: the glyph quads of just the selected /
|
||||
@@ -1645,7 +1632,7 @@ impl Pipeline {
|
||||
self.gpu_preview_wires = if wires.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
WireGpu::from_run(device, wires, depth_map, None, false, self.wire_const_bgl.as_ref())
|
||||
WireGpu::from_run(device, wires, depth_map, false, self.wire_const_bgl.as_ref())
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1848,16 +1835,6 @@ impl Pipeline {
|
||||
self.silhouette_vcount = verts.len() as u32;
|
||||
}
|
||||
|
||||
/// Recompute pixel scissor rects for viewport-clipped wires from the current view_proj.
|
||||
/// Called every frame from prepare() because scissor pixels shift with pan/zoom.
|
||||
pub fn compute_wire_scissors(&mut self, view_rot: glam::Mat4, eye: glam::DVec3, clip_w: u32, clip_h: u32) {
|
||||
self.wire_pixel_scissors = self
|
||||
.gpu_wires
|
||||
.iter()
|
||||
.map(|w| project_scissor(w.vp_scissor, view_rot, eye, clip_w, clip_h))
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// Upload this content viewport's non-rectangular clip boundary as a
|
||||
/// triangle-fan vertex buffer in render-target NDC. The boundary is already
|
||||
/// projected (paper shape → the same visible-sub-rect crop as the content),
|
||||
@@ -1914,15 +1891,6 @@ impl Pipeline {
|
||||
batch.upload_visibility(queue);
|
||||
}
|
||||
|
||||
/// Recompute pixel scissor rects for viewport-clipped wipeouts.
|
||||
pub fn compute_wipeout_scissors(&mut self, view_rot: glam::Mat4, eye: glam::DVec3, clip_w: u32, clip_h: u32) {
|
||||
self.wipeout_pixel_scissors = self
|
||||
.gpu_wipeouts
|
||||
.iter()
|
||||
.map(|h| project_scissor(h.vp_scissor, view_rot, eye, clip_w, clip_h))
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// Per-frame wipeout frustum-skip flag (Phase 2.3). Mirrors
|
||||
/// `compute_hatch_lod`'s frustum branch. No sub-pixel skip:
|
||||
/// wipeouts mask, so dropping a sub-pixel one wouldn't be wrong
|
||||
@@ -1935,15 +1903,6 @@ impl Pipeline {
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// Recompute pixel scissor rects for viewport-clipped raster images.
|
||||
pub fn compute_image_scissors(&mut self, view_rot: glam::Mat4, eye: glam::DVec3, clip_w: u32, clip_h: u32) {
|
||||
self.image_pixel_scissors = self
|
||||
.gpu_images
|
||||
.iter()
|
||||
.map(|i| project_scissor(i.vp_scissor, view_rot, eye, clip_w, clip_h))
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// Upload all 3DFACE entities as two batched GPU objects:
|
||||
/// - `gpu_face3d_fill`: filled triangles (1 buffer, 1 draw call)
|
||||
/// - `gpu_face3d_edges`: merged edge wires (1 buffer, 1 draw call)
|
||||
@@ -2324,26 +2283,11 @@ impl Pipeline {
|
||||
pass.set_pipeline(&self.image_pipeline);
|
||||
pass.set_bind_group(0, &self.uniform_bind_group, &[]);
|
||||
pass.set_stencil_reference(stencil_ref);
|
||||
let mut scissor_active = false;
|
||||
for (i, img) in self.gpu_images.iter().enumerate() {
|
||||
match self.image_pixel_scissors.get(i) {
|
||||
Some(Some([x, y, w, h])) => {
|
||||
pass.set_scissor_rect(*x, *y, *w, *h);
|
||||
scissor_active = true;
|
||||
}
|
||||
_ if scissor_active => {
|
||||
pass.set_scissor_rect(0, 0, vp.width, vp.height);
|
||||
scissor_active = false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
for img in self.gpu_images.iter() {
|
||||
pass.set_bind_group(1, &img.bind_group, &[]);
|
||||
pass.set_vertex_buffer(0, img.vertex_buffer.slice(..));
|
||||
pass.draw(0..img.vertex_count, 0..1);
|
||||
}
|
||||
if scissor_active {
|
||||
pass.set_scissor_rect(0, 0, vp.width, vp.height);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Pass 4: solid meshes (batched) ────────────────────────────────
|
||||
@@ -2647,10 +2591,9 @@ impl Pipeline {
|
||||
// colour. `wire_black_pipeline` shares the wire layout, so the switch
|
||||
// needs no bind-group rebind.
|
||||
let want_solid_with_edges = !hidden_line && !mesh_wireframe && show_3d_edges;
|
||||
let mut scissor_active = false;
|
||||
let mut black_active = false;
|
||||
pass.set_stencil_reference(stencil_ref);
|
||||
for (i, wire) in self.gpu_wires.iter().enumerate() {
|
||||
for wire in self.gpu_wires.iter() {
|
||||
if wire.instance_count == 0 {
|
||||
continue;
|
||||
}
|
||||
@@ -2673,26 +2616,12 @@ impl Pipeline {
|
||||
});
|
||||
black_active = use_black;
|
||||
}
|
||||
match self.wire_pixel_scissors.get(i) {
|
||||
Some(Some([x, y, w, h])) => {
|
||||
pass.set_scissor_rect(*x, *y, *w, *h);
|
||||
scissor_active = true;
|
||||
}
|
||||
_ if scissor_active => {
|
||||
pass.set_scissor_rect(0, 0, vp.width, vp.height);
|
||||
scissor_active = false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Some(bg) = &wire.const_bind_group {
|
||||
pass.set_bind_group(1, bg.as_ref(), &[]);
|
||||
}
|
||||
pass.set_vertex_buffer(0, wire.instance_buffer.slice(..));
|
||||
pass.draw(0..6, 0..wire.instance_count);
|
||||
}
|
||||
if scissor_active {
|
||||
pass.set_scissor_rect(0, 0, vp.width, vp.height);
|
||||
}
|
||||
// Live overlay wires (command preview / interim / grip drag) always
|
||||
// on top: the xray pipeline (depth_compare=Always, no depth write)
|
||||
// keeps them visible through any occluding geometry — a 3D solid, or
|
||||
@@ -2798,29 +2727,14 @@ impl Pipeline {
|
||||
pass.set_pipeline(&self.wipeout_pipeline);
|
||||
pass.set_bind_group(0, &self.uniform_bind_group, &[]);
|
||||
pass.set_stencil_reference(stencil_ref);
|
||||
let mut scissor_active = false;
|
||||
for (i, wipeout) in self.gpu_wipeouts.iter().enumerate() {
|
||||
if self.wipeout_skip_flags.get(i).copied().unwrap_or(false) {
|
||||
continue;
|
||||
}
|
||||
match self.wipeout_pixel_scissors.get(i) {
|
||||
Some(Some([x, y, w, h])) => {
|
||||
pass.set_scissor_rect(*x, *y, *w, *h);
|
||||
scissor_active = true;
|
||||
}
|
||||
_ if scissor_active => {
|
||||
pass.set_scissor_rect(0, 0, vp.width, vp.height);
|
||||
scissor_active = false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
pass.set_bind_group(1, &wipeout.bind_group, &[]);
|
||||
pass.set_vertex_buffer(0, wipeout.vertex_buffer.slice(..));
|
||||
pass.draw(0..6, 0..1);
|
||||
}
|
||||
if scissor_active {
|
||||
pass.set_scissor_rect(0, 0, vp.width, vp.height);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Pass 7: selected wire overlay pass ───────────────────────────
|
||||
@@ -3124,38 +3038,6 @@ fn aabb_below_pixel(
|
||||
(max_px - min_px).max(max_py - min_py) < threshold_px
|
||||
}
|
||||
|
||||
/// Project a world-space XY scissor rect through `view_proj` into the four
|
||||
/// pixel-space corners and return the smallest aligned-rect that bounds them,
|
||||
/// clamped to the clip viewport. Returns `None` when the rect is missing or
|
||||
/// the projection collapses (off-screen, behind camera).
|
||||
fn project_scissor(
|
||||
rect: Option<[f32; 4]>,
|
||||
view_rot: glam::Mat4,
|
||||
eye: glam::DVec3,
|
||||
clip_w: u32,
|
||||
clip_h: u32,
|
||||
) -> Option<[u32; 4]> {
|
||||
let [x0, y0, x1, y1] = rect?;
|
||||
let w = clip_w as f32;
|
||||
let h = clip_h as f32;
|
||||
let corners = [
|
||||
view_rot.project_point3((glam::DVec3::new(x0 as f64, y0 as f64, 0.0) - eye).as_vec3()),
|
||||
view_rot.project_point3((glam::DVec3::new(x1 as f64, y0 as f64, 0.0) - eye).as_vec3()),
|
||||
view_rot.project_point3((glam::DVec3::new(x0 as f64, y1 as f64, 0.0) - eye).as_vec3()),
|
||||
view_rot.project_point3((glam::DVec3::new(x1 as f64, y1 as f64, 0.0) - eye).as_vec3()),
|
||||
];
|
||||
let px: Vec<f32> = corners.iter().map(|c| (c.x + 1.0) * 0.5 * w).collect();
|
||||
let py: Vec<f32> = corners.iter().map(|c| (1.0 - c.y) * 0.5 * h).collect();
|
||||
let sx0 = px.iter().cloned().fold(f32::INFINITY, f32::min).max(0.0) as u32;
|
||||
let sy0 = py.iter().cloned().fold(f32::INFINITY, f32::min).max(0.0) as u32;
|
||||
let sx1 = (px.iter().cloned().fold(f32::NEG_INFINITY, f32::max) as u32).min(clip_w);
|
||||
let sy1 = (py.iter().cloned().fold(f32::NEG_INFINITY, f32::max) as u32).min(clip_h);
|
||||
if sx1 <= sx0 || sy1 <= sy0 {
|
||||
return None;
|
||||
}
|
||||
Some([sx0, sy0, sx1 - sx0, sy1 - sy0])
|
||||
}
|
||||
|
||||
fn create_depth_texture(device: &wgpu::Device, size: Size<u32>) -> wgpu::Texture {
|
||||
device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("viewer.depth_texture"),
|
||||
|
||||
@@ -119,10 +119,6 @@ pub struct FamilyBatchData {
|
||||
pub struct WipeoutGpu {
|
||||
pub vertex_buffer: wgpu::Buffer,
|
||||
pub bind_group: wgpu::BindGroup,
|
||||
/// Mirrors `HatchModel.vp_scissor`. Forwarded to the pipeline so each
|
||||
/// frame's `compute_hatch_scissors` can translate the world rect into
|
||||
/// a pixel scissor.
|
||||
pub vp_scissor: Option<[f32; 4]>,
|
||||
/// World-space XY bounding rect [min_x, min_y, max_x, max_y] of the
|
||||
/// boundary polygon. Used by the per-frame LOD pass to skip hatches
|
||||
/// whose entire footprint projects to less than ~2 px (Phase 3.3).
|
||||
@@ -382,7 +378,6 @@ impl WipeoutGpu {
|
||||
Self {
|
||||
vertex_buffer,
|
||||
bind_group,
|
||||
vp_scissor: model.vp_scissor,
|
||||
world_aabb,
|
||||
_uniform_buf,
|
||||
_boundary_buf,
|
||||
|
||||
@@ -90,13 +90,6 @@ fn handle_of(w: &WireModel) -> Option<Handle> {
|
||||
crate::scene::Scene::handle_from_wire_name(&w.name)
|
||||
}
|
||||
|
||||
/// True if the set can use the arena: no per-wire scissor (paper viewports). Mesh
|
||||
/// fills no longer disqualify it — the render layer splits the set into a regular
|
||||
/// and a mesh-edge subset, one arena each.
|
||||
pub fn is_arena_eligible(wires: &[WireModel]) -> bool {
|
||||
wires.iter().all(|w| w.vp_scissor.is_none())
|
||||
}
|
||||
|
||||
/// True when `w`'s edge segments belong to a mesh/solid whose fill is drawn in a
|
||||
/// separate pass — such wires need the draw loop's mesh-edge treatment, so they
|
||||
/// go in their own arena. `mesh_names` are the entities that emit a fill.
|
||||
@@ -439,7 +432,6 @@ impl WireArena {
|
||||
vec![WireGpu {
|
||||
instance_buffer: self.inst_buf.clone(),
|
||||
instance_count: self.inst_tail,
|
||||
vp_scissor: None,
|
||||
is_3d_mesh_edge: self.mesh_edge,
|
||||
const_bind_group: Some(self.const_bind_group.clone()),
|
||||
}]
|
||||
|
||||
@@ -208,9 +208,6 @@ impl WireInstance {
|
||||
pub struct WireGpu {
|
||||
pub instance_buffer: wgpu::Buffer,
|
||||
pub instance_count: u32,
|
||||
/// Paper-space bbox [x0, y0, x1, y1] for GPU scissor clipping.
|
||||
/// Set only for viewport-projected wires; None for regular wires.
|
||||
pub vp_scissor: Option<[f32; 4]>,
|
||||
/// `true` when the source `WireModel` also carries `fill_tris`
|
||||
/// (i.e. it is a 3D mesh face — PolyfaceMesh / PolygonMesh — whose
|
||||
/// outline lives in `points`). The wire pass skips these instances
|
||||
@@ -521,7 +518,6 @@ impl WireGpu {
|
||||
device: &wgpu::Device,
|
||||
wires: &[WireModel],
|
||||
depth_map: &rustc_hash::FxHashMap<u64, f32>,
|
||||
scissor: Option<[f32; 4]>,
|
||||
mesh_edge: bool,
|
||||
const_bgl: Option<&wgpu::BindGroupLayout>,
|
||||
) -> Vec<Self> {
|
||||
@@ -562,7 +558,6 @@ impl WireGpu {
|
||||
Self {
|
||||
instance_buffer: buf,
|
||||
instance_count: chunk.len() as u32,
|
||||
vp_scissor: scissor,
|
||||
is_3d_mesh_edge: mesh_edge,
|
||||
const_bind_group: bg.clone(),
|
||||
}
|
||||
@@ -594,7 +589,6 @@ impl WireGpu {
|
||||
Self {
|
||||
instance_buffer: buf,
|
||||
instance_count: chunk.len() as u32,
|
||||
vp_scissor: scissor,
|
||||
is_3d_mesh_edge: mesh_edge,
|
||||
const_bind_group: None,
|
||||
}
|
||||
@@ -652,7 +646,6 @@ impl WireGpu {
|
||||
Self {
|
||||
instance_buffer,
|
||||
instance_count: chunk.len() as u32,
|
||||
vp_scissor: None,
|
||||
is_3d_mesh_edge: false,
|
||||
const_bind_group: bg.clone(),
|
||||
}
|
||||
@@ -678,7 +671,6 @@ impl WireGpu {
|
||||
Self {
|
||||
instance_buffer,
|
||||
instance_count: chunk.len() as u32,
|
||||
vp_scissor: None,
|
||||
is_3d_mesh_edge: false,
|
||||
const_bind_group: None,
|
||||
}
|
||||
|
||||
+21
-16
@@ -334,7 +334,6 @@ impl Scene {
|
||||
// to keep dimensional consistency in the GPU shader.
|
||||
out.pattern_length = wire.pattern_length * scale;
|
||||
out.pattern = wire.pattern.map(|v| v * scale);
|
||||
out.vp_scissor = Some([vp_x0, vp_y0, vp_x1, vp_y1]);
|
||||
projected.push(out);
|
||||
}
|
||||
|
||||
@@ -348,17 +347,13 @@ impl Scene {
|
||||
result
|
||||
}
|
||||
|
||||
/// Clip regions for every on content viewport in `paper_block`: the paper
|
||||
/// bounding rect (matching the wires' `vp_scissor`) plus the boundary
|
||||
/// polygon whose interior the GPU keeps via the stencil buffer. A plain
|
||||
/// rectangular viewport contributes its four corners; a viewport with a
|
||||
/// non-rectangular clip (`clip_boundary_handle`) contributes that entity's
|
||||
/// tessellated outline (circle / ellipse / spline / polyline), reusing the
|
||||
/// entity's own `to_truck` tessellation.
|
||||
/// A content viewport's non-rectangular clip boundary, projected into that
|
||||
/// viewport's render-target normalized device coords. Returns an empty vec
|
||||
/// for a rectangular viewport (no `clip_boundary_handle`) — those clip via
|
||||
/// their own render rectangle and need no stencil mask.
|
||||
/// A content viewport's clip boundary, projected into that viewport's
|
||||
/// render-target normalized device coords. Every content viewport goes
|
||||
/// through the same stencil path: a rectangular viewport contributes its
|
||||
/// own four corners (a full-target mask, since the render rectangle already
|
||||
/// clips the edges), a viewport with a `clip_boundary_handle` contributes
|
||||
/// that entity's tessellated outline. Returns empty only when the viewport
|
||||
/// is degenerate.
|
||||
///
|
||||
/// `uo/vo/us/vs` are the visible-sub-rect crop the content camera applies
|
||||
/// (see `crop_view_proj`); the same crop is applied here so the boundary
|
||||
@@ -376,9 +371,6 @@ impl Scene {
|
||||
return vec![];
|
||||
};
|
||||
let vp: &Viewport = vp;
|
||||
if vp.clip_boundary_handle.is_null() {
|
||||
return vec![];
|
||||
}
|
||||
let pcx = vp.center.x as f32;
|
||||
let pcy = vp.center.y as f32;
|
||||
let z = vp.center.z as f32;
|
||||
@@ -387,7 +379,20 @@ impl Scene {
|
||||
if hw.abs() < 1e-6 || hh.abs() < 1e-6 {
|
||||
return vec![];
|
||||
}
|
||||
let poly = self.clip_boundary_polygon(vp.clip_boundary_handle, z);
|
||||
let poly = if vp.clip_boundary_handle.is_null() {
|
||||
// Rectangular viewport → its own four corners (paper coords). These
|
||||
// map to full-rect NDC [-1, 1], a no-op mask over a render target
|
||||
// that already clips to the rectangle, but it keeps rect and
|
||||
// non-rect viewports on one uniform stencil path.
|
||||
vec![
|
||||
[pcx - hw, pcy - hh, z],
|
||||
[pcx + hw, pcy - hh, z],
|
||||
[pcx + hw, pcy + hh, z],
|
||||
[pcx - hw, pcy + hh, z],
|
||||
]
|
||||
} else {
|
||||
self.clip_boundary_polygon(vp.clip_boundary_handle, z)
|
||||
};
|
||||
if poly.len() < 3 {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
@@ -325,7 +325,6 @@ pub fn apply_along(
|
||||
key_vertices: vec![],
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
@@ -365,7 +364,6 @@ pub fn apply_along(
|
||||
key_vertices: vec![],
|
||||
aabb: [nx as f32, ny as f32, xx as f32, xy as f32],
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
|
||||
@@ -387,10 +387,7 @@ impl shader::Primitive for Primitive {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let mut _patched = false;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if crate::scene::wire_gpu_patch_enabled()
|
||||
&& inner.wire_const_bgl.is_some()
|
||||
&& crate::scene::pipeline::wire_arena::is_arena_eligible(&vp.wires)
|
||||
{
|
||||
if crate::scene::wire_gpu_patch_enabled() && inner.wire_const_bgl.is_some() {
|
||||
use crate::scene::pipeline::wire_arena::{self, WireArena};
|
||||
// Split the resident set into the regular 2D wires and the
|
||||
// mesh/solid EDGE wires (which need the mesh-edge draw
|
||||
@@ -576,9 +573,6 @@ impl shader::Primitive for Primitive {
|
||||
inner.upload_silhouettes(device, &[], vp.view_dir);
|
||||
}
|
||||
inner.upload_clip_boundary(device, &vp.clip_boundary_ndc);
|
||||
inner.compute_wire_scissors(view_rot, eye, clip_size.width, clip_size.height);
|
||||
inner.compute_wipeout_scissors(view_rot, eye, clip_size.width, clip_size.height);
|
||||
inner.compute_image_scissors(view_rot, eye, clip_size.width, clip_size.height);
|
||||
inner.compute_hatch_lod(queue, view_rot, eye, clip_size.width, clip_size.height);
|
||||
inner.compute_wipeout_lod(view_rot, eye, clip_size.width, clip_size.height);
|
||||
inner.compute_mesh_lod(view_rot, eye, clip_size.width, clip_size.height);
|
||||
|
||||
Reference in new issue
Block a user