Selection: Remove limit on number of items which can be selected at once #112491

Merged
Jesse Yurkovich merged 10 commits from deadpin/blender:fixselection into main 2023-11-30 21:27:23 +01:00
15 changed files with 274 additions and 379 deletions

View File

@ -294,24 +294,26 @@ struct Bone *ED_armature_pick_bone(struct bContext *C,
bool findunsel,
struct Base **r_base);
struct EditBone *ED_armature_pick_ebone_from_selectbuffer(struct Base **bases,
uint bases_len,
const struct GPUSelectResult *buffer,
short hits,
bool findunsel,
bool do_nearest,
struct Base **r_base);
struct bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(struct Base **bases,
uint bases_len,
const struct GPUSelectResult *buffer,
short hits,
bool findunsel,
bool do_nearest,
struct Base **r_base);
struct EditBone *ED_armature_pick_ebone_from_selectbuffer(
struct Base **bases,
uint bases_len,
const struct GPUSelectResult *hit_results,
int hits,
bool findunsel,
bool do_nearest,
struct Base **r_base);
struct bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(
struct Base **bases,
uint bases_len,
const struct GPUSelectResult *hit_results,
int hits,
bool findunsel,
bool do_nearest,
struct Base **r_base);
struct Bone *ED_armature_pick_bone_from_selectbuffer(struct Base **bases,
uint bases_len,
const struct GPUSelectResult *buffer,
short hits,
const struct GPUSelectResult *hit_results,
int hits,
bool findunsel,
bool do_nearest,
struct Base **r_base);

View File

@ -155,34 +155,33 @@ Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
/* See if there are any selected bones in this buffer */
/* only bones from base are checked on */
static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode,
Base **bases,
uint bases_len,
const GPUSelectResult *buffer,
const short hits,
bool findunsel,
bool do_nearest,
Base **r_base)
static void *ed_armature_pick_bone_from_selectbuffer_impl(
const bool is_editmode,
Base **bases,
uint bases_len,
const blender::Span<GPUSelectResult> hit_results,
bool findunsel,
bool do_nearest,
Base **r_base)
{
bPoseChannel *pchan;
EditBone *ebone;
void *firstunSel = nullptr, *firstSel = nullptr, *data;
Base *firstunSel_base = nullptr, *firstSel_base = nullptr;
uint hitresult;
bool takeNext = false;
int minsel = 0xffffffff, minunsel = 0xffffffff;
for (short i = 0; i < hits; i++) {
hitresult = buffer[i].id;
for (const GPUSelectResult &result : hit_results) {
uint hit_id = result.id;
if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
if (hit_id & BONESEL_ANY) { /* to avoid including objects in selection */
Base *base = nullptr;
bool sel;
hitresult &= ~BONESEL_ANY;
hit_id &= ~BONESEL_ANY;
/* Determine what the current bone is */
if (is_editmode == false) {
base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hitresult, &pchan);
base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hit_id, &pchan);
if (pchan != nullptr) {
if (findunsel) {
sel = (pchan->bone->flag & BONE_SELECTED);
@ -199,7 +198,7 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode
}
}
else {
base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hit_id, &ebone);
if (findunsel) {
sel = (ebone->flag & BONE_SELECTED);
}
@ -213,10 +212,10 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode
if (data) {
if (sel) {
if (do_nearest) {
if (minsel > buffer[i].depth) {
if (minsel > result.depth) {
firstSel = data;
firstSel_base = base;
minsel = buffer[i].depth;
minsel = result.depth;
}
}
else {
@ -229,10 +228,10 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode
}
else {
if (do_nearest) {
if (minunsel > buffer[i].depth) {
if (minunsel > result.depth) {
firstunSel = data;
firstunSel_base = base;
minunsel = buffer[i].depth;
minunsel = result.depth;
}
}
else {
@ -260,40 +259,40 @@ static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode
EditBone *ED_armature_pick_ebone_from_selectbuffer(Base **bases,
uint bases_len,
const GPUSelectResult *buffer,
const short hits,
const GPUSelectResult *hit_results,
const int hits,
bool findunsel,
bool do_nearest,
Base **r_base)
{
const bool is_editmode = true;
return static_cast<EditBone *>(ed_armature_pick_bone_from_selectbuffer_impl(
is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base));
is_editmode, bases, bases_len, {hit_results, hits}, findunsel, do_nearest, r_base));
}
bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(Base **bases,
uint bases_len,
const GPUSelectResult *buffer,
const short hits,
const GPUSelectResult *hit_results,
const int hits,
bool findunsel,
bool do_nearest,
Base **r_base)
{
const bool is_editmode = false;
return static_cast<bPoseChannel *>(ed_armature_pick_bone_from_selectbuffer_impl(
is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base));
is_editmode, bases, bases_len, {hit_results, hits}, findunsel, do_nearest, r_base));
}
Bone *ED_armature_pick_bone_from_selectbuffer(Base **bases,
uint bases_len,
const GPUSelectResult *buffer,
const short hits,
const GPUSelectResult *hit_results,
const int hits,
bool findunsel,
bool do_nearest,
Base **r_base)
{
bPoseChannel *pchan = ED_armature_pick_pchan_from_selectbuffer(
bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
bases, bases_len, hit_results, hits, findunsel, do_nearest, r_base);
return pchan ? pchan->bone : nullptr;
}
@ -318,8 +317,8 @@ static void *ed_armature_pick_bone_impl(
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
rcti rect;
GPUSelectResult buffer[MAXPICKELEMS];
short hits;
GPUSelectBuffer buffer;
int hits;
ViewContext vc = ED_view3d_viewcontext_init(C, depsgraph);
BLI_assert((vc.obedit != nullptr) == is_editmode);
@ -329,13 +328,8 @@ static void *ed_armature_pick_bone_impl(
/* Don't use hits with this ID, (armature drawing uses this). */
const int select_id_ignore = -1;
hits = view3d_opengl_select_with_id_filter(&vc,
buffer,
ARRAY_SIZE(buffer),
&rect,
VIEW3D_SELECT_PICK_NEAREST,
VIEW3D_SELECT_FILTER_NOP,
select_id_ignore);
hits = view3d_opengl_select_with_id_filter(
&vc, &buffer, &rect, VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP, select_id_ignore);
*r_base = nullptr;
@ -352,7 +346,13 @@ static void *ed_armature_pick_bone_impl(
}
void *bone = ed_armature_pick_bone_from_selectbuffer_impl(
is_editmode, bases, bases_len, buffer, hits, findunsel, true, r_base);
is_editmode,
bases,
bases_len,
buffer.storage.as_span().take_front(hits),
findunsel,
true,
r_base);
MEM_freeN(bases);
@ -629,15 +629,18 @@ void ARMATURE_OT_select_linked_pick(wmOperatorType *ot)
* \{ */
/* utility function for get_nearest_editbonepoint */
static int selectbuffer_ret_hits_12(GPUSelectResult * /*buffer*/, const int hits12)
static int selectbuffer_ret_hits_12(blender::MutableSpan<GPUSelectResult> /*results*/,
const int hits12)
{
return hits12;
}
static int selectbuffer_ret_hits_5(GPUSelectResult *buffer, const int hits12, const int hits5)
static int selectbuffer_ret_hits_5(blender::MutableSpan<GPUSelectResult> results,
const int hits12,
const int hits5)
{
const int ofs = hits12;
deadpin marked this conversation as resolved Outdated

These are incorrect. It should be
results.slice(0, hits5).copy_from(results.slice(ofs, hits5));
Same goes for the other 2 copy_from in this patch.

These are incorrect. It should be `results.slice(0, hits5).copy_from(results.slice(ofs, hits5));` Same goes for the other 2 `copy_from` in this patch.
memcpy(buffer, buffer + ofs, hits5 * sizeof(*buffer));
results.slice(0, hits5).copy_from(results.slice(ofs, hits5)); /* Shift results to beginning. */
return hits5;
}
@ -646,7 +649,7 @@ static int selectbuffer_ret_hits_5(GPUSelectResult *buffer, const int hits12, co
static EditBone *get_nearest_editbonepoint(
ViewContext *vc, bool findunsel, bool use_cycle, Base **r_base, int *r_selmask)
{
GPUSelectResult buffer[MAXPICKELEMS];
GPUSelectBuffer buffer;
struct Result {
uint hitresult;
Base *base;
@ -688,44 +691,32 @@ static EditBone *get_nearest_editbonepoint(
const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
const eV3DSelectObjectFilter select_filter = VIEW3D_SELECT_FILTER_NOP;
GPUSelectStorage &storage = buffer.storage;
rcti rect;
BLI_rcti_init_pt_radius(&rect, vc->mval, 12);
const int hits12 = view3d_opengl_select_with_id_filter(vc,
buffer,
ARRAY_SIZE(buffer),
&rect,
eV3DSelectMode(select_mode),
select_filter,
select_id_ignore);
const int hits12 = view3d_opengl_select_with_id_filter(
vc, &buffer, &rect, eV3DSelectMode(select_mode), select_filter, select_id_ignore);
if (hits12 == 1) {
hits = selectbuffer_ret_hits_12(buffer, hits12);
hits = selectbuffer_ret_hits_12(storage.as_mutable_span(), hits12);
goto cache_end;
}
else if (hits12 > 0) {
int ofs;
ofs = hits12;
BLI_rcti_init_pt_radius(&rect, vc->mval, 5);
const int hits5 = view3d_opengl_select_with_id_filter(vc,
buffer + ofs,
ARRAY_SIZE(buffer) - ofs,
&rect,
eV3DSelectMode(select_mode),
select_filter,
select_id_ignore);
const int hits5 = view3d_opengl_select_with_id_filter(
deadpin marked this conversation as resolved Outdated

Warning: Unused variable

Warning: Unused variable
vc, &buffer, &rect, eV3DSelectMode(select_mode), select_filter, select_id_ignore);
if (hits5 == 1) {
hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
hits = selectbuffer_ret_hits_5(storage.as_mutable_span(), hits12, hits5);
goto cache_end;
}
if (hits5 > 0) {
hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
hits = selectbuffer_ret_hits_5(storage.as_mutable_span(), hits12, hits5);
goto cache_end;
}
else {
hits = selectbuffer_ret_hits_12(buffer, hits12);
hits = selectbuffer_ret_hits_12(storage.as_mutable_span(), hits12);
goto cache_end;
}
}
@ -741,7 +732,7 @@ cache_end:
/* See if there are any selected bones in this group */
if (hits > 0) {
if (hits == 1) {
result_bias.hitresult = buffer->id;
result_bias.hitresult = buffer.storage[0].id;
result_bias.base = ED_armature_base_and_ebone_from_select_buffer(
bases, bases_len, result_bias.hitresult, &result_bias.ebone);
}
@ -780,7 +771,7 @@ cache_end:
}
for (int i = 0; i < hits; i++) {
const uint hitresult = buffer[i].id;
const uint hitresult = buffer.storage[i].id;
Base *base = nullptr;
EditBone *ebone;

View File

@ -258,8 +258,8 @@ bool ED_armature_pose_select_pick_with_buffer(const Scene *scene,
ViewLayer *view_layer,
View3D *v3d,
Base *base,
const GPUSelectResult *buffer,
const short hits,
const GPUSelectResult *hit_results,
const int hits,
const SelectPick_Params *params,
bool do_nearest)
{
@ -273,7 +273,7 @@ bool ED_armature_pose_select_pick_with_buffer(const Scene *scene,
/* Callers happen to already get the active base */
Base *base_dummy = nullptr;
nearBone = ED_armature_pick_bone_from_selectbuffer(
&base, 1, buffer, hits, true, do_nearest, &base_dummy);
&base, 1, hit_results, hits, true, do_nearest, &base_dummy);
return ED_armature_pose_select_pick_bone(scene, view_layer, v3d, ob, nearBone, params);
}

View File

@ -300,8 +300,8 @@ bool ED_armature_pose_select_pick_with_buffer(const Scene *scene,
ViewLayer *view_layer,
View3D *v3d,
Base *base,
const GPUSelectResult *buffer,
short hits,
const GPUSelectResult *hit_results,
int hits,
const SelectPick_Params *params,
bool do_nearest);
/**

View File

@ -27,7 +27,7 @@ struct Camera;
struct CustomData_MeshMasks;
struct Depsgraph;
struct EditBone;
struct GPUSelectResult;
struct GPUSelectBuffer;
struct ID;
struct Main;
struct MetaElem;
@ -877,15 +877,6 @@ bool ED_view3d_autodist_simple(ARegion *region,
bool ED_view3d_depth_read_cached_seg(
const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *depth);
/**
* The default value for the maximum number of elements that can be selected at once
* using view-port selection.
*
* \note in many cases this defines the size of fixed-size stack buffers,
* so take care increasing this value.
*/
#define MAXPICKELEMS 2500
enum eV3DSelectMode {
/* all elements in the region, ignore depth */
VIEW3D_SELECT_ALL = 0,
@ -915,28 +906,21 @@ void view3d_opengl_select_cache_begin();
void view3d_opengl_select_cache_end();
/**
* \warning be sure to account for a negative return value
* This is an error, "Too many objects in select buffer"
* and no action should be taken (can crash blender) if this happens
*
* \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
*/
int view3d_opengl_select_ex(ViewContext *vc,
GPUSelectResult *buffer,
unsigned int buffer_len,
GPUSelectBuffer *buffer,
const rcti *input,
eV3DSelectMode select_mode,
eV3DSelectObjectFilter select_filter,
bool do_material_slot_selection);
int view3d_opengl_select(ViewContext *vc,
GPUSelectResult *buffer,
unsigned int buffer_len,
GPUSelectBuffer *buffer,
const rcti *input,
eV3DSelectMode select_mode,
eV3DSelectObjectFilter select_filter);
int view3d_opengl_select_with_id_filter(ViewContext *vc,
GPUSelectResult *buffer,
unsigned int buffer_len,
GPUSelectBuffer *buffer,
const rcti *input,
eV3DSelectMode select_mode,
eV3DSelectObjectFilter select_filter,

View File

@ -772,7 +772,7 @@ static bool ed_mball_findnearest_metaelem(bContext *C,
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
int a, hits;
GPUSelectResult buffer[MAXPICKELEMS];
GPUSelectBuffer buffer;
rcti rect;
bool found = false;
@ -781,8 +781,7 @@ static bool ed_mball_findnearest_metaelem(bContext *C,
BLI_rcti_init_pt_radius(&rect, mval, 12);
hits = view3d_opengl_select(&vc,
buffer,
ARRAY_SIZE(buffer),
&buffer,
&rect,
use_cycle ? VIEW3D_SELECT_PICK_ALL : VIEW3D_SELECT_PICK_NEAREST,
VIEW3D_SELECT_FILTER_NOP);
@ -809,7 +808,7 @@ static bool ed_mball_findnearest_metaelem(bContext *C,
* ensure this steps onto the next meta-element. */
a = hits;
while (a--) {
const int select_id = buffer[a].id;
const int select_id = buffer.storage[a].id;
if (select_id == -1) {
continue;
}
@ -825,7 +824,7 @@ static bool ed_mball_findnearest_metaelem(bContext *C,
for (a = 0; a < hits; a++) {
const int index = (hit_cycle_offset == 0) ? a : ((a + hit_cycle_offset) % hits);
const uint select_id = buffer[index].id;
const uint select_id = buffer.storage[index].id;
if (select_id == -1) {
continue;
}

View File

@ -31,6 +31,7 @@
#include "BLI_math_bits.h"
#include "BLI_math_geom.h"
#include "BLI_rect.h"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
@ -1676,8 +1677,7 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot)
*/
static bool object_mouse_select_menu(bContext *C,
ViewContext *vc,
const GPUSelectResult *buffer,
const int hits,
const blender::Span<GPUSelectResult> hit_results,
const int mval[2],
const SelectPick_Params *params,
Base **r_basact)
@ -1702,12 +1702,12 @@ static bool object_mouse_select_menu(bContext *C,
uint depth_id;
/* two selection methods, the CTRL select uses max dist of 15 */
if (buffer) {
for (int a = 0; a < hits; a++) {
if (!hit_results.is_empty()) {
for (const GPUSelectResult &result : hit_results) {
/* index was converted */
if (base->object->runtime->select_id == (buffer[a].id & ~0xFFFF0000)) {
if (base->object->runtime->select_id == (result.id & ~0xFFFF0000)) {
ok = true;
depth_id = buffer[a].depth;
depth_id = result.depth;
break;
}
}
@ -1890,13 +1890,10 @@ void VIEW3D_OT_bone_select_menu(wmOperatorType *ot)
* \return True when a menu was activated.
*/
static bool bone_mouse_select_menu(bContext *C,
const GPUSelectResult *buffer,
const int hits,
const blender::Span<GPUSelectResult> hit_results,
const bool is_editmode,
const SelectPick_Params *params)
{
BLI_assert(buffer);
int bone_count = 0;
struct BoneRefWithDepth {
@ -1916,10 +1913,10 @@ static bool bone_mouse_select_menu(bContext *C,
/* Select logic taken from #ed_armature_pick_bone_from_selectbuffer_impl
* in `armature_select.cc`. */
for (int a = 0; a < hits; a++) {
for (const GPUSelectResult &result : hit_results) {
void *bone_ptr = nullptr;
Base *bone_base = nullptr;
uint hitresult = buffer[a].id;
uint hitresult = result.id;
if (!(hitresult & BONESEL_ANY)) {
/* To avoid including objects in selection. */
@ -1972,7 +1969,7 @@ static bool bone_mouse_select_menu(bContext *C,
BoneRefWithDepth *bone_ref = MEM_new<BoneRefWithDepth>(__func__);
bone_ref->base = bone_base;
bone_ref->bone_ptr = bone_ptr;
bone_ref->depth_id = buffer[a].depth;
bone_ref->depth_id = result.depth;
BLI_addtail(&bone_ref_list, (void *)bone_ref);
BLI_gset_insert(added_bones, bone_ptr);
@ -2038,10 +2035,10 @@ static bool bone_mouse_select_menu(bContext *C,
return true;
}
static bool selectbuffer_has_bones(const GPUSelectResult *buffer, const uint hits)
static bool selectbuffer_has_bones(const blender::Span<GPUSelectResult> hit_results)
{
for (uint i = 0; i < hits; i++) {
if (buffer[i].id & 0xFFFF0000) {
for (const GPUSelectResult &result : hit_results) {
if (result.id & 0xFFFF0000) {
return true;
}
}
@ -2049,25 +2046,28 @@ static bool selectbuffer_has_bones(const GPUSelectResult *buffer, const uint hit
}
/* utility function for mixed_bones_object_selectbuffer */
static int selectbuffer_ret_hits_15(GPUSelectResult * /*buffer*/, const int hits15)
static int selectbuffer_ret_hits_15(blender::MutableSpan<GPUSelectResult> /*results*/,
const int hits15)
{
return hits15;
}
static int selectbuffer_ret_hits_9(GPUSelectResult *buffer, const int hits15, const int hits9)
static int selectbuffer_ret_hits_9(blender::MutableSpan<GPUSelectResult> results,
const int hits15,
const int hits9)
{
const int ofs = hits15;
memcpy(buffer, buffer + ofs, hits9 * sizeof(GPUSelectResult));
results.slice(0, hits9).copy_from(results.slice(ofs, hits9)); /* Shift results to beginning. */
return hits9;
}
static int selectbuffer_ret_hits_5(GPUSelectResult *buffer,
static int selectbuffer_ret_hits_5(blender::MutableSpan<GPUSelectResult> results,
const int hits15,
const int hits9,
const int hits5)
{
const int ofs = hits15 + hits9;
memcpy(buffer, buffer + ofs, hits5 * sizeof(GPUSelectResult));
results.slice(0, hits5).copy_from(results.slice(ofs, hits5)); /* Shift results to beginning. */
return hits5;
}
@ -2080,8 +2080,7 @@ static int selectbuffer_ret_hits_5(GPUSelectResult *buffer,
* Needed so we can step to the next, non-active object when it's already selected, see: #76445.
*/
static int mixed_bones_object_selectbuffer(ViewContext *vc,
GPUSelectResult *buffer,
const int buffer_len,
GPUSelectBuffer *buffer,
const int mval[2],
eV3DSelectObjectFilter select_filter,
bool do_nearest,
@ -2104,64 +2103,63 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
/* we _must_ end cache before return, use 'goto finally' */
view3d_opengl_select_cache_begin();
GPUSelectStorage &storage = buffer->storage;
BLI_rcti_init_pt_radius(&rect, mval, 14);
hits15 = view3d_opengl_select_ex(
vc, buffer, buffer_len, &rect, select_mode, select_filter, do_material_slot_selection);
vc, buffer, &rect, select_mode, select_filter, do_material_slot_selection);
if (hits15 == 1) {
hits = selectbuffer_ret_hits_15(buffer, hits15);
hits = selectbuffer_ret_hits_15(storage.as_mutable_span(), hits15);
goto finally;
}
else if (hits15 > 0) {
int ofs;
has_bones15 = selectbuffer_has_bones(buffer, hits15);
has_bones15 = selectbuffer_has_bones(storage.as_span().slice(0, hits15));
ofs = hits15;
BLI_rcti_init_pt_radius(&rect, mval, 9);
hits9 = view3d_opengl_select(
vc, buffer + ofs, buffer_len - ofs, &rect, select_mode, select_filter);
hits9 = view3d_opengl_select(vc, buffer, &rect, select_mode, select_filter);
if (hits9 == 1) {
hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
hits = selectbuffer_ret_hits_9(storage.as_mutable_span(), hits15, hits9);
goto finally;
}
else if (hits9 > 0) {
has_bones9 = selectbuffer_has_bones(buffer + ofs, hits9);
has_bones9 = selectbuffer_has_bones(storage.as_span().slice(ofs, hits9));
ofs += hits9;
BLI_rcti_init_pt_radius(&rect, mval, 5);
hits5 = view3d_opengl_select(
vc, buffer + ofs, buffer_len - ofs, &rect, select_mode, select_filter);
hits5 = view3d_opengl_select(vc, buffer, &rect, select_mode, select_filter);
if (hits5 == 1) {
hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
hits = selectbuffer_ret_hits_5(storage.as_mutable_span(), hits15, hits9, hits5);
goto finally;
}
else if (hits5 > 0) {
has_bones5 = selectbuffer_has_bones(buffer + ofs, hits5);
has_bones5 = selectbuffer_has_bones(storage.as_span().slice(ofs, hits5));
}
}
if (has_bones5) {
hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
hits = selectbuffer_ret_hits_5(storage.as_mutable_span(), hits15, hits9, hits5);
goto finally;
}
else if (has_bones9) {
hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
hits = selectbuffer_ret_hits_9(storage.as_mutable_span(), hits15, hits9);
goto finally;
}
else if (has_bones15) {
hits = selectbuffer_ret_hits_15(buffer, hits15);
hits = selectbuffer_ret_hits_15(storage.as_mutable_span(), hits15);
goto finally;
}
if (hits5 > 0) {
hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
hits = selectbuffer_ret_hits_5(storage.as_mutable_span(), hits15, hits9, hits5);
goto finally;
}
else if (hits9 > 0) {
hits = selectbuffer_ret_hits_9(buffer, hits15, hits9);
hits = selectbuffer_ret_hits_9(storage.as_mutable_span(), hits15, hits9);
goto finally;
}
else {
hits = selectbuffer_ret_hits_15(buffer, hits15);
hits = selectbuffer_ret_hits_15(storage.as_mutable_span(), hits15);
goto finally;
}
}
@ -2172,8 +2170,7 @@ finally:
}
static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
GPUSelectResult *buffer,
const int buffer_len,
GPUSelectBuffer *buffer,
const int mval[2],
eV3DSelectObjectFilter select_filter,
bool use_cycle,
@ -2204,7 +2201,7 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
do_nearest = do_nearest && !enumerate;
int hits = mixed_bones_object_selectbuffer(
vc, buffer, buffer_len, mval, select_filter, do_nearest, true, false);
vc, buffer, mval, select_filter, do_nearest, true, false);
return hits;
}
@ -2251,7 +2248,7 @@ static int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b
* \return the active base or nullptr.
*/
static Base *mouse_select_eval_buffer(ViewContext *vc,
const GPUSelectResult *buffer,
const GPUSelectBuffer &buffer,
int hits,
bool do_nearest,
bool has_bones,
@ -2274,8 +2271,8 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
if (has_bones && do_bones_get_priotity) {
/* we skip non-bone hits */
for (a = 0; a < hits; a++) {
if (min > buffer[a].depth && (buffer[a].id & 0xFFFF0000)) {
min = buffer[a].depth;
if (min > buffer.storage[a].depth && (buffer.storage[a].id & 0xFFFF0000)) {
min = buffer.storage[a].depth;
hit_index = a;
}
}
@ -2284,26 +2281,25 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
for (a = 0; a < hits; a++) {
/* Any object. */
if (min > buffer[a].depth) {
min = buffer[a].depth;
if (min > buffer.storage[a].depth) {
min = buffer.storage[a].depth;
hit_index = a;
}
}
}
if (hit_index != -1) {
select_id = buffer[hit_index].id & 0xFFFF;
select_id_subelem = (buffer[hit_index].id & 0xFFFF0000) >> 16;
select_id = buffer.storage[hit_index].id & 0xFFFF;
select_id_subelem = (buffer.storage[hit_index].id & 0xFFFF0000) >> 16;
found = true;
/* No need to set `min` to `buffer[hit_index].depth`, it's not used from now on. */
/* No need to set `min` to `buffer.storage[hit_index].depth`, it's not used from now on. */
}
}
else {
GPUSelectStorage buffer_sorted = buffer.storage;
{
GPUSelectResult *buffer_sorted = static_cast<GPUSelectResult *>(
MEM_mallocN(sizeof(*buffer_sorted) * hits, __func__));
memcpy(buffer_sorted, buffer, sizeof(*buffer_sorted) * hits);
buffer_sorted.resize(hits);
/* Remove non-bone objects. */
if (has_bones && do_bones_get_priotity) {
/* Loop backwards to reduce re-ordering. */
@ -2313,8 +2309,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
}
}
}
qsort(buffer_sorted, hits, sizeof(GPUSelectResult), gpu_select_buffer_depth_id_cmp);
buffer = buffer_sorted;
qsort(buffer_sorted.data(), hits, sizeof(GPUSelectResult), gpu_select_buffer_depth_id_cmp);
}
int hit_index = -1;
@ -2327,8 +2322,8 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
if (base && (base->flag & BASE_SELECTED)) {
const int select_id_active = base->object->runtime->select_id;
for (int i_next = 0, i_prev = hits - 1; i_next < hits; i_prev = i_next++) {
if ((select_id_active == (buffer[i_prev].id & 0xFFFF)) &&
(select_id_active != (buffer[i_next].id & 0xFFFF)))
if ((select_id_active == (buffer_sorted[i_prev].id & 0xFFFF)) &&
(select_id_active != (buffer_sorted[i_next].id & 0xFFFF)))
{
hit_index = i_next;
break;
@ -2344,11 +2339,10 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
}
if (hit_index != -1) {
select_id = buffer[hit_index].id & 0xFFFF;
select_id_subelem = (buffer[hit_index].id & 0xFFFF0000) >> 16;
select_id = buffer_sorted[hit_index].id & 0xFFFF;
select_id_subelem = (buffer_sorted[hit_index].id & 0xFFFF0000) >> 16;
found = true;
}
MEM_freeN((void *)buffer);
}
Base *basact = nullptr;
@ -2423,7 +2417,7 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Base *basact = nullptr;
GPUSelectResult buffer[MAXPICKELEMS];
GPUSelectBuffer buffer;
/* setup view context for argument to callbacks */
view3d_operator_needs_opengl(C);
@ -2433,17 +2427,12 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
const bool do_material_slot_selection = r_material_slot != nullptr;
const int hits = mixed_bones_object_selectbuffer(&vc,
buffer,
ARRAY_SIZE(buffer),
mval,
VIEW3D_SELECT_FILTER_NOP,
do_nearest,
false,
do_material_slot_selection);
const int hits = mixed_bones_object_selectbuffer(
&vc, &buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false, do_material_slot_selection);
if (hits > 0) {
const bool has_bones = (r_material_slot == nullptr) && selectbuffer_has_bones(buffer, hits);
const bool has_bones = (r_material_slot == nullptr) &&
selectbuffer_has_bones(buffer.storage.as_span().slice(0, hits));
basact = mouse_select_eval_buffer(
&vc, buffer, hits, do_nearest, has_bones, true, r_material_slot);
}
@ -2494,7 +2483,7 @@ static bool ed_object_select_pick_camera_track(bContext *C,
Scene *scene,
Base *basact,
MovieClip *clip,
const GPUSelectResult *buffer,
const GPUSelectBuffer &buffer,
const short hits,
const SelectPick_Params *params)
{
@ -2506,7 +2495,7 @@ static bool ed_object_select_pick_camera_track(bContext *C,
MovieTrackingTrack *track = nullptr;
for (int i = 0; i < hits; i++) {
const int hitresult = buffer[i].id;
const int hitresult = buffer.storage[i].id;
/* If there's bundles in buffer select bundles first,
* so non-camera elements should be ignored in buffer. */
@ -2615,7 +2604,7 @@ static bool ed_object_select_pick(bContext *C,
/* Set for GPU depth buffer picking, leave null when selecting by center. */
struct GPUData {
GPUSelectResult buffer[MAXPICKELEMS];
GPUSelectBuffer buffer;
int hits;
bool do_nearest;
bool has_bones;
@ -2637,17 +2626,11 @@ static bool ed_object_select_pick(bContext *C,
ED_view3d_select_filter_from_mode(scene,
vc.obact) :
VIEW3D_SELECT_FILTER_NOP);
gpu->hits = mixed_bones_object_selectbuffer_extended(&vc,
gpu->buffer,
ARRAY_SIZE(gpu->buffer),
mval,
select_filter,
true,
enumerate,
&gpu->do_nearest);
gpu->hits = mixed_bones_object_selectbuffer_extended(
&vc, &gpu->buffer, mval, select_filter, true, enumerate, &gpu->do_nearest);
gpu->has_bones = (object_only && gpu->hits > 0) ?
false :
selectbuffer_has_bones(gpu->buffer, gpu->hits);
selectbuffer_has_bones(gpu->buffer.storage.as_span().slice(0, gpu->hits));
}
/* First handle menu selection, early exit when a menu was opened.
@ -2655,17 +2638,18 @@ static bool ed_object_select_pick(bContext *C,
if (enumerate) {
bool has_menu = false;
if (center) {
if (object_mouse_select_menu(C, &vc, nullptr, 0, mval, params, &basact_override)) {
if (object_mouse_select_menu(C, &vc, {}, mval, params, &basact_override)) {
has_menu = true;
}
}
else {
if (gpu->hits != 0) {
if (gpu->has_bones && bone_mouse_select_menu(C, gpu->buffer, gpu->hits, false, params)) {
const blender::Span<GPUSelectResult> hit_results = gpu->buffer.storage.as_span().slice(
0, gpu->hits);
if (gpu->has_bones && bone_mouse_select_menu(C, hit_results, false, params)) {
has_menu = true;
}
else if (object_mouse_select_menu(
C, &vc, gpu->buffer, gpu->hits, mval, params, &basact_override)) {
else if (object_mouse_select_menu(C, &vc, hit_results, mval, params, &basact_override)) {
has_menu = true;
}
}
@ -2784,7 +2768,7 @@ static bool ed_object_select_pick(bContext *C,
view_layer,
v3d,
basact ? basact : (Base *)oldbasact,
gpu->buffer,
gpu->buffer.storage.data(),
gpu->hits,
params,
gpu->do_nearest))
@ -3374,10 +3358,11 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
}
else if (obedit->type == OB_ARMATURE) {
if (enumerate) {
GPUSelectResult buffer[MAXPICKELEMS];
GPUSelectBuffer buffer;
const int hits = mixed_bones_object_selectbuffer(
&vc, buffer, ARRAY_SIZE(buffer), mval, VIEW3D_SELECT_FILTER_NOP, false, true, false);
changed = bone_mouse_select_menu(C, buffer, hits, true, &params);
&vc, &buffer, mval, VIEW3D_SELECT_FILTER_NOP, false, true, false);
changed = bone_mouse_select_menu(
C, buffer.storage.as_span().take_front(hits), true, &params);
}
if (!changed) {
changed = ED_armature_edit_select_pick(C, mval, &params);
@ -3933,11 +3918,10 @@ static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectO
int a;
bool changed = false;
GPUSelectResult buffer[MAXPICKELEMS];
GPUSelectBuffer buffer;
int hits;
hits = view3d_opengl_select(
vc, buffer, MAXPICKELEMS, rect, VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP);
hits = view3d_opengl_select(vc, &buffer, rect, VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
changed |= BKE_mball_deselect_all(mb);
@ -3950,7 +3934,7 @@ static bool do_meta_box_select(ViewContext *vc, const rcti *rect, const eSelectO
bool is_inside_stiff = false;
for (a = 0; a < hits; a++) {
const int hitresult = buffer[a].id;
const int hitresult = buffer.storage[a].id;
if (hitresult == -1) {
continue;
@ -4001,11 +3985,10 @@ static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSel
bool changed = false;
int a;
GPUSelectResult buffer[MAXPICKELEMS];
GPUSelectBuffer buffer;
int hits;
hits = view3d_opengl_select(
vc, buffer, MAXPICKELEMS, rect, VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP);
hits = view3d_opengl_select(vc, &buffer, rect, VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
@ -4025,7 +4008,7 @@ static bool do_armature_box_select(ViewContext *vc, const rcti *rect, const eSel
/* first we only check points inside the border */
for (a = 0; a < hits; a++) {
const int select_id = buffer[a].id;
const int select_id = buffer.storage[a].id;
if (select_id != -1) {
if ((select_id & 0xFFFF0000) == 0) {
continue;
@ -4082,15 +4065,11 @@ static bool do_object_box_select(bContext *C,
const eSelectOp sel_op)
{
View3D *v3d = vc->v3d;
int totobj = MAXPICKELEMS; /* XXX solve later */
/* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */
GPUSelectResult *buffer = static_cast<GPUSelectResult *>(
MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__));
GPUSelectBuffer buffer;
const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene,
vc->obact);
const int hits = view3d_opengl_select(
vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
const int hits = view3d_opengl_select(vc, &buffer, rect, VIEW3D_SELECT_ALL, select_filter);
BKE_view_layer_synced_ensure(vc->scene, vc->view_layer);
LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) {
base->object->id.tag &= ~LIB_TAG_DOIT;
@ -4117,9 +4096,10 @@ static bool do_object_box_select(bContext *C,
}
/* The draw order doesn't always match the order we populate the engine, see: #51695. */
qsort(buffer, hits, sizeof(GPUSelectResult), opengl_bone_select_buffer_cmp);
qsort(buffer.storage.data(), hits, sizeof(GPUSelectResult), opengl_bone_select_buffer_cmp);
for (const GPUSelectResult *buf_iter = buffer, *buf_end = buf_iter + hits; buf_iter < buf_end;
for (const GPUSelectResult *buf_iter = buffer.storage.data(), *buf_end = buf_iter + hits;
buf_iter < buf_end;
buf_iter++)
{
bPoseChannel *pchan_dummy;
@ -4144,8 +4124,6 @@ static bool do_object_box_select(bContext *C,
finally:
MEM_freeN(buffer);
if (changed) {
DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
@ -4160,15 +4138,11 @@ static bool do_pose_box_select(bContext *C,
{
blender::Vector<Base *> bases = do_pose_tag_select_op_prepare(vc);
int totobj = MAXPICKELEMS; /* XXX solve later */
/* Selection buffer has bones potentially too, so add #MAXPICKELEMS. */
GPUSelectResult *buffer = static_cast<GPUSelectResult *>(
MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__));
/* Selection buffer has bones potentially too. */
GPUSelectBuffer buffer;
const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene,
vc->obact);
const int hits = view3d_opengl_select(
vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
const int hits = view3d_opengl_select(vc, &buffer, rect, VIEW3D_SELECT_ALL, select_filter);
/*
* NOTE(@theeth): Regarding the logic use here.
* The buffer and #ListBase have the same relative order, which makes the selection
@ -4181,9 +4155,10 @@ static bool do_pose_box_select(bContext *C,
/* no need to loop if there's no hit */
/* The draw order doesn't always match the order we populate the engine, see: #51695. */
qsort(buffer, hits, sizeof(GPUSelectResult), opengl_bone_select_buffer_cmp);
qsort(buffer.storage.data(), hits, sizeof(GPUSelectResult), opengl_bone_select_buffer_cmp);
for (const GPUSelectResult *buf_iter = buffer, *buf_end = buf_iter + hits; buf_iter < buf_end;
for (const GPUSelectResult *buf_iter = buffer.storage.data(), *buf_end = buf_iter + hits;
buf_iter < buf_end;
buf_iter++)
{
Bone *bone;
@ -4228,8 +4203,6 @@ static bool do_pose_box_select(bContext *C,
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene);
}
MEM_freeN(buffer);
return changed_multi;
}

View File

@ -479,8 +479,7 @@ void view3d_opengl_select_cache_end()
struct DrawSelectLoopUserData {
uint pass;
uint hits;
GPUSelectResult *buffer;
uint buffer_len;
GPUSelectBuffer *buffer;
const rcti *rect;
eGPUSelectMode gpu_select_mode;
};
@ -490,8 +489,7 @@ static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
bool continue_pass = false;
DrawSelectLoopUserData *data = static_cast<DrawSelectLoopUserData *>(user_data);
if (stage == DRW_SELECT_PASS_PRE) {
GPU_select_begin_next(
data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits);
GPU_select_begin_next(data->buffer, data->rect, data->gpu_select_mode, data->hits);
/* always run POST after PRE. */
continue_pass = true;
}
@ -544,8 +542,7 @@ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void
}
int view3d_opengl_select_ex(ViewContext *vc,
GPUSelectResult *buffer,
uint buffer_len,
GPUSelectBuffer *buffer,
const rcti *input,
eV3DSelectMode select_mode,
eV3DSelectObjectFilter select_filter,
@ -610,7 +607,7 @@ int view3d_opengl_select_ex(ViewContext *vc,
/* Re-use cache (rect must be smaller than the cached)
* other context is assumed to be unchanged */
if (GPU_select_is_cached()) {
GPU_select_begin_next(buffer, buffer_len, &rect, gpu_select_mode, 0);
GPU_select_begin_next(buffer, &rect, gpu_select_mode, 0);
GPU_select_cache_load_id();
hits = GPU_select_end();
goto finally;
@ -691,7 +688,6 @@ int view3d_opengl_select_ex(ViewContext *vc,
drw_select_loop_user_data.pass = 0;
drw_select_loop_user_data.hits = 0;
drw_select_loop_user_data.buffer = buffer;
drw_select_loop_user_data.buffer_len = buffer_len;
drw_select_loop_user_data.rect = &rect;
drw_select_loop_user_data.gpu_select_mode = gpu_select_mode;
@ -721,7 +717,6 @@ int view3d_opengl_select_ex(ViewContext *vc,
drw_select_loop_user_data.pass = 0;
drw_select_loop_user_data.hits = 0;
drw_select_loop_user_data.buffer = buffer;
drw_select_loop_user_data.buffer_len = buffer_len;
drw_select_loop_user_data.rect = &rect;
drw_select_loop_user_data.gpu_select_mode = gpu_select_mode;
@ -755,38 +750,36 @@ int view3d_opengl_select_ex(ViewContext *vc,
UI_Theme_Restore(&theme_state);
finally:
if (hits < 0) {
printf("Too many objects in select buffer\n"); /* XXX make error message */
}
return hits;
}
int view3d_opengl_select(ViewContext *vc,
GPUSelectResult *buffer,
uint buffer_len,
GPUSelectBuffer *buffer,
const rcti *input,
eV3DSelectMode select_mode,
eV3DSelectObjectFilter select_filter)
{
return view3d_opengl_select_ex(vc, buffer, buffer_len, input, select_mode, select_filter, false);
return view3d_opengl_select_ex(vc, buffer, input, select_mode, select_filter, false);
}
int view3d_opengl_select_with_id_filter(ViewContext *vc,
GPUSelectResult *buffer,
const uint buffer_len,
GPUSelectBuffer *buffer,
const rcti *input,
eV3DSelectMode select_mode,
eV3DSelectObjectFilter select_filter,
uint select_id)
{
int hits = view3d_opengl_select(vc, buffer, buffer_len, input, select_mode, select_filter);
const int64_t start = buffer->storage.size();
int hits = view3d_opengl_select(vc, buffer, input, select_mode, select_filter);
/* Selection sometimes uses -1 for an invalid selection ID, remove these as they
* interfere with detection of actual number of hits in the selection. */
if (hits > 0) {
hits = GPU_select_buffer_remove_by_id(buffer, hits, select_id);
hits = GPU_select_buffer_remove_by_id(buffer->storage.as_mutable_span().slice(start, hits),
select_id);
/* Trim buffer to the exact size in case selections were removed. */
buffer->storage.resize(start + hits);
}
return hits;
}

View File

@ -8,11 +8,9 @@
#pragma once
#include "BLI_span.hh"
#include "BLI_sys_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "BLI_vector.hh"
struct rcti;
@ -43,11 +41,15 @@ typedef struct GPUSelectResult {
unsigned int depth;
} GPUSelectResult;
using GPUSelectStorage = blender::Vector<GPUSelectResult, 2500>;
struct GPUSelectBuffer {
GPUSelectStorage storage;
};
/**
* Initialize and provide buffer for results.
*/
void GPU_select_begin(GPUSelectResult *buffer,
unsigned int buffer_len,
void GPU_select_begin(GPUSelectBuffer *buffer,
const struct rcti *input,
eGPUSelectMode mode,
int oldhits);
@ -55,8 +57,7 @@ void GPU_select_begin(GPUSelectResult *buffer,
* Initialize and provide buffer for results.
* Uses the new Select-Next engine if enabled.
*/
void GPU_select_begin_next(GPUSelectResult *buffer,
const uint buffer_len,
void GPU_select_begin_next(GPUSelectBuffer *buffer,
const struct rcti *input,
eGPUSelectMode mode,
int oldhits);
@ -92,13 +93,10 @@ void GPU_select_cache_end(void);
*
* Note that comparing depth as uint is fine.
*/
const GPUSelectResult *GPU_select_buffer_near(const GPUSelectResult *buffer, int hits);
uint GPU_select_buffer_remove_by_id(GPUSelectResult *buffer, int hits, uint select_id);
const GPUSelectResult *GPU_select_buffer_near(const blender::Span<GPUSelectResult> hit_results);
uint GPU_select_buffer_remove_by_id(blender::MutableSpan<GPUSelectResult> hit_results,
uint select_id);
/**
* Part of the solution copied from `rect_subregion_stride_calc`.
*/
void GPU_select_buffer_stride_realign(const struct rcti *src, const struct rcti *dst, uint *r_buf);
#ifdef __cplusplus
}
#endif

View File

@ -69,8 +69,7 @@ static GPUSelectState g_select_state = {false};
/** \name Public API
* \{ */
static void gpu_select_begin_ex(GPUSelectResult *buffer,
const uint buffer_len,
static void gpu_select_begin_ex(GPUSelectBuffer *buffer,
const rcti *input,
eGPUSelectMode mode,
int oldhits,
@ -117,38 +116,32 @@ static void gpu_select_begin_ex(GPUSelectResult *buffer,
switch (g_select_state.algorithm) {
case ALGO_SELECT_NEXT: {
gpu_select_next_begin(buffer, buffer_len, input, mode);
gpu_select_next_begin(buffer, input, mode);
break;
}
case ALGO_GL_QUERY: {
gpu_select_query_begin(buffer, buffer_len, input, mode, oldhits);
gpu_select_query_begin(buffer, input, mode, oldhits);
break;
}
default: /* ALGO_GL_PICK */
{
gpu_select_pick_begin(buffer, buffer_len, input, mode);
gpu_select_pick_begin(buffer, input, mode);
break;
}
}
}
void GPU_select_begin_next(GPUSelectResult *buffer,
const uint buffer_len,
void GPU_select_begin_next(GPUSelectBuffer *buffer,
const rcti *input,
eGPUSelectMode mode,
int oldhits)
{
gpu_select_begin_ex(
buffer, buffer_len, input, mode, oldhits, U.experimental.enable_overlay_next);
gpu_select_begin_ex(buffer, input, mode, oldhits, U.experimental.enable_overlay_next);
}
void GPU_select_begin(GPUSelectResult *buffer,
const uint buffer_len,
const rcti *input,
eGPUSelectMode mode,
int oldhits)
void GPU_select_begin(GPUSelectBuffer *buffer, const rcti *input, eGPUSelectMode mode, int oldhits)
{
gpu_select_begin_ex(buffer, buffer_len, input, mode, oldhits, false);
gpu_select_begin_ex(buffer, input, mode, oldhits, false);
}
bool GPU_select_load_id(uint id)
@ -249,35 +242,35 @@ bool GPU_select_is_cached()
/** \name Utilities
* \{ */
const GPUSelectResult *GPU_select_buffer_near(const GPUSelectResult *buffer, int hits)
const GPUSelectResult *GPU_select_buffer_near(const blender::Span<GPUSelectResult> hit_results)
{
const GPUSelectResult *buffer_near = nullptr;
uint depth_min = uint(-1);
for (int i = 0; i < hits; i++) {
if (buffer->depth < depth_min) {
BLI_assert(buffer->id != -1);
depth_min = buffer->depth;
buffer_near = buffer;
for (const GPUSelectResult &result : hit_results) {
if (result.depth < depth_min) {
BLI_assert(result.id != -1);
depth_min = result.depth;
buffer_near = &result;
}
buffer++;
}
return buffer_near;
}
uint GPU_select_buffer_remove_by_id(GPUSelectResult *buffer, int hits, uint select_id)
uint GPU_select_buffer_remove_by_id(blender::MutableSpan<GPUSelectResult> hit_results,
uint select_id)
{
GPUSelectResult *buffer_src = buffer;
GPUSelectResult *buffer_dst = buffer;
int hits_final = 0;
for (int i = 0; i < hits; i++) {
if (buffer_src->id != select_id) {
if (buffer_dst != buffer_src) {
memcpy(buffer_dst, buffer_src, sizeof(GPUSelectResult));
uint index_src = 0;
deadpin marked this conversation as resolved Outdated

These can be int, the range is easily enough and used elsewhere with selection indices.

These can be `int`, the range is easily enough and used elsewhere with selection indices.
uint index_dst = 0;
uint hits_final = 0;
for (const GPUSelectResult &result : hit_results) {
if (result.id != select_id) {
if (index_dst != index_src) {
hit_results[index_dst] = result;
}
buffer_dst++;
hits_final += 1;
index_dst++;
hits_final++;
}
buffer_src++;
index_src++;
}
return hits_final;
}

View File

@ -18,8 +18,7 @@
struct GPUSelectNextState {
/** Result buffer set on initialization. */
GPUSelectResult *buffer;
uint buffer_len;
GPUSelectBuffer *buffer;
/** Area of the viewport to render / select from. */
rcti rect;
/** Number of hits. Set to -1 if it overflows buffer_len. */
@ -30,15 +29,11 @@ struct GPUSelectNextState {
static GPUSelectNextState g_state = {};
void gpu_select_next_begin(GPUSelectResult *buffer,
uint buffer_len,
const rcti *input,
eGPUSelectMode mode)
void gpu_select_next_begin(GPUSelectBuffer *buffer, const rcti *input, eGPUSelectMode mode)
{
g_state.buffer = buffer;
g_state.rect = *input;
g_state.buffer_len = buffer_len;
g_state.mode = mode;
}
@ -54,32 +49,27 @@ eGPUSelectMode gpu_select_next_get_mode()
}
void gpu_select_next_set_result(GPUSelectResult *hit_buf, uint hit_len)
{
if (hit_len > g_state.buffer_len) {
g_state.hits = -1;
return;
}
blender::MutableSpan<GPUSelectResult> result(g_state.buffer, g_state.buffer_len);
blender::Span<GPUSelectResult> hits(hit_buf, hit_len);
g_state.buffer->storage.resize(hit_len);
blender::MutableSpan<GPUSelectResult> result = g_state.buffer->storage.as_mutable_span();
const blender::Span<GPUSelectResult> hits(hit_buf, hit_len);
/* TODO(fclem): There might be some conversion to do to align to the other APIs output. */
switch (g_state.mode) {
case eGPUSelectMode::GPU_SELECT_ALL:
result.take_front(hit_len).copy_from(hits);
result.copy_from(hits);
break;
case eGPUSelectMode::GPU_SELECT_NEAREST_FIRST_PASS:
result.take_front(hit_len).copy_from(hits);
result.copy_from(hits);
break;
case eGPUSelectMode::GPU_SELECT_NEAREST_SECOND_PASS:
result.take_front(hit_len).copy_from(hits);
result.copy_from(hits);
break;
case eGPUSelectMode::GPU_SELECT_PICK_ALL:
result.take_front(hit_len).copy_from(hits);
result.copy_from(hits);
break;
case eGPUSelectMode::GPU_SELECT_PICK_NEAREST:
result.take_front(hit_len).copy_from(hits);
result.copy_from(hits);
break;
}

View File

@ -227,8 +227,7 @@ static int depth_cmp(const void *v1, const void *v2)
/** Depth sorting. */
struct GPUPickState {
/** Cache on initialization. */
GPUSelectResult *buffer;
uint buffer_len;
GPUSelectBuffer *buffer;
/** Mode of this operation. */
eGPUSelectMode mode;
@ -294,10 +293,7 @@ struct GPUPickState {
static GPUPickState g_pick_state{};
void gpu_select_pick_begin(GPUSelectResult *buffer,
const uint buffer_len,
const rcti *input,
eGPUSelectMode mode)
void gpu_select_pick_begin(GPUSelectBuffer *buffer, const rcti *input, eGPUSelectMode mode)
{
GPUPickState *ps = &g_pick_state;
@ -312,7 +308,6 @@ void gpu_select_pick_begin(GPUSelectResult *buffer,
GPU_debug_group_begin("Selection Pick");
ps->buffer = buffer;
ps->buffer_len = buffer_len;
ps->mode = mode;
const uint rect_len = uint(BLI_rcti_size_x(input) * BLI_rcti_size_y(input));
@ -577,7 +572,6 @@ uint gpu_select_pick_end()
rect_depth_final = ps->gpu.rect_depth;
}
uint maxhits = g_pick_state.buffer_len;
DepthID *depth_data;
uint depth_data_len = 0;
@ -662,22 +656,16 @@ uint gpu_select_pick_end()
* so the final hit-list is sorted by depth (nearest first). */
uint hits = 0;
if (depth_data_len > maxhits) {
hits = uint(-1);
}
else {
/* Leave sorting up to the caller. */
qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp);
/* Leave sorting up to the caller. */
qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp);
for (uint i = 0; i < depth_data_len; i++) {
g_pick_state.buffer->storage.reserve(g_pick_state.buffer->storage.size() + depth_data_len);
for (uint i = 0; i < depth_data_len; i++) {
#ifdef DEBUG_PRINT
printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth);
printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth);
#endif
deadpin marked this conversation as resolved Outdated

Since the size is known ahead of time, reserve then use append_unchecked to avoid re-allocation.

Since the size is known ahead of time, reserve then use `append_unchecked` to avoid re-allocation.
g_pick_state.buffer[hits].depth = depth_data[i].depth;
g_pick_state.buffer[hits].id = depth_data[i].id;
hits++;
}
BLI_assert(hits < maxhits);
g_pick_state.buffer->storage.append_unchecked({depth_data[i].id, depth_data[i].depth});
hits++;
}
MEM_freeN(depth_data);

View File

@ -16,10 +16,7 @@ extern "C" {
/* gpu_select_pick */
void gpu_select_pick_begin(GPUSelectResult *buffer,
uint buffer_len,
const rcti *input,
eGPUSelectMode mode);
void gpu_select_pick_begin(GPUSelectBuffer *buffer, const rcti *input, eGPUSelectMode mode);
bool gpu_select_pick_load_id(uint id, bool end);
uint gpu_select_pick_end(void);
@ -33,17 +30,16 @@ void gpu_select_pick_cache_load_id(void);
/* gpu_select_sample_query */
void gpu_select_query_begin(
GPUSelectResult *buffer, uint buffer_len, const rcti *input, eGPUSelectMode mode, int oldhits);
void gpu_select_query_begin(GPUSelectBuffer *buffer,
const rcti *input,
eGPUSelectMode mode,
int oldhits);
bool gpu_select_query_load_id(uint id);
uint gpu_select_query_end(void);
/* gpu_select_next */
void gpu_select_next_begin(GPUSelectResult *buffer,
uint buffer_len,
const rcti *input,
eGPUSelectMode mode);
void gpu_select_next_begin(GPUSelectBuffer *buffer, const rcti *input, eGPUSelectMode mode);
uint gpu_select_next_end(void);
/* Return a single offset since picking uses squared viewport. */

View File

@ -39,9 +39,7 @@ struct GPUSelectQueryState {
/** Array holding the id corresponding id to each query. */
Vector<uint, QUERY_MIN_LEN> *ids;
/** Cache on initialization. */
GPUSelectResult *buffer;
/** The capacity of the `buffer` array. */
uint buffer_len;
GPUSelectBuffer *buffer;
/** Mode of operation. */
eGPUSelectMode mode;
uint index;
@ -56,8 +54,7 @@ struct GPUSelectQueryState {
static GPUSelectQueryState g_query_state = {false};
void gpu_select_query_begin(GPUSelectResult *buffer,
uint buffer_len,
void gpu_select_query_begin(GPUSelectBuffer *buffer,
const rcti *input,
const eGPUSelectMode mode,
int oldhits)
@ -66,7 +63,6 @@ void gpu_select_query_begin(GPUSelectResult *buffer,
g_query_state.query_issued = false;
g_query_state.buffer = buffer;
g_query_state.buffer_len = buffer_len;
g_query_state.mode = mode;
g_query_state.index = 0;
g_query_state.oldhits = oldhits;
@ -129,7 +125,7 @@ bool gpu_select_query_load_id(uint id)
* can read past `buffer_len` in this case. */
BLI_assert(g_query_state.oldhits != -1);
if (g_query_state.index < g_query_state.oldhits) {
if (g_query_state.buffer[g_query_state.index].id == id) {
if (g_query_state.buffer->storage[g_query_state.index].id == id) {
g_query_state.index++;
return true;
}
@ -142,7 +138,6 @@ bool gpu_select_query_load_id(uint id)
uint gpu_select_query_end()
{
uint hits = 0;
const uint maxhits = g_query_state.buffer_len;
if (g_query_state.query_issued) {
g_query_state.queries->end_query();
@ -155,22 +150,15 @@ uint gpu_select_query_end()
for (int i = 0; i < result.size(); i++) {
if (result[i] != 0) {
if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
if (hits < maxhits) {
g_query_state.buffer[hits].depth = 0xFFFF;
g_query_state.buffer[hits].id = ids[i];
hits++;
}
else {
hits = -1;
break;
}
g_query_state.buffer->storage.append({ids[i], 0xFFFF});
hits++;
}
else {
int j;
/* search in buffer and make selected object first */
for (j = 0; j < g_query_state.oldhits; j++) {
if (g_query_state.buffer[j].id == ids[i]) {
g_query_state.buffer[j].depth = 0;
if (g_query_state.buffer->storage[j].id == ids[i]) {
g_query_state.buffer->storage[j].depth = 0;
}
}
break;

View File

@ -569,7 +569,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
rcti rect;
/* Almost certainly overkill, but allow for many custom gizmos. */
GPUSelectResult buffer[MAXPICKELEMS];
GPUSelectBuffer buffer;
short hits;
BLI_rcti_init_pt_radius(&rect, co, hotspot);
@ -582,14 +582,14 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
/* TODO: waiting for the GPU in the middle of the event loop for every
* mouse move is bad for performance, we need to find a solution to not
* use the GPU or draw something once. (see #61474) */
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
GPU_select_begin(&buffer, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
/* do the drawing */
gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
hits = GPU_select_end();
if (hits > 0) {
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
GPU_select_begin(&buffer, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
GPU_select_end();
}
@ -597,6 +597,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
ED_view3d_draw_setup_view(
wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, nullptr, nullptr, nullptr);
const blender::Span<GPUSelectResult> hit_results = buffer.storage.as_span().take_front(hits);
if (use_select_bias && (hits > 1)) {
float co_direction[3];
float co_screen[3] = {float(co[0]), float(co[1]), 0.0f};
@ -608,15 +609,14 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin);
GPUSelectResult *buf_iter = buffer;
int hit_found = -1;
float dot_best = FLT_MAX;
for (int i = 0; i < hits; i++, buf_iter++) {
BLI_assert(buf_iter->id != -1);
wmGizmo *gz = visible_gizmos[buf_iter->id >> 8];
for (const GPUSelectResult &result : hit_results) {
BLI_assert(result.id != -1);
deadpin marked this conversation as resolved Outdated

Should be BLI_assert(result.id != -1);

Should be `BLI_assert(result.id != -1);`
wmGizmo *gz = visible_gizmos[result.id >> 8];
float co_3d[3];
co_screen[2] = float(double(buf_iter->depth) / double(UINT_MAX));
co_screen[2] = float(double(result.depth) / double(UINT_MAX));
GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d);
float select_bias = gz->select_bias;
if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) {
@ -626,13 +626,13 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
const float dot_test = dot_v3v3(co_3d, co_direction) - select_bias;
if (dot_best > dot_test) {
dot_best = dot_test;
hit_found = buf_iter->id;
hit_found = result.id;
}
}
return hit_found;
}
const GPUSelectResult *hit_near = GPU_select_buffer_near(buffer, hits);
const GPUSelectResult *hit_near = GPU_select_buffer_near(hit_results);
return hit_near ? hit_near->id : -1;
}