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:
parent
4c0bcc3d13
commit
faf8402c19
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue