Blender V5.0
curve_legacy_convert.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_listbase.h"
6#include "BLI_task.hh"
7#include "BLI_vector.hh"
8
9#include "DNA_curve_types.h"
10#include "DNA_curves_types.h"
11
12#include "BKE_curve.hh"
14#include "BKE_curves.hh"
15#include "BKE_curves_utils.hh"
16#include "BKE_geometry_set.hh"
17
18namespace blender::bke {
19
20static CurveType curve_type_from_legacy(const short type)
21{
22 switch (type) {
23 case CU_POLY:
24 return CURVE_TYPE_POLY;
25 case CU_BEZIER:
26 return CURVE_TYPE_BEZIER;
27 case CU_NURBS:
28 return CURVE_TYPE_NURBS;
29 }
31 return CURVE_TYPE_POLY;
32}
33
34static HandleType handle_type_from_legacy(const uint8_t handle_type_legacy)
35{
36 switch (handle_type_legacy) {
37 case HD_FREE:
38 return BEZIER_HANDLE_FREE;
39 case HD_AUTO:
40 return BEZIER_HANDLE_AUTO;
41 case HD_VECT:
43 case HD_ALIGN:
45 case HD_AUTO_ANIM:
46 return BEZIER_HANDLE_AUTO;
49 }
51 return BEZIER_HANDLE_AUTO;
52}
53
54static NormalMode normal_mode_from_legacy(const short twist_mode)
55{
56 switch (twist_mode) {
57 case CU_TWIST_Z_UP:
59 return NORMAL_MODE_Z_UP;
62 }
65}
66
85
86Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_list)
87{
88 Vector<const Nurb *> src_curves;
89 LISTBASE_FOREACH (const Nurb *, item, &nurbs_list) {
90 src_curves.append(item);
91 }
92 if (src_curves.is_empty()) {
93 return nullptr;
94 }
95
96 Curves *curves_id = curves_new_nomain(0, src_curves.size());
97 CurvesGeometry &curves = curves_id->geometry.wrap();
98 MutableAttributeAccessor curves_attributes = curves.attributes_for_write();
99
100 MutableSpan<int8_t> types = curves.curve_types_for_write();
101 MutableSpan<bool> cyclic = curves.cyclic_for_write();
102
103 int offset = 0;
104 MutableSpan<int> offsets = curves.offsets_for_write();
105 for (const int i : src_curves.index_range()) {
106 offsets[i] = offset;
107
108 const Nurb &src_curve = *src_curves[i];
109 types[i] = curve_type_from_legacy(src_curve.type);
110 cyclic[i] = src_curve.flagu & CU_NURB_CYCLIC;
111
112 offset += src_curve.pntsu;
113 }
114 offsets.last() = offset;
115 curves.resize(curves.offsets().last(), curves.curves_num());
116
117 curves.update_curve_types();
118
119 const OffsetIndices points_by_curve = curves.points_by_curve();
120 MutableSpan<float3> positions = curves.positions_for_write();
121 SpanAttributeWriter<float> radius_attribute =
122 curves_attributes.lookup_or_add_for_write_only_span<float>("radius", AttrDomain::Point);
123 MutableSpan<float> radii = radius_attribute.span;
124 MutableSpan<float> tilts = curves.tilt_for_write();
125
126 auto create_poly = [&](const IndexMask &selection) {
127 selection.foreach_index(GrainSize(256), [&](const int curve_i) {
128 const Nurb &src_curve = *src_curves[curve_i];
129 const Span<BPoint> src_points(src_curve.bp, src_curve.pntsu);
130 const IndexRange points = points_by_curve[curve_i];
131
132 for (const int i : src_points.index_range()) {
133 const BPoint &bp = src_points[i];
134 positions[points[i]] = bp.vec;
135 radii[points[i]] = bp.radius;
136 tilts[points[i]] = bp.tilt;
137 }
138 });
139 };
140
141 /* NOTE: For curve handles, legacy curves can end up in invalid situations where the handle
142 * positions don't agree with the types because of evaluation, or because one-sided aligned
143 * handles weren't considered. While recalculating automatic handles to fix those situations
144 * is an option, currently this opts not to for the sake of flexibility. */
145 auto create_bezier = [&](const IndexMask &selection) {
146 MutableSpan<int> resolutions = curves.resolution_for_write();
147 MutableSpan<float3> handle_positions_l = curves.handle_positions_left_for_write();
148 MutableSpan<float3> handle_positions_r = curves.handle_positions_right_for_write();
149 MutableSpan<int8_t> handle_types_l = curves.handle_types_left_for_write();
150 MutableSpan<int8_t> handle_types_r = curves.handle_types_right_for_write();
151
152 selection.foreach_index(GrainSize(256), [&](const int curve_i) {
153 const Nurb &src_curve = *src_curves[curve_i];
154 const Span<BezTriple> src_points(src_curve.bezt, src_curve.pntsu);
155 const IndexRange points = points_by_curve[curve_i];
156
157 resolutions[curve_i] = src_curve.resolu;
158
159 for (const int i : src_points.index_range()) {
160 const BezTriple &point = src_points[i];
161 positions[points[i]] = point.vec[1];
162 handle_positions_l[points[i]] = point.vec[0];
163 handle_types_l[points[i]] = handle_type_from_legacy(point.h1);
164 handle_positions_r[points[i]] = point.vec[2];
165 handle_types_r[points[i]] = handle_type_from_legacy(point.h2);
166 radii[points[i]] = point.radius;
167 tilts[points[i]] = point.tilt;
168 }
169 });
170 };
171
172 auto create_nurbs = [&](const IndexMask &selection) {
173 MutableSpan<int> resolutions = curves.resolution_for_write();
174 MutableSpan<float> nurbs_weights = curves.nurbs_weights_for_write();
175 MutableSpan<int8_t> nurbs_orders = curves.nurbs_orders_for_write();
176 MutableSpan<int8_t> nurbs_knots_modes = curves.nurbs_knots_modes_for_write();
177
178 selection.foreach_index(GrainSize(256), [&](const int curve_i) {
179 const Nurb &src_curve = *src_curves[curve_i];
180 const Span src_points(src_curve.bp, src_curve.pntsu);
181 const IndexRange points = points_by_curve[curve_i];
182
183 resolutions[curve_i] = src_curve.resolu;
184 nurbs_orders[curve_i] = src_curve.orderu;
185 nurbs_knots_modes[curve_i] = knots_mode_from_legacy(src_curve.flagu);
186
187 for (const int i : src_points.index_range()) {
188 const BPoint &bp = src_points[i];
189 positions[points[i]] = bp.vec;
190 radii[points[i]] = bp.radius;
191 tilts[points[i]] = bp.tilt;
192 nurbs_weights[points[i]] = bp.vec[3];
193 }
194 });
195
196 curves.nurbs_custom_knots_update_size();
197 if (!curves.nurbs_has_custom_knots()) {
198 return;
199 }
200
201 const OffsetIndices<int> knots_by_curve = curves.nurbs_custom_knots_by_curve();
202 MutableSpan<float> custom_knots = curves.nurbs_custom_knots_for_write();
203 selection.foreach_index([&](const int curve_i) {
204 if (nurbs_knots_modes[curve_i] == NURBS_KNOT_MODE_CUSTOM) {
205 const Nurb &src_curve = *src_curves[curve_i];
206 const IndexRange knots = knots_by_curve[curve_i];
207 custom_knots.slice(knots).copy_from(Span<float>(src_curve.knotsu, knots.size()));
208 }
209 });
210 };
211
213 curves.curve_types(),
214 curves.curve_type_counts(),
215 curves.curves_range(),
216 [&](const IndexMask & /*selection*/) { BLI_assert_unreachable(); },
217 create_poly,
218 create_bezier,
219 create_nurbs);
220
221 curves.normal_mode_for_write().fill(normal_mode_from_legacy(curve_legacy.twist_mode));
222
223 radius_attribute.finish();
224
225 curves_id->mat = static_cast<Material **>(MEM_dupallocN(curve_legacy.mat));
226 curves_id->totcol = curve_legacy.totcol;
227
228 return curves_id;
229}
230
232{
233 return curve_legacy_to_curves(curve_legacy, *BKE_curve_nurbs_get_for_read(&curve_legacy));
234}
235
236} // namespace blender::bke
const ListBase * BKE_curve_nurbs_get_for_read(const Curve *cu)
Definition curve.cc:4967
Low-level operations for curves.
Low-level operations for curves.
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define LISTBASE_FOREACH(type, var, list)
@ CU_NURB_CYCLIC
@ CU_NURB_CUSTOM
@ CU_NURB_ENDPOINT
@ CU_NURB_BEZIER
@ CU_TWIST_MINIMUM
@ CU_TWIST_TANGENT
@ CU_TWIST_Z_UP
@ CU_BEZIER
@ CU_POLY
@ CU_NURBS
@ HD_AUTO_ANIM
@ HD_VECT
@ HD_FREE
@ HD_AUTO
@ HD_ALIGN_DOUBLESIDE
@ HD_ALIGN
NormalMode
@ NORMAL_MODE_MINIMUM_TWIST
@ NORMAL_MODE_Z_UP
HandleType
@ BEZIER_HANDLE_FREE
@ BEZIER_HANDLE_ALIGN
@ BEZIER_HANDLE_VECTOR
@ BEZIER_HANDLE_AUTO
KnotsMode
@ NURBS_KNOT_MODE_ENDPOINT
@ NURBS_KNOT_MODE_NORMAL
@ NURBS_KNOT_MODE_BEZIER
@ NURBS_KNOT_MODE_ENDPOINT_BEZIER
@ NURBS_KNOT_MODE_CUSTOM
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:689
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
static char ** types
Definition makesdna.cc:71
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void foreach_curve_by_type(const VArray< int8_t > &types, const std::array< int, CURVE_TYPES_NUM > &type_counts, const IndexMask &selection, FunctionRef< void(IndexMask)> catmull_rom_fn, FunctionRef< void(IndexMask)> poly_fn, FunctionRef< void(IndexMask)> bezier_fn, FunctionRef< void(IndexMask)> nurbs_fn)
Curves * curve_legacy_to_curves(const Curve &curve_legacy)
static CurveType curve_type_from_legacy(const short type)
static NormalMode normal_mode_from_legacy(const short twist_mode)
static HandleType handle_type_from_legacy(const uint8_t handle_type_legacy)
KnotsMode knots_mode_from_legacy(short flag)
Curves * curves_new_nomain(int points_num, int curves_num)
float vec[4]
float vec[3][3]
struct Material ** mat
short totcol
short twist_mode
CurvesGeometry geometry
struct Material ** mat
short flagu
short orderu
float * knotsu
short type
BezTriple * bezt
BPoint * bp
short resolu
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:145