[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