Draw a silhouette outline around the selection

The renderer tints the selection blue, which says nothing about an object
that is already blue. Add a halo drawn just outside the selected objects
instead: a fixed colour against the background, so it reads whatever the
element is painted.

The mask pass reuses the main shader module and pipeline layout and shares
the main depth buffer read-only, so the halo follows the selection as
visible -- an occluded object contributes nothing. A separable dilation
widens the mask into inner and outer rings, composited after the edge pass
so the edge multiply does not darken it.

On by default; IfcViewer.setSelectionOutline(false) gets the tint alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-08-03 18:07:52 +10:00
parent 83a7836081
commit c9f269a0e5
6 changed files with 619 additions and 1 deletions
+9
View File
@@ -592,6 +592,14 @@ extern "C" EMSCRIPTEN_KEEPALIVE void show_all_c() { if (g_app && g_app->
extern "C" EMSCRIPTEN_KEEPALIVE void hide_all_c() { if (g_app && g_app->ready) g_app->core.hideAll(); }
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; }
extern "C" EMSCRIPTEN_KEEPALIVE void ifcv_set_selection_outline_c(int on) {
if (!g_app || !g_app->ready) return;
g_app->core.setSelectionOutlineEnabled(on != 0);
g_app->host.requestFrame();
}
extern "C" EMSCRIPTEN_KEEPALIVE int ifcv_selection_outline_is_on_c() {
return (g_app && g_app->ready && g_app->core.selectionOutlineEnabled()) ? 1 : 0;
}
// ===========================================================================
// Scripting API (web/ifcviewer.js wraps these into the IfcViewer object)
@@ -808,6 +816,7 @@ int main(int /*argc*/, char** /*argv*/) {
g_app->core.buildHizPipeline();
g_app->core.buildEdgePipeline();
g_app->core.buildPickPipeline();
g_app->core.buildSelectionOutlinePipelines();
// Load the embedded sample sidecar (mounted into MEMFS via
// --embed-file in CMakeLists.txt). The sample stays on the