3DFACE entities previously created one WireGpu buffer per entity,
resulting in N separate draw calls per frame. For files with large
triangle meshes this was the dominant GPU CPU overhead.
New pipeline:
- face3d.wgsl: simple flat-color vertex + fragment shader (MVP only,
no quad expansion, no pattern distance computation)
- Face3DGpu: batches ALL Face3D entities into a single TriangleList
buffer (6 vertices per face, per-vertex color) — 1 draw call
- WireGpu::from_batch: merges N Face3D edge wire models into one
quad-expanded buffer for edge rendering — 1 draw call
- split_face3d_wires: separates face3d from other wires at Primitive
build time via document handle lookup (O(N), once per epoch)
Hit-testing via WireModel (CPU) is unaffected — face3d wires remain
in entity_wires_arc() and hit_test_wires() as before.
Before: N 3DFACE → N draw calls, N × 96 B/vertex WireVertex
After: N 3DFACE → 2 draw calls (fill + edges), 28 B/vertex fill
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hide OS crosshair and drawn crosshair when cursor is over ViewCube area
- Enhanced hover glow in WGSL shader (blue tint + brightness boost)
- Fixed region_centroids() Y-axis sign for all FRONT/BACK-related regions
- Swapped corner geometry assignments (TPF↔TBK, BTF↔BBK) to match
intended FRONT/BACK semantics (sy=-1 = FRONT, sy=+1 = BACK)
- Corrected all snap_angles: yaw_pitch_to_quat(0,0) places eye at -Y
(FRONT view), so FRONT=0 and BACK=PI — cascaded through edges/corners
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MSAA and depth textures are now sized to the shader widget's clip
bounds instead of the full surface. The resolve writes to a matching
clip-sized intermediate texture; a blit pass (blit.wgsl, viewport
trick) then copies the result to the exact clip region of the surface
target, leaving all other widgets untouched.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>