Sculpt: fix memory corruption
* Fixed a nasty bit of memory corruption * Along the way, added ASAN support to bmesh customdata blocks. * Each CD layer is padded by 32 bytes inside the bmesh data block. * Also fixed a few minor errors in mempool's asan support. * Tried and failed to fix numerical stability issues with lasso/box trim brushes.
This commit is contained in:
parent
6d07e148b1
commit
f500ef58e2
|
@ -997,3 +997,28 @@ BLI_INLINE bool _pbvh_nan_check(const float *co, const char *func, const char *f
|
|||
return bad;
|
||||
}
|
||||
#define PBVH_CHECK_NAN(co) _pbvh_nan_check(co, __func__, __FILE__, __LINE__)
|
||||
|
||||
typedef struct DynTopoState DynTopoState;
|
||||
|
||||
typedef struct DynRemeshParams {
|
||||
float edge_size;
|
||||
float detail_range;
|
||||
float relax_strength;
|
||||
} DynRemeshParams;
|
||||
|
||||
/*
|
||||
Simple wrapper api to use the dyntopo remesher in
|
||||
non-sculpt contexts.
|
||||
|
||||
existing_pbvh can be NULL.
|
||||
|
||||
Note that all the sculpt customdata layers will be created
|
||||
if they don't exist, so cd_vert/face_node_offset, cd_mask_offset,
|
||||
cd_sculpt_vert, etc*/
|
||||
DynTopoState *BKE_dyntopo_init(struct BMesh *bm, PBVH *existing_pbvh);
|
||||
void BKE_dyntopo_free(DynTopoState *ds);
|
||||
void BKE_dyntopo_default_params(DynRemeshParams *params, float edge_size);
|
||||
void BKE_dyntopo_remesh(DynTopoState *ds,
|
||||
DynRemeshParams *params,
|
||||
int steps,
|
||||
PBVHTopologyUpdateMode mode);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "DNA_hair_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BLI_asan.h"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_endian_switch.h"
|
||||
|
@ -69,6 +70,8 @@
|
|||
/* number of layers to add when growing a CustomData object */
|
||||
#define CUSTOMDATA_GROW 5
|
||||
|
||||
#define BM_ASAN_PAD 32
|
||||
|
||||
/* ensure typemap size is ok */
|
||||
BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch");
|
||||
|
||||
|
@ -2577,8 +2580,16 @@ static void customData_update_offsets(CustomData *data)
|
|||
size += 8 - (size & 7);
|
||||
}
|
||||
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
|
||||
offset += BM_ASAN_PAD;
|
||||
#endif
|
||||
|
||||
data->layers[j].offset = offset;
|
||||
offset += size;
|
||||
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
|
||||
offset += BM_ASAN_PAD;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2589,22 +2600,61 @@ static void customData_update_offsets(CustomData *data)
|
|||
}
|
||||
|
||||
typeInfo = layerType_getInfo(data->layers[j].type);
|
||||
int size = (int)typeInfo->size;
|
||||
|
||||
if (i < ARRAY_SIZE(aligns) && typeInfo->size != aligns[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
|
||||
offset += BM_ASAN_PAD;
|
||||
#endif
|
||||
|
||||
BLI_BITMAP_SET(donemap, j, true);
|
||||
|
||||
data->layers[j].offset = offset;
|
||||
offset += typeInfo->size;
|
||||
offset += size;
|
||||
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
|
||||
offset += BM_ASAN_PAD;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
data->totsize = offset;
|
||||
|
||||
CustomData_update_typemap(data);
|
||||
}
|
||||
|
||||
void CustomData_bmesh_asan_poison(const CustomData *data, void *block)
|
||||
{
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *ptr = (char *)block;
|
||||
|
||||
BLI_asan_unpoison(block, data->totsize);
|
||||
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
CustomDataLayer *layer = data->layers + i;
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
|
||||
|
||||
BLI_asan_poison((ptr + layer->offset - BM_ASAN_PAD), BM_ASAN_PAD);
|
||||
BLI_asan_poison((ptr + layer->offset + typeInfo->size), BM_ASAN_PAD);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CustomData_bmesh_asan_unpoison(const CustomData *data, void *block)
|
||||
{
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
BLI_asan_unpoison(block, data->totsize);
|
||||
}
|
||||
|
||||
/* to use when we're in the middle of modifying layers */
|
||||
static int CustomData_get_layer_index__notypemap(const CustomData *data, int type)
|
||||
{
|
||||
|
@ -3643,6 +3693,13 @@ int CustomData_get_offset(const CustomData *data, int type)
|
|||
return data->layers[layer_index].offset;
|
||||
}
|
||||
|
||||
int CustomData_get_named_offset(const CustomData *data, int type, const char *name)
|
||||
{
|
||||
int idx = CustomData_get_named_layer_index(data, type, name);
|
||||
|
||||
return idx == -1 ? -1 : data->layers[idx].offset;
|
||||
}
|
||||
|
||||
int CustomData_get_n_offset(const CustomData *data, int type, int n)
|
||||
{
|
||||
/* get the layer index of the active layer of type */
|
||||
|
@ -4025,6 +4082,8 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
|
|||
return;
|
||||
}
|
||||
|
||||
CustomData_bmesh_asan_unpoison(data, *block);
|
||||
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
|
||||
|
@ -4051,6 +4110,9 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
|
|||
if (block == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
CustomData_bmesh_asan_unpoison(data, block);
|
||||
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
|
||||
|
@ -4060,9 +4122,12 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data->totsize) {
|
||||
memset(block, 0, data->totsize);
|
||||
}
|
||||
|
||||
CustomData_bmesh_asan_poison(data, block);
|
||||
}
|
||||
|
||||
static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
|
||||
|
@ -4074,6 +4139,8 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
|
|||
if (data->totsize > 0) {
|
||||
*block = BLI_mempool_alloc(data->pool);
|
||||
|
||||
CustomData_bmesh_asan_poison(data, *block);
|
||||
|
||||
/*clear toolflags pointer when created for the first time*/
|
||||
int cd_tflags = data->typemap[CD_TOOLFLAGS];
|
||||
if (cd_tflags != -1) {
|
||||
|
@ -4101,6 +4168,9 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
|
|||
if (block == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
CustomData_bmesh_asan_unpoison(data, block);
|
||||
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
if ((CD_TYPE_AS_MASK(data->layers[i].type) & mask_exclude) == 0) {
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
|
||||
|
@ -4113,6 +4183,8 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
|
|||
memset(POINTER_OFFSET(block, offset), 0, typeInfo->size);
|
||||
}
|
||||
}
|
||||
|
||||
CustomData_bmesh_asan_poison(data, block);
|
||||
}
|
||||
|
||||
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n)
|
||||
|
@ -4146,6 +4218,9 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
|
|||
|
||||
void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **block2)
|
||||
{
|
||||
CustomData_bmesh_asan_unpoison(data, *block1);
|
||||
CustomData_bmesh_asan_unpoison(data, *block2);
|
||||
|
||||
int cd_id = data->typemap[CD_MESH_ID];
|
||||
cd_id = cd_id >= 0 ? data->layers[cd_id].offset : -1;
|
||||
|
||||
|
@ -4178,6 +4253,9 @@ void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **b
|
|||
*flags2 = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
CustomData_bmesh_asan_poison(data, *block1);
|
||||
CustomData_bmesh_asan_poison(data, *block2);
|
||||
}
|
||||
|
||||
void CustomData_bmesh_swap_data(CustomData *source,
|
||||
|
@ -4193,7 +4271,10 @@ void CustomData_bmesh_swap_data(CustomData *source,
|
|||
CustomData_bmesh_alloc_block(dest, dest_block);
|
||||
|
||||
if (*dest_block) {
|
||||
CustomData_bmesh_asan_unpoison(dest, *dest_block);
|
||||
memset(*dest_block, 0, dest->totsize);
|
||||
CustomData_bmesh_asan_poison(dest, *dest_block);
|
||||
|
||||
CustomData_bmesh_set_default(dest, dest_block);
|
||||
}
|
||||
}
|
||||
|
@ -4269,8 +4350,11 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
|
|||
|
||||
if (*dest_block == NULL) {
|
||||
CustomData_bmesh_alloc_block(dest, dest_block);
|
||||
|
||||
if (*dest_block) {
|
||||
CustomData_bmesh_asan_unpoison(dest, *dest_block);
|
||||
memset(*dest_block, 0, dest->totsize);
|
||||
CustomData_bmesh_asan_poison(dest, *dest_block);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -612,7 +612,7 @@ BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v, float fac)
|
|||
BMVert *v2 = e->v1 == v ? e->v2 : e->v1;
|
||||
|
||||
// can't check for boundary here, thread
|
||||
pbvh_check_vert_boundary(pbvh, v2);
|
||||
// pbvh_check_vert_boundary(pbvh, v2);
|
||||
|
||||
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(cd_sculpt_vert, v2);
|
||||
const bool bound2 = mv2->flag & SCULPTVERT_SMOOTH_BOUNDARY;
|
||||
|
@ -4668,6 +4668,11 @@ static bool do_cleanup_3_4(EdgeQueueContext *eq_ctx,
|
|||
return modified;
|
||||
}
|
||||
|
||||
float mask_cb_nop(SculptVertRef vertex, void *userdata)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
/* Collapse short edges, subdivide long edges */
|
||||
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
||||
PBVHTopologyUpdateMode mode,
|
||||
|
@ -4749,30 +4754,6 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
|||
safe_smooth = DYNTOPO_SAFE_SMOOTH_FAC;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
typedef struct EdgeQueueContext {
|
||||
EdgeQueue *q;
|
||||
BLI_mempool *pool;
|
||||
BMesh *bm;
|
||||
DyntopoMaskCB mask_cb;
|
||||
void *mask_cb_data;
|
||||
int cd_sculpt_vert;
|
||||
int cd_vert_mask_offset;
|
||||
int cd_vert_node_offset;
|
||||
int cd_face_node_offset;
|
||||
float avg_elen;
|
||||
float max_elen;
|
||||
float min_elen;
|
||||
float totedge;
|
||||
BMVert **val34_verts;
|
||||
int val34_verts_tot;
|
||||
int val34_verts_size;
|
||||
bool local_mode;
|
||||
float surface_smooth_fac;
|
||||
} EdgeQueueContext;
|
||||
*/
|
||||
EdgeQueueContext eq_ctx = {.q = NULL,
|
||||
.pool = NULL,
|
||||
.bm = pbvh->bm,
|
||||
|
@ -5702,3 +5683,271 @@ static void pbvh_split_edges(EdgeQueueContext *eq_ctx,
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
extern char dyntopop_node_idx_layer_id[];
|
||||
extern char dyntopop_faces_areas_layer_id[];
|
||||
|
||||
typedef struct DynTopoState {
|
||||
PBVH *pbvh;
|
||||
bool is_fake_pbvh;
|
||||
} DynTopoState;
|
||||
|
||||
/* existing_pbvh may be NULL, if so a fake one will be created.
|
||||
Note that all the sculpt customdata layers will be created
|
||||
if they don't exist, so cd_vert/face_node_offset, cd_mask_offset,
|
||||
cd_sculpt_vert, etc*/
|
||||
DynTopoState *BKE_dyntopo_init(BMesh *bm, PBVH *existing_pbvh)
|
||||
{
|
||||
PBVH *pbvh;
|
||||
PBVHNode _node;
|
||||
PBVH _start;
|
||||
|
||||
if (!existing_pbvh) {
|
||||
pbvh = MEM_callocN(sizeof(*pbvh), "pbvh");
|
||||
|
||||
pbvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
|
||||
pbvh->type = PBVH_BMESH;
|
||||
pbvh->totnode = 1;
|
||||
|
||||
PBVHNode *node = pbvh->nodes;
|
||||
|
||||
node->flag = PBVH_Leaf | PBVH_UpdateTris | PBVH_UpdateTriAreas;
|
||||
node->bm_faces = BLI_table_gset_new_ex("node->bm_faces", bm->totface);
|
||||
node->bm_unique_verts = BLI_table_gset_new_ex("node->bm_unique_verts", bm->totvert);
|
||||
}
|
||||
else {
|
||||
pbvh = existing_pbvh;
|
||||
}
|
||||
|
||||
const bool isfake = pbvh != existing_pbvh;
|
||||
|
||||
BMCustomLayerReq vlayers[] = {
|
||||
{CD_PAINT_MASK, NULL, 0},
|
||||
{CD_DYNTOPO_VERT, NULL, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY},
|
||||
{CD_PROP_INT32, dyntopop_node_idx_layer_id, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY}};
|
||||
|
||||
BMCustomLayerReq flayers[] = {
|
||||
{CD_PROP_FLOAT, dyntopop_faces_areas_layer_id, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY},
|
||||
{CD_SCULPT_FACE_SETS, NULL, 0},
|
||||
{CD_PROP_INT32, dyntopop_node_idx_layer_id, CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY}};
|
||||
|
||||
BM_data_layers_ensure(bm, &bm->vdata, vlayers, 3);
|
||||
BM_data_layers_ensure(bm, &bm->pdata, flayers, 3);
|
||||
|
||||
int CustomData_get_named_offset(const CustomData *data, int type, const char *name);
|
||||
|
||||
pbvh->bm = bm;
|
||||
|
||||
pbvh->cd_vert_node_offset = CustomData_get_named_offset(
|
||||
&bm->vdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
|
||||
|
||||
pbvh->cd_face_node_offset = CustomData_get_named_offset(
|
||||
&bm->pdata, CD_PROP_INT32, dyntopop_node_idx_layer_id);
|
||||
|
||||
pbvh->cd_face_area = CustomData_get_named_offset(
|
||||
&bm->pdata, CD_PROP_FLOAT, dyntopop_faces_areas_layer_id);
|
||||
|
||||
pbvh->cd_sculpt_vert = CustomData_get_offset(&bm->vdata, CD_DYNTOPO_VERT);
|
||||
pbvh->cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
|
||||
pbvh->cd_faceset_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
|
||||
pbvh->cd_vcol_offset = -1;
|
||||
|
||||
if (isfake) {
|
||||
pbvh->bm_log = BM_log_create(bm, pbvh->cd_sculpt_vert);
|
||||
}
|
||||
|
||||
BMVert *v;
|
||||
BMFace *f;
|
||||
BMIter iter;
|
||||
|
||||
if (isfake) {
|
||||
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, 0);
|
||||
BLI_table_gset_add(pbvh->nodes->bm_unique_verts, v);
|
||||
}
|
||||
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, 0);
|
||||
BLI_table_gset_add(pbvh->nodes->bm_faces, f);
|
||||
}
|
||||
|
||||
BKE_pbvh_bmesh_check_tris(pbvh, pbvh->nodes);
|
||||
}
|
||||
|
||||
DynTopoState *ds = MEM_callocN(sizeof(DynTopoState), "DynTopoState");
|
||||
|
||||
ds->pbvh = pbvh;
|
||||
ds->is_fake_pbvh = isfake;
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
void BKE_dyntopo_default_params(DynRemeshParams *params, float edge_size)
|
||||
{
|
||||
memset(params, 0, sizeof(*params));
|
||||
params->detail_range = 0.45f;
|
||||
params->edge_size = edge_size;
|
||||
}
|
||||
|
||||
void BKE_dyntopo_free(DynTopoState *ds)
|
||||
{
|
||||
if (ds->is_fake_pbvh) {
|
||||
BM_log_free(ds->pbvh->bm_log, false);
|
||||
|
||||
PBVHNode *node = ds->pbvh->nodes;
|
||||
|
||||
if (node->tribuf || node->tri_buffers) {
|
||||
BKE_pbvh_bmesh_free_tris(ds->pbvh, node);
|
||||
}
|
||||
|
||||
BLI_table_gset_free(node->bm_faces, NULL);
|
||||
BLI_table_gset_free(node->bm_unique_verts, NULL);
|
||||
|
||||
MEM_freeN(ds->pbvh->nodes);
|
||||
MEM_freeN(ds->pbvh);
|
||||
}
|
||||
|
||||
MEM_freeN(ds);
|
||||
}
|
||||
|
||||
/*
|
||||
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
||||
PBVHTopologyUpdateMode mode,
|
||||
const float center[3],
|
||||
const float view_normal[3],
|
||||
float radius,
|
||||
const bool use_frontface,
|
||||
const bool use_projected,
|
||||
int sym_axis,
|
||||
bool updatePBVH,
|
||||
DyntopoMaskCB mask_cb,
|
||||
void *mask_cb_data,
|
||||
int custom_max_steps,
|
||||
bool disable_surface_relax)
|
||||
*/
|
||||
void BKE_dyntopo_remesh(DynTopoState *ds,
|
||||
DynRemeshParams *params,
|
||||
int steps,
|
||||
PBVHTopologyUpdateMode mode)
|
||||
{
|
||||
float cent[3] = {0.0f, 0.0f, 0.0f};
|
||||
int totcent = 0;
|
||||
float view[3] = {0.0f, 0.0f, 1.0f};
|
||||
|
||||
BMIter iter;
|
||||
BMVert *v;
|
||||
|
||||
BM_ITER_MESH (v, &iter, ds->pbvh->bm, BM_VERTS_OF_MESH) {
|
||||
MSculptVert *mv = BKE_PBVH_SCULPTVERT(ds->pbvh->cd_sculpt_vert, v);
|
||||
|
||||
mv->flag |= SCULPTVERT_NEED_BOUNDARY | SCULPTVERT_NEED_TRIANGULATE;
|
||||
mv->valence = BM_vert_edge_count(v);
|
||||
|
||||
pbvh_check_vert_boundary(ds->pbvh, v);
|
||||
|
||||
add_v3_v3(cent, v->co);
|
||||
totcent;
|
||||
}
|
||||
|
||||
if (totcent) {
|
||||
mul_v3_fl(cent, 1.0f / (float)totcent);
|
||||
}
|
||||
|
||||
ds->pbvh->bm_max_edge_len = params->edge_size;
|
||||
ds->pbvh->bm_min_edge_len = params->edge_size * params->detail_range;
|
||||
ds->pbvh->bm_detail_range = params->detail_range;
|
||||
|
||||
/* subdivide once */
|
||||
if (mode & PBVH_Subdivide) {
|
||||
BKE_pbvh_bmesh_update_topology(ds->pbvh,
|
||||
PBVH_Subdivide,
|
||||
cent,
|
||||
view,
|
||||
1e17,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
mask_cb_nop,
|
||||
NULL,
|
||||
ds->pbvh->bm->totedge,
|
||||
false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < steps; i++) {
|
||||
for (int j = 0; j < ds->pbvh->totnode; j++) {
|
||||
PBVHNode *node = ds->pbvh->nodes + j;
|
||||
|
||||
if (node->flag & PBVH_Leaf) {
|
||||
node->flag |= PBVH_UpdateTopology;
|
||||
}
|
||||
}
|
||||
|
||||
BKE_pbvh_bmesh_update_topology(ds->pbvh,
|
||||
mode,
|
||||
cent,
|
||||
view,
|
||||
1e17,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
false,
|
||||
mask_cb_nop,
|
||||
NULL,
|
||||
ds->pbvh->bm->totedge * 5,
|
||||
true);
|
||||
|
||||
BKE_pbvh_update_normals(ds->pbvh, NULL);
|
||||
|
||||
BM_ITER_MESH (v, &iter, ds->pbvh->bm, BM_VERTS_OF_MESH) {
|
||||
MSculptVert *mv = BKE_PBVH_SCULPTVERT(ds->pbvh->cd_sculpt_vert, v);
|
||||
pbvh_check_vert_boundary(ds->pbvh, v);
|
||||
|
||||
float avg[3] = {0.0f, 0.0f, 0.0f};
|
||||
float totw = 0.0f;
|
||||
|
||||
bool bound1 = mv->flag & SCULPTVERT_ALL_BOUNDARY;
|
||||
if (bound1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mv->flag & SCULPTVERT_ALL_CORNER) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!v->e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BMEdge *e = v->e;
|
||||
do {
|
||||
BMVert *v2 = BM_edge_other_vert(e, v);
|
||||
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(ds->pbvh->cd_sculpt_vert, v2);
|
||||
|
||||
pbvh_check_vert_boundary(ds->pbvh, v2);
|
||||
bool bound2 = mv2->flag & SCULPTVERT_ALL_BOUNDARY;
|
||||
|
||||
if (bound1 && !bound2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float tmp[3];
|
||||
float w = 1.0f;
|
||||
|
||||
sub_v3_v3v3(tmp, v2->co, v->co);
|
||||
madd_v3_v3fl(tmp, v->no, -dot_v3v3(v->no, tmp) * 0.75);
|
||||
add_v3_v3(tmp, v->co);
|
||||
madd_v3_v3fl(avg, tmp, w);
|
||||
|
||||
totw += w;
|
||||
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
|
||||
|
||||
if (totw == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mul_v3_fl(avg, 1.0f / totw);
|
||||
interp_v3_v3v3(v->co, v->co, avg, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
|
||||
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
|
||||
# define POISON_REDZONE_SIZE 32
|
||||
# define HAVE_MEMPOOL_ASAN
|
||||
#else
|
||||
# define POISON_REDZONE_SIZE 0
|
||||
#endif
|
||||
|
@ -141,12 +142,16 @@ struct BLI_mempool {
|
|||
uint flag;
|
||||
/* keeps aligned to 16 bits */
|
||||
|
||||
#ifdef HAVE_MEMPOOL_ASAN
|
||||
char poisoned[256];
|
||||
#endif
|
||||
|
||||
/** Free element list. Interleaved into chunk datas. */
|
||||
BLI_freenode *free;
|
||||
/** Use to know how many chunks to keep for #BLI_mempool_clear. */
|
||||
uint maxchunks;
|
||||
/** Number of elements currently in use. */
|
||||
uint totused;
|
||||
int totused;
|
||||
#ifdef USE_TOTALLOC
|
||||
/** Number of elements allocated in total. */
|
||||
uint totalloc;
|
||||
|
@ -227,7 +232,7 @@ BLI_INLINE uint mempool_maxchunks(const uint totelem, const uint pchunk)
|
|||
|
||||
static BLI_mempool_chunk *mempool_chunk_alloc(BLI_mempool *pool)
|
||||
{
|
||||
return MEM_mallocN(sizeof(BLI_mempool_chunk) + (size_t)pool->csize, pool->memtag);
|
||||
return BLI_asan_safe_malloc(sizeof(BLI_mempool_chunk) + (size_t)pool->csize, pool->memtag);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -289,7 +294,7 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
|
|||
while (j--) {
|
||||
BLI_freenode *next;
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
|
||||
|
||||
curnode->next = next = NODE_STEP_NEXT(curnode);
|
||||
curnode->freeword = FREEWORD;
|
||||
|
@ -303,7 +308,7 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
|
|||
while (j--) {
|
||||
BLI_freenode *next;
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
|
||||
curnode->next = next = NODE_STEP_NEXT(curnode);
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
|
@ -314,13 +319,13 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
|
|||
/* terminate the list (rewind one)
|
||||
* will be overwritten if 'curnode' gets passed in again as 'last_tail' */
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
|
||||
BLI_freenode *prev = NODE_STEP_PREV(curnode);
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
curnode = NODE_STEP_PREV(curnode);
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
|
||||
curnode->next = NULL;
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
|
@ -330,7 +335,7 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
|
|||
|
||||
/* final pointer in the previously allocated chunk is wrong */
|
||||
if (last_tail) {
|
||||
BLI_asan_unpoison(last_tail, pool->esize);
|
||||
BLI_asan_unpoison(last_tail, pool->esize - POISON_REDZONE_SIZE);
|
||||
last_tail->next = CHUNK_DATA(mpchunk);
|
||||
BLI_asan_poison(last_tail, pool->esize);
|
||||
}
|
||||
|
@ -389,7 +394,7 @@ BLI_mempool *BLI_mempool_create_for_tasks(const unsigned int esize,
|
|||
chunk = chunk->next;
|
||||
}
|
||||
|
||||
pool->totused = totalloc;
|
||||
pool->totused = (int)totalloc;
|
||||
pool->free = NULL;
|
||||
|
||||
int i = (int)pool->pchunk - 1;
|
||||
|
@ -442,7 +447,7 @@ BLI_mempool *BLI_mempool_create_for_tasks(const unsigned int esize,
|
|||
static void mempool_chunk_free(BLI_mempool_chunk *mpchunk, BLI_mempool *pool)
|
||||
{
|
||||
BLI_asan_unpoison(mpchunk, sizeof(BLI_mempool_chunk) + pool->esize * pool->csize);
|
||||
MEM_freeN(mpchunk);
|
||||
BLI_asan_safe_free(mpchunk);
|
||||
}
|
||||
|
||||
static void mempool_chunk_free_all(BLI_mempool_chunk *mpchunk, BLI_mempool *pool)
|
||||
|
@ -548,6 +553,10 @@ BLI_mempool *BLI_mempool_create_ex(
|
|||
VALGRIND_CREATE_MEMPOOL(pool, 0, false);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMPOOL_ASAN
|
||||
BLI_asan_poison(pool->poisoned, sizeof(pool->poisoned));
|
||||
#endif
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
|
@ -634,7 +643,7 @@ int BLI_mempool_find_elems_fuzzy(
|
|||
char *data = (char *)CHUNK_DATA(chunk);
|
||||
void *ptr = data + idx2 * (int)pool->esize;
|
||||
|
||||
BLI_asan_unpoison(ptr, pool->esize);
|
||||
BLI_asan_unpoison(ptr, pool->esize - POISON_REDZONE_SIZE);
|
||||
|
||||
BLI_freenode *fnode = (BLI_freenode *)ptr;
|
||||
if (fnode->freeword == FREEWORD) {
|
||||
|
@ -711,6 +720,12 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
|
|||
|
||||
pool->totused--;
|
||||
|
||||
if (pool->totused < 0) {
|
||||
fprintf(stderr, "Corrupted mempool\n");
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef WITH_MEM_VALGRIND
|
||||
VALGRIND_MEMPOOL_FREE(pool, addr);
|
||||
#endif
|
||||
|
@ -743,19 +758,19 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
|
|||
|
||||
j = pool->pchunk;
|
||||
while (j--) {
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
|
||||
BLI_freenode *next = curnode->next = NODE_STEP_NEXT(curnode);
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
curnode = next;
|
||||
}
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
|
||||
BLI_freenode *prev = NODE_STEP_PREV(curnode);
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
curnode = prev;
|
||||
|
||||
BLI_asan_unpoison(curnode, pool->esize);
|
||||
BLI_asan_unpoison(curnode, pool->esize - POISON_REDZONE_SIZE);
|
||||
curnode->next = NULL; /* terminate the list */
|
||||
BLI_asan_poison(curnode, pool->esize);
|
||||
|
||||
|
@ -767,14 +782,14 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
|
|||
|
||||
int BLI_mempool_len(const BLI_mempool *pool)
|
||||
{
|
||||
return (int)pool->totused;
|
||||
return pool->totused;
|
||||
}
|
||||
|
||||
void *BLI_mempool_findelem(BLI_mempool *pool, uint index)
|
||||
{
|
||||
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
|
||||
|
||||
if (index < pool->totused) {
|
||||
if (index < (uint)pool->totused) {
|
||||
/* We could have some faster mem chunk stepping code inline. */
|
||||
BLI_mempool_iter iter;
|
||||
void *elem;
|
||||
|
@ -805,7 +820,7 @@ void BLI_mempool_as_table(BLI_mempool *pool, void **data)
|
|||
while ((elem = BLI_mempool_iterstep(&iter))) {
|
||||
*p++ = elem;
|
||||
}
|
||||
BLI_assert((uint)(p - data) == pool->totused);
|
||||
BLI_assert((int)(p - data) == pool->totused);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -832,7 +847,7 @@ void BLI_mempool_as_array(BLI_mempool *pool, void *data)
|
|||
memcpy(p, elem, (size_t)esize);
|
||||
p = NODE_STEP_NEXT(p);
|
||||
}
|
||||
BLI_assert((uint)(p - (char *)data) == pool->totused * esize);
|
||||
BLI_assert((int)(p - (char *)data) == pool->totused * esize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1141,6 +1156,10 @@ void BLI_mempool_destroy(BLI_mempool *pool)
|
|||
VALGRIND_DESTROY_MEMPOOL(pool);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMPOOL_ASAN
|
||||
BLI_asan_unpoison(pool->poisoned, sizeof(pool->poisoned));
|
||||
#endif
|
||||
|
||||
MEM_freeN(pool);
|
||||
}
|
||||
|
||||
|
|
|
@ -812,6 +812,8 @@ int bmesh_elem_check(void *element, const char htype)
|
|||
|
||||
#endif /* NDEBUG */
|
||||
|
||||
int bleh = 0;
|
||||
|
||||
/**
|
||||
* low level function, only frees the vert,
|
||||
* doesn't change or adjust surrounding geometry
|
||||
|
@ -832,6 +834,11 @@ static void bm_kill_only_vert(BMesh *bm, BMVert *v)
|
|||
v, bm->vdata.layers[bm->vdata.typemap[CD_TOOLFLAGS]].offset);
|
||||
|
||||
BLI_mempool_free(bm->vtoolflagpool, flags->flag);
|
||||
flags->flag = NULL;
|
||||
|
||||
if (bleh) {
|
||||
printf("eek\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (v->head.data) {
|
||||
|
@ -969,7 +976,7 @@ void bm_kill_only_face(BMesh *bm, BMFace *f)
|
|||
MToolFlags *flags = BM_ELEM_CD_GET_VOID_P(
|
||||
f, bm->pdata.layers[bm->pdata.typemap[CD_TOOLFLAGS]].offset);
|
||||
|
||||
BLI_mempool_free(bm->vtoolflagpool, flags->flag);
|
||||
BLI_mempool_free(bm->ftoolflagpool, flags->flag);
|
||||
}
|
||||
|
||||
if (f->head.data) {
|
||||
|
|
|
@ -1438,10 +1438,25 @@ void BM_data_layers_ensure(BMesh *bm, CustomData *data, BMCustomLayerReq *layers
|
|||
return;
|
||||
}
|
||||
|
||||
CustomDataLayer **nocopy_layers = NULL;
|
||||
BLI_array_declare(nocopy_layers);
|
||||
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
if (data->layers[i].flag & CD_FLAG_NOCOPY) {
|
||||
BLI_array_append(nocopy_layers, &data->layers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
CustomData_merge(&temp, data, mask, CD_ASSIGN, 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < BLI_array_len(nocopy_layers); i++) {
|
||||
nocopy_layers[i]->flag |= CD_FLAG_NOCOPY;
|
||||
}
|
||||
|
||||
BLI_array_free(nocopy_layers);
|
||||
|
||||
for (int i = 0; i < totlayer; i++) {
|
||||
BMCustomLayerReq *req = layers + i;
|
||||
int idx;
|
||||
|
|
|
@ -59,6 +59,9 @@
|
|||
|
||||
#define CUSTOMDATA
|
||||
|
||||
void CustomData_bmesh_asan_unpoison(const CustomData *data, void *block);
|
||||
void CustomData_bmesh_asan_poison(const CustomData *data, void *block);
|
||||
|
||||
//#define DEBUG_LOG_TO_FILE
|
||||
//#define DO_LOG_PRINT
|
||||
|
||||
|
@ -685,6 +688,7 @@ static void bm_log_vert_customdata(
|
|||
//}
|
||||
|
||||
if (lv->customdata) {
|
||||
CustomData_bmesh_asan_unpoison(&entry->vdata, lv->customdata);
|
||||
BLI_mempool_free(entry->vdata.pool, lv->customdata);
|
||||
lv->customdata = NULL;
|
||||
}
|
||||
|
@ -701,6 +705,7 @@ static void bm_log_edge_customdata(
|
|||
BMesh *bm, BMLog *log, BMLogEntry *entry, BMEdge *e, BMLogEdge *le)
|
||||
{
|
||||
if (le->customdata) {
|
||||
CustomData_bmesh_asan_unpoison(&entry->edata, le->customdata);
|
||||
BLI_mempool_free(entry->edata.pool, le->customdata);
|
||||
le->customdata = NULL;
|
||||
}
|
||||
|
@ -718,6 +723,7 @@ static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *
|
|||
}
|
||||
|
||||
if (lf->customdata_f) {
|
||||
CustomData_bmesh_asan_unpoison(&entry->pdata, lf->customdata_f);
|
||||
BLI_mempool_free(entry->pdata.pool, lf->customdata_f);
|
||||
lf->customdata_f = NULL;
|
||||
}
|
||||
|
@ -731,6 +737,7 @@ static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *
|
|||
int i = 0;
|
||||
do {
|
||||
if (lf->customdata[i]) {
|
||||
CustomData_bmesh_asan_unpoison(&entry->ldata, lf->customdata[i]);
|
||||
BLI_mempool_free(entry->ldata.pool, lf->customdata[i]);
|
||||
lf->customdata[i] = NULL;
|
||||
}
|
||||
|
@ -902,12 +909,14 @@ static void bm_log_face_bmface_copy(
|
|||
// free existing customdata blocks
|
||||
|
||||
if (lf->customdata_f) {
|
||||
CustomData_bmesh_asan_unpoison(&entry->pdata, lf->customdata_f);
|
||||
BLI_mempool_free(entry->pdata.pool, lf->customdata_f);
|
||||
lf->customdata_f = NULL;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < lf->len; i++) {
|
||||
if (lf->customdata[i]) {
|
||||
CustomData_bmesh_asan_unpoison(&entry->ldata, lf->customdata[i]);
|
||||
BLI_mempool_free(entry->ldata.pool, lf->customdata[i]);
|
||||
lf->customdata[i] = NULL;
|
||||
}
|
||||
|
@ -1438,7 +1447,10 @@ static void bm_log_vert_values_swap(
|
|||
if (lv->customdata) {
|
||||
if (v->head.data) {
|
||||
old_cdata = scratch;
|
||||
|
||||
CustomData_bmesh_asan_unpoison(&bm->vdata, v->head.data);
|
||||
memcpy(old_cdata, v->head.data, (size_t)bm->vdata.totsize);
|
||||
CustomData_bmesh_asan_poison(&bm->vdata, v->head.data);
|
||||
}
|
||||
|
||||
CustomData_bmesh_swap_data(&entry->vdata, &bm->vdata, lv->customdata, &v->head.data);
|
||||
|
@ -1471,7 +1483,9 @@ static void bm_log_edge_values_swap(
|
|||
if (le->customdata) {
|
||||
if (e->head.data) {
|
||||
old_cdata = scratch;
|
||||
CustomData_bmesh_asan_unpoison(&bm->edata, e->head.data);
|
||||
memcpy(old_cdata, e->head.data, (size_t)bm->edata.totsize);
|
||||
CustomData_bmesh_asan_poison(&bm->edata, e->head.data);
|
||||
}
|
||||
|
||||
CustomData_bmesh_swap_data(&entry->edata, &bm->edata, le->customdata, &e->head.data);
|
||||
|
@ -1506,7 +1520,9 @@ static void bm_log_face_values_swap(BMLog *log,
|
|||
|
||||
if (f->head.data) {
|
||||
old_cdata = scratch;
|
||||
CustomData_bmesh_asan_unpoison(&log->bm->pdata, f->head.data);
|
||||
memcpy(old_cdata, f->head.data, (size_t)log->bm->pdata.totsize);
|
||||
CustomData_bmesh_asan_poison(&log->bm->pdata, f->head.data);
|
||||
}
|
||||
|
||||
if (lf->customdata_f) {
|
||||
|
@ -1869,16 +1885,6 @@ static bool bm_log_free_direct(BMLog *log, bool safe_mode)
|
|||
BMLogEntry *entry;
|
||||
|
||||
if (safe_mode && log->refcount) {
|
||||
#if 0
|
||||
if (log->frozen_full_mesh) {
|
||||
log->frozen_full_mesh->log = NULL;
|
||||
bm_log_entry_free(log->frozen_full_mesh);
|
||||
}
|
||||
#endif
|
||||
|
||||
// log->frozen_full_mesh = bm_log_entry_create(LOG_ENTRY_FULL_MESH);
|
||||
// bm_log_full_mesh_intern(log->bm, log, log->frozen_full_mesh);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2965,6 +2971,7 @@ void BM_log_face_topo_post(BMLog *log, BMFace *f)
|
|||
if (BLI_ghash_ensure_p(entry->topo_modified_faces_post, key, &val)) {
|
||||
BMLogFace *lf_old = (BMLogFace *)*val;
|
||||
*lf_old = *lf;
|
||||
|
||||
BLI_mempool_free(entry->pool_faces, lf);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -63,8 +63,11 @@ static BMVert *bmo_vert_copy(BMOperator *op,
|
|||
|
||||
/* Handle Ids */
|
||||
bm_alloc_id(bm_dst, (BMElem *)v_dst);
|
||||
bm_elem_check_toolflags(bm_dst, (BMElem *)v_dst);
|
||||
// short **flags = BM_ELEM_CD_GET_VOID_P(
|
||||
// v_dst, bm_dst->vdata.layers[bm_dst->vdata.typemap[CD_TOOLFLAGS]].offset);
|
||||
|
||||
bm_elem_check_toolflags(bm_dst, (BMElem *)v_dst);
|
||||
// printf("%p\n", flags);
|
||||
/* Mark the vert for output */
|
||||
BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW);
|
||||
|
||||
|
|
|
@ -973,6 +973,7 @@ typedef struct SculptGestureTrimOperation {
|
|||
|
||||
float depth_front;
|
||||
float depth_back;
|
||||
float avg_edge_len;
|
||||
|
||||
bool use_cursor_depth;
|
||||
|
||||
|
@ -1171,6 +1172,17 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
|
|||
mul_v3_m4v3(trim_operation->true_mesh_co[i], ob_imat, new_point);
|
||||
}
|
||||
|
||||
float avg_elen = 0.0f;
|
||||
|
||||
for (int i = 0; i < tot_screen_points; i++) {
|
||||
MVert *v1 = trim_operation->mesh->mvert + i;
|
||||
MVert *v2 = trim_operation->mesh->mvert + ((i + 1) % tot_screen_points);
|
||||
|
||||
avg_elen += len_v3v3(v1->co, v2->co);
|
||||
}
|
||||
|
||||
trim_operation->avg_edge_len = avg_elen / (float)tot_screen_points;
|
||||
|
||||
/* Write vertices coordinates for the back face. */
|
||||
madd_v3_v3v3fl(depth_point, shape_origin, shape_normal, depth_back);
|
||||
for (int i = 0; i < tot_screen_points; i++) {
|
||||
|
@ -1242,8 +1254,16 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
|
|||
|
||||
BKE_mesh_calc_edges(trim_operation->mesh, false, false);
|
||||
sculpt_gesture_trim_normals_update(sgcontext);
|
||||
}
|
||||
|
||||
mp = trim_operation->mesh->mpoly + tot_tris_face * 2;
|
||||
|
||||
/* flag edges as sharp for dyntopo remesher */
|
||||
for (int i = 0; i < tot_screen_points * 2; i++, mp++) {
|
||||
ml = trim_operation->mesh->mloop + mp->loopstart;
|
||||
|
||||
trim_operation->mesh->medge[ml[1].e].flag |= ME_SHARP;
|
||||
}
|
||||
}
|
||||
static void sculpt_gesture_trim_geometry_free(SculptGestureContext *sgcontext)
|
||||
{
|
||||
SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
|
||||
|
@ -1284,13 +1304,45 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
|
|||
}));
|
||||
}
|
||||
|
||||
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(sculpt_mesh, trim_mesh);
|
||||
BMesh *trimbm = BM_mesh_create(
|
||||
&allocsize,
|
||||
&((struct BMeshCreateParams){.use_toolflags = false,
|
||||
.create_unique_ids = true,
|
||||
.no_reuse_ids = false,
|
||||
.temporary_ids = false,
|
||||
.copy_all_layers = true,
|
||||
.id_elem_mask = BM_VERT | BM_EDGE | BM_FACE,
|
||||
.id_map = true}));
|
||||
|
||||
BM_mesh_bm_from_me(NULL,
|
||||
bm,
|
||||
trimbm,
|
||||
trim_mesh,
|
||||
&((struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
}));
|
||||
|
||||
BM_mesh_normals_update(bm);
|
||||
|
||||
#if 0
|
||||
// remesh
|
||||
DynTopoState *ds = BKE_dyntopo_init(trimbm, NULL);
|
||||
DynRemeshParams params;
|
||||
BKE_dyntopo_default_params(¶ms, trim_operation->avg_edge_len * 4.0);
|
||||
BKE_dyntopo_remesh(ds, ¶ms, 10, PBVH_Collapse | PBVH_Cleanup | PBVH_Subdivide);
|
||||
|
||||
BM_mesh_toolflags_set(bm, true);
|
||||
|
||||
BKE_dyntopo_free(ds);
|
||||
#endif
|
||||
|
||||
BM_mesh_toolflags_set(bm, true);
|
||||
|
||||
BMO_op_callf(trimbm, BMO_FLAG_DEFAULTS, "duplicate geom=%avef dest=%p", bm, 3);
|
||||
|
||||
SCULPT_update_customdata_refs(sgcontext->ss);
|
||||
BM_mesh_free(trimbm);
|
||||
|
||||
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
|
||||
BMLoop *(*looptris)[3];
|
||||
looptris = MEM_malloc_arrayN(looptris_tot, sizeof(*looptris), __func__);
|
||||
|
@ -1409,10 +1461,6 @@ static void sculpt_gesture_trim_end(bContext *UNUSED(C), SculptGestureContext *s
|
|||
|
||||
sculpt_gesture_trim_geometry_free(sgcontext);
|
||||
|
||||
if (sgcontext->ss && sgcontext->ss->bm) {
|
||||
SCULPT_dynamic_topology_triangulate(sgcontext->ss, sgcontext->ss->bm);
|
||||
}
|
||||
|
||||
SCULPT_undo_push_node(sgcontext->vc.obact, NULL, SCULPT_UNDO_GEOMETRY);
|
||||
BKE_mesh_batch_cache_dirty_tag(sgcontext->vc.obact->data, BKE_MESH_BATCH_DIRTY_ALL);
|
||||
DEG_id_tag_update(&sgcontext->vc.obact->id, ID_RECALC_GEOMETRY);
|
||||
|
@ -1828,7 +1876,8 @@ static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op)
|
|||
{
|
||||
Object *object = CTX_data_active_object(C);
|
||||
SculptSession *ss = object->sculpt;
|
||||
if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
|
||||
|
||||
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
|
||||
/* Not supported in Multires and Dyntopo. */
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue