ifcviewer: multi-selection + box-select with active highlight

SelectionState (new) owns the multi-set, the "active" id (last single-
clicked), and a per-object_id flags SSBO bound at binding=3.  Main
shader reads sel_flags[v_object_id] for the in-set tint and a separate
u_active_id uniform for a stronger tint on the active.

Click semantics: plain replaces, Shift/Ctrl toggles.  LMB-drag past 5px
boxes the rect through a pick-pass readback — plain replaces, Shift
adds, Ctrl removes; box-select preserves the active.  Drag promotes
regardless of start point so a press on geometry doesn't disqualify it.

Sidecar fast-path bulk-loads instances, so noteObjectId is also called
from the apply path — without it the flags buffer was sized to 1 slot
while object_ids were in the 100k+ range and the in-set bit was lost.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-05-09 22:04:00 +10:00
parent d0c8c84e7b
commit bba2f30816
7 changed files with 659 additions and 43 deletions
+10
View File
@@ -20,6 +20,7 @@
#ifndef IFCVIEWER_OVERLAYRENDERER_H
#define IFCVIEWER_OVERLAYRENDERER_H
#include <QRect>
#include <QString>
#include <QtOpenGL/QOpenGLFunctions_4_5_Core>
@@ -86,6 +87,12 @@ public:
// render(). Empty hides the HUD.
void setHudText(const QString& text);
// Box-select rectangle (in logical pixel coords, top-left origin).
// Drawn as a translucent fill + 1-px outline using the same
// screen-space rect program that draws label/HUD backgrounds.
// Empty rect hides it.
void setSelectionRect(const QRect& rect_logical);
// Render every overlay primitive in order: GL highlight triangles
// (using `view_proj`, column-major float[16]), then HUD text via
// QPainter on a QOpenGLPaintDevice sized to (pixel_w × pixel_h)
@@ -182,6 +189,9 @@ private:
std::vector<Label> labels_;
QString hud_text_;
// Box-select rectangle in logical pixels. Null/empty = hidden.
QRect selection_rect_;
};
#endif // IFCVIEWER_OVERLAYRENDERER_H