Added initial support for customdata to dyntopo undo (BMLog).

TODO:
 - Handle face (loop) data
 - Figure out what to do about edge data (warn user? actually handle
   it?)
 - Handle sculpt color undo push nodes properly (shouldn't be hard).
This commit is contained in:
Joseph Eagar 2020-10-26 02:45:56 -07:00
parent 4c0bcc3d13
commit faf8402c19
9 changed files with 223 additions and 22 deletions

View File

@ -104,6 +104,8 @@ bool CustomData_has_math(const struct CustomData *data);
bool CustomData_has_interp(const struct CustomData *data);
bool CustomData_bmesh_has_free(const struct CustomData *data);
bool CustomData_layout_is_same(const struct CustomData *_a, const struct CustomData *_b);
/**
* Checks if any of the customdata layers is referenced.
*/
@ -140,6 +142,10 @@ void CustomData_copy(const struct CustomData *source,
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
/* copies all customdata layers without allocating data,
* and without respect to type masks or NO_COPY/etc flags*/
void CustomData_copy_all_layout(const struct CustomData *source, struct CustomData *dest);
/* same as the above, except that this will preserve existing layers, and only
* add the layers that were not there yet */
bool CustomData_merge(const struct CustomData *source,

View File

@ -72,6 +72,32 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "siz
static CLG_LogRef LOG = {"bke.customdata"};
bool CustomData_layout_is_same(const CustomData *_a, const CustomData *_b)
{
CustomData a = *_a;
CustomData b = *_b;
a.layers = b.layers = NULL;
a.pool = b.pool = NULL;
if (memcmp((void *)&a, (void *)&b, sizeof(CustomData)) != 0) {
return false;
}
for (int i = 0; i < a.totlayer; i++) {
CustomDataLayer cla = _a->layers[i];
CustomDataLayer clb = _b->layers[i];
cla.data = clb.data = NULL;
if (memcmp((void *)&cla, (void *)&clb, sizeof(CustomDataLayer)) != 0) {
return false;
}
}
return true;
}
/** Update mask_dst with layers defined in mask_src (equivalent to a bitwise OR). */
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
const CustomData_MeshMasks *mask_src)
@ -2072,6 +2098,26 @@ static bool customdata_typemap_is_valid(const CustomData *data)
}
#endif
/* copies all customdata layers without allocating data,
* and without respect to type masks or NO_COPY/etc flags*/
void CustomData_copy_all_layout(const struct CustomData *source, struct CustomData *dest)
{
*dest = *source;
if (dest->pool) {
dest->pool = NULL;
}
if (source->layers) {
dest->layers = MEM_mallocN(sizeof(*dest->layers) * source->totlayer, __func__);
for (int i = 0; i < source->totlayer; i++) {
dest->layers[i] = source->layers[i];
dest->layers[i].data = NULL;
}
}
}
bool CustomData_merge(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,

View File

@ -2048,6 +2048,9 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
return pbvh;
}
//XXX hack
extern SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me);
PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
{
if (ob == NULL || ob->sculpt == NULL) {

View File

@ -1362,11 +1362,17 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode,
CustomData *ldata;
if (pbvh->type == PBVH_BMESH) {
vdata = &pbvh->bm->vdata;
ldata = &pbvh->bm->ldata;
} else {
vdata = &pbvh->vdata;
ldata = &pbvh->ldata;
if (pbvh->bm) {
vdata = &pbvh->bm->vdata;
ldata = &pbvh->bm->ldata;
}
else {
vdata = ldata = NULL;
}
}
else {
vdata = pbvh->vdata;
ldata = pbvh->ldata;
}
GPU_pbvh_update_attribute_names(vdata, ldata);

View File

@ -1762,7 +1762,10 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
/* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it
* may have been deleted above) */
if (v_conn != NULL) {
BM_log_vert_before_modified(pbvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
//BM_log_vert_before_modified(pbvh->bm, pbvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset, false);
void *dummy;
BKE_pbvh_bmesh_update_origvert(pbvh, v_conn, &dummy, &dummy, &dummy);
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
add_v3_v3(v_conn->no, v_del->no);
normalize_v3(v_conn->no);

View File

@ -1,3 +1,4 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -45,6 +46,8 @@
#include "BLI_strict_flags.h"
#define CUSTOMDATA
struct BMLogEntry {
struct BMLogEntry *next, *prev;
@ -75,6 +78,9 @@ struct BMLogEntry {
* This field is not guaranteed to be valid, any use of it should
* check for NULL. */
BMLog *log;
CustomData vdata, edata, ldata, pdata;
struct BMLogEntry *combined_prev, *combined_next;
};
struct BMLog {
@ -93,6 +99,8 @@ struct BMLog {
GHash *id_to_elem;
GHash *elem_to_id;
BMesh *bm;
/* All BMLogEntrys, ordered from earliest to most recent */
ListBase entries;
@ -177,6 +185,51 @@ 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)
{
#ifdef CUSTOMDATA
// if (!lv) {
// return;
//}
BMLogEntry *entry = log->current_entry;
if (lv->customdata) {
BLI_mempool_free(entry->vdata.pool, lv->customdata);
lv->customdata = NULL;
}
CustomData_bmesh_copy_data(&bm->vdata, &entry->vdata, v->head.data, &lv->customdata);
#endif
}
static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *lf)
{
#ifdef CUSTOMDATA
// if (!lf) {
// return;
//}
BMLogEntry *entry = log->current_entry;
uint f_id = bm_log_face_id_get(log, f);
void *key = POINTER_FROM_UINT(f_id);
BLI_ghash_insert(log->current_entry->modified_faces, key, lf);
BMLoop *l1 = f->l_first;
BMLoop *l2 = f->l_first->next;
BMLoop *l3 = f->l_first->prev;
BMLoop *ls[3] = {l1, l2, l3};
for (int i = 0; i < 3; i++) {
if (lf->customdata[i]) {
BLI_mempool_free(entry->ldata.pool, lf->customdata[i]);
lf->customdata[i] = NULL;
}
CustomData_bmesh_copy_data(&bm->ldata, &entry->ldata, ls[i]->head.data, &lf->customdata[i]);
}
#endif
}
/* Get a vertex's paint-mask value
*
* Returns zero if no paint-mask layer is present */
@ -212,6 +265,7 @@ static BMLogVert *bm_log_vert_alloc(BMLog *log, BMVert *v, const int cd_vert_mas
{
BMLogEntry *entry = log->current_entry;
BMLogVert *lv = BLI_mempool_alloc(entry->pool_verts);
lv->customdata = NULL;
bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
@ -225,6 +279,7 @@ static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f)
BMLogFace *lf = BLI_mempool_alloc(entry->pool_faces);
BMVert *v[3];
lf->customdata[0] = lf->customdata[1] = lf->customdata[2] = NULL;
BLI_assert(f->len == 3);
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3);
@ -285,7 +340,7 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
}
}
static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
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);
@ -298,6 +353,12 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
v->head.hflag = lv->hflag;
normal_short_to_float_v3(v->no, lv->no);
bm_log_vert_id_set(log, v, POINTER_AS_UINT(key));
#ifdef CUSTOMDATA
if (lv->customdata) {
CustomData_bmesh_copy_data(&bm->vdata, &entry->vdata, lv->customdata, &v->head.data);
}
#endif
}
}
@ -641,6 +702,31 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
MEM_freeN(farr);
}
BMLogEntry *BM_log_entry_check_customdata(BMesh *bm, BMLog *log)
{
BMLogEntry *entry = log->current_entry;
if (!entry) {
return BM_log_entry_add_ex(bm, log, false);
}
#ifndef CUSTOMDATA
return entry;
#else
CustomData *cd1[4] = {&bm->vdata, &bm->edata, &bm->ldata, &bm->pdata};
CustomData *cd2[4] = {&entry->vdata, &entry->edata, &entry->ldata, &entry->pdata};
for (int i = 0; i < 4; i++) {
if (!CustomData_layout_is_same(cd1[i], cd2[i])) {
return BM_log_entry_add_ex(bm, log, true);
}
}
return entry;
#endif
}
/* Start a new log entry and update the log entry list
*
* If the log entry list is empty, or if the current log entry is the
@ -651,8 +737,15 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
*
* In either case, the new entry is set as the current log entry.
*/
BMLogEntry *BM_log_entry_add(BMLog *log)
BMLogEntry *BM_log_entry_add(BMesh *bm, BMLog *log)
{
return BM_log_entry_add_ex(bm, log, false);
}
BMLogEntry *BM_log_entry_add_ex(BMesh *bm, BMLog *log, bool combine_with_last)
{
log->bm = bm;
/* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT
* freeing here causes unnecessary complications. */
BMLogEntry *entry;
@ -675,6 +768,25 @@ BMLogEntry *BM_log_entry_add(BMLog *log)
entry->log = log;
log->current_entry = entry;
#ifdef CUSTOMDATA
if (combine_with_last) {
if (log->current_entry) {
log->current_entry->combined_next = entry;
}
entry->combined_prev = log->current_entry;
}
CustomData_copy_all_layout(&bm->vdata, &entry->vdata);
CustomData_copy_all_layout(&bm->edata, &entry->edata);
CustomData_copy_all_layout(&bm->ldata, &entry->ldata);
CustomData_copy_all_layout(&bm->pdata, &entry->pdata);
CustomData_bmesh_init_pool(&entry->vdata, 0, BM_VERT);
CustomData_bmesh_init_pool(&entry->edata, 0, BM_EDGE);
CustomData_bmesh_init_pool(&entry->ldata, 0, BM_LOOP);
CustomData_bmesh_init_pool(&entry->pdata, 0, BM_FACE);
#endif
return entry;
}
@ -768,7 +880,7 @@ void BM_log_undo(BMesh *bm, BMLog *log)
bm_log_verts_unmake(bm, log, entry->added_verts);
/* Restore deleted verts and faces */
bm_log_verts_restore(bm, log, entry->deleted_verts);
bm_log_verts_restore(bm, log, entry->deleted_verts, entry);
bm_log_faces_restore(bm, log, entry->deleted_faces);
/* Restore vertex coordinates, mask, and hflag */
@ -805,7 +917,7 @@ void BM_log_redo(BMesh *bm, BMLog *log)
bm_log_verts_unmake(bm, log, entry->deleted_verts);
/* Restore previously added verts and faces */
bm_log_verts_restore(bm, log, entry->added_verts);
bm_log_verts_restore(bm, log, entry->added_verts, entry);
bm_log_faces_restore(bm, log, entry->added_faces);
/* Restore vertex coordinates, mask, and hflag */
@ -853,6 +965,10 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o
lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
*val_p = lv;
}
if (lv) {
bm_log_vert_customdata(log->bm, log, v, lv);
}
}
/* Log a new vertex as added to the BMesh

View File

@ -44,9 +44,12 @@ int BM_log_length(const BMLog *log);
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log);
/* Start a new log entry and update the log entry list */
BMLogEntry *BM_log_entry_add(BMLog *log);
BMLogEntry *BM_log_entry_add(BMesh *bm, BMLog *log);
BMLogEntry *BM_log_entry_add_ex(BMesh *bm, BMLog *log, bool combine_with_last);
/* Mark all used ids as unused for this node */
BMLogEntry *BM_log_entry_check_customdata(BMesh *bm, BMLog *log);
/* Mark all used ids as unused for this node */
void BM_log_cleanup_entry(BMLogEntry *entry);
/* Remove an entry from the log */

View File

@ -2097,10 +2097,13 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
if (use_original) {
if (unode->bm_entry) {
const float *temp_co;
const short *temp_no_s;
BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s);
const float *temp_no;
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);
copy_v3_v3_short(no_s, temp_no_s);
}
else {
copy_v3_v3(co, unode->co[vd.i]);

View File

@ -1181,7 +1181,7 @@ 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);
unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
BM_log_before_all_removed(ss->bm, ss->bm_log);
}
else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
@ -1193,17 +1193,21 @@ 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);
unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
BM_log_all_added(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:
@ -1212,8 +1216,8 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
{
void *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);
//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);
}
BKE_pbvh_vertex_iter_end;
break;
@ -1230,16 +1234,27 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
TGSET_ITER (f, faces) {
BM_log_face_modified(ss->bm_log, f);
} TGSET_ITER_END
}
TGSET_ITER_END
break;
}
case SCULPT_UNDO_COLOR: {
#if 0
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
{
BM_log_vert_before_modified(
ss->bm, ss->bm_log, vd.bm_vert, vd.cd_vert_mask_offset, true);
}
BKE_pbvh_vertex_iter_end;
#endif
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;
}
}