commit before merge
This commit is contained in:
parent
f61d4b2e3a
commit
3ae8229843
|
@ -53,6 +53,77 @@ struct TaskParallelTLS;
|
|||
typedef struct PBVH PBVH;
|
||||
typedef struct PBVHNode PBVHNode;
|
||||
|
||||
//#define PROXY_ADVANCED
|
||||
|
||||
// experimental performance test of "data-based programming" approach
|
||||
#ifdef PROXY_ADVANCED
|
||||
typedef struct ProxyKey {
|
||||
int node;
|
||||
int pindex;
|
||||
} ProxyKey;
|
||||
|
||||
# define MAX_PROXY_NEIGHBORS 12
|
||||
|
||||
typedef struct ProxyVertArray {
|
||||
float **ownerco;
|
||||
short **ownerno;
|
||||
float (*co)[3];
|
||||
float (*fno)[3];
|
||||
short (*no)[3];
|
||||
float *mask, **ownermask;
|
||||
int *index;
|
||||
float **ownercolor, (*color)[4];
|
||||
|
||||
ProxyKey (*neighbors)[MAX_PROXY_NEIGHBORS];
|
||||
|
||||
int size;
|
||||
int datamask;
|
||||
|
||||
GHash *indexmap;
|
||||
} ProxyVertArray;
|
||||
|
||||
typedef enum {
|
||||
PV_OWNERCO = 1,
|
||||
PV_OWNERNO = 2,
|
||||
PV_CO = 4,
|
||||
PV_NO = 8,
|
||||
PV_MASK = 16,
|
||||
PV_OWNERMASK = 32,
|
||||
PV_INDEX = 64,
|
||||
PV_OWNERCOLOR = 128,
|
||||
PV_COLOR = 256,
|
||||
PV_NEIGHBORS = 512
|
||||
} ProxyVertField;
|
||||
|
||||
typedef struct ProxyVertUpdateRec {
|
||||
float *co, *no, *mask, *color;
|
||||
int index, newindex;
|
||||
} ProxyVertUpdateRec;
|
||||
|
||||
# define PBVH_PROXY_DEFAULT CO | INDEX | MASK
|
||||
|
||||
struct SculptSession;
|
||||
|
||||
void BKE_pbvh_ensure_proxyarrays(struct SculptSession *ss, PBVH *pbvh, int mask);
|
||||
void BKE_pbvh_load_proxyarrays(PBVH *pbvh, PBVHNode **nodes, int totnode, int mask);
|
||||
|
||||
void BKE_pbvh_ensure_proxyarray(
|
||||
struct SculptSession *ss,
|
||||
struct PBVH *pbvh,
|
||||
struct PBVHNode *node,
|
||||
int mask,
|
||||
struct GHash
|
||||
*vert_node_map, // vert_node_map maps vertex SculptIdxs to PBVHNode indices; optional
|
||||
bool check_indexmap,
|
||||
bool force_update);
|
||||
void BKE_pbvh_gather_proxyarray(PBVH *pbvh, PBVHNode **nodes, int totnode);
|
||||
|
||||
void BKE_pbvh_free_proxyarray(struct PBVH *pbvh, struct PBVHNode *node);
|
||||
void BKE_pbvh_update_proxyvert(struct PBVH *pbvh, struct PBVHNode *node, ProxyVertUpdateRec *rec);
|
||||
ProxyVertArray *BKE_pbvh_get_proxyarrays(struct PBVH *pbvh, struct PBVHNode *node);
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
float (*co)[3];
|
||||
} PBVHProxyNode;
|
||||
|
|
|
@ -3067,3 +3067,379 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
|
|||
{
|
||||
pbvh->respect_hide = respect_hide;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PROXY_ADVANCED
|
||||
// TODO: if this really works, make sure to pull the neighbor iterator out of sculpt.c and put it
|
||||
// here
|
||||
/* clang-format off */
|
||||
# include "BKE_context.h"
|
||||
# include "DNA_object_types.h"
|
||||
# include "DNA_scene_types.h"
|
||||
# include "../../editors/sculpt_paint/sculpt_intern.h"
|
||||
/* clang-format on */
|
||||
|
||||
int checkalloc(void **data, int esize, int oldsize, int newsize, int emask, int umask)
|
||||
{
|
||||
if (!*data && (emask & umask)) {
|
||||
*data = MEM_callocN(newsize * esize, "pbvh proxy vert arrays");
|
||||
return emask;
|
||||
}
|
||||
// update channel if it already was allocated once, or is requested by umask
|
||||
else if (newsize != oldsize && (*data || (emask & umask))) {
|
||||
*data = MEM_reallocN(data, newsize * esize);
|
||||
return emask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BKE_pbvh_ensure_proxyarray_indexmap(PBVH *pbvh, PBVHNode *node, GHash *vert_node_map)
|
||||
{
|
||||
ProxyVertArray *p = &node->proxyverts;
|
||||
|
||||
int totvert = 0;
|
||||
BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
|
||||
|
||||
bool update = !p->indexmap || p->size != totvert;
|
||||
|
||||
if (!update) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->indexmap) {
|
||||
BLI_ghash_free(p->indexmap, NULL, NULL);
|
||||
}
|
||||
|
||||
GHash *gs = p->indexmap = BLI_ghash_ptr_new("BKE_pbvh_ensure_proxyarray_indexmap");
|
||||
|
||||
PBVHVertexIter vd;
|
||||
|
||||
int i = 0;
|
||||
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
|
||||
{
|
||||
BLI_ghash_insert(gs, (void *)vd.index, (void *)i);
|
||||
i++;
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
bool pbvh_proxyarray_needs_update(PBVH *pbvh, PBVHNode *node, int mask)
|
||||
{
|
||||
ProxyVertArray *p = &node->proxyverts;
|
||||
int totvert = 0;
|
||||
|
||||
BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
|
||||
|
||||
bool bad = p->size != totvert || !p->neighbors;
|
||||
bad = bad || (p->datamask & mask) != mask;
|
||||
|
||||
bad = bad && totvert > 0;
|
||||
|
||||
return bad;
|
||||
}
|
||||
|
||||
GHash *pbvh_build_vert_node_map(PBVH *pbvh, int mask)
|
||||
{
|
||||
GHash *vert_node_map = BLI_ghash_ptr_new("BKE_pbvh_ensure_proxyarrays");
|
||||
|
||||
for (int i = 0; i < pbvh->totnode; i++) {
|
||||
PBVHVertexIter vd;
|
||||
PBVHNode *node = pbvh->nodes + i;
|
||||
|
||||
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
|
||||
{
|
||||
BLI_ghash_insert(vert_node_map, (void *)vd.index, (void *)i);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
return vert_node_map;
|
||||
}
|
||||
|
||||
void BKE_pbvh_ensure_proxyarrays(SculptSession *ss, PBVH *pbvh, int mask)
|
||||
{
|
||||
|
||||
bool update = false;
|
||||
|
||||
for (int i = 0; i < pbvh->totnode; i++) {
|
||||
if (pbvh_proxyarray_needs_update(pbvh, pbvh->nodes + i, mask)) {
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!update) {
|
||||
return;
|
||||
}
|
||||
|
||||
GHash *vert_node_map = pbvh_build_vert_node_map(pbvh, mask);
|
||||
|
||||
for (int i = 0; i < pbvh->totnode; i++) {
|
||||
BKE_pbvh_ensure_proxyarray_indexmap(pbvh, pbvh->nodes + i, vert_node_map);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pbvh->totnode; i++) {
|
||||
BKE_pbvh_ensure_proxyarray(ss, pbvh, pbvh->nodes + i, mask, vert_node_map, false, false);
|
||||
}
|
||||
|
||||
if (vert_node_map) {
|
||||
BLI_ghash_free(vert_node_map, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_pbvh_ensure_proxyarray(SculptSession *ss,
|
||||
PBVH *pbvh,
|
||||
PBVHNode *node,
|
||||
int mask,
|
||||
GHash *vert_node_map,
|
||||
bool check_indexmap,
|
||||
bool force_update)
|
||||
{
|
||||
ProxyVertArray *p = &node->proxyverts;
|
||||
|
||||
if (check_indexmap) {
|
||||
BKE_pbvh_ensure_proxyarray_indexmap(pbvh, node, vert_node_map);
|
||||
}
|
||||
|
||||
GHash *gs = p->indexmap;
|
||||
|
||||
int totvert = 0;
|
||||
BKE_pbvh_node_num_verts(pbvh, node, &totvert, NULL);
|
||||
|
||||
if (!totvert) {
|
||||
return;
|
||||
}
|
||||
|
||||
int updatemask = 0;
|
||||
|
||||
# define UPDATETEST(name, emask, esize) \
|
||||
if (mask & emask) { \
|
||||
updatemask |= checkalloc((void **)&p->name, esize, p->size, totvert, emask, mask); \
|
||||
}
|
||||
|
||||
UPDATETEST(ownerco, PV_OWNERCO, sizeof(void *))
|
||||
UPDATETEST(ownerno, PV_OWNERNO, sizeof(void *))
|
||||
UPDATETEST(ownermask, PV_OWNERMASK, sizeof(void *))
|
||||
UPDATETEST(ownercolor, PV_OWNERCOLOR, sizeof(void *))
|
||||
UPDATETEST(co, PV_CO, sizeof(float) * 3)
|
||||
UPDATETEST(no, PV_NO, sizeof(short) * 3)
|
||||
UPDATETEST(fno, PV_NO, sizeof(float) * 3)
|
||||
UPDATETEST(mask, PV_MASK, sizeof(float))
|
||||
UPDATETEST(color, PV_COLOR, sizeof(float) * 4)
|
||||
UPDATETEST(index, PV_INDEX, sizeof(int))
|
||||
UPDATETEST(neighbors, PV_NEIGHBORS, sizeof(ProxyKey) * MAX_PROXY_NEIGHBORS)
|
||||
|
||||
p->size = totvert;
|
||||
|
||||
if (force_update) {
|
||||
updatemask |= mask;
|
||||
}
|
||||
|
||||
if (!updatemask) {
|
||||
return;
|
||||
}
|
||||
|
||||
p->datamask |= mask;
|
||||
|
||||
PBVHVertexIter vd;
|
||||
|
||||
int i = 0;
|
||||
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
|
||||
{
|
||||
BLI_ghash_insert(gs, (void *)vd.index, (void *)i);
|
||||
i++;
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
i = 0;
|
||||
BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE)
|
||||
{
|
||||
if (updatemask & PV_OWNERCO) {
|
||||
p->ownerco[i] = vd.co;
|
||||
}
|
||||
if (updatemask & PV_INDEX) {
|
||||
p->index[i] = vd.index;
|
||||
}
|
||||
if (updatemask & PV_OWNERNO) {
|
||||
p->ownerno[i] = vd.no;
|
||||
}
|
||||
if (updatemask & PV_NO) {
|
||||
copy_v3_v3_short(p->no[i], vd.no);
|
||||
normal_short_to_float_v3(p->fno[i], vd.no);
|
||||
}
|
||||
if (updatemask & PV_CO) {
|
||||
copy_v3_v3(p->co[i], vd.co);
|
||||
}
|
||||
if (updatemask & PV_OWNERMASK) {
|
||||
p->ownermask[i] = vd.mask;
|
||||
}
|
||||
if (updatemask & PV_MASK) {
|
||||
p->mask[i] = vd.mask ? *vd.mask : 0.0f;
|
||||
}
|
||||
if (updatemask & PV_COLOR) {
|
||||
if (vd.vcol) {
|
||||
copy_v4_v4(p->color[i], vd.vcol->color);
|
||||
}
|
||||
}
|
||||
|
||||
if (updatemask & PV_NEIGHBORS) {
|
||||
int j = 0;
|
||||
SculptVertexNeighborIter ni;
|
||||
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
|
||||
if (j >= MAX_PROXY_NEIGHBORS - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
ProxyKey key;
|
||||
|
||||
int *pindex = (int *)BLI_ghash_lookup_p(gs, (void *)ni.index);
|
||||
|
||||
if (!pindex) {
|
||||
if (vert_node_map) {
|
||||
int *nindex = BLI_ghash_lookup_p(vert_node_map, (void *)ni.index);
|
||||
|
||||
if (!nindex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PBVHNode *node2 = pbvh->nodes + *nindex;
|
||||
if (node2->proxyverts.indexmap) {
|
||||
pindex = (int *)BLI_ghash_lookup_p(node2->proxyverts.indexmap, (void *)ni.index);
|
||||
}
|
||||
|
||||
if (!pindex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
key.node = (int)(node2 - pbvh->nodes);
|
||||
key.pindex = *pindex;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
key.node = (int)(node - pbvh->nodes);
|
||||
key.pindex = *pindex;
|
||||
}
|
||||
|
||||
p->neighbors[i][j++] = key;
|
||||
}
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
|
||||
|
||||
p->neighbors[i][j].node = -1;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
typedef struct GatherProxyThread {
|
||||
PBVHNode **nodes;
|
||||
PBVH *pbvh;
|
||||
int mask;
|
||||
} GatherProxyThread;
|
||||
|
||||
static void pbvh_load_proxyarray_exec(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
GatherProxyThread *data = (GatherProxyThread *)userdata;
|
||||
PBVHNode *node = data->nodes[n];
|
||||
PBVHVertexIter vd;
|
||||
ProxyVertArray *p = &node->proxyverts;
|
||||
int i = 0;
|
||||
|
||||
int mask = p->datamask;
|
||||
|
||||
BKE_pbvh_ensure_proxyarray(NULL, data->pbvh, node, data->mask, NULL, false, true);
|
||||
}
|
||||
|
||||
void BKE_pbvh_load_proxyarrays(PBVH *pbvh, PBVHNode **nodes, int totnode, int mask)
|
||||
{
|
||||
GatherProxyThread data = {.nodes = nodes, .pbvh = pbvh, .mask = mask};
|
||||
|
||||
mask = mask & ~PV_NEIGHBORS; //don't update neighbors in threaded code?
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
BLI_task_parallel_range(0, totnode, &data, pbvh_load_proxyarray_exec, &settings);
|
||||
}
|
||||
|
||||
static void pbvh_gather_proxyarray_exec(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
GatherProxyThread *data = (GatherProxyThread *)userdata;
|
||||
PBVHNode *node = data->nodes[n];
|
||||
PBVHVertexIter vd;
|
||||
ProxyVertArray *p = &node->proxyverts;
|
||||
int i = 0;
|
||||
|
||||
int mask = p->datamask;
|
||||
|
||||
BKE_pbvh_vertex_iter_begin(data->pbvh, node, vd, PBVH_ITER_UNIQUE)
|
||||
{
|
||||
if (mask & PV_CO) {
|
||||
copy_v3_v3(vd.co, p->co[i]);
|
||||
}
|
||||
|
||||
if (vd.mask && (mask & PV_MASK)) {
|
||||
*vd.mask = p->mask[i];
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
void BKE_pbvh_gather_proxyarray(PBVH *pbvh, PBVHNode **nodes, int totnode)
|
||||
{
|
||||
GatherProxyThread data = {.nodes = nodes, .pbvh = pbvh};
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
BLI_task_parallel_range(0, totnode, &data, pbvh_gather_proxyarray_exec, &settings);
|
||||
}
|
||||
|
||||
void BKE_pbvh_free_proxyarray(PBVH *pbvh, PBVHNode *node)
|
||||
{
|
||||
ProxyVertArray *p = &node->proxyverts;
|
||||
|
||||
if (p->co)
|
||||
MEM_freeN(p->co);
|
||||
if (p->no)
|
||||
MEM_freeN(p->no);
|
||||
if (p->index)
|
||||
MEM_freeN(p->index);
|
||||
if (p->mask)
|
||||
MEM_freeN(p->mask);
|
||||
if (p->ownerco)
|
||||
MEM_freeN(p->ownerco);
|
||||
if (p->ownerno)
|
||||
MEM_freeN(p->ownerno);
|
||||
if (p->ownermask)
|
||||
MEM_freeN(p->ownermask);
|
||||
if (p->ownercolor)
|
||||
MEM_freeN(p->ownercolor);
|
||||
if (p->color)
|
||||
MEM_freeN(p->color);
|
||||
if (p->neighbors)
|
||||
MEM_freeN(p->neighbors);
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
|
||||
void BKE_pbvh_update_proxyvert(PBVH *pbvh, PBVHNode *node, ProxyVertUpdateRec *rec)
|
||||
{
|
||||
}
|
||||
|
||||
ProxyVertArray *BKE_pbvh_get_proxyarrays(PBVH *pbvh, PBVHNode *node)
|
||||
{
|
||||
return &node->proxyverts;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -107,6 +107,9 @@ struct PBVHNode {
|
|||
|
||||
/* Used to store the brush color during a stroke and composite it over the original color */
|
||||
PBVHColorBufferNode color_buffer;
|
||||
#ifdef PROXY_ADVANCED
|
||||
ProxyVertArray proxyverts;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -346,7 +346,7 @@ void MESH_OT_paint_mask_extract(wmOperatorType *ot)
|
|||
ot->invoke = paint_mask_extract_invoke;
|
||||
ot->exec = paint_mask_extract_exec;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER;
|
||||
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
RNA_def_float(
|
||||
ot->srna,
|
||||
|
|
|
@ -58,7 +58,12 @@
|
|||
#include "RNA_define.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
#ifdef PROXY_ADVANCED
|
||||
/* clang-format off */
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "../../blenkernel/intern/pbvh_intern.h"
|
||||
/* clang-format on */
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -289,6 +294,79 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
|
|||
BLI_task_parallel_range(0, totnode, &data, do_enhance_details_brush_task_cb_ex, &settings);
|
||||
}
|
||||
|
||||
#ifdef PROXY_ADVANCED
|
||||
static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
SculptThreadedTaskData *data = userdata;
|
||||
SculptSession *ss = data->ob->sculpt;
|
||||
Sculpt *sd = data->sd;
|
||||
const Brush *brush = data->brush;
|
||||
const bool smooth_mask = data->smooth_mask;
|
||||
float bstrength = data->strength;
|
||||
|
||||
PBVHVertexIter vd;
|
||||
|
||||
CLAMP(bstrength, 0.0f, 1.0f);
|
||||
|
||||
SculptBrushTest test;
|
||||
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
|
||||
ss, &test, data->brush->falloff_shape);
|
||||
|
||||
const int thread_id = BLI_task_parallel_thread_id(tls);
|
||||
|
||||
PBVHNode **nodes = data->nodes;
|
||||
ProxyVertArray *p = &nodes[n]->proxyverts;
|
||||
|
||||
for (int i = 0; i < p->size; i++) {
|
||||
float co[3] = {0.0f, 0.0f, 0.0f};
|
||||
int ni = 0;
|
||||
|
||||
# if 1
|
||||
if (sculpt_brush_test_sq_fn(&test, p->co[i])) {
|
||||
const float fade = bstrength * SCULPT_brush_strength_factor(
|
||||
ss,
|
||||
brush,
|
||||
p->co[i],
|
||||
sqrtf(test.dist),
|
||||
p->no[i],
|
||||
p->fno[i],
|
||||
smooth_mask ? 0.0f : (p->mask ? p->mask[i] : 0.0f),
|
||||
p->index[i],
|
||||
thread_id);
|
||||
# else
|
||||
if (1) {
|
||||
const float fade = 1.0;
|
||||
# endif
|
||||
|
||||
while (ni < MAX_PROXY_NEIGHBORS && p->neighbors[i][ni].node >= 0) {
|
||||
ProxyKey *key = p->neighbors[i] + ni;
|
||||
PBVHNode *n2 = ss->pbvh->nodes + key->node;
|
||||
|
||||
// printf("%d %d %d %p\n", key->node, key->pindex, ss->pbvh->totnode, n2);
|
||||
|
||||
add_v3_v3(co, n2->proxyverts.co[key->pindex]);
|
||||
ni++;
|
||||
}
|
||||
|
||||
// printf("ni %d\n", ni);
|
||||
|
||||
if (ni > 2) {
|
||||
mul_v3_fl(co, 1.0f / (float)ni);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(co, p->co[i]);
|
||||
}
|
||||
|
||||
// printf("%f %f %f ", co[0], co[1], co[2]);
|
||||
|
||||
interp_v3_v3v3(p->co[i], p->co[i], co, fade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
|
@ -343,6 +421,7 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
|
|||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SCULPT_smooth(Sculpt *sd,
|
||||
Object *ob,
|
||||
|
@ -373,6 +452,12 @@ void SCULPT_smooth(Sculpt *sd,
|
|||
SCULPT_vertex_random_access_ensure(ss);
|
||||
SCULPT_boundary_info_ensure(ob);
|
||||
|
||||
#ifdef PROXY_ADVANCED
|
||||
int datamask = PV_CO | PV_NEIGHBORS | PV_NO | PV_INDEX | PV_MASK;
|
||||
BKE_pbvh_ensure_proxyarrays(ss, ss->pbvh, datamask);
|
||||
|
||||
BKE_pbvh_load_proxyarrays(ss->pbvh, nodes, totnode, PV_CO | PV_NO | PV_MASK);
|
||||
#endif
|
||||
for (iteration = 0; iteration <= count; iteration++) {
|
||||
const float strength = (iteration != count) ? 1.0f : last;
|
||||
|
||||
|
@ -388,6 +473,10 @@ void SCULPT_smooth(Sculpt *sd,
|
|||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_task_cb_ex, &settings);
|
||||
|
||||
#ifdef PROXY_ADVANCED
|
||||
BKE_pbvh_gather_proxyarray(ss->pbvh, nodes, totnode);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1878,6 +1878,7 @@ typedef struct UVWarpModifierData {
|
|||
/* UVWarp modifier flags */
|
||||
enum {
|
||||
MOD_UVWARP_INVERT_VGROUP = 1 << 0,
|
||||
MOD_UVWARP_RESTRICT_ISLANDS = 1<<1
|
||||
};
|
||||
|
||||
/* cache modifier */
|
||||
|
|
|
@ -4993,6 +4993,13 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "restrict_to_islands", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_UVWARP_RESTRICT_ISLANDS);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Island Restrict",
|
||||
"Don't affect UVs in faces outside of the vertex group's influence");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
|
||||
RNA_def_property_ui_text(prop, "UV Layer", "UV Layer name");
|
||||
|
|
|
@ -100,6 +100,7 @@ typedef struct UVWarpData {
|
|||
|
||||
MDeformVert *dvert;
|
||||
int defgrp_index;
|
||||
bool restrict_island;
|
||||
|
||||
float (*warp_mat)[4];
|
||||
bool invert_vgroup;
|
||||
|
@ -123,6 +124,19 @@ static void uv_warp_compute(void *__restrict userdata,
|
|||
int l;
|
||||
|
||||
if (dvert) {
|
||||
if (data->restrict_island) {
|
||||
for (l = 0; l < mp->totloop; l++, ml++) {
|
||||
const float weight = data->invert_vgroup ?
|
||||
1.0f - BKE_defvert_find_weight(&dvert[ml->v], defgrp_index) :
|
||||
BKE_defvert_find_weight(&dvert[ml->v], defgrp_index);
|
||||
if (weight == 0.0f) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ml = &data->mloop[mp->loopstart];
|
||||
}
|
||||
|
||||
for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
|
||||
float uv[2];
|
||||
const float weight = data->invert_vgroup ?
|
||||
|
@ -221,6 +235,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||
|
||||
UVWarpData data = {
|
||||
.mpoly = mpoly,
|
||||
.restrict_island = umd->flag & MOD_UVWARP_RESTRICT_ISLANDS,
|
||||
.mloop = mloop,
|
||||
.mloopuv = mloopuv,
|
||||
.dvert = dvert,
|
||||
|
@ -299,6 +314,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
|
|||
}
|
||||
|
||||
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
|
||||
uiItemR(layout, ptr, "restrict_to_islands", 0, NULL, ICON_NONE);
|
||||
|
||||
modifier_panel_end(layout, ptr);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue