[Bf-blender-cvs] [226f0c4fef7] master: Curves: initial brush implementations for curves sculpt mode

Jacques Lucke noreply at git.blender.org
Wed Feb 23 16:56:41 CET 2022


Commit: 226f0c4fef7e7792c16458cd3e456b169ddce918
Author: Jacques Lucke
Date:   Wed Feb 23 16:56:27 2022 +0100
Branches: master
https://developer.blender.org/rB226f0c4fef7e7792c16458cd3e456b169ddce918

Curves: initial brush implementations for curves sculpt mode

The main goal here is to add the boilerplate code to make it possible
to add the actual sculpt tools more easily. Both brush implementations
added by this patch are meant to be prototypes which will be removed
or refined in the coming weeks.

Ref T95773.

Differential Revision: https://developer.blender.org/D14180

===================================================================

M	source/blender/blenkernel/BKE_brush.h
A	source/blender/blenlib/BLI_index_mask_ops.hh
M	source/blender/blenlib/BLI_math_geom.h
M	source/blender/blenlib/CMakeLists.txt
M	source/blender/blenlib/intern/index_mask.cc
M	source/blender/blenlib/intern/math_geom.c
M	source/blender/editors/sculpt_paint/CMakeLists.txt
M	source/blender/editors/sculpt_paint/curves_sculpt_ops.cc

===================================================================

diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index c3a2aba18b5..4b84c0cfe23 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -8,13 +8,13 @@
  * General operations for brushes.
  */
 
+#include "DNA_color_types.h"
 #include "DNA_object_enums.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-enum eCurveMappingPreset;
 struct Brush;
 struct ImBuf;
 struct ImagePool;
diff --git a/source/blender/blenlib/BLI_index_mask_ops.hh b/source/blender/blenlib/BLI_index_mask_ops.hh
new file mode 100644
index 00000000000..48a1f27a2fa
--- /dev/null
+++ b/source/blender/blenlib/BLI_index_mask_ops.hh
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ *
+ * This is separate from `BLI_index_mask.hh` because it includes headers just `IndexMask` shouldn't
+ * depend on.
+ */
+
+#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_index_mask.hh"
+#include "BLI_task.hh"
+#include "BLI_vector.hh"
+
+namespace blender::index_mask_ops {
+
+namespace detail {
+IndexMask find_indices_based_on_predicate__merge(
+    IndexMask indices_to_check,
+    threading::EnumerableThreadSpecific<Vector<Vector<int64_t>>> &sub_masks,
+    Vector<int64_t> &r_indices);
+}  // namespace detail
+
+/**
+ * Evaluate the #predicate for all indices in #indices_to_check and return a mask that contains all
+ * indices where the predicate was true.
+ *
+ * #r_indices indices is only used if necessary.
+ */
+template<typename Predicate>
+inline IndexMask find_indices_based_on_predicate(const IndexMask indices_to_check,
+                                                 const int64_t parallel_grain_size,
+                                                 Vector<int64_t> &r_indices,
+                                                 const Predicate &predicate)
+{
+  /* Evaluate predicate in parallel. Since the size of the final mask is not known yet, many
+   * smaller vectors have to be filled with all indices where the predicate is true. Those smaller
+   * vectors are joined afterwards. */
+  threading::EnumerableThreadSpecific<Vector<Vector<int64_t>>> sub_masks;
+  threading::parallel_for(
+      indices_to_check.index_range(), parallel_grain_size, [&](const IndexRange range) {
+        const IndexMask sub_mask = indices_to_check.slice(range);
+        Vector<int64_t> masked_indices;
+        for (const int64_t i : sub_mask) {
+          if (predicate(i)) {
+            masked_indices.append(i);
+          }
+        }
+        if (!masked_indices.is_empty()) {
+          sub_masks.local().append(std::move(masked_indices));
+        }
+      });
+
+  /* This part doesn't have to be in the header. */
+  return detail::find_indices_based_on_predicate__merge(indices_to_check, sub_masks, r_indices);
+}
+
+}  // namespace blender::index_mask_ops
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 3d2ac5688ff..4bba84f2e29 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -303,6 +303,9 @@ float dist_squared_to_projected_aabb_simple(const float projmat[4][4],
                                             const float bbmin[3],
                                             const float bbmax[3]);
 
+/** Returns the distance between two 2D line segments. */
+float dist_seg_seg_v2(const float a1[3], const float a2[3], const float b1[3], const float b2[3]);
+
 float closest_to_ray_v3(float r_close[3],
                         const float p[3],
                         const float ray_orig[3],
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index ca22315b2ed..6e3e84f6495 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -203,6 +203,7 @@ set(SRC
   BLI_heap.h
   BLI_heap_simple.h
   BLI_index_mask.hh
+  BLI_index_mask_ops.hh
   BLI_index_range.hh
   BLI_inplace_priority_queue.hh
   BLI_iterator.h
diff --git a/source/blender/blenlib/intern/index_mask.cc b/source/blender/blenlib/intern/index_mask.cc
index 8c03df2d4c3..1e301bc5fb9 100644
--- a/source/blender/blenlib/intern/index_mask.cc
+++ b/source/blender/blenlib/intern/index_mask.cc
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 
 #include "BLI_index_mask.hh"
+#include "BLI_index_mask_ops.hh"
 
 namespace blender {
 
@@ -126,3 +127,70 @@ Vector<IndexRange> IndexMask::extract_ranges_invert(const IndexRange full_range,
 }
 
 }  // namespace blender
+
+namespace blender::index_mask_ops::detail {
+
+IndexMask find_indices_based_on_predicate__merge(
+    IndexMask indices_to_check,
+    threading::EnumerableThreadSpecific<Vector<Vector<int64_t>>> &sub_masks,
+    Vector<int64_t> &r_indices)
+{
+  /* Gather vectors that have been generated by possibly multiple threads. */
+  Vector<Vector<int64_t> *> all_vectors;
+  int64_t result_mask_size = 0;
+  for (Vector<Vector<int64_t>> &local_sub_masks : sub_masks) {
+    for (Vector<int64_t> &sub_mask : local_sub_masks) {
+      all_vectors.append(&sub_mask);
+      result_mask_size += sub_mask.size();
+    }
+  }
+
+  if (all_vectors.is_empty()) {
+    /* Special case when the predicate was false for all elements. */
+    return {};
+  }
+  if (result_mask_size == indices_to_check.size()) {
+    /* Special case when the predicate was true for all elements. */
+    return indices_to_check;
+  }
+  if (all_vectors.size() == 1) {
+    /* Special case when all indices for which the predicate is true happen to be in a single
+     * vector. */
+    r_indices = std::move(*all_vectors[0]);
+    return r_indices.as_span();
+  }
+
+  /* Indices in separate vectors don't overlap. So it is ok to sort the vectors just by looking at
+   * the first element. */
+  std::sort(all_vectors.begin(),
+            all_vectors.end(),
+            [](const Vector<int64_t> *a, const Vector<int64_t> *b) { return (*a)[0] < (*b)[0]; });
+
+  /* Precompute the offsets for the individual vectors, so that the indices can be copied into the
+   * final vector in parallel. */
+  Vector<int64_t> offsets;
+  offsets.reserve(all_vectors.size() + 1);
+  offsets.append(0);
+  for (Vector<int64_t> *vector : all_vectors) {
+    offsets.append(offsets.last() + vector->size());
+  }
+
+  r_indices.resize(result_mask_size);
+
+  /* Fill the final index mask in parallel again. */
+  threading::parallel_for(all_vectors.index_range(), 100, [&](const IndexRange all_vectors_range) {
+    for (const int64_t vector_index : all_vectors_range) {
+      Vector<int64_t> &vector = *all_vectors[vector_index];
+      const int64_t offset = offsets[vector_index];
+      threading::parallel_for(vector.index_range(), 1024, [&](const IndexRange range) {
+        initialized_copy_n(vector.data() + range.start(),
+                           range.size(),
+                           r_indices.data() + offset + range.start());
+      });
+    }
+  });
+
+  return r_indices.as_span();
+}
+
+}  // namespace blender::index_mask_ops::detail
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index f96c80185b1..bc3ed099fd5 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -903,6 +903,18 @@ float dist_squared_to_projected_aabb_simple(const float projmat[4][4],
 
 /** \} */
 
+float dist_seg_seg_v2(const float a1[3], const float a2[3], const float b1[3], const float b2[3])
+{
+  if (isect_seg_seg_v2_simple(a1, a2, b1, b2)) {
+    return 0.0f;
+  }
+  const float d1 = dist_squared_to_line_segment_v2(a1, b1, b2);
+  const float d2 = dist_squared_to_line_segment_v2(a2, b1, b2);
+  const float d3 = dist_squared_to_line_segment_v2(b1, a1, a2);
+  const float d4 = dist_squared_to_line_segment_v2(b2, a1, a2);
+  return sqrtf(min_ffff(d1, d2, d3, d4));
+}
+
 void closest_on_tri_to_point_v3(
     float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
 {
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index de7888aa1e8..59fbc3a64fb 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -9,6 +9,7 @@ set(INC
   ../../bmesh
   ../../depsgraph
   ../../draw
+  ../../functions
   ../../gpu
   ../../imbuf
   ../../makesdna
@@ -78,5 +79,16 @@ set(LIB
   bf_blenlib
 )
 
+if(WITH_TBB)
+  list(APPEND INC_SYS
+    ${TBB_INCLUDE_DIRS}
+  )
+  add_definitions(-DWITH_TBB)
+  if(WIN32)
+    # TBB includes Windows.h which will define min/max macros
+    # that will collide with the stl versions.
+    add_definitions(-DNOMINMAX)
+  endif()
+endif()
 
 blender_add_lib(bf_editor_sculpt_paint "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
index 04a14712d03..936226a03ed 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -2,7 +2,9 @@
 
 #include "BLI_utildefines.h"
 
+#include "BKE_brush.h"
 #include "BKE_context.h"
+#include "BKE_curves.hh"
 #include "BKE_paint.h"
 
 #include "WM_api.h"
@@ -10,6 +12,19 @@
 
 #include "ED_curves_sculpt.h"
 #include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_screen_types.h"
+
+#include "RNA_access.h"
+
+#include "BLI_index_mask_ops.hh"
+#include "BLI_math_vector.hh"
 
 #include "curves_sculpt_intern.h"
 #include "paint_intern.h"
@@ -35,14 +50,178 @@ bool CURVES_SCULPT_mode_poll_view3d(bContext *C)
   return true;
 }
 
+/** \} */
+
 namespace blender::ed::sculpt_paint {
 
-/** \} */
+using blender::bke::CurvesGeometry;
 
 /* -------------------------------------------------------------------- */
 /** \name * SCULPT_CURVES_OT_brush_stroke
  * \{ */
 
+struct StrokeExtension {
+  bool is_first;
+  float2 mouse_position;
+};
+
+/**
+ * Base class for stroke based operations in curves sculpt mode.
+ */
+class CurvesSculptStrokeOperation {
+ publ

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list