* Fixed an annoying number of undo bugs

* Original data for bmesh pbvh is no longer handled by the undo code.
  This should eliminate a whole class of subtle and hard to track down
  bugs.
This commit is contained in:
Joseph Eagar 2021-04-07 20:39:16 -07:00
parent 55045ed85a
commit 6f91eaad39
11 changed files with 283 additions and 201 deletions

View File

@ -268,6 +268,12 @@ void CustomData_copy_data_named(const struct CustomData *source,
int dest_index,
int count);
void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count);
void CustomData_bmesh_swap_data(struct CustomData *source,
struct CustomData *dest,
void *src_block,
void **dest_block);
void CustomData_bmesh_copy_data(const struct CustomData *source,
struct CustomData *dest,
void *src_block,

View File

@ -23,11 +23,11 @@
* \ingroup bke
*/
#include "BKE_pbvh.h"
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "DNA_brush_enums.h"
#include "DNA_object_enums.h"
#include "BKE_pbvh.h"
#ifdef __cplusplus
extern "C" {
@ -344,7 +344,7 @@ typedef struct SculptClothSimulation {
struct GHash *node_state_index;
eSculptClothNodeSimState *node_state;
//persistent base customdata layer offsets
// persistent base customdata layer offsets
int cd_pers_co;
int cd_pers_no;
int cd_pers_disp;
@ -624,6 +624,10 @@ typedef struct SculptSession {
*/
char needs_flush_to_id;
char update_boundary_info_bmesh;
// id of current stroke, used to detect
// if vertex original data needs to be updated
int stroke_id;
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);

View File

@ -1533,6 +1533,7 @@ void layerDynTopoVert_interp(
if (i == 0) { // copy flag from first source
mv->flag = mv2->flag;
mv->stroke_id = mv2->stroke_id;
}
if (sub_weights) {
@ -1949,10 +1950,9 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
NULL, // flag singleton layer
1,
N_("DynTopoVert"),
layerDynTopoVert_copy,
NULL,
layerDynTopoVert_interp
}};
layerDynTopoVert_copy,
NULL,
layerDynTopoVert_interp}};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert",
@ -3818,7 +3818,71 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
}
}
void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
__attribute__((optnone)) void CustomData_bmesh_swap_data(CustomData *source,
CustomData *dest,
void *src_block,
void **dest_block)
{
int src_i = 0;
int dest_i = 0;
int dest_i_start = 0;
if (*dest_block == NULL) {
CustomData_bmesh_alloc_block(dest, dest_block);
if (*dest_block) {
memset(*dest_block, 0, dest->totsize);
CustomData_bmesh_set_default(dest, dest_block);
}
}
for (src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
*/
while (dest_i_start < dest->totlayer &&
dest->layers[dest_i_start].type < source->layers[src_i].type) {
dest_i_start++;
}
/* if there are no more dest layers, we're done */
if (dest_i_start >= dest->totlayer) {
return;
}
dest_i = dest_i_start;
while (dest_i < dest->totlayer && dest->layers[dest_i].type == source->layers[src_i].type) {
/* if we found a matching layer, copy the data */
if (dest->layers[dest_i].type == source->layers[src_i].type &&
STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
const uint size = typeInfo->size;
// swap data
char *bsrc = (char *)src_data;
char *bdst = (char *)dest_data;
for (int j = 0; j < size; j++) {
char t = *bsrc;
*bsrc = *bdst;
*bdst = t;
bsrc++;
bdst++;
}
break;
}
dest_i++;
}
}
}
__attribute__ ((optnone)) void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
CustomData *dest,
void *src_block,
void **dest_block,
@ -3835,50 +3899,55 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
}
}
for (int dest_i=0; dest_i < dest->totlayer; dest_i++) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
dest_i++;
}
/* copies a layer at a time */
int dest_i = 0;
int dest_i_start = 0;
for (int src_i = 0; src_i < source->totlayer; src_i++) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
*/
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
dest_i++;
while (dest_i_start < dest->totlayer &&
dest->layers[dest_i_start].type < source->layers[src_i].type) {
dest_i_start++;
}
/* if there are no more dest layers, we're done */
if (dest_i >= dest->totlayer) {
if (dest_i_start >= dest->totlayer) {
return;
}
/* if we found a matching layer, copy the data */
if (dest->layers[dest_i].type == source->layers[src_i].type &&
STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
if (typeInfo->copy) {
typeInfo->copy(src_data, dest_data, 1);
}
else {
memcpy(dest_data, src_data, typeInfo->size);
int dest_i = dest_i_start;
/*Previously this code was only checking one source layer against one destination.
Now it scans all the layers of that type. - joeedh
*/
while (dest_i < dest->totlayer && dest->layers[dest_i].type == source->layers[src_i].type) {
/* if we found a matching layer, copy the data */
if (STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
if (typeInfo->copy) {
typeInfo->copy(src_data, dest_data, 1);
}
else {
memcpy(dest_data, src_data, typeInfo->size);
}
}
break;
}
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
* increment dest_i
*/
dest_i++;
}
}
while (dest_i < dest->totlayer) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
dest_i++;
}
}
void CustomData_bmesh_copy_data(const CustomData *source,

View File

@ -4091,6 +4091,7 @@ void BKE_pbvh_update_offsets(PBVH *pbvh,
pbvh->cd_face_node_offset = cd_face_node_offset;
pbvh->cd_vert_node_offset = cd_vert_node_offset;
pbvh->cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK);
pbvh->cd_vcol_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PROP_COLOR);
pbvh->cd_dyn_vert = cd_dyn_vert;
}

View File

@ -119,9 +119,6 @@ struct BMLog {
*/
BMLogEntry *current_entry;
int cd_origco_offset;
int cd_origno_offset;
int cd_origvcol_offset;
int cd_dyn_vert;
};
@ -260,17 +257,13 @@ static BMFace *bm_log_face_from_id(BMLog *log, uint id)
/************************ BMLogVert / BMLogFace ***********************/
static void bm_log_vert_customdata(BMesh *bm, BMLog *log, BMVert *v, BMLogVert *lv)
__attribute__((optnone)) static void bm_log_vert_customdata(
BMesh *bm, BMLog *log, BMLogEntry *entry, BMVert *v, BMLogVert *lv)
{
#ifdef CUSTOMDATA
// if (!lv) {
// return;
//}
BMLogEntry *entry = log->current_entry;
if (!entry) {
return;
}
if (lv->customdata) {
BLI_mempool_free(entry->vdata.pool, lv->customdata);
@ -336,27 +329,34 @@ static void vert_mask_set(BMVert *v, const float new_mask, const int cd_vert_mas
}
/* Update a BMLogVert with data from a BMVert */
static void bm_log_vert_bmvert_copy(BMLog *log,
BMLogVert *lv,
BMVert *v,
const int cd_vert_mask_offset)
__attribute__((optnone)) static void bm_log_vert_bmvert_copy(BMLog *log,
BMLog *entry,
BMLogVert *lv,
BMVert *v,
const int cd_vert_mask_offset,
bool copy_customdata)
{
copy_v3_v3(lv->co, v->co);
normal_float_to_short_v3(lv->no, v->no);
lv->mask = vert_mask_get(v, cd_vert_mask_offset);
lv->hflag = v->head.hflag;
bm_log_vert_customdata(log->bm, log, v, lv);
if (copy_customdata) {
bm_log_vert_customdata(log->bm, log, entry, v, lv);
}
}
/* Allocate and initialize a BMLogVert */
static BMLogVert *bm_log_vert_alloc(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
static BMLogVert *bm_log_vert_alloc(BMLog *log,
BMVert *v,
const int cd_vert_mask_offset,
bool log_customdata)
{
BMLogEntry *entry = log->current_entry;
BMLogVert *lv = BLI_mempool_alloc(entry->pool_verts);
lv->customdata = NULL;
bm_log_vert_bmvert_copy(log, lv, v, cd_vert_mask_offset);
bm_log_vert_bmvert_copy(log, entry, lv, v, cd_vert_mask_offset, log_customdata);
return lv;
}
@ -384,7 +384,10 @@ static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f)
/************************ Helpers for undo/redo ***********************/
static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts)
__attribute__((optnone)) static void bm_log_verts_unmake(BMesh *bm,
BMLog *log,
GHash *verts,
BMLogEntry *entry)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
@ -397,13 +400,13 @@ static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts)
/* Ensure the log has the final values of the vertex before
* deleting it */
bm_log_vert_bmvert_copy(log, lv, v, cd_vert_mask_offset);
bm_log_vert_bmvert_copy(log, entry, lv, v, cd_vert_mask_offset, true);
BM_vert_kill(bm, v);
}
}
static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry)
{
GHashIterator gh_iter;
GHASH_ITER (gh_iter, faces) {
@ -435,10 +438,12 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
}
}
static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts, BMLogEntry *entry)
__attribute__((optnone)) static void bm_log_verts_restore(BMesh *bm,
BMLog *log,
GHash *verts,
BMLogEntry *entry)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
int cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
GHashIterator gh_iter;
GHASH_ITER (gh_iter, verts) {
@ -455,18 +460,6 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts, BMLogEntry
CustomData_bmesh_copy_data(&entry->vdata, &bm->vdata, lv->customdata, &v->head.data);
}
#endif
if (log->cd_dyn_vert >= 0) {
MDynTopoVert *mv = BM_ELEM_CD_GET_VOID_P(v, log->cd_dyn_vert);
copy_v3_v3(mv->origco, v->co);
copy_v3_v3(mv->origno, v->no);
if (cd_vcol_offset >= 0) {
float *color = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
copy_v4_v4(mv->origcolor, color);
}
}
}
}
@ -504,12 +497,13 @@ static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces, BMLogEntry
}
}
static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts, BMLogEntry *entry)
__attribute__((optnone)) static void bm_log_vert_values_swap(BMesh *bm,
BMLog *log,
GHash *verts,
BMLogEntry *entry)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
int cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
GHashIterator gh_iter;
GHASH_ITER (gh_iter, verts) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
@ -530,7 +524,7 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts, BMLogEn
#ifdef CUSTOMDATA
if (lv->customdata) {
CustomData_bmesh_copy_data(&entry->vdata, &bm->vdata, lv->customdata, &v->head.data);
CustomData_bmesh_swap_data(&entry->vdata, &bm->vdata, lv->customdata, &v->head.data);
}
#endif
}
@ -549,14 +543,14 @@ static void bm_log_face_values_swap(BMLog *log, GHash *faces, BMLogEntry *entry)
#ifdef CUSTOMDATA
if (lf->customdata_f) {
CustomData_bmesh_copy_data(&entry->pdata, &log->bm->pdata, lf->customdata_f, &f->head.data);
CustomData_bmesh_swap_data(&entry->pdata, &log->bm->pdata, lf->customdata_f, &f->head.data);
}
BMLoop *ls[3] = {f->l_first, f->l_first->next, f->l_first->prev};
for (int i = 0; i < 3; i++) {
if (lf->customdata[i]) {
CustomData_bmesh_copy_data(
CustomData_bmesh_swap_data(
&entry->ldata, &log->bm->ldata, lf->customdata[i], &ls[i]->head.data);
}
}
@ -695,15 +689,13 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
/***************************** Public API *****************************/
void BM_log_set_cd_offsets(
BMLog *log, int cd_origco_offset, int cd_origno_offset, int cd_origvol_offset, int cd_dyn_vert)
void BM_log_set_cd_offsets(BMLog *log, int cd_dyn_vert)
{
log->cd_dyn_vert = cd_dyn_vert;
}
/* Allocate, initialize, and assign a new BMLog */
BMLog *BM_log_create(
BMesh *bm, int cd_origco_offset, int cd_origno_offset, int cd_origvcol_offset, int cd_dyn_vert)
BMLog *BM_log_create(BMesh *bm, int cd_dyn_vert)
{
BMLog *log = MEM_callocN(sizeof(*log), __func__);
const uint reserve_num = (uint)(bm->totvert + bm->totface);
@ -714,7 +706,7 @@ BMLog *BM_log_create(
log->id_to_elem = BLI_ghash_new_ex(logkey_hash, logkey_cmp, __func__, reserve_num);
log->elem_to_id = BLI_ghash_ptr_new_ex(__func__, reserve_num);
BM_log_set_cd_offsets(log, cd_origco_offset, cd_origno_offset, cd_origvcol_offset, cd_dyn_vert);
BM_log_set_cd_offsets(log, cd_dyn_vert);
/* Assign IDs to all existing vertices and faces */
bm_log_assign_ids(bm, log);
@ -754,7 +746,7 @@ void BM_log_cleanup_entry(BMLogEntry *entry)
*/
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
{
BMLog *log = BM_log_create(bm, -1, -1, -1, -1);
BMLog *log = BM_log_create(bm, -1);
if (entry->prev) {
log->current_entry = entry;
@ -947,13 +939,14 @@ BMLogEntry *BM_log_entry_add_ex(BMesh *bm, BMLog *log, bool combine_with_last)
entry = bm_log_entry_create();
BLI_addtail(&log->entries, entry);
entry->log = log;
log->current_entry = entry;
#ifdef CUSTOMDATA
if (combine_with_last) {
if (log->current_entry) {
log->current_entry->combined_next = entry;
BLI_remlink(&log->entries, log->current_entry);
}
entry->combined_prev = log->current_entry;
}
@ -968,6 +961,8 @@ BMLogEntry *BM_log_entry_add_ex(BMesh *bm, BMLog *log, bool combine_with_last)
CustomData_bmesh_init_pool(&entry->pdata, 0, BM_FACE);
#endif
log->current_entry = entry;
return entry;
}
@ -1049,39 +1044,67 @@ void BM_log_entry_drop(BMLogEntry *entry)
/* Undo one BMLogEntry
*
* Has no effect if there's nothing left to undo */
void BM_log_undo(BMesh *bm, BMLog *log)
static void bm_log_undo_intern(BMesh *bm, BMLog *log, BMLogEntry *entry)
{
BMLogEntry *entry = log->current_entry;
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
if (entry) {
log->current_entry = entry->prev;
/* Delete added faces and verts */
bm_log_faces_unmake(bm, log, entry->added_faces, entry);
bm_log_verts_unmake(bm, log, entry->added_verts, entry);
/* Delete added faces and verts */
bm_log_faces_unmake(bm, log, entry->added_faces);
bm_log_verts_unmake(bm, log, entry->added_verts);
/* Restore deleted verts and faces */
bm_log_verts_restore(bm, log, entry->deleted_verts, entry);
bm_log_faces_restore(bm, log, entry->deleted_faces, entry);
/* Restore deleted verts and faces */
bm_log_verts_restore(bm, log, entry->deleted_verts, entry);
bm_log_faces_restore(bm, log, entry->deleted_faces, entry);
/* Restore vertex coordinates, mask, and hflag */
bm_log_vert_values_swap(bm, log, entry->modified_verts, entry);
bm_log_face_values_swap(log, entry->modified_faces, entry);
}
/* Restore vertex coordinates, mask, and hflag */
bm_log_vert_values_swap(bm, log, entry->modified_verts, entry);
bm_log_face_values_swap(log, entry->modified_faces, entry);
void BM_log_undo(BMesh *bm, BMLog *log) {
BMLogEntry *entry = log->current_entry;
log->bm = bm;
if (!entry) {
return;
}
BMLogEntry *preventry = entry->prev;
while (entry) {
bm_log_undo_intern(bm, log, entry);
entry = entry->combined_prev;
}
log->current_entry = preventry;
}
/* Redo one BMLogEntry
*
* Has no effect if there's nothing left to redo */
static void bm_log_redo_intern(BMesh *bm, BMLog *log, BMLogEntry *entry)
{
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
/* Re-delete previously deleted faces and verts */
bm_log_faces_unmake(bm, log, entry->deleted_faces, entry);
bm_log_verts_unmake(bm, log, entry->deleted_verts, entry);
/* Restore previously added verts and faces */
bm_log_verts_restore(bm, log, entry->added_verts, entry);
bm_log_faces_restore(bm, log, entry->added_faces, entry);
/* Restore vertex coordinates, mask, and hflag */
bm_log_vert_values_swap(bm, log, entry->modified_verts, entry);
bm_log_face_values_swap(log, entry->modified_faces, entry);
}
void BM_log_redo(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
log->bm = bm;
if (!entry) {
/* Currently at the beginning of the undo stack, move to first entry */
@ -1091,28 +1114,25 @@ void BM_log_redo(BMesh *bm, BMLog *log)
/* Move to next undo entry */
entry = entry->next;
}
else {
if (!entry) {
/* Currently at the end of the undo stack, nothing left to redo */
return;
}
log->current_entry = entry;
BMLogEntry *nextentry = entry;
if (entry) {
/* Re-delete previously deleted faces and verts */
bm_log_faces_unmake(bm, log, entry->deleted_faces);
bm_log_verts_unmake(bm, log, entry->deleted_verts);
/* Restore previously added verts and faces */
bm_log_verts_restore(bm, log, entry->added_verts, entry);
bm_log_faces_restore(bm, log, entry->added_faces, entry);
/* Restore vertex coordinates, mask, and hflag */
bm_log_vert_values_swap(bm, log, entry->modified_verts, entry);
bm_log_face_values_swap(log, entry->modified_faces, entry);
while (entry->combined_prev) {
entry = entry->combined_prev;
}
}
while (entry) {
bm_log_redo_intern(bm, log, entry);
entry = entry->combined_next;
}
log->current_entry = nextentry;
}
/* Log a vertex before it is modified
*
* Before modifying vertex coordinates, masks, or hflags, call this
@ -1149,16 +1169,12 @@ void BM_log_vert_before_modified(BMLog *log,
/* Find or create the BMLogVert entry */
if ((lv = log_ghash_lookup(log, entry->added_verts, key))) {
bm_log_vert_bmvert_copy(log, lv, v, cd_vert_mask_offset);
bm_log_vert_bmvert_copy(log, entry, lv, v, cd_vert_mask_offset, log_customdata);
}
else if (!log_ghash_ensure_p(log, entry->modified_verts, key, &val_p)) {
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset, true);
*val_p = lv;
}
if (lv && log_customdata) {
bm_log_vert_customdata(log->bm, log, v, lv);
}
}
/* Log a new vertex as added to the BMesh
@ -1174,10 +1190,8 @@ void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
void *key = POINTER_FROM_UINT(v_id);
bm_log_vert_id_set(log, v, v_id);
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset, true);
log_ghash_insert(log, log->current_entry->added_verts, key, lv);
// bm_log_vert_customdata(log->bm, log, v, lv);
}
/* Log a face before it is modified
@ -1235,7 +1249,9 @@ void BM_log_face_added(BMLog *log, BMFace *f)
* If there's a move record for the vertex, that's used as the
* vertices original location, then the move record is deleted.
*/
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
__attribute__((optnone)) void BM_log_vert_removed(BMLog *log,
BMVert *v,
const int cd_vert_mask_offset)
{
BMLogEntry *entry = log->current_entry;
uint v_id = bm_log_vert_id_get(log, v);
@ -1251,18 +1267,24 @@ void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
else {
BMLogVert *lv, *lv_mod;
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset, false);
log_ghash_insert(log, entry->deleted_verts, key, lv);
/* If the vertex was modified before deletion, ensure that the
* original vertex values are stored */
if ((lv_mod = log_ghash_lookup(log, entry->modified_verts, key))) {
(*lv) = (*lv_mod);
log_ghash_remove(log, entry->modified_verts, key, NULL, NULL);
}
if (lv->customdata) {
BLI_mempool_free(entry->vdata.pool, lv->customdata);
}
if (lv) {
bm_log_vert_customdata(log->bm, log, v, lv);
(*lv) = (*lv_mod);
lv_mod->customdata = NULL;
log_ghash_remove(log, entry->modified_verts, key, NULL, NULL);
BLI_mempool_free(entry->pool_verts, lv_mod);
}
else {
bm_log_vert_customdata(log->bm, log, entry, v, lv);
}
}
}

View File

@ -29,13 +29,8 @@ typedef struct BMLog BMLog;
typedef struct BMLogEntry BMLogEntry;
/* Allocate and initialize a new BMLog */
BMLog *BM_log_create(
BMesh *bm, int cd_origco_offset, int cd_origno_offset, int cd_origvol_offset, int cd_dyn_vert);
void BM_log_set_cd_offsets(BMLog *log,
int cd_origco_offset,
int cd_origno_offset,
int cd_origvcol_offset,
int cd_dyn_vert);
BMLog *BM_log_create(BMesh *bm, int cd_dyn_vert);
void BM_log_set_cd_offsets(BMLog *log, int cd_dyn_vert);
/* Allocate and initialize a new BMLog using existing BMLogEntries */
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry);

View File

@ -68,6 +68,7 @@ void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob)
struct GPUBatch *geom = DRW_cache_lattice_wire_get(ob, false);
OVERLAY_extra_wire(cb, geom, ob->obmat, color);
}
void OVERLAY_edit_lattice_draw(OVERLAY_Data *vedata)

View File

@ -1677,6 +1677,29 @@ void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
*/
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
{
// check if we need to update original data for current stroke
if (orig_data->bm_log) {
MDynTopoVert *mv = BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert);
if (mv->stroke_id != orig_data->ss->stroke_id) {
mv->stroke_id = orig_data->ss->stroke_id;
copy_v3_v3(mv->origco, iter->bm_vert->co);
copy_v3_v3(mv->origno, iter->bm_vert->no);
const int cd_vcol = iter->cd_vcol_offset;
const int cd_mask = iter->cd_vert_mask_offset;
if (cd_vcol >= 0) {
MPropCol *col = BM_ELEM_CD_GET_VOID_P(iter->bm_vert, cd_vcol);
copy_v4_v4(mv->origcolor, col->color);
}
if (cd_mask >= 0) {
mv->origmask = BM_ELEM_CD_GET_FLOAT(iter->bm_vert, cd_mask);
}
}
}
if (orig_data->datatype == SCULPT_UNDO_COORDS) {
if (orig_data->bm_log) {
orig_data->co = BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert)->origco;
@ -1704,8 +1727,7 @@ void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter
}
else if (orig_data->datatype == SCULPT_UNDO_MASK) {
if (orig_data->bm_log) {
orig_data->mask = BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert)
->origmask; // BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
orig_data->mask = BKE_PBVH_DYNVERT(iter->cd_dyn_vert, iter->bm_vert)->origmask;
}
else {
orig_data->mask = orig_data->vmasks[iter->i];
@ -2439,16 +2461,11 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
if (use_original) {
if (unode->bm_entry) {
float *temp_co;
float *temp_no;
BMVert *v = vd.bm_vert;
MDynTopoVert *mv = BKE_PBVH_DYNVERT(vd.cd_dyn_vert, v);
BKE_pbvh_bmesh_update_origvert(ss->pbvh, vd.bm_vert, &temp_co, &temp_no, NULL);
if (temp_no) {
normal_float_to_short_v3(no_s, temp_no);
}
// BM_log_original_vert_data(ss->bm, ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s,
// false);
copy_v3_v3(co, temp_co);
normal_float_to_short_v3(no_s, mv->origno);
copy_v3_v3(co, mv->origco);
}
else {
copy_v3_v3(co, unode->co[vd.i]);
@ -5110,10 +5127,6 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
*disp_factor = 0.0f;
// update orig data to while we're at it, just to be paranoid
float *dummy;
BKE_pbvh_bmesh_update_origvert(ss->pbvh, v, &dummy, &dummy, NULL);
BLI_BITMAP_SET(ss->cache->layer_disp_map, nidx, true);
}
BKE_pbvh_vertex_iter_end;
@ -5255,6 +5268,12 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
cd_pers_disp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP);
cd_layer_disp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_DISP);
//should never happen
if (cd_pers_co < 0 || cd_pers_no < 0 || cd_pers_disp < 0 || cd_layer_disp < 0) {
printf("error!! $d $d $d $d\n", cd_pers_co, cd_pers_no, cd_pers_disp, cd_layer_disp);
return;
}
}
else if (ss->cache->layer_displacement_factor == NULL) {
ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
@ -5265,7 +5284,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.ob = ob,
.brush = brush,
.nodes = nodes,
.cd_pers_co = cd_pers_co,
@ -6492,16 +6511,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
for (int i = 0; i < totnode; i++) {
int other = brush->vcol_boundary_factor > 0.0f ? SCULPT_UNDO_COORDS : -1;
if (SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COLOR, other)) {
BKE_pbvh_update_origcolor_bmesh(ss->pbvh, nodes[i]);
if (other != -1) {
BKE_pbvh_update_origco_bmesh(ss->pbvh, nodes[i]);
}
}
SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COLOR, other);
BKE_pbvh_node_mark_update_color(nodes[i]);
// SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COLOR);
}
}
else if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) {
@ -6515,26 +6526,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
BKE_pbvh_node_mark_update(nodes[i]);
}
}
else if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
PBVHNode **nodes2;
int totnode2 = 0;
BKE_pbvh_get_nodes(ss->pbvh, PBVH_Leaf, &nodes2, &totnode2);
for (int i = 0; i < totnode2; i++) {
if (SCULPT_ensure_dyntopo_node_undo(ob, nodes2[i], SCULPT_UNDO_COORDS, -1)) {
BKE_pbvh_update_origco_bmesh(ss->pbvh, nodes2[i]);
BKE_pbvh_node_free_proxies(nodes2[i]);
}
BKE_pbvh_node_mark_update(nodes2[i]);
}
}
else {
} else {
for (int i = 0; i < totnode; i++) {
if (SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COORDS, -1)) {
// BKE_pbvh_update_origco_bmesh(ss->pbvh, nodes[i]);
}
SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COORDS, -1);
BKE_pbvh_node_mark_update(nodes[i]);
}
}
@ -8516,6 +8510,8 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
// increment stroke_id to flag origdata update
ss->stroke_id++;
sculpt_update_cache_invariants(C, sd, ss, op, mouse);
SCULPT_undo_push_begin(ob, sculpt_tool_name(sd));

View File

@ -134,6 +134,8 @@ static char layer_id[] = "_dyntopo_node_id";
void SCULPT_dyntopo_node_layers_update_offsets(SculptSession *ss)
{
SCULPT_dyntopo_node_layers_add(ss);
BKE_pbvh_update_offsets(
ss->pbvh, ss->cd_vert_node_offset, ss->cd_face_node_offset, ss->cd_dyn_vert);
}
bool SCULPT_dyntopo_has_templayer(SculptSession *ss, int type, const char *name)
@ -148,8 +150,6 @@ void SCULPT_dyntopo_ensure_templayer(SculptSession *ss, int type, const char *na
if (li < 0) {
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, type, name);
SCULPT_dyntopo_node_layers_update_offsets(ss);
BKE_pbvh_update_offsets(
ss->pbvh, ss->cd_vert_node_offset, ss->cd_face_node_offset, ss->cd_dyn_vert);
li = CustomData_get_named_layer_index(&ss->bm->vdata, type, name);
ss->bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY;
@ -319,8 +319,6 @@ void SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me)
if (modified) {
SCULPT_dyntopo_node_layers_update_offsets(ss);
BKE_pbvh_update_offsets(
ss->pbvh, ss->cd_vert_node_offset, ss->cd_face_node_offset, ss->cd_dyn_vert);
}
}
@ -378,8 +376,6 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
cd_layer_disp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_DISP);
SCULPT_dyntopo_node_layers_update_offsets(ss);
BKE_pbvh_update_offsets(
ss->pbvh, ss->cd_vert_node_offset, ss->cd_face_node_offset, ss->cd_dyn_vert);
cd_vcol_offset = CustomData_get_offset(&ss->bm->vdata, CD_PROP_COLOR);
}
@ -430,8 +426,7 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
ss->update_boundary_info_bmesh = 1;
/* Enable logging for undo/redo. */
ss->bm_log = BM_log_create(
ss->bm, ss->cd_origco_offset, ss->cd_origno_offset, ss->cd_origvcol_offset, ss->cd_dyn_vert);
ss->bm_log = BM_log_create(ss->bm, ss->cd_dyn_vert);
/* Update dependency graph, so modifiers that depend on dyntopo being enabled
* are re-evaluated and the PBVH is re-created. */

View File

@ -459,15 +459,12 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
}));
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
SCULPT_dyntopo_node_layers_add(ss);
SCULPT_dyntopo_save_origverts(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);
BM_log_set_cd_offsets(
ss->bm_log, ss->cd_origco_offset, ss->cd_origno_offset, ss->cd_origvcol_offset, ss->cd_dyn_vert);
BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
}
static void sculpt_undo_bmesh_restore_begin(bContext *C,
@ -601,8 +598,7 @@ static int sculpt_undo_bmesh_restore(bContext *C,
SculptSession *ss)
{
if (ss->bm_log) {
BM_log_set_cd_offsets(
ss->bm_log, ss->cd_origco_offset, ss->cd_origno_offset, ss->cd_origvcol_offset, ss->cd_dyn_vert);
BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
}
switch (unode->type) {
@ -1325,12 +1321,9 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
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_UNIQUE) {
float *dummy;
BKE_pbvh_bmesh_update_origvert(ss->pbvh, vd.bm_vert, &dummy, &dummy, &dummy);
// BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, false);
BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, false);
}
BKE_pbvh_vertex_iter_end;
break;
@ -1341,7 +1334,6 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
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_bmesh_update_origvert(ss->pbvh, vd.bm_vert, &dummy, &dummy, &dummy);
}
BKE_pbvh_vertex_iter_end;
@ -1353,13 +1345,11 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
}
case SCULPT_UNDO_COLOR: {
#if 1
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
float *dummy;
BKE_pbvh_bmesh_update_origvert(ss->pbvh, vd.bm_vert, NULL, NULL, &dummy);
BM_log_vert_before_modified(ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, true);
}
BKE_pbvh_vertex_iter_end;
#endif
break;
}
case SCULPT_UNDO_FACE_SETS: {

View File

@ -536,7 +536,10 @@ typedef struct MDynTopoVert {
float origmask;
float curvature_dir[3];
int _pad[1];
/* id of current stroke, used to detect
if vertex original data needs to be updated*/
int stroke_id;
} MDynTopoVert;
/*MDynTopoVert->flag*/