mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-17 10:59:17 +00:00
ifcviewer: visibility (hide/isolate/show-all) + X-ray — desktop parity on web
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 <noreply@anthropic.com>
This commit is contained in:
@@ -1124,36 +1124,11 @@ void ViewportWindow::setSelectedObjectId(uint32_t id) {
|
||||
if (isExposed()) requestUpdate();
|
||||
}
|
||||
|
||||
void ViewportWindow::hideSelectedElements() {
|
||||
if (selection_.count() == 0) return;
|
||||
for (uint32_t id : selection_.selectionIds()) visibility_.hide(id);
|
||||
selection_.clear();
|
||||
if (isExposed()) requestUpdate();
|
||||
}
|
||||
|
||||
void ViewportWindow::isolateSelectedElements() {
|
||||
if (selection_.count() == 0) return;
|
||||
// Hide every object in a visible model that isn't in the selection.
|
||||
// Model-hidden objects stay model-hidden — element-level hiding on
|
||||
// top of that is redundant and just bloats hidden_ids_.
|
||||
const auto& sel_ids = selection_.selectionIds();
|
||||
for (const auto& [mid, m] : models_gpu_) {
|
||||
if (m.hidden) continue;
|
||||
for (const InstanceCpu& inst : m.instances) {
|
||||
if (inst.object_id == 0) continue;
|
||||
if (sel_ids.find(inst.object_id) == sel_ids.end()) {
|
||||
visibility_.hide(inst.object_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isExposed()) requestUpdate();
|
||||
}
|
||||
|
||||
void ViewportWindow::showAllElements() {
|
||||
if (visibility_.hiddenCount() == 0) return;
|
||||
visibility_.clear();
|
||||
if (isExposed()) requestUpdate();
|
||||
}
|
||||
// Visibility ops now live in ViewportCore (shared with web); these stay as thin
|
||||
// Qt-facing wrappers for the menu actions.
|
||||
void ViewportWindow::hideSelectedElements() { core_.hideSelected(); }
|
||||
void ViewportWindow::isolateSelectedElements() { core_.isolateSelected(); }
|
||||
void ViewportWindow::showAllElements() { core_.showAll(); }
|
||||
|
||||
void ViewportWindow::invertElementVisibility() {
|
||||
// Compute the new hidden set: every live object_id in a visible model
|
||||
@@ -1988,53 +1963,13 @@ void ViewportWindow::keyPressEvent(QKeyEvent* event) {
|
||||
// Shift+H — isolate selected
|
||||
// Alt+H — show all (clear hidden set)
|
||||
// Shift+F — enter fly mode (Esc exits)
|
||||
if (key == Qt::Key_H && mods == Qt::AltModifier) {
|
||||
if (visibility_.hiddenCount() == 0) return;
|
||||
visibility_.clear();
|
||||
Log::info() << "[wgpu] show all";
|
||||
requestUpdate();
|
||||
return;
|
||||
}
|
||||
// Alt+X — toggle global X-ray (translucent everything). The frame
|
||||
// uniform `xray_alpha_cap` clamps `fs_main`'s output alpha; the cull
|
||||
// classifier sees `xray_alpha_cap_ < 1` and routes every instance
|
||||
// through the transparent pass so the blend actually fires.
|
||||
// Visibility + X-ray math lives in ViewportCore (shared with web).
|
||||
if (key == Qt::Key_H && mods == Qt::AltModifier) { core_.showAll(); return; }
|
||||
if (key == Qt::Key_X && mods == Qt::AltModifier && !event->isAutoRepeat()) {
|
||||
constexpr float kXrayOnCap = 0.3f;
|
||||
xray_alpha_cap_ = (xray_alpha_cap_ < 1.0f) ? 1.0f : kXrayOnCap;
|
||||
Log::info().noquote().nospace()
|
||||
<< "[wgpu] x-ray "
|
||||
<< (xray_alpha_cap_ < 1.0f ? "ON" : "OFF")
|
||||
<< " (cap=" << xray_alpha_cap_ << ")";
|
||||
requestUpdate();
|
||||
return;
|
||||
}
|
||||
if (key == Qt::Key_H && mods == Qt::ShiftModifier) {
|
||||
if (selection_.count() == 0) return;
|
||||
size_t hidden_now = 0;
|
||||
for (auto& [mid, m] : models_gpu_) {
|
||||
for (const auto& inst : m.instances) {
|
||||
if (selection_.contains(inst.object_id)) continue;
|
||||
if (!visibility_.isHidden(inst.object_id)) {
|
||||
visibility_.hide(inst.object_id);
|
||||
++hidden_now;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log::info().noquote().nospace() << "[wgpu] isolated " << selection_.count()
|
||||
<< " (hid " << hidden_now << " others)";
|
||||
requestUpdate();
|
||||
return;
|
||||
}
|
||||
if (key == Qt::Key_H && mods == Qt::NoModifier) {
|
||||
if (selection_.count() == 0) return;
|
||||
for (uint32_t id : selection_.selectionIds()) visibility_.hide(id);
|
||||
const size_t n = selection_.count();
|
||||
selection_.clear(); // hiding deselects, matching GL behaviour
|
||||
Log::info().noquote().nospace() << "[wgpu] hid " << n << " selected";
|
||||
requestUpdate();
|
||||
return;
|
||||
core_.toggleXray(); return;
|
||||
}
|
||||
if (key == Qt::Key_H && mods == Qt::ShiftModifier) { core_.isolateSelected(); return; }
|
||||
if (key == Qt::Key_H && mods == Qt::NoModifier) { core_.hideSelected(); return; }
|
||||
if (key == Qt::Key_F && mods == Qt::ShiftModifier && !event->isAutoRepeat()) {
|
||||
enterFpsMode();
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user