mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-30 08:33:10 +00:00
wgpu: marquee box-select (drag rect + Shift/Ctrl set ops)
Drag LMB in empty space to select every visible object whose pick-pixel
falls inside the rect. Mirrors GL ViewportWindow's marquee.
UI flow
- LMB press in non-tool-consuming context arms the marquee. The
cursor must move past kBoxSelectThresholdPx (5 logical) for it to
become active — until then a release falls through to single-pick,
so an unintentional micro-drag still picks under the cursor.
- Press-time modifiers decide the set op so a mid-drag Shift release
doesn't flip behaviour:
plain → selection.clear() then add every picked id
Shift → add to current selection
Ctrl → remove from current selection
- Section tool intercepts plain LMB first (already wired); the
marquee is mutually exclusive with it.
Rectangle pick
picksInRect(x, y, w, h):
- Render the existing pick pass (R32UInt object_id + RGBA16F normal
MRT) into the persistent pick attachments.
- copyTextureToBuffer the rect region of pick_color_texture_ into
box_pick_staging_buffer_ (regrown 2× on demand to fit the
largest rect we've seen). R32UInt is a color format so partial
sub-rect copies are allowed (unlike Depth32Float).
- Iterate the mapped staging buffer, accumulate unique non-zero ids
into an unordered_set, return.
Visual rect
A new marquee overlay pipeline draws the drag rect on the resolved
surface after the corner gizmo. Two passes per active frame share one
uniform buffer / bind group:
fill — 6-vert unit quad, vs_fill maps (0,1)² to NDC via
rect_min/rect_max, fs_fill outputs color × fill_alpha
outline — 24-vert thick-line quad (4 segs × 6 verts), uses the
shared thick_line_clip + fs_main from THICK_LINE_HELPERS_WGSL
so the rect outline has analytical AA without MSAA
Colour: Bonsai decorator_color_special (0.157, 0.565, 1.000) for the
axis-blue parity the user requested; outline alpha 0.95, fill alpha
0.20 of that so geometry behind the rect still reads.
Closes #41 and #61.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "SidecarCache.h"
|
||||
#include "WgpuBufferPool.h"
|
||||
@@ -266,6 +267,11 @@ private:
|
||||
QVector3D& world_pos_out,
|
||||
QVector3D& world_normal_out,
|
||||
float* aabb_radius_out = nullptr);
|
||||
// Rectangle pick: render the pick pass, copy the rect region of the
|
||||
// R32UInt color attachment, and return every unique non-zero
|
||||
// object_id covered. `rect` is in physical pixels (post-DPR), already
|
||||
// clipped to the framebuffer by the caller.
|
||||
std::vector<uint32_t> picksInRect(int x, int y, int w, int h);
|
||||
|
||||
// Section-cutting tool. Mirrors the GL ViewportWindow API:
|
||||
// K toggle (sectionToolActive / toggleSectionTool)
|
||||
@@ -461,6 +467,22 @@ private:
|
||||
WGPURenderPipeline axis_pivot_pipeline_ = nullptr;
|
||||
WGPURenderPipeline axis_pivot_xray_pipeline_ = nullptr;
|
||||
WGPURenderPipeline axis_corner_pipeline_ = nullptr;
|
||||
// Marquee overlay (drag-rect for box-select). Renders on the resolved
|
||||
// surface after the corner gizmo. Uses a 4-segment unit-quad VBO; the
|
||||
// shader maps unit coords to NDC via per-frame uniform (rect min/max
|
||||
// in NDC + colour + viewport + line width).
|
||||
WGPUShaderModule marquee_shader_module_ = nullptr;
|
||||
WGPUBindGroupLayout marquee_bgl_ = nullptr;
|
||||
WGPUPipelineLayout marquee_pipeline_layout_ = nullptr;
|
||||
WGPURenderPipeline marquee_pipeline_ = nullptr; // outline (thick line + AA)
|
||||
WGPURenderPipeline marquee_fill_pipeline_ = nullptr; // translucent quad fill
|
||||
WGPUBuffer marquee_vertex_buffer_ = nullptr; // outline geometry
|
||||
WGPUBuffer marquee_fill_vertex_buffer_ = nullptr; // 6-vert quad
|
||||
WGPUBuffer marquee_uniform_buffer_ = nullptr;
|
||||
WGPUBindGroup marquee_bind_group_ = nullptr;
|
||||
bool buildMarquee();
|
||||
void encodeMarquee(WGPUCommandEncoder enc, WGPUTextureView surface_view);
|
||||
void releaseMarquee();
|
||||
WGPUBuffer axis_vertex_buffer_ = nullptr; // 6 × 24 B
|
||||
WGPUBuffer axis_uniform_buffer_ = nullptr; // 3 × 256 B slots
|
||||
WGPUBindGroup axis_bind_group_ = nullptr; // dynamic-offset
|
||||
@@ -500,6 +522,22 @@ private:
|
||||
};
|
||||
std::vector<SectionPlane> section_planes_;
|
||||
bool section_tool_active_ = false;
|
||||
|
||||
// Marquee box-select. Armed on LMB press (when no other tool consumes
|
||||
// the click), becomes active after the cursor moves past
|
||||
// kBoxSelectThresholdPx — until then a release still routes through
|
||||
// the single-pick path. Press-time modifiers decide the set op at
|
||||
// release: plain → replace, Shift → add, Ctrl → remove.
|
||||
bool box_select_armed_ = false;
|
||||
bool box_select_active_ = false;
|
||||
QPoint box_select_start_pos_; // logical px
|
||||
QPoint box_select_current_pos_; // logical px
|
||||
Qt::KeyboardModifiers box_select_press_mods_ = Qt::NoModifier;
|
||||
static constexpr int kBoxSelectThresholdPx = 5;
|
||||
// R32UInt staging for the rect-pick. Sized to the largest rect we've
|
||||
// seen so far (padded to 256 bpr), regrown if a bigger rect arrives.
|
||||
WGPUBuffer box_pick_staging_buffer_ = nullptr;
|
||||
uint64_t box_pick_staging_capacity_ = 0;
|
||||
// Drag-to-move state for the arrow gizmo. While `section_drag_active_`
|
||||
// is true, mouseMoveEvent calls updateSectionDrag instead of letting
|
||||
// the press fall through to the orbit/pan handlers.
|
||||
|
||||
Reference in New Issue
Block a user