Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-09-16 07:06:04 +0300
committerHans Goudey <h.goudey@me.com>2022-09-16 07:06:04 +0300
commitac76da2944a2b2810fc17f793ba313144beddd78 (patch)
treefca6b90fe56d76a4df4d86fcdb5924f22855c953 /source/blender
parent15d85c54c3f960814068074bcdff0a5546fa4d5a (diff)
Revert "UI: Use full word for face set operator name, tweak description"
This reverts commit 15d85c54c3f960814068074bcdff0a5546fa4d5a. Included a separate change/new file by mistake. Sorry for the noise.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.cc1505
1 files changed, 0 insertions, 1505 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc
deleted file mode 100644
index 1d59ba34d3e..00000000000
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc
+++ /dev/null
@@ -1,1505 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later
- * Copyright 2020 Blender Foundation. All rights reserved. */
-
-/** \file
- * \ingroup edsculpt
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_hash.h"
-#include "BLI_math.h"
-#include "BLI_task.h"
-
-#include "DNA_brush_types.h"
-#include "DNA_customdata_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "BKE_brush.h"
-#include "BKE_ccg.h"
-#include "BKE_colortools.h"
-#include "BKE_context.h"
-#include "BKE_customdata.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_fair.h"
-#include "BKE_mesh_mapping.h"
-#include "BKE_multires.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_pbvh.h"
-#include "BKE_scene.h"
-
-#include "DEG_depsgraph.h"
-
-#include "WM_api.h"
-#include "WM_message.h"
-#include "WM_toolsystem.h"
-#include "WM_types.h"
-
-#include "ED_object.h"
-#include "ED_screen.h"
-#include "ED_sculpt.h"
-#include "ED_view3d.h"
-#include "paint_intern.h"
-#include "sculpt_intern.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "bmesh.h"
-
-#include <math.h>
-#include <stdlib.h>
-
-/* Utils. */
-
-int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh)
-{
- const int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
- if (!face_sets) {
- return SCULPT_FACE_SET_NONE;
- }
-
- int next_face_set_id = 0;
- for (int i = 0; i < mesh->totpoly; i++) {
- next_face_set_id = max_ii(next_face_set_id, face_sets[i]);
- }
- next_face_set_id++;
-
- return next_face_set_id;
-}
-
-void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, const int new_id)
-{
- int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
- if (!face_sets) {
- return;
- }
-
- for (int i = 0; i < mesh->totpoly; i++) {
- if (face_sets[i] == SCULPT_FACE_SET_NONE) {
- face_sets[i] = new_id;
- }
- }
-}
-
-int ED_sculpt_face_sets_active_update_and_get(bContext *C, Object *ob, const float mval[2])
-{
- SculptSession *ss = ob->sculpt;
- if (!ss) {
- return SCULPT_FACE_SET_NONE;
- }
-
- SculptCursorGeometryInfo gi;
- if (!SCULPT_cursor_geometry_info_update(C, &gi, mval, false)) {
- return SCULPT_FACE_SET_NONE;
- }
-
- return SCULPT_active_face_set_get(ss);
-}
-
-/* Draw Face Sets Brush. */
-
-static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- MeshElemMap *vert_map = &ss->pmap[vd.index];
- for (int j = 0; j < ss->pmap[vd.index].count; j++) {
- const MPoly *p = &ss->mpoly[vert_map->indices[j]];
-
- float poly_center[3];
- BKE_mesh_calc_poly_center(p, &ss->mloop[p->loopstart], mvert, poly_center);
-
- if (!sculpt_brush_test_sq_fn(&test, poly_center)) {
- continue;
- }
- const bool face_hidden = ss->hide_poly && ss->hide_poly[vert_map->indices[j]];
- if (face_hidden) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.vertex,
- thread_id);
-
- if (fade > 0.05f) {
- ss->face_sets[vert_map->indices[j]] = ss->cache->paint_face_set;
- }
- }
- }
- else if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.vertex,
- thread_id);
-
- if (fade > 0.05f) {
- SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0);
- /* This operations needs a strength tweak as the relax deformation is too weak by default. */
- if (relax_face_sets) {
- bstrength *= 2.0f;
- }
-
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.vertex)) {
- continue;
- }
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.vertex,
- thread_id);
-
- SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
- if (vd.mvert) {
- BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- if (ss->cache->alt_smooth) {
- SCULPT_boundary_info_ensure(ob);
- for (int i = 0; i < 4; i++) {
- BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
- }
- }
- else {
- BLI_task_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings);
- }
-}
-
-/* Face Sets Operators */
-
-typedef enum eSculptFaceGroupsCreateModes {
- SCULPT_FACE_SET_MASKED = 0,
- SCULPT_FACE_SET_VISIBLE = 1,
- SCULPT_FACE_SET_ALL = 2,
- SCULPT_FACE_SET_SELECTION = 3,
-} eSculptFaceGroupsCreateModes;
-
-static EnumPropertyItem prop_sculpt_face_set_create_types[] = {
- {
- SCULPT_FACE_SET_MASKED,
- "MASKED",
- 0,
- "Face Set from Masked",
- "Create a new Face Set from the masked faces",
- },
- {
- SCULPT_FACE_SET_VISIBLE,
- "VISIBLE",
- 0,
- "Face Set from Visible",
- "Create a new Face Set from the visible vertices",
- },
- {
- SCULPT_FACE_SET_ALL,
- "ALL",
- 0,
- "Face Set Full Mesh",
- "Create an unique Face Set with all faces in the sculpt",
- },
- {
- SCULPT_FACE_SET_SELECTION,
- "SELECTION",
- 0,
- "Face Set from Edit Mode Selection",
- "Create an Face Set corresponding to the Edit Mode face selection",
- },
- {0, nullptr, 0, nullptr, nullptr},
-};
-
-static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- const int mode = RNA_enum_get(op->ptr, "mode");
-
- /* Dyntopo not supported. */
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
- ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED, false);
-
- const int tot_vert = SCULPT_vertex_count_get(ss);
- float threshold = 0.5f;
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode);
-
- if (!nodes) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_begin(ob, op);
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- const int next_face_set = SCULPT_face_set_next_available_get(ss);
-
- if (mode == SCULPT_FACE_SET_MASKED) {
- for (int i = 0; i < tot_vert; i++) {
- PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
-
- if (SCULPT_vertex_mask_get(ss, vertex) >= threshold &&
- SCULPT_vertex_visible_get(ss, vertex)) {
- SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
- }
- }
- }
-
- if (mode == SCULPT_FACE_SET_VISIBLE) {
-
- /* If all vertices in the sculpt are visible, create the new face set and update the default
- * color. This way the new face set will be white, which is a quick way of disabling all face
- * sets and the performance hit of rendering the overlay. */
- bool all_visible = true;
- for (int i = 0; i < tot_vert; i++) {
- PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
-
- if (!SCULPT_vertex_visible_get(ss, vertex)) {
- all_visible = false;
- break;
- }
- }
-
- if (all_visible) {
- mesh->face_sets_color_default = next_face_set;
- BKE_pbvh_face_sets_color_set(
- ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default);
- }
-
- for (int i = 0; i < tot_vert; i++) {
- PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
-
- if (SCULPT_vertex_visible_get(ss, vertex)) {
- SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
- }
- }
- }
-
- if (mode == SCULPT_FACE_SET_ALL) {
- for (int i = 0; i < tot_vert; i++) {
- PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
-
- SCULPT_vertex_face_set_set(ss, vertex, next_face_set);
- }
- }
-
- if (mode == SCULPT_FACE_SET_SELECTION) {
- 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(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .calc_vert_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++) {
- BKE_pbvh_node_mark_redraw(nodes[i]);
- }
-
- MEM_SAFE_FREE(nodes);
-
- SCULPT_undo_push_end(ob);
-
- SCULPT_tag_update_overlays(C);
-
- return OPERATOR_FINISHED;
-}
-
-void SCULPT_OT_face_sets_create(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Create Face Set";
- ot->idname = "SCULPT_OT_face_sets_create";
- ot->description = "Create a new Face Set";
-
- /* api callbacks */
- ot->exec = sculpt_face_set_create_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(
- ot->srna, "mode", prop_sculpt_face_set_create_types, SCULPT_FACE_SET_MASKED, "Mode", "");
-}
-
-typedef enum eSculptFaceSetsInitMode {
- SCULPT_FACE_SETS_FROM_LOOSE_PARTS = 0,
- SCULPT_FACE_SETS_FROM_MATERIALS = 1,
- SCULPT_FACE_SETS_FROM_NORMALS = 2,
- SCULPT_FACE_SETS_FROM_UV_SEAMS = 3,
- SCULPT_FACE_SETS_FROM_CREASES = 4,
- SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5,
- SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6,
- SCULPT_FACE_SETS_FROM_FACE_MAPS = 7,
- SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES = 8,
-} eSculptFaceSetsInitMode;
-
-static EnumPropertyItem prop_sculpt_face_sets_init_types[] = {
- {
- SCULPT_FACE_SETS_FROM_LOOSE_PARTS,
- "LOOSE_PARTS",
- 0,
- "Face Sets from Loose Parts",
- "Create a Face Set per loose part in the mesh",
- },
- {
- SCULPT_FACE_SETS_FROM_MATERIALS,
- "MATERIALS",
- 0,
- "Face Sets from Material Slots",
- "Create a Face Set per Material Slot",
- },
- {
- SCULPT_FACE_SETS_FROM_NORMALS,
- "NORMALS",
- 0,
- "Face Sets from Mesh Normals",
- "Create Face Sets for Faces that have similar normal",
- },
- {
- SCULPT_FACE_SETS_FROM_UV_SEAMS,
- "UV_SEAMS",
- 0,
- "Face Sets from UV Seams",
- "Create Face Sets using UV Seams as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_CREASES,
- "CREASES",
- 0,
- "Face Sets from Edge Creases",
- "Create Face Sets using Edge Creases as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT,
- "BEVEL_WEIGHT",
- 0,
- "Face Sets from Bevel Weight",
- "Create Face Sets using Bevel Weights as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_SHARP_EDGES,
- "SHARP_EDGES",
- 0,
- "Face Sets from Sharp Edges",
- "Create Face Sets using Sharp Edges as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_FACE_MAPS,
- "FACE_MAPS",
- 0,
- "Face Sets from Face Maps",
- "Create a Face Set per Face Map",
- },
- {
- SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES,
- "FACE_SET_BOUNDARIES",
- 0,
- "Face Sets from Face Set Boundaries",
- "Create a Face Set per isolated Face Set",
- },
-
- {0, nullptr, 0, nullptr, nullptr},
-};
-
-typedef bool (*face_sets_flood_fill_test)(
- BMesh *bm, BMFace *from_f, BMEdge *from_e, BMFace *to_f, const float threshold);
-
-static bool sculpt_face_sets_init_loose_parts_test(BMesh *UNUSED(bm),
- BMFace *from_f,
- BMEdge *UNUSED(from_e),
- BMFace *to_f,
- const float UNUSED(threshold))
-{
- return BM_elem_flag_test(from_f, BM_ELEM_HIDDEN) == BM_elem_flag_test(to_f, BM_ELEM_HIDDEN);
-}
-
-static bool sculpt_face_sets_init_normals_test(
- BMesh *UNUSED(bm), BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float threshold)
-{
- return fabsf(dot_v3v3(from_f->no, to_f->no)) > threshold;
-}
-
-static bool sculpt_face_sets_init_uv_seams_test(BMesh *UNUSED(bm),
- BMFace *UNUSED(from_f),
- BMEdge *from_e,
- BMFace *UNUSED(to_f),
- const float UNUSED(threshold))
-{
- return !BM_elem_flag_test(from_e, BM_ELEM_SEAM);
-}
-
-static bool sculpt_face_sets_init_crease_test(
- BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
-{
- return BM_elem_float_data_get(&bm->edata, from_e, CD_CREASE) < threshold;
-}
-
-static bool sculpt_face_sets_init_bevel_weight_test(
- BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
-{
- return BM_elem_float_data_get(&bm->edata, from_e, CD_BWEIGHT) < threshold;
-}
-
-static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm),
- BMFace *UNUSED(from_f),
- BMEdge *from_e,
- BMFace *UNUSED(to_f),
- const float UNUSED(threshold))
-{
- return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH);
-}
-
-static bool sculpt_face_sets_init_face_set_boundary_test(
- BMesh *bm, BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float UNUSED(threshold))
-{
- const int cd_face_sets_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
- return BM_ELEM_CD_GET_INT(from_f, cd_face_sets_offset) ==
- BM_ELEM_CD_GET_INT(to_f, cd_face_sets_offset);
-}
-
-static void sculpt_face_sets_init_flood_fill(Object *ob,
- face_sets_flood_fill_test test,
- const float threshold)
-{
- 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(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .calc_vert_normal = true,
- }));
-
- BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces");
- const int totfaces = mesh->totpoly;
-
- int *face_sets = ss->face_sets;
-
- BM_mesh_elem_table_init(bm, BM_FACE);
- BM_mesh_elem_table_ensure(bm, BM_FACE);
-
- int next_face_set = 1;
-
- for (int i = 0; i < totfaces; i++) {
- if (BLI_BITMAP_TEST(visited_faces, i)) {
- continue;
- }
- GSQueue *queue;
- queue = BLI_gsqueue_new(sizeof(int));
-
- face_sets[i] = next_face_set;
- BLI_BITMAP_ENABLE(visited_faces, i);
- BLI_gsqueue_push(queue, &i);
-
- while (!BLI_gsqueue_is_empty(queue)) {
- int from_f;
- BLI_gsqueue_pop(queue, &from_f);
-
- BMFace *f, *f_neighbor;
- BMEdge *ed;
- BMIter iter_a, iter_b;
-
- f = BM_face_at_index(bm, from_f);
-
- BM_ITER_ELEM (ed, &iter_a, f, BM_EDGES_OF_FACE) {
- BM_ITER_ELEM (f_neighbor, &iter_b, ed, BM_FACES_OF_EDGE) {
- if (f_neighbor == f) {
- continue;
- }
- int neighbor_face_index = BM_elem_index_get(f_neighbor);
- if (BLI_BITMAP_TEST(visited_faces, neighbor_face_index)) {
- continue;
- }
- if (!test(bm, f, ed, f_neighbor, threshold)) {
- continue;
- }
-
- face_sets[neighbor_face_index] = next_face_set;
- BLI_BITMAP_ENABLE(visited_faces, neighbor_face_index);
- BLI_gsqueue_push(queue, &neighbor_face_index);
- }
- }
- }
-
- next_face_set += 1;
-
- BLI_gsqueue_free(queue);
- }
-
- MEM_SAFE_FREE(visited_faces);
-
- BM_mesh_free(bm);
-}
-
-static void sculpt_face_sets_init_loop(Object *ob, const int mode)
-{
- Mesh *mesh = ob->data;
- SculptSession *ss = ob->sculpt;
- 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(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .calc_vert_normal = true,
- }));
- BMIter iter;
- BMFace *f;
-
- const int cd_fmaps_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
-
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (mode == SCULPT_FACE_SETS_FROM_MATERIALS) {
- ss->face_sets[BM_elem_index_get(f)] = (int)(f->mat_nr + 1);
- }
- else if (mode == SCULPT_FACE_SETS_FROM_FACE_MAPS) {
- if (cd_fmaps_offset != -1) {
- ss->face_sets[BM_elem_index_get(f)] = BM_ELEM_CD_GET_INT(f, cd_fmaps_offset) + 2;
- }
- else {
- ss->face_sets[BM_elem_index_get(f)] = 1;
- }
- }
- }
- BM_mesh_free(bm);
-}
-
-static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- 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;
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode);
-
- if (!nodes) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_begin(ob, op);
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- const float threshold = RNA_float_get(op->ptr, "threshold");
-
- Mesh *mesh = ob->data;
- ss->face_sets = BKE_sculpt_face_sets_ensure(mesh);
-
- switch (mode) {
- case SCULPT_FACE_SETS_FROM_LOOSE_PARTS:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_loose_parts_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_MATERIALS:
- sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_MATERIALS);
- break;
- case SCULPT_FACE_SETS_FROM_NORMALS:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_normals_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_UV_SEAMS:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_uv_seams_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_CREASES:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_crease_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_SHARP_EDGES:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_sharp_edges_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES:
- sculpt_face_sets_init_flood_fill(
- ob, sculpt_face_sets_init_face_set_boundary_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_FACE_MAPS:
- sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS);
- break;
- }
-
- SCULPT_undo_push_end(ob);
-
- /* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
- SCULPT_visibility_sync_all_from_faces(ob);
-
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_update_visibility(nodes[i]);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
-
- MEM_SAFE_FREE(nodes);
-
- if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
- BKE_mesh_flush_hidden_from_verts(ob->data);
- }
-
- SCULPT_tag_update_overlays(C);
-
- return OPERATOR_FINISHED;
-}
-
-void SCULPT_OT_face_sets_init(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Initialize Face Sets";
- ot->idname = "SCULPT_OT_face_sets_init";
- ot->description = "Set the value for all faces sets on the mesh";
-
- /* api callbacks */
- ot->exec = sculpt_face_set_init_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(
- ot->srna, "mode", prop_sculpt_face_sets_init_types, SCULPT_FACE_SET_MASKED, "Mode", "");
- RNA_def_float(
- ot->srna,
- "threshold",
- 0.5f,
- 0.0f,
- 1.0f,
- "Threshold",
- "Minimum value to consider a certain attribute a boundary when creating the Face Sets",
- 0.0f,
- 1.0f);
-}
-
-typedef enum eSculptFaceGroupVisibilityModes {
- SCULPT_FACE_SET_VISIBILITY_TOGGLE = 0,
- SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE = 1,
- SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE = 2,
- SCULPT_FACE_SET_VISIBILITY_INVERT = 3,
- SCULPT_FACE_SET_VISIBILITY_SHOW_ALL = 4,
-} eSculptFaceGroupVisibilityModes;
-
-static EnumPropertyItem prop_sculpt_face_sets_change_visibility_types[] = {
- {
- SCULPT_FACE_SET_VISIBILITY_TOGGLE,
- "TOGGLE",
- 0,
- "Toggle Visibility",
- "Hide all Face Sets except for the active one",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE,
- "SHOW_ACTIVE",
- 0,
- "Show Active Face Set",
- "Show Active Face Set",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE,
- "HIDE_ACTIVE",
- 0,
- "Hide Active Face Sets",
- "Hide Active Face Sets",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_INVERT,
- "INVERT",
- 0,
- "Invert Face Set Visibility",
- "Invert Face Set Visibility",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_SHOW_ALL,
- "SHOW_ALL",
- 0,
- "Show All Face Sets",
- "Show All Face Sets",
- },
- {0, nullptr, 0, nullptr, nullptr},
-};
-
-static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- /* Dyntopo not supported. */
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- return OPERATOR_CANCELLED;
- }
-
- if (!ss->face_sets) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = BKE_object_get_original_mesh(ob);
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
- const int tot_vert = SCULPT_vertex_count_get(ss);
- const int mode = RNA_enum_get(op->ptr, "mode");
- const int active_face_set = SCULPT_active_face_set_get(ss);
-
- SCULPT_undo_push_begin(ob, op);
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
-
- BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode);
-
- if (totnode == 0) {
- MEM_SAFE_FREE(nodes);
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_TOGGLE) {
- bool hidden_vertex = false;
-
- /* This can fail with regular meshes with non-manifold geometry as the visibility state can't
- * be synced from face sets to non-manifold vertices. */
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- for (int i = 0; i < tot_vert; i++) {
- PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
-
- if (!SCULPT_vertex_visible_get(ss, vertex)) {
- hidden_vertex = true;
- break;
- }
- }
- }
-
- if (ss->hide_poly) {
- for (int i = 0; i < ss->totfaces; i++) {
- if (ss->hide_poly[i]) {
- hidden_vertex = true;
- break;
- }
- }
- }
-
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
-
- if (hidden_vertex) {
- SCULPT_face_visibility_all_set(ss, true);
- }
- else {
- SCULPT_face_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
- }
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ALL) {
- /* As an optimization, free the hide attribute when making all geometry visible. This allows
- * reduced memory usage without manually clearing it later, and allows sculpt operations to
- * avoid checking element's hide status. */
- CustomData_free_layer_named(&mesh->pdata, ".hide_poly", mesh->totpoly);
- ss->hide_poly = nullptr;
- BKE_pbvh_update_hide_attributes_from_mesh(pbvh);
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) {
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- SCULPT_face_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) {
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- SCULPT_face_set_visibility_set(ss, active_face_set, false);
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) {
- ss->hide_poly = BKE_sculpt_hide_poly_ensure(mesh);
- SCULPT_face_visibility_all_invert(ss);
- }
-
- /* For modes that use the cursor active vertex, update the rotation origin for viewport
- * navigation. */
- if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) {
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- float location[3];
- copy_v3_v3(location, SCULPT_active_vertex_co_get(ss));
- mul_m4_v3(ob->obmat, location);
- copy_v3_v3(ups->average_stroke_accum, location);
- ups->average_stroke_counter = 1;
- ups->last_stroke_valid = true;
- }
-
- /* Sync face sets visibility and vertex visibility. */
- SCULPT_visibility_sync_all_from_faces(ob);
-
- SCULPT_undo_push_end(ob);
-
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_update_visibility(nodes[i]);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
-
- MEM_SAFE_FREE(nodes);
-
- SCULPT_tag_update_overlays(C);
-
- return OPERATOR_FINISHED;
-}
-
-static int sculpt_face_sets_change_visibility_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *event)
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- /* Update the active vertex and Face Set using the cursor position to avoid relying on the paint
- * cursor updates. */
- SculptCursorGeometryInfo sgi;
- const float mval_fl[2] = {UNPACK2(event->mval)};
- SCULPT_vertex_random_access_ensure(ss);
- SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
-
- return sculpt_face_sets_change_visibility_exec(C, op);
-}
-
-void SCULPT_OT_face_sets_change_visibility(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Face Sets Visibility";
- ot->idname = "SCULPT_OT_face_set_change_visibility";
- ot->description = "Change the visibility of the Face Sets of the sculpt";
-
- /* Api callbacks. */
- ot->exec = sculpt_face_sets_change_visibility_exec;
- ot->invoke = sculpt_face_sets_change_visibility_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna,
- "mode",
- prop_sculpt_face_sets_change_visibility_types,
- SCULPT_FACE_SET_VISIBILITY_TOGGLE,
- "Mode",
- "");
-}
-
-static int sculpt_face_sets_randomize_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
-
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- /* Dyntopo not supported. */
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- return OPERATOR_CANCELLED;
- }
-
- if (!ss->face_sets) {
- return OPERATOR_CANCELLED;
- }
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
- Mesh *mesh = ob->data;
-
- mesh->face_sets_color_seed += 1;
- if (ss->face_sets) {
- const int random_index = clamp_i(ss->totfaces * BLI_hash_int_01(mesh->face_sets_color_seed),
- 0,
- max_ii(0, ss->totfaces - 1));
- mesh->face_sets_color_default = ss->face_sets[random_index];
- }
- BKE_pbvh_face_sets_color_set(pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default);
-
- BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode);
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_redraw(nodes[i]);
- }
-
- MEM_SAFE_FREE(nodes);
-
- SCULPT_tag_update_overlays(C);
-
- return OPERATOR_FINISHED;
-}
-
-void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Randomize Face Sets Colors";
- ot->idname = "SCULPT_OT_face_sets_randomize_colors";
- ot->description = "Generates a new set of random colors to render the Face Sets in the viewport";
-
- /* Api callbacks. */
- ot->exec = sculpt_face_sets_randomize_colors_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-typedef enum eSculptFaceSetEditMode {
- SCULPT_FACE_SET_EDIT_GROW = 0,
- SCULPT_FACE_SET_EDIT_SHRINK = 1,
- SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY = 2,
- SCULPT_FACE_SET_EDIT_FAIR_POSITIONS = 3,
- SCULPT_FACE_SET_EDIT_FAIR_TANGENCY = 4,
-} eSculptFaceSetEditMode;
-
-static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = {
- {
- SCULPT_FACE_SET_EDIT_GROW,
- "GROW",
- 0,
- "Grow Face Set",
- "Grows the Face Sets boundary by one face based on mesh topology",
- },
- {
- SCULPT_FACE_SET_EDIT_SHRINK,
- "SHRINK",
- 0,
- "Shrink Face Set",
- "Shrinks the Face Sets boundary by one face based on mesh topology",
- },
- {
- SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY,
- "DELETE_GEOMETRY",
- 0,
- "Delete Geometry",
- "Deletes the faces that are assigned to the Face Set",
- },
- {
- SCULPT_FACE_SET_EDIT_FAIR_POSITIONS,
- "FAIR_POSITIONS",
- 0,
- "Fair Positions",
- "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
- "vertex positions",
- },
- {
- SCULPT_FACE_SET_EDIT_FAIR_TANGENCY,
- "FAIR_TANGENCY",
- 0,
- "Fair Tangency",
- "Creates a smooth as possible geometry patch from the Face Set minimizing changes in "
- "vertex tangents",
- },
- {0, nullptr, 0, nullptr, nullptr},
-};
-
-static void sculpt_face_set_grow(Object *ob,
- SculptSession *ss,
- const int *prev_face_sets,
- const int active_face_set_id,
- const bool modify_hidden)
-{
- Mesh *mesh = BKE_mesh_from_object(ob);
- const MPoly *polys = BKE_mesh_polys(mesh);
- const MLoop *loops = BKE_mesh_loops(mesh);
-
- for (int p = 0; p < mesh->totpoly; p++) {
- if (!modify_hidden && prev_face_sets[p] <= 0) {
- continue;
- }
- const MPoly *c_poly = &polys[p];
- for (int l = 0; l < c_poly->totloop; l++) {
- const MLoop *c_loop = &loops[c_poly->loopstart + l];
- const MeshElemMap *vert_map = &ss->pmap[c_loop->v];
- for (int i = 0; i < vert_map->count; i++) {
- const int neighbor_face_index = vert_map->indices[i];
- if (neighbor_face_index == p) {
- continue;
- }
- if (abs(prev_face_sets[neighbor_face_index]) == active_face_set_id) {
- ss->face_sets[p] = active_face_set_id;
- }
- }
- }
- }
-}
-
-static void sculpt_face_set_shrink(Object *ob,
- SculptSession *ss,
- const int *prev_face_sets,
- const int active_face_set_id,
- const bool modify_hidden)
-{
- Mesh *mesh = BKE_mesh_from_object(ob);
- const MPoly *polys = BKE_mesh_polys(mesh);
- const MLoop *loops = BKE_mesh_loops(mesh);
- for (int p = 0; p < mesh->totpoly; p++) {
- if (!modify_hidden && prev_face_sets[p] <= 0) {
- continue;
- }
- if (abs(prev_face_sets[p]) == active_face_set_id) {
- const MPoly *c_poly = &polys[p];
- for (int l = 0; l < c_poly->totloop; l++) {
- const MLoop *c_loop = &loops[c_poly->loopstart + l];
- const MeshElemMap *vert_map = &ss->pmap[c_loop->v];
- for (int i = 0; i < vert_map->count; i++) {
- const int neighbor_face_index = vert_map->indices[i];
- if (neighbor_face_index == p) {
- continue;
- }
- if (abs(prev_face_sets[neighbor_face_index]) != active_face_set_id) {
- ss->face_sets[p] = prev_face_sets[neighbor_face_index];
- }
- }
- }
- }
- }
-}
-
-static bool check_single_face_set(SculptSession *ss, int *face_sets, const bool check_visible_only)
-{
- if (face_sets == nullptr) {
- return true;
- }
- int first_face_set = SCULPT_FACE_SET_NONE;
- if (check_visible_only) {
- for (int f = 0; f < ss->totfaces; f++) {
- if (ss->hide_poly && ss->hide_poly[f]) {
- continue;
- }
- first_face_set = face_sets[f];
- break;
- }
- }
- else {
- first_face_set = face_sets[0];
- }
-
- if (first_face_set == SCULPT_FACE_SET_NONE) {
- return true;
- }
-
- for (int f = 0; f < ss->totfaces; f++) {
- if (check_visible_only && ss->hide_poly && ss->hide_poly[f]) {
- continue;
- }
- if (face_sets[f] != first_face_set) {
- return false;
- }
- }
- return true;
-}
-
-static void sculpt_face_set_delete_geometry(Object *ob,
- SculptSession *ss,
- const int active_face_set_id,
- const bool modify_hidden)
-{
-
- Mesh *mesh = ob->data;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- BMesh *bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = true,
- }));
-
- BM_mesh_bm_from_me(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .calc_vert_normal = true,
- }));
-
- BM_mesh_elem_table_init(bm, BM_FACE);
- BM_mesh_elem_table_ensure(bm, BM_FACE);
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- const int face_index = BM_elem_index_get(f);
- if (!modify_hidden && ss->hide_poly && ss->hide_poly[face_index]) {
- continue;
- }
- BM_elem_flag_set(f, BM_ELEM_TAG, ss->face_sets[face_index] == active_face_set_id);
- }
- BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
- BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
-
- BM_mesh_bm_to_me(nullptr,
- bm,
- ob->data,
- (&(struct BMeshToMeshParams){
- .calc_object_remap = false,
- }));
-
- BM_mesh_free(bm);
-}
-
-static void sculpt_face_set_edit_fair_face_set(Object *ob,
- const int active_face_set_id,
- const int fair_order)
-{
- SculptSession *ss = ob->sculpt;
- const int totvert = SCULPT_vertex_count_get(ss);
-
- Mesh *mesh = ob->data;
- bool *fair_verts = MEM_malloc_arrayN(totvert, sizeof(bool), "fair vertices");
-
- SCULPT_boundary_info_ensure(ob);
-
- for (int i = 0; i < totvert; i++) {
- PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i);
-
- fair_verts[i] = !SCULPT_vertex_is_boundary(ss, vertex) &&
- SCULPT_vertex_has_face_set(ss, vertex, active_face_set_id) &&
- SCULPT_vertex_has_unique_face_set(ss, vertex);
- }
-
- MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss);
- BKE_mesh_prefair_and_fair_verts(mesh, mvert, fair_verts, fair_order);
- MEM_freeN(fair_verts);
-}
-
-static void sculpt_face_set_apply_edit(Object *ob,
- const int active_face_set_id,
- const int mode,
- const bool modify_hidden)
-{
- SculptSession *ss = ob->sculpt;
-
- switch (mode) {
- case SCULPT_FACE_SET_EDIT_GROW: {
- int *prev_face_sets = MEM_dupallocN(ss->face_sets);
- sculpt_face_set_grow(ob, ss, prev_face_sets, active_face_set_id, modify_hidden);
- MEM_SAFE_FREE(prev_face_sets);
- break;
- }
- case SCULPT_FACE_SET_EDIT_SHRINK: {
- int *prev_face_sets = MEM_dupallocN(ss->face_sets);
- sculpt_face_set_shrink(ob, ss, prev_face_sets, active_face_set_id, modify_hidden);
- MEM_SAFE_FREE(prev_face_sets);
- break;
- }
- case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY:
- sculpt_face_set_delete_geometry(ob, ss, active_face_set_id, modify_hidden);
- break;
- case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS:
- sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_POSITION);
- break;
- case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY:
- sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_TANGENCY);
- break;
- }
-}
-
-static bool sculpt_face_set_edit_is_operation_valid(SculptSession *ss,
- const eSculptFaceSetEditMode mode,
- const bool modify_hidden)
-{
- if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- /* Dyntopo is not supported. */
- return false;
- }
-
- if (mode == SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY) {
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- /* Modification of base mesh geometry requires special remapping of multires displacement,
- * which does not happen here.
- * Disable delete operation. It can be supported in the future by doing similar displacement
- * data remapping as what happens in the mesh edit mode. */
- return false;
- }
- if (check_single_face_set(ss, ss->face_sets, !modify_hidden)) {
- /* Cancel the operator if the mesh only contains one Face Set to avoid deleting the
- * entire object. */
- return false;
- }
- }
-
- if (ELEM(mode, SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, SCULPT_FACE_SET_EDIT_FAIR_TANGENCY)) {
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- /* TODO: Multires topology representation using grids and duplicates can't be used directly
- * by the fair algorithm. Multires topology needs to be exposed in a different way or
- * converted to a mesh for this operation. */
- return false;
- }
- }
-
- return true;
-}
-
-static void sculpt_face_set_edit_modify_geometry(bContext *C,
- Object *ob,
- const int active_face_set,
- const eSculptFaceSetEditMode mode,
- const bool modify_hidden,
- wmOperator *op)
-{
- ED_sculpt_undo_geometry_begin(ob, op);
- sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden);
- ED_sculpt_undo_geometry_end(ob);
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-}
-
-static void face_set_edit_do_post_visibility_updates(Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ss->pbvh;
-
- /* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
- SCULPT_visibility_sync_all_from_faces(ob);
-
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_update_visibility(nodes[i]);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
-
- if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
- BKE_mesh_flush_hidden_from_verts(ob->data);
- }
-}
-
-static void sculpt_face_set_edit_modify_face_sets(Object *ob,
- const int active_face_set,
- const eSculptFaceSetEditMode mode,
- const bool modify_hidden,
- wmOperator *op)
-{
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode);
-
- if (!nodes) {
- return;
- }
- SCULPT_undo_push_begin(ob, op);
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
- sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, modify_hidden);
- SCULPT_undo_push_end(ob);
- face_set_edit_do_post_visibility_updates(ob, nodes, totnode);
- MEM_freeN(nodes);
-}
-
-static void sculpt_face_set_edit_modify_coordinates(bContext *C,
- Object *ob,
- const int active_face_set,
- const eSculptFaceSetEditMode mode,
- wmOperator *op)
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ss->pbvh;
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode);
- SCULPT_undo_push_begin(ob, op);
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_update(nodes[i]);
- SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COORDS);
- }
- sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, false);
-
- if (ss->deform_modifiers_active || ss->shapekey_active) {
- SCULPT_flush_stroke_deform(sd, ob, true);
- }
- SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
- SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
- SCULPT_undo_push_end(ob);
- MEM_freeN(nodes);
-}
-
-static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- 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");
- const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden");
-
- if (!sculpt_face_set_edit_is_operation_valid(ss, mode, modify_hidden)) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
-
- /* Update the current active Face Set and Vertex as the operator can be used directly from the
- * tool without brush cursor. */
- SculptCursorGeometryInfo sgi;
- const float mval_fl[2] = {UNPACK2(event->mval)};
- if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
- /* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */
- return OPERATOR_CANCELLED;
- }
- const int active_face_set = SCULPT_active_face_set_get(ss);
-
- switch (mode) {
- case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY:
- sculpt_face_set_edit_modify_geometry(C, ob, active_face_set, mode, modify_hidden, op);
- break;
- case SCULPT_FACE_SET_EDIT_GROW:
- case SCULPT_FACE_SET_EDIT_SHRINK:
- sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden, op);
- break;
- case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS:
- case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY:
- sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode, op);
- break;
- }
-
- SCULPT_tag_update_overlays(C);
-
- return OPERATOR_FINISHED;
-}
-
-void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Edit Face Set";
- ot->idname = "SCULPT_OT_face_set_edit";
- ot->description = "Edits the current active Face Set";
-
- /* Api callbacks. */
- ot->invoke = sculpt_face_set_edit_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(
- ot->srna, "mode", prop_sculpt_face_sets_edit_types, SCULPT_FACE_SET_EDIT_GROW, "Mode", "");
- ot->prop = RNA_def_boolean(ot->srna,
- "modify_hidden",
- true,
- "Modify Hidden",
- "Apply the edit operation to hidden Face Sets");
-}