Refactored sculpt code to use a new type, SculptVertRef, that replaces

much of the usage of integer indices.  Meshes and grids simply store the
index here, but bmesh stores a pointer to a BMVert.  This greatly speeds
up DynTopo by reducing the need to maintain flat pointer arrays in bmesh.

To prevent the accidental casting of ScuptVertexRef to indices and vice
versa SculptVertRef is defined as a struct:

typedef struct {intptr_t i} SculptVertRef;

There are also two functions to convert flat index indices to
SculptVertRefs and back:

ScultpVertRef BKE_pbvh_table_index_to_vertex(PBVH *pbvh, int index);
int BKE_pbvh_vertex_index_to_table(PBVH *pbvh, SculptVertRef *ref);

Note that these functions require the aforementioned maintanance of
flat pointer arrays in bmesh, so make sure to call
SCULPT_ensure_vertex_random_access().
This commit is contained in:
Joseph Eagar 2020-10-25 00:32:59 -07:00
parent 661dcd813c
commit f482afadab
25 changed files with 718 additions and 496 deletions

View File

@ -287,10 +287,10 @@ typedef struct SculptClothLengthConstraint {
* point, position for a previous state). In that case, elem_index_a and elem_index_b should be
* the same to avoid affecting two different vertices when solving the constraints.
* *elem_position points to the position which is owned by the element. */
SculptVertRef elem_index_a;
int elem_index_a;
float *elem_position_a;
SculptVertRef elem_index_b;
int elem_index_b;
float *elem_position_b;
float length;
@ -343,7 +343,7 @@ typedef struct SculptPersistentBase {
typedef struct SculptVertexInfo {
/* Indexed by vertex, stores and ID of its topologically connected component. */
SculptVertRef *connected_component;
int *connected_component;
/* Indexed by base mesh vertex index, stores if that vertex is a boundary. */
BLI_bitmap *boundary;
@ -352,6 +352,7 @@ typedef struct SculptVertexInfo {
typedef struct SculptBoundaryEditInfo {
/* Vertex index from where the topology propagation reached this vertex. */
SculptVertRef original_vertex;
int original_vertex_i;
/* How many steps were needed to reach this vertex from the boundary. */
int num_propagation_steps;
@ -362,13 +363,15 @@ typedef struct SculptBoundaryEditInfo {
/* Edge for drawing the boundary preview in the cursor. */
typedef struct SculptBoundaryPreviewEdge {
int v1;
int v2;
SculptVertRef v1;
SculptVertRef v2;
} SculptBoundaryPreviewEdge;
typedef struct SculptBoundary {
/* Vertex indices of the active boundary. */
SculptVertRef *vertices;
int *vertex_indices;
int vertices_capacity;
int num_vertices;
@ -525,7 +528,7 @@ typedef struct SculptSession {
int cd_origno_offset;
/* Dynamic mesh preview */
int *preview_vert_index_list;
SculptVertRef *preview_vert_index_list;
int preview_vert_index_count;
/* Pose Brush Preview */

View File

@ -23,6 +23,7 @@
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
#include "BLI_compiler_compat.h"
/* For embedding CCGKey in iterator. */
#include "BKE_ccg.h"
@ -32,7 +33,13 @@
extern "C" {
#endif
typedef int64_t SculptVertRef;
typedef struct {int64_t i;} SculptVertRef;
BLI_INLINE SculptVertRef BKE_pbvh_make_vref(intptr_t i)
{
SculptVertRef ret = {i};
return ret;
}
struct BMLog;
struct BMesh;
@ -421,7 +428,8 @@ typedef struct PBVHVertexIter {
int gx;
int gy;
int i;
SculptVertRef index;
int index;
SculptVertRef vertex;
bool respect_hide;
/* grid */
@ -469,7 +477,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
if (vi.grids) { \
vi.width = vi.gridsize; \
vi.height = vi.gridsize; \
vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
vi.vertex.i = vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
vi.grid = vi.grids[vi.grid_indices[vi.g]]; \
if (mode == PBVH_ITER_UNIQUE) { \
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
@ -488,6 +496,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \
vi.grid = CCG_elem_next(&vi.key, vi.grid); \
vi.index++; \
vi.vertex.i++;\
vi.visible = true; \
if (vi.gh) { \
if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) { \
@ -539,13 +548,14 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
continue; \
} \
vi.bm_vert = bv;\
vi.vertex.i = (intptr_t)bv;\
vi.index = BM_elem_index_get(vi.bm_vert); \
vi.visible = !BM_elem_flag_test_bool(vi.bm_vert, BM_ELEM_HIDDEN); \
if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
continue; \
} \
vi.co = vi.bm_vert->co; \
vi.fno = vi.bm_vert->no; \
vi.index = BM_elem_index_get(vi.bm_vert); \
vi.mask = BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
}
@ -556,9 +566,10 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
((void)0)
#define BKE_pbvh_vertex_index_to_table(pbvh, v) \
(BKE_pbvh_type(pbvh) == PBVH_BMESH ? BM_elem_index_get((BMVert *)(v)) : (v))
(BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != -1 ? BM_elem_index_get((BMVert *)(v.i)) : (v.i))
SculptVertRef BKE_pbvh_table_index_to_vertex(PBVH *pbvh, int idx);
void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count);
void BKE_pbvh_node_free_proxies(PBVHNode *node);
PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node);

View File

@ -2173,7 +2173,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
if (j == 0 ||
len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
*r_active_vertex_index = mloop[lt->tri[j]].v;
*r_active_vertex_index = BKE_pbvh_make_vref(mloop[lt->tri[j]].v);
*r_active_face_index = lt->poly;
}
}
@ -2258,8 +2258,8 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh,
len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
*r_active_vertex_index = gridkey->grid_area * grid_index +
(y + y_it[j]) * gridkey->grid_size + (x + x_it[j]);
*r_active_vertex_index = BKE_pbvh_make_vref(gridkey->grid_area * grid_index +
(y + y_it[j]) * gridkey->grid_size + (x + x_it[j]));
}
}
}
@ -2322,7 +2322,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
face_normal);
break;
case PBVH_BMESH:
BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT);
//BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT);
hit = pbvh_bmesh_node_raycast(node,
ray_start,
ray_normal,
@ -2941,6 +2941,8 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->no = NULL;
vi->fno = NULL;
vi->mvert = NULL;
vi->vertex.i = 0;
vi->index = 0;
vi->respect_hide = pbvh->respect_hide;
if (pbvh->respect_hide == false) {
@ -3005,10 +3007,11 @@ bool pbvh_has_mask(PBVH *pbvh)
SculptVertRef BKE_pbvh_table_index_to_vertex(PBVH *pbvh, int idx) {
if (pbvh->type == PBVH_BMESH) {
return (SculptVertRef) pbvh->bm->vtable[idx];
SculptVertRef ref = {(intptr_t)pbvh->bm->vtable[idx]};
return ref;
}
return (SculptVertRef)idx;
return BKE_pbvh_make_vref(idx);
}
bool pbvh_has_face_sets(PBVH *pbvh)
{
@ -3128,7 +3131,7 @@ void BKE_pbvh_ensure_proxyarray_indexmap(PBVH *pbvh, PBVHNode *node, GHash *vert
int i = 0;
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
{
BLI_ghash_insert(gs, (void *)vd.index, (void *)i);
BLI_ghash_insert(gs, (void *)vd.vertex, (void *)i);
i++;
}
BKE_pbvh_vertex_iter_end;
@ -3159,7 +3162,7 @@ GHash *pbvh_build_vert_node_map(PBVH *pbvh, int mask)
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
{
BLI_ghash_insert(vert_node_map, (void *)vd.index, (void *)i);
BLI_ghash_insert(vert_node_map, (void *)vd.vertex, (void *)i);
}
BKE_pbvh_vertex_iter_end;
}
@ -3257,7 +3260,7 @@ void BKE_pbvh_ensure_proxyarray(SculptSession *ss,
int i = 0;
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
{
BLI_ghash_insert(gs, (void *)vd.index, (void *)i);
BLI_ghash_insert(gs, (void *)vd.vertex, (void *)i);
i++;
}
BKE_pbvh_vertex_iter_end;
@ -3269,7 +3272,7 @@ void BKE_pbvh_ensure_proxyarray(SculptSession *ss,
p->ownerco[i] = vd.co;
}
if (updatemask & PV_INDEX) {
p->index[i] = vd.index;
p->index[i] = vd.vertex;
}
if (updatemask & PV_OWNERNO) {
p->ownerno[i] = vd.no;
@ -3297,18 +3300,18 @@ void BKE_pbvh_ensure_proxyarray(SculptSession *ss,
int j = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
if (j >= MAX_PROXY_NEIGHBORS - 1) {
break;
}
ProxyKey key;
int *pindex = (int *)BLI_ghash_lookup_p(gs, (void *)ni.index);
int *pindex = (int *)BLI_ghash_lookup_p(gs, (void *)ni.vertex);
if (!pindex) {
if (vert_node_map) {
int *nindex = BLI_ghash_lookup_p(vert_node_map, (void *)ni.index);
int *nindex = BLI_ghash_lookup_p(vert_node_map, (void *)ni.vertex);
if (!nindex) {
continue;
@ -3316,7 +3319,7 @@ void BKE_pbvh_ensure_proxyarray(SculptSession *ss,
PBVHNode *node2 = pbvh->nodes + *nindex;
if (node2->proxyverts.indexmap) {
pindex = (int *)BLI_ghash_lookup_p(node2->proxyverts.indexmap, (void *)ni.index);
pindex = (int *)BLI_ghash_lookup_p(node2->proxyverts.indexmap, (void *)ni.vertex);
}
if (!pindex) {

View File

@ -40,7 +40,7 @@
#include "pbvh_intern.h"
#define DYNTOPO_TIME_LIMIT 0.015
#define DYNTOPO_RUN_INTERVAL 0.01
#define DYNTOPO_RUN_INTERVAL 0.02
#define DYNTOPO_USE_HEAP
@ -56,6 +56,11 @@
# include "BKE_global.h"
#endif
#ifndef DEBUG
# define DEBUG_DEFINED
# define DEBUG
#endif
#ifdef WIN32
# include "crtdbg.h"
#endif
@ -67,6 +72,10 @@ static void check_heap()
printf("Memory corruption!");
_CrtDbgBreak();
}
# ifdef DEBUG_DEFINED
# undef DEBUG_DEFINED
# undef DEBUG
# endif
#endif
}
/* Support for only operating on front-faces */
@ -327,11 +336,15 @@ static void pbvh_bmesh_node_split(
/* Initialize children */
PBVHNode *c1 = &pbvh->nodes[children], *c2 = &pbvh->nodes[children + 1];
c1->flag |= PBVH_Leaf;
c2->flag |= PBVH_Leaf;
c1->bm_faces = BLI_table_gset_new_ex("bm_faces", BLI_table_gset_len(n->bm_faces) / 2);
c2->bm_faces = BLI_table_gset_new_ex("bm_faces", BLI_table_gset_len(n->bm_faces) / 2);
c1->bm_unique_verts = c2->bm_unique_verts = NULL;
c1->bm_other_verts = c2->bm_other_verts = NULL;
/* Partition the parent node's faces between the two children */
TGSET_ITER (f, n->bm_faces) {
const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
@ -374,17 +387,20 @@ static void pbvh_bmesh_node_split(
TGSET_ITER (v, n->bm_unique_verts) {
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
}
TGSET_ITER_END
BLI_table_gset_free(n->bm_unique_verts, NULL);
}
TGSET_ITER_END
/* Unclaim faces */
TGSET_ITER (f, n->bm_faces) {
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
if (n->bm_faces) {
/* Unclaim faces */
TGSET_ITER (f, n->bm_faces) {
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
}
TGSET_ITER_END
BLI_table_gset_free(n->bm_faces, NULL);
}
TGSET_ITER_END
BLI_table_gset_free(n->bm_faces, NULL);
if (n->bm_other_verts) {
BLI_table_gset_free(n->bm_other_verts, NULL);
@ -436,6 +452,15 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
BMFace *f;
int i;
/*
TGSET_ITER_INDEX(f, bm_faces, i)
{
}
TGSET_ITER_INDEX_END
printf("size: %d %d\n", i + 1, bm_faces_size);
*/
TGSET_ITER_INDEX(f, bm_faces, i)
{
BBC *bbc = &bbc_array[i];
@ -1620,7 +1645,7 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
double time = PIL_check_seconds_timer();
RNG *rng = BLI_rng_new(time * 1000.0);
RNG *rng = BLI_rng_new(time * 1000.0f);
while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
if (PIL_check_seconds_timer() - time > DYNTOPO_TIME_LIMIT) {
@ -1749,7 +1774,8 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
if (len_squared_v3v3(location, v_tri[j]->co) <
len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, v_tri[j]->co);
*r_active_vertex_index = (SculptVertRef)v_tri[j]; // BM_elem_index_get(v_tri[j]);
SculptVertRef vref = {(intptr_t)v_tri[j]}; // BM_elem_index_get(v_tri[j]);
*r_active_vertex_index = vref;
}
}
}
@ -2423,21 +2449,13 @@ static void BKE_pbvh_bmesh_corect_tree(PBVH *pbvh, PBVHNode *node, PBVHNode *par
PBVH_UpdateVisibility | PBVH_UpdateColor | PBVH_UpdateTopology |
PBVH_UpdateNormals;
GSet *other = BLI_table_gset_new(__func__);
TableGSet *other = BLI_table_gset_new(__func__);
BMVert *v;
node->children_offset = 0;
node->draw_buffers = NULL;
// make sure other list isn't overlapping with unique
TGSET_ITER (v, node->bm_other_verts) {
if (!BLI_table_gset_haskey(node->bm_unique_verts, v)) {
// BLI_table_gset_add(other, v);
}
}
TGSET_ITER_END
// rebuild bm_other_verts
BMFace *f;
TGSET_ITER (f, node->bm_faces) {
BMLoop *l = f->l_first;
@ -2607,7 +2625,7 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
}
if (j != totnode) {
printf("eek!");
printf("pbvh error: %s", __func__);
}
if (bvh->totnode != j) {
@ -2638,13 +2656,15 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
TGSET_ITER (v, n->bm_unique_verts) {
BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, i);
} TGSET_ITER_END
}
TGSET_ITER_END
BMFace *f;
TGSET_ITER (f, n->bm_faces) {
BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, i);
} TGSET_ITER_END
}
TGSET_ITER_END
}
BMVert **scratch = NULL;
@ -2666,7 +2686,8 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
BLI_array_append(scratch, v);
}
// BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, i);
} TGSET_ITER_END
}
TGSET_ITER_END
int slen = BLI_array_len(scratch);
for (int j = 0; j < slen; j++) {

View File

@ -217,7 +217,7 @@ int BLI_table_gset_len(TableGSet *ts);
#define TGSET_ITER_INDEX(v, ts, index) \
{ \
int _i1; \
index = 0; \
index = -1; \
for (_i1 = 0; _i1 < (ts)->cur; _i1++) { \
if (!(ts)->elems[_i1]) \
continue; \
@ -226,7 +226,7 @@ int BLI_table_gset_len(TableGSet *ts);
#define TGSET_ITER_INDEX_END \
} \
}
} \
typedef GHashHashFP GSetHashFP;
typedef GHashCmpFP GSetCmpFP;

View File

@ -368,7 +368,7 @@ void BLI_table_gset_insert(TableGSet *ts, void *elem)
}
ts->size = newsize;
ts->cur = ts->length;
ts->cur = j;
}
BLI_ghash_insert(ts->ptr_to_idx, elem, (void *)ts->cur);
@ -378,16 +378,23 @@ void BLI_table_gset_insert(TableGSet *ts, void *elem)
void BLI_table_gset_remove(TableGSet *ts, void *elem, GHashKeyFreeFP freefp)
{
int idx = (int)BLI_ghash_lookup(ts->ptr_to_idx, elem);
if (!elem) {
return;
}
int *idx = (int*)BLI_ghash_lookup_p(ts->ptr_to_idx, elem);
if (!idx) {
return;
}
BLI_ghash_remove(ts->ptr_to_idx, elem, freefp, NULL);
if (!ts->elems || ts->elems[idx] != elem) {
if (!ts->elems || ts->elems[*idx] != elem) {
return;
}
ts->length--;
ts->elems[idx] = NULL;
ts->elems[*idx] = NULL;
}
bool BLI_table_gset_haskey(TableGSet *ts, void *elem)

View File

@ -1214,7 +1214,7 @@ typedef struct PaintCursorContext {
/* Sculpt related data. */
Sculpt *sd;
SculptSession *ss;
int prev_active_vertex_index;
SculptVertRef prev_active_vertex_index;
bool is_stroke_active;
bool is_cursor_over_mesh;
bool is_multires;
@ -1568,8 +1568,8 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
paint_cursor_update_object_space_radius(pcontext);
const bool update_previews = pcontext->prev_active_vertex_index !=
SCULPT_active_vertex_get(pcontext->ss);
const bool update_previews = pcontext->prev_active_vertex_index.i !=
SCULPT_active_vertex_get(pcontext->ss).i;
/* Setup drawing. */
wmViewport(&pcontext->region->winrct);

View File

@ -209,17 +209,15 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
}
static void partialvis_update_bmesh_verts(BMesh *bm,
GSet *verts,
TableGSet *verts,
PartialVisAction action,
PartialVisArea area,
float planes[4][4],
bool *any_changed,
bool *any_visible)
{
GSetIterator gs_iter;
GSET_ITER (gs_iter, verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
BMVert *v;
TGSET_ITER (v, verts) {
float *vmask = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_PAINT_MASK);
/* Hide vertex if in the hide volume. */
@ -237,15 +235,14 @@ static void partialvis_update_bmesh_verts(BMesh *bm,
(*any_visible) = true;
}
}
TGSET_ITER_END
}
static void partialvis_update_bmesh_faces(GSet *faces)
static void partialvis_update_bmesh_faces(TableGSet *faces)
{
GSetIterator gs_iter;
GSET_ITER (gs_iter, faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
BMFace *f;
TGSET_ITER (f, faces) {
if (paint_is_bmesh_face_hidden(f)) {
BM_elem_flag_enable(f, BM_ELEM_HIDDEN);
}
@ -253,6 +250,7 @@ static void partialvis_update_bmesh_faces(GSet *faces)
BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
}
}
TGSET_ITER_END
}
static void partialvis_update_bmesh(Object *ob,
@ -263,7 +261,7 @@ static void partialvis_update_bmesh(Object *ob,
float planes[4][4])
{
BMesh *bm;
GSet *unique, *other, *faces;
TableGSet *unique, *other, *faces;
bool any_changed = false, any_visible = false;
bm = BKE_pbvh_get_bmesh(pbvh);

View File

@ -616,7 +616,7 @@ static bool sculpt_gesture_is_effected_lasso(SculptGestureContext *sgcontext, co
static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, PBVHVertexIter *vd)
{
float vertex_normal[3];
SCULPT_vertex_normal_get(sgcontext->ss, vd->index, vertex_normal);
SCULPT_vertex_normal_get(sgcontext->ss, vd->vertex, vertex_normal);
float dot = dot_v3v3(sgcontext->view_normal, vertex_normal);
const bool is_effected_front_face = !(sgcontext->front_faces_only && dot < 0.0f);
@ -691,7 +691,7 @@ static void face_set_gesture_apply_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) {
SCULPT_vertex_face_set_set(sgcontext->ss, vd.index, face_set_operation->new_face_set_id);
SCULPT_vertex_face_set_set(sgcontext->ss, vd.vertex, face_set_operation->new_face_set_id);
any_updated = true;
}
}
@ -929,7 +929,7 @@ static void sculpt_gesture_trim_calculate_depth(bContext *C, SculptGestureContex
trim_operation->depth_back = -FLT_MAX;
for (int i = 0; i < totvert; i++) {
const float *vco = SCULPT_vertex_co_get(ss, i);
const float *vco = SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, i));
/* Convert the coordinates to world space to calculate the depth. When generating the trimming
* mesh, coordinates are first calculated in world space, then converted to object space to
* store them. */

File diff suppressed because it is too large Load Diff

View File

@ -138,7 +138,7 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
* automasking information can't be computed in real time per vertex and needs to be
* initialized for the whole mesh when the stroke starts. */
if (automasking->factor) {
return automasking->factor[vert];
return automasking->factor[BKE_pbvh_vertex_index_to_table(ss->pbvh, vert)];
}
if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) {
@ -193,16 +193,19 @@ typedef struct AutomaskFloodFillData {
char symm;
} AutomaskFloodFillData;
static bool automask_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
static bool automask_floodfill_cb(SculptSession *ss,
SculptVertRef from_vref,
SculptVertRef to_vref,
bool UNUSED(is_duplicate),
void *userdata)
{
AutomaskFloodFillData *data = userdata;
data->automask_factor[to_v] = 1.0f;
data->automask_factor[from_v] = 1.0f;
data->automask_factor[BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vref)] = 1.0f;
data->automask_factor[BKE_pbvh_vertex_index_to_table(ss->pbvh, from_vref)] = 1.0f;
return (!data->use_radius ||
SCULPT_is_vertex_inside_brush_radius_symm(
SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm));
SCULPT_vertex_co_get(ss, to_vref), data->location, data->radius, data->symm));
}
static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
@ -257,7 +260,9 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a
int tot_vert = SCULPT_vertex_count_get(ss);
int active_face_set = SCULPT_active_face_set_get(ss);
for (int i = 0; i < tot_vert; i++) {
if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
if (!SCULPT_vertex_has_face_set(ss, vertex, active_face_set)) {
automask_factor[i] *= 0.0f;
}
}
@ -283,15 +288,17 @@ float *SCULPT_boundary_automasking_init(Object *ob,
int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
for (int i = 0; i < totvert; i++) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
edge_distance[i] = EDGE_DISTANCE_INF;
switch (mode) {
case AUTOMASK_INIT_BOUNDARY_EDGES:
if (SCULPT_vertex_is_boundary(ss, i)) {
if (SCULPT_vertex_is_boundary(ss, vertex)) {
edge_distance[i] = 0;
}
break;
case AUTOMASK_INIT_BOUNDARY_FACE_SETS:
if (!SCULPT_vertex_has_unique_face_set(ss, i)) {
if (!SCULPT_vertex_has_unique_face_set(ss, vertex)) {
edge_distance[i] = 0;
}
break;
@ -300,9 +307,11 @@ float *SCULPT_boundary_automasking_init(Object *ob,
for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
for (int i = 0; i < totvert; i++) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
if (edge_distance[i] == EDGE_DISTANCE_INF) {
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
if (edge_distance[ni.index] == propagation_it) {
edge_distance[i] = propagation_it + 1;
}

View File

@ -62,19 +62,28 @@
#define BOUNDARY_STEPS_NONE -1
typedef struct BoundaryInitialVertexFloodFillData {
int initial_vertex;
SculptVertRef initial_vertex;
int initial_vertex_index;
int boundary_initial_vertex_steps;
int boundary_initial_vertex;
SculptVertRef boundary_initial_vertex;
int *floodfill_steps;
float radius_sq;
} BoundaryInitialVertexFloodFillData;
static bool boundary_initial_vertex_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
static bool boundary_initial_vertex_floodfill_cb(SculptSession *ss,
SculptVertRef from_vref,
SculptVertRef to_vref,
bool is_duplicate,
void *userdata)
{
BoundaryInitialVertexFloodFillData *data = userdata;
if (!SCULPT_vertex_visible_get(ss, to_v)) {
int to_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vref);
int from_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_vref);
if (!SCULPT_vertex_visible_get(ss, to_vref)) {
return false;
}
@ -85,23 +94,25 @@ static bool boundary_initial_vertex_floodfill_cb(
data->floodfill_steps[to_v] = data->floodfill_steps[from_v];
}
if (SCULPT_vertex_is_boundary(ss, to_v)) {
if (SCULPT_vertex_is_boundary(ss, to_vref)) {
if (data->floodfill_steps[to_v] < data->boundary_initial_vertex_steps) {
data->boundary_initial_vertex_steps = data->floodfill_steps[to_v];
data->boundary_initial_vertex = to_v;
data->boundary_initial_vertex = to_vref;
}
}
const float len_sq = len_squared_v3v3(SCULPT_vertex_co_get(ss, data->initial_vertex),
SCULPT_vertex_co_get(ss, to_v));
SCULPT_vertex_co_get(ss, to_vref));
return len_sq < data->radius_sq;
}
/* From a vertex index anywhere in the mesh, returns the closest vertex in a mesh boundary inside
* the given radius, if it exists. */
static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
const int initial_vertex,
const float radius)
static SculptVertRef sculpt_boundary_get_closest_boundary_vertex(
SculptSession *ss,
const SculptVertRef initial_vertex,
const int initial_vertex_index,
const float radius)
{
if (SCULPT_vertex_is_boundary(ss, initial_vertex)) {
@ -114,6 +125,7 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
BoundaryInitialVertexFloodFillData fdata = {
.initial_vertex = initial_vertex,
.initial_vertex_index = initial_vertex_index,
.boundary_initial_vertex = BOUNDARY_VERTEX_NONE,
.boundary_initial_vertex_steps = INT_MAX,
.radius_sq = radius * radius,
@ -134,28 +146,34 @@ static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss,
* deformations usually need in the boundary. */
static int BOUNDARY_INDICES_BLOCK_SIZE = 300;
static void sculpt_boundary_index_add(SculptBoundary *boundary,
const int new_index,
static void sculpt_boundary_index_add(SculptSession *ss,
SculptBoundary *boundary,
const SculptVertRef new_index,
const float distance,
GSet *included_vertices)
{
boundary->vertices[boundary->num_vertices] = new_index;
if (boundary->distance) {
boundary->distance[new_index] = distance;
boundary->distance[BKE_pbvh_vertex_index_to_table(ss->pbvh, new_index)] = distance;
}
if (included_vertices) {
BLI_gset_add(included_vertices, POINTER_FROM_INT(new_index));
BLI_gset_add(included_vertices, POINTER_FROM_INT(new_index.i));
}
boundary->num_vertices++;
if (boundary->num_vertices >= boundary->vertices_capacity) {
boundary->vertices_capacity += BOUNDARY_INDICES_BLOCK_SIZE;
boundary->vertices = MEM_reallocN_id(
boundary->vertices, boundary->vertices_capacity * sizeof(int), "boundary indices");
boundary->vertices = MEM_reallocN_id(boundary->vertices,
boundary->vertices_capacity * sizeof(SculptVertRef),
"boundary vertrefs");
boundary->vertex_indices = MEM_reallocN_id(
boundary->vertex_indices, boundary->vertices_capacity * sizeof(int), "boundary indices");
}
};
static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int v1, const int v2)
static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary,
const SculptVertRef v1,
const SculptVertRef v2)
{
boundary->edges[boundary->num_edges].v1 = v1;
@ -175,7 +193,7 @@ static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int
* as well as to check if the initial vertex is valid.
*/
static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
const int initial_vertex)
const SculptVertRef initial_vertex)
{
if (!SCULPT_vertex_visible_get(ss, initial_vertex)) {
@ -186,9 +204,9 @@ static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss,
int boundary_vertex_count = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, initial_vertex, ni) {
if (SCULPT_vertex_visible_get(ss, ni.index)) {
if (SCULPT_vertex_visible_get(ss, ni.vertex)) {
neighbor_count++;
if (SCULPT_vertex_is_boundary(ss, ni.index)) {
if (SCULPT_vertex_is_boundary(ss, ni.vertex)) {
boundary_vertex_count++;
}
}
@ -218,22 +236,25 @@ typedef struct BoundaryFloodFillData {
GSet *included_vertices;
EdgeSet *preview_edges;
int last_visited_vertex;
SculptVertRef last_visited_vertex;
} BoundaryFloodFillData;
static bool boundary_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata)
{
BoundaryFloodFillData *data = userdata;
SculptBoundary *boundary = data->boundary;
const int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v);
if (SCULPT_vertex_is_boundary(ss, to_v)) {
const float edge_len = len_v3v3(SCULPT_vertex_co_get(ss, from_v),
SCULPT_vertex_co_get(ss, to_v));
const float distance_boundary_to_dst = boundary->distance ?
boundary->distance[from_v] + edge_len :
boundary->distance[from_v_i] + edge_len :
0.0f;
sculpt_boundary_index_add(boundary, to_v, distance_boundary_to_dst, data->included_vertices);
sculpt_boundary_index_add(
ss, boundary, to_v, distance_boundary_to_dst, data->included_vertices);
if (!is_duplicate) {
sculpt_boundary_preview_edge_add(boundary, from_v, to_v);
}
@ -245,12 +266,15 @@ static bool boundary_floodfill_cb(
static void sculpt_boundary_indices_init(SculptSession *ss,
SculptBoundary *boundary,
const bool init_boundary_distances,
const int initial_boundary_index)
const SculptVertRef initial_boundary_index)
{
const int totvert = SCULPT_vertex_count_get(ss);
boundary->vertices = MEM_malloc_arrayN(
BOUNDARY_INDICES_BLOCK_SIZE, sizeof(SculptVertRef), "boundary vrefs");
boundary->vertex_indices = MEM_malloc_arrayN(
BOUNDARY_INDICES_BLOCK_SIZE, sizeof(int), "boundary indices");
if (init_boundary_distances) {
boundary->distance = MEM_calloc_arrayN(totvert, sizeof(float), "boundary distances");
}
@ -264,7 +288,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
boundary->initial_vertex = initial_boundary_index;
copy_v3_v3(boundary->initial_vertex_position,
SCULPT_vertex_co_get(ss, boundary->initial_vertex));
sculpt_boundary_index_add(boundary, initial_boundary_index, 0.0f, included_vertices);
sculpt_boundary_index_add(ss, boundary, initial_boundary_index, 0.0f, included_vertices);
SCULPT_floodfill_add_initial(&flood, initial_boundary_index);
BoundaryFloodFillData fdata = {
@ -278,13 +302,13 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
SCULPT_floodfill_free(&flood);
/* Check if the boundary loops into itself and add the extra preview edge to close the loop. */
if (fdata.last_visited_vertex != BOUNDARY_VERTEX_NONE &&
if (fdata.last_visited_vertex.i != BOUNDARY_VERTEX_NONE &&
sculpt_boundary_is_vertex_in_editable_boundary(ss, fdata.last_visited_vertex)) {
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, fdata.last_visited_vertex, ni) {
if (BLI_gset_haskey(included_vertices, POINTER_FROM_INT(ni.index)) &&
sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.index)) {
sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.index);
if (BLI_gset_haskey(included_vertices, POINTER_FROM_INT(ni.vertex.i)) &&
sculpt_boundary_is_vertex_in_editable_boundary(ss, ni.vertex)) {
sculpt_boundary_preview_edge_add(boundary, fdata.last_visited_vertex, ni.vertex);
boundary->forms_loop = true;
}
}
@ -302,7 +326,7 @@ static void sculpt_boundary_indices_init(SculptSession *ss,
*/
static void sculpt_boundary_edit_data_init(SculptSession *ss,
SculptBoundary *boundary,
const int initial_vertex,
const SculptVertRef initial_vertex,
const float radius)
{
const int totvert = SCULPT_vertex_count_get(ss);
@ -313,19 +337,22 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
totvert, sizeof(SculptBoundaryEditInfo), "Boundary edit info");
for (int i = 0; i < totvert; i++) {
boundary->edit_info[i].original_vertex = BOUNDARY_VERTEX_NONE;
boundary->edit_info[i].original_vertex.i = BOUNDARY_VERTEX_NONE;
boundary->edit_info[i].original_vertex_i = BOUNDARY_VERTEX_NONE;
boundary->edit_info[i].num_propagation_steps = BOUNDARY_STEPS_NONE;
}
GSQueue *current_iteration = BLI_gsqueue_new(sizeof(int));
GSQueue *next_iteration = BLI_gsqueue_new(sizeof(int));
GSQueue *current_iteration = BLI_gsqueue_new(sizeof(SculptVertRef));
GSQueue *next_iteration = BLI_gsqueue_new(sizeof(SculptVertRef));
/* Initialized the first iteration with the vertices already in the boundary. This is propagation
* step 0. */
BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
for (int i = 0; i < boundary->num_vertices; i++) {
boundary->edit_info[boundary->vertices[i]].original_vertex = boundary->vertices[i];
boundary->edit_info[boundary->vertices[i]].num_propagation_steps = 0;
boundary->edit_info[boundary->vertex_indices[i]].original_vertex = boundary->vertices[i];
boundary->edit_info[boundary->vertex_indices[i]].original_vertex_i =
boundary->vertex_indices[i];
boundary->edit_info[boundary->vertex_indices[i]].num_propagation_steps = 0;
/* This ensures that all duplicate vertices in the boundary have the same original_vertex
* index, so the deformation for them will be the same. */
@ -333,7 +360,11 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
SculptVertexNeighborIter ni_duplis;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, boundary->vertices[i], ni_duplis) {
if (ni_duplis.is_duplicate) {
boundary->edit_info[ni_duplis.index].original_vertex = boundary->vertices[i];
int index = ni_duplis.index;
boundary->edit_info[index].original_vertex = boundary->vertices[i];
boundary->edit_info[index].original_vertex_i = BKE_pbvh_vertex_index_to_table(
ss->pbvh, boundary->vertices[i]);
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis);
@ -354,29 +385,35 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
}
while (!BLI_gsqueue_is_empty(current_iteration)) {
int from_v;
SculptVertRef from_v;
BLI_gsqueue_pop(current_iteration, &from_v);
const int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
const bool is_visible = SCULPT_vertex_visible_get(ss, ni.index);
if (is_visible &&
boundary->edit_info[ni.index].num_propagation_steps == BOUNDARY_STEPS_NONE) {
boundary->edit_info[ni.index].original_vertex =
boundary->edit_info[from_v].original_vertex;
const int index = ni.index;
BLI_BITMAP_ENABLE(visited_vertices, ni.index);
const bool is_visible = SCULPT_vertex_visible_get(ss, ni.vertex);
if (is_visible &&
boundary->edit_info[index].num_propagation_steps == BOUNDARY_STEPS_NONE) {
boundary->edit_info[index].original_vertex =
boundary->edit_info[from_v_i].original_vertex;
boundary->edit_info[index].original_vertex_i =
boundary->edit_info[from_v_i].original_vertex_i;
BLI_BITMAP_ENABLE(visited_vertices, index);
if (ni.is_duplicate) {
/* Grids duplicates handling. */
boundary->edit_info[ni.index].num_propagation_steps =
boundary->edit_info[from_v].num_propagation_steps;
boundary->edit_info[index].num_propagation_steps =
boundary->edit_info[from_v_i].num_propagation_steps;
}
else {
boundary->edit_info[ni.index].num_propagation_steps =
boundary->edit_info[from_v].num_propagation_steps + 1;
boundary->edit_info[index].num_propagation_steps =
boundary->edit_info[from_v_i].num_propagation_steps + 1;
BLI_gsqueue_push(next_iteration, &ni.index);
BLI_gsqueue_push(next_iteration, &ni.vertex);
/* When copying the data to the neighbor for the next iteration, it has to be copied to
* all its duplicates too. This is because it is not possible to know if the updated
@ -384,12 +421,15 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
* copy the data in the from_v neighbor iterator. */
if (has_duplicates) {
SculptVertexNeighborIter ni_duplis;
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.index, ni_duplis) {
SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, ni.vertex, ni_duplis) {
if (ni_duplis.is_duplicate) {
boundary->edit_info[ni_duplis.index].original_vertex =
boundary->edit_info[from_v].original_vertex;
boundary->edit_info[ni_duplis.index].num_propagation_steps =
boundary->edit_info[from_v].num_propagation_steps + 1;
const int index = ni_duplis.index;
boundary->edit_info[index].original_vertex =
boundary->edit_info[from_v_i].original_vertex;
boundary->edit_info[index].original_vertex_i =
boundary->edit_info[from_v_i].original_vertex_i;
boundary->edit_info[index].num_propagation_steps =
boundary->edit_info[from_v_i].num_propagation_steps + 1;
}
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni_duplis);
@ -397,11 +437,11 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* Check the distance using the vertex that was propagated from the initial vertex that
* was used to initialize the boundary. */
if (boundary->edit_info[from_v].original_vertex == initial_vertex) {
boundary->pivot_vertex = ni.index;
copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.index));
if (boundary->edit_info[from_v_i].original_vertex.i == initial_vertex.i) {
boundary->pivot_vertex = ni.vertex;
copy_v3_v3(boundary->initial_pivot_position, SCULPT_vertex_co_get(ss, ni.vertex));
accum_distance += len_v3v3(SCULPT_vertex_co_get(ss, from_v),
SCULPT_vertex_co_get(ss, ni.index));
SCULPT_vertex_co_get(ss, ni.vertex));
}
}
}
@ -411,7 +451,7 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* Copy the new vertices to the queue to be processed in the next iteration. */
while (!BLI_gsqueue_is_empty(next_iteration)) {
int next_v;
SculptVertRef next_v;
BLI_gsqueue_pop(next_iteration, &next_v);
BLI_gsqueue_push(current_iteration, &next_v);
}
@ -442,7 +482,7 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
brush, boundary->edit_info[i].num_propagation_steps, boundary->max_propagation_steps);
}
if (boundary->edit_info[i].original_vertex == boundary->initial_vertex) {
if (boundary->edit_info[i].original_vertex.i == boundary->initial_vertex.i) {
/* All vertices that are propagated from the original vertex won't be affected by the
* boundary falloff, so there is no need to calculate anything else. */
continue;
@ -454,7 +494,8 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
continue;
}
const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex];
const float boundary_distance = boundary->distance[BKE_pbvh_vertex_index_to_table(
ss->pbvh, boundary->edit_info[i].original_vertex)];
float falloff_distance = 0.0f;
float direction = 1.0f;
@ -495,17 +536,17 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object,
{
SculptSession *ss = object->sculpt;
if (initial_vertex == BOUNDARY_VERTEX_NONE) {
if (initial_vertex.i == BOUNDARY_VERTEX_NONE) {
return NULL;
}
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_info_ensure(object);
const int boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex(
ss, initial_vertex, radius);
const SculptVertRef boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex(
ss, initial_vertex, BKE_pbvh_vertex_index_to_table(ss->pbvh, initial_vertex), radius);
if (boundary_initial_vertex == BOUNDARY_VERTEX_NONE) {
if (boundary_initial_vertex.i == BOUNDARY_VERTEX_NONE) {
return NULL;
}
@ -554,24 +595,27 @@ static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bo
if (boundary->edit_info[i].num_propagation_steps == boundary->max_propagation_steps) {
float dir[3];
float normal[3];
SCULPT_vertex_normal_get(ss, i, normal);
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
SCULPT_vertex_normal_get(ss, vertex, normal);
sub_v3_v3v3(dir,
SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
SCULPT_vertex_co_get(ss, i));
cross_v3_v3v3(
boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex], dir, normal);
normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]);
copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex],
SCULPT_vertex_co_get(ss, i));
SCULPT_vertex_co_get(ss, vertex));
cross_v3_v3v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i],
dir,
normal);
normalize_v3(boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]);
copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i],
SCULPT_vertex_co_get(ss, vertex));
}
}
for (int i = 0; i < totvert; i++) {
if (boundary->edit_info[i].num_propagation_steps != BOUNDARY_STEPS_NONE) {
copy_v3_v3(boundary->bend.pivot_positions[i],
boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex]);
boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex_i]);
copy_v3_v3(boundary->bend.pivot_rotation_axis[i],
boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]);
boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex_i]);
}
}
}
@ -583,17 +627,20 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b
for (int i = 0; i < totvert; i++) {
if (boundary->edit_info[i].num_propagation_steps == boundary->max_propagation_steps) {
sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex],
const int index = boundary->edit_info[i].original_vertex_i;
sub_v3_v3v3(boundary->slide.directions[index],
SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex),
SCULPT_vertex_co_get(ss, i));
normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex]);
SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, i)));
normalize_v3(boundary->slide.directions[index]);
}
}
for (int i = 0; i < totvert; i++) {
if (boundary->edit_info[i].num_propagation_steps != BOUNDARY_STEPS_NONE) {
copy_v3_v3(boundary->slide.directions[i],
boundary->slide.directions[boundary->edit_info[i].original_vertex]);
boundary->slide.directions[BKE_pbvh_vertex_index_to_table(
ss->pbvh, boundary->edit_info[i].original_vertex)]);
}
}
}
@ -668,13 +715,15 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
orig_data.co, boundary->initial_vertex_position, symm)) {
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
float t_orig_co[3];
const int index = vd.index;
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[index]);
rotate_v3_v3v3fl(target_co,
t_orig_co,
boundary->bend.pivot_rotation_axis[vd.index],
angle * boundary->edit_info[vd.index].strength_factor * mask);
add_v3_v3(target_co, boundary->bend.pivot_positions[vd.index]);
boundary->bend.pivot_rotation_axis[index],
angle * boundary->edit_info[index].strength_factor * mask);
add_v3_v3(target_co, boundary->bend.pivot_positions[index]);
}
}
@ -895,9 +944,9 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
int total_neighbors = 0;
const int current_propagation_steps = boundary->edit_info[vd.index].num_propagation_steps;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
if (current_propagation_steps == boundary->edit_info[ni.index].num_propagation_steps) {
add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.index));
add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.vertex));
total_neighbors++;
}
}
@ -931,7 +980,8 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
const int symm_area = ss->cache->mirror_symmetry_pass;
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
int initial_vertex;
SculptVertRef initial_vertex;
if (ss->cache->mirror_symmetry_pass == 0) {
initial_vertex = SCULPT_active_vertex_get(ss);
}

View File

@ -182,20 +182,25 @@ static void cloth_brush_reallocate_constraints(SculptClothSimulation *cloth_sim)
static void cloth_brush_add_length_constraint(SculptSession *ss,
SculptClothSimulation *cloth_sim,
const int node_index,
const int v1,
const int v2,
const int v1i,
const int v2i,
const bool use_persistent)
{
SculptClothLengthConstraint *length_constraint =
&cloth_sim->length_constraints[cloth_sim->tot_length_constraints];
length_constraint->elem_index_a = v1;
length_constraint->elem_index_b = v2;
SculptVertRef v1, v2;
v1 = BKE_pbvh_table_index_to_vertex(ss->pbvh, v1i);
v2 = BKE_pbvh_table_index_to_vertex(ss->pbvh, v2i);
length_constraint->elem_index_a = v1i;
length_constraint->elem_index_b = v2i;
length_constraint->node = node_index;
length_constraint->elem_position_a = cloth_sim->pos[v1];
length_constraint->elem_position_b = cloth_sim->pos[v2];
length_constraint->elem_position_a = cloth_sim->pos[v1i];
length_constraint->elem_position_b = cloth_sim->pos[v2i];
length_constraint->type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL;
@ -215,7 +220,7 @@ static void cloth_brush_add_length_constraint(SculptSession *ss,
cloth_brush_reallocate_constraints(cloth_sim);
/* Add the constraint to the GSet to avoid creating it again. */
BLI_edgeset_add(cloth_sim->created_length_constraints, v1, v2);
BLI_edgeset_add(cloth_sim->created_length_constraints, v1i, v2i);
}
static void cloth_brush_add_softbody_constraint(SculptClothSimulation *cloth_sim,
@ -347,7 +352,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
int tot_indices = 0;
build_indices[tot_indices] = vd.index;
tot_indices++;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
build_indices[tot_indices] = ni.index;
tot_indices++;
}
@ -515,7 +520,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
float brush_disp[3];
@ -749,7 +754,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
mul_v3_fl(pos_diff, (1.0f - cloth_sim->damping) * sim_factor);
const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) *
SCULPT_automasking_factor_get(automasking, ss, vd.index);
SCULPT_automasking_factor_get(automasking, ss, vd.vertex);
madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v);
madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v);
@ -796,6 +801,9 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
const int v1 = constraint->elem_index_a;
const int v2 = constraint->elem_index_b;
const SculptVertRef v1ref = BKE_pbvh_table_index_to_vertex(ss->pbvh, v1);
const SculptVertRef v2ref = BKE_pbvh_table_index_to_vertex(ss->pbvh, v2);
float v1_to_v2[3];
sub_v3_v3v3(v1_to_v2, constraint->elem_position_b, constraint->elem_position_a);
const float current_distance = len_v3(v1_to_v2);
@ -818,10 +826,10 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
mul_v3_v3fl(correction_vector_half, correction_vector, 0.5f);
const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, v1)) *
SCULPT_automasking_factor_get(automasking, ss, v1);
const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2)) *
SCULPT_automasking_factor_get(automasking, ss, v2);
const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, v1ref)) *
SCULPT_automasking_factor_get(automasking, ss, v1ref);
const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2ref)) *
SCULPT_automasking_factor_get(automasking, ss, v2ref);
float sim_location[3];
cloth_brush_simulation_location_get(ss, brush, sim_location);
@ -1095,15 +1103,17 @@ void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation
const bool has_deformation_pos = cloth_sim->deformation_pos != NULL;
const bool has_softbody_pos = cloth_sim->softbody_pos != NULL;
for (int i = 0; i < totverts; i++) {
copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, vertex));
copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, vertex));
copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, vertex));
if (has_deformation_pos) {
copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, vertex));
cloth_sim->deformation_strength[i] = 1.0f;
}
if (has_softbody_pos) {
copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(cloth_sim->softbody_pos[i], SCULPT_vertex_co_get(ss, vertex));
}
}
}
@ -1112,7 +1122,9 @@ void SCULPT_cloth_brush_store_simulation_state(SculptSession *ss, SculptClothSim
{
const int totverts = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totverts; i++) {
copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
copy_v3_v3(cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex));
}
}
@ -1366,13 +1378,13 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
float fade = vd.mask ? *vd.mask : 0.0f;
fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
fade = 1.0f - fade;
float force[3] = {0.0f, 0.0f, 0.0f};
float disp[3], temp[3], transform[3][3];
if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) {
if (!SCULPT_vertex_has_face_set(ss, vd.vertex, ss->filter_cache->active_face_set)) {
continue;
}
}
@ -1391,7 +1403,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
break;
case CLOTH_FILTER_INFLATE: {
float normal[3];
SCULPT_vertex_normal_get(ss, vd.index, normal);
SCULPT_vertex_normal_get(ss, vd.vertex, normal);
mul_v3_v3fl(force, normal, fade * data->filter_strength);
} break;
case CLOTH_FILTER_EXPAND:
@ -1456,7 +1468,9 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
const int totverts = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totverts; i++) {
copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, vertex));
}
SculptThreadedTaskData data = {

View File

@ -184,13 +184,13 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
/* Average the edge length of the connected edges to the active vertex. */
int active_vertex = SCULPT_active_vertex_get(ss);
SculptVertRef active_vertex = SCULPT_active_vertex_get(ss);
const float *active_vertex_co = SCULPT_active_vertex_co_get(ss);
float edge_length = 0.0f;
int tot = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.index));
edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.vertex));
tot += 1;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);

View File

@ -150,7 +150,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) {
@ -170,11 +170,11 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
if (fade > 0.05f) {
SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set);
}
}
}
@ -209,7 +209,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
if (relax_face_sets != SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
if (relax_face_sets != SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) {
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
vd.co,
@ -217,7 +217,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
@ -333,8 +333,10 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
if (mode == SCULPT_FACE_SET_MASKED) {
for (int i = 0; i < tot_vert; i++) {
if (SCULPT_vertex_mask_get(ss, i) >= threshold && SCULPT_vertex_visible_get(ss, i)) {
SCULPT_vertex_face_set_set(ss, i, next_face_set);
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
if (SCULPT_vertex_mask_get(ss, vertex) >= threshold && SCULPT_vertex_visible_get(ss, vertex)) {
SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
}
}
}
@ -346,7 +348,9 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
* sets and the performance hit of rendering the overlay. */
bool all_visible = true;
for (int i = 0; i < tot_vert; i++) {
if (!SCULPT_vertex_visible_get(ss, i)) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
if (!SCULPT_vertex_visible_get(ss, vertex)) {
all_visible = false;
break;
}
@ -360,15 +364,19 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
}
for (int i = 0; i < tot_vert; i++) {
if (SCULPT_vertex_visible_get(ss, i)) {
SCULPT_vertex_face_set_set(ss, i, next_face_set);
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
if (SCULPT_vertex_visible_get(ss, vertex)) {
SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
}
}
}
if (mode == SCULPT_FACE_SET_ALL) {
for (int i = 0; i < tot_vert; i++) {
SCULPT_vertex_face_set_set(ss, i, next_face_set);
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
}
}
@ -852,7 +860,9 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
* be synced from face sets to non-manifold vertices. */
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
for (int i = 0; i < tot_vert; i++) {
if (!SCULPT_vertex_visible_get(ss, i)) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
if (!SCULPT_vertex_visible_get(ss, vertex)) {
hidden_vertex = true;
break;
}

View File

@ -119,7 +119,7 @@ static void color_filter_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
if (fade == 0.0f) {
continue;
}
@ -197,7 +197,7 @@ static void color_filter_task_cb(void *__restrict userdata,
case COLOR_FILTER_SMOOTH: {
fade = clamp_f(fade, -1.0f, 1.0f);
float smooth_color[4];
SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex);
blend_color_interpolate_float(final_color, vd.col, smooth_color, fade);
break;
}

View File

@ -120,7 +120,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
switch (mode) {
case MASK_FILTER_SMOOTH:
case MASK_FILTER_SHARPEN: {
float val = SCULPT_neighbor_mask_average(ss, vd.index);
float val = SCULPT_neighbor_mask_average(ss, vd.vertex);
val -= *vd.mask;
@ -140,7 +140,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
}
case MASK_FILTER_GROW:
max = 0.0f;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vmask_f = data->prev_mask[ni.index];
if (vmask_f > max) {
max = vmask_f;
@ -151,7 +151,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
break;
case MASK_FILTER_SHRINK:
min = 1.0f;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vmask_f = data->prev_mask[ni.index];
if (vmask_f < min) {
min = vmask_f;
@ -233,7 +233,9 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask");
for (int j = 0; j < num_verts; j++) {
prev_mask[j] = SCULPT_vertex_mask_get(ss, j);
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, j);
prev_mask[j] = SCULPT_vertex_mask_get(ss, vertex);
}
}
@ -324,9 +326,9 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
zero_v3(avg);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) {
float normalized[3];
sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.index), vd->co);
sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.vertex), vd->co);
normalize_v3(normalized);
add_v3_v3(avg, normalized);
total++;

View File

@ -309,7 +309,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
if (fade == 0.0f && filter_type != MESH_FILTER_SURFACE_SMOOTH) {
/* Surface Smooth can't skip the loop for this vertex as it needs to calculate its
@ -327,7 +327,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
}
if (filter_type == MESH_FILTER_RELAX_FACE_SETS) {
if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) {
continue;
}
}
@ -335,7 +335,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
switch (filter_type) {
case MESH_FILTER_SMOOTH:
fade = clamp_f(fade, -1.0f, 1.0f);
SCULPT_neighbor_coords_average_interior(ss, avg, vd.index);
SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex);
sub_v3_v3v3(val, avg, orig_co);
madd_v3_v3v3fl(val, orig_co, val, fade);
sub_v3_v3v3(disp, val, orig_co);
@ -398,7 +398,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
disp,
vd.co,
ss->filter_cache->surface_smooth_laplacian_disp,
vd.index,
vd.vertex,
orig_data.co,
ss->filter_cache->surface_smooth_shape_preservation);
break;
@ -412,10 +412,10 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float disp_sharpen[3] = {0.0f, 0.0f, 0.0f};
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float disp_n[3];
sub_v3_v3v3(
disp_n, SCULPT_vertex_co_get(ss, ni.index), SCULPT_vertex_co_get(ss, vd.index));
disp_n, SCULPT_vertex_co_get(ss, ni.vertex), SCULPT_vertex_co_get(ss, vd.vertex));
mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[ni.index]);
add_v3_v3(disp_sharpen, disp_n);
}
@ -425,7 +425,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float disp_avg[3];
float avg_co[3];
SCULPT_neighbor_coords_average(ss, avg_co, vd.index);
SCULPT_neighbor_coords_average(ss, avg_co, vd.vertex);
sub_v3_v3v3(disp_avg, avg_co, vd.co);
mul_v3_v3fl(
disp_avg, disp_avg, smooth_ratio * pow2f(ss->filter_cache->sharpen_factor[vd.index]));
@ -487,9 +487,11 @@ static void mesh_filter_enhance_details_init_directions(SculptSession *ss)
filter_cache->detail_directions = MEM_malloc_arrayN(
totvert, sizeof(float[3]), "detail directions");
for (int i = 0; i < totvert; i++) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
float avg[3];
SCULPT_neighbor_coords_average(ss, avg, i);
sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i));
SCULPT_neighbor_coords_average(ss, avg, vertex);
sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex));
}
}
@ -513,8 +515,10 @@ static void mesh_filter_init_limit_surface_co(SculptSession *ss)
filter_cache->limit_surface_co = MEM_malloc_arrayN(
sizeof(float[3]), totvert, "limit surface co");
for (int i = 0; i < totvert; i++) {
SCULPT_vertex_limit_surface_get(ss, i, filter_cache->limit_surface_co[i]);
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
SCULPT_vertex_limit_surface_get(ss, vertex, filter_cache->limit_surface_co[i]);
}
}
@ -535,8 +539,10 @@ static void mesh_filter_sharpen_init(SculptSession *ss,
for (int i = 0; i < totvert; i++) {
float avg[3];
SCULPT_neighbor_coords_average(ss, avg, i);
sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i));
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
SCULPT_neighbor_coords_average(ss, avg, vertex);
sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex));
filter_cache->sharpen_factor[i] = len_v3(filter_cache->detail_directions[i]);
}
@ -559,11 +565,12 @@ static void mesh_filter_sharpen_init(SculptSession *ss,
smooth_iterations++) {
for (int i = 0; i < totvert; i++) {
float direction_avg[3] = {0.0f, 0.0f, 0.0f};
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
float sharpen_avg = 0;
int total = 0;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
add_v3_v3(direction_avg, filter_cache->detail_directions[ni.index]);
sharpen_avg += filter_cache->sharpen_factor[ni.index];
total++;
@ -591,7 +598,7 @@ static void mesh_filter_surface_smooth_displace_task_cb(
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.index);
fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex);
if (fade == 0.0f) {
continue;
}
@ -599,7 +606,7 @@ static void mesh_filter_surface_smooth_displace_task_cb(
SCULPT_surface_smooth_displace_step(ss,
vd.co,
ss->filter_cache->surface_smooth_laplacian_disp,
vd.index,
vd.vertex,
ss->filter_cache->surface_smooth_current_vertex,
clamp_f(fade, 0.0f, 1.0f));
}

View File

@ -124,21 +124,25 @@ float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
typedef struct SculptVertexNeighborIter {
/* Storage */
SculptVertRef *neighbors;
int *neighbor_indices;
int size;
int capacity;
SculptVertRef neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
int neighbor_indices_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
/* Internal iterator. */
int num_duplicates;
int i;
/* Public */
SculptVertRef index;
SculptVertRef vertex;
int index;
bool is_duplicate;
} SculptVertexNeighborIter;
void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
const SculptVertRef index,
const SculptVertRef vref,
const bool include_duplicates,
SculptVertexNeighborIter *iter);
@ -147,7 +151,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i];\
neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i];
/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
* first since they are nearest for floodfill. */
@ -155,7 +160,8 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
neighbor_iterator.i--) { \
neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \
neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; \
neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
neighbor_iterator.size - neighbor_iterator.num_duplicates);

View File

@ -119,7 +119,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
int vi = vd.index;
float final_mask = *vd.mask;
if (data->mask_expand_use_normals) {
if (ss->filter_cache->normal_factor[SCULPT_active_vertex_get(ss)] <
if (ss->filter_cache->normal_factor[BKE_pbvh_vertex_index_to_table(ss->pbvh, SCULPT_active_vertex_get(ss))] <
ss->filter_cache->normal_factor[vd.index]) {
final_mask = 1.0f;
}
@ -139,7 +139,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
if (data->mask_expand_create_face_set) {
if (final_mask == 1.0f) {
SCULPT_vertex_face_set_set(ss, vd.index, ss->filter_cache->new_face_set);
SCULPT_vertex_face_set_set(ss, vd.vertex, ss->filter_cache->new_face_set);
}
BKE_pbvh_node_mark_redraw(node);
}
@ -190,7 +190,8 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
mouse[1] = event->mval[1];
if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
/* The cursor is over the mesh, get the update iteration from the updated active vertex. */
mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
int vi = BKE_pbvh_vertex_index_to_table(ss->pbvh, SCULPT_active_vertex_get(ss));
mask_expand_update_it = ss->filter_cache->mask_update_it[vi];
}
else {
/* When the cursor is outside the mesh, affect the entire connected component. */
@ -312,10 +313,13 @@ typedef struct MaskExpandFloodFillData {
} MaskExpandFloodFillData;
static bool mask_expand_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
SculptSession *ss, SculptVertRef from_vref, SculptVertRef to_vref, bool is_duplicate, void *userdata)
{
MaskExpandFloodFillData *data = userdata;
int to_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vref);
int from_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_vref);
if (!is_duplicate) {
int to_it = ss->filter_cache->mask_update_it[from_v] + 1;
ss->filter_cache->mask_update_it[to_v] = to_it;
@ -325,8 +329,8 @@ static bool mask_expand_floodfill_cb(
if (data->use_normals) {
float current_normal[3], prev_normal[3];
SCULPT_vertex_normal_get(ss, to_v, current_normal);
SCULPT_vertex_normal_get(ss, from_v, prev_normal);
SCULPT_vertex_normal_get(ss, to_vref, current_normal);
SCULPT_vertex_normal_get(ss, from_vref, prev_normal);
const float from_edge_factor = ss->filter_cache->edge_factor[from_v];
ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) *
from_edge_factor;
@ -415,13 +419,15 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
else {
ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask");
for (int i = 0; i < vertex_count; i++) {
ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, i);
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, vertex);
}
}
ss->filter_cache->mask_update_last_it = 1;
ss->filter_cache->mask_update_current_it = 1;
ss->filter_cache->mask_update_it[SCULPT_active_vertex_get(ss)] = 0;
ss->filter_cache->mask_update_it[BKE_pbvh_vertex_index_to_table(ss->pbvh, SCULPT_active_vertex_get(ss))] = 0;
copy_v3_v3(ss->filter_cache->mask_expand_initial_co, SCULPT_active_vertex_co_get(ss));
@ -440,9 +446,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
if (use_normals) {
for (int repeat = 0; repeat < 2; repeat++) {
for (int i = 0; i < vertex_count; i++) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
float avg = 0.0f;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) {
avg += ss->filter_cache->normal_factor[ni.index];
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);

View File

@ -106,7 +106,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
/* Sample the normal and area of the +X and -X axis individually. */
@ -208,7 +208,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);

View File

@ -95,11 +95,11 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
float smooth_color[4];
SCULPT_neighbor_color_average(ss, smooth_color, vd.index);
SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex);
blend_color_interpolate_float(vd.col, vd.col, smooth_color, fade);
if (vd.mvert) {
@ -161,7 +161,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
/* Density. */
@ -385,7 +385,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
float current_disp[3];
@ -408,10 +408,10 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vertex_disp[3];
float vertex_disp_norm[3];
sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.vertex), vd.co);
const float *neighbor_color = ss->cache->prev_colors[ni.index];
normalize_v3_v3(vertex_disp_norm, vertex_disp);
if (dot_v3v3(current_disp_norm, vertex_disp_norm) < 0.0f) {
@ -445,7 +445,7 @@ static void do_smear_store_prev_colors_task_cb_exec(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.index));
copy_v4_v4(ss->cache->prev_colors[vd.index], SCULPT_vertex_color_get(ss, vd.vertex));
}
BKE_pbvh_vertex_iter_end;
}
@ -465,7 +465,9 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
if (!ss->cache->prev_colors) {
ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
for (int i = 0; i < totvert; i++) {
copy_v4_v4(ss->cache->prev_colors[i], SCULPT_vertex_color_get(ss, i));
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
copy_v4_v4(ss->cache->prev_colors[i], SCULPT_vertex_color_get(ss, vertex));
}
}
}

View File

@ -238,7 +238,7 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
float max = 0.0f;
/* Grow the factor. */
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
float vmask_f = data->prev_mask[ni.index];
max = MAX2(vmask_f, max);
}
@ -384,7 +384,8 @@ typedef struct PoseFloodFillData {
int current_face_set;
int next_face_set;
int prev_face_set;
int next_vertex;
SculptVertRef next_vertex;
int next_vertex_index;
bool next_face_set_found;
@ -415,10 +416,12 @@ typedef struct PoseFloodFillData {
} PoseFloodFillData;
static bool pose_topology_floodfill_cb(
SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
SculptSession *ss, SculptVertRef UNUSED(from_v), SculptVertRef to_vref, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
const float *co = SCULPT_vertex_co_get(ss, to_v);
int to_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vref);
const float *co = SCULPT_vertex_co_get(ss, to_vref);
if (data->pose_factor) {
data->pose_factor[to_v] = 1.0f;
@ -444,14 +447,14 @@ static bool pose_topology_floodfill_cb(
}
static bool pose_face_sets_floodfill_cb(
SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
SculptSession *ss, SculptVertRef UNUSED(from_v), SculptVertRef to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
const int index = to_v;
const int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v);
bool visit_next = false;
const float *co = SCULPT_vertex_co_get(ss, index);
const float *co = SCULPT_vertex_co_get(ss, to_v);
const bool symmetry_check = SCULPT_check_vertex_pivot_symmetry(
co, data->pose_initial_co, data->symm) &&
!is_duplicate;
@ -465,11 +468,11 @@ static bool pose_face_sets_floodfill_cb(
if (sculpt_pose_brush_is_vertex_inside_brush_radius(
co, data->pose_initial_co, data->radius, data->symm)) {
const int visited_face_set = SCULPT_vertex_face_set_get(ss, index);
const int visited_face_set = SCULPT_vertex_face_set_get(ss, to_v);
BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(visited_face_set));
}
else if (symmetry_check) {
data->current_face_set = SCULPT_vertex_face_set_get(ss, index);
data->current_face_set = SCULPT_vertex_face_set_get(ss, to_v);
BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(data->current_face_set));
}
return true;
@ -483,11 +486,11 @@ static bool pose_face_sets_floodfill_cb(
GSetIterator gs_iter;
GSET_ITER (gs_iter, data->visited_face_sets) {
const int visited_face_set = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
is_vertex_valid |= SCULPT_vertex_has_face_set(ss, index, visited_face_set);
is_vertex_valid |= SCULPT_vertex_has_face_set(ss, to_v, visited_face_set);
}
}
else {
is_vertex_valid = SCULPT_vertex_has_face_set(ss, index, data->current_face_set);
is_vertex_valid = SCULPT_vertex_has_face_set(ss, to_v, data->current_face_set);
}
if (is_vertex_valid) {
@ -500,26 +503,27 @@ static bool pose_face_sets_floodfill_cb(
/* Fallback origin accumulation. */
if (symmetry_check) {
add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, index));
add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, to_v));
data->fallback_count++;
}
if (symmetry_check && !SCULPT_vertex_has_unique_face_set(ss, index)) {
if (symmetry_check && !SCULPT_vertex_has_unique_face_set(ss, to_v)) {
/* We only add coordinates for calculating the origin when it is possible to go from this
* vertex to another vertex in a valid face set for the next iteration. */
bool count_as_boundary = false;
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.index);
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, to_v, ni) {
int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.vertex);
/* Check if we can get a valid face set for the next iteration from this neighbor. */
if (SCULPT_vertex_has_unique_face_set(ss, ni.index) &&
if (SCULPT_vertex_has_unique_face_set(ss, ni.vertex) &&
!BLI_gset_haskey(data->visited_face_sets, POINTER_FROM_INT(next_face_set_candidate))) {
if (!data->next_face_set_found) {
data->next_face_set = next_face_set_candidate;
data->next_vertex = ni.index;
data->next_vertex_index = ni.index;
data->next_vertex = ni.vertex;
data->next_face_set_found = true;
}
count_as_boundary = true;
@ -529,7 +533,7 @@ static bool pose_face_sets_floodfill_cb(
/* Origin accumulation. */
if (count_as_boundary) {
add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, index));
add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, to_v));
data->tot_co++;
}
}
@ -608,7 +612,7 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata,
SculptVertexNeighborIter ni;
float avg = 0.0f;
int total = 0;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
avg += data->pose_factor[ni.index];
total++;
}
@ -683,7 +687,8 @@ static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd,
float next_chain_segment_target[3];
int totvert = SCULPT_vertex_count_get(ss);
int nearest_vertex_index = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true);
SculptVertRef nearest_vertex = SCULPT_nearest_vertex_get(sd, ob, initial_location, FLT_MAX, true);
int nearest_vertex_index = BKE_pbvh_vertex_index_to_table(ss->pbvh, nearest_vertex);
/* Init the buffers used to keep track of the changes in the pose factors as more segments are
* added to the IK chain. */
@ -768,7 +773,8 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
int current_face_set = SCULPT_FACE_SET_NONE;
int prev_face_set = SCULPT_FACE_SET_NONE;
int current_vertex = SCULPT_active_vertex_get(ss);
SculptVertRef current_vertex = SCULPT_active_vertex_get(ss);
int current_vertex_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, current_vertex);
for (int s = 0; s < ik_chain->tot_segments; s++) {
@ -824,9 +830,11 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets(
}
static bool pose_face_sets_fk_find_masked_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
SculptSession *ss, SculptVertRef from_vr, SculptVertRef to_vr, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
int from_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_vr);
int to_v = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_vr);
if (!is_duplicate) {
data->floodfill_it[to_v] = data->floodfill_it[from_v] + 1;
@ -835,11 +843,11 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb(
data->floodfill_it[to_v] = data->floodfill_it[from_v];
}
const int to_face_set = SCULPT_vertex_face_set_get(ss, to_v);
const int to_face_set = SCULPT_vertex_face_set_get(ss, to_vr);
if (!BLI_gset_haskey(data->visited_face_sets, POINTER_FROM_INT(to_face_set))) {
if (SCULPT_vertex_has_unique_face_set(ss, to_v) &&
!SCULPT_vertex_has_unique_face_set(ss, from_v) &&
SCULPT_vertex_has_face_set(ss, from_v, to_face_set)) {
if (SCULPT_vertex_has_unique_face_set(ss, to_vr) &&
!SCULPT_vertex_has_unique_face_set(ss, from_vr) &&
SCULPT_vertex_has_face_set(ss, from_vr, to_face_set)) {
BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(to_face_set));
@ -854,14 +862,14 @@ static bool pose_face_sets_fk_find_masked_floodfill_cb(
}
}
return SCULPT_vertex_has_face_set(ss, to_v, data->initial_face_set);
return SCULPT_vertex_has_face_set(ss, to_vr, data->initial_face_set);
}
static bool pose_face_sets_fk_set_weights_floodfill_cb(
SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
SculptSession *ss, SculptVertRef UNUSED(from_v), SculptVertRef to_v, bool UNUSED(is_duplicate), void *userdata)
{
PoseFloodFillData *data = userdata;
data->fk_weights[to_v] = 1.0f;
data->fk_weights[BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v)] = 1.0f;
return !SCULPT_vertex_has_face_set(ss, to_v, data->masked_face_set);
}
@ -872,7 +880,9 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert);
const int active_vertex = SCULPT_active_vertex_get(ss);
const SculptVertRef active_vertex = SCULPT_active_vertex_get(ss);
const int active_vertex_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, active_vertex);
const int active_face_set = SCULPT_active_face_set_get(ss);
SculptFloodFill flood;
@ -880,7 +890,7 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
SCULPT_floodfill_add_initial(&flood, active_vertex);
PoseFloodFillData fdata;
fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(int), "floodfill iteration");
fdata.floodfill_it[active_vertex] = 1;
fdata.floodfill_it[active_vertex_i] = 1;
fdata.initial_face_set = active_face_set;
fdata.masked_face_set = SCULPT_FACE_SET_NONE;
fdata.target_face_set = SCULPT_FACE_SET_NONE;
@ -893,9 +903,11 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
int origin_count = 0;
float origin_acc[3] = {0.0f};
for (int i = 0; i < totvert; i++) {
if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) &&
SCULPT_vertex_has_face_set(ss, i, fdata.masked_face_set)) {
add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, i));
SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, vref, fdata.initial_face_set) &&
SCULPT_vertex_has_face_set(ss, vref, fdata.masked_face_set)) {
add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, vref));
origin_count++;
}
}
@ -904,10 +916,12 @@ static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
float target_acc[3] = {0.0f};
if (fdata.target_face_set != fdata.masked_face_set) {
for (int i = 0; i < totvert; i++) {
SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
if (fdata.floodfill_it[i] != 0 &&
SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) &&
SCULPT_vertex_has_face_set(ss, i, fdata.target_face_set)) {
add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, i));
SCULPT_vertex_has_face_set(ss, vref, fdata.initial_face_set) &&
SCULPT_vertex_has_face_set(ss, vref, fdata.target_face_set)) {
add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, vref));
target_count++;
}
}

View File

@ -67,7 +67,9 @@
#include <math.h>
#include <stdlib.h>
void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], SculptVertRef index)
void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float result[3],
SculptVertRef index)
{
float avg[3] = {0.0f, 0.0f, 0.0f};
int total = 0;
@ -79,14 +81,14 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3],
neighbor_count++;
if (is_boundary) {
/* Boundary vertices use only other boundary vertices. */
if (SCULPT_vertex_is_boundary(ss, ni.index)) {
add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
if (SCULPT_vertex_is_boundary(ss, ni.vertex)) {
add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex));
total++;
}
}
else {
/* Interior vertices use all neighbors. */
add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex));
total++;
}
}
@ -164,7 +166,7 @@ void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], SculptVe
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.vertex));
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@ -184,7 +186,7 @@ float SCULPT_neighbor_mask_average(SculptSession *ss, SculptVertRef index)
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
avg += SCULPT_vertex_mask_get(ss, ni.index);
avg += SCULPT_vertex_mask_get(ss, ni.vertex);
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@ -202,7 +204,7 @@ void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], SculptVer
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
add_v4_v4(avg, SCULPT_vertex_color_get(ss, ni.index));
add_v4_v4(avg, SCULPT_vertex_color_get(ss, ni.vertex));
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
@ -244,7 +246,7 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
float disp[3];
@ -277,8 +279,10 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
for (int i = 0; i < totvert; i++) {
float avg[3];
SCULPT_neighbor_coords_average(ss, avg, i);
sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i));
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
SCULPT_neighbor_coords_average(ss, avg, vertex);
sub_v3_v3v3(ss->cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, vertex));
}
}
@ -336,8 +340,8 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
p->index[i],
thread_id);
# else
if (1) {
const float fade = 1.0;
if (1) {
const float fade = 1.0;
# endif
while (ni < MAX_PROXY_NEIGHBORS && p->neighbors[i][ni].node >= 0) {
@ -399,17 +403,17 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
vd.no,
vd.fno,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
vd.index,
vd.vertex,
thread_id);
if (smooth_mask) {
float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask;
float val = SCULPT_neighbor_mask_average(ss, vd.vertex) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
CLAMP(*vd.mask, 0.0f, 1.0f);
}
else {
float avg[3], val[3];
SCULPT_neighbor_coords_average_interior(ss, avg, vd.index);
SCULPT_neighbor_coords_average_interior(ss, avg, vd.vertex);
sub_v3_v3v3(val, avg, vd.co);
madd_v3_v3v3fl(val, vd.co, val, fade);
SCULPT_clip(sd, ss, vd.co, val);
@ -449,7 +453,10 @@ void SCULPT_smooth(Sculpt *sd,
return;
}
SCULPT_vertex_random_access_ensure(ss);
if (type != PBVH_BMESH) {
SCULPT_vertex_random_access_ensure(ss);
}
SCULPT_boundary_info_ensure(ob);
#ifdef PROXY_ADVANCED
@ -508,10 +515,12 @@ void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
float weigthed_o[3], weigthed_q[3], d[3];
SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, v_index);
int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, v_index);
mul_v3_v3fl(weigthed_o, origco, alpha);
mul_v3_v3fl(weigthed_q, co, 1.0f - alpha);
add_v3_v3v3(d, weigthed_o, weigthed_q);
sub_v3_v3v3(laplacian_disp[v_index], laplacian_smooth_co, d);
sub_v3_v3v3(laplacian_disp[index], laplacian_smooth_co, d);
sub_v3_v3v3(disp, laplacian_smooth_co, co);
}
@ -526,15 +535,18 @@ void SCULPT_surface_smooth_displace_step(SculptSession *ss,
float b_avg[3] = {0.0f, 0.0f, 0.0f};
float b_current_vertex[3];
int total = 0;
int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, v_index);
SculptVertexNeighborIter ni;
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_index, ni) {
add_v3_v3(b_avg, laplacian_disp[ni.index]);
total++;
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (total > 0) {
mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / total);
madd_v3_v3fl(b_current_vertex, laplacian_disp[v_index], beta);
madd_v3_v3fl(b_current_vertex, laplacian_disp[index], beta);
mul_v3_fl(b_current_vertex, clamp_f(fade, 0.0f, 1.0f));
sub_v3_v3(co, b_current_vertex);
}
@ -570,7 +582,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
float disp[3];
@ -578,7 +590,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
disp,
vd.co,
ss->cache->surface_smooth_laplacian_disp,
vd.index,
vd.vertex,
orig_data.co,
alpha);
madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
@ -616,10 +628,10 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
vd.vertex,
thread_id);
SCULPT_surface_smooth_displace_step(
ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade);
ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, beta, fade);
}
}
BKE_pbvh_vertex_iter_end;

View File

@ -303,7 +303,7 @@ static bool sculpt_undo_restore_hidden(bContext *C, SculptUndoNode *unode)
MVert *mvert = ss->mvert;
for (int i = 0; i < unode->totvert; i++) {
MVert *v = &mvert[unode->index[i]];
MVert *v = &mvert[unode->index[i].i];
if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) {
BLI_BITMAP_FLIP(unode->vert_hidden, i);
v->flag ^= ME_HIDE;
@ -1064,7 +1064,9 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
}
if (ss->deform_modifiers_active) {
copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]);
int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, unode->index[vd.i]);
copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[index]);
}
}
BKE_pbvh_vertex_iter_end;