Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_undo.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c634
1 files changed, 575 insertions, 59 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 501a1e53276..df4b43d21a2 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -113,9 +113,11 @@ typedef struct UndoSculpt {
ListBase nodes;
size_t undo_size;
+ BMLog *bm_restore;
} UndoSculpt;
static UndoSculpt *sculpt_undo_get_nodes(void);
+void sculpt_undo_print_nodes(void *active);
static void update_cb(PBVHNode *node, void *rebuild)
{
@@ -133,6 +135,8 @@ struct PartialUpdateData {
char *modified_grids;
};
+static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p);
+
/**
* A version of #update_cb that tests for 'ME_VERT_PBVH_UPDATE'
*/
@@ -170,6 +174,8 @@ static bool test_swap_v3_v3(float a[3], float b[3])
return false;
}
+void pbvh_bmesh_check_nodes(PBVH *pbvh);
+
static bool sculpt_undo_restore_deformed(
const SculptSession *ss, SculptUndoNode *unode, int uindex, int oindex, float coord[3])
{
@@ -187,7 +193,7 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
SculptSession *ss = ob->sculpt;
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
MVert *mvert;
- int *index;
+ SculptVertRef *index;
if (unode->maxvert) {
/* Regular mesh restore. */
@@ -221,18 +227,18 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
if (unode->orig_co) {
if (ss->deform_modifiers_active) {
for (int i = 0; i < unode->totvert; i++) {
- sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
+ sculpt_undo_restore_deformed(ss, unode, i, index[i].i, vertCos[index[i].i]);
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(vertCos[index[i]], unode->orig_co[i]);
+ swap_v3_v3(vertCos[index[i].i], unode->orig_co[i]);
}
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(vertCos[index[i]], unode->co[i]);
+ swap_v3_v3(vertCos[index[i].i], unode->co[i]);
}
}
@@ -249,21 +255,21 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
if (unode->orig_co) {
if (ss->deform_modifiers_active) {
for (int i = 0; i < unode->totvert; i++) {
- sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ sculpt_undo_restore_deformed(ss, unode, i, index[i].i, mvert[index[i].i].co);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ swap_v3_v3(mvert[index[i].i].co, unode->orig_co[i]);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- swap_v3_v3(mvert[index[i]].co, unode->co[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ swap_v3_v3(mvert[index[i].i].co, unode->co[i]);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
@@ -303,7 +309,7 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode)
MVert *mvert = ss->mvert;
for (int i = 0; i < unode->totvert; i++) {
- MVert *v = &mvert[unode->index[i]];
+ MVert *v = &mvert[unode->index[i].i];
if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) {
BLI_BITMAP_FLIP(unode->vert_hidden, i);
v->flag ^= ME_HIDE;
@@ -330,13 +336,13 @@ static bool sculpt_undo_restore_color(bContext *C, SculptUndoNode *unode)
if (unode->maxvert) {
/* regular mesh restore */
- int *index = unode->index;
+ SculptVertRef *index = unode->index;
MVert *mvert = ss->mvert;
MPropCol *vcol = ss->vcol;
for (int i = 0; i < unode->totvert; i++) {
- copy_v4_v4(vcol[index[i]].color, unode->col[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ swap_v4_v4(vcol[index[i].i].color, unode->col[i]);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
return true;
@@ -350,7 +356,7 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
MVert *mvert;
float *vmask;
- int *index;
+ SculptVertRef *index;
if (unode->maxvert) {
/* Regular mesh restore. */
@@ -360,9 +366,9 @@ static bool sculpt_undo_restore_mask(bContext *C, SculptUndoNode *unode)
vmask = ss->vmask;
for (int i = 0; i < unode->totvert; i++) {
- if (vmask[index[i]] != unode->mask[i]) {
- SWAP(float, vmask[index[i]], unode->mask[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ if (vmask[index[i].i] != unode->mask[i]) {
+ SWAP(float, vmask[index[i].i], unode->mask[i]);
+ mvert[index[i].i].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
@@ -397,7 +403,7 @@ static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode)
Mesh *me = BKE_object_get_original_mesh(ob);
int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
for (int i = 0; i < me->totpoly; i++) {
- face_sets[i] = unode->face_sets[i];
+ SWAP(int, face_sets[i], unode->face_sets[i]);
}
return false;
}
@@ -410,18 +416,152 @@ static void sculpt_undo_bmesh_restore_generic_task_cb(
BKE_pbvh_node_mark_redraw(nodes[n]);
}
+extern const char dyntopop_node_idx_layer_id[];
+
+typedef struct BmeshUndoData {
+ PBVH *pbvh;
+ BMesh *bm;
+ bool do_full_recalc;
+ bool balance_pbvh;
+ int cd_face_node_offset, cd_vert_node_offset;
+} BmeshUndoData;
+
+static void bmesh_undo_on_vert_kill(BMVert *v, void *userdata)
+{
+ BmeshUndoData *data = (BmeshUndoData *)userdata;
+ // data->do_full_recalc = true;
+
+ if (BM_ELEM_CD_GET_INT(v, data->cd_vert_node_offset) < 0) {
+ // something went wrong
+ printf("pbvh bmesh undo error\n");
+ data->do_full_recalc = true;
+ return;
+ }
+ else {
+ int ni = BM_ELEM_CD_GET_INT(v, data->cd_vert_node_offset);
+
+ /*
+ regenerate bm_unique_verts, which can end up with
+ freed verts for some reason. I've run this through
+ ASAN and fixed one likely cause, but it still happens.
+ - joeedh
+ */
+ if (ni >= 0) {
+ PBVHNode *node = BKE_pbvh_get_node(data->pbvh, ni);
+ BKE_pbvh_bmesh_mark_node_regen(data->pbvh, node);
+ }
+ }
+
+ BKE_pbvh_bmesh_remove_vertex(data->pbvh, v, false);
+ data->balance_pbvh = true;
+}
+static void bmesh_undo_on_vert_add(BMVert *v, void *userdata)
+{
+ BmeshUndoData *data = (BmeshUndoData *)userdata;
+
+ BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1);
+ // data->do_full_recalc = true;
+ data->balance_pbvh = true;
+}
+static void bmesh_undo_on_face_kill(BMFace *f, void *userdata)
+{
+ BmeshUndoData *data = (BmeshUndoData *)userdata;
+ int ni = BM_ELEM_CD_GET_INT(f, data->cd_face_node_offset);
+
+ /*
+ regenerate bm_unique_verts, which can end up with
+ freed verts for some reason. I've run this through
+ ASAN and fixed one likely cause, but it still happens.
+ - joeedh
+ */
+ if (ni >= 0) {
+ PBVHNode *node = BKE_pbvh_get_node(data->pbvh, ni);
+ BKE_pbvh_bmesh_mark_node_regen(data->pbvh, node);
+ }
+
+ BKE_pbvh_bmesh_remove_face(data->pbvh, f, false);
+
+ // data->do_full_recalc = true;
+ data->balance_pbvh = true;
+}
+static void bmesh_undo_on_face_add(BMFace *f, void *userdata)
+{
+ BmeshUndoData *data = (BmeshUndoData *)userdata;
+ // data->do_full_recalc = true;
+
+ BM_ELEM_CD_SET_INT(f, data->cd_face_node_offset, -1);
+ BKE_pbvh_bmesh_add_face(data->pbvh, f, false, true);
+
+ data->balance_pbvh = true;
+}
+static void bmesh_undo_full_mesh(void *userdata)
+{
+ BmeshUndoData *data = (BmeshUndoData *)userdata;
+ data->do_full_recalc = true;
+}
+
+static void bmesh_undo_on_vert_change(BMVert *v, void *userdata, void *old_customdata)
+{
+ BmeshUndoData *data = (BmeshUndoData *)userdata;
+
+ if (!old_customdata) {
+ BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1);
+ return;
+ }
+
+ BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1);
+ return;
+ // preserve pbvh node references
+
+ BMVert h;
+ h.head.data = old_customdata;
+
+ int oldnode_i = BM_ELEM_CD_GET_INT(&h, data->cd_vert_node_offset);
+
+ BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, oldnode_i);
+
+ if (oldnode_i >= 0) {
+ PBVHNode *node = BKE_pbvh_node_from_index(data->pbvh, oldnode_i);
+ BKE_pbvh_node_mark_update(node);
+ }
+}
+
+static void bmesh_undo_on_face_change(BMFace *f, void *userdata, void *old_customdata)
+{
+ BmeshUndoData *data = (BmeshUndoData *)userdata;
+
+ // vert will be added back to pbvh when its owning faces are
+ BM_ELEM_CD_SET_INT(f, data->cd_face_node_offset, -1);
+}
+
static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob, SculptSession *ss)
{
+ BmeshUndoData data = {
+ ss->pbvh, ss->bm, false, false, ss->cd_face_node_offset, ss->cd_vert_node_offset};
+
+ BMLogCallbacks callbacks = {bmesh_undo_on_vert_add,
+ bmesh_undo_on_vert_kill,
+ bmesh_undo_on_vert_change,
+ bmesh_undo_on_face_add,
+ bmesh_undo_on_face_kill,
+ bmesh_undo_on_face_change,
+ bmesh_undo_full_mesh,
+ (void *)&data};
+
if (unode->applied) {
- BM_log_undo(ss->bm, ss->bm_log);
+ BM_log_undo(ss->bm, ss->bm_log, &callbacks, dyntopop_node_idx_layer_id);
unode->applied = false;
}
else {
- BM_log_redo(ss->bm, ss->bm_log);
+ BM_log_redo(ss->bm, ss->bm_log, &callbacks, dyntopop_node_idx_layer_id);
unode->applied = true;
}
- if (unode->type == SCULPT_UNDO_MASK) {
+ BKE_pbvh_bmesh_regen_node_verts(ss->pbvh);
+ pbvh_bmesh_check_nodes(ss->pbvh);
+
+ if (!data.do_full_recalc || unode->type == SCULPT_UNDO_MASK ||
+ unode->type == SCULPT_UNDO_COLOR) {
int totnode;
PBVHNode **nodes;
@@ -435,6 +575,12 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob,
if (nodes) {
MEM_freeN(nodes);
}
+
+ SCULPT_dyntopo_node_layers_update_offsets(ss);
+
+ if (data.balance_pbvh) {
+ BKE_pbvh_bmesh_after_stroke(ss->pbvh);
+ }
}
else {
SCULPT_pbvh_clear(ob);
@@ -448,18 +594,27 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
Mesh *me = ob->data;
SCULPT_pbvh_clear(ob);
+ ss->active_face_index.i = ss->active_vertex_index.i = 0;
/* Create empty BMesh and enable logging. */
ss->bm = BM_mesh_create(&bm_mesh_allocsize_default,
- &((struct BMeshCreateParams){
- .use_toolflags = false,
- }));
- BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+ &((struct BMeshCreateParams){.use_toolflags = false,
+ .use_unique_ids = true,
+ .use_id_elem_mask = BM_VERT | BM_FACE,
+ .use_id_map = true}));
SCULPT_dyntopo_node_layers_add(ss);
+
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
- /* Restore the BMLog using saved entries. */
- ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry);
+ ss->bm_log = BM_log_unfreeze(ss->bm, unode->bm_entry);
+
+ if (!ss->bm_log) {
+ /* Restore the BMLog using saved entries. */
+ ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry);
+ }
+
+ SCULPT_dyntopo_node_layers_update_offsets(ss);
+ BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
}
static void sculpt_undo_bmesh_restore_begin(bContext *C,
@@ -475,7 +630,7 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C,
sculpt_undo_bmesh_enable(ob, unode);
/* Restore the mesh from the first log entry. */
- BM_log_redo(ss->bm, ss->bm_log);
+ BM_log_redo(ss->bm, ss->bm_log, NULL, dyntopop_node_idx_layer_id);
unode->applied = true;
}
@@ -486,11 +641,12 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
Object *ob,
SculptSession *ss)
{
+
if (unode->applied) {
sculpt_undo_bmesh_enable(ob, unode);
/* Restore the mesh from the last log entry. */
- BM_log_undo(ss->bm, ss->bm_log);
+ BM_log_undo(ss->bm, ss->bm_log, NULL, dyntopop_node_idx_layer_id);
unode->applied = false;
}
@@ -499,6 +655,10 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
SCULPT_dynamic_topology_disable(C, NULL);
unode->applied = true;
}
+
+ if (ss->bm) {
+ BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
+ }
}
static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Object *object)
@@ -590,23 +750,91 @@ static int sculpt_undo_bmesh_restore(bContext *C,
Object *ob,
SculptSession *ss)
{
+ if (ss->bm_log && ss->bm &&
+ !ELEM(unode->type, SCULPT_UNDO_DYNTOPO_BEGIN, SCULPT_UNDO_DYNTOPO_END)) {
+ SCULPT_dyntopo_node_layers_update_offsets(ss);
+ BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
+
+ if (ss->active_face_index.i && ss->active_face_index.i != -1LL) {
+ ss->active_face_index.i = (intptr_t)BM_log_face_id_get(ss->bm_log,
+ (BMFace *)ss->active_face_index.i);
+ }
+ else {
+ ss->active_face_index.i = -1;
+ }
+
+ if (ss->active_vertex_index.i && ss->active_vertex_index.i != -1LL) {
+ ss->active_vertex_index.i = (intptr_t)BM_log_vert_id_get(
+ ss->bm_log, (BMVert *)ss->active_vertex_index.i);
+ }
+ else {
+ ss->active_vertex_index.i = -1;
+ }
+ }
+ else {
+ ss->active_face_index.i = ss->active_vertex_index.i = -1;
+ }
+
+ bool ret = false;
+
switch (unode->type) {
case SCULPT_UNDO_DYNTOPO_BEGIN:
sculpt_undo_bmesh_restore_begin(C, unode, ob, ss);
- return true;
-
+ SCULPT_vertex_random_access_ensure(ss);
+ ss->active_face_index.i = ss->active_vertex_index.i = 0;
+ ret = true;
+ break;
case SCULPT_UNDO_DYNTOPO_END:
- sculpt_undo_bmesh_restore_end(C, unode, ob, ss);
- return true;
+ ss->active_face_index.i = ss->active_vertex_index.i = 0;
+
+ if (ss->bm) {
+ sculpt_undo_bmesh_restore_end(C, unode, ob, ss);
+ }
+ SCULPT_vertex_random_access_ensure(ss);
+ ret = true;
+ break;
default:
if (ss->bm_log) {
sculpt_undo_bmesh_restore_generic(unode, ob, ss);
- return true;
+ SCULPT_vertex_random_access_ensure(ss);
+ ret = true;
}
break;
}
- return false;
+ if (ss->bm_log && ss->bm) {
+ if (ss->active_face_index.i != -1) {
+ BMFace *f = BM_log_id_face_get(ss->bm_log, (uint)ss->active_face_index.i);
+ if (f && f->head.htype == BM_FACE) {
+ ss->active_face_index.i = (intptr_t)f;
+ }
+ else {
+ ss->active_face_index.i = 0LL;
+ }
+ }
+ else {
+ ss->active_face_index.i = 0LL;
+ }
+
+ if (ss->active_vertex_index.i != -1) {
+ BMVert *v = BM_log_id_vert_get(ss->bm_log, (uint)ss->active_vertex_index.i);
+
+ if (v && v->head.htype == BM_VERT) {
+ ss->active_vertex_index.i = (intptr_t)v;
+ }
+ else {
+ ss->active_vertex_index.i = 0LL;
+ }
+ }
+ else {
+ ss->active_vertex_index.i = 0LL;
+ }
+ }
+ else {
+ ss->active_face_index.i = ss->active_vertex_index.i = 0;
+ }
+
+ return ret;
}
/* Geometry updates (such as Apply Base, for example) will re-evaluate the object and refine its
@@ -647,8 +875,36 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
bool update = false, rebuild = false, update_mask = false, update_visibility = false;
bool need_mask = false;
bool need_refine_subdiv = false;
+ bool did_first_hack = false;
for (unode = lb->first; unode; unode = unode->next) {
+ if (unode->bm_entry && !ss->bm) {
+ // file loading breaks undo because the stack isn't initialized
+ // detect that case and try to fix it
+
+ did_first_hack = true;
+
+ ss->active_face_index.i = ss->active_vertex_index.i = 0;
+ SCULPT_dynamic_topology_enable_ex(CTX_data_main(C), depsgraph, scene, ob);
+
+ // see if we have a saved log in the entry
+ BMLog *log = BM_log_unfreeze(ss->bm, unode->bm_entry);
+
+ if (log) {
+ if (ss->bm_log) {
+ BM_log_free(ss->bm_log, false);
+ }
+
+ ss->bm_log = log;
+
+ SCULPT_dyntopo_node_layers_update_offsets(ss);
+ BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
+ }
+
+ // PBVH is corrupted at this point, destroy it
+ SCULPT_pbvh_clear(ob);
+ }
+
/* Restore pivot. */
copy_v3_v3(ss->pivot_pos, unode->pivot_pos);
copy_v3_v3(ss->pivot_rot, unode->pivot_rot);
@@ -664,7 +920,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
- if (lb->first) {
+ sculpt_undo_print_nodes(NULL);
+
+ if (!ss->bm && lb->first) {
unode = lb->first;
if (unode->type == SCULPT_UNDO_FACE_SETS) {
sculpt_undo_restore_face_sets(C, unode);
@@ -719,6 +977,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
* continue. */
if (unode->maxvert) {
if (ss->totvert != unode->maxvert) {
+ printf("error! %s\n", __func__);
continue;
}
}
@@ -859,6 +1118,9 @@ static void sculpt_undo_free_list(ListBase *lb)
if (unode->co) {
MEM_freeN(unode->co);
}
+ if (unode->nodemap) {
+ MEM_freeN(unode->nodemap);
+ }
if (unode->no) {
MEM_freeN(unode->no);
}
@@ -888,6 +1150,7 @@ static void sculpt_undo_free_list(ListBase *lb)
if (unode->bm_entry) {
BM_log_entry_drop(unode->bm_entry);
+ unode->bm_entry = NULL;
}
sculpt_undo_geometry_free_data(&unode->geometry_original);
@@ -927,7 +1190,28 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
}
#endif
-SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
+static int hash_sculpt_colors(SculptUndoNode *node)
+{
+ if (!node->col) {
+ return -1;
+ }
+
+ int i = 0;
+ int hash = 0;
+
+ for (i = 0; i < node->totvert; i++) {
+ float *col = node->col[i];
+
+ for (int j = 0; j < 4; j++) {
+ hash = hash ^ (int)(col[j] * 2048.0f * 2048.0f);
+ hash += (1 << 23) - 1;
+ }
+ }
+
+ return hash;
+}
+
+SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
@@ -935,7 +1219,19 @@ SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
return NULL;
}
- return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
+ if (type < 0) {
+ return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
+ }
+
+ SculptUndoNode *unode;
+
+ for (unode = usculpt->nodes.first; unode; unode = unode->next) {
+ if (unode->node == node && type == unode->type) {
+ return unode;
+ }
+ }
+
+ return NULL;
}
SculptUndoNode *SCULPT_undo_get_first_node()
@@ -1104,6 +1400,9 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
SculptSession *ss = ob->sculpt;
PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ SCULPT_orig_vert_data_unode_init(&orig_data, ob, unode);
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
copy_v3_v3(unode->co[vd.i], vd.co);
if (vd.no) {
@@ -1114,7 +1413,11 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
}
if (ss->deform_modifiers_active) {
- copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]);
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, unode->index[vd.i]);
+
+ copy_v3_v3(unode->orig_co[vd.i], orig_data.co);
}
}
BKE_pbvh_vertex_iter_end;
@@ -1157,6 +1460,8 @@ static void sculpt_undo_store_color(Object *ob, SculptUndoNode *unode)
SculptSession *ss = ob->sculpt;
PBVHVertexIter vd;
+ // unode->gen++;
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
copy_v4_v4(unode->col[vd.i], vd.col);
}
@@ -1217,7 +1522,10 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
SculptUndoNode *unode = usculpt->nodes.first;
+ bool new_node = false;
+
if (unode == NULL) {
+ new_node = true;
unode = MEM_callocN(sizeof(*unode), __func__);
BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
@@ -1225,8 +1533,10 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
unode->applied = true;
if (type == SCULPT_UNDO_DYNTOPO_END) {
- unode->bm_entry = BM_log_entry_add(ss->bm_log);
- BM_log_before_all_removed(ss->bm, ss->bm_log);
+ unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
+ BM_log_full_mesh(ss->bm, ss->bm_log);
+
+ // BM_log_before_all_removed(ss->bm, ss->bm_log);
}
else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
/* Store a copy of the mesh's current vertices, loops, and
@@ -1237,56 +1547,140 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
SculptUndoNodeGeometry *geometry = &unode->geometry_bmesh_enter;
sculpt_undo_geometry_store_data(geometry, ob);
- unode->bm_entry = BM_log_entry_add(ss->bm_log);
- BM_log_all_added(ss->bm, ss->bm_log);
+ unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
+ // BM_log_all_added(ss->bm, ss->bm_log);
+ BM_log_full_mesh(ss->bm, ss->bm_log);
}
else {
- unode->bm_entry = BM_log_entry_add(ss->bm_log);
+ unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
}
BLI_addtail(&usculpt->nodes, unode);
}
if (node) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ unode->bm_entry = BM_log_entry_check_customdata(ss->bm, ss->bm_log);
+ }
+
switch (type) {
case SCULPT_UNDO_COORDS:
case SCULPT_UNDO_MASK:
- /* Before any vertex values get modified, ensure their
- * original positions are logged. */
- BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
- BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ float *dummy;
+ BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, false);
}
BKE_pbvh_vertex_iter_end;
break;
case SCULPT_UNDO_HIDDEN: {
- GSetIterator gs_iter;
- GSet *faces = BKE_pbvh_bmesh_node_faces(node);
- BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
- BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset);
+ TableGSet *faces = BKE_pbvh_bmesh_node_faces(node);
+ BMFace *f;
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, true);
}
BKE_pbvh_vertex_iter_end;
- GSET_ITER (gs_iter, faces) {
- BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ TGSET_ITER (f, faces) {
BM_log_face_modified(ss->bm_log, f);
}
+ TGSET_ITER_END
+ break;
+ }
+
+ case SCULPT_UNDO_COLOR: {
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
+ float *dummy;
+ BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, true);
+ }
+ BKE_pbvh_vertex_iter_end;
break;
}
+ case SCULPT_UNDO_FACE_SETS: {
+ TableGSet *faces = BKE_pbvh_bmesh_node_faces(node);
+ BMFace *f;
+ TGSET_ITER (f, faces) {
+ BM_log_face_modified(ss->bm_log, f);
+ }
+ TGSET_ITER_END
+
+ break;
+ }
case SCULPT_UNDO_DYNTOPO_BEGIN:
case SCULPT_UNDO_DYNTOPO_END:
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
case SCULPT_UNDO_GEOMETRY:
- case SCULPT_UNDO_FACE_SETS:
- case SCULPT_UNDO_COLOR:
break;
}
}
+ else {
+ switch (type) {
+ case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+ case SCULPT_UNDO_GEOMETRY:
+ BM_log_full_mesh(ss->bm, ss->bm_log);
+ break;
+ }
+ }
+
+ if (new_node) {
+ sculpt_undo_print_nodes(NULL);
+ }
return unode;
}
+bool SCULPT_ensure_dyntopo_node_undo(Object *ob,
+ PBVHNode *node,
+ SculptUndoType type,
+ int extraType)
+{
+ SculptSession *ss = ob->sculpt;
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ SculptUndoNode *unode = usculpt->nodes.first;
+
+ if (!unode || unode->type != type) {
+ unode = sculpt_undo_alloc_node_type(ob, type);
+
+ BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
+
+ unode->type = type;
+ unode->applied = true;
+ unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
+
+ return SCULPT_ensure_dyntopo_node_undo(ob, node, type, extraType);
+ }
+
+ int n = BKE_pbvh_get_node_id(ss->pbvh, node);
+
+ if (unode->nodemap_size <= n) {
+ int newsize = (n + 1) * 2;
+
+ if (!unode->nodemap) {
+ unode->nodemap = MEM_callocN(sizeof(*unode->nodemap) * newsize, "unode->nodemap");
+ }
+ else {
+ unode->nodemap = MEM_recallocN(unode->nodemap, sizeof(*unode->nodemap) * newsize);
+ }
+
+ unode->nodemap_size = newsize;
+ }
+
+ if (unode->nodemap[n]) {
+ return false;
+ }
+
+ unode->nodemap[n] = 1;
+ sculpt_undo_bmesh_push(ob, node, type);
+
+ if (extraType >= 0) {
+ sculpt_undo_bmesh_push(ob, node, extraType);
+ }
+
+ return true;
+}
+
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type)
{
SculptSession *ss = ob->sculpt;
@@ -1301,20 +1695,24 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
/* Dynamic topology stores only one undo node per stroke,
* regardless of the number of PBVH nodes modified. */
unode = sculpt_undo_bmesh_push(ob, node, type);
+ sculpt_undo_print_nodes(NULL);
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
if (type == SCULPT_UNDO_GEOMETRY) {
unode = sculpt_undo_geometry_push(ob, type);
+ sculpt_undo_print_nodes(NULL);
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
if (type == SCULPT_UNDO_FACE_SETS) {
unode = sculpt_undo_face_sets_push(ob, type);
+ sculpt_undo_print_nodes(NULL);
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
- if ((unode = SCULPT_undo_get_node(node))) {
+ if ((unode = SCULPT_undo_get_node(node, type))) {
+ sculpt_undo_print_nodes(NULL);
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
@@ -1336,7 +1734,11 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
int allvert;
BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert);
BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL);
- memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert);
+
+ for (int i = 0; i < unode->totvert; i++) {
+ unode->index[i].i = vert_indices[i];
+ }
+ // memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert);
}
switch (type) {
@@ -1373,6 +1775,8 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
unode->shapeName[0] = '\0';
}
+ sculpt_undo_print_nodes(NULL);
+
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
@@ -1434,6 +1838,7 @@ typedef struct SculptUndoStep {
UndoStep step;
/* NOTE: will split out into list for multi-object-sculpt-mode. */
UndoSculpt data;
+ int id;
} SculptUndoStep;
static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
@@ -1472,6 +1877,8 @@ static void sculpt_undosys_step_decode_undo_impl(struct bContext *C,
BLI_assert(us->step.is_applied == true);
sculpt_undo_restore_list(C, depsgraph, &us->data.nodes);
us->step.is_applied = false;
+
+ sculpt_undo_print_nodes(us);
}
static void sculpt_undosys_step_decode_redo_impl(struct bContext *C,
@@ -1481,6 +1888,8 @@ static void sculpt_undosys_step_decode_redo_impl(struct bContext *C,
BLI_assert(us->step.is_applied == false);
sculpt_undo_restore_list(C, depsgraph, &us->data.nodes);
us->step.is_applied = true;
+
+ sculpt_undo_print_nodes(us);
}
static void sculpt_undosys_step_decode_undo(struct bContext *C,
@@ -1632,6 +2041,10 @@ static UndoSculpt *sculpt_undo_get_nodes(void)
return sculpt_undosys_step_get_nodes(us);
}
+void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss)
+{
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1726,3 +2139,106 @@ void ED_sculpt_undo_push_multires_mesh_end(bContext *C, const char *str)
}
/** \} */
+
+#ifdef _
+# undef _
+#endif
+#define _(type) \
+ case type: \
+ return #type;
+static char *undo_type_to_str(int type)
+{
+ switch (type) {
+ _(SCULPT_UNDO_DYNTOPO_BEGIN)
+ _(SCULPT_UNDO_DYNTOPO_END)
+ _(SCULPT_UNDO_COORDS)
+ _(SCULPT_UNDO_GEOMETRY)
+ _(SCULPT_UNDO_DYNTOPO_SYMMETRIZE)
+ _(SCULPT_UNDO_FACE_SETS)
+ _(SCULPT_UNDO_HIDDEN)
+ _(SCULPT_UNDO_MASK)
+ _(SCULPT_UNDO_COLOR)
+ default:
+ return "unknown node type";
+ }
+}
+#undef _
+
+static int nodeidgen = 1;
+
+static void print_sculpt_node(SculptUndoNode *node)
+{
+ int hash = hash_sculpt_colors(node);
+
+ // if (node->lasthash == 0) {
+ // node->lasthash = hash;
+ // }
+
+ printf(" %s:%s {applied=%d gen=%d hash=%d}\n",
+ undo_type_to_str(node->type),
+ node->idname,
+ node->applied,
+ 0, // node->gen,
+ hash /*- node->lasthash*/);
+}
+
+static void print_sculpt_undo_step(UndoStep *us, UndoStep *active, int i)
+{
+ SculptUndoNode *node;
+
+ if (us->type != BKE_UNDOSYS_TYPE_SCULPT) {
+ return;
+ }
+
+ int id = -1;
+
+ SculptUndoStep *su = (SculptUndoStep *)us;
+ if (!su->id) {
+ su->id = nodeidgen++;
+ }
+
+ id = su->id;
+
+ printf("id=%d %s %d %s\n", id, us == active ? "->" : " ", i, us->name);
+
+ if (us->type == BKE_UNDOSYS_TYPE_SCULPT) {
+ UndoSculpt *usculpt = sculpt_undosys_step_get_nodes(us);
+
+ for (node = usculpt->nodes.first; node; node = node->next) {
+ print_sculpt_node(node);
+ }
+ }
+}
+void sculpt_undo_print_nodes(void *active)
+{
+#if 0
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us = ustack->steps.first;
+ if (active == NULL) {
+ active = ustack->step_active;
+ }
+
+ SculptUndoNode *node;
+
+ if (!us) {
+ return;
+ }
+
+ printf("\n");
+ if (ustack->step_init) {
+ printf("===undo init===\n");
+ print_sculpt_undo_step(ustack->step_init, active, -1);
+ printf("===============\n");
+ }
+
+ int i = 0;
+ for (; us; us = us->next, i++) {
+ print_sculpt_undo_step(us, active, i);
+ }
+
+ if (ustack->step_active) {
+ print_sculpt_undo_step(ustack->step_active, active, i);
+ }
+
+#endif
+}