From ca29376e002c5427513ee2ed6633dd82811ac1bd Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Wed, 8 Jun 2022 03:32:57 -0700 Subject: Cleanup: Move sculpt_automasking.c to c++ --- source/blender/editors/sculpt_paint/CMakeLists.txt | 2 +- .../editors/sculpt_paint/sculpt_automasking.c | 367 -------------------- .../editors/sculpt_paint/sculpt_automasking.cc | 372 +++++++++++++++++++++ source/tools | 2 +- 4 files changed, 374 insertions(+), 369 deletions(-) delete mode 100644 source/blender/editors/sculpt_paint/sculpt_automasking.c create mode 100644 source/blender/editors/sculpt_paint/sculpt_automasking.cc (limited to 'source') diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 9a9efc9e6cf..b1b52d16c6d 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -58,7 +58,7 @@ set(SRC paint_vertex_weight_ops.c paint_vertex_weight_utils.c sculpt.c - sculpt_automasking.c + sculpt_automasking.cc sculpt_boundary.c sculpt_brush_types.c sculpt_cloth.c diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c deleted file mode 100644 index d7a2a18504c..00000000000 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.c +++ /dev/null @@ -1,367 +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_mesh_types.h" -#include "DNA_meshdata_types.h" - -#include "BKE_brush.h" -#include "BKE_context.h" -#include "BKE_mesh.h" -#include "BKE_mesh_mapping.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 "paint_intern.h" -#include "sculpt_intern.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "bmesh.h" - -#include -#include - -AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss) -{ - if (ss->cache) { - return ss->cache->automasking; - } - if (ss->filter_cache) { - return ss->filter_cache->automasking; - } - return NULL; -} - -bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd, - const Brush *br, - const eAutomasking_flag mode) -{ - if (br) { - return br->automasking_flags & mode || sd->automasking_flags & mode; - } - return sd->automasking_flags & mode; -} - -bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br) -{ - if (br && SCULPT_stroke_is_dynamic_topology(ss, br)) { - return false; - } - if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_TOPOLOGY)) { - return true; - } - if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_FACE_SETS)) { - return true; - } - if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) { - return true; - } - if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) { - return true; - } - return false; -} - -static int sculpt_automasking_mode_effective_bits(const Sculpt *sculpt, const Brush *brush) -{ - if (brush) { - return sculpt->automasking_flags | brush->automasking_flags; - } - return sculpt->automasking_flags; -} - -static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush *brush) -{ - - const int automasking_flags = sculpt_automasking_mode_effective_bits(sd, brush); - if (automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) { - return true; - } - if (automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) { - return brush && brush->automasking_boundary_edges_propagation_steps != 1; - } - if (automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS) { - return brush && brush->automasking_boundary_edges_propagation_steps != 1; - } - return false; -} - -float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, int vert) -{ - if (!automasking) { - return 1.0f; - } - /* If the cache is initialized with valid info, use the cache. This is used when the - * automasking information can't be computed in real time per vertex and needs to be - * initialized for the whole mesh when the stroke starts. */ - if (automasking->factor) { - return automasking->factor[vert]; - } - - if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) { - if (!SCULPT_vertex_has_face_set(ss, vert, automasking->settings.initial_face_set)) { - return 0.0f; - } - } - - if (automasking->settings.flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) { - if (SCULPT_vertex_is_boundary(ss, vert)) { - return 0.0f; - } - } - - if (automasking->settings.flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS) { - if (!SCULPT_vertex_has_unique_face_set(ss, vert)) { - return 0.0f; - } - } - - return 1.0f; -} - -void SCULPT_automasking_cache_free(AutomaskingCache *automasking) -{ - if (!automasking) { - return; - } - - MEM_SAFE_FREE(automasking->factor); - MEM_SAFE_FREE(automasking); -} - -static bool sculpt_automasking_is_constrained_by_radius(Brush *br) -{ - /* 2D falloff is not constrained by radius. */ - if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - return false; - } - - if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)) { - return true; - } - return false; -} - -typedef struct AutomaskFloodFillData { - float *automask_factor; - float radius; - bool use_radius; - float location[3]; - char symm; -} AutomaskFloodFillData; - -static bool automask_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata) -{ - AutomaskFloodFillData *data = userdata; - - data->automask_factor[to_v] = 1.0f; - data->automask_factor[from_v] = 1.0f; - return (!data->use_radius || - SCULPT_is_vertex_inside_brush_radius_symm( - SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm)); -} - -static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { - BLI_assert_msg(0, "Topology masking: pmap missing"); - return NULL; - } - - const int totvert = SCULPT_vertex_count_get(ss); - for (int i = 0; i < totvert; i++) { - automask_factor[i] = 0.0f; - } - - /* Flood fill automask to connected vertices. Limited to vertices inside - * the brush radius if the tool requires it. */ - SculptFloodFill flood; - SCULPT_floodfill_init(ss, &flood); - const float radius = ss->cache ? ss->cache->radius : FLT_MAX; - SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius); - - AutomaskFloodFillData fdata = { - .automask_factor = automask_factor, - .radius = radius, - .use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush), - .symm = SCULPT_mesh_symmetry_xyz_get(ob), - }; - copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss)); - SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata); - SCULPT_floodfill_free(&flood); - - return automask_factor; -} - -static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - if (!SCULPT_is_automasking_enabled(sd, ss, brush)) { - return NULL; - } - - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { - BLI_assert_msg(0, "Face Sets automasking: pmap missing"); - return NULL; - } - - int tot_vert = SCULPT_vertex_count_get(ss); - int active_face_set = SCULPT_active_face_set_get(ss); - for (int i = 0; i < tot_vert; i++) { - if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) { - automask_factor[i] *= 0.0f; - } - } - - return automask_factor; -} - -#define EDGE_DISTANCE_INF -1 - -float *SCULPT_boundary_automasking_init(Object *ob, - eBoundaryAutomaskMode mode, - int propagation_steps, - float *automask_factor) -{ - SculptSession *ss = ob->sculpt; - - if (!ss->pmap) { - BLI_assert_msg(0, "Boundary Edges masking: pmap missing"); - return NULL; - } - - const int totvert = SCULPT_vertex_count_get(ss); - int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor"); - - for (int i = 0; i < totvert; i++) { - edge_distance[i] = EDGE_DISTANCE_INF; - switch (mode) { - case AUTOMASK_INIT_BOUNDARY_EDGES: - if (SCULPT_vertex_is_boundary(ss, i)) { - edge_distance[i] = 0; - } - break; - case AUTOMASK_INIT_BOUNDARY_FACE_SETS: - if (!SCULPT_vertex_has_unique_face_set(ss, i)) { - edge_distance[i] = 0; - } - break; - } - } - - for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) { - for (int i = 0; i < totvert; i++) { - if (edge_distance[i] != EDGE_DISTANCE_INF) { - continue; - } - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { - if (edge_distance[ni.index] == propagation_it) { - edge_distance[i] = propagation_it + 1; - } - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - } - } - - for (int i = 0; i < totvert; i++) { - if (edge_distance[i] == EDGE_DISTANCE_INF) { - continue; - } - const float p = 1.0f - ((float)edge_distance[i] / (float)propagation_steps); - const float edge_boundary_automask = pow2f(p); - automask_factor[i] *= (1.0f - edge_boundary_automask); - } - - MEM_SAFE_FREE(edge_distance); - return automask_factor; -} - -static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automasking, - SculptSession *ss, - Sculpt *sd, - Brush *brush) -{ - automasking->settings.flags = sculpt_automasking_mode_effective_bits(sd, brush); - automasking->settings.initial_face_set = SCULPT_active_face_set_get(ss); -} - -AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob) -{ - SculptSession *ss = ob->sculpt; - const int totvert = SCULPT_vertex_count_get(ss); - - if (!SCULPT_is_automasking_enabled(sd, ss, brush)) { - return NULL; - } - - AutomaskingCache *automasking = MEM_callocN(sizeof(AutomaskingCache), "automasking cache"); - SCULPT_automasking_cache_settings_update(automasking, ss, sd, brush); - SCULPT_boundary_info_ensure(ob); - - if (!SCULPT_automasking_needs_factors_cache(sd, brush)) { - return automasking; - } - - automasking->factor = MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor"); - for (int i = 0; i < totvert; i++) { - automasking->factor[i] = 1.0f; - } - - const int boundary_propagation_steps = brush ? - brush->automasking_boundary_edges_propagation_steps : - 1; - - if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) { - SCULPT_vertex_random_access_ensure(ss); - SCULPT_topology_automasking_init(sd, ob, automasking->factor); - } - if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_FACE_SETS)) { - SCULPT_vertex_random_access_ensure(ss); - sculpt_face_sets_automasking_init(sd, ob, automasking->factor); - } - - if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) { - SCULPT_vertex_random_access_ensure(ss); - SCULPT_boundary_automasking_init( - ob, AUTOMASK_INIT_BOUNDARY_EDGES, boundary_propagation_steps, automasking->factor); - } - if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) { - SCULPT_vertex_random_access_ensure(ss); - SCULPT_boundary_automasking_init( - ob, AUTOMASK_INIT_BOUNDARY_FACE_SETS, boundary_propagation_steps, automasking->factor); - } - - return automasking; -} diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc new file mode 100644 index 00000000000..94417defe48 --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -0,0 +1,372 @@ +/* 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_index_range.hh" +#include "BLI_math.h" +#include "BLI_task.h" + +#include "DNA_brush_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_brush.h" +#include "BKE_context.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.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 "paint_intern.h" +#include "sculpt_intern.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "bmesh.h" + +#include +#include + +using blender::IndexRange; + +AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss) +{ + if (ss->cache) { + return ss->cache->automasking; + } + if (ss->filter_cache) { + return ss->filter_cache->automasking; + } + return NULL; +} + +bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd, + const Brush *br, + const eAutomasking_flag mode) +{ + if (br) { + return br->automasking_flags & mode || sd->automasking_flags & mode; + } + return sd->automasking_flags & mode; +} + +bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br) +{ + if (br && SCULPT_stroke_is_dynamic_topology(ss, br)) { + return false; + } + if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_TOPOLOGY)) { + return true; + } + if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_FACE_SETS)) { + return true; + } + if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) { + return true; + } + if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) { + return true; + } + return false; +} + +static int sculpt_automasking_mode_effective_bits(const Sculpt *sculpt, const Brush *brush) +{ + if (brush) { + return sculpt->automasking_flags | brush->automasking_flags; + } + return sculpt->automasking_flags; +} + +static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush *brush) +{ + + const int automasking_flags = sculpt_automasking_mode_effective_bits(sd, brush); + if (automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) { + return true; + } + if (automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) { + return brush && brush->automasking_boundary_edges_propagation_steps != 1; + } + if (automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS) { + return brush && brush->automasking_boundary_edges_propagation_steps != 1; + } + return false; +} + +float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, int vert) +{ + if (!automasking) { + return 1.0f; + } + /* If the cache is initialized with valid info, use the cache. This is used when the + * automasking information can't be computed in real time per vertex and needs to be + * initialized for the whole mesh when the stroke starts. */ + if (automasking->factor) { + return automasking->factor[vert]; + } + + if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) { + if (!SCULPT_vertex_has_face_set(ss, vert, automasking->settings.initial_face_set)) { + return 0.0f; + } + } + + if (automasking->settings.flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) { + if (SCULPT_vertex_is_boundary(ss, vert)) { + return 0.0f; + } + } + + if (automasking->settings.flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS) { + if (!SCULPT_vertex_has_unique_face_set(ss, vert)) { + return 0.0f; + } + } + + return 1.0f; +} + +void SCULPT_automasking_cache_free(AutomaskingCache *automasking) +{ + if (!automasking) { + return; + } + + MEM_SAFE_FREE(automasking->factor); + MEM_SAFE_FREE(automasking); +} + +static bool sculpt_automasking_is_constrained_by_radius(Brush *br) +{ + /* 2D falloff is not constrained by radius. */ + if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + return false; + } + + if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)) { + return true; + } + return false; +} + +typedef struct AutomaskFloodFillData { + float *automask_factor; + float radius; + bool use_radius; + float location[3]; + char symm; +} AutomaskFloodFillData; + +static bool automask_floodfill_cb( + SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata) +{ + AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata; + + data->automask_factor[to_v] = 1.0f; + data->automask_factor[from_v] = 1.0f; + return (!data->use_radius || + SCULPT_is_vertex_inside_brush_radius_symm( + SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm)); +} + +static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { + BLI_assert_msg(0, "Topology masking: pmap missing"); + return NULL; + } + + const int totvert = SCULPT_vertex_count_get(ss); + for (int i : IndexRange(totvert)) { + automask_factor[i] = 0.0f; + } + + /* Flood fill automask to connected vertices. Limited to vertices inside + * the brush radius if the tool requires it. */ + SculptFloodFill flood; + SCULPT_floodfill_init(ss, &flood); + const float radius = ss->cache ? ss->cache->radius : FLT_MAX; + SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius); + + AutomaskFloodFillData fdata = {0}; + + fdata.automask_factor = automask_factor; + fdata.radius = radius; + fdata.use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush); + fdata.symm = SCULPT_mesh_symmetry_xyz_get(ob); + + copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss)); + SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata); + SCULPT_floodfill_free(&flood); + + return automask_factor; +} + +static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *automask_factor) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + if (!SCULPT_is_automasking_enabled(sd, ss, brush)) { + return NULL; + } + + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { + BLI_assert_msg(0, "Face Sets automasking: pmap missing"); + return NULL; + } + + int tot_vert = SCULPT_vertex_count_get(ss); + int active_face_set = SCULPT_active_face_set_get(ss); + for (int i : IndexRange(tot_vert)) { + if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) { + automask_factor[i] *= 0.0f; + } + } + + return automask_factor; +} + +#define EDGE_DISTANCE_INF -1 + +float *SCULPT_boundary_automasking_init(Object *ob, + eBoundaryAutomaskMode mode, + int propagation_steps, + float *automask_factor) +{ + SculptSession *ss = ob->sculpt; + + if (!ss->pmap) { + BLI_assert_msg(0, "Boundary Edges masking: pmap missing"); + return NULL; + } + + const int totvert = SCULPT_vertex_count_get(ss); + int *edge_distance = (int *)MEM_callocN(sizeof(int) * totvert, "automask_factor"); + + for (int i : IndexRange(totvert)) { + edge_distance[i] = EDGE_DISTANCE_INF; + switch (mode) { + case AUTOMASK_INIT_BOUNDARY_EDGES: + if (SCULPT_vertex_is_boundary(ss, i)) { + edge_distance[i] = 0; + } + break; + case AUTOMASK_INIT_BOUNDARY_FACE_SETS: + if (!SCULPT_vertex_has_unique_face_set(ss, i)) { + edge_distance[i] = 0; + } + break; + } + } + + for (int propagation_it : IndexRange(propagation_steps)) { + for (int i : IndexRange(totvert)) { + if (edge_distance[i] != EDGE_DISTANCE_INF) { + continue; + } + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { + if (edge_distance[ni.index] == propagation_it) { + edge_distance[i] = propagation_it + 1; + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + } + } + + for (int i : IndexRange(totvert)) { + if (edge_distance[i] == EDGE_DISTANCE_INF) { + continue; + } + const float p = 1.0f - ((float)edge_distance[i] / (float)propagation_steps); + const float edge_boundary_automask = pow2f(p); + automask_factor[i] *= (1.0f - edge_boundary_automask); + } + + MEM_SAFE_FREE(edge_distance); + return automask_factor; +} + +static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automasking, + SculptSession *ss, + Sculpt *sd, + Brush *brush) +{ + automasking->settings.flags = sculpt_automasking_mode_effective_bits(sd, brush); + automasking->settings.initial_face_set = SCULPT_active_face_set_get(ss); +} + +AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + + if (!SCULPT_is_automasking_enabled(sd, ss, brush)) { + return NULL; + } + + AutomaskingCache *automasking = (AutomaskingCache *)MEM_callocN(sizeof(AutomaskingCache), + "automasking cache"); + SCULPT_automasking_cache_settings_update(automasking, ss, sd, brush); + SCULPT_boundary_info_ensure(ob); + + if (!SCULPT_automasking_needs_factors_cache(sd, brush)) { + return automasking; + } + + automasking->factor = (float *)MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor"); + for (int i : IndexRange(totvert)) { + automasking->factor[i] = 1.0f; + } + + const int boundary_propagation_steps = brush ? + brush->automasking_boundary_edges_propagation_steps : + 1; + + if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) { + SCULPT_vertex_random_access_ensure(ss); + SCULPT_topology_automasking_init(sd, ob, automasking->factor); + } + if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_FACE_SETS)) { + SCULPT_vertex_random_access_ensure(ss); + sculpt_face_sets_automasking_init(sd, ob, automasking->factor); + } + + if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) { + SCULPT_vertex_random_access_ensure(ss); + SCULPT_boundary_automasking_init( + ob, AUTOMASK_INIT_BOUNDARY_EDGES, boundary_propagation_steps, automasking->factor); + } + if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) { + SCULPT_vertex_random_access_ensure(ss); + SCULPT_boundary_automasking_init( + ob, AUTOMASK_INIT_BOUNDARY_FACE_SETS, boundary_propagation_steps, automasking->factor); + } + + return automasking; +} diff --git a/source/tools b/source/tools index ccc8fceb6bd..01b4c0e4a17 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit ccc8fceb6bd83ffbf6e5207247fb8f76fc47a5b6 +Subproject commit 01b4c0e4a172819414229445c314be34527bf412 -- cgit v1.2.3