Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/mesh/editmesh_loopcut.c
| Show First 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | typedef struct RingSelOpData { | ||||
| void *draw_handle; /* for drawing preview loop */ | void *draw_handle; /* for drawing preview loop */ | ||||
| struct EditMesh_PreSelEdgeRing *presel_edgering; | struct EditMesh_PreSelEdgeRing *presel_edgering; | ||||
| ViewContext vc; | ViewContext vc; | ||||
| Depsgraph *depsgraph; | Depsgraph *depsgraph; | ||||
| Object **objects; | Base **bases; | ||||
| uint objects_len; | uint bases_len; | ||||
| /* These values switch objects based on the object under the cursor. */ | /* These values switch objects based on the object under the cursor. */ | ||||
| uint ob_index; | uint base_index; | ||||
| Object *ob; | Object *ob; | ||||
| BMEditMesh *em; | BMEditMesh *em; | ||||
| BMEdge *eed; | BMEdge *eed; | ||||
| NumInput num; | NumInput num; | ||||
| bool extend; | bool extend; | ||||
| bool do_cut; | bool do_cut; | ||||
| Show All 11 Lines | |||||
| static void edgering_select(RingSelOpData *lcd) | static void edgering_select(RingSelOpData *lcd) | ||||
| { | { | ||||
| if (!lcd->eed) { | if (!lcd->eed) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (!lcd->extend) { | if (!lcd->extend) { | ||||
| for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { | for (uint base_index = 0; base_index < lcd->bases_len; base_index++) { | ||||
| Object *ob_iter = lcd->objects[ob_index]; | Object *ob_iter = lcd->bases[base_index]->object; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob_iter); | BMEditMesh *em = BKE_editmesh_from_object(ob_iter); | ||||
| EDBM_flag_disable_all(em, BM_ELEM_SELECT); | EDBM_flag_disable_all(em, BM_ELEM_SELECT); | ||||
| DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); | DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); | ||||
| WM_main_add_notifier(NC_GEOM | ND_SELECT, ob_iter->data); | WM_main_add_notifier(NC_GEOM | ND_SELECT, ob_iter->data); | ||||
| } | } | ||||
| } | } | ||||
| BMEditMesh *em = lcd->em; | BMEditMesh *em = lcd->em; | ||||
| ▲ Show 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| RingSelOpData *lcd = op->customdata; | RingSelOpData *lcd = op->customdata; | ||||
| /* deactivate the extra drawing stuff in 3D-View */ | /* deactivate the extra drawing stuff in 3D-View */ | ||||
| ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle); | ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle); | ||||
| EDBM_preselect_edgering_destroy(lcd->presel_edgering); | EDBM_preselect_edgering_destroy(lcd->presel_edgering); | ||||
| MEM_freeN(lcd->objects); | MEM_freeN(lcd->bases); | ||||
| ED_region_tag_redraw(lcd->ar); | ED_region_tag_redraw(lcd->ar); | ||||
| /* free the custom data */ | /* free the custom data */ | ||||
| MEM_freeN(lcd); | MEM_freeN(lcd); | ||||
| op->customdata = NULL; | op->customdata = NULL; | ||||
| } | } | ||||
| Show All 38 Lines | |||||
| static void ringcut_cancel(bContext *C, wmOperator *op) | static void ringcut_cancel(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| /* this is just a wrapper around exit() */ | /* this is just a wrapper around exit() */ | ||||
| ringsel_exit(C, op); | ringsel_exit(C, op); | ||||
| } | } | ||||
| static void loopcut_update_edge(RingSelOpData *lcd, | static void loopcut_update_edge(RingSelOpData *lcd, | ||||
| uint ob_index, | uint base_index, | ||||
| BMEdge *e, | BMEdge *e, | ||||
| const int previewlines) | const int previewlines) | ||||
| { | { | ||||
| if (e != lcd->eed) { | if (e != lcd->eed) { | ||||
| lcd->eed = e; | lcd->eed = e; | ||||
| lcd->ob = lcd->vc.obedit; | lcd->ob = lcd->vc.obedit; | ||||
| lcd->ob_index = ob_index; | lcd->base_index = base_index; | ||||
| lcd->em = lcd->vc.em; | lcd->em = lcd->vc.em; | ||||
| ringsel_find_edge(lcd, previewlines); | ringsel_find_edge(lcd, previewlines); | ||||
| } | } | ||||
| else if (e == NULL) { | else if (e == NULL) { | ||||
| lcd->ob = NULL; | lcd->ob = NULL; | ||||
| lcd->em = NULL; | lcd->em = NULL; | ||||
| lcd->ob_index = UINT_MAX; | lcd->base_index = UINT_MAX; | ||||
| } | } | ||||
| } | } | ||||
| static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines) | static void loopcut_mouse_move(RingSelOpData *lcd, const int previewlines) | ||||
| { | { | ||||
| struct { | struct { | ||||
| Object *ob; | Object *ob; | ||||
| BMEdge *eed; | BMEdge *eed; | ||||
| float dist; | float dist; | ||||
| int ob_index; | int base_index; | ||||
| } best = { | } best = { | ||||
| .dist = ED_view3d_select_dist_px(), | .dist = ED_view3d_select_dist_px(), | ||||
| }; | }; | ||||
| for (uint ob_index = 0; ob_index < lcd->objects_len; ob_index++) { | uint base_index; | ||||
| Object *ob_iter = lcd->objects[ob_index]; | BMEdge *eed_test = EDBM_edge_find_nearest_ex( | ||||
| ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); | &lcd->vc, &best.dist, NULL, false, false, NULL, lcd->bases, lcd->bases_len, &base_index); | ||||
| BMEdge *eed_test = EDBM_edge_find_nearest_ex(&lcd->vc, &best.dist, NULL, false, false, NULL); | |||||
| if (eed_test) { | if (eed_test) { | ||||
| best.ob = ob_iter; | best.ob = lcd->bases[base_index]->object; | ||||
| best.eed = eed_test; | best.eed = eed_test; | ||||
| best.ob_index = ob_index; | best.base_index = base_index; | ||||
| } | |||||
| } | } | ||||
| if (best.eed) { | if (best.eed) { | ||||
| ED_view3d_viewcontext_init_object(&lcd->vc, best.ob); | ED_view3d_viewcontext_init_object(&lcd->vc, best.ob); | ||||
| } | } | ||||
| loopcut_update_edge(lcd, best.ob_index, best.eed, previewlines); | loopcut_update_edge(lcd, best.base_index, best.eed, previewlines); | ||||
| } | } | ||||
| /* called by both init() and exec() */ | /* called by both init() and exec() */ | ||||
| static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) | static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| const bool is_interactive = (event != NULL); | const bool is_interactive = (event != NULL); | ||||
| /* Use for redo - intentionally wrap int to uint. */ | /* Use for redo - intentionally wrap int to uint. */ | ||||
| const struct { | const struct { | ||||
| uint ob_index; | uint base_index; | ||||
| uint e_index; | uint e_index; | ||||
| } exec_data = { | } exec_data = { | ||||
| .ob_index = (uint)RNA_int_get(op->ptr, "object_index"), | .base_index = (uint)RNA_int_get(op->ptr, "object_index"), | ||||
| .e_index = (uint)RNA_int_get(op->ptr, "edge_index"), | .e_index = (uint)RNA_int_get(op->ptr, "edge_index"), | ||||
| }; | }; | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| uint objects_len; | uint bases_len; | ||||
| Object **objects = BKE_view_layer_array_from_objects_in_edit_mode( | Base **bases = BKE_view_layer_array_from_bases_in_edit_mode( | ||||
| view_layer, CTX_wm_view3d(C), &objects_len); | view_layer, CTX_wm_view3d(C), &bases_len); | ||||
| if (is_interactive) { | if (is_interactive) { | ||||
| for (uint ob_index = 0; ob_index < objects_len; ob_index++) { | for (uint base_index = 0; base_index < bases_len; base_index++) { | ||||
| Object *ob_iter = objects[ob_index]; | Object *ob_iter = bases[base_index]->object; | ||||
| if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) { | if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) { | ||||
| BKE_report( | BKE_report( | ||||
| op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display"); | op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display"); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| view3d_operator_needs_opengl(C); | view3d_operator_needs_opengl(C); | ||||
| /* for re-execution, check edge index is in range before we setup ringsel */ | /* for re-execution, check edge index is in range before we setup ringsel */ | ||||
| bool ok = true; | bool ok = true; | ||||
| if (is_interactive == false) { | if (is_interactive == false) { | ||||
| if (exec_data.ob_index >= objects_len) { | if (exec_data.base_index >= bases_len) { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| ok = false; | ok = false; | ||||
| } | } | ||||
| else { | else { | ||||
| Object *ob_iter = objects[exec_data.ob_index]; | Object *ob_iter = bases[exec_data.base_index]->object; | ||||
| BMEditMesh *em = BKE_editmesh_from_object(ob_iter); | BMEditMesh *em = BKE_editmesh_from_object(ob_iter); | ||||
| if (exec_data.e_index >= em->bm->totedge) { | if (exec_data.e_index >= em->bm->totedge) { | ||||
| ok = false; | ok = false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (!ok || !ringsel_init(C, op, true)) { | if (!ok || !ringsel_init(C, op, true)) { | ||||
| MEM_freeN(objects); | MEM_freeN(bases); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* add a modal handler for this operator - handles loop selection */ | /* add a modal handler for this operator - handles loop selection */ | ||||
| if (is_interactive) { | if (is_interactive) { | ||||
| op->flag |= OP_IS_MODAL_CURSOR_REGION; | op->flag |= OP_IS_MODAL_CURSOR_REGION; | ||||
| WM_event_add_modal_handler(C, op); | WM_event_add_modal_handler(C, op); | ||||
| } | } | ||||
| RingSelOpData *lcd = op->customdata; | RingSelOpData *lcd = op->customdata; | ||||
| lcd->objects = objects; | lcd->bases = bases; | ||||
| lcd->objects_len = objects_len; | lcd->bases_len = bases_len; | ||||
| if (is_interactive) { | if (is_interactive) { | ||||
| copy_v2_v2_int(lcd->vc.mval, event->mval); | copy_v2_v2_int(lcd->vc.mval, event->mval); | ||||
| loopcut_mouse_move(lcd, is_interactive ? 1 : 0); | loopcut_mouse_move(lcd, is_interactive ? 1 : 0); | ||||
| } | } | ||||
| else { | else { | ||||
| Object *ob_iter = objects[exec_data.ob_index]; | Object *ob_iter = bases[exec_data.base_index]->object; | ||||
| ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); | ED_view3d_viewcontext_init_object(&lcd->vc, ob_iter); | ||||
| BMEdge *e; | BMEdge *e; | ||||
| BM_mesh_elem_table_ensure(lcd->vc.em->bm, BM_EDGE); | BM_mesh_elem_table_ensure(lcd->vc.em->bm, BM_EDGE); | ||||
| e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index); | e = BM_edge_at_index(lcd->vc.em->bm, exec_data.e_index); | ||||
| loopcut_update_edge(lcd, exec_data.ob_index, e, 0); | loopcut_update_edge(lcd, exec_data.base_index, e, 0); | ||||
| } | } | ||||
| #ifdef USE_LOOPSLIDE_HACK | #ifdef USE_LOOPSLIDE_HACK | ||||
| /* for use in macro so we can restore, HACK */ | /* for use in macro so we can restore, HACK */ | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ToolSettings *settings = scene->toolsettings; | ToolSettings *settings = scene->toolsettings; | ||||
| const bool mesh_select_mode[3] = { | const bool mesh_select_mode[3] = { | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| /* finish */ | /* finish */ | ||||
| ED_region_tag_redraw(lcd->ar); | ED_region_tag_redraw(lcd->ar); | ||||
| ED_workspace_status_text(C, NULL); | ED_workspace_status_text(C, NULL); | ||||
| if (lcd->eed) { | if (lcd->eed) { | ||||
| /* set for redo */ | /* set for redo */ | ||||
| BM_mesh_elem_index_ensure(lcd->em->bm, BM_EDGE); | BM_mesh_elem_index_ensure(lcd->em->bm, BM_EDGE); | ||||
| RNA_int_set(op->ptr, "object_index", lcd->ob_index); | RNA_int_set(op->ptr, "object_index", lcd->base_index); | ||||
| RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed)); | RNA_int_set(op->ptr, "edge_index", BM_elem_index_get(lcd->eed)); | ||||
| /* execute */ | /* execute */ | ||||
| ringsel_finish(C, op); | ringsel_finish(C, op); | ||||
| ringsel_exit(C, op); | ringsel_exit(C, op); | ||||
| } | } | ||||
| else { | else { | ||||
| ringcut_cancel(C, op); | ringcut_cancel(C, op); | ||||
| ▲ Show 20 Lines • Show All 244 Lines • Show Last 20 Lines | |||||