Today I ran outside screaming and an hour later came back in and made BMLog
reference counted. This fixes various undo bugs caused by dyntopo needing to execute an undo push but not being able too (e.g. during file load, and I think it also happens sometimes with global undo). A much better way of fixing this would be to add unique IDs to mesh verts and faces, perhaps as a customdata layer. The root problem is that BMLog assigns unique IDs to mesh elements, which it does via a series of GHash's. I imagine this is a fairly serious violation of the undo system's design rules, since it means BMLogs are tied to specific instances of the bmesh in SculptSession->bm. There were some hacks to try and get around this, but they were buggy and needed to push the unstack stack to work, which wasn't possible in all cases (e.g. if G_MAIN->wm.first->undo_stack is NULL, as it is during file loading and apparently global undo). Anyway, long story short each chain of SculptUndoNodes needs some way to reconstruct their ID GHash's when exiting/entering the chain. The only way I could think to do this was to make BMLog reference counted, with BMLogEntry the users. Like I said, having a proper system to assign unique IDs to mesh elements would be *much* better.
This commit is contained in:
parent
dbe767f5d9
commit
b8a8e4f9b1
|
@ -652,6 +652,10 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
|
|||
(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);
|
||||
|
||||
#define BKE_pbvh_face_index_to_table(pbvh, v) \
|
||||
(BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != -1 ? BM_elem_index_get((BMFace *)(v.i)) : (v.i))
|
||||
SculptFaceRef BKE_pbvh_table_index_to_face(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);
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "BKE_context.h"
|
||||
#include "BKE_crazyspace.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_idtype.h"
|
||||
#include "BKE_image.h"
|
||||
|
@ -67,6 +68,7 @@
|
|||
#include "BKE_pbvh.h"
|
||||
#include "BKE_subdiv_ccg.h"
|
||||
#include "BKE_subsurf.h"
|
||||
#include "BKE_undo_system.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
@ -79,6 +81,7 @@
|
|||
|
||||
// XXX todo: work our bad module cross ref
|
||||
void SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me);
|
||||
void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss);
|
||||
|
||||
static void palette_init_data(ID *id)
|
||||
{
|
||||
|
@ -1380,12 +1383,6 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
|
|||
|
||||
if (ss->bm) {
|
||||
if (ob->data) {
|
||||
BMIter iter;
|
||||
BMFace *efa;
|
||||
BM_ITER_MESH (efa, &iter, ss->bm, BM_FACES_OF_MESH) {
|
||||
BM_elem_flag_set(efa, BM_ELEM_SMOOTH, ss->bm_smooth_shading);
|
||||
}
|
||||
|
||||
if (reorder) {
|
||||
BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
|
||||
}
|
||||
|
@ -1473,7 +1470,14 @@ void BKE_sculptsession_free(Object *ob)
|
|||
if (ob && ob->sculpt) {
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
if (ss->bm_log) {
|
||||
BM_log_free(ss->bm_log, true);
|
||||
}
|
||||
|
||||
/*try to save current mesh*/
|
||||
if (ss->bm) {
|
||||
SCULPT_on_sculptsession_bmesh_free(ss);
|
||||
|
||||
BKE_sculptsession_bm_to_me(ob, true);
|
||||
BM_mesh_free(ss->bm);
|
||||
}
|
||||
|
@ -1489,10 +1493,6 @@ void BKE_sculptsession_free(Object *ob)
|
|||
MEM_SAFE_FREE(ss->vemap);
|
||||
MEM_SAFE_FREE(ss->vemap_mem);
|
||||
|
||||
if (ss->bm_log) {
|
||||
BM_log_free(ss->bm_log);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(ss->texcache);
|
||||
|
||||
if (ss->tex_pool) {
|
||||
|
@ -1911,7 +1911,7 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
|
|||
|
||||
if (!sd->detail_range) {
|
||||
sd->detail_range = 0.4f;
|
||||
sd->flags |= SCULPT_DYNTOPO_CLEANUP; //should really do this in do_versions_290.c
|
||||
sd->flags |= SCULPT_DYNTOPO_CLEANUP; // should really do this in do_versions_290.c
|
||||
}
|
||||
|
||||
if (!sd->detail_percent) {
|
||||
|
|
|
@ -3174,6 +3174,17 @@ SculptVertRef BKE_pbvh_table_index_to_vertex(PBVH *pbvh, int idx)
|
|||
|
||||
return BKE_pbvh_make_vref(idx);
|
||||
}
|
||||
|
||||
SculptFaceRef BKE_pbvh_table_index_to_face(PBVH *pbvh, int idx)
|
||||
{
|
||||
if (pbvh->type == PBVH_BMESH) {
|
||||
SculptFaceRef ref = {(intptr_t)pbvh->bm->ftable[idx]};
|
||||
return ref;
|
||||
}
|
||||
|
||||
return BKE_pbvh_make_fref(idx);
|
||||
}
|
||||
|
||||
bool pbvh_has_face_sets(PBVH *pbvh)
|
||||
{
|
||||
switch (pbvh->type) {
|
||||
|
|
|
@ -108,6 +108,10 @@ struct BMLog {
|
|||
/* Tree of free IDs */
|
||||
struct RangeTreeUInt *unused_ids;
|
||||
|
||||
BMLogEntry *frozen_full_mesh;
|
||||
|
||||
int refcount;
|
||||
|
||||
/* Mapping from unique IDs to vertices and faces
|
||||
*
|
||||
* Each vertex and face in the log gets a unique uinteger
|
||||
|
@ -161,6 +165,9 @@ typedef struct {
|
|||
#define logkey_hash BLI_ghashutil_inthash_p_simple
|
||||
#define logkey_cmp BLI_ghashutil_intcmp
|
||||
|
||||
static void full_copy_swap(BMesh *bm, BMLog *log, BMLogEntry *entry);
|
||||
static void bm_log_entry_free(BMLogEntry *entry);
|
||||
|
||||
static void *log_ghash_lookup(BMLog *log, GHash *gh, const void *key)
|
||||
{
|
||||
BLI_rw_mutex_lock(&log->lock, THREAD_LOCK_READ);
|
||||
|
@ -665,6 +672,15 @@ static BMLogEntry *bm_log_entry_create(void)
|
|||
* Note: does not free the log entry itself */
|
||||
static void bm_log_entry_free(BMLogEntry *entry)
|
||||
{
|
||||
if (entry->log) {
|
||||
entry->log->refcount--;
|
||||
|
||||
if (entry->log->refcount < 0) {
|
||||
fprintf(stderr, "BMLog refcount error\n");
|
||||
entry->log->refcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->full_copy_mesh) {
|
||||
BKE_mesh_free(entry->full_copy_mesh);
|
||||
|
||||
|
@ -855,11 +871,41 @@ BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
|
|||
return log;
|
||||
}
|
||||
|
||||
/* Free all the data in a BMLog including the log itself */
|
||||
void BM_log_free(BMLog *log)
|
||||
ATTR_NO_OPT BMLog *BM_log_unfreeze(BMesh *bm, BMLogEntry *entry)
|
||||
{
|
||||
if (!entry || !entry->log) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!entry->log->frozen_full_mesh) {
|
||||
return entry->log;
|
||||
}
|
||||
|
||||
full_copy_swap(bm, entry->log, entry->log->frozen_full_mesh);
|
||||
|
||||
entry->log->frozen_full_mesh->log = NULL;
|
||||
bm_log_entry_free(entry->log->frozen_full_mesh);
|
||||
entry->log->frozen_full_mesh = NULL;
|
||||
|
||||
return entry->log;
|
||||
}
|
||||
|
||||
/* Free all the data in a BMLog including the log itself
|
||||
* safe_mode means log->refcount will be checked, and if nonzero log will not be freed
|
||||
*/
|
||||
void BM_log_free(BMLog *log, bool safe_mode)
|
||||
{
|
||||
BMLogEntry *entry;
|
||||
|
||||
if (safe_mode && log->refcount) {
|
||||
if (!log->frozen_full_mesh) {
|
||||
log->frozen_full_mesh = bm_log_entry_create();
|
||||
bm_log_full_mesh_intern(log->bm, log, log->frozen_full_mesh);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_rw_mutex_end(&log->lock);
|
||||
|
||||
if (log->unused_ids) {
|
||||
|
@ -1010,6 +1056,8 @@ BMLogEntry *BM_log_entry_add_ex(BMesh *bm, BMLog *log, bool combine_with_last)
|
|||
BLI_addtail(&log->entries, entry);
|
||||
entry->log = log;
|
||||
|
||||
log->refcount++;
|
||||
|
||||
#ifdef CUSTOMDATA
|
||||
if (combine_with_last) {
|
||||
if (log->current_entry) {
|
||||
|
@ -1162,7 +1210,7 @@ static void full_copy_swap(BMesh *bm, BMLog *log, BMLogEntry *entry)
|
|||
else {
|
||||
// eek, error!
|
||||
printf("bmlog error!\n");
|
||||
log_ghash_remove(log, log->id_to_elem, (void*)id, NULL, NULL);
|
||||
log_ghash_remove(log, log->id_to_elem, (void *)id, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1474,6 +1522,10 @@ void BM_log_face_removed(BMLog *log, BMFace *f)
|
|||
/* Log all vertices/faces in the BMesh as added */
|
||||
void BM_log_all_added(BMesh *bm, BMLog *log)
|
||||
{
|
||||
if (!log->current_entry) {
|
||||
BM_log_entry_add_ex(bm, log, false);
|
||||
}
|
||||
|
||||
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
|
||||
BMIter bm_iter;
|
||||
BMVert *v;
|
||||
|
@ -1524,6 +1576,10 @@ void BM_log_full_mesh(BMesh *bm, BMLog *log)
|
|||
/* Log all vertices/faces in the BMesh as removed */
|
||||
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
|
||||
{
|
||||
if (!log->current_entry) {
|
||||
BM_log_entry_add_ex(bm, log, false);
|
||||
}
|
||||
|
||||
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
|
||||
BMIter bm_iter;
|
||||
BMVert *v;
|
||||
|
|
|
@ -36,9 +36,11 @@ void BM_log_set_cd_offsets(BMLog *log, int cd_dyn_vert);
|
|||
BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry);
|
||||
|
||||
/* Free all the data in a BMLog including the log itself */
|
||||
void BM_log_free(BMLog *log);
|
||||
void BM_log_free(BMLog *log, bool safe_mode);
|
||||
|
||||
/* Get the number of log entries */
|
||||
BMLog *BM_log_unfreeze(BMesh *bm, BMLogEntry *entry);
|
||||
|
||||
/* Get the number of log entries */
|
||||
int BM_log_length(const BMLog *log);
|
||||
|
||||
/* Apply a consistent ordering to BMesh vertices and faces */
|
||||
|
|
|
@ -117,6 +117,22 @@ void SCULPT_vertex_random_access_ensure(SculptSession *ss)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Sculpt PBVH abstraction API
|
||||
*
|
||||
* This is read-only, for writing use PBVH vertex iterators. There vd.index matches
|
||||
* the indices used here.
|
||||
*
|
||||
* For multi-resolution, the same vertex in multiple grids is counted multiple times, with
|
||||
* different index for each grid. */
|
||||
|
||||
void SCULPT_face_random_access_ensure(SculptSession *ss)
|
||||
{
|
||||
if (ss->bm) {
|
||||
BM_mesh_elem_index_ensure(ss->bm, BM_FACE);
|
||||
BM_mesh_elem_table_ensure(ss->bm, BM_FACE);
|
||||
}
|
||||
}
|
||||
int SCULPT_vertex_count_get(SculptSession *ss)
|
||||
{
|
||||
switch (BKE_pbvh_type(ss->pbvh)) {
|
||||
|
@ -9176,7 +9192,7 @@ static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene,
|
|||
}
|
||||
}
|
||||
|
||||
void ED_object_sculptmode_enter_ex(Main *bmain,
|
||||
ATTR_NO_OPT void ED_object_sculptmode_enter_ex(Main *bmain,
|
||||
Depsgraph *depsgraph,
|
||||
Scene *scene,
|
||||
Object *ob,
|
||||
|
|
|
@ -23,10 +23,15 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_array.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_polyfill_2d.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
@ -77,12 +82,79 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void SCULPT_dynamic_topology_triangulate(BMesh *bm)
|
||||
ATTR_NO_OPT void SCULPT_dynamic_topology_triangulate(BMesh *bm)
|
||||
{
|
||||
if (bm->totloop != bm->totface * 3) {
|
||||
BM_mesh_triangulate(
|
||||
bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, 4, false, NULL, NULL, NULL);
|
||||
if (bm->totloop == bm->totface * 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
|
||||
BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BM_elem_flag_enable(f, BM_ELEM_TAG);
|
||||
}
|
||||
|
||||
MemArena *pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
|
||||
LinkNode *f_double = NULL;
|
||||
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (f->len <= 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool sel = BM_elem_flag_test(f, BM_ELEM_SELECT);
|
||||
|
||||
int faces_array_tot = f->len;
|
||||
BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
|
||||
|
||||
printf("%d: ", f->head.hflag);
|
||||
|
||||
BM_face_triangulate(bm,
|
||||
f,
|
||||
faces_array,
|
||||
&faces_array_tot,
|
||||
NULL,
|
||||
NULL,
|
||||
&f_double,
|
||||
MOD_TRIANGULATE_QUAD_BEAUTY,
|
||||
MOD_TRIANGULATE_NGON_EARCLIP,
|
||||
true,
|
||||
pf_arena,
|
||||
NULL);
|
||||
|
||||
printf("%d, ", f->head.hflag);
|
||||
|
||||
for (int i = 0; i < faces_array_tot; i++) {
|
||||
BMFace *f2 = faces_array[i];
|
||||
|
||||
//forcibly copy selection state
|
||||
if (sel) {
|
||||
BM_face_select_set(bm, f2, true);
|
||||
|
||||
//restore original face selection state too, triangulate code unset it
|
||||
BM_face_select_set(bm, f, true);
|
||||
}
|
||||
|
||||
//paranoia check that tag flag wasn't copied over
|
||||
BM_elem_flag_disable(f2, BM_ELEM_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
while (f_double) {
|
||||
LinkNode *next = f_double->next;
|
||||
BM_face_kill(bm, f_double->link);
|
||||
MEM_freeN(f_double);
|
||||
f_double = next;
|
||||
}
|
||||
|
||||
BLI_memarena_free(pf_arena);
|
||||
|
||||
// BM_mesh_triangulate(
|
||||
// bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, 4, false, NULL, NULL,
|
||||
// NULL);
|
||||
}
|
||||
|
||||
void SCULPT_pbvh_clear(Object *ob)
|
||||
|
@ -326,7 +398,7 @@ void SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me)
|
|||
break;
|
||||
}
|
||||
|
||||
//based off of how CustomData_set_layer_XXXX_index works
|
||||
// based off of how CustomData_set_layer_XXXX_index works
|
||||
|
||||
cl3->active = (cl2->active + baseidx) - k;
|
||||
cl3->active_rnd = (cl2->active_rnd + baseidx) - k;
|
||||
|
@ -545,7 +617,7 @@ static void SCULPT_dynamic_topology_disable_ex(
|
|||
ss->bm = NULL;
|
||||
}
|
||||
if (ss->bm_log) {
|
||||
BM_log_free(ss->bm_log);
|
||||
BM_log_free(ss->bm_log, true);
|
||||
ss->bm_log = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -156,10 +156,12 @@ enum {
|
|||
*/
|
||||
static bool sculpt_expand_is_vert_in_active_component(SculptSession *ss,
|
||||
ExpandCache *expand_cache,
|
||||
const int v)
|
||||
const SculptVertRef v)
|
||||
{
|
||||
const int v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, v);
|
||||
|
||||
for (int i = 0; i < EXPAND_SYMM_AREAS; i++) {
|
||||
if (ss->vertex_info.connected_component[v] == expand_cache->active_connected_components[i]) {
|
||||
if (ss->vertex_info.connected_component[v_i] == expand_cache->active_connected_components[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -171,10 +173,18 @@ static bool sculpt_expand_is_vert_in_active_component(SculptSession *ss,
|
|||
*/
|
||||
static bool sculpt_expand_is_face_in_active_component(SculptSession *ss,
|
||||
ExpandCache *expand_cache,
|
||||
const int f)
|
||||
const SculptFaceRef f)
|
||||
{
|
||||
const MLoop *loop = &ss->mloop[ss->mpoly[f].loopstart];
|
||||
return sculpt_expand_is_vert_in_active_component(ss, expand_cache, loop->v);
|
||||
if (ss->bm) {
|
||||
BMFace *bf = (BMFace*)f.i;
|
||||
BMLoop *l = bf->l_first;
|
||||
SculptVertRef v = {(intptr_t)l->v};
|
||||
|
||||
return sculpt_expand_is_vert_in_active_component(ss, expand_cache, v);
|
||||
} else {
|
||||
const MLoop *loop = &ss->mloop[ss->mpoly[f.i].loopstart];
|
||||
return sculpt_expand_is_vert_in_active_component(ss, expand_cache, BKE_pbvh_table_index_to_vertex(ss->pbvh, loop->v));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,24 +193,26 @@ static bool sculpt_expand_is_face_in_active_component(SculptSession *ss,
|
|||
*/
|
||||
static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss,
|
||||
ExpandCache *expand_cache,
|
||||
const int v)
|
||||
const SculptVertRef v)
|
||||
{
|
||||
const int v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, v);
|
||||
|
||||
if (expand_cache->texture_distortion_strength == 0.0f) {
|
||||
return expand_cache->vert_falloff[v];
|
||||
return expand_cache->vert_falloff[v_i];
|
||||
}
|
||||
|
||||
if (!expand_cache->brush->mtex.tex) {
|
||||
return expand_cache->vert_falloff[v];
|
||||
return expand_cache->vert_falloff[v_i];
|
||||
}
|
||||
|
||||
float rgba[4];
|
||||
const float *vertex_co = SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, v));
|
||||
const float *vertex_co = SCULPT_vertex_co_get(ss, v);
|
||||
const float avg = BKE_brush_sample_tex_3d(
|
||||
expand_cache->scene, expand_cache->brush, vertex_co, rgba, 0, ss->tex_pool);
|
||||
|
||||
const float distortion = (avg - 0.5f) * expand_cache->texture_distortion_strength *
|
||||
expand_cache->max_vert_falloff;
|
||||
return expand_cache->vert_falloff[v] + distortion;
|
||||
return expand_cache->vert_falloff[v_i] + distortion;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -225,11 +237,9 @@ static float sculpt_expand_max_vertex_falloff_get(ExpandCache *expand_cache)
|
|||
* Main function to get the state of a vertex for the current state and settings of a #ExpandCache.
|
||||
* Returns true when the target data should be modified by expand.
|
||||
*/
|
||||
static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache, const int v)
|
||||
static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache, const SculptVertRef v)
|
||||
{
|
||||
SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, v);
|
||||
|
||||
if (!SCULPT_vertex_visible_get(ss, vref)) {
|
||||
if (!SCULPT_vertex_visible_get(ss, v)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -247,7 +257,7 @@ static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache
|
|||
/* Face Sets are not being modified when using this function, so it is ok to get this directly
|
||||
* from the Sculpt API instead of implementing a custom function to get them from
|
||||
* expand_cache->original_face_sets. */
|
||||
const int face_set = SCULPT_vertex_face_set_get(ss, vref);
|
||||
const int face_set = SCULPT_vertex_face_set_get(ss, v);
|
||||
enabled = BLI_gset_haskey(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(face_set));
|
||||
}
|
||||
else {
|
||||
|
@ -273,9 +283,11 @@ static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache
|
|||
* Main function to get the state of a face for the current state and settings of a #ExpandCache.
|
||||
* Returns true when the target data should be modified by expand.
|
||||
*/
|
||||
static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_cache, const int f)
|
||||
static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_cache, const SculptFaceRef f)
|
||||
{
|
||||
if (ss->face_sets[f] <= 0) {
|
||||
const int f_i = BKE_pbvh_face_index_to_table(ss->pbvh, f);
|
||||
|
||||
if (ss->face_sets[f_i] <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -290,7 +302,7 @@ static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_
|
|||
bool enabled = false;
|
||||
|
||||
if (expand_cache->snap_enabled_face_sets) {
|
||||
const int face_set = expand_cache->original_face_sets[f];
|
||||
const int face_set = expand_cache->original_face_sets[f_i];
|
||||
enabled = BLI_gset_haskey(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(face_set));
|
||||
}
|
||||
else {
|
||||
|
@ -298,12 +310,12 @@ static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_
|
|||
SCULPT_EXPAND_LOOP_THRESHOLD;
|
||||
|
||||
const float active_factor = fmod(expand_cache->active_falloff, loop_len);
|
||||
const float falloff_factor = fmod(expand_cache->face_falloff[f], loop_len);
|
||||
const float falloff_factor = fmod(expand_cache->face_falloff[f_i], loop_len);
|
||||
enabled = falloff_factor < active_factor;
|
||||
}
|
||||
|
||||
if (expand_cache->falloff_type == SCULPT_EXPAND_FALLOFF_ACTIVE_FACE_SET) {
|
||||
if (ss->face_sets[f] == expand_cache->initial_active_face_set) {
|
||||
if (ss->face_sets[f_i] == expand_cache->initial_active_face_set) {
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +333,7 @@ static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_
|
|||
*/
|
||||
static float sculpt_expand_gradient_value_get(SculptSession *ss,
|
||||
ExpandCache *expand_cache,
|
||||
const int v)
|
||||
const SculptVertRef v)
|
||||
{
|
||||
if (!expand_cache->falloff_gradient) {
|
||||
return 1.0f;
|
||||
|
@ -365,7 +377,7 @@ static BLI_bitmap *sculpt_expand_bitmap_from_enabled(SculptSession *ss, ExpandCa
|
|||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices");
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
const bool enabled = sculpt_expand_state_get(ss, expand_cache, i);
|
||||
const bool enabled = sculpt_expand_state_get(ss, expand_cache, BKE_pbvh_table_index_to_vertex(ss->pbvh, i));
|
||||
BLI_BITMAP_SET(enabled_vertices, i, enabled);
|
||||
}
|
||||
return enabled_vertices;
|
||||
|
@ -741,12 +753,15 @@ static void sculpt_expand_update_max_vert_falloff_value(SculptSession *ss,
|
|||
{
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
expand_cache->max_vert_falloff = -FLT_MAX;
|
||||
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
if (expand_cache->vert_falloff[i] == FLT_MAX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) {
|
||||
SculptVertRef v = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
|
||||
|
||||
if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, v)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -765,11 +780,13 @@ static void sculpt_expand_update_max_face_falloff_factor(SculptSession *ss,
|
|||
const int totface = ss->totfaces;
|
||||
expand_cache->max_face_falloff = -FLT_MAX;
|
||||
for (int i = 0; i < totface; i++) {
|
||||
SculptFaceRef f = BKE_pbvh_table_index_to_face(ss->pbvh, i);
|
||||
|
||||
if (expand_cache->face_falloff[i] == FLT_MAX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, i)) {
|
||||
if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, f)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1262,12 +1279,12 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata,
|
|||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_ALL) {
|
||||
const float initial_mask = *vd.mask;
|
||||
const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index);
|
||||
const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.vertex);
|
||||
|
||||
float new_mask;
|
||||
|
||||
if (enabled) {
|
||||
new_mask = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index);
|
||||
new_mask = sculpt_expand_gradient_value_get(ss, expand_cache, vd.vertex);
|
||||
}
|
||||
else {
|
||||
new_mask = 0.0f;
|
||||
|
@ -1298,17 +1315,20 @@ static void sculpt_expand_mask_update_task_cb(void *__restrict userdata,
|
|||
*/
|
||||
static void sculpt_expand_face_sets_update(SculptSession *ss, ExpandCache *expand_cache)
|
||||
{
|
||||
const int totface = ss->totfaces;
|
||||
for (int f = 0; f < totface; f++) {
|
||||
const int totface = ss->totpoly;
|
||||
|
||||
for (int f_i = 0; f_i < totface; f_i++) {
|
||||
SculptFaceRef f = BKE_pbvh_table_index_to_face(ss->pbvh, f_i);
|
||||
|
||||
const bool enabled = sculpt_expand_face_state_get(ss, expand_cache, f);
|
||||
if (!enabled) {
|
||||
continue;
|
||||
}
|
||||
if (expand_cache->preserve) {
|
||||
ss->face_sets[f] += expand_cache->next_face_set;
|
||||
ss->face_sets[f_i] += expand_cache->next_face_set;
|
||||
}
|
||||
else {
|
||||
ss->face_sets[f] = expand_cache->next_face_set;
|
||||
ss->face_sets[f_i] = expand_cache->next_face_set;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1336,11 +1356,11 @@ static void sculpt_expand_colors_update_task_cb(void *__restrict userdata,
|
|||
float initial_color[4];
|
||||
copy_v4_v4(initial_color, vd.col);
|
||||
|
||||
const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index);
|
||||
const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.vertex);
|
||||
float fade;
|
||||
|
||||
if (enabled) {
|
||||
fade = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index);
|
||||
fade = sculpt_expand_gradient_value_get(ss, expand_cache, vd.vertex);
|
||||
}
|
||||
else {
|
||||
fade = 0.0f;
|
||||
|
@ -1429,9 +1449,22 @@ static void sculpt_expand_original_state_store(Object *ob, ExpandCache *expand_c
|
|||
*/
|
||||
static void sculpt_expand_face_sets_restore(SculptSession *ss, ExpandCache *expand_cache)
|
||||
{
|
||||
const int totfaces = ss->totfaces;
|
||||
for (int i = 0; i < totfaces; i++) {
|
||||
ss->face_sets[i] = expand_cache->initial_face_sets[i];
|
||||
if (ss->bm) {
|
||||
const int totfaces = ss->totfaces;
|
||||
const int cd_faceset = ss->cd_faceset_offset;
|
||||
|
||||
for (int i = 0; i < totfaces; i++) {
|
||||
BMFace *f = (BMFace*)BKE_pbvh_table_index_to_face(ss->pbvh, i).i;
|
||||
|
||||
BM_ELEM_CD_SET_INT(f, cd_faceset, expand_cache->initial_face_sets[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const int totfaces = ss->totfaces;
|
||||
|
||||
for (int i = 0; i < totfaces; i++) {
|
||||
ss->face_sets[i] = expand_cache->initial_face_sets[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1544,11 +1577,13 @@ static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) {
|
||||
SculptVertRef v = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
|
||||
|
||||
if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, v)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float *vertex_co = SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, i));
|
||||
const float *vertex_co = SCULPT_vertex_co_get(ss, v);
|
||||
|
||||
if (!SCULPT_check_vertex_pivot_symmetry(vertex_co, expand_init_co, symm)) {
|
||||
continue;
|
||||
|
@ -1925,6 +1960,96 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
|
|||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes the `delete_id` Face Set ID from the mesh Face Sets
|
||||
* and stores the result in `r_face_set`.
|
||||
* The faces that were using the `delete_id` Face Set are filled
|
||||
* using the content from their neighbors.
|
||||
*/
|
||||
static void sculpt_expand_delete_face_set_id_bmesh(int *r_face_sets,
|
||||
SculptSession *ss,
|
||||
ExpandCache *expand_cache,
|
||||
const int delete_id)
|
||||
{
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
int i = 0;
|
||||
const int totface = ss->bm->totface;
|
||||
|
||||
/* Check that all the face sets IDs in the mesh are not equal to `delete_id`
|
||||
* before attempting to delete it. */
|
||||
bool all_same_id = true;
|
||||
|
||||
BM_ITER_MESH (f, &iter, ss->bm, BM_FACES_OF_MESH) {
|
||||
SculptFaceRef fref = {(intptr_t)f};
|
||||
i++;
|
||||
|
||||
if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, fref)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r_face_sets[i] != delete_id) {
|
||||
all_same_id = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_same_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_LINKSTACK_DECLARE(queue, void *);
|
||||
BLI_LINKSTACK_DECLARE(queue_next, void *);
|
||||
|
||||
BLI_LINKSTACK_INIT(queue);
|
||||
BLI_LINKSTACK_INIT(queue_next);
|
||||
|
||||
for (int i = 0; i < totface; i++) {
|
||||
SculptFaceRef fref = BKE_pbvh_table_index_to_face(ss->pbvh, i);
|
||||
|
||||
if (r_face_sets[i] == delete_id) {
|
||||
BLI_LINKSTACK_PUSH(queue, POINTER_FROM_INT(fref.i));
|
||||
}
|
||||
}
|
||||
|
||||
while (BLI_LINKSTACK_SIZE(queue)) {
|
||||
while (BLI_LINKSTACK_SIZE(queue)) {
|
||||
const SculptFaceRef f = {(intptr_t)(BLI_LINKSTACK_POP(queue))};
|
||||
BMFace *bf = (BMFace*)f.i;
|
||||
const int f_index = BM_elem_index_get(bf);
|
||||
|
||||
int other_id = delete_id;
|
||||
BMLoop *l = bf->l_first;
|
||||
do {
|
||||
BMLoop *l2 = l->radial_next;
|
||||
do {
|
||||
const int neighbor_face_index = BM_elem_index_get(l2->f);
|
||||
|
||||
if (r_face_sets[neighbor_face_index] != delete_id) {
|
||||
other_id = r_face_sets[neighbor_face_index];
|
||||
}
|
||||
|
||||
l2 = l2->radial_next;
|
||||
} while (l2 != l);
|
||||
l = l->next;
|
||||
} while (l != bf->l_first);
|
||||
|
||||
if (other_id != delete_id) {
|
||||
r_face_sets[f_index] = other_id;
|
||||
}
|
||||
else {
|
||||
BLI_LINKSTACK_PUSH(queue_next, bf);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_LINKSTACK_SWAP(queue, queue_next);
|
||||
}
|
||||
|
||||
BLI_LINKSTACK_FREE(queue);
|
||||
BLI_LINKSTACK_FREE(queue_next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the `delete_id` Face Set ID from the mesh Face Sets
|
||||
* and stores the result in `r_face_set`.
|
||||
|
@ -1937,6 +2062,11 @@ static void sculpt_expand_delete_face_set_id(int *r_face_sets,
|
|||
Mesh *mesh,
|
||||
const int delete_id)
|
||||
{
|
||||
if (ss->bm) {
|
||||
sculpt_expand_delete_face_set_id_bmesh(r_face_sets, ss, expand_cache, delete_id);
|
||||
return;
|
||||
}
|
||||
|
||||
const int totface = ss->totvert;
|
||||
MeshElemMap *pmap = ss->pmap;
|
||||
|
||||
|
@ -1944,7 +2074,7 @@ static void sculpt_expand_delete_face_set_id(int *r_face_sets,
|
|||
* before attempting to delete it. */
|
||||
bool all_same_id = true;
|
||||
for (int i = 0; i < totface; i++) {
|
||||
if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, i)) {
|
||||
if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, BKE_pbvh_table_index_to_face(ss->pbvh, i))) {
|
||||
continue;
|
||||
}
|
||||
if (r_face_sets[i] != delete_id) {
|
||||
|
@ -2092,12 +2222,14 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Face Set operations are not supported in dyntopo. */
|
||||
if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS &&
|
||||
BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
|
||||
sculpt_expand_cache_free(ss);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
sculpt_expand_ensure_sculptsession_data(ob);
|
||||
|
||||
|
|
|
@ -74,6 +74,78 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int SCULPT_face_set_get(SculptSession *ss, SculptFaceRef face)
|
||||
{
|
||||
if (ss->bm) {
|
||||
BMFace *f = (BMFace *)face.i;
|
||||
return BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
|
||||
}
|
||||
|
||||
return ss->face_sets[face.i];
|
||||
}
|
||||
|
||||
// returns previous face set
|
||||
int SCULPT_face_set_set(SculptSession *ss, SculptFaceRef face, int fset)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ss->bm) {
|
||||
BMFace *f = (BMFace *)face.i;
|
||||
ret = BM_ELEM_CD_GET_INT(f, ss->cd_faceset_offset);
|
||||
|
||||
BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, fset);
|
||||
}
|
||||
else {
|
||||
ret = ss->face_sets[face.i];
|
||||
ss->face_sets[face.i] = fset;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SCULPT_face_set_flag_get(SculptSession *ss, SculptFaceRef face, char flag)
|
||||
{
|
||||
if (ss->bm) {
|
||||
BMFace *f = (BMFace *)face.i;
|
||||
|
||||
flag = BM_face_flag_from_mflag(flag);
|
||||
return f->head.hflag & flag;
|
||||
}
|
||||
else {
|
||||
return ss->mpoly[face.i].flag & flag;
|
||||
}
|
||||
}
|
||||
|
||||
int SCULPT_face_set_flag_set(SculptSession *ss, SculptFaceRef face, char flag, bool state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ss->bm) {
|
||||
BMFace *f = (BMFace *)face.i;
|
||||
|
||||
flag = BM_face_flag_from_mflag(flag);
|
||||
ret = f->head.hflag & flag;
|
||||
|
||||
if (state) {
|
||||
f->head.hflag |= flag;
|
||||
}
|
||||
else {
|
||||
f->head.hflag &= ~flag;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = ss->mpoly[face.i].flag & flag;
|
||||
|
||||
if (state) {
|
||||
ss->mpoly[face.i].flag |= flag;
|
||||
}
|
||||
else {
|
||||
ss->mpoly[face.i].flag &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/* Utils. */
|
||||
int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh)
|
||||
{
|
||||
|
@ -120,6 +192,34 @@ int ED_sculpt_face_sets_active_update_and_get(bContext *C, Object *ob, const flo
|
|||
return SCULPT_active_face_set_get(ss);
|
||||
}
|
||||
|
||||
static BMesh *sculpt_faceset_bm_begin(SculptSession *ss, Mesh *mesh)
|
||||
{
|
||||
if (ss->bm) {
|
||||
return ss->bm;
|
||||
}
|
||||
|
||||
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
|
||||
BMesh *bm = BM_mesh_create(&allocsize,
|
||||
&((struct BMeshCreateParams){
|
||||
.use_toolflags = true,
|
||||
}));
|
||||
|
||||
BM_mesh_bm_from_me(NULL,
|
||||
bm,
|
||||
mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
}));
|
||||
return bm;
|
||||
}
|
||||
|
||||
static void sculpt_faceset_bm_end(SculptSession *ss, BMesh *bm)
|
||||
{
|
||||
if (bm != ss->bm) {
|
||||
BM_mesh_free(bm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw Face Sets Brush. */
|
||||
|
||||
static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
||||
|
@ -338,7 +438,7 @@ static EnumPropertyItem prop_sculpt_face_set_create_types[] = {
|
|||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
|
||||
ATTR_NO_OPT static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
@ -347,6 +447,7 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
|
|||
const int mode = RNA_enum_get(op->ptr, "mode");
|
||||
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED, false);
|
||||
SCULPT_face_random_access_ensure(ss);
|
||||
|
||||
const int tot_vert = SCULPT_vertex_count_get(ss);
|
||||
float threshold = 0.5f;
|
||||
|
@ -416,44 +517,23 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
|
||||
if (mode == SCULPT_FACE_SET_SELECTION) {
|
||||
|
||||
Mesh *mesh = ob->data;
|
||||
BMesh *bm;
|
||||
BMFace *f;
|
||||
BMIter iter;
|
||||
const totface = ss->totfaces;
|
||||
|
||||
if (ss->bm) {
|
||||
bm = ss->bm;
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
|
||||
BM_ELEM_CD_SET_INT(f, ss->cd_faceset_offset, next_face_set);
|
||||
}
|
||||
for (int i = 0; i < totface; i++) {
|
||||
SculptFaceRef fref = BKE_pbvh_table_index_to_face(ss->pbvh, i);
|
||||
|
||||
// XXX check hidden?
|
||||
int ok = !SCULPT_face_set_flag_get(ss, fref, ME_HIDE);
|
||||
ok = ok && SCULPT_face_set_flag_get(ss, fref, ME_FACE_SEL);
|
||||
|
||||
if (ok) {
|
||||
SCULPT_face_set_set(ss, fref, next_face_set);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
|
||||
bm = BM_mesh_create(&allocsize,
|
||||
&((struct BMeshCreateParams){
|
||||
.use_toolflags = true,
|
||||
}));
|
||||
|
||||
BM_mesh_bm_from_me(NULL,
|
||||
bm,
|
||||
mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
}));
|
||||
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
|
||||
ss->face_sets[BM_elem_index_get(f)] = next_face_set;
|
||||
}
|
||||
}
|
||||
|
||||
BM_mesh_free(bm);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < totnode; i++) {
|
||||
|
@ -629,25 +709,16 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
|
|||
SculptSession *ss = ob->sculpt;
|
||||
Mesh *mesh = ob->data;
|
||||
BMesh *bm;
|
||||
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
|
||||
bm = BM_mesh_create(&allocsize,
|
||||
&((struct BMeshCreateParams){
|
||||
.use_toolflags = true,
|
||||
}));
|
||||
|
||||
BM_mesh_bm_from_me(NULL,
|
||||
bm,
|
||||
mesh,
|
||||
(&(struct BMeshFromMeshParams){
|
||||
.calc_face_normal = true,
|
||||
}));
|
||||
bm = sculpt_faceset_bm_begin(ss, mesh);
|
||||
|
||||
BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces");
|
||||
const int totfaces = mesh->totpoly;
|
||||
|
||||
int *face_sets = ss->face_sets;
|
||||
SCULPT_vertex_random_access_ensure(ss);
|
||||
SCULPT_face_random_access_ensure(ss);
|
||||
|
||||
BM_mesh_elem_table_init(bm, BM_FACE);
|
||||
BM_mesh_elem_index_ensure(bm, BM_FACE);
|
||||
BM_mesh_elem_table_ensure(bm, BM_FACE);
|
||||
|
||||
int next_face_set = 1;
|
||||
|
@ -659,7 +730,9 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
|
|||
GSQueue *queue;
|
||||
queue = BLI_gsqueue_new(sizeof(int));
|
||||
|
||||
face_sets[i] = next_face_set;
|
||||
SculptFaceRef fref = BKE_pbvh_table_index_to_face(ss->pbvh, i);
|
||||
SCULPT_face_set_set(ss, fref, next_face_set);
|
||||
|
||||
BLI_BITMAP_ENABLE(visited_faces, i);
|
||||
BLI_gsqueue_push(queue, &i);
|
||||
|
||||
|
@ -686,7 +759,9 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
|
|||
continue;
|
||||
}
|
||||
|
||||
face_sets[neighbor_face_index] = next_face_set;
|
||||
SculptFaceRef fref2 = BKE_pbvh_table_index_to_face(ss->pbvh, neighbor_face_index);
|
||||
SCULPT_face_set_set(ss, fref2, next_face_set);
|
||||
|
||||
BLI_BITMAP_ENABLE(visited_faces, neighbor_face_index);
|
||||
BLI_gsqueue_push(queue, &neighbor_face_index);
|
||||
}
|
||||
|
@ -700,7 +775,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
|
|||
|
||||
MEM_SAFE_FREE(visited_faces);
|
||||
|
||||
BM_mesh_free(bm);
|
||||
sculpt_faceset_bm_end(ss, bm);
|
||||
}
|
||||
|
||||
static void sculpt_face_sets_init_loop(Object *ob, const int mode)
|
||||
|
@ -749,11 +824,6 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
|
|||
|
||||
const int mode = RNA_enum_get(op->ptr, "mode");
|
||||
|
||||
/* Dyntopo not supported. */
|
||||
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
|
||||
|
||||
PBVH *pbvh = ob->sculpt->pbvh;
|
||||
|
|
|
@ -48,7 +48,7 @@ enum ePaintSymmetryFlags;
|
|||
maximum symmetry passes returned by SCULPT_get_symmetry_pass.
|
||||
enough for about ~30 radial symmetry passes, which seems like plenty
|
||||
|
||||
used by various code that needs to statically store per-pass state.
|
||||
used by various code that needs to statically store per-pass state.
|
||||
*/
|
||||
#define SCULPT_MAX_SYMMETRY_PASSES 255
|
||||
|
||||
|
@ -105,6 +105,7 @@ char SCULPT_mesh_symmetry_xyz_get(Object *object);
|
|||
|
||||
/* Sculpt PBVH abstraction API */
|
||||
void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
|
||||
void SCULPT_face_random_access_ensure(struct SculptSession *ss);
|
||||
|
||||
int SCULPT_vertex_count_get(struct SculptSession *ss);
|
||||
const float *SCULPT_vertex_co_get(struct SculptSession *ss, SculptVertRef index);
|
||||
|
@ -236,6 +237,13 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, SculptVertRef ind
|
|||
void SCULPT_face_sets_visibility_invert(SculptSession *ss);
|
||||
void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
|
||||
|
||||
int SCULPT_face_set_get(SculptSession *ss, SculptFaceRef face);
|
||||
|
||||
// returns previous face set
|
||||
int SCULPT_face_set_set(SculptSession *ss, SculptFaceRef face, int fset);
|
||||
int SCULPT_face_set_flag_get(SculptSession *ss, SculptFaceRef face, char flag);
|
||||
int SCULPT_face_set_flag_set(SculptSession *ss, SculptFaceRef face, char flag, bool state);
|
||||
|
||||
bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache);
|
||||
bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache);
|
||||
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache);
|
||||
|
@ -577,7 +585,10 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
|
|||
void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
|
||||
|
||||
/* Topology rake */
|
||||
void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v, float projection);
|
||||
void SCULPT_bmesh_four_neighbor_average(float avg[3],
|
||||
float direction[3],
|
||||
struct BMVert *v,
|
||||
float projection);
|
||||
|
||||
/* Smoothing api */
|
||||
void SCULPT_neighbor_coords_average(SculptSession *ss,
|
||||
|
@ -604,7 +615,8 @@ void SCULPT_smooth(Sculpt *sd,
|
|||
const bool smooth_mask,
|
||||
float projection);
|
||||
|
||||
void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float projection);
|
||||
void SCULPT_do_smooth_brush(
|
||||
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float projection);
|
||||
|
||||
/* Surface Smooth Brush. */
|
||||
|
||||
|
@ -1124,9 +1136,9 @@ typedef struct StrokeCache {
|
|||
rcti previous_r; /* previous redraw rectangle */
|
||||
rcti current_r; /* current redraw rectangle */
|
||||
|
||||
float stroke_distance; // copy of PaintStroke->stroke_distance
|
||||
float stroke_distance_t; // copy of PaintStroke->stroke_distance_t
|
||||
|
||||
float stroke_distance; // copy of PaintStroke->stroke_distance
|
||||
float stroke_distance_t; // copy of PaintStroke->stroke_distance_t
|
||||
|
||||
float last_dyntopo_t;
|
||||
float last_smooth_t[SCULPT_MAX_SYMMETRY_PASSES];
|
||||
float last_rake_t[SCULPT_MAX_SYMMETRY_PASSES];
|
||||
|
@ -1502,3 +1514,5 @@ void SCULPT_dyntopo_save_persistent_base(SculptSession *ss);
|
|||
/*get current symmetry pass index inclusive of both
|
||||
mirror and radial symmetry*/
|
||||
int SCULPT_get_symmetry_pass(const SculptSession *ss);
|
||||
|
||||
void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss);
|
||||
|
|
|
@ -113,6 +113,7 @@ typedef struct UndoSculpt {
|
|||
ListBase nodes;
|
||||
|
||||
size_t undo_size;
|
||||
BMLog *bm_restore;
|
||||
} UndoSculpt;
|
||||
|
||||
static UndoSculpt *sculpt_undo_get_nodes(void);
|
||||
|
@ -400,7 +401,7 @@ static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode)
|
|||
Mesh *me = BKE_object_get_original_mesh(ob);
|
||||
int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
|
||||
for (int i = 0; i < me->totpoly; i++) {
|
||||
face_sets[i] = unode->face_sets[i];
|
||||
SWAP(int, face_sets[i], unode->face_sets[i]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -650,7 +651,7 @@ static void sculpt_undo_refine_subdiv(Depsgraph *depsgraph,
|
|||
MEM_freeN(deformed_verts);
|
||||
}
|
||||
|
||||
static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase *lb)
|
||||
ATTR_NO_OPT static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase *lb)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
@ -664,6 +665,23 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
bool need_refine_subdiv = false;
|
||||
|
||||
for (unode = lb->first; unode; unode = unode->next) {
|
||||
if (unode->bm_entry && !ss->bm) {
|
||||
// file loading breaks undo because the stack isn't initialized
|
||||
// detect that case and try to fix it
|
||||
|
||||
SCULPT_dynamic_topology_enable_ex(CTX_data_main(C), depsgraph, scene, ob);
|
||||
|
||||
//see if we have a saved log in the entry
|
||||
ss->bm_log = BM_log_unfreeze(ss->bm, unode->bm_entry);
|
||||
|
||||
if (!ss->bm_log) {
|
||||
/* Restore the BMLog using saved entries. */
|
||||
ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry);
|
||||
}
|
||||
|
||||
BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
|
||||
}
|
||||
|
||||
/* Restore pivot. */
|
||||
copy_v3_v3(ss->pivot_pos, unode->pivot_pos);
|
||||
copy_v3_v3(ss->pivot_rot, unode->pivot_rot);
|
||||
|
@ -679,6 +697,8 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
|
||||
|
||||
sculpt_undo_print_nodes(NULL);
|
||||
|
||||
if (!ss->bm && lb->first) {
|
||||
unode = lb->first;
|
||||
if (unode->type == SCULPT_UNDO_FACE_SETS) {
|
||||
|
@ -782,7 +802,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
case SCULPT_UNDO_DYNTOPO_BEGIN:
|
||||
case SCULPT_UNDO_DYNTOPO_END:
|
||||
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
|
||||
BLI_assert(!"Dynamic topology should've already been handled");
|
||||
printf("Dynamic topology should've already been handled\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1118,7 +1138,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
|
|||
case SCULPT_UNDO_DYNTOPO_BEGIN:
|
||||
case SCULPT_UNDO_DYNTOPO_END:
|
||||
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
|
||||
BLI_assert(!"Dynamic topology should've already been handled");
|
||||
printf("Dynamic topology should've already been handled\n");
|
||||
case SCULPT_UNDO_GEOMETRY:
|
||||
case SCULPT_UNDO_FACE_SETS:
|
||||
break;
|
||||
|
@ -1370,14 +1390,14 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
|
|||
case SCULPT_UNDO_GEOMETRY:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
switch (type) {
|
||||
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
|
||||
case SCULPT_UNDO_GEOMETRY:
|
||||
BM_log_full_mesh(ss->bm, ss->bm_log);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
|
||||
case SCULPT_UNDO_GEOMETRY:
|
||||
BM_log_full_mesh(ss->bm, ss->bm_log);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_node) {
|
||||
|
@ -1513,7 +1533,7 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
|
|||
case SCULPT_UNDO_DYNTOPO_BEGIN:
|
||||
case SCULPT_UNDO_DYNTOPO_END:
|
||||
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
|
||||
BLI_assert(!"Dynamic topology should've already been handled");
|
||||
printf("Dynamic topology should've already been handled\n");
|
||||
case SCULPT_UNDO_GEOMETRY:
|
||||
case SCULPT_UNDO_FACE_SETS:
|
||||
break;
|
||||
|
@ -1797,6 +1817,10 @@ static UndoSculpt *sculpt_undo_get_nodes(void)
|
|||
return sculpt_undosys_step_get_nodes(us);
|
||||
}
|
||||
|
||||
void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss)
|
||||
{
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -1963,7 +1987,7 @@ static void print_sculpt_undo_step(UndoStep *us, UndoStep *active, int i)
|
|||
}
|
||||
void sculpt_undo_print_nodes(void *active)
|
||||
{
|
||||
#if 0
|
||||
#if 1
|
||||
UndoStack *ustack = ED_undo_stack_get();
|
||||
UndoStep *us = ustack->steps.first;
|
||||
if (active == NULL) {
|
||||
|
|
Loading…
Reference in New Issue