feat(web): render hatches on WebGL2 via a texture-backed renderer

WebGL2 has no vertex/fragment storage buffers, so the batched storage-buffer
hatch renderer (hatch_gpu) is disabled on wasm and real hatch fills never
rendered on the web build — the pick highlighted the boundary and the command
then appeared to cancel (issue #204).

Add a wasm-only per-hatch renderer (hatch_web_gpu + hatch_web.wgsl) that packs
the variable-length boundary / family / dash arrays into one RGBA32F data
texture read with textureLoad, instead of the fixed-size uniforms of the
wipeout path. This removes the MAX_FAMILIES (16) / MAX_HATCH_BOUNDARY_VERTS
(1024) / MAX_DASHES (128) caps, so every hatch — solid, gradient, and
arbitrarily complex line patterns — renders on the web. The fill algorithm
(in_polygon, per-family line/dash/dot, gradient, LOD, double-single vertex
transform) is identical to the desktop path; only the array ACCESS changes.
Pattern phase is anchored at world_origin with the boundary stored raw, and
scale / gradient-range clamped, to match the desktop batched renderer exactly.

Native (hatch_gpu + hatch.wgsl) and the wipeout mask renderer are untouched;
the new module and pipeline are gated on target_arch = "wasm32".

Also silence the resulting (and pre-existing) wasm-only dead-code warnings for
native-only paths so both the native and web builds compile clean.

Closes #204.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-14 00:53:51 +03:00
1 parent 9b1a495549
commit a4fc34c6a2
11 files changed
+745 -13

No files matched your search

+1
View File
@@ -86,6 +86,7 @@ pub fn unregister_handler() -> Result<(), String> {
/// freedesktop `.thumbnailer` (pointing at this binary's `--dwg-thumbnail` mode)
/// plus the mimetype icons under `$XDG_DATA_HOME`; on Windows it registers the
/// bundled thumbnail-provider DLL.
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
pub fn install_thumbnailer() {
#[cfg(target_os = "linux")]
{
+1
View File
@@ -346,6 +346,7 @@ pub fn dropped_on_save_count(
/// Before overwriting `path`, copy the existing file to a sibling `<name>.bak`
/// so a faulty or accidental save can be recovered (#205). Best-effort: a
/// failed backup never blocks the save itself.
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
pub fn write_backup(path: &std::path::Path) {
if path.exists() {
let _ = std::fs::copy(path, path.with_extension("bak"));
+1
View File
@@ -18,6 +18,7 @@ use crate::scene::WireModel;
/// "printto" shell verb); copies / quality / colour need the driver DEVMODE
/// and are ignored there.
#[derive(Debug, Clone, Default)]
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
pub struct PrintOptions {
/// Target printer name, or `None` for the system default.
pub printer: Option<String>,
+1
View File
@@ -123,6 +123,7 @@ fn to_rgb(c: [f32; 4]) -> [u8; 3] {
/// generic icon. Backs the hidden `--dwg-thumbnail` mode the installed
/// freedesktop `.thumbnailer` invokes. Extraction lives in the shared
/// [`dwg_thumbnailer`] core (also used by the Windows/macOS handlers).
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
pub fn extract_to_png(input: &std::path::Path, output: &std::path::Path, size: u32) -> bool {
match dwg_thumbnailer::extract(input, size) {
Some(mut img) => {