[Bf-blender-cvs] [d9fd3be084f] sculpt-mode-features: Pose tool: Mask expand operator
Pablo Dobarro
noreply at git.blender.org
Tue Jun 11 15:28:36 CEST 2019
Commit: d9fd3be084fa9dabb3d73b8e3b24d5394acb2483
Author: Pablo Dobarro
Date: Tue Jun 11 15:28:10 2019 +0200
Branches: sculpt-mode-features
https://developer.blender.org/rBd9fd3be084fa9dabb3d73b8e3b24d5394acb2483
Pose tool: Mask expand operator
This operator is designed to use with the transform.rotate tool to
create a pose tool. It generates a mask from the active vertex,
following the topology of the mesh.
The operator has two modes. It can expand the mask to the vertex under
the cursor or to a certain number of iterations. All the iterations are
cached when the operator is invoked, so it should be usable with high
poly meshes.
I also included some hardcoded mask operations when the operator
finishes. In the future, this could be included as an operator macro if
it does not have a significant performance penalty (like redrawing all
nodes each time a new operator is invoked).
It does not support symmetry and it only works with meshes (no dyntopo
or multires).
I also fixed some bugs in the transform code that were breaking EEVEE
compatibility. Undo system still fails sometimes.
===================================================================
M source/blender/draw/modes/sculpt_mode.c
M source/blender/editors/sculpt_paint/sculpt.c
M source/blender/editors/sculpt_paint/sculpt_intern.h
===================================================================
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
index 42a2333f305..18deddb04ae 100644
--- a/source/blender/draw/modes/sculpt_mode.c
+++ b/source/blender/draw/modes/sculpt_mode.c
@@ -155,7 +155,7 @@ static void SCULPT_cache_populate(void *vedata, Object *ob)
if (ob->sculpt) {
const DRWContextState *draw_ctx = DRW_context_state_get();
- if ((ob == draw_ctx->obact) && BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d)) {
+ if (ob == draw_ctx->obact) {
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh && pbvh_has_mask(pbvh)) {
DRW_shgroup_call_sculpt(stl->g_data->mask_overlay_grp, ob, false, true, false);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index d22750c1f89..266279e688b 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -31,6 +31,7 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_stack.h"
+#include "BLI_gsqueue.h"
#include "BLT_translation.h"
@@ -7756,14 +7757,21 @@ static void sculpt_filter_cache_init(Object *ob, Sculpt *sd, bool init_random, b
static void sculpt_filter_cache_free(SculptSession *ss)
{
- MEM_freeN(ss->filter_cache->orco);
- MEM_freeN(ss->filter_cache->nodes);
+ if (ss->filter_cache->orco) {
+ MEM_freeN(ss->filter_cache->orco);
+ }
+ if (ss->filter_cache->nodes) {
+ MEM_freeN(ss->filter_cache->nodes);
+ }
if (ss->filter_cache->random_disp) {
MEM_freeN(ss->filter_cache->random_disp);
}
if (ss->filter_cache->orvcol) {
MEM_freeN(ss->filter_cache->orvcol);
}
+ if (ss->filter_cache->mask_update_it) {
+ MEM_freeN(ss->filter_cache->mask_update_it);
+ }
MEM_freeN(ss->filter_cache);
}
@@ -8788,7 +8796,6 @@ void ED_sculpt_init_transform(const struct bContext *C, bool transform_pivot_onl
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
- struct Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
copy_v3_v3(ss->init_pivot_pos, ss->pivot_pos);
@@ -8938,16 +8945,36 @@ void ED_sculpt_update_modal_transform(const struct bContext *C, bool transform_p
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
- ARegion *ar = CTX_wm_region(C);
- struct Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
if (transform_pivot_only) {
return;
}
+ if (!ss->pbvh) {
+ return;
+ }
+
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
+ if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
+
+ if (ss->filter_cache->nodes) {
+ MEM_freeN(ss->filter_cache->nodes);
+ }
+ SculptSearchSphereData searchdata = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = FLT_MAX,
+ };
+ BKE_pbvh_search_gather(ss->pbvh,
+ sculpt_search_sphere_cb,
+ &searchdata,
+ &ss->filter_cache->nodes,
+ &ss->filter_cache->totnode);
+ }
+
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
@@ -9038,7 +9065,6 @@ static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const w
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
ARegion *ar = CTX_wm_region(C);
- struct Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
@@ -9130,6 +9156,273 @@ static void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
"");
}
+static void sculpt_expand_task_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+ int proc_it = data->proc_it;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ int vi = vd.vert_indices[vd.i];
+ float final_mask = *vd.mask;
+ if (ss->filter_cache->mask_update_it[vi] <= proc_it &&
+ ss->filter_cache->mask_update_it[vi] != 0) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+
+ if (*vd.mask != final_mask) {
+ *vd.mask = final_mask;
+ BKE_pbvh_node_mark_redraw(node);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ float prevclik_f[2];
+ copy_v2_v2(prevclik_f, op->customdata);
+ int prevclick[2];
+ prevclick[0] = (int)prevclik_f[0];
+ prevclick[1] = (int)prevclik_f[1];
+ int len = len_v2v2_int(prevclick, event->mval);
+
+ len = ABS(len);
+ int mask_speed = RNA_int_get(op->ptr, "mask_speed");
+ int proc_it = len / mask_speed;
+ proc_it = proc_it + 1;
+
+ if (RNA_boolean_get(op->ptr, "use_cursor")) {
+ StrokeGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ sculpt_stroke_get_geometry_info(C, &sgi, mouse);
+ proc_it = ss->filter_cache->mask_update_it[ss->active_vertex_mesh_index];
+ }
+
+ if (event->type == 1 && (event->val == 2 || event->val == 1)) {
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ /* Invert */
+ if (RNA_boolean_get(op->ptr, "invert")) {
+ for (int i = 0; i < ss->totvert; i++) {
+ ss->vmask[i] = 1.0f - ss->vmask[i];
+ }
+ }
+
+ /* Smooth iterations */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .smooth_value = 0.5f,
+ .filter_type = MASK_FILTER_BLUR,
+ };
+
+ int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
+ for (int i = 0; i < smooth_iterations; i++) {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
+ ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings);
+ }
+
+ /* Pivot position */
+ if (RNA_boolean_get(op->ptr, "update_pivot")) {
+ float avg[3];
+ int total = 0;
+ float threshold = 0.2f;
+ zero_v3(avg);
+ for (int i = 0; i < ss->totvert; i++) {
+ // symmetry not supported yet
+ if (ss->vmask[i] < (0.5f + threshold) && ss->vmask[i] > (0.5f - threshold) &&
+ check_vertex_pivot_symmetry(ss->mvert[i].co, ss->pivot_pos, 0)) {
+ total++;
+ add_v3_v3(avg, ss->mvert[i].co);
+ }
+ }
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
+
+ MEM_freeN(op->customdata);
+
+ sculpt_undo_push_end();
+ sculpt_filter_cache_free(ss);
+
+ sculpt_flush_update_done(C, ob);
+ return OPERATOR_FINISHED;
+ }
+
+ if (proc_it == ss->filter_cache->mask_update_current_it) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (proc_it < ss->filter_cache->mask_update_last_it) {
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .proc_it = proc_it,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
+ ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
+
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ ss->filter_cache->mask_update_current_it = proc_it;
+ }
+
+ sculpt_flush_update_step(C);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+typedef struct maskExmandVIT {
+ int v;
+ int it;
+} maskExmandVIT;
+
+static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ StrokeGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+
+ op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");
+ copy_v2_v2(op->customdata, mouse);
+
+ sculpt_stroke_get_geometry_info(C, &sgi, mouse);
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ if (!ss->vmask) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
+
+ SculptSearchSphereData searchdata = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = FLT_MAX,
+ };
+ BKE_pbvh_search_gather(pbvh,
+ sculpt_search_sphere_cb,
+ &searchdata,
+ &ss->filter_cache->nodes,
+ &ss->filter_cache->totnode);
+
+ sculpt_undo_push_begin("mesh filter fill");
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ sculpt_undo_push_node(ob, ss->filter_cache->nodes[i], SCULPT_UNDO_MASK);
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+
+ ss->filter_cache->mask_update_it = MEM_callocN(sizeof(int) * ss->totvert,
+ "mask update iteration");
+ ss->filter_cache->mask_update_last_it = 1;
+ ss->filter_cache->mask_update_current_it = 1;
+ ss->filter_cache->mask_update_it[ss->active_vertex_mesh_index] = 1;
+ ss->vmask[ss->active_vertex_mesh_index] = 1.0f;
+
+ char *prev_mask = MEM_callocN(ss->totvert * sizeof(char), "prevmask");
+
+ GSQueue *queue = BLI_gsqueue_new(sizeof(maskExmandV
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list