forked from bartvdbraak/blender
Fix T54686: objects don't occlude each other for edit-mesh select (part 2)
The previous fix 8a6414ed46f66, resolved selection picking but didn't work for box/circle/lasso select. - Add ED_select_buffer_utils.h for general select-buffer operations unrelated to edit-mesh. - Circle select still needs to cache select-id's for each update.
This commit is contained in:
parent
eddda5194c
commit
4f6e252805
@ -2779,7 +2779,7 @@ void DRW_draw_select_id_object(Scene *scene,
|
||||
world_clip_planes = rv3d->clip_local;
|
||||
}
|
||||
|
||||
initial_offset += 1;
|
||||
BLI_assert(initial_offset > 0);
|
||||
|
||||
switch (ob->type) {
|
||||
case OB_MESH:
|
||||
|
@ -152,6 +152,12 @@ struct BMElem *EDBM_select_id_bm_elem_get(struct EDBMSelectID_Context *sel_id_ct
|
||||
const uint sel_id,
|
||||
uint *r_base_index);
|
||||
|
||||
uint EDBM_select_id_context_offset_for_object_elem(const struct EDBMSelectID_Context *sel_id_ctx,
|
||||
int base_index,
|
||||
char htype);
|
||||
|
||||
uint EDBM_select_id_context_elem_len(const struct EDBMSelectID_Context *sel_id_ctx);
|
||||
|
||||
void EDBM_select_mirrored(
|
||||
struct BMEditMesh *em, const int axis, const bool extend, int *r_totmirr, int *r_totfail);
|
||||
void EDBM_automerge(struct Scene *scene, struct Object *ob, bool update, const char hflag);
|
||||
|
35
source/blender/editors/include/ED_select_buffer_utils.h
Normal file
35
source/blender/editors/include/ED_select_buffer_utils.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup editors
|
||||
*/
|
||||
|
||||
#ifndef __ED_SELECT_BUFFER_UTILS_H__
|
||||
#define __ED_SELECT_BUFFER_UTILS_H__
|
||||
|
||||
struct rcti;
|
||||
|
||||
uint *ED_select_buffer_bitmap_from_rect(const uint bitmap_len, const struct rcti *rect);
|
||||
uint *ED_select_buffer_bitmap_from_circle(const uint bitmap_len,
|
||||
const int center[2],
|
||||
const int radius);
|
||||
uint *ED_select_buffer_bitmap_from_poly(const uint bitmap_len,
|
||||
const int poly[][2],
|
||||
const int poly_len,
|
||||
const rcti *rect);
|
||||
|
||||
#endif /* __ED_SELECT_BUFFER_UTILS_H__ */
|
@ -42,6 +42,7 @@ struct GPUFX;
|
||||
struct GPUFXSettings;
|
||||
struct GPUOffScreen;
|
||||
struct GPUViewport;
|
||||
struct ID;
|
||||
struct ImBuf;
|
||||
struct MVert;
|
||||
struct Main;
|
||||
|
@ -199,8 +199,19 @@ void EDBM_automerge(Scene *scene, Object *obedit, bool update, const char hflag)
|
||||
* \{ */
|
||||
|
||||
struct EDBMBaseOffset {
|
||||
uint face;
|
||||
uint edge;
|
||||
/* For convenience only. */
|
||||
union {
|
||||
uint offset;
|
||||
uint face_start;
|
||||
};
|
||||
union {
|
||||
uint face;
|
||||
uint edge_start;
|
||||
};
|
||||
union {
|
||||
uint edge;
|
||||
uint vert_start;
|
||||
};
|
||||
uint vert;
|
||||
};
|
||||
|
||||
@ -209,6 +220,8 @@ struct EDBMSelectID_Context {
|
||||
/** Borrow from caller (not freed). */
|
||||
struct Base **bases;
|
||||
uint bases_len;
|
||||
/** Total number of items `base_array_index_offsets[bases_len - 1].vert`. */
|
||||
uint base_array_index_len;
|
||||
};
|
||||
|
||||
static bool check_ob_drawface_dot(short select_mode, const View3D *v3d, char dt)
|
||||
@ -234,7 +247,7 @@ static void edbm_select_pick_draw_bases(struct EDBMSelectID_Context *sel_id_ctx,
|
||||
Scene *scene_eval = (Scene *)DEG_get_evaluated_id(vc->depsgraph, &vc->scene->id);
|
||||
DRW_framebuffer_select_id_setup(vc->ar, true);
|
||||
|
||||
uint offset = 0;
|
||||
uint offset = 1;
|
||||
for (uint base_index = 0; base_index < sel_id_ctx->bases_len; base_index++) {
|
||||
Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph,
|
||||
sel_id_ctx->bases[base_index]->object);
|
||||
@ -252,9 +265,12 @@ static void edbm_select_pick_draw_bases(struct EDBMSelectID_Context *sel_id_ctx,
|
||||
&base_ofs->edge,
|
||||
&base_ofs->face);
|
||||
|
||||
base_ofs->offset = offset;
|
||||
offset = base_ofs->vert;
|
||||
}
|
||||
|
||||
sel_id_ctx->base_array_index_len = offset;
|
||||
|
||||
DRW_framebuffer_select_id_release(vc->ar);
|
||||
}
|
||||
|
||||
@ -306,6 +322,29 @@ BMElem *EDBM_select_id_bm_elem_get(struct EDBMSelectID_Context *sel_id_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
uint EDBM_select_id_context_offset_for_object_elem(const struct EDBMSelectID_Context *sel_id_ctx,
|
||||
int base_index,
|
||||
char htype)
|
||||
{
|
||||
struct EDBMBaseOffset *base_ofs = &sel_id_ctx->base_array_index_offsets[base_index];
|
||||
if (htype == BM_VERT) {
|
||||
return base_ofs->vert_start - 1;
|
||||
}
|
||||
if (htype == BM_EDGE) {
|
||||
return base_ofs->edge_start - 1;
|
||||
}
|
||||
if (htype == BM_FACE) {
|
||||
return base_ofs->face_start - 1;
|
||||
}
|
||||
BLI_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint EDBM_select_id_context_elem_len(const struct EDBMSelectID_Context *sel_id_ctx)
|
||||
{
|
||||
return sel_id_ctx->base_array_index_len;
|
||||
}
|
||||
|
||||
struct EDBMSelectID_Context *EDBM_select_id_context_create(ViewContext *vc,
|
||||
Base **bases,
|
||||
uint bases_len,
|
||||
|
@ -214,7 +214,7 @@ static void validate_object_select_id(struct Depsgraph *depsgraph,
|
||||
obact_eval,
|
||||
select_mode,
|
||||
false,
|
||||
0,
|
||||
1,
|
||||
&bm_vertoffs,
|
||||
&bm_wireoffs,
|
||||
&bm_solidoffs);
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_array.h"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_lasso_2d.h"
|
||||
#include "BLI_rect.h"
|
||||
@ -88,6 +89,7 @@
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_buffer_utils.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_sculpt.h"
|
||||
#include "ED_mball.h"
|
||||
@ -178,21 +180,67 @@ static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Edit-Mesh Select Buffer Wrapper
|
||||
*
|
||||
* Avoid duplicate code when using edit-mode selection,
|
||||
* actual logic is handled outside of this function.
|
||||
*
|
||||
* \note Currently this #EDBMSelectID_Context which is mesh specific
|
||||
* however the logic could also be used for non-meshes too.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
struct EditSelectBuf_Cache {
|
||||
Base **bases;
|
||||
uint bases_len;
|
||||
struct EDBMSelectID_Context *sel_id_ctx;
|
||||
BLI_bitmap *select_bitmap;
|
||||
};
|
||||
|
||||
static void editselect_buf_cache_init(struct EditSelectBuf_Cache *esel, ViewContext *vc)
|
||||
{
|
||||
esel->bases = BKE_view_layer_array_from_bases_in_edit_mode(
|
||||
vc->view_layer, vc->v3d, &esel->bases_len);
|
||||
esel->sel_id_ctx = EDBM_select_id_context_create(
|
||||
vc, esel->bases, esel->bases_len, vc->scene->toolsettings->selectmode);
|
||||
for (int i = 0; i < esel->bases_len; i++) {
|
||||
esel->bases[i]->object->runtime.select_id = i;
|
||||
}
|
||||
}
|
||||
|
||||
static void editselect_buf_cache_free(struct EditSelectBuf_Cache *esel)
|
||||
{
|
||||
if (esel->sel_id_ctx) {
|
||||
EDBM_select_id_context_destroy(esel->sel_id_ctx);
|
||||
}
|
||||
MEM_SAFE_FREE(esel->select_bitmap);
|
||||
MEM_SAFE_FREE(esel->bases);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Edit-Mesh Utilities
|
||||
* \{ */
|
||||
|
||||
static bool edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp sel_op)
|
||||
static bool edbm_backbuf_check_and_select_verts(struct EditSelectBuf_Cache *esel,
|
||||
Object *ob,
|
||||
BMEditMesh *em,
|
||||
const eSelectOp sel_op)
|
||||
{
|
||||
BMVert *eve;
|
||||
BMIter iter;
|
||||
uint index = bm_wireoffs;
|
||||
bool changed = false;
|
||||
|
||||
const BLI_bitmap *select_bitmap = esel->select_bitmap;
|
||||
uint index = EDBM_select_id_context_offset_for_object_elem(
|
||||
esel->sel_id_ctx, ob->runtime.select_id, BM_VERT);
|
||||
|
||||
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
|
||||
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
|
||||
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
|
||||
const bool is_inside = EDBM_backbuf_check(index);
|
||||
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
|
||||
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
|
||||
if (sel_op_result != -1) {
|
||||
BM_vert_select_set(em->bm, eve, sel_op_result);
|
||||
@ -204,17 +252,23 @@ static bool edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool edbm_backbuf_check_and_select_edges(BMEditMesh *em, const eSelectOp sel_op)
|
||||
static bool edbm_backbuf_check_and_select_edges(struct EditSelectBuf_Cache *esel,
|
||||
Object *ob,
|
||||
BMEditMesh *em,
|
||||
const eSelectOp sel_op)
|
||||
{
|
||||
BMEdge *eed;
|
||||
BMIter iter;
|
||||
uint index = bm_solidoffs;
|
||||
bool changed = false;
|
||||
|
||||
const BLI_bitmap *select_bitmap = esel->select_bitmap;
|
||||
uint index = EDBM_select_id_context_offset_for_object_elem(
|
||||
esel->sel_id_ctx, ob->runtime.select_id, BM_EDGE);
|
||||
|
||||
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
|
||||
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
|
||||
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
|
||||
const bool is_inside = EDBM_backbuf_check(index);
|
||||
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
|
||||
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
|
||||
if (sel_op_result != -1) {
|
||||
BM_edge_select_set(em->bm, eed, sel_op_result);
|
||||
@ -226,17 +280,23 @@ static bool edbm_backbuf_check_and_select_edges(BMEditMesh *em, const eSelectOp
|
||||
return changed;
|
||||
}
|
||||
|
||||
static bool edbm_backbuf_check_and_select_faces(BMEditMesh *em, const eSelectOp sel_op)
|
||||
static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel,
|
||||
Object *ob,
|
||||
BMEditMesh *em,
|
||||
const eSelectOp sel_op)
|
||||
{
|
||||
BMFace *efa;
|
||||
BMIter iter;
|
||||
uint index = 1;
|
||||
bool changed = false;
|
||||
|
||||
const BLI_bitmap *select_bitmap = esel->select_bitmap;
|
||||
uint index = EDBM_select_id_context_offset_for_object_elem(
|
||||
esel->sel_id_ctx, ob->runtime.select_id, BM_FACE);
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
|
||||
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
|
||||
const bool is_inside = EDBM_backbuf_check(index);
|
||||
const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index);
|
||||
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
|
||||
if (sel_op_result != -1) {
|
||||
BM_face_select_set(em->bm, efa, sel_op_result);
|
||||
@ -621,14 +681,26 @@ static void do_lasso_select_mesh__doSelectVert(void *userData,
|
||||
data->is_changed = true;
|
||||
}
|
||||
}
|
||||
static void do_lasso_select_mesh__doSelectEdge_pass0(
|
||||
void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
|
||||
struct LassoSelectUserData_ForMeshEdge {
|
||||
LassoSelectUserData *data;
|
||||
struct EditSelectBuf_Cache *esel;
|
||||
uint backbuf_offset;
|
||||
};
|
||||
static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
|
||||
BMEdge *eed,
|
||||
const float screen_co_a[2],
|
||||
const float screen_co_b[2],
|
||||
int index)
|
||||
{
|
||||
LassoSelectUserData *data = userData;
|
||||
struct LassoSelectUserData_ForMeshEdge *data_for_edge = user_data;
|
||||
LassoSelectUserData *data = data_for_edge->data;
|
||||
const bool is_visible = (data_for_edge->esel ?
|
||||
BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap,
|
||||
data_for_edge->backbuf_offset + index) :
|
||||
true);
|
||||
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
|
||||
const bool is_inside =
|
||||
(EDBM_backbuf_check(bm_solidoffs + index) &&
|
||||
edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
|
||||
(is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
|
||||
BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) &&
|
||||
BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED));
|
||||
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
|
||||
@ -674,6 +746,7 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
|
||||
static bool do_lasso_select_mesh(ViewContext *vc,
|
||||
const int mcords[][2],
|
||||
short moves,
|
||||
struct EditSelectBuf_Cache *esel,
|
||||
const eSelectOp sel_op)
|
||||
{
|
||||
LassoSelectUserData data;
|
||||
@ -699,12 +772,21 @@ static bool do_lasso_select_mesh(ViewContext *vc,
|
||||
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
|
||||
|
||||
GPU_matrix_set(vc->rv3d->viewmat);
|
||||
bbsel = EDBM_backbuf_border_mask_init(
|
||||
vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
|
||||
|
||||
bbsel = !XRAY_FLAG_ENABLED(vc->v3d);
|
||||
|
||||
if (bbsel) {
|
||||
/* Lazy initialize. */
|
||||
if (esel->sel_id_ctx == NULL) {
|
||||
editselect_buf_cache_init(esel, vc);
|
||||
const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx);
|
||||
esel->select_bitmap = ED_select_buffer_bitmap_from_poly(buffer_len, mcords, moves, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (ts->selectmode & SCE_SELECT_VERTEX) {
|
||||
if (bbsel) {
|
||||
data.is_changed |= edbm_backbuf_check_and_select_verts(vc->em, sel_op);
|
||||
data.is_changed |= edbm_backbuf_check_and_select_verts(esel, vc->obedit, vc->em, sel_op);
|
||||
}
|
||||
else {
|
||||
mesh_foreachScreenVert(
|
||||
@ -713,17 +795,24 @@ static bool do_lasso_select_mesh(ViewContext *vc,
|
||||
}
|
||||
if (ts->selectmode & SCE_SELECT_EDGE) {
|
||||
/* Does both bbsel and non-bbsel versions (need screen cos for both) */
|
||||
struct LassoSelectUserData_ForMeshEdge data_for_edge = {
|
||||
.data = &data,
|
||||
.esel = bbsel ? esel : NULL,
|
||||
.backbuf_offset = bbsel ? EDBM_select_id_context_offset_for_object_elem(
|
||||
esel->sel_id_ctx, vc->obedit->runtime.select_id, BM_EDGE) :
|
||||
0,
|
||||
};
|
||||
mesh_foreachScreenEdge(
|
||||
vc, do_lasso_select_mesh__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR);
|
||||
vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, V3D_PROJ_TEST_CLIP_NEAR);
|
||||
if (data.is_done == false) {
|
||||
mesh_foreachScreenEdge(
|
||||
vc, do_lasso_select_mesh__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR);
|
||||
vc, do_lasso_select_mesh__doSelectEdge_pass1, &data_for_edge, V3D_PROJ_TEST_CLIP_NEAR);
|
||||
}
|
||||
}
|
||||
|
||||
if (ts->selectmode & SCE_SELECT_FACE) {
|
||||
if (bbsel) {
|
||||
data.is_changed |= edbm_backbuf_check_and_select_faces(vc->em, sel_op);
|
||||
data.is_changed |= edbm_backbuf_check_and_select_faces(esel, vc->obedit, vc->em, sel_op);
|
||||
}
|
||||
else {
|
||||
mesh_foreachScreenFace(
|
||||
@ -1121,13 +1210,15 @@ static bool view3d_lasso_select(
|
||||
}
|
||||
else { /* Edit Mode */
|
||||
|
||||
struct EditSelectBuf_Cache esel = {NULL};
|
||||
|
||||
FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->type, ob->mode, ob_iter) {
|
||||
ED_view3d_viewcontext_init_object(vc, ob_iter);
|
||||
bool changed = false;
|
||||
|
||||
switch (vc->obedit->type) {
|
||||
case OB_MESH:
|
||||
changed = do_lasso_select_mesh(vc, mcords, moves, sel_op);
|
||||
changed = do_lasso_select_mesh(vc, mcords, moves, &esel, sel_op);
|
||||
break;
|
||||
case OB_CURVE:
|
||||
case OB_SURF:
|
||||
@ -1154,6 +1245,8 @@ static bool view3d_lasso_select(
|
||||
}
|
||||
}
|
||||
FOREACH_OBJECT_IN_MODE_END;
|
||||
|
||||
editselect_buf_cache_free(&esel);
|
||||
}
|
||||
return changed_multi;
|
||||
}
|
||||
@ -2520,12 +2613,22 @@ static void do_mesh_box_select__doSelectVert(void *userData,
|
||||
data->is_changed = true;
|
||||
}
|
||||
}
|
||||
struct BoxSelectUserData_ForMeshEdge {
|
||||
BoxSelectUserData *data;
|
||||
struct EditSelectBuf_Cache *esel;
|
||||
uint backbuf_offset;
|
||||
};
|
||||
static void do_mesh_box_select__doSelectEdge_pass0(
|
||||
void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
|
||||
{
|
||||
BoxSelectUserData *data = userData;
|
||||
struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
|
||||
BoxSelectUserData *data = data_for_edge->data;
|
||||
const bool is_visible = (data_for_edge->esel ?
|
||||
BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap,
|
||||
data_for_edge->backbuf_offset + index) :
|
||||
true);
|
||||
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
|
||||
const bool is_inside = (EDBM_backbuf_check(bm_solidoffs + index) &&
|
||||
const bool is_inside = (is_visible &&
|
||||
edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
|
||||
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
|
||||
if (sel_op_result != -1) {
|
||||
@ -2537,10 +2640,14 @@ static void do_mesh_box_select__doSelectEdge_pass0(
|
||||
static void do_mesh_box_select__doSelectEdge_pass1(
|
||||
void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
|
||||
{
|
||||
BoxSelectUserData *data = userData;
|
||||
struct BoxSelectUserData_ForMeshEdge *data_for_edge = userData;
|
||||
BoxSelectUserData *data = data_for_edge->data;
|
||||
const bool is_visible = (data_for_edge->esel ?
|
||||
BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap,
|
||||
data_for_edge->backbuf_offset + index) :
|
||||
true);
|
||||
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
|
||||
const bool is_inside = (EDBM_backbuf_check(bm_solidoffs + index) &&
|
||||
edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
|
||||
const bool is_inside = (is_visible && edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
|
||||
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
|
||||
if (sel_op_result != -1) {
|
||||
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
|
||||
@ -2561,7 +2668,10 @@ static void do_mesh_box_select__doSelectFace(void *userData,
|
||||
data->is_changed = true;
|
||||
}
|
||||
}
|
||||
static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
|
||||
static bool do_mesh_box_select(ViewContext *vc,
|
||||
const rcti *rect,
|
||||
struct EditSelectBuf_Cache *esel,
|
||||
const eSelectOp sel_op)
|
||||
{
|
||||
BoxSelectUserData data;
|
||||
ToolSettings *ts = vc->scene->toolsettings;
|
||||
@ -2580,11 +2690,20 @@ static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_
|
||||
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
|
||||
|
||||
GPU_matrix_set(vc->rv3d->viewmat);
|
||||
bbsel = EDBM_backbuf_border_init(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
|
||||
bbsel = !XRAY_FLAG_ENABLED(vc->v3d);
|
||||
|
||||
if (bbsel) {
|
||||
/* Lazy initialize. */
|
||||
if (esel->sel_id_ctx == NULL) {
|
||||
editselect_buf_cache_init(esel, vc);
|
||||
const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx);
|
||||
esel->select_bitmap = ED_select_buffer_bitmap_from_rect(buffer_len, rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (ts->selectmode & SCE_SELECT_VERTEX) {
|
||||
if (bbsel) {
|
||||
data.is_changed |= edbm_backbuf_check_and_select_verts(vc->em, sel_op);
|
||||
data.is_changed |= edbm_backbuf_check_and_select_verts(esel, vc->obedit, vc->em, sel_op);
|
||||
}
|
||||
else {
|
||||
mesh_foreachScreenVert(
|
||||
@ -2593,17 +2712,24 @@ static bool do_mesh_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_
|
||||
}
|
||||
if (ts->selectmode & SCE_SELECT_EDGE) {
|
||||
/* Does both bbsel and non-bbsel versions (need screen cos for both) */
|
||||
struct BoxSelectUserData_ForMeshEdge cb_data = {
|
||||
.data = &data,
|
||||
.esel = bbsel ? esel : NULL,
|
||||
.backbuf_offset = bbsel ? EDBM_select_id_context_offset_for_object_elem(
|
||||
esel->sel_id_ctx, vc->obedit->runtime.select_id, BM_EDGE) :
|
||||
0,
|
||||
};
|
||||
mesh_foreachScreenEdge(
|
||||
vc, do_mesh_box_select__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR);
|
||||
vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, V3D_PROJ_TEST_CLIP_NEAR);
|
||||
if (data.is_done == false) {
|
||||
mesh_foreachScreenEdge(
|
||||
vc, do_mesh_box_select__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR);
|
||||
vc, do_mesh_box_select__doSelectEdge_pass1, &cb_data, V3D_PROJ_TEST_CLIP_NEAR);
|
||||
}
|
||||
}
|
||||
|
||||
if (ts->selectmode & SCE_SELECT_FACE) {
|
||||
if (bbsel) {
|
||||
data.is_changed |= edbm_backbuf_check_and_select_faces(vc->em, sel_op);
|
||||
data.is_changed |= edbm_backbuf_check_and_select_faces(esel, vc->obedit, vc->em, sel_op);
|
||||
}
|
||||
else {
|
||||
mesh_foreachScreenFace(
|
||||
@ -2941,6 +3067,8 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
|
||||
|
||||
if (vc.obedit) {
|
||||
|
||||
struct EditSelectBuf_Cache esel = {NULL};
|
||||
|
||||
FOREACH_OBJECT_IN_MODE_BEGIN (
|
||||
vc.view_layer, vc.v3d, vc.obedit->type, vc.obedit->mode, ob_iter) {
|
||||
ED_view3d_viewcontext_init_object(&vc, ob_iter);
|
||||
@ -2949,7 +3077,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
|
||||
switch (vc.obedit->type) {
|
||||
case OB_MESH:
|
||||
vc.em = BKE_editmesh_from_object(vc.obedit);
|
||||
changed = do_mesh_box_select(&vc, &rect, sel_op);
|
||||
changed = do_mesh_box_select(&vc, &rect, &esel, sel_op);
|
||||
if (changed) {
|
||||
DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
|
||||
@ -2991,6 +3119,8 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
|
||||
changed_multi |= changed;
|
||||
}
|
||||
FOREACH_OBJECT_IN_MODE_END;
|
||||
|
||||
editselect_buf_cache_free(&esel);
|
||||
}
|
||||
else { /* no editmode, unified for bones and objects */
|
||||
if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) {
|
||||
@ -3120,7 +3250,11 @@ static void mesh_circle_doSelectFace(void *userData,
|
||||
}
|
||||
}
|
||||
|
||||
static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval[2], float rad)
|
||||
static bool mesh_circle_select(ViewContext *vc,
|
||||
struct EditSelectBuf_Cache *esel,
|
||||
eSelectOp sel_op,
|
||||
const int mval[2],
|
||||
float rad)
|
||||
{
|
||||
ToolSettings *ts = vc->scene->toolsettings;
|
||||
int bbsel;
|
||||
@ -3136,14 +3270,26 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval
|
||||
}
|
||||
const bool select = (sel_op != SEL_OP_SUB);
|
||||
|
||||
bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
|
||||
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
|
||||
|
||||
view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
|
||||
|
||||
bbsel = !XRAY_FLAG_ENABLED(vc->v3d);
|
||||
|
||||
if (bbsel) {
|
||||
/* Lazy initialize. */
|
||||
if (esel->sel_id_ctx == NULL) {
|
||||
editselect_buf_cache_init(esel, vc);
|
||||
const uint buffer_len = EDBM_select_id_context_elem_len(esel->sel_id_ctx);
|
||||
esel->select_bitmap = ED_select_buffer_bitmap_from_circle(
|
||||
buffer_len, mval, (int)(rad + 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (ts->selectmode & SCE_SELECT_VERTEX) {
|
||||
if (bbsel) {
|
||||
changed |= edbm_backbuf_check_and_select_verts(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
|
||||
changed |= edbm_backbuf_check_and_select_verts(
|
||||
esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
|
||||
}
|
||||
else {
|
||||
mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
|
||||
@ -3152,7 +3298,8 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval
|
||||
|
||||
if (ts->selectmode & SCE_SELECT_EDGE) {
|
||||
if (bbsel) {
|
||||
changed |= edbm_backbuf_check_and_select_edges(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
|
||||
changed |= edbm_backbuf_check_and_select_edges(
|
||||
esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
|
||||
}
|
||||
else {
|
||||
mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
|
||||
@ -3161,7 +3308,8 @@ static bool mesh_circle_select(ViewContext *vc, eSelectOp sel_op, const int mval
|
||||
|
||||
if (ts->selectmode & SCE_SELECT_FACE) {
|
||||
if (bbsel) {
|
||||
changed |= edbm_backbuf_check_and_select_faces(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
|
||||
changed |= edbm_backbuf_check_and_select_faces(
|
||||
esel, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB);
|
||||
}
|
||||
else {
|
||||
mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
|
||||
@ -3593,6 +3741,7 @@ static bool mball_circle_select(ViewContext *vc,
|
||||
/** Callbacks for circle selection in Editmode */
|
||||
|
||||
static bool obedit_circle_select(ViewContext *vc,
|
||||
struct EditSelectBuf_Cache *esel,
|
||||
const eSelectOp sel_op,
|
||||
const int mval[2],
|
||||
float rad)
|
||||
@ -3600,7 +3749,7 @@ static bool obedit_circle_select(ViewContext *vc,
|
||||
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
|
||||
switch (vc->obedit->type) {
|
||||
case OB_MESH:
|
||||
return mesh_circle_select(vc, sel_op, mval, rad);
|
||||
return mesh_circle_select(vc, esel, sel_op, mval, rad);
|
||||
case OB_CURVE:
|
||||
case OB_SURF:
|
||||
return nurbscurve_circle_select(vc, sel_op, mval, rad);
|
||||
@ -3674,6 +3823,8 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
|
||||
view3d_operator_needs_opengl(C);
|
||||
BKE_object_update_select_id(CTX_data_main(C));
|
||||
|
||||
struct EditSelectBuf_Cache esel = {NULL};
|
||||
|
||||
FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->type, obact->mode, ob_iter) {
|
||||
ED_view3d_viewcontext_init_object(&vc, ob_iter);
|
||||
|
||||
@ -3681,7 +3832,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
|
||||
obedit = vc.obedit;
|
||||
|
||||
if (obedit) {
|
||||
if (obedit_circle_select(&vc, sel_op, mval, (float)radius)) {
|
||||
if (obedit_circle_select(&vc, &esel, sel_op, mval, (float)radius)) {
|
||||
DEG_id_tag_update(obact->data, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data);
|
||||
}
|
||||
@ -3700,6 +3851,8 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
FOREACH_OBJECT_IN_MODE_END;
|
||||
|
||||
editselect_buf_cache_free(&esel);
|
||||
}
|
||||
else if (obact && (obact->mode & OB_MODE_PARTICLE_EDIT)) {
|
||||
if (PE_circle_select(C, sel_op, mval, (float)radius)) {
|
||||
|
@ -41,6 +41,7 @@ set(SRC
|
||||
ed_util.c
|
||||
gizmo_utils.c
|
||||
numinput.c
|
||||
select_buffer_utils.c
|
||||
select_utils.c
|
||||
|
||||
# general includes
|
||||
@ -79,6 +80,7 @@ set(SRC
|
||||
../include/ED_screen.h
|
||||
../include/ED_screen_types.h
|
||||
../include/ED_sculpt.h
|
||||
../include/ED_select_buffer_utils.h
|
||||
../include/ED_select_utils.h
|
||||
../include/ED_sequencer.h
|
||||
../include/ED_sound.h
|
||||
|
179
source/blender/editors/util/select_buffer_utils.c
Normal file
179
source/blender/editors/util/select_buffer_utils.c
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup edutil
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_bitmap_draw_2d.h"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "ED_select_buffer_utils.h"
|
||||
|
||||
/* Only for #ED_view3d_select_id_read,
|
||||
* note that this file shouldn't have 3D view specific logic in it, we could have a more general
|
||||
* way to read from selection buffers that doesn't depend on the view3d API. */
|
||||
#include "ED_view3d.h"
|
||||
|
||||
/**
|
||||
* \param bitmap_len: Number of indices in the selection id buffer.
|
||||
* \param rect: The rectangle to sample indices from (min/max inclusive).
|
||||
* \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
|
||||
*/
|
||||
uint *ED_select_buffer_bitmap_from_rect(const uint bitmap_len, const rcti *rect)
|
||||
{
|
||||
uint buf_len;
|
||||
const uint *buf = ED_view3d_select_id_read(
|
||||
rect->xmin, rect->ymin, rect->xmax, rect->ymax, &buf_len);
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint *buf_iter = buf;
|
||||
|
||||
BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__);
|
||||
|
||||
while (buf_len--) {
|
||||
const uint index = *buf_iter - 1;
|
||||
if (index < bitmap_len) {
|
||||
BLI_BITMAP_ENABLE(bitmap_buf, index);
|
||||
}
|
||||
buf_iter++;
|
||||
}
|
||||
MEM_freeN((void *)buf);
|
||||
return bitmap_buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param bitmap_len: Number of indices in the selection id buffer.
|
||||
* \param center: Circle center.
|
||||
* \param radius: Circle radius.
|
||||
* \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
|
||||
*/
|
||||
uint *ED_select_buffer_bitmap_from_circle(const uint bitmap_len,
|
||||
const int center[2],
|
||||
const int radius)
|
||||
{
|
||||
if (bitmap_len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int xmin = center[0] - radius;
|
||||
const int xmax = center[0] + radius;
|
||||
const int ymin = center[1] - radius;
|
||||
const int ymax = center[1] + radius;
|
||||
|
||||
const uint *buf = ED_view3d_select_id_read(xmin, ymin, xmax, ymax, NULL);
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint *buf_iter = buf;
|
||||
|
||||
BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__);
|
||||
const int radius_sq = radius * radius;
|
||||
for (int yc = -radius; yc <= radius; yc++) {
|
||||
for (int xc = -radius; xc <= radius; xc++, buf_iter++) {
|
||||
if (xc * xc + yc * yc < radius_sq) {
|
||||
/* Intentionally wrap to max value if this is zero. */
|
||||
const uint index = *buf_iter - 1;
|
||||
if (index < bitmap_len) {
|
||||
BLI_BITMAP_ENABLE(bitmap_buf, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MEM_freeN((void *)buf);
|
||||
return bitmap_buf;
|
||||
}
|
||||
|
||||
struct PolyMaskData {
|
||||
BLI_bitmap *px;
|
||||
int width;
|
||||
};
|
||||
|
||||
static void ed_select_buffer_mask_px_cb(int x, int x_end, int y, void *user_data)
|
||||
{
|
||||
struct PolyMaskData *data = user_data;
|
||||
BLI_bitmap *px = data->px;
|
||||
int i = (y * data->width) + x;
|
||||
do {
|
||||
BLI_BITMAP_ENABLE(px, i);
|
||||
i++;
|
||||
} while (++x != x_end);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param bitmap_len: Number of indices in the selection id buffer.
|
||||
* \param center: Circle center.
|
||||
* \param radius: Circle radius.
|
||||
* \returns a #BLI_bitmap the length of \a bitmap_len or NULL on failure.
|
||||
*/
|
||||
uint *ED_select_buffer_bitmap_from_poly(const uint bitmap_len,
|
||||
const int poly[][2],
|
||||
const int poly_len,
|
||||
const rcti *rect)
|
||||
|
||||
{
|
||||
if (bitmap_len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct PolyMaskData poly_mask_data;
|
||||
uint buf_len;
|
||||
const uint *buf = ED_view3d_select_id_read(
|
||||
rect->xmin, rect->ymin, rect->xmax, rect->ymax, &buf_len);
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BLI_bitmap *buf_mask = BLI_BITMAP_NEW(buf_len, __func__);
|
||||
poly_mask_data.px = buf_mask;
|
||||
poly_mask_data.width = (rect->xmax - rect->xmin) + 1;
|
||||
|
||||
BLI_bitmap_draw_2d_poly_v2i_n(rect->xmin,
|
||||
rect->ymin,
|
||||
rect->xmax + 1,
|
||||
rect->ymax + 1,
|
||||
poly,
|
||||
poly_len,
|
||||
ed_select_buffer_mask_px_cb,
|
||||
&poly_mask_data);
|
||||
|
||||
/* Build selection lookup. */
|
||||
const uint *buf_iter = buf;
|
||||
BLI_bitmap *bitmap_buf = BLI_BITMAP_NEW(bitmap_len, __func__);
|
||||
int i = 0;
|
||||
while (buf_len--) {
|
||||
const uint index = *buf_iter - 1;
|
||||
if (index < bitmap_len && BLI_BITMAP_TEST(buf_mask, i)) {
|
||||
BLI_BITMAP_ENABLE(bitmap_buf, index);
|
||||
}
|
||||
buf_iter++;
|
||||
i++;
|
||||
}
|
||||
MEM_freeN((void *)buf);
|
||||
MEM_freeN(buf_mask);
|
||||
|
||||
return bitmap_buf;
|
||||
}
|
Loading…
Reference in New Issue
Block a user