* Got box trim tool working for dyntopo

- This required implementing SCULPT_UNDO_GEOMETRY for dyntopo.
    That turned out to be more work then I expected.  Basically
    it writes an entire Mesh to BMLogEntry, which can be swapped
    with current bmesh.  Tricky part was patching bm log ids.
This commit is contained in:
Joseph Eagar 2021-04-27 13:04:36 -07:00
parent 3028d53865
commit 786781304c
12 changed files with 477 additions and 42 deletions

View File

@ -602,6 +602,9 @@ void CustomData_blend_write(struct BlendWriter *writer,
struct ID *id);
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
void CustomData_unmark_temporary_nocopy(struct CustomData *data);
void CustomData_mark_temporary_nocopy(struct CustomData *data);
#ifdef __cplusplus
}
#endif

View File

@ -73,6 +73,7 @@ typedef struct PBVHTriBuf {
struct BMLog;
struct BMesh;
struct BMVert;
struct BMEdge;
struct BMFace;
struct CCGElem;
struct CCGKey;
@ -699,6 +700,17 @@ void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_recalc_bmesh_boundary(PBVH *pbvh);
void BKE_pbvh_bmesh_face_kill(PBVH *pbvh, struct BMFace *f);
// note that e_tri and f_example are allowed to be NULL
struct BMFace *BKE_pbvh_face_create_bmesh(PBVH *pbvh,
struct BMVert *v_tri[3],
struct BMEdge *e_tri[3],
const struct BMFace *f_example);
// if node is NULL, one will be foudn in the pbvh, which potentially can be slow
struct BMVert *BKE_pbvh_vert_create_bmesh(
PBVH *pbvh, float co[3], float no[3], PBVHNode *node, struct BMVert *v_example);
PBVHNode *BKE_pbvh_node_from_face_bmesh(PBVH *pbvh, struct BMFace *f);
#ifdef __cplusplus
}
#endif

View File

@ -2943,6 +2943,22 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type)
return (layer->flag & CD_FLAG_NOFREE) != 0;
}
void CustomData_unmark_temporary_nocopy(CustomData *data) {
for (int i=0; i<data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_TEMPORARY) {
data->layers[i].flag &= ~CD_FLAG_NOCOPY;
}
}
}
void CustomData_mark_temporary_nocopy(CustomData *data) {
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_TEMPORARY) {
data->layers[i].flag |= CD_FLAG_NOCOPY;
}
}
}
void CustomData_free_temporary(CustomData *data, int totelem)
{
int i, j;

View File

@ -1040,7 +1040,11 @@ Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
BLI_assert(params->calc_object_remap == false);
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me(NULL, NULL, bm, mesh, params);
BKE_mesh_copy_settings(mesh, me_settings);
if (me_settings) {
BKE_mesh_copy_settings(mesh, me_settings);
}
return mesh;
}

View File

@ -596,6 +596,7 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
int node_index,
const float co[3],
const float no[3],
BMVert *v_example,
const int cd_vert_mask_offset)
{
PBVHNode *node = &pbvh->nodes[node_index];
@ -606,15 +607,27 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
BMVert *v = BM_vert_create(pbvh->bm, co, NULL, BM_CREATE_SKIP_CD);
CustomData_bmesh_set_default(&pbvh->bm->vdata, &v->head.data);
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
if (v_example) {
v->head.hflag = v_example->head.hflag;
copy_v3_v3(mv->origco, co);
copy_v3_v3(mv->origno, no);
mv->origmask = 0.0f;
mv->flag = 0;
CustomData_bmesh_copy_data(&pbvh->bm->vdata, &pbvh->bm->vdata, v_example->head.data, &v->head.data);
/* This value is logged below */
copy_v3_v3(v->no, no);
/* This value is logged below */
copy_v3_v3(v->no, no);
//keep MDynTopoVert copied from v_example as-is
}
else {
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
copy_v3_v3(mv->origco, co);
copy_v3_v3(mv->origno, no);
mv->origmask = 0.0f;
mv->flag = 0;
/* This value is logged below */
copy_v3_v3(v->no, no);
}
BLI_table_gset_insert(node->bm_unique_verts, v);
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, node_index);
@ -653,7 +666,9 @@ static BMFace *pbvh_bmesh_face_create(PBVH *pbvh,
f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
}
f->head.hflag = f_example->head.hflag;
if (f_example) {
f->head.hflag = f_example->head.hflag;
}
BLI_table_gset_insert(node->bm_faces, f);
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, node_index);
@ -689,6 +704,136 @@ static BMFace *pbvh_bmesh_face_create(PBVH *pbvh,
return f;
}
BMVert *BKE_pbvh_vert_create_bmesh(
PBVH *pbvh, float co[3], float no[3], PBVHNode *node, BMVert *v_example)
{
if (!node) {
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *node2 = pbvh->nodes + i;
if (!(node2->flag & PBVH_Leaf)) {
continue;
}
// ensure we have at least some node somewhere picked
node = node2;
bool ok = true;
for (int j = 0; j < 3; j++) {
if (co[j] < node2->vb.bmin[j] || co[j] >= node2->vb.bmax[j]) {
continue;
}
}
if (ok) {
break;
}
}
}
BMVert *v;
if (!node) {
printf("possible pbvh error\n");
v = BM_vert_create(pbvh->bm, co, v_example, BM_CREATE_NOP);
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
MDynTopoVert *mv = BM_ELEM_CD_GET_VOID_P(v, pbvh->cd_dyn_vert);
copy_v3_v3(mv->origco, co);
return v;
}
return pbvh_bmesh_vert_create(
pbvh, node - pbvh->nodes, co, no, v_example, pbvh->cd_vert_mask_offset);
}
PBVHNode *BKE_pbvh_node_from_face_bmesh(PBVH *pbvh, BMFace *f)
{
return BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset);
}
BMFace *BKE_pbvh_face_create_bmesh(PBVH *pbvh,
BMVert *v_tri[3],
BMEdge *e_tri[3],
const BMFace *f_example)
{
int ni = DYNTOPO_NODE_NONE;
for (int i = 0; i < 3; i++) {
BMVert *v = v_tri[i];
BMLoop *l;
BMIter iter;
BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
int ni2 = BM_ELEM_CD_GET_INT(l->f, pbvh->cd_face_node_offset);
if (ni2 != DYNTOPO_NODE_NONE) {
ni = ni2;
break;
}
}
}
if (ni == DYNTOPO_NODE_NONE) {
BMFace *f;
// no existing nodes? find one
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *node = pbvh->nodes + i;
if (!(node->flag & PBVH_Leaf)) {
continue;
}
for (int j = 0; j < 3; j++) {
BMVert *v = v_tri[j];
bool ok = true;
for (int k = 0; k < 3; k++) {
if (v->co[k] < node->vb.bmin[k] || v->co[k] >= node->vb.bmax[k]) {
ok = false;
}
}
if (ok &&
(ni == DYNTOPO_NODE_NONE || BLI_table_gset_len(node->bm_faces) < pbvh->leaf_limit)) {
ni = i;
break;
}
}
if (ni != DYNTOPO_NODE_NONE) {
break;
}
}
if (ni == DYNTOPO_NODE_NONE) {
// empty pbvh?
printf("possibly pbvh error\n");
if (e_tri) {
f = BM_face_create_verts(pbvh->bm, v_tri, 3, f_example, BM_CREATE_NOP, true);
}
else {
f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
}
if (f_example) {
f->head.hflag = f_example->head.hflag;
}
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
return f;
}
}
return pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_example, true, true);
}
/* Return the number of faces in 'node' that use vertex 'v' */
#if 0
static int pbvh_bmesh_node_vert_use_count(PBVH *pbvh, PBVHNode *node, BMVert *v)
@ -2014,7 +2159,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
BMVert *v_new = pbvh_bmesh_vert_create(
pbvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
pbvh, node_index, co_mid, no_mid, NULL, eq_ctx->cd_vert_mask_offset);
// transfer edge flags
BMEdge *e1 = BM_edge_create(pbvh->bm, e->v1, v_new, e, BM_CREATE_NOP);
@ -3904,6 +4049,11 @@ void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
tri.v[j] = (intptr_t)val[0];
j++;
if (j >= 3) {
break;
}
l = l->next;
} while (l != f->l_first);

View File

@ -32,6 +32,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.h"
#include "BLI_compiler_attrs.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@ -39,9 +41,11 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "bmesh.h"
#include "bmesh_log.h"
@ -51,6 +55,14 @@
#define CUSTOMDATA
struct Mesh;
typedef struct BMLogEdge {
uint v1, v2;
void *data;
int flag;
} BMLogEdge;
struct BMLogEntry {
struct BMLogEntry *next, *prev;
@ -61,6 +73,7 @@ struct BMLogEntry {
* deleted */
GHash *deleted_verts;
GHash *deleted_faces;
/* Elements that were not in the previous entry, but are in the
* result of this entry */
GHash *added_verts;
@ -84,6 +97,11 @@ struct BMLogEntry {
CustomData vdata, edata, ldata, pdata;
struct BMLogEntry *combined_prev, *combined_next;
bool fully_copy; // has full copy
struct Mesh
*full_copy_mesh; // avoid excessive memory use by saving a Mesh instead of copying the bmesh
GHash *full_copy_idmap; // maps ids to indices (with the elem-type in the high order bits)
};
struct BMLog {
@ -589,6 +607,42 @@ static void bm_log_assign_ids(BMesh *bm, BMLog *log)
}
}
static void bm_log_full_mesh_intern(BMesh *bm, BMLog *log, BMLogEntry *entry)
{
CustomData_MeshMasks cd_mask_extra = {CD_MASK_DYNTOPO_VERT, 0, 0, 0, 0};
entry->full_copy_idmap = BLI_ghash_ptr_new_ex("bmlog", bm->totvert + bm->totface);
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE | BM_FACE);
GHashIterator gi;
for (int step = 0; step < 2; step++) {
BMIter iter;
BMHeader *elem;
BM_ITER_MESH (elem, &iter, bm, step ? BM_FACES_OF_MESH : BM_VERTS_OF_MESH) {
void **val = log_ghash_lookup_p(entry, log->elem_to_id, (void *)elem);
if (!val) {
continue;
}
uint id = POINTER_AS_UINT(*val);
uintptr_t key = elem->index;
key |= ((uintptr_t)elem->htype) << 31L;
BLI_ghash_insert(entry->full_copy_idmap, POINTER_FROM_UINT(id), (void *)key);
}
}
entry->full_copy_mesh = BKE_mesh_from_bmesh_nomain(
bm,
(&(struct BMeshToMeshParams){.update_shapekey_indices = false,
.calc_object_remap = false,
.cd_mask_extra = cd_mask_extra,
.copy_temp_cdlayers = true}),
NULL);
}
/* Allocate an empty log entry */
static BMLogEntry *bm_log_entry_create(void)
{
@ -612,6 +666,14 @@ static BMLogEntry *bm_log_entry_create(void)
* Note: does not free the log entry itself */
static void bm_log_entry_free(BMLogEntry *entry)
{
if (entry->full_copy_mesh) {
BKE_mesh_free(entry->full_copy_mesh);
if (entry->full_copy_idmap) {
BLI_ghash_free(entry->full_copy_idmap, NULL, NULL);
}
}
BLI_ghash_free(entry->deleted_verts, NULL, NULL);
BLI_ghash_free(entry->deleted_faces, NULL, NULL);
BLI_ghash_free(entry->added_verts, NULL, NULL);
@ -1049,6 +1111,75 @@ void BM_log_entry_drop(BMLogEntry *entry)
bm_log_entry_free(entry);
BLI_freelinkN(&log->entries, entry);
}
static void full_copy_swap(BMesh *bm, BMLog *log, BMLogEntry *entry)
{
CustomData_MeshMasks cd_mask_extra = {CD_MASK_DYNTOPO_VERT, 0, 0, 0, 0};
BMIter iter;
BMVert *v;
BMFace *f;
BMLogEntry tmp = {0};
bm_log_full_mesh_intern(bm, log, &tmp);
BM_mesh_clear(bm);
BM_mesh_bm_from_me(NULL,
bm,
entry->full_copy_mesh,
(&(struct BMeshFromMeshParams){.calc_face_normal = false,
.add_key_index = false,
.use_shapekey = false,
.active_shapekey = -1,
.cd_mask_extra = cd_mask_extra,
.copy_temp_cdlayers = true}));
bm->elem_index_dirty |= BM_VERT | BM_FACE;
BM_mesh_elem_table_ensure(bm, BM_VERT | BM_FACE);
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
// restores ids
GHashIterator gi;
GHASH_ITER (gi, entry->full_copy_idmap) {
// uint id = POINTER_AS_UINT(BLI_ghashIterator_getKey(&gi));
uintptr_t id = (uintptr_t)BLI_ghashIterator_getKey(&gi);
uintptr_t key = (uintptr_t)BLI_ghashIterator_getValue(&gi);
uintptr_t idx = (key & ((1L << 31L) - 1L));
uintptr_t type = key >> 31L;
BMHeader *elem = NULL;
switch (type) {
case BM_VERT:
elem = &bm->vtable[idx]->head;
break;
case BM_FACE:
elem = &bm->ftable[idx]->head;
break;
}
if (elem) {
log_ghash_reinsert(entry, log->id_to_elem, POINTER_FROM_UINT(id), elem, NULL, NULL);
log_ghash_reinsert(entry, log->elem_to_id, elem, POINTER_FROM_UINT(id), NULL, NULL);
}
else {
// eek, error!
printf("bmlog error!\n");
log_ghash_remove(entry, log->id_to_elem, id, NULL, NULL);
}
}
BKE_mesh_free(entry->full_copy_mesh);
BLI_ghash_free(entry->full_copy_idmap, NULL, NULL);
entry->full_copy_idmap = tmp.full_copy_idmap;
entry->full_copy_mesh = tmp.full_copy_mesh;
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
}
/* Undo one BMLogEntry
*
@ -1058,6 +1189,11 @@ static void bm_log_undo_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;
if (entry->fully_copy) {
full_copy_swap(bm, log, entry);
return;
}
/* 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);
@ -1095,6 +1231,12 @@ void BM_log_undo(BMesh *bm, BMLog *log)
* Has no effect if there's nothing left to redo */
static void bm_log_redo_intern(BMesh *bm, BMLog *log, BMLogEntry *entry)
{
if (entry->fully_copy) {
// hrm, should we swap?
full_copy_swap(bm, log, entry);
return;
}
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
@ -1362,6 +1504,30 @@ void BM_log_all_added(BMesh *bm, BMLog *log)
}
}
void BM_log_full_mesh(BMesh *bm, BMLog *log)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
BMLogEntry *entry = log->current_entry;
bool add = BLI_ghash_len(entry->added_faces) > 0;
add |= BLI_ghash_len(entry->modified_verts) > 0;
add |= BLI_ghash_len(entry->modified_faces) > 0;
add |= BLI_ghash_len(entry->deleted_verts) > 0;
add |= BLI_ghash_len(entry->deleted_faces) > 0;
if (add) {
entry = BM_log_entry_add_ex(bm, log, true);
}
entry->fully_copy = true;
bm_log_full_mesh_intern(bm, log, entry);
// push a fresh entry
BM_log_entry_add_ex(bm, log, true);
}
/* Log all vertices/faces in the BMesh as removed */
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
{

View File

@ -86,6 +86,8 @@ void BM_log_face_removed(BMLog *log, struct BMFace *f);
/* Log all vertices/faces in the BMesh as added */
void BM_log_all_added(BMesh *bm, BMLog *log);
void BM_log_full_mesh(BMesh *bm, BMLog *log);
/* Log all vertices/faces in the BMesh as removed */
void BM_log_before_all_removed(BMesh *bm, BMLog *log);

View File

@ -95,6 +95,22 @@
#include "bmesh.h"
#include "intern/bmesh_private.h" /* For element checking. */
static void bm_unmark_temp_cdlayers(BMesh *bm)
{
CustomData_unmark_temporary_nocopy(&bm->vdata);
CustomData_unmark_temporary_nocopy(&bm->edata);
CustomData_unmark_temporary_nocopy(&bm->ldata);
CustomData_unmark_temporary_nocopy(&bm->pdata);
}
static void bm_mark_temp_cdlayers(BMesh *bm)
{
CustomData_mark_temporary_nocopy(&bm->vdata);
CustomData_mark_temporary_nocopy(&bm->edata);
CustomData_mark_temporary_nocopy(&bm->ldata);
CustomData_mark_temporary_nocopy(&bm->pdata);
}
void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
{
const char cd_flag_all = BM_mesh_cd_flag_from_bmesh(bm) | cd_flag;
@ -157,6 +173,7 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
cd_flag |= ME_CDFLAG_EDGE_CREASE;
}
return cd_flag;
}
@ -176,7 +193,8 @@ static BMFace *bm_face_create_from_mpoly(
return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
}
void BM_enter_multires_space(Object *ob, BMesh *bm, int space) {
void BM_enter_multires_space(Object *ob, BMesh *bm, int space)
{
if (!bm->haveMultiResSettings && ob) {
MultiresModifierData *mmd = get_multires_modifier(NULL, ob, true);
if (mmd) {
@ -186,7 +204,8 @@ void BM_enter_multires_space(Object *ob, BMesh *bm, int space) {
}
}
if (!bm->haveMultiResSettings || !CustomData_has_layer(&bm->ldata, CD_MDISPS) || space == bm->multiresSpace) {
if (!bm->haveMultiResSettings || !CustomData_has_layer(&bm->ldata, CD_MDISPS) ||
space == bm->multiresSpace) {
return;
}
@ -205,7 +224,10 @@ void BM_enter_multires_space(Object *ob, BMesh *bm, int space) {
*
* \warning This function doesn't calculate face normals.
*/
void BM_mesh_bm_from_me(Object *ob, BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
void BM_mesh_bm_from_me(Object *ob,
BMesh *bm,
const Mesh *me,
const struct BMeshFromMeshParams *params)
{
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
bm->pdata.totlayer || bm->ldata.totlayer));
@ -222,13 +244,18 @@ void BM_mesh_bm_from_me(Object *ob, BMesh *bm, const Mesh *me, const struct BMes
CustomData_MeshMasks mask = CD_MASK_BMESH;
CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
if (params->copy_temp_cdlayers) {
bm_unmark_temp_cdlayers(bm);
}
MultiresModifierData *mmd = ob ? get_multires_modifier(NULL, ob, true) : NULL;
if (mmd) {
bm->multires = *mmd;
bm->haveMultiResSettings = true;
bm->multiresSpace = MULTIRES_SPACE_TANGENT;
} else {
}
else {
bm->haveMultiResSettings = false;
}
@ -244,6 +271,11 @@ void BM_mesh_bm_from_me(Object *ob, BMesh *bm, const Mesh *me, const struct BMes
CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
}
if (params->copy_temp_cdlayers) {
bm_mark_temp_cdlayers(bm);
}
return; /* Sanity check. */
}
@ -531,6 +563,10 @@ void BM_mesh_bm_from_me(Object *ob, BMesh *bm, const Mesh *me, const struct BMes
if (ftable) {
MEM_freeN(ftable);
}
if (params->copy_temp_cdlayers) {
bm_mark_temp_cdlayers(bm);
}
}
/**
@ -615,7 +651,8 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
*
* \param bmain: May be NULL in case \a calc_object_remap parameter option is not set.
*/
void BM_mesh_bm_to_me(Main *bmain, Object *ob, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
void BM_mesh_bm_to_me(
Main *bmain, Object *ob, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
{
MEdge *med;
BMVert *v, *eve;
@ -624,7 +661,11 @@ void BM_mesh_bm_to_me(Main *bmain, Object *ob, BMesh *bm, Mesh *me, const struct
BMIter iter;
int i, j;
//ensure multires space is correct
if (params->copy_temp_cdlayers) {
bm_unmark_temp_cdlayers(bm);
}
// ensure multires space is correct
if (bm->haveMultiResSettings && bm->multiresSpace != MULTIRES_SPACE_TANGENT) {
BM_enter_multires_space(ob, bm, MULTIRES_SPACE_TANGENT);
}
@ -1037,6 +1078,11 @@ void BM_mesh_bm_to_me(Main *bmain, Object *ob, BMesh *bm, Mesh *me, const struct
/* To be removed as soon as COW is enabled by default.. */
BKE_mesh_runtime_clear_geometry(me);
if (params && params->copy_temp_cdlayers) {
bm_mark_temp_cdlayers(bm);
}
}
/**

View File

@ -42,6 +42,7 @@ struct BMeshFromMeshParams {
/* define the active shape key (index + 1) */
int active_shapekey;
struct CustomData_MeshMasks cd_mask_extra;
uint copy_temp_cdlayers : 1;
};
struct Object;
@ -62,6 +63,7 @@ struct BMeshToMeshParams {
*/
uint update_shapekey_indices : 1;
struct CustomData_MeshMasks cd_mask_extra;
uint copy_temp_cdlayers : 1;
};
void BM_enter_multires_space(struct Object *ob, struct BMesh *bm, int space);

View File

@ -445,7 +445,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
/* join faces */
f_new = BM_faces_join_pair(bm, l_a, l_b, false);
if (BM_face_find_double(f_new)) {
if (f_new && BM_face_find_double(f_new)) {
BM_face_kill(bm, f_new);
f_new = NULL;
}

View File

@ -974,7 +974,8 @@ static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext)
.use_toolflags = true,
}));
BM_mesh_bm_from_me(NULL, bm,
BM_mesh_bm_from_me(NULL,
bm,
trim_mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@ -1220,11 +1221,24 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
Mesh *trim_mesh = trim_operation->mesh;
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(sculpt_mesh, trim_mesh);
bm = BM_mesh_create(&allocsize,
&((struct BMeshCreateParams){
.use_toolflags = false,
}));
if (sgcontext->ss && sgcontext->ss->bm) {
bm = sgcontext->ss->bm;
}
else {
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(sculpt_mesh, trim_mesh);
bm = BM_mesh_create(&allocsize,
&((struct BMeshCreateParams){
.use_toolflags = false,
}));
BM_mesh_bm_from_me(NULL,
bm,
sculpt_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
}
BM_mesh_bm_from_me(NULL,
bm,
@ -1233,13 +1247,6 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
.calc_face_normal = true,
}));
BM_mesh_bm_from_me(NULL,
bm,
sculpt_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
}));
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
int tottri;
BMLoop *(*looptris)[3];
@ -1297,15 +1304,29 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
MEM_freeN(looptris);
Mesh *result = BKE_mesh_from_bmesh_nomain(bm,
(&(struct BMeshToMeshParams){
.calc_object_remap = false,
}),
sculpt_mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
BKE_mesh_nomain_to_mesh(
result, sgcontext->vc.obact->data, sgcontext->vc.obact, &CD_MASK_MESH, true);
if (sgcontext->ss && sgcontext->ss->bm) { //rebuild pbvh
BKE_pbvh_free(sgcontext->ss->pbvh);
sgcontext->ss->pbvh = BKE_pbvh_new();
BKE_pbvh_build_bmesh(sgcontext->ss->pbvh,
sgcontext->ss->bm,
false,
sgcontext->ss->bm_log,
sgcontext->ss->cd_vert_node_offset,
sgcontext->ss->cd_face_node_offset,
sgcontext->ss->cd_dyn_vert);
}
else { //save result to mesh
Mesh *result = BKE_mesh_from_bmesh_nomain(bm,
(&(struct BMeshToMeshParams){
.calc_object_remap = false,
}),
sculpt_mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
BKE_mesh_nomain_to_mesh(
result, sgcontext->vc.obact->data, sgcontext->vc.obact, &CD_MASK_MESH, true);
}
}
static void sculpt_gesture_trim_begin(bContext *C, SculptGestureContext *sgcontext)
@ -1342,6 +1363,10 @@ static void sculpt_gesture_trim_end(bContext *UNUSED(C), SculptGestureContext *s
sculpt_gesture_trim_geometry_free(sgcontext);
if (sgcontext->ss && sgcontext->ss->bm) {
SCULPT_dynamic_topology_triangulate(sgcontext->ss->bm);
}
SCULPT_undo_push_node(sgcontext->vc.obact, NULL, SCULPT_UNDO_GEOMETRY);
BKE_mesh_batch_cache_dirty_tag(sgcontext->vc.obact->data, BKE_MESH_BATCH_DIRTY_ALL);
DEG_id_tag_update(&sgcontext->vc.obact->id, ID_RECALC_GEOMETRY);
@ -1551,8 +1576,8 @@ static int sculpt_trim_gesture_box_exec(bContext *C, wmOperator *op)
{
Object *object = CTX_data_active_object(C);
SculptSession *ss = object->sculpt;
if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
/* Not supported in Multires and Dyntopo. */
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
/* Not supported in Multires. */
return OPERATOR_CANCELLED;
}

View File

@ -597,7 +597,8 @@ static int sculpt_undo_bmesh_restore(bContext *C,
Object *ob,
SculptSession *ss)
{
if (ss->bm_log) {
if (ss->bm_log && ss->bm) {
SCULPT_dyntopo_node_layers_update_offsets(ss);
BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
}
@ -1369,6 +1370,14 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
case SCULPT_UNDO_GEOMETRY:
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) {