Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_view3d/view3d_select.c
| Context not available. | |||||
| return changed; | return changed; | ||||
| } | } | ||||
| static bool edbm_backbuf_check_and_select_faces(struct EditSelectBuf_Cache *esel, | static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, | ||||
| struct EditSelectBuf_Cache *esel, | |||||
| Depsgraph *depsgraph, | Depsgraph *depsgraph, | ||||
| Object *ob, | Object *ob, | ||||
| BMEditMesh *em, | BMEditMesh *em, | ||||
| const eSelectOp sel_op) | const eSelectOp sel_op) | ||||
| { | { | ||||
| BMIter iter, viter; | |||||
| BMFace *efa; | BMFace *efa; | ||||
| BMIter iter; | BMVert *eve; | ||||
| bool changed = false; | bool changed = false; | ||||
| ToolSettings *ts = vc->scene->toolsettings; | |||||
| ScrArea *area = CTX_wm_area(vc->C); | |||||
| bToolRef *tref = area->runtime.tool; | |||||
| const bool circle_select = STREQ(tref->idname, "builtin.select_circle"); | |||||
| const BLI_bitmap *select_bitmap = esel->select_bitmap; | const BLI_bitmap *select_bitmap = esel->select_bitmap; | ||||
| uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_FACE); | uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_FACE); | ||||
| if (index == 0) { | uint vindex = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX); | ||||
| if (index == 0 || vindex == 0) { | |||||
| return false; | return false; | ||||
| } | } | ||||
| index -= 1; | index -= 1; | ||||
| vindex -= 1; | |||||
| BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { | ||||
| if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { | if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { | ||||
| const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); | const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); | ||||
| const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); | const bool face_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); | ||||
| const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); | |||||
| bool verts_inside = true; | |||||
| if (face_inside && ts->fully_enclosed_faces && !circle_select) { | |||||
| BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { | |||||
| if (!BLI_BITMAP_TEST_BOOL(select_bitmap, vindex + BM_elem_index_get(eve))) { | |||||
| verts_inside = false; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| const int sel_op_result = ED_select_op_action_deselected( | |||||
| sel_op, is_select, face_inside && verts_inside); | |||||
| if (sel_op_result != -1) { | if (sel_op_result != -1) { | ||||
| BM_face_select_set(em->bm, efa, sel_op_result); | BM_face_select_set(em->bm, efa, sel_op_result); | ||||
| changed = true; | changed = true; | ||||
| Context not available. | |||||
| if (BLI_rctf_isect_segment(data->rect_fl, screen_co_a, screen_co_b) && | if (BLI_rctf_isect_segment(data->rect_fl, screen_co_a, screen_co_b) && | ||||
| BLI_lasso_is_edge_inside( | BLI_lasso_is_edge_inside( | ||||
| data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { | data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX, false)) { | ||||
| pchan->bone->flag |= BONE_DONE; | pchan->bone->flag |= BONE_DONE; | ||||
| data->is_changed = true; | data->is_changed = true; | ||||
| } | } | ||||
| Context not available. | |||||
| V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT); | V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT); | ||||
| } | } | ||||
| static bool do_lasso_select_objects(ViewContext *vc, | static bool do_lasso_select_objects(bContext *C, | ||||
| ViewContext *vc, | |||||
| const int mcoords[][2], | const int mcoords[][2], | ||||
| const int mcoords_len, | const int mcoords_len, | ||||
| const eSelectOp sel_op) | const eSelectOp sel_op) | ||||
| { | { | ||||
| View3D *v3d = vc->v3d; | View3D *v3d = vc->v3d; | ||||
| Base *base; | Base *base; | ||||
| ToolSettings *ts = vc->scene->toolsettings; | |||||
| const bool xray_reset = vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_AUTOMATIC && | |||||
| ts->lasso_auto_xray && ts->auto_xray_reset; | |||||
| bool changed = false; | bool changed = false; | ||||
| if (SEL_OP_USE_PRE_DESELECT(sel_op)) { | if (SEL_OP_USE_PRE_DESELECT(sel_op)) { | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| if (xray_reset) { | |||||
| wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_toggle_xray", true); | |||||
| BLI_assert(ot); | |||||
| PointerRNA ptr; | |||||
| WM_operator_properties_create_ptr(&ptr, ot); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| WM_operator_properties_free(&ptr); | |||||
| } | |||||
| if (changed) { | if (changed) { | ||||
| DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); | DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); | ||||
| WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene); | WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene); | ||||
| Context not available. | |||||
| data->mcoords_len, | data->mcoords_len, | ||||
| UNPACK2(screen_co_a), | UNPACK2(screen_co_a), | ||||
| UNPACK2(screen_co_b), | UNPACK2(screen_co_b), | ||||
| IS_CLIPPED)); | IS_CLIPPED, false)); | ||||
| const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); | const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); | ||||
| if (sel_op_result != -1) { | if (sel_op_result != -1) { | ||||
| BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); | BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| static void do_lasso_select_mesh__doSelectFace(void *userData, | static void do_lasso_select_mesh__doSelectFaceCenter(void *userData, | ||||
| BMFace *efa, | BMFace *efa, | ||||
| const float screen_co[2], | const float screen_co[2], | ||||
| int UNUSED(index)) | int UNUSED(index)) | ||||
| { | { | ||||
| LassoSelectUserData *data = userData; | LassoSelectUserData *data = userData; | ||||
| const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); | const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| static void do_lasso_select_mesh__doSelectFace(void *user_data, | |||||
| BMFace *efa, | |||||
| const float screen_co[][2], | |||||
| int total_count, | |||||
| rctf *screen_rect, | |||||
| bool *face_hit) | |||||
| { | |||||
| LassoSelectUserData *data = user_data; | |||||
| if (!BLI_rctf_isect(data->rect_fl, screen_rect, NULL)) | |||||
| return; | |||||
| bool inside = false; | |||||
| const bool enclose = data->vc->scene->toolsettings->fully_enclosed_faces; | |||||
| for (int i = 0; i < total_count; i++) { | |||||
| int a = i; | |||||
| int b = (i + 1) % total_count; | |||||
| if (enclose) { | |||||
| inside = BLI_lasso_is_edge_inside(data->mcoords, | |||||
| data->mcoords_len, | |||||
| UNPACK2(screen_co[a]), | |||||
| UNPACK2(screen_co[b]), | |||||
| IS_CLIPPED, | |||||
| true); | |||||
| if (!inside) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else { | |||||
| inside = BLI_lasso_is_edge_inside(data->mcoords, | |||||
| data->mcoords_len, | |||||
| UNPACK2(screen_co[a]), | |||||
| UNPACK2(screen_co[b]), | |||||
| IS_CLIPPED, | |||||
| false); | |||||
| if (inside) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (!enclose) { | |||||
| /* Single point check should be suffienct as we only care if the lasso is inside of the | |||||
| poly. */ | |||||
| if (!inside) { | |||||
| float point[2] = {data->mcoords[0][0], data->mcoords[0][1]}; | |||||
| inside = isect_point_poly_v2(point, screen_co, total_count, true); | |||||
| } | |||||
| } | |||||
| *face_hit = inside; | |||||
| const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); | |||||
| const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside); | |||||
| if (sel_op_result != -1) { | |||||
| BM_face_select_set(data->vc->em->bm, efa, sel_op_result); | |||||
| data->is_changed = true; | |||||
| } | |||||
| } | |||||
| static bool do_lasso_select_mesh(ViewContext *vc, | static bool do_lasso_select_mesh(ViewContext *vc, | ||||
| bContext *C, | |||||
| wmGenericUserData *wm_userdata, | wmGenericUserData *wm_userdata, | ||||
| const int mcoords[][2], | const int mcoords[][2], | ||||
| const int mcoords_len, | const int mcoords_len, | ||||
| const eSelectOp sel_op) | const eSelectOp sel_op, | ||||
| wmOperator *op) | |||||
| { | { | ||||
| LassoSelectUserData data; | LassoSelectUserData data; | ||||
| ToolSettings *ts = vc->scene->toolsettings; | ToolSettings *ts = vc->scene->toolsettings; | ||||
| rcti rect; | rcti rect; | ||||
| const bool *mesh_select_through = RNA_boolean_get(op->ptr, "mesh_select_through"); | |||||
| /* set editmesh */ | /* set editmesh */ | ||||
| vc->em = BKE_editmesh_from_object(vc->obedit); | vc->em = BKE_editmesh_from_object(vc->obedit); | ||||
| Context not available. | |||||
| GPU_matrix_set(vc->rv3d->viewmat); | GPU_matrix_set(vc->rv3d->viewmat); | ||||
| const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); | /* when to not select through */ | ||||
| const bool use_zbuf = | |||||
| !(vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_KEYMAP) && | |||||
| !(vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_BUTTON) && | |||||
| !XRAY_FLAG_ENABLED(vc->v3d) || | |||||
| vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_KEYMAP && | |||||
| !mesh_select_through && !XRAY_FLAG_ENABLED(vc->v3d) || | |||||
| vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_BUTTON && | |||||
| !ts->lasso_select_through && !XRAY_FLAG_ENABLED(vc->v3d); | |||||
| /* when to use facedots */ | |||||
| const bool facedot = ts->select_xray_facedots && XRAY_FLAG_ENABLED(vc->v3d) && | |||||
| vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT_XRAY; | |||||
| /* when to reset autoxray */ | |||||
| const bool xray_reset = vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_AUTOMATIC && | |||||
| ts->lasso_auto_xray && ts->auto_xray_reset; | |||||
| struct EditSelectBuf_Cache *esel = wm_userdata->data; | struct EditSelectBuf_Cache *esel = wm_userdata->data; | ||||
| if (use_zbuf) { | if (use_zbuf) { | ||||
| if (wm_userdata->data == NULL) { | if (wm_userdata->data == NULL) { | ||||
| editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); | if (ts->fully_enclosed_faces && ts->selectmode & SCE_SELECT_FACE && | ||||
| !(ts->selectmode & SCE_SELECT_VERTEX)) { | |||||
| editselect_buf_cache_init_with_generic_userdata( | |||||
| wm_userdata, vc, ts->selectmode | SCE_SELECT_VERTEX); | |||||
| } | |||||
| else { | |||||
| editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); | |||||
| } | |||||
| esel = wm_userdata->data; | esel = wm_userdata->data; | ||||
| esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( | esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( | ||||
| vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); | vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); | ||||
| Context not available. | |||||
| .esel = use_zbuf ? esel : NULL, | .esel = use_zbuf ? esel : NULL, | ||||
| .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( | .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( | ||||
| vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) : | vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) : | ||||
| 0, | 0}; | ||||
| }; | |||||
| const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | | const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | | ||||
| (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); | (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); | ||||
| /* Fully inside. */ | /* Fully inside. */ | ||||
| mesh_foreachScreenEdge_clip_bb_segment( | if (!ts->select_all_edges) { | ||||
| vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag); | mesh_foreachScreenEdge_clip_bb_segment( | ||||
| vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag); | |||||
| } | |||||
| if (data.is_done == false) { | if (data.is_done == false) { | ||||
| /* Fall back to partially inside. | /* Fall back to partially inside. | ||||
| * Clip content to account for edges partially behind the view. */ | * Clip content to account for edges partially behind the view. */ | ||||
| Context not available. | |||||
| } | } | ||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| if (use_zbuf) { | if (facedot) { | ||||
| data.is_changed |= edbm_backbuf_check_and_select_faces( | mesh_foreachScreenFaceCenter( | ||||
| esel, vc->depsgraph, vc->obedit, vc->em, sel_op); | vc, do_lasso_select_mesh__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); | ||||
| } | |||||
| else if (!use_zbuf) { | |||||
| if (SEL_OP_USE_OUTSIDE(sel_op)) { | |||||
| /* wonky intersect selection fallback, has some issues if also in vert but better than | |||||
| * nothing */ | |||||
| const bool multi_select_mode = ts->selectmode & SCE_SELECT_EDGE; | |||||
| editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_EDGE); | |||||
| esel = wm_userdata->data; | |||||
| esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( | |||||
| vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); | |||||
| struct LassoSelectUserData_ForMeshEdge data_for_edge = { | |||||
| .data = &data, | |||||
| .esel = use_zbuf ? esel : NULL, | |||||
| .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( | |||||
| vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) : | |||||
| 0}; | |||||
| const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | | |||||
| (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); | |||||
| /* Fully inside. */ | |||||
| mesh_foreachScreenEdge_clip_bb_segment( | |||||
| vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag); | |||||
| /* If in face select only, need to enable/disable edge select and then re-enable face */ | |||||
| if (!multi_select_mode) { | |||||
| wmOperatorType *ot = WM_operatortype_find("MESH_OT_select_mode", true); | |||||
| BLI_assert(ot); | |||||
| PointerRNA ptr; | |||||
| WM_operator_properties_create_ptr(&ptr, ot); | |||||
| RNA_enum_set_identifier(C, &ptr, "type", "EDGE"); | |||||
| RNA_enum_set_identifier(C, &ptr, "action", "ENABLE"); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| RNA_enum_set_identifier(C, &ptr, "action", "DISABLE"); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| RNA_enum_set_identifier(C, &ptr, "action", "ENABLE"); | |||||
| RNA_enum_set_identifier(C, &ptr, "type", "FACE"); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| WM_operator_properties_free(&ptr); | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* works good except intersect selection */ | |||||
| mesh_foreachScreenFaceVerts(vc, | |||||
| do_lasso_select_mesh__doSelectFace, | |||||
| &data, | |||||
| V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); | |||||
| } | |||||
| } | } | ||||
| else { | else { | ||||
| mesh_foreachScreenFace( | data.is_changed |= edbm_backbuf_check_and_select_faces( | ||||
| vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); | vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op); | ||||
| } | } | ||||
| } | } | ||||
| if (xray_reset) { | |||||
| wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_toggle_xray", true); | |||||
| BLI_assert(ot); | |||||
| PointerRNA ptr; | |||||
| WM_operator_properties_create_ptr(&ptr, ot); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| WM_operator_properties_free(&ptr); | |||||
| } | |||||
| if (data.is_changed) { | if (data.is_changed) { | ||||
| EDBM_selectmode_flush(vc->em); | EDBM_selectmode_flush(vc->em); | ||||
| } | } | ||||
| Context not available. | |||||
| data->mcoords_len, | data->mcoords_len, | ||||
| UNPACK2(screen_co_a), | UNPACK2(screen_co_a), | ||||
| UNPACK2(screen_co_b), | UNPACK2(screen_co_b), | ||||
| INT_MAX)) { | INT_MAX, | ||||
| false)) { | |||||
| is_inside_flag |= BONESEL_BONE; | is_inside_flag |= BONESEL_BONE; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| if (BLI_lasso_is_edge_inside( | if (BLI_lasso_is_edge_inside( | ||||
| data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { | data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX, false)) { | ||||
| is_inside_flag |= BONESEL_BONE; | is_inside_flag |= BONESEL_BONE; | ||||
| } | } | ||||
| Context not available. | |||||
| ViewContext *vc, | ViewContext *vc, | ||||
| const int mcoords[][2], | const int mcoords[][2], | ||||
| const int mcoords_len, | const int mcoords_len, | ||||
| const eSelectOp sel_op) | const eSelectOp sel_op, | ||||
| wmOperator *op) | |||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| bool changed_multi = false; | bool changed_multi = false; | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op); | changed_multi |= do_lasso_select_objects(C, vc, mcoords, mcoords_len, sel_op); | ||||
| if (changed_multi) { | if (changed_multi) { | ||||
| ED_outliner_select_sync_from_object_tag(C); | ED_outliner_select_sync_from_object_tag(C); | ||||
| } | } | ||||
| Context not available. | |||||
| switch (vc->obedit->type) { | switch (vc->obedit->type) { | ||||
| case OB_MESH: | case OB_MESH: | ||||
| changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op); | changed = do_lasso_select_mesh(vc, C, wm_userdata, mcoords, mcoords_len, sel_op, op); | ||||
| break; | break; | ||||
| case OB_CURVE: | case OB_CURVE: | ||||
| case OB_SURF: | case OB_SURF: | ||||
| Context not available. | |||||
| ED_view3d_viewcontext_init(C, &vc, depsgraph); | ED_view3d_viewcontext_init(C, &vc, depsgraph); | ||||
| eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); | eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); | ||||
| bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op); | bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op, op); | ||||
| MEM_freeN((void *)mcoords); | MEM_freeN((void *)mcoords); | ||||
| Context not available. | |||||
| } | } | ||||
| static void do_mesh_box_select__doSelectFace(void *userData, | static void do_mesh_box_select__doSelectFace(void *userData, | ||||
| BMFace *efa, | BMFace *efa, | ||||
| const float screen_co[2], | const float screen_co[][2], | ||||
| int UNUSED(index)) | int total_count, | ||||
| rctf *screen_rect, | |||||
| bool *face_hit) | |||||
| { | |||||
| BoxSelectUserData *data = userData; | |||||
| if (!BLI_rctf_isect(data->rect_fl, screen_rect, NULL)) | |||||
| return; | |||||
| bool inside = false; | |||||
| const bool enclose = data->vc->scene->toolsettings->fully_enclosed_faces; | |||||
| for (int i = 0; i < total_count; i++) { | |||||
| int a = i; | |||||
| int b = (i + 1) % total_count; | |||||
| if (enclose) { | |||||
| inside = edge_fully_inside_rect(data->rect_fl, screen_co[a], screen_co[b]); | |||||
| if (!inside) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else { | |||||
| inside = edge_inside_rect(data->rect_fl, screen_co[a], screen_co[b]); | |||||
| if (inside) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (!enclose) { | |||||
| /* Single point check should be suffienct as we only care if the box rect is inside of the | |||||
| polygon.*/ | |||||
| if (!inside) { | |||||
| float point[2] = {data->rect_fl->xmax, data->rect_fl->ymax}; | |||||
| inside = isect_point_poly_v2(point, screen_co, total_count, true); | |||||
| } | |||||
| } | |||||
| *face_hit = inside; | |||||
| const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); | |||||
| const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside); | |||||
| if (sel_op_result != -1) { | |||||
| BM_face_select_set(data->vc->em->bm, efa, sel_op_result); | |||||
| data->is_changed = true; | |||||
| } | |||||
| } | |||||
| static void do_mesh_box_select__doSelectFaceCenter(void *userData, | |||||
| BMFace *efa, | |||||
| const float screen_co[2], | |||||
| int UNUSED(index)) | |||||
| { | { | ||||
| BoxSelectUserData *data = userData; | BoxSelectUserData *data = userData; | ||||
| const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); | const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| static bool do_mesh_box_select(ViewContext *vc, | static bool do_mesh_box_select(ViewContext *vc, | ||||
| bContext *C, | |||||
| wmGenericUserData *wm_userdata, | wmGenericUserData *wm_userdata, | ||||
| const rcti *rect, | const rcti *rect, | ||||
| const eSelectOp sel_op) | const eSelectOp sel_op, | ||||
| wmOperator *op) | |||||
| { | { | ||||
| BoxSelectUserData data; | BoxSelectUserData data; | ||||
| ToolSettings *ts = vc->scene->toolsettings; | ToolSettings *ts = vc->scene->toolsettings; | ||||
| const bool *mesh_select_through = RNA_boolean_get(op->ptr, "mesh_select_through"); | |||||
| view3d_userdata_boxselect_init(&data, vc, rect, sel_op); | view3d_userdata_boxselect_init(&data, vc, rect, sel_op); | ||||
| Context not available. | |||||
| GPU_matrix_set(vc->rv3d->viewmat); | GPU_matrix_set(vc->rv3d->viewmat); | ||||
| const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); | /* when to not select through */ | ||||
| const bool use_zbuf = | |||||
| !(vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_KEYMAP) && | |||||
| !(vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_BUTTON) && | |||||
| !XRAY_FLAG_ENABLED(vc->v3d) || | |||||
| vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_KEYMAP && | |||||
| !mesh_select_through && !XRAY_FLAG_ENABLED(vc->v3d) || | |||||
| vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_BUTTON && | |||||
| !ts->box_select_through && !XRAY_FLAG_ENABLED(vc->v3d); | |||||
| /* when to use facedots */ | |||||
| const bool facedot = ts->select_xray_facedots && XRAY_FLAG_ENABLED(vc->v3d) && | |||||
| vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT_XRAY; | |||||
| /* when to reset autoxray */ | |||||
| const bool xray_reset = vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_AUTOMATIC && | |||||
| ts->box_auto_xray && ts->auto_xray_reset; | |||||
| struct EditSelectBuf_Cache *esel = wm_userdata->data; | struct EditSelectBuf_Cache *esel = wm_userdata->data; | ||||
| if (use_zbuf) { | if (use_zbuf) { | ||||
| if (wm_userdata->data == NULL) { | if (wm_userdata->data == NULL) { | ||||
| editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); | if (ts->fully_enclosed_faces && ts->selectmode & SCE_SELECT_FACE && !(ts->selectmode & SCE_SELECT_VERTEX)) { | ||||
| editselect_buf_cache_init_with_generic_userdata( | |||||
| wm_userdata, vc, ts->selectmode | SCE_SELECT_VERTEX); | |||||
| } | |||||
| else { | |||||
| editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); | |||||
| } | |||||
| esel = wm_userdata->data; | esel = wm_userdata->data; | ||||
| esel->select_bitmap = DRW_select_buffer_bitmap_from_rect( | esel->select_bitmap = DRW_select_buffer_bitmap_from_rect( | ||||
| vc->depsgraph, vc->region, vc->v3d, rect, NULL); | vc->depsgraph, vc->region, vc->v3d, rect, NULL); | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| if (ts->selectmode & SCE_SELECT_EDGE) { | if (ts->selectmode & SCE_SELECT_EDGE) { | ||||
| /* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */ | /* Does both use_zbuf and non-use_zbuf versions (need screen pos for both) */ | ||||
| struct BoxSelectUserData_ForMeshEdge cb_data = { | struct BoxSelectUserData_ForMeshEdge cb_data = { | ||||
| .data = &data, | .data = &data, | ||||
| .esel = use_zbuf ? esel : NULL, | .esel = use_zbuf ? esel : NULL, | ||||
| Context not available. | |||||
| const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | | const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | | ||||
| (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); | (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); | ||||
| /* Fully inside. */ | /* Fully inside. */ | ||||
| mesh_foreachScreenEdge_clip_bb_segment( | if (!ts->select_all_edges) { | ||||
| vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag); | mesh_foreachScreenEdge_clip_bb_segment( | ||||
| vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag); | |||||
| } | |||||
| if (data.is_done == false) { | if (data.is_done == false) { | ||||
| /* Fall back to partially inside. | /* Fall back to partially inside. | ||||
| * Clip content to account for edges partially behind the view. */ | * Clip content to account for edges partially behind the view. */ | ||||
| Context not available. | |||||
| } | } | ||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| if (use_zbuf) { | if (facedot) { | ||||
| data.is_changed |= edbm_backbuf_check_and_select_faces( | mesh_foreachScreenFaceCenter( | ||||
| esel, vc->depsgraph, vc->obedit, vc->em, sel_op); | vc, do_mesh_box_select__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); | ||||
| } | |||||
| else if (!use_zbuf) { | |||||
| if (SEL_OP_USE_OUTSIDE(sel_op)) { | |||||
| /* wonky intersect selection fallback, has some issues if also in vert but better than | |||||
| * nothing */ | |||||
| const bool multi_select_mode = ts->selectmode & SCE_SELECT_EDGE; | |||||
| editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_EDGE); | |||||
| esel = wm_userdata->data; | |||||
| esel->select_bitmap = DRW_select_buffer_bitmap_from_rect( | |||||
| vc->depsgraph, vc->region, vc->v3d, rect, NULL); | |||||
| struct BoxSelectUserData_ForMeshEdge cb_data = { | |||||
| .data = &data, | |||||
| .esel = use_zbuf ? esel : NULL, | |||||
| .backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem( | |||||
| vc->depsgraph, vc->obedit, SCE_SELECT_EDGE) : | |||||
| 0, | |||||
| }; | |||||
| const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | | |||||
| (use_zbuf ? 0 : V3D_PROJ_TEST_CLIP_BB); | |||||
| /* Fully inside. */ | |||||
| mesh_foreachScreenEdge_clip_bb_segment( | |||||
| vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag); | |||||
| /* If in face select only, need to enable/disable edge select and then re-enable face */ | |||||
| if (!multi_select_mode) { | |||||
| wmOperatorType *ot = WM_operatortype_find("MESH_OT_select_mode", true); | |||||
| BLI_assert(ot); | |||||
| PointerRNA ptr; | |||||
| WM_operator_properties_create_ptr(&ptr, ot); | |||||
| RNA_enum_set_identifier(C, &ptr, "type", "EDGE"); | |||||
| RNA_enum_set_identifier(C, &ptr, "action", "ENABLE"); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| RNA_enum_set_identifier(C, &ptr, "action", "DISABLE"); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| RNA_enum_set_identifier(C, &ptr, "action", "ENABLE"); | |||||
| RNA_enum_set_identifier(C, &ptr, "type", "FACE"); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| WM_operator_properties_free(&ptr); | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* works good except intersect selection */ | |||||
| mesh_foreachScreenFaceVerts(vc, | |||||
| do_mesh_box_select__doSelectFace, | |||||
| &data, | |||||
| V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); | |||||
| } | |||||
| } | } | ||||
| else { | else { | ||||
| mesh_foreachScreenFace( | data.is_changed |= edbm_backbuf_check_and_select_faces( | ||||
| vc, do_mesh_box_select__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); | vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op); | ||||
| } | } | ||||
| } | } | ||||
| if (xray_reset) { | |||||
| wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_toggle_xray", true); | |||||
| BLI_assert(ot); | |||||
| PointerRNA ptr; | |||||
| WM_operator_properties_create_ptr(&ptr, ot); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| WM_operator_properties_free(&ptr); | |||||
| } | |||||
| if (data.is_changed) { | if (data.is_changed) { | ||||
| EDBM_selectmode_flush(vc->em); | EDBM_selectmode_flush(vc->em); | ||||
| } | } | ||||
| Context not available. | |||||
| const int hits = view3d_opengl_select( | const int hits = view3d_opengl_select( | ||||
| vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); | vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); | ||||
| ToolSettings *ts = vc->scene->toolsettings; | |||||
| const bool xray_reset = vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_AUTOMATIC && | |||||
| ts->box_auto_xray && ts->auto_xray_reset; | |||||
| LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) { | LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) { | ||||
| base->object->id.tag &= ~LIB_TAG_DOIT; | base->object->id.tag &= ~LIB_TAG_DOIT; | ||||
| } | } | ||||
| Context not available. | |||||
| MEM_freeN(vbuffer); | MEM_freeN(vbuffer); | ||||
| /* turn xray off for autoxray */ | |||||
| if (xray_reset) { | |||||
| wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_toggle_xray", true); | |||||
| BLI_assert(ot); | |||||
| PointerRNA ptr; | |||||
| WM_operator_properties_create_ptr(&ptr, ot); | |||||
| WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); | |||||
| WM_operator_properties_free(&ptr); | |||||
| } | |||||
| if (changed) { | if (changed) { | ||||
| DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); | DEG_id_tag_update(&vc->scene->id, ID_RECALC_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); | ||||
| Context not available. | |||||
| 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); | ||||
| changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op); | changed = do_mesh_box_select(&vc, C, wm_userdata, &rect, sel_op, op); | ||||
| if (changed) { | if (changed) { | ||||
| DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); | DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); | ||||
| WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); | ||||
| Context not available. | |||||
| data->is_changed = true; | data->is_changed = true; | ||||
| } | } | ||||
| } | } | ||||
| static void mesh_circle_doSelectFace(void *userData, | static void mesh_circle_doSelectFace(void *userData, | ||||
| BMFace *efa, | BMFace *efa, | ||||
| const float screen_co[2], | const float screen_co[][2], | ||||
| int UNUSED(index)) | int total_count, | ||||
| rctf *screen_rect, | |||||
| bool *face_hit) | |||||
| { | |||||
| struct CircleSelectUserData *data = userData; | |||||
| if (!BLI_rctf_isect_circle(screen_rect, data->mval_fl, data->radius)) { | |||||
| return; | |||||
| } | |||||
| bool inside = false; | |||||
| for (int i = 0; i < total_count; i++) { | |||||
| int a = i; | |||||
| int b = (i + 1) % total_count; | |||||
| inside = edge_inside_circle(data->mval_fl, data->radius, screen_co[a], screen_co[b]); | |||||
| if (inside) | |||||
| break; | |||||
| } | |||||
| if (!inside) { | |||||
| inside = isect_point_poly_v2(data->mval_fl, screen_co, total_count, true); | |||||
| } | |||||
| *face_hit = inside; | |||||
| if (inside) { | |||||
| BM_face_select_set(data->vc->em->bm, efa, data->select); | |||||
| data->is_changed = true; | |||||
| } | |||||
| } | |||||
| static void mesh_circle_doSelectFaceCenter(void *userData, | |||||
| BMFace *efa, | |||||
| const float screen_co[2], | |||||
| int UNUSED(index)) | |||||
| { | { | ||||
| CircleSelectUserData *data = userData; | CircleSelectUserData *data = userData; | ||||
| Context not available. | |||||
| } | } | ||||
| static bool mesh_circle_select(ViewContext *vc, | static bool mesh_circle_select(ViewContext *vc, | ||||
| bContext *C, | |||||
| wmGenericUserData *wm_userdata, | wmGenericUserData *wm_userdata, | ||||
| eSelectOp sel_op, | eSelectOp sel_op, | ||||
| const int mval[2], | const int mval[2], | ||||
| float rad) | float rad, | ||||
| wmOperator *op) | |||||
| { | { | ||||
| ToolSettings *ts = vc->scene->toolsettings; | ToolSettings *ts = vc->scene->toolsettings; | ||||
| CircleSelectUserData data; | CircleSelectUserData data; | ||||
| vc->em = BKE_editmesh_from_object(vc->obedit); | vc->em = BKE_editmesh_from_object(vc->obedit); | ||||
| const bool *mesh_select_through = RNA_boolean_get(op->ptr, "mesh_select_through"); | |||||
| bool changed = false; | bool changed = false; | ||||
| if (SEL_OP_USE_PRE_DESELECT(sel_op)) { | if (SEL_OP_USE_PRE_DESELECT(sel_op)) { | ||||
| Context not available. | |||||
| view3d_userdata_circleselect_init(&data, vc, select, mval, rad); | view3d_userdata_circleselect_init(&data, vc, select, mval, rad); | ||||
| const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); | /* when to not select through */ | ||||
| const bool use_zbuf = | |||||
| !(vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_KEYMAP) && | |||||
| !(vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_BUTTON) && | |||||
| !XRAY_FLAG_ENABLED(vc->v3d) || | |||||
| vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_KEYMAP && | |||||
| !mesh_select_through && !XRAY_FLAG_ENABLED(vc->v3d) || | |||||
| vc->v3d->shading.xray_mode_type == V3D_SHADING_XRAY_SELECT_THROUGH_BUTTON && | |||||
| !ts->circle_select_through && !XRAY_FLAG_ENABLED(vc->v3d); | |||||
| /* when to use facedots */ | |||||
| const bool facedot = ts->select_xray_facedots && XRAY_FLAG_ENABLED(vc->v3d) && | |||||
| vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT_XRAY; | |||||
| if (use_zbuf) { | if (use_zbuf) { | ||||
| if (wm_userdata->data == NULL) { | if (wm_userdata->data == NULL) { | ||||
| Context not available. | |||||
| } | } | ||||
| if (ts->selectmode & SCE_SELECT_FACE) { | if (ts->selectmode & SCE_SELECT_FACE) { | ||||
| if (use_zbuf) { | if (facedot) { | ||||
| mesh_foreachScreenFaceCenter( | |||||
| vc, mesh_circle_doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); | |||||
| } | |||||
| else if (!use_zbuf) { | |||||
| mesh_foreachScreenFaceVerts( | |||||
| vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); | |||||
| } | |||||
| else { | |||||
| if (esel->select_bitmap != NULL) { | if (esel->select_bitmap != NULL) { | ||||
| changed |= edbm_backbuf_check_and_select_faces( | changed |= edbm_backbuf_check_and_select_faces( | ||||
| esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); | vc, esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); | ||||
| } | } | ||||
| } | } | ||||
| else { | |||||
| mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); | |||||
| } | |||||
| } | } | ||||
| changed |= data.is_changed; | changed |= data.is_changed; | ||||
| Context not available. | |||||
| wmGenericUserData *wm_userdata, | wmGenericUserData *wm_userdata, | ||||
| const eSelectOp sel_op, | const eSelectOp sel_op, | ||||
| const int mval[2], | const int mval[2], | ||||
| float rad) | float rad, | ||||
| wmOperator *op) | |||||
| { | { | ||||
| bool changed = false; | bool changed = false; | ||||
| BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); | BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); | ||||
| switch (vc->obedit->type) { | switch (vc->obedit->type) { | ||||
| case OB_MESH: | case OB_MESH: | ||||
| changed = mesh_circle_select(vc, wm_userdata, sel_op, mval, rad); | changed = mesh_circle_select(vc, C, wm_userdata, sel_op, mval, rad, op); | ||||
| break; | break; | ||||
| case OB_CURVE: | case OB_CURVE: | ||||
| case OB_SURF: | case OB_SURF: | ||||
| Context not available. | |||||
| obedit = vc.obedit; | obedit = vc.obedit; | ||||
| if (obedit) { | if (obedit) { | ||||
| obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, (float)radius); | obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, (float)radius, op); | ||||
| } | } | ||||
| else if (BKE_paint_select_face_test(obact)) { | else if (BKE_paint_select_face_test(obact)) { | ||||
| paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius); | paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius); | ||||
| Context not available. | |||||