diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 21 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 1 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 6 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_mask_init.c | 196 |
5 files changed, 225 insertions, 0 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 19bf0662885..e393ddf16d6 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3121,6 +3121,11 @@ class VIEW3D_MT_mask(Menu): props = layout.operator("sculpt.dirty_mask", text='Dirty Mask') + layout.separator() + + layout.menu("VIEW3D_MT_random_mask", text="Random Mask") + + class VIEW3D_MT_face_sets(Menu): bl_label = "Face Sets" @@ -3222,6 +3227,21 @@ class VIEW3D_MT_face_sets_init(Menu): op.mode = 'FACE_MAPS' +class VIEW3D_MT_random_mask(Menu): + bl_label = "Random Mask" + + def draw(self, _context): + layout = self.layout + + op = layout.operator("sculpt.mask_init", text='Per Vertex') + op.mode = 'RANDOM_PER_VERTEX' + + op = layout.operator("sculpt.mask_init", text='Per Face Set') + op.mode = 'RANDOM_PER_FACE_SET' + + op = layout.operator("sculpt.mask_init", text='Per Loose Part') + op.mode = 'RANDOM_PER_LOOSE_PART' + class VIEW3D_MT_particle(Menu): bl_label = "Particle" @@ -7563,6 +7583,7 @@ classes = ( VIEW3D_MT_mask, VIEW3D_MT_face_sets, VIEW3D_MT_face_sets_init, + VIEW3D_MT_random_mask, VIEW3D_MT_particle, VIEW3D_MT_particle_context_menu, VIEW3D_MT_particle_showhide, diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index fff172c0707..3b668a1bd4c 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -68,6 +68,7 @@ set(SRC sculpt_filter_mesh.c sculpt_geodesic.c sculpt_mask_expand.c + sculpt_mask_init.c sculpt_multiplane_scrape.c sculpt_paint_color.c sculpt_pose.c diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 0b30303de91..d32391bfb67 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -9461,6 +9461,7 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_color_filter); WM_operatortype_append(SCULPT_OT_mask_by_color); WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit); + WM_operatortype_append(SCULPT_OT_mask_init); WM_operatortype_append(SCULPT_OT_expand); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index c323a4d744a..087cb6dd94a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -792,6 +792,9 @@ typedef struct SculptThreadedTaskData { int face_set; int filter_undo_type; + int mask_init_mode; + int mask_init_seed; + ThreadMutex mutex; } SculptThreadedTaskData; @@ -1356,6 +1359,9 @@ void SCULPT_OT_dirty_mask(struct wmOperatorType *ot); /* Mask and Face Sets Expand. */ void SCULPT_OT_mask_expand(struct wmOperatorType *ot); +/* Mask Init. */ +void SCULPT_OT_mask_init(struct wmOperatorType *ot); + /* Detail size. */ void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot); void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_init.c b/source/blender/editors/sculpt_paint/sculpt_mask_init.c new file mode 100644 index 00000000000..b2fae9198fd --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_mask_init.c @@ -0,0 +1,196 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_hash.h" +#include "BLI_task.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "DNA_brush_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_brush.h" +#include "BKE_ccg.h" +#include "BKE_context.h" +#include "BKE_mesh.h" +#include "BKE_multires.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_sculpt.h" +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "bmesh.h" + +#include <math.h> +#include <stdlib.h> + +/* Mask Init operator. */ +/* Initializes mask values for the entire mesh depending on the mode. */ + +typedef enum eSculptMaskInitMode { + SCULPT_MASK_INIT_RANDOM_PER_VERTEX, + SCULPT_MASK_INIT_RANDOM_PER_FACE_SET, + SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART, +} eSculptMaskInitMode; + +static EnumPropertyItem prop_sculpt_mask_init_mode_types[] = { + { + SCULPT_MASK_INIT_RANDOM_PER_VERTEX, + "RANDOM_PER_VERTEX", + 0, + "Random per Vertex", + "", + }, + { + SCULPT_MASK_INIT_RANDOM_PER_FACE_SET, + "RANDOM_PER_FACE_SET", + 0, + "Random per Face Set", + "", + }, + { + SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART, + "RANDOM_PER_LOOSE_PART", + 0, + "Random per Loose Part", + "", + }, + {0, NULL, 0, NULL, NULL}, +}; + +static void mask_init_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + PBVHNode *node = data->nodes[i]; + PBVHVertexIter vd; + const int mode = data->mask_init_mode; + const int seed = data->mask_init_seed; + SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + switch (mode) { + case SCULPT_MASK_INIT_RANDOM_PER_VERTEX: + *vd.mask = BLI_hash_int_01(vd.index + seed); + break; + case SCULPT_MASK_INIT_RANDOM_PER_FACE_SET: { + const int face_set = SCULPT_vertex_face_set_get(ss, vd.index); + *vd.mask = BLI_hash_int_01(face_set + seed); + break; + } + case SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART: + *vd.mask = BLI_hash_int_01(ss->vertex_info.connected_component[vd.index] + seed); + break; + } + } + BKE_pbvh_vertex_iter_end; + BKE_pbvh_node_mark_update_mask(data->nodes[i]); +} + +static int sculpt_mask_init_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + + const int mode = RNA_enum_get(op->ptr, "mode"); + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + + PBVH *pbvh = ob->sculpt->pbvh; + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + + if (totnode == 0) { + return OPERATOR_CANCELLED; + } + + SCULPT_undo_push_begin(ob, "init mask"); + + if (mode == SCULPT_MASK_INIT_RANDOM_PER_LOOSE_PART) { + SCULPT_connected_components_ensure(ob); + } + + SculptThreadedTaskData data = { + .ob = ob, + .nodes = nodes, + .mask_init_mode = mode, + .mask_init_seed = PIL_check_seconds_timer(), + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, mask_init_task_cb, &settings); + + multires_stitch_grids(ob); + + SCULPT_undo_push_end(); + + BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); + MEM_SAFE_FREE(nodes); + SCULPT_tag_update_overlays(C); + return OPERATOR_FINISHED; +} + +void SCULPT_OT_mask_init(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Init Mask"; + ot->description = "Creates a new mask for the entire mesh"; + ot->idname = "SCULPT_OT_mask_init"; + + /* api callbacks */ + ot->exec = sculpt_mask_init_exec; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + RNA_def_enum(ot->srna, + "mode", + prop_sculpt_mask_init_mode_types, + SCULPT_MASK_INIT_RANDOM_PER_VERTEX, + "Mode", + ""); +} |