Dyntopo now updates the existing pbvh on undo instead of building

a new one from scratch, an operation that can be slow despite being
  threaded.

PBVH building is a memory bound operation (not just on the CPU side
either, remember the draw buffers have to be fully regenerated too).
Incrementally updating it this way is enormously faster (about as fast
as non-dyntopo undo).

The downside is we don't have the convienience of users regularly
building the pbvh from scratch anymore.  Dyntopo does try to
join empty PBVH nodes (which happens after every stroke), but
that's not a complete substitute for a decent tree balancer.
That's on the todo list.
This commit is contained in:
Joseph Eagar 2021-05-15 21:19:20 -07:00
parent 27f4f761e7
commit 7fca310f25
10 changed files with 653 additions and 116 deletions

View File

@ -68,6 +68,7 @@ typedef struct PBVHTriBuf {
// private field
intptr_t *loops;
int totloop;
float min[3], max[3];
} PBVHTriBuf;
struct BMLog;
@ -702,7 +703,10 @@ void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node);
/*recalculates boundary flags for *all* vertices. used by
symmetrize.*/
void BKE_pbvh_recalc_bmesh_boundary(PBVH *pbvh);
void BKE_pbvh_bmesh_face_kill(PBVH *pbvh, struct BMFace *f);
void BKE_pbvh_bmesh_remove_face(PBVH *pbvh, struct BMFace *f, bool log_face);
void BKE_pbvh_bmesh_remove_vertex(PBVH *pbvh, struct BMVert *v, bool log_vert);
void BKE_pbvh_bmesh_add_face(PBVH *pbvh, struct BMFace *f, bool log_face, bool force_tree_walk);
// note that e_tri and f_example are allowed to be NULL
struct BMFace *BKE_pbvh_face_create_bmesh(PBVH *pbvh,

View File

@ -1021,11 +1021,14 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
{
/* never match for first time */
int f_node_index_prev = DYNTOPO_NODE_NONE;
const int updateflag = PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_UpdateTris |
PBVH_UpdateNormals;
PBVHNode *v_node = pbvh_bmesh_node_from_vert(pbvh, v);
if (v_node) {
BLI_table_gset_remove(v_node->bm_unique_verts, v, NULL);
v_node->flag |= updateflag;
}
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
@ -1045,7 +1048,7 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
f_node_index_prev = f_node_index;
PBVHNode *f_node = &pbvh->nodes[f_node_index];
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_UpdateTris;
f_node->flag |= updateflag;
/* Remove current ownership */
BLI_table_gset_remove(f_node->bm_other_verts, v, NULL);
@ -1057,15 +1060,16 @@ 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)
static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f, bool log_face)
{
PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
if (!f_node) {
if (!f_node || !(f_node->flag & PBVH_Leaf)) {
printf("pbvh corruption\n");
fflush(stdout);
return;
}
/* Check if any of this face's vertices need to be removed
* from the node */
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
@ -1083,6 +1087,10 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
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);
}
}
else {
/* Remove from other verts */
@ -1096,16 +1104,204 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
/* Log removed face */
BM_log_face_removed(pbvh->bm_log, f);
if (log_face) {
BM_log_face_removed(pbvh->bm_log, f);
}
/* mark node for update */
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateTris;
}
void BKE_pbvh_bmesh_face_kill(PBVH *pbvh, BMFace *f)
void BKE_pbvh_bmesh_remove_face(PBVH *pbvh, BMFace *f, bool log_face)
{
pbvh_bmesh_face_remove(pbvh, f);
BM_face_kill(pbvh->bm, f);
pbvh_bmesh_face_remove(pbvh, f, log_face);
}
void BKE_pbvh_bmesh_remove_vertex(PBVH *pbvh, BMVert *v, bool log_vert)
{
pbvh_bmesh_vert_remove(pbvh, v);
if (log_vert) {
BM_log_vert_removed(pbvh->bm_log, v, pbvh->cd_vert_mask_offset);
}
}
static bool point_in_node(const PBVHNode *node, const float co[3])
{
return co[0] >= node->vb.bmin[0] && co[0] <= node->vb.bmax[0] && co[1] >= node->vb.bmin[1] &&
co[1] <= node->vb.bmax[1] && co[2] >= node->vb.bmin[2] && co[2] <= node->vb.bmax[2];
}
static void bke_pbvh_insert_face_finalize(PBVH *pbvh, BMFace *f, const int ni)
{
PBVHNode *node = pbvh->nodes + ni;
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, ni);
BLI_table_gset_add(node->bm_faces, f);
int updateflag = PBVH_UpdateTris | PBVH_UpdateBB | PBVH_UpdateDrawBuffers |
PBVH_UpdateCurvatureDir;
updateflag |= PBVH_UpdateColor | PBVH_UpdateMask | PBVH_UpdateNormals | PBVH_UpdateOriginalBB;
updateflag |= PBVH_UpdateVisibility | PBVH_UpdateRedraw;
node->flag |= updateflag;
// ensure verts are in pbvh
BMLoop *l = f->l_first;
do {
const int ni2 = BM_ELEM_CD_GET_INT(l->v, pbvh->cd_vert_node_offset);
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, l->v);
BB_expand(&node->vb, l->v->co);
BB_expand(&node->orig_vb, mv->origco);
if (ni2 == DYNTOPO_NODE_NONE) {
BM_ELEM_CD_SET_INT(l->v, pbvh->cd_vert_node_offset, ni);
BLI_table_gset_add(node->bm_unique_verts, l->v);
}
else {
PBVHNode *node2 = pbvh->nodes + ni2;
BLI_table_gset_add(node->bm_other_verts, l->v);
node2->flag |= updateflag;
BB_expand(&node2->vb, l->v->co);
BB_expand(&node2->orig_vb, mv->origco);
}
l = l->next;
} while (l != f->l_first);
}
static void bke_pbvh_insert_face(PBVH *pbvh, struct BMFace *f)
{
int i = 0;
bool ok = false;
int ni = -1;
#if 1
while (i < pbvh->totnode) {
PBVHNode *node = pbvh->nodes + i;
bool ok2 = false;
if (node->flag & PBVH_Leaf) {
ok = true;
ni = i;
break;
}
if (node->children_offset == 0) {
continue;
}
for (int j = 0; j < 2; j++) {
int ni2 = node->children_offset + j;
if (ni2 == 0) {
continue;
}
PBVHNode *node2 = pbvh->nodes + ni2;
BMLoop *l = f->l_first;
do {
if (point_in_node(node2, l->v->co)) {
i = ni2;
ok2 = true;
break;
}
l = l->next;
} while (l != f->l_first);
if (ok2) {
break;
}
}
if (!ok2) {
break;
}
}
#endif
if (!ok) {
// find closest node
float co[3];
int tot = 0;
BMLoop *l = f->l_first;
zero_v3(co);
do {
add_v3_v3(co, l->v->co);
l = l->next;
tot++;
} while (l != f->l_first);
mul_v3_fl(co, 1.0f / (float)tot);
float mindis = 1e17;
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *node = pbvh->nodes + i;
if (!(node->flag & PBVH_Leaf)) {
continue;
}
float cent[3];
add_v3_v3v3(cent, node->vb.bmin, node->vb.bmax);
mul_v3_fl(cent, 0.5f);
float dis = len_squared_v3v3(co, cent);
if (dis < mindis) {
mindis = dis;
ni = i;
}
}
}
if (ni < 0) {
fprintf(stderr, "pbvh error!\n");
fflush(stderr);
return;
}
bke_pbvh_insert_face_finalize(pbvh, f, ni);
}
void BKE_pbvh_bmesh_add_face(PBVH *pbvh, struct BMFace *f, bool log_face, bool force_tree_walk)
{
int ni = -1;
// look for node in surrounding geometry
BMLoop *l = f->l_first;
do {
ni = BM_ELEM_CD_GET_INT(l->radial_next->f, pbvh->cd_face_node_offset);
if (ni >= 0 && (!(pbvh->nodes[ni].flag & PBVH_Leaf) || ni >= pbvh->totnode)) {
printf("EEK! ni: %d totnode: %d\n", ni, pbvh->totnode);
l = l->next;
continue;
}
if (ni >= 0 && (pbvh->nodes[ni].flag & PBVH_Leaf)) {
break;
}
l = l->next;
} while (l != f->l_first);
if (ni < 0 || force_tree_walk) {
bke_pbvh_insert_face(pbvh, f);
}
else {
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, ni);
bke_pbvh_insert_face_finalize(pbvh, f, ni);
}
if (log_face) {
BM_log_face_added(pbvh->bm_log, f);
}
}
static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e)
@ -1770,7 +1966,7 @@ static void long_edge_queue_edge_add_recursive(EdgeQueueContext *eq_ctx,
BMLoop *l_iter = l_edge;
do {
BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
for (int i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
for (int i = 0; i < (int)ARRAY_SIZE(l_adjacent); i++) {
float len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
// edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other);
@ -1892,7 +2088,7 @@ static void short_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata,
BMLoop *l_iter = l_edge;
do {
BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
for (int i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
for (int i = 0; i < (int)ARRAY_SIZE(l_adjacent); i++) {
float len_sq_other = calc_weighted_edge_collapse(
tdata->eq_ctx, l_adjacent[i]->e->v1, l_adjacent[i]->e->v2);
@ -1948,7 +2144,7 @@ static void long_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata,
BMLoop *l_iter = l_edge;
do {
BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
for (int i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
for (int i = 0; i < (int)ARRAY_SIZE(l_adjacent); i++) {
float len_sq_other = calc_weighted_edge_split(
tdata->eq_ctx, l_adjacent[i]->e->v1, l_adjacent[i]->e->v2);
@ -2337,7 +2533,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
}
/* For each face, add two new triangles and delete the original */
for (int i = 0; i < edge_loops->count; i++) {
for (int i = 0; i < (int)edge_loops->count; i++) {
BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i);
BMFace *f_adj = l_adj->f;
BMFace *f_new;
@ -2464,7 +2660,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);
pbvh_bmesh_face_remove(pbvh, f_adj, true);
BM_face_kill(pbvh->bm, f_adj);
/* Ensure new vertex is in the node */
@ -2645,7 +2841,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);
pbvh_bmesh_face_remove(pbvh, f_adj, true);
BM_face_kill(pbvh->bm, f_adj);
}
@ -2660,7 +2856,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
* really buy anything. */
BLI_buffer_clear(deleted_faces);
BMLoop *l;
BMLoop *l = NULL;
BMLoop **ls = NULL;
void **blocks = NULL;
float *ws = NULL;
@ -2741,7 +2937,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
bool ok = true;
// check we're not already in deleted_faces
for (int i = 0; i < deleted_faces->count; i++) {
for (int i = 0; i < (int)deleted_faces->count; i++) {
if (BLI_buffer_at(deleted_faces, BMFace *, i) == existing_face) {
ok = false;
break;
@ -2788,7 +2984,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
BM_LOOPS_OF_VERT_ITER_END;
/* Delete the tagged faces */
for (int i = 0; i < deleted_faces->count; i++) {
for (int i = 0; i < (int)deleted_faces->count; i++) {
BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i);
/* Get vertices and edges of face */
@ -2809,17 +3005,17 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
do {
if (!l1->e) {
printf("bmesh error!\n");
l1->e = BM_edge_exists(l->v, l->next->v);
l1->e = BM_edge_exists(l1->v, l1->next->v);
if (!l1->e) {
// create
l1->e = BM_edge_create(pbvh->bm, l->v, l->next->v, NULL, 0);
l1->e = BM_edge_create(pbvh->bm, l1->v, l1->next->v, NULL, 0);
}
}
l1 = l1->next;
} while (l1 != f_del->l_first);
/* Remove the face */
pbvh_bmesh_face_remove(pbvh, f_del);
pbvh_bmesh_face_remove(pbvh, f_del, true);
BM_face_kill(pbvh->bm, f_del);
/* Check if any of the face's edges are now unused by any
@ -3826,7 +4022,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);
pbvh_bmesh_face_remove(pbvh, f, true);
}
}
@ -4259,6 +4455,10 @@ void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
GHash *vmap = BLI_ghash_ptr_new("pbvh_bmesh.c vmap");
BMFace *f;
float min[3], max[3];
INIT_MINMAX(min, max);
TGSET_ITER (f, node->bm_faces) {
BMVert *v1 = f->l_first->v;
BMVert *v2 = f->l_first->next->v;
@ -4275,6 +4475,8 @@ void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
if (!BLI_ghash_ensure_p(vmap, l->v, &val)) {
SculptVertRef sv = {(intptr_t)l->v};
minmax_v3v3_v3(min, max, l->v->co);
*val = (void *)BLI_array_len(verts);
BLI_array_append(verts, sv);
}
@ -4304,6 +4506,15 @@ void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
node->tribuf->verts = verts;
node->tribuf->totvert = BLI_array_len(verts);
if (node->tribuf->totvert) {
copy_v3_v3(node->tribuf->min, min);
copy_v3_v3(node->tribuf->max, max);
}
else {
zero_v3(node->tribuf->min);
zero_v3(node->tribuf->max);
}
BLI_ghash_free(vmap, NULL, NULL);
}
@ -4368,16 +4579,14 @@ static void pbvh_bmesh_join_subnodes(PBVH *pbvh, PBVHNode *node, PBVHNode *paren
TGSET_ITER_END
}
static void BKE_pbvh_bmesh_corect_tree(PBVH *pbvh, PBVHNode *node, PBVHNode *parent)
static void BKE_pbvh_bmesh_correct_tree(PBVH *pbvh, PBVHNode *node, PBVHNode *parent)
{
const int size_lower = pbvh->leaf_limit - (pbvh->leaf_limit >> 1);
const int size_higher = pbvh->leaf_limit + (pbvh->leaf_limit >> 1);
if (node->flag & PBVH_Leaf) {
// pbvh_trimesh_node_limit_ensure(pbvh, (int)(node - pbvh->nodes));
// pbvh_bmesh_node_limit_ensure(pbvh, (int)(node - pbvh->nodes));
return;
// join nodes if subtree lacks verts, unless node is root
}
if (node->subtree_tottri < size_lower && node != pbvh->nodes) {
@ -4443,7 +4652,7 @@ static void BKE_pbvh_bmesh_corect_tree(PBVH *pbvh, PBVHNode *node, PBVHNode *par
for (int i = 0; i < 2; i++, ni++) {
PBVHNode *child = pbvh->nodes + ni;
BKE_pbvh_bmesh_corect_tree(pbvh, child, node);
BKE_pbvh_bmesh_correct_tree(pbvh, child, node);
}
}
@ -4454,7 +4663,7 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
}
pbvh_count_subtree_verts(bvh, bvh->nodes);
BKE_pbvh_bmesh_corect_tree(bvh, bvh->nodes, NULL);
BKE_pbvh_bmesh_correct_tree(bvh, bvh->nodes, NULL);
// compact nodes
int totnode = 0;
@ -5027,7 +5236,7 @@ static void scan_edge_split(BMesh *bm, BMEdge **edges, int totedge)
f2->head.data = BLI_mempool_alloc(bm->ldata.pool);
BMLoop *prev = NULL;
BMLoop *l2;
BMLoop *l2 = NULL;
for (int j = 0; j < 3; j++) {
l2 = BLI_mempool_alloc(bm->lpool);

View File

@ -411,7 +411,8 @@ 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, BMLogEntry *entry)
static void bm_log_verts_unmake(
BMesh *bm, BMLog *log, GHash *verts, BMLogEntry *entry, BMLogCallbacks *callbacks)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
@ -426,11 +427,16 @@ static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts, BMLogEntry
* deleting it */
bm_log_vert_bmvert_copy(log, entry, lv, v, cd_vert_mask_offset, true);
if (callbacks) {
callbacks->on_vert_kill(v, callbacks->userdata);
}
BM_vert_kill(bm, v);
}
}
static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry)
static void bm_log_faces_unmake(
BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry, BMLogCallbacks *callbacks)
{
GHashIterator gh_iter;
GHASH_ITER (gh_iter, faces) {
@ -469,6 +475,10 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces, BMLogEntry
}
#endif
if (callbacks) {
callbacks->on_face_kill(f, callbacks->userdata);
}
BM_face_kill(bm, f);
/* Remove any unused edges */
@ -480,7 +490,8 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces, BMLogEntry
}
}
static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts, BMLogEntry *entry)
static void bm_log_verts_restore(
BMesh *bm, BMLog *log, GHash *verts, BMLogEntry *entry, BMLogCallbacks *callbacks)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
@ -499,10 +510,15 @@ 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 (callbacks) {
callbacks->on_vert_add(v, callbacks->userdata);
}
}
}
static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry)
static void bm_log_faces_restore(
BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry, BMLogCallbacks *callbacks)
{
GHashIterator gh_iter;
GHASH_ITER (gh_iter, faces) {
@ -533,13 +549,20 @@ static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces, BMLogEntry
}
}
#endif
if (callbacks) {
callbacks->on_face_add(f, callbacks->userdata);
}
}
}
static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts, BMLogEntry *entry)
static void bm_log_vert_values_swap(
BMesh *bm, BMLog *log, GHash *verts, BMLogEntry *entry, BMLogCallbacks *callbacks)
{
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
void *scratch = bm->vdata.pool ? BLI_mempool_alloc(bm->vdata.pool) : NULL;
GHashIterator gh_iter;
GHASH_ITER (gh_iter, verts) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
@ -559,15 +582,34 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts, BMLogEn
vert_mask_set(v, mask, cd_vert_mask_offset);
#ifdef CUSTOMDATA
void *old_cdata = NULL;
if (lv->customdata) {
if (v->head.data) {
old_cdata = scratch;
memcpy(old_cdata, v->head.data, bm->vdata.totsize);
}
CustomData_bmesh_swap_data(&entry->vdata, &bm->vdata, lv->customdata, &v->head.data);
}
if (callbacks) {
callbacks->on_vert_change(v, callbacks->userdata, old_cdata);
}
#endif
}
if (scratch) {
BLI_mempool_free(bm->vdata.pool, scratch);
}
}
static void bm_log_face_values_swap(BMLog *log, GHash *faces, BMLogEntry *entry)
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;
GHashIterator gh_iter;
GHASH_ITER (gh_iter, faces) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
@ -577,7 +619,14 @@ static void bm_log_face_values_swap(BMLog *log, GHash *faces, BMLogEntry *entry)
SWAP(char, f->head.hflag, lf->hflag);
void *old_cdata = NULL;
#ifdef CUSTOMDATA
if (f->head.data) {
old_cdata = scratch;
memcpy(old_cdata, f->head.data, log->bm->pdata.totsize);
}
if (lf->customdata_f) {
CustomData_bmesh_swap_data(&entry->pdata, &log->bm->pdata, lf->customdata_f, &f->head.data);
}
@ -591,6 +640,14 @@ static void bm_log_face_values_swap(BMLog *log, GHash *faces, BMLogEntry *entry)
}
}
#endif
if (callbacks) {
callbacks->on_face_change(f, callbacks->userdata, old_cdata);
}
}
if (scratch) {
BLI_mempool_free(log->bm->pdata.pool, scratch);
}
}
@ -1315,30 +1372,35 @@ static void full_copy_swap(BMesh *bm, BMLog *log, BMLogEntry *entry)
/* Undo one BMLogEntry
*
* Has no effect if there's nothing left to undo */
static void bm_log_undo_intern(BMesh *bm, BMLog *log, BMLogEntry *entry)
static void bm_log_undo_intern(
BMesh *bm, BMLog *log, BMLogEntry *entry, BMLogCallbacks *callbacks, const char *node_layer_id)
{
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);
if (callbacks) {
callbacks->on_full_mesh_load(callbacks->userdata);
}
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);
bm_log_faces_unmake(bm, log, entry->added_faces, entry, callbacks);
bm_log_verts_unmake(bm, log, entry->added_verts, entry, callbacks);
/* 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);
bm_log_verts_restore(bm, log, entry->deleted_verts, entry, callbacks);
bm_log_faces_restore(bm, log, entry->deleted_faces, entry, callbacks);
/* 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);
bm_log_vert_values_swap(bm, log, entry->modified_verts, entry, callbacks);
bm_log_face_values_swap(log, entry->modified_faces, entry, callbacks);
}
void BM_log_undo(BMesh *bm, BMLog *log)
void BM_log_undo(BMesh *bm, BMLog *log, BMLogCallbacks *callbacks, const char *node_layer_id)
{
BMLogEntry *entry = log->current_entry;
log->bm = bm;
@ -1350,7 +1412,7 @@ void BM_log_undo(BMesh *bm, BMLog *log)
BMLogEntry *preventry = entry->prev;
while (entry) {
bm_log_undo_intern(bm, log, entry);
bm_log_undo_intern(bm, log, entry, callbacks, node_layer_id);
entry = entry->combined_prev;
}
@ -1360,11 +1422,16 @@ void BM_log_undo(BMesh *bm, BMLog *log)
/* 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)
static void bm_log_redo_intern(
BMesh *bm, BMLog *log, BMLogEntry *entry, BMLogCallbacks *callbacks, const char *node_layer_id)
{
if (entry->fully_copy) {
// hrm, should we swap?
full_copy_swap(bm, log, entry);
if (callbacks) {
callbacks->on_full_mesh_load(callbacks->userdata);
}
return;
}
@ -1372,19 +1439,19 @@ static void bm_log_redo_intern(BMesh *bm, BMLog *log, BMLogEntry *entry)
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);
bm_log_faces_unmake(bm, log, entry->deleted_faces, entry, callbacks);
bm_log_verts_unmake(bm, log, entry->deleted_verts, entry, callbacks);
/* 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);
bm_log_verts_restore(bm, log, entry->added_verts, entry, callbacks);
bm_log_faces_restore(bm, log, entry->added_faces, entry, callbacks);
/* 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);
bm_log_vert_values_swap(bm, log, entry->modified_verts, entry, callbacks);
bm_log_face_values_swap(log, entry->modified_faces, entry, callbacks);
}
void BM_log_redo(BMesh *bm, BMLog *log)
void BM_log_redo(BMesh *bm, BMLog *log, BMLogCallbacks *callbacks, const char *node_layer_id)
{
BMLogEntry *entry = log->current_entry;
log->bm = bm;
@ -1410,7 +1477,7 @@ void BM_log_redo(BMesh *bm, BMLog *log)
}
while (entry) {
bm_log_redo_intern(bm, log, entry);
bm_log_redo_intern(bm, log, entry, callbacks, node_layer_id);
entry = entry->combined_next;
}

View File

@ -28,6 +28,19 @@ struct RangeTreeUInt;
typedef struct BMLog BMLog;
typedef struct BMLogEntry BMLogEntry;
typedef struct BMLogCallbacks {
void (*on_vert_add)(struct BMVert *v, void *userdata);
void (*on_vert_kill)(struct BMVert *v, void *userdata);
void (*on_vert_change)(struct BMVert *v, void *userdata, void *old_customdata);
void (*on_face_add)(struct BMFace *f, void *userdata);
void (*on_face_kill)(struct BMFace *f, void *userdata);
void (*on_face_change)(struct BMFace *f, void *userdata, void *old_customdata);
void (*on_full_mesh_load)(void *userdata);
void *userdata;
} BMLogCallbacks;
/* Allocate and initialize a new BMLog */
BMLog *BM_log_create(BMesh *bm, int cd_dyn_vert);
void BM_log_set_cd_offsets(BMLog *log, int cd_dyn_vert);
@ -42,7 +55,7 @@ BMLog *BM_log_unfreeze(BMesh *bm, BMLogEntry *entry);
void BM_log_set_bm(BMesh *bm, BMLog *log);
/* Get the number of log entries */
/* Get the number of log entries */
int BM_log_length(const BMLog *log);
/* Apply a consistent ordering to BMesh vertices and faces */
@ -60,11 +73,12 @@ void BM_log_cleanup_entry(BMLogEntry *entry);
/* Remove an entry from the log */
void BM_log_entry_drop(BMLogEntry *entry);
/* Undo one BMLogEntry */
void BM_log_undo(BMesh *bm, BMLog *log);
/* Undo one BMLogEntry. node_layer_id is necassary to preserve node idxs with customdata, whose
* layout might have changed */
void BM_log_undo(BMesh *bm, BMLog *log, BMLogCallbacks *callbacks, const char *node_layer_id);
/* Redo one BMLogEntry */
void BM_log_redo(BMesh *bm, BMLog *log);
void BM_log_redo(BMesh *bm, BMLog *log, BMLogCallbacks *callbacks, const char *node_layer_id);
/* Log a vertex before it is modified */
void BM_log_vert_before_modified(BMLog *log,

View File

@ -514,10 +514,10 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
drw_call_calc_orco(ob, ob_infos->orcotexfac);
/* Random float value. */
uint random = (DST.dupli_source) ?
DST.dupli_source->random_id :
/* TODO(fclem): this is rather costly to do at runtime. Maybe we can
* put it in ob->runtime and make depsgraph ensure it is up to date. */
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
DST.dupli_source->random_id :
/* TODO(fclem): this is rather costly to do at runtime. Maybe we can
* put it in ob->runtime and make depsgraph ensure it is up to date. */
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF);
/* Object State. */
ob_infos->ob_flag = 1.0f; /* Required to have a correct sign */
@ -933,9 +933,23 @@ static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers
DRW_shgroup_uniform_vec3(
shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->debug_node_nr++), 1);
}
#if 0
float extramat[4][4], mat[4][4];
float *extra = GPU_pbvh_get_extra_matrix(buffers);
if (extra) {
memcpy(extramat, GPU_pbvh_get_extra_matrix(buffers), sizeof(float) * 16);
mul_m4_m4m4(mat, scd->ob->obmat, extramat);
}
else {
copy_m4_m4(mat, scd->ob->obmat);
}
DRW_shgroup_call_obmat(shgrp, geom, mat);
#else
/* DRW_shgroup_call_no_cull reuses matrices calculations for all the drawcalls of this
* object. */
DRW_shgroup_call_no_cull(shgrp, geom, scd->ob);
#endif
}
}
@ -1042,7 +1056,8 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
&update_frustum,
&draw_frustum,
(void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb,
scd, scd->active_vcol_only);
scd,
scd->active_vcol_only);
if (SCULPT_DEBUG_BUFFERS) {
int debug_node_nr = 0;
@ -1057,15 +1072,13 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
void DRW_shgroup_call_sculpt(DRWShadingGroup *shgroup, Object *ob, bool use_wire, bool use_mask)
{
DRWSculptCallbackData scd = {
.ob = ob,
.shading_groups = &shgroup,
.num_shading_groups = 1,
.use_wire = use_wire,
.use_mats = false,
.use_mask = use_mask,
.active_vcol_only = true
};
DRWSculptCallbackData scd = {.ob = ob,
.shading_groups = &shgroup,
.num_shading_groups = 1,
.use_wire = use_wire,
.use_mats = false,
.use_mask = use_mask,
.active_vcol_only = true};
drw_sculpt_generate_calls(&scd);
}
@ -1073,15 +1086,13 @@ void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **shgroups,
int num_shgroups,
Object *ob)
{
DRWSculptCallbackData scd = {
.ob = ob,
.shading_groups = shgroups,
.num_shading_groups = num_shgroups,
.use_wire = false,
.use_mats = true,
.use_mask = false,
.active_vcol_only = false
};
DRWSculptCallbackData scd = {.ob = ob,
.shading_groups = shgroups,
.num_shading_groups = num_shgroups,
.use_wire = false,
.use_mats = true,
.use_mask = false,
.active_vcol_only = false};
drw_sculpt_generate_calls(&scd);
}

View File

@ -248,7 +248,7 @@ void SCULPT_dyntopo_save_origverts(SculptSession *ss)
}
}
static char layer_id[] = "_dyntopo_node_id";
char dyntopop_node_idx_layer_id[] = "_dyntopo_node_id";
void SCULPT_dyntopo_node_layers_update_offsets(SculptSession *ss)
{
@ -303,21 +303,23 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
ss->bm->vdata.layers[cd_dyn_vert].flag |= CD_FLAG_TEMPORARY;
}
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT32, layer_id);
cd_node_layer_index = CustomData_get_named_layer_index(
&ss->bm->vdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
if (cd_node_layer_index == -1) {
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, layer_id);
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
}
cd_face_node_layer_index = CustomData_get_named_layer_index(
&ss->bm->pdata, CD_PROP_INT32, layer_id);
&ss->bm->pdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
if (cd_face_node_layer_index == -1) {
BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, layer_id);
BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
}
// get indices again, as they might have changed after adding new layers
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT32, layer_id);
cd_node_layer_index = CustomData_get_named_layer_index(
&ss->bm->vdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
cd_face_node_layer_index = CustomData_get_named_layer_index(
&ss->bm->pdata, CD_PROP_INT32, layer_id);
&ss->bm->pdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
ss->cd_origvcol_offset = -1;

View File

@ -718,7 +718,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
bm = sculpt_faceset_bm_begin(ss, mesh);
BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces");
const int totfaces = ss->totfaces; //mesh->totpoly;
const int totfaces = ss->totfaces; // mesh->totpoly;
if (!ss->bm) {
BM_mesh_elem_index_ensure(bm, BM_FACE);
@ -787,14 +787,14 @@ static void sculpt_face_sets_init_loop(Object *ob, const int mode)
Mesh *mesh = ob->data;
SculptSession *ss = ob->sculpt;
BMesh *bm = sculpt_faceset_bm_begin(ss, mesh);
BMIter iter;
BMFace *f;
const int cd_fmaps_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
SculptFaceRef fref = {(intptr_t) f};
SculptFaceRef fref = {(intptr_t)f};
if (mode == SCULPT_FACE_SETS_FROM_MATERIALS) {
SCULPT_face_set_set(ss, fref, (int)(f->mat_nr + 1));
@ -1004,7 +1004,8 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
break;
}
}
} else if (ss->bm) {
}
else if (ss->bm) {
BMIter iter;
BMFace *f;
@ -1450,7 +1451,7 @@ static void sculpt_face_set_delete_geometry(Object *ob,
}
for (int i = 0; i < BLI_array_len(faces); i++) {
BKE_pbvh_bmesh_face_kill(ss->pbvh, faces[i]);
BKE_pbvh_bmesh_remove_face(ss->pbvh, faces[i], true);
}
BLI_array_free(faces);

View File

@ -414,18 +414,129 @@ static void sculpt_undo_bmesh_restore_generic_task_cb(
BKE_pbvh_node_mark_redraw(nodes[n]);
}
extern const char dyntopop_node_idx_layer_id[];
typedef struct BmeshUndoData {
PBVH *pbvh;
BMesh *bm;
bool do_full_recalc;
bool balance_pbvh;
int cd_face_node_offset, cd_vert_node_offset;
} BmeshUndoData;
static void bmesh_undo_on_vert_kill(BMVert *v, void *userdata)
{
BmeshUndoData *data = (BmeshUndoData *)userdata;
// data->do_full_recalc = true;
BKE_pbvh_bmesh_remove_vertex(data->pbvh, v, false);
data->balance_pbvh = true;
}
static void bmesh_undo_on_vert_add(BMVert *v, void *userdata)
{
BmeshUndoData *data = (BmeshUndoData *)userdata;
BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1);
// data->do_full_recalc = true;
data->balance_pbvh = true;
}
static void bmesh_undo_on_face_kill(BMFace *f, void *userdata)
{
BmeshUndoData *data = (BmeshUndoData *)userdata;
BKE_pbvh_bmesh_remove_face(data->pbvh, f, false);
// data->do_full_recalc = true;
data->balance_pbvh = true;
}
static void bmesh_undo_on_face_add(BMFace *f, void *userdata)
{
BmeshUndoData *data = (BmeshUndoData *)userdata;
// data->do_full_recalc = true;
BM_ELEM_CD_SET_INT(f, data->cd_face_node_offset, -1);
BKE_pbvh_bmesh_add_face(data->pbvh, f, false, true);
data->balance_pbvh = true;
}
static void bmesh_undo_full_mesh(void *userdata)
{
BmeshUndoData *data = (BmeshUndoData *)userdata;
data->do_full_recalc = true;
}
static void bmesh_undo_on_vert_change(BMVert *v, void *userdata, void *old_customdata)
{
BmeshUndoData *data = (BmeshUndoData *)userdata;
if (!old_customdata) {
return;
}
if (!old_customdata) {
BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, -1);
return;
}
// preserve pbvh node references
BMVert h;
h.head.data = old_customdata;
int oldnode_i = BM_ELEM_CD_GET_INT(&h, data->cd_vert_node_offset);
BM_ELEM_CD_SET_INT(v, data->cd_vert_node_offset, oldnode_i);
}
static void bmesh_undo_on_face_change(BMFace *f, void *userdata, void *old_customdata)
{
BmeshUndoData *data = (BmeshUndoData *)userdata;
if (old_customdata) {
return;
}
if (!old_customdata) {
BM_ELEM_CD_SET_INT(f, data->cd_face_node_offset, -1);
return;
}
// preserve pbvh node references
BMFace h;
h.head.data = old_customdata;
int oldnode_i = BM_ELEM_CD_GET_INT(&h, data->cd_face_node_offset);
BM_ELEM_CD_SET_INT(f, data->cd_face_node_offset, oldnode_i);
}
static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob, SculptSession *ss)
{
BmeshUndoData data = {
ss->pbvh, ss->bm, false, false, ss->cd_face_node_offset, ss->cd_vert_node_offset};
BMLogCallbacks callbacks = {bmesh_undo_on_vert_add,
bmesh_undo_on_vert_kill,
bmesh_undo_on_vert_change,
bmesh_undo_on_face_add,
bmesh_undo_on_face_kill,
bmesh_undo_on_face_change,
bmesh_undo_full_mesh,
(void *)&data};
if (unode->applied) {
BM_log_undo(ss->bm, ss->bm_log);
BM_log_undo(ss->bm, ss->bm_log, &callbacks, dyntopop_node_idx_layer_id);
unode->applied = false;
}
else {
BM_log_redo(ss->bm, ss->bm_log);
BM_log_redo(ss->bm, ss->bm_log, &callbacks, dyntopop_node_idx_layer_id);
unode->applied = true;
}
if (unode->type == SCULPT_UNDO_MASK || unode->type == SCULPT_UNDO_COLOR) {
if (!data.do_full_recalc || unode->type == SCULPT_UNDO_MASK ||
unode->type == SCULPT_UNDO_COLOR) {
int totnode;
PBVHNode **nodes;
@ -439,6 +550,10 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob,
if (nodes) {
MEM_freeN(nodes);
}
if (data.balance_pbvh) {
BKE_pbvh_bmesh_after_stroke(ss->pbvh);
}
}
else {
SCULPT_pbvh_clear(ob);
@ -475,9 +590,9 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
}
static void sculpt_undo_bmesh_restore_begin(bContext *C,
SculptUndoNode *unode,
Object *ob,
SculptSession *ss)
SculptUndoNode *unode,
Object *ob,
SculptSession *ss)
{
if (unode->applied) {
SCULPT_dynamic_topology_disable(C, unode);
@ -487,22 +602,22 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C,
sculpt_undo_bmesh_enable(ob, unode);
/* Restore the mesh from the first log entry. */
BM_log_redo(ss->bm, ss->bm_log);
BM_log_redo(ss->bm, ss->bm_log, NULL, dyntopop_node_idx_layer_id);
unode->applied = true;
}
}
static void sculpt_undo_bmesh_restore_end(bContext *C,
SculptUndoNode *unode,
Object *ob,
SculptSession *ss)
SculptUndoNode *unode,
Object *ob,
SculptSession *ss)
{
if (unode->applied) {
sculpt_undo_bmesh_enable(ob, unode);
/* Restore the mesh from the last log entry. */
BM_log_undo(ss->bm, ss->bm_log);
BM_log_undo(ss->bm, ss->bm_log, NULL, dyntopop_node_idx_layer_id);
unode->applied = false;
}
@ -602,9 +717,9 @@ static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *object)
* Returns true if this was a dynamic-topology undo step, otherwise
* returns false to indicate the non-dyntopo code should run. */
static int sculpt_undo_bmesh_restore(bContext *C,
SculptUndoNode *unode,
Object *ob,
SculptSession *ss)
SculptUndoNode *unode,
Object *ob,
SculptSession *ss)
{
if (ss->bm_log && ss->bm) {
SCULPT_dyntopo_node_layers_update_offsets(ss);
@ -1341,7 +1456,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
sculpt_undo_geometry_store_data(geometry, ob);
unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
//BM_log_all_added(ss->bm, ss->bm_log);
// BM_log_all_added(ss->bm, ss->bm_log);
BM_log_full_mesh(ss->bm, ss->bm_log);
}
else {

View File

@ -89,7 +89,9 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
/** if active_vcol_only is true, only the active (not render!) layer will
be uploaded to GPU*/
void GPU_pbvh_update_attribute_names(struct CustomData *vdata, struct CustomData *ldata, bool active_vcol_only);
void GPU_pbvh_update_attribute_names(struct CustomData *vdata,
struct CustomData *ldata,
bool active_vcol_only);
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
@ -126,8 +128,8 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires);
short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers);
bool GPU_pbvh_buffers_has_overlays(GPU_PBVH_Buffers *buffers);
float *GPU_pbvh_get_extra_matrix(GPU_PBVH_Buffers *buffers);
#ifdef __cplusplus
}

View File

@ -60,6 +60,17 @@
/* XXX: the rest of the code in this file is used for optimized PBVH
* drawing and doesn't interact at all with the buffer code above */
/*
this tests a low-data draw mode. faceset and mask overlays must be disabled,
meshes cannot have uv layers, and DynTopo must be on, along with "draw smooth."
Normalizes coordinates to 16 bit integers, normals to 8-bit bytes, and skips
all other attributes.
To test, enable #if 0 branch in sculpt_draw_cb in draw_manager_data.c
*/
//#define QUANTIZED_PERF_TEST
struct GPU_PBVH_Buffers {
GPUIndexBuf *index_buf, *index_buf_fast;
GPUIndexBuf *index_lines_buf, *index_lines_buf_fast;
@ -99,6 +110,9 @@ struct GPU_PBVH_Buffers {
bool smooth;
bool show_overlay;
#ifdef QUANTIZED_PERF_TEST
float matrix[4][4];
#endif
};
static struct {
@ -156,8 +170,23 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
return GPU_vertbuf_get_data(buffers->vert_buf) != NULL;
}
float *GPU_pbvh_get_extra_matrix(GPU_PBVH_Buffers *buffers)
{
#ifdef QUANTIZED_PERF_TEST
return (float *)buffers->matrix;
#else
return NULL;
#endif
}
static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim)
{
#ifdef QUANTIZED_PERF_TEST
memset(buffers->matrix, 0, sizeof(buffers->matrix));
buffers->matrix[0][0] = buffers->matrix[1][1] = buffers->matrix[2][2] = buffers->matrix[3][3] =
1.0f;
#endif
if (buffers->triangles == NULL) {
buffers->triangles = GPU_batch_create(prim,
buffers->vert_buf,
@ -959,11 +988,24 @@ void GPU_pbvh_update_attribute_names(CustomData *vdata, CustomData *ldata, bool
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
if (g_vbo_id.format.attr_len == 0) {
#ifdef QUANTIZED_PERF_TEST
g_vbo_id.pos = GPU_vertformat_attr_add(
&g_vbo_id.format, "pos", GPU_COMP_U16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
g_vbo_id.nor = GPU_vertformat_attr_add(
&g_vbo_id.format, "nor", GPU_COMP_I8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
#else
g_vbo_id.pos = GPU_vertformat_attr_add(
&g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
g_vbo_id.nor = GPU_vertformat_attr_add(
&g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
#endif
/* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
#ifdef QUANTIZED_PERF_TEST
return;
#endif
g_vbo_id.msk = GPU_vertformat_attr_add(
&g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
@ -1288,7 +1330,6 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
const bool indexed = buffers->smooth && tribuf && !have_uv;
tottri = indexed ? tribuf->tottri : gpu_bmesh_face_visible_count(bm_faces);
// XXX disable indexed verts for now
if (indexed) {
/* Count visible vertices */
totvert = tribuf->totvert;
@ -1331,10 +1372,69 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
GHash *bm_vert_to_index = BLI_ghash_int_new_ex("bm_vert_to_index", totvert);
BMFace *f;
GPUVertBuf *vert_buf = buffers->vert_buf;
#ifdef QUANTIZED_PERF_TEST
float min[3];
float max[3];
float mat[4][4];
float imat[4][4];
float scale[3];
INIT_MINMAX(min, max);
for (int i = 0; i < tribuf->totvert; i++) {
BMVert *v = (BMVert *)tribuf->verts[i].i;
minmax_v3v3_v3(min, max, v->co);
}
sub_v3_v3v3(scale, max, min);
scale[0] = scale[0] != 0.0f ? 1.0f / scale[0] : 0.0f;
scale[1] = scale[1] != 0.0f ? 1.0f / scale[1] : 0.0f;
scale[2] = scale[2] != 0.0f ? 1.0f / scale[2] : 0.0f;
memset((float *)mat, 0, sizeof(float) * 16);
mat[0][0] = scale[0];
mat[1][1] = scale[1];
mat[2][2] = scale[2];
mat[3][0] = -min[0] * scale[0];
mat[3][1] = -min[1] * scale[1];
mat[3][2] = -min[2] * scale[2];
mat[3][3] = 1.0f;
invert_m4_m4(imat, mat);
#endif
for (int i = 0; i < tribuf->totvert; i++) {
BMVert *v = (BMVert *)tribuf->verts[i].i;
#ifdef QUANTIZED_PERF_TEST
float co[3];
copy_v3_v3(co, v->co);
mul_v3_m4v3(co, mat, co);
// sub_v3_v3(co, tribuf->min);
// mul_v3_v3(co, scale);
// normal_float_to_short_
unsigned short co_short[3];
co_short[0] = (unsigned short)(co[0] * 65535.0f);
co_short[1] = (unsigned short)(co[1] * 65535.0f);
co_short[2] = (unsigned short)(co[2] * 65535.0f);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, i, co_short);
signed char no_short[3];
// normal_float_to_short_v3(no_short, v->no);
no_short[0] = (signed char)(v->no[0] * 127.0f);
no_short[1] = (signed char)(v->no[1] * 127.0f);
no_short[2] = (signed char)(v->no[2] * 127.0f);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, i, no_short);
#else
gpu_bmesh_vert_to_buffer_copy(v,
buffers->vert_buf,
i,
@ -1347,6 +1447,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
&empty_mask,
cd_vcols,
cd_vcol_count);
#endif
}
for (int i = 0; i < tribuf->tottri; i++) {
@ -1354,9 +1455,11 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_add_tri_verts(&elb, tri->v[0], tri->v[1], tri->v[2]);
#ifndef QUANTIZED_PERF_TEST
GPU_indexbuf_add_line_verts(&elb_lines, tri->v[0], tri->v[1]);
GPU_indexbuf_add_line_verts(&elb_lines, tri->v[1], tri->v[2]);
GPU_indexbuf_add_line_verts(&elb_lines, tri->v[2], tri->v[0]);
#endif
}
buffers->tot_tri = tottri;
@ -1368,6 +1471,16 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_build_in_place(&elb, buffers->index_buf);
}
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
/* Get material index from the last face we iterated on. */
buffers->material_index = (f) ? f->mat_nr : 0;
buffers->show_overlay = !empty_mask || !default_face_set;
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
#ifdef QUANTIZED_PERF_TEST
copy_m4_m4(buffers->matrix, imat);
#endif
}
else {
GPUIndexBufBuilder elb_lines;
@ -1468,14 +1581,13 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
buffers->tot_tri = tottri;
/* Get material index from the last face we iterated on. */
buffers->material_index = (f) ? f->mat_nr : 0;
buffers->show_overlay = !empty_mask || !default_face_set;
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
}
/* Get material index from the last face we iterated on. */
buffers->material_index = (f) ? f->mat_nr : 0;
buffers->show_overlay = !empty_mask || !default_face_set;
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
}
/* -------------------------------------------------------------------- */