Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt.c
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
| Show First 20 Lines • Show All 7,689 Lines • ▼ Show 20 Lines | if (((op->flag & OP_IS_INVOKE) == 0) || (mouse == NULL) || | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| Sculpt *sd = CTX_data_tool_settings(C)->sculpt; | Sculpt *sd = CTX_data_tool_settings(C)->sculpt; | ||||
| ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C)); | ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C)); | ||||
| sculpt_update_cache_invariants(C, sd, ss, op, mouse); | sculpt_update_cache_invariants(C, sd, ss, op, mouse); | ||||
| SCULPT_undo_push_begin(sculpt_tool_name(sd)); | SCULPT_undo_push_begin(C, sculpt_tool_name(sd)); | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| static void sculpt_stroke_update_step(bContext *C, | static void sculpt_stroke_update_step(bContext *C, | ||||
| struct PaintStroke *UNUSED(stroke), | struct PaintStroke *UNUSED(stroke), | ||||
| ▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | if (ss->cache) { | ||||
| if (SCULPT_is_automasking_enabled(sd, ss, brush)) { | if (SCULPT_is_automasking_enabled(sd, ss, brush)) { | ||||
| SCULPT_automasking_cache_free(ss->cache->automasking); | SCULPT_automasking_cache_free(ss->cache->automasking); | ||||
| } | } | ||||
| BKE_pbvh_node_color_buffer_free(ss->pbvh); | BKE_pbvh_node_color_buffer_free(ss->pbvh); | ||||
| SCULPT_cache_free(ss->cache); | SCULPT_cache_free(ss->cache); | ||||
| ss->cache = NULL; | ss->cache = NULL; | ||||
| SCULPT_undo_push_end(); | SCULPT_undo_push_end(C); | ||||
| if (brush->sculpt_tool == SCULPT_TOOL_MASK) { | if (brush->sculpt_tool == SCULPT_TOOL_MASK) { | ||||
| SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); | SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); | ||||
| } | } | ||||
| else { | else { | ||||
| SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); | SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 210 Lines • ▼ Show 20 Lines | static int sculpt_symmetrize_exec(bContext *C, wmOperator *op) | ||||
| switch (BKE_pbvh_type(pbvh)) { | switch (BKE_pbvh_type(pbvh)) { | ||||
| case PBVH_BMESH: | case PBVH_BMESH: | ||||
| /* Dyntopo Symmetrize. */ | /* Dyntopo Symmetrize. */ | ||||
| /* To simplify undo for symmetrize, all BMesh elements are logged | /* To simplify undo for symmetrize, all BMesh elements are logged | ||||
| * as deleted, then after symmetrize operation all BMesh elements | * as deleted, then after symmetrize operation all BMesh elements | ||||
| * are logged as added (as opposed to attempting to store just the | * are logged as added (as opposed to attempting to store just the | ||||
| * parts that symmetrize modifies). */ | * parts that symmetrize modifies). */ | ||||
| SCULPT_undo_push_begin("Dynamic topology symmetrize"); | SCULPT_undo_push_begin(C, "Dynamic topology symmetrize"); | ||||
| SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); | SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); | ||||
| BM_log_before_all_removed(ss->bm, ss->bm_log); | BM_log_before_all_removed(ss->bm, ss->bm_log); | ||||
| BM_mesh_toolflags_set(ss->bm, true); | BM_mesh_toolflags_set(ss->bm, true); | ||||
| /* Symmetrize and re-triangulate. */ | /* Symmetrize and re-triangulate. */ | ||||
| BMO_op_callf(ss->bm, | BMO_op_callf(ss->bm, | ||||
| (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), | (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), | ||||
| "symmetrize input=%avef direction=%i dist=%f", | "symmetrize input=%avef direction=%i dist=%f", | ||||
| sd->symmetrize_direction, | sd->symmetrize_direction, | ||||
| 0.00001f); | 0.00001f); | ||||
| SCULPT_dynamic_topology_triangulate(ss->bm); | SCULPT_dynamic_topology_triangulate(ss->bm); | ||||
| /* Bisect operator flags edges (keep tags clean for edge queue). */ | /* Bisect operator flags edges (keep tags clean for edge queue). */ | ||||
| BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false); | BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false); | ||||
| BM_mesh_toolflags_set(ss->bm, false); | BM_mesh_toolflags_set(ss->bm, false); | ||||
| /* Finish undo. */ | /* Finish undo. */ | ||||
| BM_log_all_added(ss->bm, ss->bm_log); | BM_log_all_added(ss->bm, ss->bm_log); | ||||
| SCULPT_undo_push_end(); | SCULPT_undo_push_end(C); | ||||
| break; | break; | ||||
| case PBVH_FACES: | case PBVH_FACES: | ||||
| /* Mesh Symmetrize. */ | /* Mesh Symmetrize. */ | ||||
| ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize"); | ED_sculpt_undo_geometry_begin(C, ob, "mesh symmetrize"); | ||||
| Mesh *mesh = ob->data; | Mesh *mesh = ob->data; | ||||
| Mesh *mesh_mirror; | Mesh *mesh_mirror; | ||||
| MirrorModifierData mmd = {{0}}; | MirrorModifierData mmd = {{0}}; | ||||
| int axis = 0; | int axis = 0; | ||||
| mmd.flag = 0; | mmd.flag = 0; | ||||
| mmd.tolerance = RNA_float_get(op->ptr, "merge_tolerance"); | mmd.tolerance = RNA_float_get(op->ptr, "merge_tolerance"); | ||||
| switch (sd->symmetrize_direction) { | switch (sd->symmetrize_direction) { | ||||
| case BMO_SYMMETRIZE_NEGATIVE_X: | case BMO_SYMMETRIZE_NEGATIVE_X: | ||||
| Show All 20 Lines | case PBVH_FACES: | ||||
| axis = 2; | axis = 2; | ||||
| mmd.flag |= MOD_MIR_AXIS_Z | MOD_MIR_BISECT_AXIS_Z; | mmd.flag |= MOD_MIR_AXIS_Z | MOD_MIR_BISECT_AXIS_Z; | ||||
| break; | break; | ||||
| } | } | ||||
| mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis(&mmd, NULL, ob, mesh, axis); | mesh_mirror = BKE_mesh_mirror_apply_mirror_on_axis(&mmd, NULL, ob, mesh, axis); | ||||
| if (mesh_mirror) { | if (mesh_mirror) { | ||||
| BKE_mesh_nomain_to_mesh(mesh_mirror, mesh, ob, &CD_MASK_MESH, true); | BKE_mesh_nomain_to_mesh(mesh_mirror, mesh, ob, &CD_MASK_MESH, true); | ||||
| } | } | ||||
| ED_sculpt_undo_geometry_end(ob); | ED_sculpt_undo_geometry_end(C, ob); | ||||
| BKE_mesh_calc_normals(ob->data); | BKE_mesh_calc_normals(ob->data); | ||||
| BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); | BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); | ||||
| break; | break; | ||||
| case PBVH_GRIDS: | case PBVH_GRIDS: | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, | ||||
| int flush_recalc = 0; | int flush_recalc = 0; | ||||
| /* Multires in sculpt mode could have different from object mode subdivision level. */ | /* Multires in sculpt mode could have different from object mode subdivision level. */ | ||||
| flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl; | flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl; | ||||
| /* If object has got active modifiers, its dm could be different in sculpt mode. */ | /* If object has got active modifiers, its dm could be different in sculpt mode. */ | ||||
| flush_recalc |= sculpt_has_active_modifiers(scene, ob); | flush_recalc |= sculpt_has_active_modifiers(scene, ob); | ||||
| return flush_recalc; | return flush_recalc; | ||||
| } | } | ||||
| void ED_object_sculptmode_enter_ex(Main *bmain, | void ED_object_sculptmode_enter_ex(const bContext *C, | ||||
| Main *bmain, | |||||
| Depsgraph *depsgraph, | Depsgraph *depsgraph, | ||||
| Scene *scene, | Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| const bool force_dyntopo, | const bool force_dyntopo, | ||||
| ReportList *reports) | ReportList *reports) | ||||
| { | { | ||||
| const int mode_flag = OB_MODE_SCULPT; | const int mode_flag = OB_MODE_SCULPT; | ||||
| Mesh *me = BKE_mesh_from_object(ob); | Mesh *me = BKE_mesh_from_object(ob); | ||||
| ▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { | ||||
| } | } | ||||
| if ((message_unsupported == NULL) || force_dyntopo) { | if ((message_unsupported == NULL) || force_dyntopo) { | ||||
| /* Needed because we may be entering this mode before the undo system loads. */ | /* Needed because we may be entering this mode before the undo system loads. */ | ||||
| wmWindowManager *wm = bmain->wm.first; | wmWindowManager *wm = bmain->wm.first; | ||||
| bool has_undo = wm->undo_stack != NULL; | bool has_undo = wm->undo_stack != NULL; | ||||
| /* Undo push is needed to prevent memory leak. */ | /* Undo push is needed to prevent memory leak. */ | ||||
| if (has_undo) { | if (has_undo) { | ||||
| SCULPT_undo_push_begin("Dynamic topology enable"); | SCULPT_undo_push_begin(C, "Dynamic topology enable"); | ||||
| } | } | ||||
| SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob); | SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob); | ||||
| if (has_undo) { | if (has_undo) { | ||||
| SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); | SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); | ||||
| SCULPT_undo_push_end(); | SCULPT_undo_push_end(C); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| BKE_reportf( | BKE_reportf( | ||||
| reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported); | reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported); | ||||
| me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; | me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; | ||||
| } | } | ||||
| } | } | ||||
| /* Flush object mode. */ | /* Flush object mode. */ | ||||
| DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); | ||||
| } | } | ||||
| void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports) | void ED_object_sculptmode_enter(bContext *C, Depsgraph *depsgraph, ReportList *reports) | ||||
| { | { | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| Object *ob = OBACT(view_layer); | Object *ob = OBACT(view_layer); | ||||
| ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports); | ED_object_sculptmode_enter_ex(C, bmain, depsgraph, scene, ob, false, reports); | ||||
| } | } | ||||
| void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) | void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) | ||||
| { | { | ||||
| const int mode_flag = OB_MODE_SCULPT; | const int mode_flag = OB_MODE_SCULPT; | ||||
| Mesh *me = BKE_mesh_from_object(ob); | Mesh *me = BKE_mesh_from_object(ob); | ||||
| multires_flush_sculpt_updates(ob); | multires_flush_sculpt_updates(ob); | ||||
| Show All 9 Lines | #endif | ||||
| if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) { | if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) { | ||||
| DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); | DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); | ||||
| } | } | ||||
| if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { | if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { | ||||
| /* Dynamic topology must be disabled before exiting sculpt | /* Dynamic topology must be disabled before exiting sculpt | ||||
| * mode to ensure the undo stack stays in a consistent | * mode to ensure the undo stack stays in a consistent | ||||
| * state. */ | * state. */ | ||||
| sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob); | sculpt_dynamic_topology_disable_with_undo(NULL, bmain, depsgraph, scene, ob); | ||||
| /* Store so we know to re-enable when entering sculpt mode. */ | /* Store so we know to re-enable when entering sculpt mode. */ | ||||
| me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; | me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; | ||||
| } | } | ||||
| /* Leave sculpt mode. */ | /* Leave sculpt mode. */ | ||||
| ob->mode &= ~mode_flag; | ob->mode &= ~mode_flag; | ||||
| Show All 37 Lines | static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) | ||||
| if (is_mode_set) { | if (is_mode_set) { | ||||
| ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); | ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); | ||||
| } | } | ||||
| else { | else { | ||||
| if (depsgraph) { | if (depsgraph) { | ||||
| depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | depsgraph = CTX_data_ensure_evaluated_depsgraph(C); | ||||
| } | } | ||||
| ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports); | ED_object_sculptmode_enter_ex(C, bmain, depsgraph, scene, ob, false, op->reports); | ||||
| BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint); | BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint); | ||||
| if (ob->mode & mode_flag) { | if (ob->mode & mode_flag) { | ||||
| Mesh *me = ob->data; | Mesh *me = ob->data; | ||||
| /* Dyntopo adds its own undo step. */ | /* Dyntopo adds its own undo step. */ | ||||
| if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) { | if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) { | ||||
| /* Without this the memfile undo step is used, | /* Without this the memfile undo step is used, | ||||
| * while it works it causes lag when undoing the first undo step, see T71564. */ | * while it works it causes lag when undoing the first undo step, see T71564. */ | ||||
| wmWindowManager *wm = CTX_wm_manager(C); | wmWindowManager *wm = CTX_wm_manager(C); | ||||
| if (wm->op_undo_depth <= 1) { | if (wm->op_undo_depth <= 1) { | ||||
| SCULPT_undo_push_begin(op->type->name); | SCULPT_undo_push_begin(C, op->type->name); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); | WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); | ||||
| WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); | WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); | ||||
| ▲ Show 20 Lines • Show All 776 Lines • ▼ Show 20 Lines | static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move, | /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move, | ||||
| * so it needs to be updated here. */ | * so it needs to be updated here. */ | ||||
| SculptCursorGeometryInfo sgi; | SculptCursorGeometryInfo sgi; | ||||
| float mouse[2]; | float mouse[2]; | ||||
| mouse[0] = event->mval[0]; | mouse[0] = event->mval[0]; | ||||
| mouse[1] = event->mval[1]; | mouse[1] = event->mval[1]; | ||||
| SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); | SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); | ||||
| SCULPT_undo_push_begin("Mask by color"); | SCULPT_undo_push_begin(C, "Mask by color"); | ||||
| const int active_vertex = SCULPT_active_vertex_get(ss); | const int active_vertex = SCULPT_active_vertex_get(ss); | ||||
| const float threshold = RNA_float_get(op->ptr, "threshold"); | const float threshold = RNA_float_get(op->ptr, "threshold"); | ||||
| const bool invert = RNA_boolean_get(op->ptr, "invert"); | const bool invert = RNA_boolean_get(op->ptr, "invert"); | ||||
| const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask"); | const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask"); | ||||
| if (RNA_boolean_get(op->ptr, "contiguous")) { | if (RNA_boolean_get(op->ptr, "contiguous")) { | ||||
| sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask); | sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask); | ||||
| } | } | ||||
| else { | else { | ||||
| sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask); | sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask); | ||||
| } | } | ||||
| BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); | BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); | ||||
| SCULPT_undo_push_end(); | SCULPT_undo_push_end(C); | ||||
| SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); | SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| static void SCULPT_OT_mask_by_color(wmOperatorType *ot) | static void SCULPT_OT_mask_by_color(wmOperatorType *ot) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 397 Lines • Show Last 20 Lines | |||||