[Bf-blender-cvs] [b1baebd0224] master: Cleanup: abstract sculpt floodfill code
Brecht Van Lommel
noreply at git.blender.org
Tue Oct 1 16:15:31 CEST 2019
Commit: b1baebd0224a806082ffec99fd6db0667e0ef49d
Author: Brecht Van Lommel
Date: Mon Sep 30 20:39:04 2019 +0200
Branches: master
https://developer.blender.org/rBb1baebd0224a806082ffec99fd6db0667e0ef49d
Cleanup: abstract sculpt floodfill code
===================================================================
M source/blender/editors/sculpt_paint/sculpt.c
===================================================================
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index b5b653c4b62..075efd19c08 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -27,13 +27,11 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_dial_2d.h"
-#include "BLI_hash.h"
#include "BLI_gsqueue.h"
-#include "BLI_stack.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.h"
#include "BLI_task.h"
-#include "BLI_stack.h"
#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
#include "BLT_translation.h"
@@ -413,7 +411,7 @@ static bool is_symmetry_iteration_valid(char i, char symm)
}
/* Checks if a vertex is inside the brush radius from any of its mirrored axis */
-static bool sculpt_is_vertex_inside_brush_radius_symm(float vertex[3],
+static bool sculpt_is_vertex_inside_brush_radius_symm(const float vertex[3],
const float br_co[3],
float radius,
char symm)
@@ -430,6 +428,101 @@ static bool sculpt_is_vertex_inside_brush_radius_symm(float vertex[3],
return false;
}
+/* Sculpt Flood Fill API
+ *
+ * Iterate over connected vertices, starting from one or more initial vertices. */
+
+typedef struct SculptFloodFill {
+ GSQueue *queue;
+ char *visited_vertices;
+} SculptFloodFill;
+
+typedef struct SculptFloodFillIterator {
+ int v;
+ int it;
+ float edge_factor;
+} SculptFloodFillIterator;
+
+static void sculpt_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
+{
+ int vertex_count = sculpt_vertex_count_get(ss);
+ sculpt_vertex_random_access_init(ss);
+
+ flood->queue = BLI_gsqueue_new(sizeof(SculptFloodFillIterator));
+ flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+}
+
+static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index)
+{
+ SculptFloodFillIterator mevit;
+ mevit.v = index;
+ mevit.it = 0;
+ mevit.edge_factor = 1.0f;
+ BLI_gsqueue_push(flood->queue, &mevit);
+}
+
+static void sculpt_floodfill_add_active(
+ Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, float radius)
+{
+ /* Add active vertex and symmetric vertices to the queue. */
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ for (char i = 0; i <= symm; ++i) {
+ if (is_symmetry_iteration_valid(i, symm)) {
+ int v = -1;
+ if (i == 0) {
+ v = sculpt_active_vertex_get(ss);
+ }
+ else if (radius > 0.0f) {
+ float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
+ float location[3];
+ flip_v3_v3(location, sculpt_active_vertex_co_get(ss), i);
+ v = sculpt_nearest_vertex_get(sd, ob, location, radius_squared, false);
+ }
+ if (v != -1) {
+ sculpt_floodfill_add_initial(flood, v);
+ }
+ }
+ }
+}
+
+static void sculpt_floodfill_execute(SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss,
+ const SculptFloodFillIterator *from,
+ SculptFloodFillIterator *to,
+ void *userdata),
+ void *userdata)
+{
+ while (!BLI_gsqueue_is_empty(flood->queue)) {
+ SculptFloodFillIterator from;
+ BLI_gsqueue_pop(flood->queue, &from);
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_neighbors_iter_begin(ss, from.v, ni)
+ {
+ if (flood->visited_vertices[ni.index] == 0) {
+ flood->visited_vertices[ni.index] = 1;
+
+ SculptFloodFillIterator to;
+ to.v = ni.index;
+ to.it = from.it + 1;
+ to.edge_factor = 0.0f;
+
+ if (func(ss, &from, &to, userdata)) {
+ BLI_gsqueue_push(flood->queue, &to);
+ }
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ }
+}
+
+static void sculpt_floodfill_free(SculptFloodFill *flood)
+{
+ MEM_SAFE_FREE(flood->visited_vertices);
+ BLI_gsqueue_free(flood->queue);
+ flood->queue = NULL;
+}
+
/** \name Tool Capabilities
*
* Avoid duplicate checks, internal logic only,
@@ -1111,15 +1204,29 @@ static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
return false;
}
-typedef struct VertexTopologyIterator {
- int v;
- int it;
- float edge_factor;
-} VertexTopologyIterator;
+typedef struct AutomaskFloodFillData {
+ float *automask_factor;
+ float radius;
+ bool use_radius;
+ float location[3];
+ char symm;
+} AutomaskFloodFillData;
-static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+static bool automask_floodfill_cb(SculptSession *ss,
+ const SculptFloodFillIterator *UNUSED(from),
+ SculptFloodFillIterator *to,
+ void *userdata)
{
+ AutomaskFloodFillData *data = userdata;
+
+ data->automask_factor[to->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);
@@ -1132,63 +1239,21 @@ static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *au
return NULL;
}
- bool *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(bool),
- "visited vertices");
-
- BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator),
- "not vertices stack");
-
- VertexTopologyIterator mevit;
+ /* 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);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, ss->cache->radius);
- /* Add active vertex and symmetric vertices to the stack. */
- float location[3];
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- for (char i = 0; i <= symm; ++i) {
- if (is_symmetry_iteration_valid(i, symm)) {
- flip_v3_v3(location, sculpt_active_vertex_co_get(ss), i);
- if (i == 0) {
- mevit.v = sculpt_active_vertex_get(ss);
- }
- else {
- mevit.v = sculpt_nearest_vertex_get(
- sd, ob, location, ss->cache->radius * ss->cache->radius, false);
- }
- if (mevit.v != -1) {
- mevit.it = 1;
- BLI_stack_push(not_visited_vertices, &mevit);
- }
- }
- }
-
- copy_v3_v3(location, sculpt_active_vertex_co_get(ss));
- bool use_radius = sculpt_automasking_is_constrained_by_radius(brush);
-
- /* Flood fill automask to connected vertices. Limited to vertices inside the brush radius if the
- * tool requires it */
- while (!BLI_stack_is_empty(not_visited_vertices)) {
- VertexTopologyIterator c_mevit;
- BLI_stack_pop(not_visited_vertices, &c_mevit);
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
- {
- if (!visited_vertices[(int)ni.index]) {
- VertexTopologyIterator new_entry;
- new_entry.v = ni.index;
- automask_factor[new_entry.v] = 1.0f;
- visited_vertices[(int)ni.index] = true;
- if (!use_radius ||
- sculpt_is_vertex_inside_brush_radius_symm(
- sculpt_vertex_co_get(ss, new_entry.v), location, ss->cache->radius, symm)) {
- BLI_stack_push(not_visited_vertices, &new_entry);
- }
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- }
-
- BLI_stack_free(not_visited_vertices);
-
- MEM_freeN(visited_vertices);
+ AutomaskFloodFillData fdata = {
+ .automask_factor = automask_factor,
+ .radius = ss->cache->radius,
+ .use_radius = sculpt_automasking_is_constrained_by_radius(brush),
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ };
+ 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;
}
@@ -3674,7 +3739,7 @@ static void sculpt_pose_grow_pose_factor(
MEM_SAFE_FREE(nodes);
}
-static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3],
+static bool sculpt_pose_brush_is_vertex_inside_brush_radius(const float vertex[3],
const float br_co[3],
float radius,
char symm)
@@ -3695,6 +3760,40 @@ static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3],
*
* r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't
* be calculated. */
+typedef struct PoseFloodFillData {
+ float pose_initial_co[3];
+ float radius;
+ int symm;
+
+ float *pose_factor;
+ float pose_origin[3];
+ int tot_co;
+} PoseFloodFillData;
+
+static bool pose_floodfill_cb(SculptSession *ss,
+ const SculptFloodFillIterator *UNUSED(from),
+ SculptFloodFillIterator *to,
+ void *userdata)
+{
+ PoseFloodFillData *data = userdata;
+
+ if (data->pose_factor) {
+ data->pose_factor[to->v] = 1.0f;
+ }
+
+ const float *co = sculpt_vertex_co_get(ss, to->v);
+ if (sculpt_pose_brush_is_vertex_inside_brush_radius(
+ co, data->pose_initial_co, data->radius, data->symm)) {
+ return true;
+ }
+ else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) {
+ add_v3_v3(data->pose_origin, co);
+ data->tot_co++;
+ }
+
+ return false;
+}
+
void sculpt_pose_calc_pose_data(Sculpt *sd,
Object *ob,
Sculp
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list