The road-surface drawing (대산당진 2공구_노면) rendered nothing for its
노면/부체도로면 geometry. The cause was not the renderer: the parseResult
contained zero MESH entities.
Two faults, both in the wasm parser, fixed upstream in hmwebviewer 35f5b1c:
1. dwg-wasm never serialized MESH. acadrust reads the entity in full; only the
JSON arm was missing.
2. acadrust's read_mesh clamped its array counts with the blanket 100_000-item
corrupt-data guard. This drawing's road mesh has 105_497 vertices, so the
count was truncated, the remaining vertex bits were never consumed, and the
face/edge/crease lists after them decoded from the wrong bit offset —
producing a plausible-looking vertex count next to a nonsense 14-face list.
Counts are now bounded by the bits actually left in the object stream.
before verts=100000 faces=14 face sizes [64, 0, 64, 23, 0, 0, 0, 15]
after verts=105497 faces=185444 face sizes [3, 3, 3, ...]
This commit carries the vendored side of that work:
- the rebuilt wasm, which now emits MESH as flat arrays (vertices [x,y,z,...],
faceList in DXF group-93 layout, deduplicated edges). The sample drawing goes
from 116 MB to 130 MB of parseResult with parse time unchanged at ~3.2 s.
- a MESH case in the property inspector (vertex/face/edge counts, subdivision
level, bbox and elevation range)
- docs/subdmesh-rendering.md, plus README pointers
- the acadrust licence notice, which can no longer say "consumed unmodified" —
read_mesh now carries a local patch. MPL-2.0 is file-level copyleft, so the
patched file stays under MPL and its source ships in hmwebviewer.
Verified: 9 MESH entities parsed from the drawing; entity histograms over six
other sample drawings are byte-identical to the previous wasm, so nothing else
moved.
Two deliberate omissions, both because a lineweight/fat-line refactor is in
flight in this working tree:
- Viewer2D.js is not included. Its _meshSegs helper and three MESH dispatch
sites share hunks with that refactor and cannot be separated; the same
renderer code is committed upstream in hmwebviewer 35f5b1c and will land here
with the refactor. docs/subdmesh-rendering.md records this.
- dist2/ is not rebuilt here. The current build embeds the half-wired
lineweight button and progress-bar markup; deploy per
docs/deploy-dist2-static-build.md once that work lands.
The wasm binary also carries the new lineweight parser fields (lwdisplay,
celweight, layer and entity lineWeight), since it was built from a tree that
already had them. They are additive JSON keys with no consumer in this commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This repository has no deploy script or CI: package.json only builds to
dist/ (gitignored), yet dist2/ is committed and is what actually gets
served. The procedure was folklore reconstructed from commit history each
time someone deployed.
Write it down, including the two traps found while deploying fb8f7ca:
- vite's emptyOutDir defaults to true when outDir sits inside the project
root, so a bare `vite build --outDir dist2` deletes the hand-placed test
assets in dist2/samples (configBak/, dwg_18.3mb.dwg). Always pass
--emptyOutDir false.
- npx vite can fail here with `Missing script: "vite"`; call
./node_modules/.bin/vite directly.
Also notes the open issues: no build:dist2 script, old hashed bundles
accumulating in dist2/assets, and test fixtures living inside the build
output directory.
Link it from the README issue table.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
setHiddenLayers() called load(result, {keepView:true}), so every layer
on/off re-parsed and re-tessellated the whole drawing — arc sampling,
hatch triangulation, complex linetypes and the Slug text batch all rebuilt
from scratch. On an 18 MB DWG a single eye-icon click took 5 s+.
Build every layer once, then switch geometry on and off:
- Merged LineSegments buffers get an index buffer plus a per-segment layer
id (_registerIndexed). A toggle rewrites the index and setDrawRange;
positions, colors and lineDistances are untouched, so draw order, dash
phase and the selection-highlight offsets in meta.colStart stay valid.
- Per-entity meshes (hatch fills, SOLID quads, arrowheads, OLE images,
sprites) are tagged by layer via _addObj and toggled with .visible.
- Slug text builds one merged mesh per CAD layer instead of one per
draw order, so text hides with a visible flag. The shader source is
identical across batches, so three still shares one WebGLProgram.
- Hidden geometry stays in the pick buffers, so _onClick now skips it via
the _metaHidden mask.
- Fit keeps framing only what is drawn: per-layer Box3 + fit samples are
recorded at build and unioned over the visible layers.
- getLayerInfo() caches the O(entities) name/color/count pass per load;
only the visible flag is recomputed.
Layer panel: one delegated click listener instead of re-binding a handler
per row, and a toggle patches the affected row's opacity/icon in place
rather than regenerating the whole list's innerHTML.
Trade-off: hidden layers are now built and kept in memory, so loading a
file with layers already off costs what a full load costs.
Rebuilds dist2.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
SlugTextBatch.add() scaled em-unit glyph outlines by the raw DWG
`height` value, but glyph ink only reaches capHeightEm (~0.74 em) of
the em box. Rendered cap height ended up ~26% short of spec (e.g. a
3.6-height TABLE cell text rendered at ~2.68), while the canvas-sprite
fallback already corrected for this via measured ascent. Divide by
capHeightEm so both paths agree.
Rebuilds dist2 (was stale since before the Entity selection/Property
Inspector/Layer panel work landed).
Mirrors hmwebviewer's rust/dwg-wasm change into the sample: the wasm
artifact plus the parser wrapper, which now goes through parse_dwg_json
and JSON.parse instead of the JsValue-returning parse_dwg.
Building the whole result as a serde_json::Value tree pushed the live
wasm heap near 2.9GB for a 19MB drawing, and the allocator's cost grows
with that heap, so parsing went quadratic — 354s, with the tab frozen
throughout. Streaming one entity at a time keeps it linear: 2.5s.
The same build also fixes three bugs that drew stray 4km grey shapes
where two CF-PATT SOLID hatches should be. Max hatch span 4655 -> 110.
Adds two docs recording both investigations, in the format of the
existing ones: measurements, the hypotheses that were ruled out, the
fixes, regression checks, and the MPL-2.0 position (acadrust is
unmodified, so no new source-disclosure obligation arises).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>