* Fix bug with symmetrize creating non-manifold geometry.
* Fix bug in pbvh face create
This commit is contained in:
parent
daa4a33383
commit
71959181ad
|
@ -1060,7 +1060,7 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
|
|||
BM_FACES_OF_VERT_ITER_END;
|
||||
}
|
||||
|
||||
static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f, bool log_face)
|
||||
static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f, bool log_face, bool check_verts)
|
||||
{
|
||||
PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
|
||||
|
||||
|
@ -1072,32 +1072,30 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f, bool log_face)
|
|||
|
||||
/* Check if any of this face's vertices need to be removed
|
||||
* from the node */
|
||||
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
|
||||
BMLoop *l_iter = l_first;
|
||||
do {
|
||||
BMVert *v = l_iter->v;
|
||||
if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, f_node, v, 1)) {
|
||||
if (BLI_table_gset_haskey(f_node->bm_unique_verts, v)) {
|
||||
/* Find a different node that uses 'v' */
|
||||
PBVHNode *new_node;
|
||||
if (check_verts) {
|
||||
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
|
||||
BMLoop *l_iter = l_first;
|
||||
do {
|
||||
BMVert *v = l_iter->v;
|
||||
if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, f_node, v, 1)) {
|
||||
if (BLI_table_gset_haskey(f_node->bm_unique_verts, v)) {
|
||||
/* Find a different node that uses 'v' */
|
||||
PBVHNode *new_node;
|
||||
|
||||
new_node = pbvh_bmesh_vert_other_node_find(pbvh, v);
|
||||
BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
|
||||
new_node = pbvh_bmesh_vert_other_node_find(pbvh, v);
|
||||
BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
|
||||
|
||||
if (new_node) {
|
||||
pbvh_bmesh_vert_ownership_transfer(pbvh, new_node, v);
|
||||
if (new_node) {
|
||||
pbvh_bmesh_vert_ownership_transfer(pbvh, new_node, v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
|
||||
BLI_table_gset_remove(f_node->bm_unique_verts, v, NULL);
|
||||
/* Remove from other verts */
|
||||
BLI_table_gset_remove(f_node->bm_other_verts, v, NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Remove from other verts */
|
||||
BLI_table_gset_remove(f_node->bm_other_verts, v, NULL);
|
||||
}
|
||||
}
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
||||
/* Remove face from node and top level */
|
||||
BLI_table_gset_remove(f_node->bm_faces, f, NULL);
|
||||
|
@ -1114,7 +1112,7 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f, bool log_face)
|
|||
|
||||
void BKE_pbvh_bmesh_remove_face(PBVH *pbvh, BMFace *f, bool log_face)
|
||||
{
|
||||
pbvh_bmesh_face_remove(pbvh, f, log_face);
|
||||
pbvh_bmesh_face_remove(pbvh, f, log_face, true);
|
||||
}
|
||||
|
||||
void BKE_pbvh_bmesh_remove_vertex(PBVH *pbvh, BMVert *v, bool log_vert)
|
||||
|
@ -2660,7 +2658,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
|
|||
&pbvh->bm->ldata, (const void **)lsrcs, lws, lws, 1, f_new->l_first->prev->head.data);
|
||||
|
||||
/* Delete original */
|
||||
pbvh_bmesh_face_remove(pbvh, f_adj, true);
|
||||
pbvh_bmesh_face_remove(pbvh, f_adj, true, true);
|
||||
BM_face_kill(pbvh->bm, f_adj);
|
||||
|
||||
/* Ensure new vertex is in the node */
|
||||
|
@ -2841,7 +2839,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
|
|||
l = l->next;
|
||||
} while (l != f_adj->l_first);
|
||||
|
||||
pbvh_bmesh_face_remove(pbvh, f_adj, true);
|
||||
pbvh_bmesh_face_remove(pbvh, f_adj, true, true);
|
||||
BM_face_kill(pbvh->bm, f_adj);
|
||||
}
|
||||
|
||||
|
@ -3015,7 +3013,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
|
|||
} while (l1 != f_del->l_first);
|
||||
|
||||
/* Remove the face */
|
||||
pbvh_bmesh_face_remove(pbvh, f_del, true);
|
||||
pbvh_bmesh_face_remove(pbvh, f_del, true, true);
|
||||
BM_face_kill(pbvh->bm, f_del);
|
||||
|
||||
/* Check if any of the face's edges are now unused by any
|
||||
|
@ -3939,8 +3937,6 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
|
|||
continue;
|
||||
}
|
||||
|
||||
PBVHVertexIter vi;
|
||||
GSetIterator gi;
|
||||
BMVert *v;
|
||||
|
||||
TGSET_ITER (v, node->bm_unique_verts) {
|
||||
|
@ -4022,7 +4018,7 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
|
|||
BLI_table_gset_remove(node2->bm_unique_verts, v, NULL);
|
||||
BLI_table_gset_remove(node2->bm_other_verts, v, NULL);
|
||||
|
||||
pbvh_bmesh_face_remove(pbvh, f, true);
|
||||
pbvh_bmesh_face_remove(pbvh, f, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4037,6 +4033,8 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
|
|||
BMFace *f1 = NULL;
|
||||
if (vs[0] != vs[1] && vs[1] != vs[2] && vs[0] != vs[2]) {
|
||||
f1 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, l->f, false, false);
|
||||
normal_tri_v3(
|
||||
f1->no, f1->l_first->v->co, f1->l_first->next->v->co, f1->l_first->prev->v->co);
|
||||
}
|
||||
|
||||
if (val == 4 && vs[0] != vs[2] && vs[2] != vs[3] && vs[0] != vs[3]) {
|
||||
|
@ -4052,6 +4050,8 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
|
|||
CustomData_bmesh_copy_data(
|
||||
&pbvh->bm->ldata, &pbvh->bm->ldata, ls[2]->head.data, &f2->l_first->next->head.data);
|
||||
|
||||
normal_tri_v3(
|
||||
f2->no, f2->l_first->v->co, f2->l_first->next->v->co, f2->l_first->prev->v->co);
|
||||
BM_log_face_added(pbvh->bm_log, f2);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,12 +57,6 @@
|
|||
|
||||
struct Mesh;
|
||||
|
||||
typedef struct BMLogEdge {
|
||||
uint v1, v2;
|
||||
void *data;
|
||||
int flag;
|
||||
} BMLogEdge;
|
||||
|
||||
struct BMLogEntry {
|
||||
struct BMLogEntry *next, *prev;
|
||||
|
||||
|
@ -142,6 +136,7 @@ struct BMLog {
|
|||
BMLogEntry *current_entry;
|
||||
|
||||
int cd_dyn_vert;
|
||||
bool dead;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -168,8 +163,8 @@ typedef struct {
|
|||
|
||||
static void full_copy_swap(BMesh *bm, BMLog *log, BMLogEntry *entry);
|
||||
static void full_copy_load(BMesh *bm, BMLog *log, BMLogEntry *entry);
|
||||
|
||||
static void bm_log_entry_free(BMLogEntry *entry);
|
||||
static bool bm_log_free_direct(BMLog *log, bool safe_mode);
|
||||
|
||||
static void *log_ghash_lookup(BMLog *log, GHash *gh, const void *key)
|
||||
{
|
||||
|
@ -608,10 +603,10 @@ static void bm_log_vert_values_swap(
|
|||
}
|
||||
}
|
||||
|
||||
ATTR_NO_OPT static void bm_log_face_values_swap(BMLog *log,
|
||||
GHash *faces,
|
||||
BMLogEntry *entry,
|
||||
BMLogCallbacks *callbacks)
|
||||
static void bm_log_face_values_swap(BMLog *log,
|
||||
GHash *faces,
|
||||
BMLogEntry *entry,
|
||||
BMLogCallbacks *callbacks)
|
||||
{
|
||||
void *scratch = log->bm->pdata.pool ? BLI_mempool_alloc(log->bm->pdata.pool) : NULL;
|
||||
|
||||
|
@ -737,13 +732,18 @@ 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->log) {
|
||||
entry->log->refcount--;
|
||||
BMLog *log = entry->log;
|
||||
bool kill_log = false;
|
||||
|
||||
if (entry->log->refcount < 0) {
|
||||
if (log) {
|
||||
log->refcount--;
|
||||
|
||||
if (log->refcount < 0) {
|
||||
fprintf(stderr, "BMLog refcount error\n");
|
||||
entry->log->refcount = 0;
|
||||
log->refcount = 0;
|
||||
}
|
||||
|
||||
kill_log = !log->refcount;
|
||||
}
|
||||
|
||||
if (entry->full_copy_mesh) {
|
||||
|
@ -781,6 +781,10 @@ static void bm_log_entry_free(BMLogEntry *entry)
|
|||
CustomData_free(&entry->edata, 0);
|
||||
CustomData_free(&entry->ldata, 0);
|
||||
CustomData_free(&entry->pdata, 0);
|
||||
|
||||
if (kill_log) {
|
||||
bm_log_free_direct(log, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash)
|
||||
|
@ -981,7 +985,7 @@ BMLog *BM_log_unfreeze(BMesh *bm, BMLogEntry *entry)
|
|||
/* Free all the data in a BMLog including the log itself
|
||||
* safe_mode means log->refcount will be checked, and if nonzero log will not be freed
|
||||
*/
|
||||
bool BM_log_free(BMLog *log, bool safe_mode)
|
||||
static bool bm_log_free_direct(BMLog *log, bool safe_mode)
|
||||
{
|
||||
BMLogEntry *entry;
|
||||
|
||||
|
@ -998,6 +1002,8 @@ bool BM_log_free(BMLog *log, bool safe_mode)
|
|||
return false;
|
||||
}
|
||||
|
||||
log->dead = true;
|
||||
|
||||
BLI_rw_mutex_end(&log->lock);
|
||||
|
||||
if (log->unused_ids) {
|
||||
|
@ -1018,11 +1024,24 @@ bool BM_log_free(BMLog *log, bool safe_mode)
|
|||
entry->log = NULL;
|
||||
}
|
||||
|
||||
MEM_freeN(log);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BM_log_free(BMLog *log, bool safe_mode)
|
||||
{
|
||||
if (log->dead) {
|
||||
MEM_freeN(log);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bm_log_free_direct(log, safe_mode)) {
|
||||
MEM_freeN(log);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the number of log entries */
|
||||
int BM_log_length(const BMLog *log)
|
||||
{
|
||||
|
@ -1127,6 +1146,12 @@ BMLogEntry *BM_log_entry_add(BMesh *bm, BMLog *log)
|
|||
|
||||
BMLogEntry *BM_log_entry_add_ex(BMesh *bm, BMLog *log, bool combine_with_last)
|
||||
{
|
||||
if (log->dead) {
|
||||
fprintf(stderr, "BMLog Error: log is dead\n");
|
||||
fflush(stderr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log->bm = bm;
|
||||
|
||||
/* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
#define ELE_OUT 1
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
|
||||
void bmo_symmetrize_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
const float dist = BMO_slot_float_get(op->slots_in, "dist");
|
||||
|
@ -96,6 +98,10 @@ void bmo_symmetrize_exec(BMesh *bm, BMOperator *op)
|
|||
slot_targetmap = BMO_slot_get(op_weld.slots_in, "targetmap");
|
||||
|
||||
BMO_ITER (v, &siter, op_bisect.slots_out, "geom_cut.out", BM_VERT) {
|
||||
if (!BM_vert_is_boundary(v)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BMVert *v_dupe = BMO_slot_map_elem_get(slot_vertmap, v);
|
||||
BMO_slot_map_elem_insert(&op_weld, slot_targetmap, v_dupe, v);
|
||||
}
|
||||
|
|
|
@ -872,7 +872,7 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, SculptVertRef index)
|
|||
}
|
||||
}
|
||||
|
||||
return ret < 0 ? 0 : ret;
|
||||
return ret;
|
||||
}
|
||||
case PBVH_GRIDS: {
|
||||
const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
|
||||
|
@ -925,6 +925,54 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, SculptVertRef index, int face
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
calcs visibility state based on face sets.
|
||||
todo: also calc a face set boundary flag.
|
||||
*/
|
||||
void sculpt_vertex_faceset_update_bmesh(SculptSession *ss, SculptVertRef vert)
|
||||
{
|
||||
if (!ss->bm) {
|
||||
return;
|
||||
}
|
||||
|
||||
BMVert *v = (BMVert *)vert.i;
|
||||
BMEdge *e = v->e;
|
||||
bool ok = false;
|
||||
const int cd_faceset_offset = ss->cd_faceset_offset;
|
||||
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
BMLoop *l = e->l;
|
||||
if (l) {
|
||||
do {
|
||||
if (BM_ELEM_CD_GET_INT(l->f, cd_faceset_offset) > 0) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
|
||||
l = l->radial_next;
|
||||
} while (l != e->l);
|
||||
|
||||
if (ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
e = v == e->v1 ? e->v1_disk_link.next : e->v2_disk_link.next;
|
||||
} while (e != v->e);
|
||||
|
||||
MDynTopoVert *mv = BM_ELEM_CD_GET_VOID_P(v, ss->cd_dyn_vert);
|
||||
|
||||
if (ok) {
|
||||
mv->flag &= ~DYNVERT_VERT_FSET_HIDDEN;
|
||||
}
|
||||
else {
|
||||
mv->flag |= DYNVERT_VERT_FSET_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
void SCULPT_visibility_sync_all_face_sets_to_vertices(Object *ob)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
@ -956,6 +1004,8 @@ void SCULPT_visibility_sync_all_face_sets_to_vertices(Object *ob)
|
|||
}
|
||||
|
||||
BM_ITER_MESH (v, &iter, ss->bm, BM_VERTS_OF_MESH) {
|
||||
MDynTopoVert *mv = BM_ELEM_CD_GET_VOID_P(v, ss->cd_dyn_vert);
|
||||
|
||||
BMIter iter2;
|
||||
BMLoop *l;
|
||||
|
||||
|
@ -969,9 +1019,11 @@ void SCULPT_visibility_sync_all_face_sets_to_vertices(Object *ob)
|
|||
}
|
||||
|
||||
if (!visible) {
|
||||
mv->flag |= DYNVERT_VERT_FSET_HIDDEN;
|
||||
BM_elem_flag_enable(v, BM_ELEM_HIDDEN);
|
||||
}
|
||||
else {
|
||||
mv->flag &= ~DYNVERT_VERT_FSET_HIDDEN;
|
||||
BM_elem_flag_disable(v, BM_ELEM_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
@ -1279,49 +1331,57 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
|
|||
iter->neighbor_indices = iter->neighbor_indices_fixed;
|
||||
iter->i = 0;
|
||||
|
||||
#if 1
|
||||
// cache profiling revealed a hotspot here, don't use BM_ITER
|
||||
BMEdge *e = v->e;
|
||||
|
||||
if (!v->e) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (v == e->v1) {
|
||||
sculpt_vertex_neighbor_add_nocheck(
|
||||
iter, BKE_pbvh_make_vref((intptr_t)e->v2), BM_elem_index_get(e->v2));
|
||||
const bool have_facesets = ss->cd_faceset_offset >= 0;
|
||||
const int cd_faceset_offset = ss->cd_faceset_offset;
|
||||
|
||||
e = e->v1_disk_link.next;
|
||||
do {
|
||||
BMVert *v2;
|
||||
BMEdge *e2;
|
||||
|
||||
if (v == e->v1) {
|
||||
v2 = e->v2;
|
||||
e2 = e->v1_disk_link.next;
|
||||
}
|
||||
else {
|
||||
sculpt_vertex_neighbor_add_nocheck(
|
||||
iter, BKE_pbvh_make_vref((intptr_t)e->v1), BM_elem_index_get(e->v1));
|
||||
v2 = e->v1;
|
||||
e2 = e->v2_disk_link.next;
|
||||
}
|
||||
|
||||
e = e->v2_disk_link.next;
|
||||
// TODO: cache this in MDynTopoVert to avoid excessive DRAM fetches
|
||||
BMLoop *l = e->l;
|
||||
bool ok = false;
|
||||
|
||||
#if 0
|
||||
if (l && have_facesets) {
|
||||
do {
|
||||
if (BM_ELEM_CD_GET_INT(l->f, cd_faceset_offset) > 0) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
|
||||
l = l->radial_next;
|
||||
} while (l != e->l);
|
||||
}
|
||||
else {
|
||||
ok = true;
|
||||
}
|
||||
#else
|
||||
ok = true;
|
||||
#endif
|
||||
|
||||
e = e2;
|
||||
if (ok) {
|
||||
sculpt_vertex_neighbor_add_nocheck(
|
||||
iter, BKE_pbvh_make_vref((intptr_t)v2), BM_elem_index_get(v2));
|
||||
}
|
||||
} while (e != v->e);
|
||||
#elif 0 // note that BM_EDGES_OF_VERT should be faster then BM_LOOPS_OF_VERT
|
||||
BMEdge *e;
|
||||
BM_ITER_ELEM (e, &liter, v, BM_EDGES_OF_VERT) {
|
||||
BMVert *v_other = BM_edge_other_vert(e, v);
|
||||
|
||||
sculpt_vertex_neighbor_add(
|
||||
iter, BKE_pbvh_make_vref((intptr_t)v_other), BM_elem_index_get(v_other));
|
||||
}
|
||||
#else
|
||||
|
||||
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
|
||||
const BMVert *adj_v[2] = {l->prev->v, l->next->v};
|
||||
for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
|
||||
const BMVert *v_other = adj_v[i];
|
||||
|
||||
if (v_other != (BMVert *)index.i) {
|
||||
sculpt_vertex_neighbor_add(
|
||||
iter, BKE_pbvh_make_vref((intptr_t)v_other), BM_elem_index_get(v_other));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
|
||||
|
|
|
@ -488,8 +488,10 @@ static void bmesh_undo_on_vert_change(BMVert *v, void *userdata, void *old_custo
|
|||
|
||||
BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, oldnode_i);
|
||||
|
||||
PBVHNode *node = BKE_pbvh_node_from_index(data->pbvh, oldnode_i);
|
||||
BKE_pbvh_node_mark_update(node);
|
||||
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)
|
||||
|
|
|
@ -543,7 +543,7 @@ typedef struct MDynTopoVert {
|
|||
} MDynTopoVert;
|
||||
|
||||
/*MDynTopoVert->flag*/
|
||||
enum { DYNVERT_BOUNDARY = (1 << 0) };
|
||||
enum { DYNVERT_BOUNDARY = (1 << 0), DYNVERT_VERT_FSET_HIDDEN = (1 << 1) };
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue