Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt_undo.c
| Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
| #include "BKE_multires.h" | #include "BKE_multires.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_paint.h" | #include "BKE_paint.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| #include "BKE_subdiv_ccg.h" | #include "BKE_subdiv_ccg.h" | ||||
| #include "BKE_subsurf.h" | #include "BKE_subsurf.h" | ||||
| #include "BKE_undo_system.h" | #include "BKE_undo_system.h" | ||||
| /* XXX: Ideally should be no direct call to such low level things. */ | /* TODO(sergey): Ideally should be no direct call to such low level things. */ | ||||
| #include "BKE_subdiv_eval.h" | #include "BKE_subdiv_eval.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "ED_object.h" | #include "ED_object.h" | ||||
| ▲ Show 20 Lines • Show All 537 Lines • ▼ Show 20 Lines | default: | ||||
| return true; | return true; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Geometry updates (such as Apply Base, for example) will re-evaluate the object and refine its | |||||
| * Subdiv descriptor. Upon undo it is required that mesh, grids, and subdiv all stay consistent | |||||
| * with each other. This means that when geometry coordinate changes the undo should refine the | |||||
| * subdiv to the new coarse mesh coordinates. Tricky part is: this needs to happen without using | |||||
| * dependency graph tag: tagging object for geometry update will either loose sculpted data from | |||||
| * the sculpt grids, or will wrongly "commit" them to the CD_MDISPS. | |||||
| * | |||||
| * So what we do instead is do minimum object evaluation to get base mesh coordinates for the | |||||
| * multires modifier input. While this is expensive, it is less expensive than dependency graph | |||||
| * evaluation and is only happening when geometry coordinates changes on undo. | |||||
| * | |||||
| * Note that the dependency graph is ensured to be evaluated prior to the undo step is decoded, | |||||
| * so if the object's modifier stack references other object it is all fine. */ | |||||
| static void sculpt_undo_refine_subdiv(Depsgraph *depsgraph, | |||||
| SculptSession *ss, | |||||
| Object *object, | |||||
| struct Subdiv *subdiv) | |||||
| { | |||||
| float(*deformed_verts)[3] = BKE_multires_create_deformed_base_mesh_vert_coords( | |||||
| depsgraph, object, ss->multires.modifier, NULL); | |||||
| BKE_subdiv_eval_refine_from_mesh(subdiv, object->data, deformed_verts); | |||||
| MEM_freeN(deformed_verts); | |||||
| } | |||||
| static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase *lb) | static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase *lb) | ||||
| { | { | ||||
| 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); | ||||
| View3D *v3d = CTX_wm_view3d(C); | View3D *v3d = CTX_wm_view3d(C); | ||||
| Object *ob = OBACT(view_layer); | Object *ob = OBACT(view_layer); | ||||
| SculptSession *ss = ob->sculpt; | SculptSession *ss = ob->sculpt; | ||||
| SubdivCCG *subdiv_ccg = ss->subdiv_ccg; | SubdivCCG *subdiv_ccg = ss->subdiv_ccg; | ||||
| SculptUndoNode *unode; | SculptUndoNode *unode; | ||||
| bool update = false, rebuild = false, update_mask = false, update_visibility = false; | bool update = false, rebuild = false, update_mask = false, update_visibility = false; | ||||
| bool need_mask = false; | bool need_mask = false; | ||||
| bool need_refine_subdiv = false; | |||||
| for (unode = lb->first; unode; unode = unode->next) { | for (unode = lb->first; unode; unode = unode->next) { | ||||
| /* Restore pivot. */ | /* Restore pivot. */ | ||||
| copy_v3_v3(ss->pivot_pos, unode->pivot_pos); | copy_v3_v3(ss->pivot_pos, unode->pivot_pos); | ||||
| copy_v3_v3(ss->pivot_rot, unode->pivot_rot); | copy_v3_v3(ss->pivot_rot, unode->pivot_rot); | ||||
| if (STREQ(unode->idname, ob->id.name)) { | if (STREQ(unode->idname, ob->id.name)) { | ||||
| if (unode->type == SCULPT_UNDO_MASK) { | if (unode->type == SCULPT_UNDO_MASK) { | ||||
| /* Is possible that we can't do the mask undo (below) | /* Is possible that we can't do the mask undo (below) | ||||
| ▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | switch (unode->type) { | ||||
| break; | break; | ||||
| case SCULPT_UNDO_COLOR: | case SCULPT_UNDO_COLOR: | ||||
| if (sculpt_undo_restore_color(C, unode)) { | if (sculpt_undo_restore_color(C, unode)) { | ||||
| update = true; | update = true; | ||||
| } | } | ||||
| break; | break; | ||||
| case SCULPT_UNDO_GEOMETRY: | case SCULPT_UNDO_GEOMETRY: | ||||
| need_refine_subdiv = true; | |||||
| sculpt_undo_geometry_restore(unode, ob); | sculpt_undo_geometry_restore(unode, ob); | ||||
| BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask, false); | BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask, false); | ||||
| break; | break; | ||||
| case SCULPT_UNDO_DYNTOPO_BEGIN: | case SCULPT_UNDO_DYNTOPO_BEGIN: | ||||
| case SCULPT_UNDO_DYNTOPO_END: | case SCULPT_UNDO_DYNTOPO_END: | ||||
| case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: | case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: | ||||
| BLI_assert(!"Dynamic topology should've already been handled"); | BLI_assert(!"Dynamic topology should've already been handled"); | ||||
| Show All 15 Lines | for (unode = lb->first; unode; unode = unode->next) { | ||||
| } | } | ||||
| for (int i = 0; i < unode->totgrid; i++) { | for (int i = 0; i < unode->totgrid; i++) { | ||||
| undo_modified_grids[unode->grids[i]] = 1; | undo_modified_grids[unode->grids[i]] = 1; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (subdiv_ccg != NULL) { | if (subdiv_ccg != NULL && need_refine_subdiv) { | ||||
| BKE_subdiv_eval_refine_from_mesh(subdiv_ccg->subdiv, ob->data, NULL); | sculpt_undo_refine_subdiv(depsgraph, ss, ob, subdiv_ccg->subdiv); | ||||
| } | } | ||||
| if (update || rebuild) { | if (update || rebuild) { | ||||
| bool tag_update = false; | bool tag_update = false; | ||||
| /* We update all nodes still, should be more clever, but also | /* We update all nodes still, should be more clever, but also | ||||
| * needs to work correct when exiting/entering sculpt mode and | * needs to work correct when exiting/entering sculpt mode and | ||||
| * the nodes get recreated, though in that case it could do all. */ | * the nodes get recreated, though in that case it could do all. */ | ||||
| struct PartialUpdateData data = { | struct PartialUpdateData data = { | ||||
| ▲ Show 20 Lines • Show All 922 Lines • Show Last 20 Lines | |||||