* Layer brush now supports dyntopo.

- To do this I made a little API to make scratch
    customdata layers: SCULPT_dyntopo_[ensure/get]_templayer.
    Takes a customdata type and a layer name (e.g.
    '__dyntopo_bleh") and returns a customdata offset.
  - Note that I also did this for the persistent base code.

* Added a macro to check if a tool supports splitting the PBVH
  during a stroke, DYNTOPO_HAS_DYNAMIC_SPLIT.  It is in sculpt_intern.h
  (for now) to avoid the enormous amount of recompiling that is
  triggered if DNA_brush_enum.h is modified.

* TODO: Right now the undo code resets original vertex coordinates for
  bmesh PBVH.  This means tools that rely on original data (sharp and
  layer) can't split the pbvh during the stroke, since that will
  allocate new undo nodes and reset original coords.

  The solution is to move the original data API entirely out of the undo
  code.
This commit is contained in:
Joseph Eagar 2021-04-07 01:20:21 -07:00
parent 8aac19cab5
commit 55415cd62a
11 changed files with 334 additions and 117 deletions

View File

@ -343,6 +343,11 @@ typedef struct SculptClothSimulation {
/** #PBVHNode pointer as a key, index in #SculptClothSimulation.node_state as value. */
struct GHash *node_state_index;
eSculptClothNodeSimState *node_state;
//persistent base customdata layer offsets
int cd_pers_co;
int cd_pers_no;
int cd_pers_disp;
} SculptClothSimulation;
typedef struct SculptPersistentBase {

View File

@ -658,6 +658,8 @@ void SCULPT_update_flat_vcol_shading(struct Object *ob, struct Scene *scene);
void BKE_pbvh_curvature_update_set(PBVHNode *node, bool state);
bool BKE_pbvh_curvature_update_get(PBVHNode *node);
int BKE_pbvh_get_totnodes(PBVH *pbvh);
#ifdef __cplusplus
}
#endif

View File

@ -1385,6 +1385,7 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
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);
}

View File

@ -3240,6 +3240,10 @@ int BKE_pbvh_get_node_index(PBVH *pbvh, PBVHNode *node)
return (int)(node - pbvh->nodes);
}
int BKE_pbvh_get_totnodes(PBVH *pbvh) {
return pbvh->totnode;
}
int BKE_pbvh_get_node_id(PBVH *pbvh, PBVHNode *node)
{
return node->id;

View File

@ -39,6 +39,8 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
#include "bmesh.h"
@ -454,20 +456,16 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts, BMLogEntry
}
#endif
if (log->cd_origco_offset >= 0) {
float *oco = BM_ELEM_CD_GET_VOID_P(v, log->cd_origco_offset);
copy_v3_v3(oco, v->co);
}
if (log->cd_dyn_vert >= 0) {
MDynTopoVert *mv = BM_ELEM_CD_GET_VOID_P(v, log->cd_dyn_vert);
copy_v3_v3(mv->origco, v->co);
copy_v3_v3(mv->origno, v->no);
if (log->cd_origno_offset >= 0) {
float *ono = BM_ELEM_CD_GET_VOID_P(v, log->cd_origno_offset);
copy_v3_v3(ono, v->no);
}
if (cd_vcol_offset >= 0) {
float *color = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
if (log->cd_origvcol_offset >= 0) {
float *ocolor = BM_ELEM_CD_GET_VOID_P(v, log->cd_origvcol_offset);
float *color = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
copy_v3_v3(ocolor, color);
copy_v4_v4(mv->origcolor, color);
}
}
}
}
@ -535,22 +533,6 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts, BMLogEn
CustomData_bmesh_copy_data(&entry->vdata, &bm->vdata, lv->customdata, &v->head.data);
}
#endif
if (log->cd_origco_offset >= 0) {
float *oco = BM_ELEM_CD_GET_VOID_P(v, log->cd_origco_offset);
copy_v3_v3(oco, v->co);
}
if (log->cd_origno_offset >= 0) {
float *ono = BM_ELEM_CD_GET_VOID_P(v, log->cd_origno_offset);
copy_v3_v3(ono, v->no);
}
if (log->cd_origvcol_offset >= 0) {
float *ocolor = BM_ELEM_CD_GET_VOID_P(v, log->cd_origvcol_offset);
float *color = BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
copy_v3_v3(ocolor, color);
}
}
}
@ -716,9 +698,6 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
void BM_log_set_cd_offsets(
BMLog *log, int cd_origco_offset, int cd_origno_offset, int cd_origvol_offset, int cd_dyn_vert)
{
log->cd_origco_offset = cd_origco_offset;
log->cd_origno_offset = cd_origno_offset;
log->cd_origvcol_offset = cd_origvol_offset;
log->cd_dyn_vert = cd_dyn_vert;
}

View File

@ -210,14 +210,27 @@ void SCULPT_vertex_normal_get(SculptSession *ss, SculptVertRef index, float no[3
}
}
const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, SculptVertRef index)
const float *SCULPT_vertex_persistent_co_get(SculptSession *ss,
SculptVertRef index,
int cd_pers_co)
{
if (ss->persistent_base) {
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
index.i = BM_elem_index_get((BMVert *)index.i);
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
if (cd_pers_co >= 0) {
BMVert *v = (BMVert *)index.i;
float *co = BM_ELEM_CD_GET_VOID_P(v, cd_pers_co);
return co;
}
return ss->persistent_base[index.i].co;
return SCULPT_vertex_co_get(ss, index);
}
if (ss->persistent_base) {
int i = BKE_pbvh_vertex_index_to_table(ss->pbvh, index);
return ss->persistent_base[i].co;
}
return SCULPT_vertex_co_get(ss, index);
}
@ -259,8 +272,24 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, SculptVertRef index, flo
}
}
void SCULPT_vertex_persistent_normal_get(SculptSession *ss, SculptVertRef index, float no[3])
void SCULPT_vertex_persistent_normal_get(SculptSession *ss,
SculptVertRef index,
float no[3],
int cd_pers_no)
{
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
if (cd_pers_no >= 0) {
BMVert *v = (BMVert *)index.i;
float(*no2)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_pers_no);
copy_v3_v3(no, no2);
return;
}
SCULPT_vertex_normal_get(ss, index, no);
return;
}
if (ss->persistent_base) {
copy_v3_v3(no, ss->persistent_base[BKE_pbvh_vertex_index_to_table(ss->pbvh, index)].no);
return;
@ -5060,7 +5089,26 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
Sculpt *sd = data->sd;
const Brush *brush = data->brush;
const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT;
bool use_persistent_base = brush->flag & BRUSH_PERSISTENT;
const bool is_bmesh = BKE_pbvh_type(ss->pbvh) == PBVH_BMESH;
bool reset_disp = false;
if (is_bmesh) {
use_persistent_base = use_persistent_base && data->cd_pers_co >= 0;
// check if we need to zero displacement factor
// in first run of brush stroke
if (!use_persistent_base) {
int nidx = BKE_pbvh_get_node_index(ss->pbvh, data->nodes[n]);
reset_disp = !BLI_BITMAP_TEST(ss->cache->layer_disp_map, nidx);
BLI_BITMAP_SET(ss->cache->layer_disp_map, nidx, true);
}
}
else {
use_persistent_base = use_persistent_base && ss->persistent_base;
}
PBVHVertexIter vd;
SculptOrigVertData orig_data;
@ -5073,10 +5121,6 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
const int thread_id = BLI_task_parallel_thread_id(tls);
bool bmeshpbvh = BKE_pbvh_type(ss->pbvh) == PBVH_BMESH;
if (bmeshpbvh) {
BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
// BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
}
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
@ -5097,12 +5141,26 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
const int vi = vd.index;
float *disp_factor;
if (use_persistent_base) {
disp_factor = &ss->persistent_base[vi].disp;
if (is_bmesh) {
BMVert *v = (BMVert *)vd.vertex.i;
disp_factor = BM_ELEM_CD_GET_VOID_P(v, data->cd_pers_disp);
}
else {
disp_factor = &ss->persistent_base[vi].disp;
}
}
else if (is_bmesh) {
BMVert *v = (BMVert *)vd.vertex.i;
disp_factor = BM_ELEM_CD_GET_VOID_P(v, data->cd_layer_disp);
}
else {
disp_factor = &ss->cache->layer_displacement_factor[vi];
}
if (reset_disp) {
*disp_factor = 0.0f;
}
/* When using persistent base, the layer brush (holding Control) invert mode resets the
* height of the layer to 0. This makes possible to clean edges of previously added layers
* on top of the base. */
@ -5127,10 +5185,12 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
float normal[3];
if (use_persistent_base) {
SCULPT_vertex_persistent_normal_get(ss, vd.vertex, normal);
SCULPT_vertex_persistent_normal_get(ss, vd.vertex, normal, data->cd_pers_no);
mul_v3_fl(normal, brush->height);
madd_v3_v3v3fl(
final_co, SCULPT_vertex_persistent_co_get(ss, vd.vertex), normal, *disp_factor);
madd_v3_v3v3fl(final_co,
SCULPT_vertex_persistent_co_get(ss, vd.vertex, data->cd_pers_co),
normal,
*disp_factor);
}
else {
normal_short_to_float_v3(normal, orig_data.no);
@ -5156,17 +5216,53 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
int cd_pers_co = -1, cd_pers_no = -1, cd_pers_disp = -1, cd_layer_disp = -1;
if (ss->cache->layer_displacement_factor == NULL) {
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
if (ss->cache->layer_displacement_factor) {
MEM_SAFE_FREE(ss->cache->layer_displacement_factor);
ss->cache->layer_displacement_factor = NULL;
}
// note that we don't allow dyntopo to split the PBVH during
// the stroke (see DYNTOPO_HAS_DYNAMIC_SPLIT)
// so we don't have to worry about resizing ss->cache->layer_disp_map
if (!ss->cache->layer_disp_map) {
int totnode2 = BKE_pbvh_get_totnodes(ss->pbvh);
ss->cache->layer_disp_map = BLI_BITMAP_NEW(totnode2, "ss->cache->layer_disp_map");
ss->cache->layer_disp_map_size = totnode2;
}
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO);
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO);
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP);
SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_DISP);
cd_pers_co = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO);
cd_pers_no = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO);
cd_pers_disp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP);
cd_layer_disp = SCULPT_dyntopo_get_templayer(
ss, CD_PROP_FLOAT, SCULPT_LAYER_DISP);
}
else if (ss->cache->layer_displacement_factor == NULL) {
ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
"layer displacement factor");
}
SCULPT_vertex_random_access_ensure(ss);
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
.cd_pers_co = cd_pers_co,
.cd_pers_no = cd_pers_no,
.cd_pers_disp = cd_pers_disp,
.cd_layer_disp = cd_layer_disp,
};
TaskParallelSettings settings;
@ -6188,10 +6284,12 @@ static void topology_undopush_cb(PBVHNode *node, void *data)
{
SculptSearchSphereData *sdata = (SculptSearchSphereData *)data;
SCULPT_undo_push_node(sdata->ob,
node,
sdata->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
SCULPT_UNDO_COORDS);
SCULPT_ensure_dyntopo_node_undo(
sdata->ob,
node,
sdata->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS,
0);
BKE_pbvh_node_mark_update(node);
}
@ -6260,7 +6358,7 @@ static void sculpt_topology_update(Sculpt *sd,
(brush->flag & BRUSH_FRONTFACE) != 0,
(brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE),
symidx,
brush->sculpt_tool != SCULPT_TOOL_DRAW_SHARP);
DYNTOPO_HAS_DYNAMIC_SPLIT(brush->sculpt_tool));
/* Update average stroke position. */
copy_v3_v3(location, ss->cache->true_location);
@ -7189,6 +7287,10 @@ void SCULPT_cache_free(StrokeCache *cache)
MEM_SAFE_FREE(cache->prev_displacement);
MEM_SAFE_FREE(cache->limit_surface_co);
MEM_SAFE_FREE(cache->layer_disp_map);
cache->layer_disp_map = NULL;
cache->layer_disp_map_size = 0;
if (cache->pose_ik_chain) {
SCULPT_pose_ik_chain_free(cache->pose_ik_chain);
}
@ -8706,6 +8808,30 @@ static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
MEM_SAFE_FREE(ss->persistent_base);
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
ss->persistent_base = NULL;
int cd_pers_co = SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO);
int cd_pers_no = SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO);
int cd_pers_disp = SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP);
const int totvert = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totvert; i++) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
BMVert *v = (BMVert *)vertex.i;
float(*co)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_pers_co);
float(*no)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_pers_no);
float *disp = BM_ELEM_CD_GET_VOID_P(v, cd_pers_disp);
copy_v3_v3(co, SCULPT_vertex_co_get(ss, vertex));
SCULPT_vertex_normal_get(ss, vertex, no);
*disp = 0.0f;
}
return OPERATOR_FINISHED;
}
const int totvert = SCULPT_vertex_count_get(ss);
ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert,
"layer persistent base");

View File

@ -242,8 +242,9 @@ static void cloth_brush_add_length_constraint(SculptSession *ss,
length_constraint->type = SCULPT_CLOTH_CONSTRAINT_STRUCTURAL;
if (use_persistent) {
length_constraint->length = len_v3v3(SCULPT_vertex_persistent_co_get(ss, v1),
SCULPT_vertex_persistent_co_get(ss, v2));
length_constraint->length = len_v3v3(
SCULPT_vertex_persistent_co_get(ss, v1, cloth_sim->cd_pers_co),
SCULPT_vertex_persistent_co_get(ss, v2, cloth_sim->cd_pers_no));
}
else {
length_constraint->length = len_v3v3(SCULPT_vertex_co_get(ss, v1),
@ -1073,6 +1074,13 @@ SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
cloth_sim = MEM_callocN(sizeof(SculptClothSimulation), "cloth constraints");
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
cloth_sim->cd_pers_co = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO);
cloth_sim->cd_pers_no = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO);
cloth_sim->cd_pers_disp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP);
}
//cloth_sim->cd_pers_co = SCULPT_dyntopo_get_templayer
cloth_sim->length_constraints = MEM_callocN(sizeof(SculptClothLengthConstraint) *
CLOTH_LENGTH_CONSTRAINTS_BLOCK,
"cloth length constraints");

View File

@ -130,15 +130,47 @@ void SCULPT_dyntopo_save_origverts(SculptSession *ss)
}
static char layer_id[] = "_dyntopo_node_id";
static char origco_id[] = "_dyntopop_orig_co";
static char origno_id[] = "_dyntopop_orig_no";
static char origcolor_id[] = "_dyntopo_orig_vcol";
void SCULPT_dyntopo_node_layers_update_offsets(SculptSession *ss)
{
SCULPT_dyntopo_node_layers_add(ss);
}
bool SCULPT_dyntopo_has_templayer(SculptSession *ss, int type, const char *name)
{
return CustomData_get_named_layer_index(&ss->bm->vdata, type, name) >= 0;
}
int SCULPT_dyntopo_ensure_templayer(SculptSession *ss, int type, const char *name)
{
int li = CustomData_get_named_layer_index(&ss->bm->vdata, type, name);
if (li < 0) {
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, type, name);
SCULPT_dyntopo_node_layers_update_offsets(ss);
BKE_pbvh_update_offsets(
ss->pbvh, ss->cd_vert_node_offset, ss->cd_face_node_offset, ss->cd_dyn_vert);
li = CustomData_get_named_layer_index(&ss->bm->vdata, type, name);
}
int cd_off = CustomData_get_n_offset(
&ss->bm->vdata, type, li - CustomData_get_layer_index(&ss->bm->vdata, type));
ss->bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY;
return cd_off;
}
int SCULPT_dyntopo_get_templayer(SculptSession *ss, int type, const char *name)
{
if (!SCULPT_dyntopo_has_templayer(ss, type, name)) {
return -1;
}
return SCULPT_dyntopo_ensure_templayer(ss, type, name);
}
void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
{
int cd_node_layer_index, cd_face_node_layer_index;
@ -146,15 +178,6 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
int cd_origco_index, cd_origno_index, cd_origvcol_index = -1;
bool have_vcol = CustomData_has_layer(&ss->bm->vdata, CD_PROP_COLOR);
if (have_vcol) {
cd_origvcol_index = CustomData_get_named_layer_index(
&ss->bm->vdata, CD_PROP_COLOR, origcolor_id);
if (cd_origvcol_index == -1) {
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_COLOR, origcolor_id);
}
}
if (!CustomData_has_layer(&ss->bm->vdata, CD_DYNTOPO_VERT)) {
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_DYNTOPO_VERT);
@ -162,16 +185,6 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
ss->bm->vdata.layers[cd_dyn_vert].flag |= CD_FLAG_TEMPORARY;
}
cd_origco_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3, origco_id);
if (cd_origco_index == -1) {
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT3, origco_id);
}
cd_origno_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3, origno_id);
if (cd_origno_index == -1) {
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_FLOAT3, origno_id);
}
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT32, layer_id);
if (cd_node_layer_index == -1) {
BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT32, layer_id);
@ -184,42 +197,16 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
}
// get indices again, as they might have changed after adding new layers
cd_origco_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3, origco_id);
cd_origno_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3, origno_id);
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT32, layer_id);
cd_face_node_layer_index = CustomData_get_named_layer_index(
&ss->bm->pdata, CD_PROP_INT32, layer_id);
if (have_vcol) {
cd_origvcol_index = CustomData_get_named_layer_index(
&ss->bm->vdata, CD_PROP_COLOR, origcolor_id);
ss->cd_origvcol_offset = CustomData_get_n_offset(
&ss->bm->vdata,
CD_PROP_COLOR,
cd_origvcol_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_COLOR));
ss->bm->vdata.layers[cd_origvcol_index].flag |= CD_FLAG_TEMPORARY;
}
else {
ss->cd_origvcol_offset = -1;
}
ss->cd_origvcol_offset = -1;
ss->cd_dyn_vert = CustomData_get_offset(&ss->bm->vdata, CD_DYNTOPO_VERT);
ss->cd_origco_offset = CustomData_get_n_offset(
&ss->bm->vdata,
CD_PROP_FLOAT3,
cd_origco_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3));
ss->bm->vdata.layers[cd_origco_index].flag |= CD_FLAG_TEMPORARY;
ss->cd_vcol_offset = CustomData_get_offset(&ss->bm->vdata, CD_PROP_COLOR);
ss->cd_origno_offset = CustomData_get_n_offset(
&ss->bm->vdata,
CD_PROP_FLOAT3,
cd_origno_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_FLOAT3));
ss->bm->vdata.layers[cd_origno_index].flag |= CD_FLAG_TEMPORARY;
ss->cd_vert_node_offset = CustomData_get_n_offset(
&ss->bm->vdata,
CD_PROP_INT32,
@ -360,7 +347,6 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
.use_toolflags = false,
}));
BM_mesh_bm_from_me(NULL,
ss->bm,
me,
@ -379,9 +365,47 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
BMVert *v;
int cd_vcol_offset = CustomData_get_offset(&ss->bm->vdata, CD_PROP_COLOR);
int cd_pers_co = -1, cd_pers_no = -1, cd_pers_disp = -1;
int cd_layer_disp = -1;
// convert layer brush data
if (ss->persistent_base) {
cd_pers_co = SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO);
cd_pers_no = SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO);
cd_pers_disp = SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP);
cd_layer_disp = SCULPT_dyntopo_ensure_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_DISP);
SCULPT_dyntopo_node_layers_update_offsets(ss);
BKE_pbvh_update_offsets(
ss->pbvh, ss->cd_vert_node_offset, ss->cd_face_node_offset, ss->cd_dyn_vert);
cd_vcol_offset = CustomData_get_offset(&ss->bm->vdata, CD_PROP_COLOR);
}
else {
cd_layer_disp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP);
}
int i = 0;
BM_ITER_MESH (v, &iter, ss->bm, BM_VERTS_OF_MESH) {
MDynTopoVert *mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v);
// persistent base
if (cd_pers_co >= 0) {
float(*co)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_pers_co);
float(*no)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_pers_no);
float *disp = BM_ELEM_CD_GET_VOID_P(v, cd_pers_disp);
copy_v3_v3(co, ss->persistent_base[i].co);
copy_v3_v3(no, ss->persistent_base[i].no);
*disp = ss->persistent_base[i].disp;
}
if (cd_layer_disp >= 0) {
float *disp = BM_ELEM_CD_GET_VOID_P(v, cd_layer_disp);
*disp = 0.0f;
}
copy_v3_v3(mv->origco, v->co);
copy_v3_v3(mv->origno, v->no);
@ -389,6 +413,8 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
MPropCol *color = (MPropCol *)BM_ELEM_CD_GET_VOID_P(v, cd_vcol_offset);
copy_v4_v4(mv->origcolor, color->color);
}
i++;
}
/* Make sure the data for existing faces are initialized. */
@ -411,6 +437,33 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
void SCULPT_dyntopo_save_persistent_base(SculptSession *ss) {
int cd_pers_co = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO);
int cd_pers_no = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO);
int cd_pers_disp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_PERS_DISP);
if (cd_pers_co >= 0) {
BMIter iter;
MEM_SAFE_FREE(ss->persistent_base);
ss->persistent_base = MEM_callocN(sizeof(*ss->persistent_base) * ss->bm->totvert,
"ss->persistent_base");
BMVert *v;
int i = 0;
BM_ITER_MESH (v, &iter, ss->bm, BM_VERTS_OF_MESH) {
float(*co)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_pers_co);
float(*no)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_pers_no);
float *disp = BM_ELEM_CD_GET_VOID_P(v, cd_pers_disp);
copy_v3_v3(ss->persistent_base[i].co, co);
copy_v3_v3(ss->persistent_base[i].no, no);
ss->persistent_base[i].disp = *disp;
i++;
}
}
}
/* Free the sculpt BMesh and BMLog
*
* If 'unode' is given, the BMesh's data is copied out to the unode
@ -464,6 +517,9 @@ static void SCULPT_dynamic_topology_disable_ex(
/* Typically valid but with global-undo they can be NULL, see: T36234. */
if (ss->bm) {
//rebuild ss->persistent_base if necassary
SCULPT_dyntopo_save_persistent_base(ss);
BM_mesh_free(ss->bm);
ss->bm = NULL;
}

View File

@ -104,8 +104,13 @@ void SCULPT_vertex_normal_get(SculptSession *ss, SculptVertRef index, float no[3
float SCULPT_vertex_mask_get(struct SculptSession *ss, SculptVertRef index);
const float *SCULPT_vertex_color_get(SculptSession *ss, SculptVertRef index);
const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, SculptVertRef index);
void SCULPT_vertex_persistent_normal_get(SculptSession *ss, SculptVertRef index, float no[3]);
const float *SCULPT_vertex_persistent_co_get(SculptSession *ss,
SculptVertRef index,
int cd_pers_co);
void SCULPT_vertex_persistent_normal_get(SculptSession *ss,
SculptVertRef index,
float no[3],
int cd_pers_no);
/* Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. */
const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, SculptVertRef index);
@ -309,11 +314,14 @@ void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
void SCULPT_floodfill_add_initial(SculptFloodFill *flood, SculptVertRef index);
void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index);
void SCULPT_floodfill_execute(
struct SculptSession *ss,
SculptFloodFill *flood,
bool (*func)(SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata),
void *userdata);
void SCULPT_floodfill_execute(struct SculptSession *ss,
SculptFloodFill *flood,
bool (*func)(SculptSession *ss,
SculptVertRef from_v,
SculptVertRef to_v,
bool is_duplicate,
void *userdata),
void *userdata);
void SCULPT_floodfill_free(SculptFloodFill *flood);
/* Dynamic topology */
@ -695,7 +703,7 @@ typedef struct SculptUndoNode {
int nodemap_size;
size_t undo_size;
//int gen, lasthash;
// int gen, lasthash;
} SculptUndoNode;
/* Factor of brush to have rake point following behind
@ -820,6 +828,9 @@ typedef struct SculptThreadedTaskData {
ThreadMutex mutex;
// Layer brush
int cd_pers_co, cd_pers_no, cd_pers_disp;
int cd_layer_disp;
} SculptThreadedTaskData;
/*************** Brush testing declarations ****************/
@ -1092,9 +1103,12 @@ 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; // copy of PaintStroke->stroke_distance
float stroke_distance_t;
float last_dyntopo_t;
int layer_disp_map_size;
BLI_bitmap *layer_disp_map;
} StrokeCache;
/* Sculpt Filters */
@ -1415,7 +1429,6 @@ bool SCULPT_ensure_dyntopo_node_undo(struct Object *ob,
float SCULPT_calc_concavity(SculptSession *ss, SculptVertRef vref);
typedef struct SculptCurvatureData {
float ks[3];
float principle[3][3]; // normalized
@ -1427,3 +1440,28 @@ bool SCULPT_calc_principle_curvatures(SculptSession *ss,
void SCULPT_curvature_begin(SculptSession *ss, struct PBVHNode *node);
void SCULPT_curvature_dir_get(SculptSession *ss, SculptVertRef v, float dir[3]);
/*
Get a named temporary customdata layer, creating it if necassary.
The layer will be marked with CD_FLAG_TEMPORARY.
Returns customdata offset.
*/
int SCULPT_dyntopo_ensure_templayer(SculptSession *ss, int type, const char *name);
bool SCULPT_dyntopo_has_templayer(SculptSession *ss, int type, const char *name);
/* like SCULPT_dyntopo_ensure_templayer but doesn't auto-create layers,
if a layer doesn't exist it will return -1*/
int SCULPT_dyntopo_get_templayer(SculptSession *ss, int type, const char *name);
void SCULPT_dyntopo_save_persistent_base(SculptSession *ss);
#define SCULPT_LAYER_PERS_CO "__dyntopo_layer_pers_co"
#define SCULPT_LAYER_PERS_NO "__dyntopo_layer_pers_no"
#define SCULPT_LAYER_PERS_DISP "__dyntopo_layer_pers_disp"
#define SCULPT_LAYER_DISP "__dyntopo_layer_disp"
// these tools don't support dynamic pbvh splitting during the stroke
#define DYNTOPO_HAS_DYNAMIC_SPLIT(tool) \
(ELEM(tool, SCULPT_TOOL_DRAW_SHARP, SCULPT_TOOL_LAYER) == 0)

View File

@ -506,8 +506,6 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_GRAB, \
SCULPT_TOOL_ROTATE, \
SCULPT_TOOL_CLOTH, \
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_LAYER, \
SCULPT_TOOL_DISPLACEMENT_ERASER, \
SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_ELASTIC_DEFORM, \
@ -527,7 +525,6 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_GRAB, \
SCULPT_TOOL_ELASTIC_DEFORM, \
SCULPT_TOOL_ROTATE, \
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_DISPLACEMENT_ERASER, \
SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_MASK) == 0)

View File

@ -536,6 +536,7 @@ typedef struct MDynTopoVert {
float origmask;
float curvature_dir[3];
int _pad[1];
} MDynTopoVert;
/*MDynTopoVert->flag*/