Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_view3d/view3d_select.c
| Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_tracking_types.h" | #include "DNA_tracking_types.h" | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_array.h" | |||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_lasso_2d.h" | #include "BLI_lasso_2d.h" | ||||
| #include "BLI_rect.h" | #include "BLI_rect.h" | ||||
| #include "BLI_linklist.h" | #include "BLI_linklist.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_string.h" | #include "BLI_string.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc) | ||||
| vc->engine_type = CTX_data_engine_type(C); | vc->engine_type = CTX_data_engine_type(C); | ||||
| vc->v3d = CTX_wm_view3d(C); | vc->v3d = CTX_wm_view3d(C); | ||||
| vc->win = CTX_wm_window(C); | vc->win = CTX_wm_window(C); | ||||
| vc->rv3d = CTX_wm_region_view3d(C); | vc->rv3d = CTX_wm_region_view3d(C); | ||||
| vc->obact = CTX_data_active_object(C); | vc->obact = CTX_data_active_object(C); | ||||
| vc->obedit = CTX_data_edit_object(C); | vc->obedit = CTX_data_edit_object(C); | ||||
| } | } | ||||
| void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact) | |||||
| { | |||||
| vc->obact = obact; | |||||
| if (vc->obedit) { | |||||
| BLI_assert(BKE_object_is_in_editmode(obact)); | |||||
| vc->obedit = obact; | |||||
| /* previous selections are now invalid. */ | |||||
| vc->v3d->flag |= V3D_INVALID_BACKBUF; | |||||
| if (vc->em) { | |||||
| vc->em = BKE_editmesh_from_object(vc->obedit); | |||||
| } | |||||
| } | |||||
| } | |||||
| /* ********************** view3d_select: selection manipulations ********************* */ | /* ********************** view3d_select: selection manipulations ********************* */ | ||||
| /* local prototypes */ | /* local prototypes */ | ||||
| static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const bool select) | static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const bool select) | ||||
| { | { | ||||
| BMVert *eve; | BMVert *eve; | ||||
| BMIter iter; | BMIter iter; | ||||
| ▲ Show 20 Lines • Show All 256 Lines • ▼ Show 20 Lines | for (base = view_layer->object_bases.first; base; base = base->next) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void do_lasso_select_objects( | static void do_lasso_select_objects( | ||||
| ViewContext *vc, const int mcords[][2], const short moves, | ViewContext *vc, const int mcords[][2], const short moves, | ||||
| const bool extend, const bool select) | const bool extend, const bool select) | ||||
| { | { | ||||
| bool is_pose_mode = vc->obact ? (vc->obact->mode & OB_MODE_POSE) : false; | |||||
| Base *base; | Base *base; | ||||
| if (extend == false && select) | if (extend == false && select) | ||||
| object_deselect_all_visible(vc->view_layer); | object_deselect_all_visible(vc->view_layer); | ||||
| for (base = vc->view_layer->object_bases.first; base; base = base->next) { | for (base = vc->view_layer->object_bases.first; base; base = base->next) { | ||||
| if (BASE_SELECTABLE(base)) { /* use this to avoid un-needed lasso lookups */ | if (BASE_SELECTABLE(base)) { /* use this to avoid un-needed lasso lookups */ | ||||
| if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) { | if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) { | ||||
| if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) { | if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) { | ||||
| ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); | ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); | ||||
| } | } | ||||
| } | } | ||||
| if (vc->obact == base->object && (base->object->mode & OB_MODE_POSE)) { | if (is_pose_mode && | ||||
| ((vc->obact == base->object) || (base->flag & BASE_SELECTED)) && | |||||
| (base->object->mode & OB_MODE_POSE)) | |||||
| { | |||||
| do_lasso_select_pose(vc, base->object, mcords, moves, select); | do_lasso_select_pose(vc, base->object, mcords, moves, select); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index)) | static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index)) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 410 Lines • ▼ Show 20 Lines | else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { | ||||
| PE_lasso_select(C, mcords, moves, extend, select); | PE_lasso_select(C, mcords, moves, extend, select); | ||||
| } | } | ||||
| else { | else { | ||||
| do_lasso_select_objects(vc, mcords, moves, extend, select); | do_lasso_select_objects(vc, mcords, moves, extend, select); | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); | WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); | ||||
| } | } | ||||
| } | } | ||||
| else { /* Edit Mode */ | else { /* Edit Mode */ | ||||
| /* don't indent to avoid diff noise! */ | |||||
| FOREACH_OBJECT_IN_MODE_BEGIN (eval_ctx.view_layer, ob->mode, ob_iter) { | |||||
| ED_view3d_viewcontext_init_object(vc, ob_iter); | |||||
| /* --- */ | |||||
| switch (vc->obedit->type) { | switch (vc->obedit->type) { | ||||
| case OB_MESH: | case OB_MESH: | ||||
| do_lasso_select_mesh(&eval_ctx, vc, mcords, moves, extend, select); | do_lasso_select_mesh(&eval_ctx, vc, mcords, moves, extend, select); | ||||
| break; | break; | ||||
| case OB_CURVE: | case OB_CURVE: | ||||
| case OB_SURF: | case OB_SURF: | ||||
| do_lasso_select_curve(vc, mcords, moves, extend, select); | do_lasso_select_curve(vc, mcords, moves, extend, select); | ||||
| break; | break; | ||||
| case OB_LATTICE: | case OB_LATTICE: | ||||
| do_lasso_select_lattice(vc, mcords, moves, extend, select); | do_lasso_select_lattice(vc, mcords, moves, extend, select); | ||||
| break; | break; | ||||
| case OB_ARMATURE: | case OB_ARMATURE: | ||||
| do_lasso_select_armature(vc, mcords, moves, extend, select); | do_lasso_select_armature(vc, mcords, moves, extend, select); | ||||
| break; | break; | ||||
| case OB_MBALL: | case OB_MBALL: | ||||
| do_lasso_select_meta(vc, mcords, moves, extend, select); | do_lasso_select_meta(vc, mcords, moves, extend, select); | ||||
| break; | break; | ||||
| default: | default: | ||||
| assert(!"lasso select on incorrect object type"); | assert(!"lasso select on incorrect object type"); | ||||
| break; | break; | ||||
| } | } | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data); | ||||
| } FOREACH_OBJECT_IN_MODE_END; | |||||
| } | } | ||||
| } | } | ||||
| /* lasso operator gives properties, but since old code works | /* lasso operator gives properties, but since old code works | ||||
| * with short array we convert */ | * with short array we convert */ | ||||
| static int view3d_lasso_select_exec(bContext *C, wmOperator *op) | static int view3d_lasso_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 508 Lines • ▼ Show 20 Lines | static bool ed_object_select_pick( | ||||
| CTX_data_eval_ctx(C, &eval_ctx); | CTX_data_eval_ctx(C, &eval_ctx); | ||||
| ED_view3d_viewcontext_init(C, &vc); | ED_view3d_viewcontext_init(C, &vc); | ||||
| is_obedit = (vc.obedit != NULL); | is_obedit = (vc.obedit != NULL); | ||||
| if (object) { | if (object) { | ||||
| /* signal for view3d_opengl_select to skip editmode objects */ | /* signal for view3d_opengl_select to skip editmode objects */ | ||||
| vc.obedit = NULL; | vc.obedit = NULL; | ||||
| } | } | ||||
| /* In pose mode we don't want to mess with object selection. */ | |||||
| const bool is_pose_mode = (vc.obact && vc.obact->mode & OB_MODE_POSE); | |||||
| /* always start list from basact in wire mode */ | /* always start list from basact in wire mode */ | ||||
| startbase = FIRSTBASE(view_layer); | startbase = FIRSTBASE(view_layer); | ||||
| if (BASACT(view_layer) && BASACT(view_layer)->next) startbase = BASACT(view_layer)->next; | if (BASACT(view_layer) && BASACT(view_layer)->next) startbase = BASACT(view_layer)->next; | ||||
| /* This block uses the control key to make the object selected by its center point rather than its contents */ | /* This block uses the control key to make the object selected by its center point rather than its contents */ | ||||
| /* in editmode do not activate */ | /* in editmode do not activate */ | ||||
| if (obcenter) { | if (obcenter) { | ||||
| ▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | if (hits > 0) { | ||||
| if (!changed) { | if (!changed) { | ||||
| /* fallback to regular object selection if no new bundles were selected, | /* fallback to regular object selection if no new bundles were selected, | ||||
| * allows to select object parented to reconstruction object */ | * allows to select object parented to reconstruction object */ | ||||
| basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest); | basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (ED_armature_pose_select_pick_with_buffer(view_layer, basact, buffer, hits, extend, deselect, toggle, do_nearest)) { | else if (ED_armature_pose_select_pick_with_buffer( | ||||
| view_layer, basact, buffer, hits, extend, deselect, toggle, do_nearest)) | |||||
| { | |||||
| /* then bone is found */ | /* then bone is found */ | ||||
| /* we make the armature selected: | /* we make the armature selected: | ||||
| * not-selected active object in posemode won't work well for tools */ | * not-selected active object in posemode won't work well for tools */ | ||||
| basact->flag |= BASE_SELECTED; | basact->flag |= BASE_SELECTED; | ||||
| BKE_scene_object_base_flag_sync_from_base(basact); | BKE_scene_object_base_flag_sync_from_base(basact); | ||||
| retval = true; | retval = true; | ||||
| Show All 40 Lines | else if (BASE_SELECTABLE(basact)) { | ||||
| ED_object_base_select(basact, BA_DESELECT); | ED_object_base_select(basact, BA_DESELECT); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| ED_object_base_select(basact, BA_SELECT); | ED_object_base_select(basact, BA_SELECT); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* When enabled, this puts other objects out of multi pose-mode. */ | |||||
| if (is_pose_mode == false) { | |||||
| deselectall_except(view_layer, basact); | deselectall_except(view_layer, basact); | ||||
| ED_object_base_select(basact, BA_SELECT); | ED_object_base_select(basact, BA_SELECT); | ||||
| } | } | ||||
| } | |||||
| if ((oldbasact != basact) && (is_obedit == false)) { | if ((oldbasact != basact) && (is_obedit == false)) { | ||||
| ED_object_base_activate(C, basact); /* adds notifier */ | ED_object_base_activate(C, basact); /* adds notifier */ | ||||
| } | } | ||||
| } | } | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); | WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 327 Lines • ▼ Show 20 Lines | static int do_meta_box_select( | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static int do_armature_box_select( | static int do_armature_box_select( | ||||
| const struct EvaluationContext *eval_ctx, ViewContext *vc, | const struct EvaluationContext *eval_ctx, ViewContext *vc, | ||||
| const rcti *rect, bool select, bool extend) | const rcti *rect, bool select, bool extend) | ||||
| { | { | ||||
| bArmature *arm = vc->obedit->data; | |||||
| int a; | int a; | ||||
| unsigned int buffer[MAXPICKBUF]; | unsigned int buffer[MAXPICKBUF]; | ||||
| int hits; | int hits; | ||||
| hits = view3d_opengl_select(eval_ctx, vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL); | hits = view3d_opengl_select(eval_ctx, vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL); | ||||
| uint objects_len = 0; | |||||
| Object **objects = BKE_view_layer_array_from_objects_in_mode( | |||||
| eval_ctx->view_layer, &objects_len, { | |||||
| .object_mode = OB_MODE_EDIT, | |||||
| .no_dup_data = true}); | |||||
| /* clear flag we use to detect point was affected */ | /* clear flag we use to detect point was affected */ | ||||
| for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) | for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | ||||
| Object *obedit = objects[ob_index]; | |||||
| bArmature *arm = obedit->data; | |||||
| for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { | |||||
| ebone->flag &= ~BONE_DONE; | ebone->flag &= ~BONE_DONE; | ||||
| } | |||||
| } | |||||
| if (extend == false && select) | if (extend == false && select) { | ||||
| ED_armature_edit_deselect_all_visible(vc->obedit); | ED_armature_edit_deselect_all_visible_multi(objects, objects_len); | ||||
| } | |||||
| /* first we only check points inside the border */ | /* first we only check points inside the border */ | ||||
| for (a = 0; a < hits; a++) { | for (a = 0; a < hits; a++) { | ||||
| int index = buffer[(4 * a) + 3]; | int index = buffer[(4 * a) + 3]; | ||||
| if (index != -1) { | if (index != -1) { | ||||
| if ((index & 0xFFFF0000) == 0) { | if ((index & 0xFFFF0000) == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| EditBone *ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY)); | |||||
| EditBone *ebone; | |||||
| ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone); | |||||
| if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) { | if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) { | ||||
| if (index & BONESEL_TIP) { | if (index & BONESEL_TIP) { | ||||
| ebone->flag |= BONE_DONE; | ebone->flag |= BONE_DONE; | ||||
| if (select) ebone->flag |= BONE_TIPSEL; | if (select) ebone->flag |= BONE_TIPSEL; | ||||
| else ebone->flag &= ~BONE_TIPSEL; | else ebone->flag &= ~BONE_TIPSEL; | ||||
| } | } | ||||
| if (index & BONESEL_ROOT) { | if (index & BONESEL_ROOT) { | ||||
| ebone->flag |= BONE_DONE; | ebone->flag |= BONE_DONE; | ||||
| if (select) ebone->flag |= BONE_ROOTSEL; | if (select) ebone->flag |= BONE_ROOTSEL; | ||||
| else ebone->flag &= ~BONE_ROOTSEL; | else ebone->flag &= ~BONE_ROOTSEL; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* now we have to flush tag from parents... */ | /* now we have to flush tag from parents... */ | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| bArmature *arm = obedit->data; | |||||
| for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { | for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { | ||||
| if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { | if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { | ||||
| if (ebone->parent->flag & BONE_DONE) { | if (ebone->parent->flag & BONE_DONE) { | ||||
| ebone->flag |= BONE_DONE; | ebone->flag |= BONE_DONE; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| /* only select/deselect entire bones when no points where in the rect */ | /* only select/deselect entire bones when no points where in the rect */ | ||||
| for (a = 0; a < hits; a++) { | for (a = 0; a < hits; a++) { | ||||
| int index = buffer[(4 * a) + 3]; | int index = buffer[(4 * a) + 3]; | ||||
| if (index != -1) { | if (index != -1) { | ||||
| if (index & BONESEL_BONE) { | if (index & BONESEL_BONE) { | ||||
| EditBone *ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY)); | EditBone *ebone; | ||||
| ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone); | |||||
| if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) { | if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) { | ||||
| if (!(ebone->flag & BONE_DONE)) { | if (!(ebone->flag & BONE_DONE)) { | ||||
| if (select) { | if (select) { | ||||
| ebone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED); | ebone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED); | ||||
| } | } | ||||
| else { | else { | ||||
| ebone->flag &= ~(BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED); | ebone->flag &= ~(BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | |||||
| Object *obedit = objects[ob_index]; | |||||
| bArmature *arm = obedit->data; | |||||
| ED_armature_edit_sync_selection(arm->edbo); | ED_armature_edit_sync_selection(arm->edbo); | ||||
| } | |||||
| MEM_freeN(objects); | |||||
| return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED; | return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /** | /** | ||||
| * Compare result of 'GPU_select': 'uint[4]', | * Compare result of 'GPU_select': 'uint[4]', | ||||
| * needed for when we need to align with object draw-order. | * needed for when we need to align with object draw-order. | ||||
| */ | */ | ||||
| static int opengl_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p) | static int opengl_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p) | ||||
| Show All 11 Lines | static int opengl_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p) | ||||
| else { | else { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend) | static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend) | ||||
| { | { | ||||
| EvaluationContext eval_ctx; | EvaluationContext eval_ctx; | ||||
| Bone *bone; | |||||
| Object *ob = vc->obact; | |||||
| unsigned int *vbuffer = NULL; /* selection buffer */ | unsigned int *vbuffer = NULL; /* selection buffer */ | ||||
| unsigned int *col; /* color in buffer */ | |||||
| int bone_only; | int bone_only; | ||||
| int bone_selected = 0; | |||||
| int totobj = MAXPICKBUF; /* XXX solve later */ | int totobj = MAXPICKBUF; /* XXX solve later */ | ||||
| int hits; | int hits; | ||||
| CTX_data_eval_ctx(C, &eval_ctx); | CTX_data_eval_ctx(C, &eval_ctx); | ||||
| if ((ob) && (ob->mode & OB_MODE_POSE)) | if (vc->obact && (vc->obact->mode & OB_MODE_POSE)) | ||||
| bone_only = 1; | bone_only = 1; | ||||
| else | else | ||||
| bone_only = 0; | bone_only = 0; | ||||
| if (extend == false && select) { | if (extend == false && select) { | ||||
| if (bone_only) { | if (bone_only) { | ||||
| CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) | FOREACH_OBJECT_IN_MODE_BEGIN (eval_ctx.view_layer, OB_MODE_POSE, ob_iter) { | ||||
| { | bArmature *arm = ob_iter->data; | ||||
| for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { | |||||
| if (PBONE_VISIBLE(arm, pchan->bone)) { | |||||
| if ((select == false) || ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)) { | if ((select == false) || ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)) { | ||||
| pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); | pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | } | ||||
| } FOREACH_OBJECT_IN_MODE_END; | |||||
| } | } | ||||
| else { | else { | ||||
| object_deselect_all_visible(vc->view_layer); | object_deselect_all_visible(vc->view_layer); | ||||
| } | } | ||||
| } | } | ||||
| /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ | /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ | ||||
| vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(unsigned int), "selection buffer"); | vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(unsigned int), "selection buffer"); | ||||
| hits = view3d_opengl_select(&eval_ctx, vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL); | hits = view3d_opengl_select(&eval_ctx, vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL); | ||||
| /* | /* | ||||
| * LOGIC NOTES (theeth): | * LOGIC NOTES (theeth): | ||||
| * The buffer and ListBase have the same relative order, which makes the selection | * The buffer and ListBase have the same relative order, which makes the selection | ||||
| * very simple. Loop through both data sets at the same time, if the color | * very simple. Loop through both data sets at the same time, if the color | ||||
| * is the same as the object, we have a hit and can move to the next color | * is the same as the object, we have a hit and can move to the next color | ||||
| * and object pair, if not, just move to the next object, | * and object pair, if not, just move to the next object, | ||||
| * keeping the same color until we have a hit. | * keeping the same color until we have a hit. | ||||
| */ | */ | ||||
| if (hits > 0) { /* no need to loop if there's no hit */ | if (hits > 0) { /* no need to loop if there's no hit */ | ||||
| Base *base; | |||||
| col = vbuffer + 3; | |||||
| /* The draw order doesn't always match the order we populate the engine, see: T51695. */ | /* The draw order doesn't always match the order we populate the engine, see: T51695. */ | ||||
| qsort(vbuffer, hits, sizeof(uint[4]), opengl_select_buffer_cmp); | qsort(vbuffer, hits, sizeof(uint[4]), opengl_select_buffer_cmp); | ||||
| /* | Base **bases = NULL; | ||||
| * Even though 'DRW_draw_select_loop' uses 'DEG_OBJECT_ITER_BEGIN', | BLI_array_declare(bases); | ||||
| * we can be sure the order remains the same between both. | |||||
| */ | for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) { | ||||
| for (base = vc->view_layer->object_bases.first; base && hits; base = base->next) { | |||||
| if (BASE_SELECTABLE(base)) { | if (BASE_SELECTABLE(base)) { | ||||
| while (base->object->select_color == (*col & 0xFFFF)) { /* we got an object */ | if ((base->object->select_color & 0x0000FFFF) != 0) { | ||||
| if (*col & 0xFFFF0000) { /* we got a bone */ | BLI_array_append(bases, base); | ||||
| bone = ED_armature_bone_find_index(base->object, *col & ~(BONESEL_ANY)); | } | ||||
| if (bone) { | } | ||||
| } | |||||
| for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) { | |||||
| Bone *bone; | |||||
| Base *base = ED_armature_base_and_bone_from_select_buffer(bases, BLI_array_len(bases), *col, &bone); | |||||
| if (base == NULL) { | |||||
| continue; | |||||
| } | |||||
| /* Loop over contiguous bone hits for 'base'. */ | |||||
| bool bone_selected = false; | |||||
| for (; col != col_end; col += 4) { | |||||
| /* should never fail */ | |||||
| if (bone != NULL) { | |||||
| if (select) { | if (select) { | ||||
| if ((bone->flag & BONE_UNSELECTABLE) == 0) { | if ((bone->flag & BONE_UNSELECTABLE) == 0) { | ||||
| bone->flag |= BONE_SELECTED; | bone->flag |= BONE_SELECTED; | ||||
| bone_selected = 1; | bone_selected = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| bArmature *arm = base->object->data; | bArmature *arm = base->object->data; | ||||
| bone->flag &= ~BONE_SELECTED; | bone->flag &= ~BONE_SELECTED; | ||||
| if (arm->act_bone == bone) | if (arm->act_bone == bone) | ||||
| arm->act_bone = NULL; | arm->act_bone = NULL; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| else if (!bone_only) { | else if (!bone_only) { | ||||
| ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); | ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); | ||||
| } | } | ||||
| col += 4; /* next color */ | /* Select the next bone if we're not switching bases. */ | ||||
| hits--; | if (col + 4 != col_end) { | ||||
| if (hits == 0) break; | if ((base->object->select_color & 0x0000FFFF) != (col[4] & 0x0000FFFF)) { | ||||
| break; | |||||
| } | |||||
| const uint hit_bone = (col[4] & ~BONESEL_ANY) >> 16; | |||||
| bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);; | |||||
| bone = pchan ? pchan->bone : NULL; | |||||
| } | } | ||||
| } | } | ||||
| if (bone_selected) { | if (bone_selected) { | ||||
| if (base->object && (base->object->type == OB_ARMATURE)) { | if (base->object && (base->object->type == OB_ARMATURE)) { | ||||
| bArmature *arm = base->object->data; | bArmature *arm = base->object->data; | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object); | WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object); | ||||
| if (arm && (arm->flag & ARM_HAS_VIZ_DEPS)) { | if (vc->obact && arm && (arm->flag & ARM_HAS_VIZ_DEPS)) { | ||||
| /* mask modifier ('armature' mode), etc. */ | /* mask modifier ('armature' mode), etc. */ | ||||
| DEG_id_tag_update(&ob->id, OB_RECALC_DATA); | DEG_id_tag_update(&vc->obact->id, OB_RECALC_DATA); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(bases); | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); | WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); | ||||
| } | } | ||||
| MEM_freeN(vbuffer); | MEM_freeN(vbuffer); | ||||
| return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED; | return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED; | ||||
| } | } | ||||
| static int view3d_borderselect_exec(bContext *C, wmOperator *op) | static int view3d_borderselect_exec(bContext *C, wmOperator *op) | ||||
| Show All 12 Lines | static int view3d_borderselect_exec(bContext *C, wmOperator *op) | ||||
| CTX_data_eval_ctx(C, &eval_ctx); | CTX_data_eval_ctx(C, &eval_ctx); | ||||
| ED_view3d_viewcontext_init(C, &vc); | ED_view3d_viewcontext_init(C, &vc); | ||||
| select = !RNA_boolean_get(op->ptr, "deselect"); | select = !RNA_boolean_get(op->ptr, "deselect"); | ||||
| extend = RNA_boolean_get(op->ptr, "extend"); | extend = RNA_boolean_get(op->ptr, "extend"); | ||||
| WM_operator_properties_border_to_rcti(op, &rect); | WM_operator_properties_border_to_rcti(op, &rect); | ||||
| if (vc.obedit) { | if (vc.obedit) { | ||||
| /* don't indent to avoid diff noise! */ | |||||
| FOREACH_OBJECT_IN_MODE_BEGIN (eval_ctx.view_layer, vc.obedit->mode, ob_iter) { | |||||
| ED_view3d_viewcontext_init_object(&vc, ob_iter); | |||||
| /* --- */ | |||||
| switch (vc.obedit->type) { | switch (vc.obedit->type) { | ||||
| case OB_MESH: | case OB_MESH: | ||||
| vc.em = BKE_editmesh_from_object(vc.obedit); | vc.em = BKE_editmesh_from_object(vc.obedit); | ||||
| ret = do_mesh_box_select(&eval_ctx, &vc, &rect, select, extend); | ret |= do_mesh_box_select(&eval_ctx, &vc, &rect, select, extend); | ||||
| // if (EM_texFaceCheck()) | |||||
| if (ret & OPERATOR_FINISHED) { | if (ret & OPERATOR_FINISHED) { | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | ||||
| } | } | ||||
| break; | break; | ||||
| case OB_CURVE: | case OB_CURVE: | ||||
| case OB_SURF: | case OB_SURF: | ||||
| ret = do_nurbs_box_select(&vc, &rect, select, extend); | ret |= do_nurbs_box_select(&vc, &rect, select, extend); | ||||
| if (ret & OPERATOR_FINISHED) { | if (ret & OPERATOR_FINISHED) { | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | ||||
| } | } | ||||
| break; | break; | ||||
| case OB_MBALL: | case OB_MBALL: | ||||
| ret = do_meta_box_select(&eval_ctx, &vc, &rect, select, extend); | ret |= do_meta_box_select(&eval_ctx, &vc, &rect, select, extend); | ||||
| if (ret & OPERATOR_FINISHED) { | if (ret & OPERATOR_FINISHED) { | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | ||||
| } | } | ||||
| break; | break; | ||||
| case OB_ARMATURE: | case OB_ARMATURE: | ||||
| ret = do_armature_box_select(&eval_ctx, &vc, &rect, select, extend); | ret |= do_armature_box_select(&eval_ctx, &vc, &rect, select, extend); | ||||
| if (ret & OPERATOR_FINISHED) { | if (ret & OPERATOR_FINISHED) { | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); | WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); | ||||
| } | } | ||||
| break; | break; | ||||
| case OB_LATTICE: | case OB_LATTICE: | ||||
| ret = do_lattice_box_select(&vc, &rect, select, extend); | ret |= do_lattice_box_select(&vc, &rect, select, extend); | ||||
| if (ret & OPERATOR_FINISHED) { | if (ret & OPERATOR_FINISHED) { | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | ||||
| } | } | ||||
| break; | break; | ||||
| default: | default: | ||||
| assert(!"border select on incorrect object type"); | assert(!"border select on incorrect object type"); | ||||
| break; | break; | ||||
| } | }} FOREACH_OBJECT_IN_MODE_END; | ||||
| } | } | ||||
| else { /* no editmode, unified for bones and objects */ | else { /* no editmode, unified for bones and objects */ | ||||
| if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) { | if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) { | ||||
| ret = ED_sculpt_mask_box_select(C, &vc, &rect, select, extend); | ret |= ED_sculpt_mask_box_select(C, &vc, &rect, select, extend); | ||||
| } | } | ||||
| else if (vc.obact && BKE_paint_select_face_test(vc.obact)) { | else if (vc.obact && BKE_paint_select_face_test(vc.obact)) { | ||||
| ret = do_paintface_box_select(&eval_ctx, &vc, &rect, select, extend); | ret |= do_paintface_box_select(&eval_ctx, &vc, &rect, select, extend); | ||||
| } | } | ||||
| else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) { | else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) { | ||||
| ret = do_paintvert_box_select(&eval_ctx, &vc, &rect, select, extend); | ret |= do_paintvert_box_select(&eval_ctx, &vc, &rect, select, extend); | ||||
| } | } | ||||
| else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) { | else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) { | ||||
| ret = PE_border_select(C, &rect, select, extend); | ret |= PE_border_select(C, &rect, select, extend); | ||||
| } | } | ||||
| else { /* object mode with none active */ | else { /* object mode with none active */ | ||||
| ret = do_object_pose_box_select(C, &vc, &rect, select, extend); | ret |= do_object_pose_box_select(C, &vc, &rect, select, extend); | ||||
| } | |||||
| } | } | ||||
| if (ret & OPERATOR_FINISHED) { | |||||
| ret = OPERATOR_FINISHED; | |||||
| } | |||||
| else { | |||||
| ret = OPERATOR_CANCELLED; | |||||
| } | } | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| /* *****************Selection Operators******************* */ | /* *****************Selection Operators******************* */ | ||||
| ▲ Show 20 Lines • Show All 626 Lines • ▼ Show 20 Lines | static bool object_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad) | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /* not a real operator, only for circle test */ | /* not a real operator, only for circle test */ | ||||
| static int view3d_circle_select_exec(bContext *C, wmOperator *op) | static int view3d_circle_select_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | ViewContext vc; | ||||
| Object *obact = CTX_data_active_object(C); | EvaluationContext eval_ctx; | ||||
| CTX_data_eval_ctx(C, &eval_ctx); | |||||
| const int radius = RNA_int_get(op->ptr, "radius"); | const int radius = RNA_int_get(op->ptr, "radius"); | ||||
| const bool select = !RNA_boolean_get(op->ptr, "deselect"); | const bool select = !RNA_boolean_get(op->ptr, "deselect"); | ||||
| const int mval[2] = {RNA_int_get(op->ptr, "x"), | const int mval[2] = {RNA_int_get(op->ptr, "x"), | ||||
| RNA_int_get(op->ptr, "y")}; | RNA_int_get(op->ptr, "y")}; | ||||
| if (CTX_data_edit_object(C) || BKE_paint_select_elem_test(obact) || | |||||
| ED_view3d_viewcontext_init(C, &vc); | |||||
| Object *obact = vc.obact; | |||||
| Object *obedit = vc.obedit; | |||||
| if (obedit || BKE_paint_select_elem_test(obact) || | |||||
| (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) ) | (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) ) | ||||
| { | { | ||||
| EvaluationContext eval_ctx; | |||||
| ViewContext vc; | |||||
| view3d_operator_needs_opengl(C); | view3d_operator_needs_opengl(C); | ||||
| CTX_data_eval_ctx(C, &eval_ctx); | /* don't indent to avoid diff noise! */ | ||||
| ED_view3d_viewcontext_init(C, &vc); | FOREACH_OBJECT_IN_MODE_BEGIN (eval_ctx.view_layer, obact->mode, ob_iter) { | ||||
| ED_view3d_viewcontext_init_object(&vc, ob_iter); | |||||
| /* --- */ | |||||
| obact = vc.obact; | |||||
| obedit = vc.obedit; | |||||
| if (CTX_data_edit_object(C)) { | if (CTX_data_edit_object(C)) { | ||||
| obedit_circle_select(&eval_ctx, &vc, select, mval, (float)radius); | obedit_circle_select(&eval_ctx, &vc, select, mval, (float)radius); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); | ||||
| } | } | ||||
| else if (BKE_paint_select_face_test(obact)) { | else if (BKE_paint_select_face_test(obact)) { | ||||
| paint_facesel_circle_select(&eval_ctx, &vc, select, mval, (float)radius); | paint_facesel_circle_select(&eval_ctx, &vc, select, mval, (float)radius); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); | ||||
| } | } | ||||
| else if (BKE_paint_select_vert_test(obact)) { | else if (BKE_paint_select_vert_test(obact)) { | ||||
| paint_vertsel_circle_select(&eval_ctx, &vc, select, mval, (float)radius); | paint_vertsel_circle_select(&eval_ctx, &vc, select, mval, (float)radius); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); | ||||
| } | } | ||||
| else if (obact->mode & OB_MODE_POSE) | else if (obact->mode & OB_MODE_POSE) | ||||
| pose_circle_select(&vc, select, mval, (float)radius); | pose_circle_select(&vc, select, mval, (float)radius); | ||||
| else | else | ||||
| return PE_circle_select(C, select, mval, (float)radius); | return PE_circle_select(C, select, mval, (float)radius); | ||||
| } FOREACH_OBJECT_IN_MODE_END; | |||||
| } | } | ||||
| else if (obact && obact->mode & OB_MODE_SCULPT) { | else if (obact && obact->mode & OB_MODE_SCULPT) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| else { | else { | ||||
| ViewContext vc; | |||||
| ED_view3d_viewcontext_init(C, &vc); | |||||
| if (object_circle_select(&vc, select, mval, (float)radius)) { | if (object_circle_select(&vc, select, mval, (float)radius)) { | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); | WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene); | ||||
| } | } | ||||
| } | } | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void VIEW3D_OT_select_circle(wmOperatorType *ot) | void VIEW3D_OT_select_circle(wmOperatorType *ot) | ||||
| { | { | ||||
| Show All 16 Lines | |||||