From 68d6280c93f3d6fddd46a160b7bf54de62f3c9e9 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 2 Jul 2026 15:47:03 +1000 Subject: [PATCH] =?UTF-8?q?ifcviewer:=20visibility=20(hide/isolate/show-al?= =?UTF-8?q?l)=20+=20X-ray=20=E2=80=94=20desktop=20parity=20on=20web?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lift the visibility + X-ray ops into ViewportCore so desktop and web share them. The cull already reads visibility_ (hidden objects skipped) and the frame uniform reads xray_alpha_cap_, both per frame, so each op just mutates state + schedules a frame — no GPU buffers to rebuild, no rendering work: - hideSelected (hide the selection, then deselect), isolateSelected (hide every non-selected object in a visible model), showAll (clear the hidden set), toggleXray (flip the alpha cap 1.0<->0.3; cull routes all to the transparent pass), xrayActive(). - Desktop ViewportWindow: the H / Shift+H / Alt+H / Alt+X keys and the menu-action wrappers now call the core; the four inline/duplicated implementations are gone. - Web main_web: same keys (H hide · Shift+H isolate · Alt+H show all · Alt+X x-ray) + toolbar buttons (Hide / Isolate / Show all / X-ray, the last reflecting active state). Verified on web: x-ray toggles and visibly translucent-izes the scene, hide after a pick removes geometry, 0 GPU errors. 113/113 desktop + 6/6 web smoke; desktop app builds. Co-Authored-By: Claude Opus 4.8 --- src/ifcviewer-web/CMakeLists.txt | 2 +- src/ifcviewer-web/main_web.cpp | 17 +++++++ src/ifcviewer-web/shell.html | 13 +++++ src/ifcviewer/ViewportCore.cpp | 43 ++++++++++++++++ src/ifcviewer/ViewportCore.h | 13 +++++ src/ifcviewer/ViewportWindow.cpp | 85 ++++---------------------------- 6 files changed, 97 insertions(+), 76 deletions(-) diff --git a/src/ifcviewer-web/CMakeLists.txt b/src/ifcviewer-web/CMakeLists.txt index aa3301eb1c..e7dbb004f5 100644 --- a/src/ifcviewer-web/CMakeLists.txt +++ b/src/ifcviewer-web/CMakeLists.txt @@ -104,7 +104,7 @@ target_link_options(IfcViewerWeb PRIVATE # EMSCRIPTEN_KEEPALIVE alone keeps the symbols in the binary but doesn't # add them to Module. ccall lets shell.html pass a JS string (the ?model # URL) to load_sidecar_from_url_c without manual heap marshalling. - "-sEXPORTED_FUNCTIONS=['_main','_raf_tick_c','_load_sidecar_from_source_c','_clear_scene_c','_ifcv_on_range_done','_ifcv_chunks_resident_c','_ifcv_chunks_total_c','_ifcv_model_count_c','_ifcv_model_resident_c','_ifcv_model_total_c','_ifcv_bytes_total_c','_ifcv_bytes_needed_c','_ifcv_bytes_loaded_c','_view_all_c','_frame_selection_c','_toggle_projection_c','_projection_is_ortho_c','_standard_view_c','_toggle_fly_c','_fly_is_active_c']" + "-sEXPORTED_FUNCTIONS=['_main','_raf_tick_c','_load_sidecar_from_source_c','_clear_scene_c','_ifcv_on_range_done','_ifcv_chunks_resident_c','_ifcv_chunks_total_c','_ifcv_model_count_c','_ifcv_model_resident_c','_ifcv_model_total_c','_ifcv_bytes_total_c','_ifcv_bytes_needed_c','_ifcv_bytes_loaded_c','_view_all_c','_frame_selection_c','_toggle_projection_c','_projection_is_ortho_c','_standard_view_c','_toggle_fly_c','_fly_is_active_c','_hide_selected_c','_isolate_selected_c','_show_all_c','_toggle_xray_c','_xray_is_active_c']" # ccall: shell.html passes the ?model URL string to load_sidecar_from_url_c. # HEAPU8: lets tooling/tests read the wasm heap size (e.g. to verify a large # sidecar streams by range instead of loading whole). Standard, zero-cost. diff --git a/src/ifcviewer-web/main_web.cpp b/src/ifcviewer-web/main_web.cpp index af6b64ef93..4a0d02bde8 100644 --- a/src/ifcviewer-web/main_web.cpp +++ b/src/ifcviewer-web/main_web.cpp @@ -227,6 +227,16 @@ EM_BOOL onKeyDown(int, const EmscriptenKeyboardEvent* e, void* user) { // While flying, WASDQE/Shift are held-movement keys, not hotkeys. if (app->fly_mode) { if (setFlyKey(app, code, true)) return EM_TRUE; return EM_FALSE; } if (e->repeat) return EM_FALSE; + const bool alt = e->altKey; + // Visibility + X-ray, matching desktop: H hide selected · Shift+H isolate · + // Alt+H show all · Alt+X x-ray. + if (!std::strcmp(code, "KeyH")) { + if (alt) app->core.showAll(); + else if (shift) app->core.isolateSelected(); + else app->core.hideSelected(); + return EM_TRUE; + } + if (!std::strcmp(code, "KeyX") && alt) { app->core.toggleXray(); return EM_TRUE; } using SV = ViewportCore::StandardView; if (!std::strcmp(code, "Home")) app->core.viewAll(); else if (!std::strcmp(code, "KeyF") && !shift) app->core.frameSelection(); @@ -356,6 +366,13 @@ extern "C" EMSCRIPTEN_KEEPALIVE int fly_is_active_c() { return (g_app && g_app->ready && g_app->fly_mode) ? 1 : 0; } +// Visibility + X-ray, for the toolbar (same ops as the H/Shift+H/Alt+H/Alt+X keys). +extern "C" EMSCRIPTEN_KEEPALIVE void hide_selected_c() { if (g_app && g_app->ready) g_app->core.hideSelected(); } +extern "C" EMSCRIPTEN_KEEPALIVE void isolate_selected_c() { if (g_app && g_app->ready) g_app->core.isolateSelected(); } +extern "C" EMSCRIPTEN_KEEPALIVE void show_all_c() { if (g_app && g_app->ready) g_app->core.showAll(); } +extern "C" EMSCRIPTEN_KEEPALIVE void toggle_xray_c() { if (g_app && g_app->ready) g_app->core.toggleXray(); } +extern "C" EMSCRIPTEN_KEEPALIVE int xray_is_active_c() { return (g_app && g_app->ready && g_app->core.xrayActive()) ? 1 : 0; } + // id: 0 Front, 1 Back, 2 Left, 3 Right, 4 Top, 5 Bottom. extern "C" EMSCRIPTEN_KEEPALIVE void standard_view_c(int id) { if (!g_app || !g_app->ready || id < 0 || id > 5) return; diff --git a/src/ifcviewer-web/shell.html b/src/ifcviewer-web/shell.html index 846179b3b7..17ec6f082f 100644 --- a/src/ifcviewer-web/shell.html +++ b/src/ifcviewer-web/shell.html @@ -86,6 +86,11 @@ + + + + +
Starting…