[Bf-blender-cvs] [5606942c63b] master: Curves: Skip CurveEval in legacy curve conversion

Hans Goudey noreply at git.blender.org
Sat Jun 25 18:12:25 CEST 2022


Commit: 5606942c63bf81afa16a0f148287da9421d53a48
Author: Hans Goudey
Date:   Sat Jun 25 11:11:12 2022 -0500
Branches: master
https://developer.blender.org/rB5606942c63bf81afa16a0f148287da9421d53a48

Curves: Skip CurveEval in legacy curve conversion

Currently when converting from the legacy curve type to the new type,
which happens during evaluation of every legacy curve object, the
`CurveEval` type is used as an intermediate step. This involves
copying all data twice, and allocating a bunch of temporary arrays.
It's also another use of `CurveEval` that has to be removed before
we remove the type.

The main user difference besides the subtlety described below
will be improved performance.

**Invalid Handles and Types**
One important note is that there are two cases (that I know of)
where handles and handle types can be invalid in the old curve
type. The first is animation, where animated handle positions don't
necessary respect the types. The second is control points with a
single aligned handle that didn't necessarily align with the other.

In master (partially on purpose) the code corrects the first situation
(which caused T98965). But it doesn't correct the second situation.
It's trivial to correct for the second case with this patch (because of the
eager calculation decided on in D14464), but this patch makes the choice
not to correct for //either//.

Though not correcting the handle types puts curves in an invalid state,
it also adds flexibility by allowing that option. Users must understand
that any deformation may correct invalid handles.

Fixes T98965

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

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

A	source/blender/blenkernel/BKE_curve_legacy_convert.hh
M	source/blender/blenkernel/CMakeLists.txt
A	source/blender/blenkernel/intern/curve_legacy_convert.cc
M	source/blender/blenkernel/intern/displist.cc

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

diff --git a/source/blender/blenkernel/BKE_curve_legacy_convert.hh b/source/blender/blenkernel/BKE_curve_legacy_convert.hh
new file mode 100644
index 00000000000..88f93282f25
--- /dev/null
+++ b/source/blender/blenkernel/BKE_curve_legacy_convert.hh
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_curves.hh"
+
+struct Curve;
+struct Curves;
+
+namespace blender::bke {
+
+Curves *curve_legacy_to_curves(const Curve &curve_legacy);
+Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_list);
+
+}  // namespace blender::bke
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 8dc6f711fae..50be5b475d4 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -111,6 +111,7 @@ set(SRC
   intern/curve_decimate.c
   intern/curve_deform.c
   intern/curve_eval.cc
+  intern/curve_legacy_convert.cc
   intern/curve_nurbs.cc
   intern/curve_poly.cc
   intern/curve_to_mesh_convert.cc
@@ -353,6 +354,7 @@ set(SRC
   BKE_cryptomatte.h
   BKE_cryptomatte.hh
   BKE_curve.h
+  BKE_curve_legacy_convert.hh
   BKE_curve_to_mesh.hh
   BKE_curveprofile.h
   BKE_curves.h
diff --git a/source/blender/blenkernel/intern/curve_legacy_convert.cc b/source/blender/blenkernel/intern/curve_legacy_convert.cc
new file mode 100644
index 00000000000..62e89d8be80
--- /dev/null
+++ b/source/blender/blenkernel/intern/curve_legacy_convert.cc
@@ -0,0 +1,212 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_task.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_curve_types.h"
+#include "DNA_curves_types.h"
+
+#include "BKE_curve.h"
+#include "BKE_curve_legacy_convert.hh"
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
+#include "BKE_geometry_set.hh"
+
+namespace blender::bke {
+
+static CurveType curve_type_from_legacy(const short type)
+{
+  switch (type) {
+    case CU_POLY:
+      return CURVE_TYPE_POLY;
+    case CU_BEZIER:
+      return CURVE_TYPE_BEZIER;
+    case CU_NURBS:
+      return CURVE_TYPE_NURBS;
+  }
+  BLI_assert_unreachable();
+  return CURVE_TYPE_POLY;
+}
+
+static HandleType handle_type_from_legacy(const uint8_t handle_type_legacy)
+{
+  switch (handle_type_legacy) {
+    case HD_FREE:
+      return BEZIER_HANDLE_FREE;
+    case HD_AUTO:
+      return BEZIER_HANDLE_AUTO;
+    case HD_VECT:
+      return BEZIER_HANDLE_VECTOR;
+    case HD_ALIGN:
+      return BEZIER_HANDLE_ALIGN;
+    case HD_AUTO_ANIM:
+      return BEZIER_HANDLE_AUTO;
+    case HD_ALIGN_DOUBLESIDE:
+      return BEZIER_HANDLE_ALIGN;
+  }
+  BLI_assert_unreachable();
+  return BEZIER_HANDLE_AUTO;
+}
+
+static NormalMode normal_mode_from_legacy(const short twist_mode)
+{
+  switch (twist_mode) {
+    case CU_TWIST_Z_UP:
+    case CU_TWIST_TANGENT:
+      return NORMAL_MODE_Z_UP;
+    case CU_TWIST_MINIMUM:
+      return NORMAL_MODE_MINIMUM_TWIST;
+  }
+  BLI_assert_unreachable();
+  return NORMAL_MODE_MINIMUM_TWIST;
+}
+
+static KnotsMode knots_mode_from_legacy(const short flag)
+{
+  switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
+    case CU_NURB_ENDPOINT:
+      return NURBS_KNOT_MODE_ENDPOINT;
+    case CU_NURB_BEZIER:
+      return NURBS_KNOT_MODE_BEZIER;
+    case CU_NURB_ENDPOINT | CU_NURB_BEZIER:
+      return NURBS_KNOT_MODE_ENDPOINT_BEZIER;
+    case 0:
+      return NURBS_KNOT_MODE_NORMAL;
+  }
+  BLI_assert_unreachable();
+  return NURBS_KNOT_MODE_NORMAL;
+}
+
+Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_list)
+{
+  const Vector<const Nurb *> src_curves(nurbs_list);
+
+  Curves *curves_id = curves_new_nomain(0, src_curves.size());
+  CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+  CurveComponent component;
+  component.replace(curves_id, GeometryOwnershipType::Editable);
+
+  MutableSpan<int8_t> types = curves.curve_types_for_write();
+  MutableSpan<bool> cyclic = curves.cyclic_for_write();
+
+  int offset = 0;
+  MutableSpan<int> offsets = curves.offsets_for_write();
+  for (const int i : src_curves.index_range()) {
+    offsets[i] = offset;
+
+    const Nurb &src_curve = *src_curves[i];
+    types[i] = curve_type_from_legacy(src_curve.type);
+    cyclic[i] = src_curve.flagu & CU_NURB_CYCLIC;
+
+    offset += src_curve.pntsu;
+  }
+  offsets.last() = offset;
+  curves.resize(curves.offsets().last(), curves.curves_num());
+
+  curves.update_curve_types();
+
+  MutableSpan<float3> positions = curves.positions_for_write();
+  OutputAttribute_Typed<float> radius_attribute =
+      component.attribute_try_get_for_output_only<float>("radius", ATTR_DOMAIN_POINT);
+  MutableSpan<float> radii = radius_attribute.as_span();
+  MutableSpan<float> tilts = curves.tilt_for_write();
+
+  auto create_poly = [&](IndexMask selection) {
+    threading::parallel_for(selection.index_range(), 246, [&](IndexRange range) {
+      for (const int curve_i : selection.slice(range)) {
+        const Nurb &src_curve = *src_curves[curve_i];
+        const Span<BPoint> src_points(src_curve.bp, src_curve.pntsu);
+        const IndexRange points = curves.points_for_curve(curve_i);
+
+        for (const int i : src_points.index_range()) {
+          const BPoint &bp = src_points[i];
+          positions[points[i]] = bp.vec;
+          radii[points[i]] = bp.radius;
+          tilts[points[i]] = bp.tilt;
+        }
+      }
+    });
+  };
+
+  /* Note: For curve handles, legacy curves can end up in invalid situations where the handle
+   * positions don't agree with the types because of evaluation, or because one-sided aligned
+   * handles weren't considered. While recalculating automatic handles to fix those situations
+   * is an option, currently this opts not to for the sake of flexibility. */
+  auto create_bezier = [&](IndexMask selection) {
+    MutableSpan<int> resolutions = curves.resolution_for_write();
+    MutableSpan<float3> handle_positions_l = curves.handle_positions_left_for_write();
+    MutableSpan<float3> handle_positions_r = curves.handle_positions_right_for_write();
+    MutableSpan<int8_t> handle_types_l = curves.handle_types_left_for_write();
+    MutableSpan<int8_t> handle_types_r = curves.handle_types_right_for_write();
+
+    threading::parallel_for(selection.index_range(), 246, [&](IndexRange range) {
+      for (const int curve_i : selection.slice(range)) {
+        const Nurb &src_curve = *src_curves[curve_i];
+        const Span<BezTriple> src_points(src_curve.bezt, src_curve.pntsu);
+        const IndexRange points = curves.points_for_curve(curve_i);
+
+        resolutions[curve_i] = src_curve.resolu;
+
+        for (const int i : src_points.index_range()) {
+          const BezTriple &point = src_points[i];
+          positions[points[i]] = point.vec[1];
+          handle_positions_l[points[i]] = point.vec[0];
+          handle_types_l[points[i]] = handle_type_from_legacy(point.h1);
+          handle_positions_r[points[i]] = point.vec[2];
+          handle_types_r[points[i]] = handle_type_from_legacy(point.h2);
+          radii[points[i]] = point.radius;
+          tilts[points[i]] = point.tilt;
+        }
+      }
+    });
+  };
+
+  auto create_nurbs = [&](IndexMask selection) {
+    threading::parallel_for(selection.index_range(), 246, [&](IndexRange range) {
+      MutableSpan<int> resolutions = curves.resolution_for_write();
+      MutableSpan<float> nurbs_weights = curves.nurbs_weights_for_write();
+      MutableSpan<int8_t> nurbs_orders = curves.nurbs_orders_for_write();
+      MutableSpan<int8_t> nurbs_knots_modes = curves.nurbs_knots_modes_for_write();
+
+      for (const int curve_i : selection.slice(range)) {
+        const Nurb &src_curve = *src_curves[curve_i];
+        const Span src_points(src_curve.bp, src_curve.pntsu);
+        const IndexRange points = curves.points_for_curve(curve_i);
+
+        resolutions[curve_i] = src_curve.resolu;
+        nurbs_orders[curve_i] = src_curve.orderu;
+        nurbs_knots_modes[curve_i] = knots_mode_from_legacy(src_curve.flagu);
+
+        for (const int i : src_points.index_range()) {
+          const BPoint &bp = src_points[i];
+          positions[points[i]] = bp.vec;
+          radii[points[i]] = bp.radius;
+          tilts[points[i]] = bp.tilt;
+          nurbs_weights[points[i]] = bp.vec[3];
+        }
+      }
+    });
+  };
+
+  bke::curves::foreach_curve_by_type(
+      curves.curve_types(),
+      curves.curve_type_counts(),
+      curves.curves_range(),
+      [&](IndexMask /* selection */) {},
+      create_poly,
+      create_bezier,
+      create_nurbs);
+
+  curves.normal_mode_for_write().fill(normal_mode_from_legacy(curve_legacy.twist_mode));
+
+  radius_attribute.save();
+
+  return curves_id;
+}
+
+Curves *curve_legacy_to_curves(const Curve &curve_legacy)
+{
+  return curve_legacy_to_curves(curve_legacy, *BKE_curve_nurbs_get_for_read(&curve_legacy));
+}
+
+}  // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index 63aa03483b2..823fce52b50 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -30,6 +30,7 @@
 
 #include "BKE_anim_path.h"
 #include "BKE_curve.h"
+#include "BKE_curve_legacy_convert.hh"
 #include "BKE_displist.h"
 #include "BKE_geometry_set.hh"
 #include "BKE_key.h"
@@ -40,7 +41,6 @@
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BKE_object.h"
-#include "BKE_spline.hh"
 #include "BKE_vfont.h"
 
 #include "BLI_sys_types.h" /* For #intptr_t support. */
@@ -863,9 +863,8 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
     geometry_set.replace_mesh(mesh);
   }
   else {
-    std::unique_ptr<CurveEval> curve_eval = curve_eval_from_dna_curve(
-        *cu, ob->runtime.curve_cache->deformed_nurbs);
-    geometry_set.replace_curves(curve_eval_to_curves(*curve_eval));
+    geometry_set.replace_curves(
+        blender::bke::curve_legacy_to_curves(*cu, ob->runtime.curve_cache->deformed_nurbs));
   }
 
   for (; md; md = md->next) {



More information about the Bf-blender-cvs mailing list