25 const int *src = intervals.
data();
27 int *dst = intervals.
data() + curve_interval_ranges[0].
size();
29 for (
const int curve :
IndexRange(1, curve_interval_ranges.
size() - 1)) {
30 const IndexRange range = curve_interval_ranges[curve];
31 const int width = range.
size() - 1;
32 std::copy_n(src + range.
first() + 1, width, dst);
35 (*dst) = src[curve_interval_ranges[curve_interval_ranges.
size() - 1].
last() + 1];
36 return {intervals.
data(), dst - intervals.
data() + 1};
45 const int interval_offset,
47 int ¤t_interval,
52 const int first_elem = offsets[curve_index];
53 const int last_elem = offsets[curve_index + 1] - 1;
55 if (current_interval == 0) {
56 is_first_selected[curve_index] = range.
first() == first_elem && range.
size() == 1;
57 if (!is_first_selected[curve_index]) {
61 curve_intervals[interval_offset + current_interval] = range.
first();
64 bool inside_curve = last_elem >= range.
last();
66 curve_intervals[interval_offset + current_interval] = range.
last();
69 curve_intervals[interval_offset + current_interval] = last_elem;
86 const int points_in_curve = (offsets[curve_index + 1] - offsets[curve_index] +
87 curve_interval_ranges[curve_index].
size() - 1);
88 new_offsets[curve_index + 1] = new_offsets[curve_index] + points_in_curve;
89 interval_offset += curve_interval_ranges[curve_index].
size() + 1;
102 if (curve_intervals[interval_offset + last_interval] != last_elem ||
103 curve_intervals[interval_offset + last_interval - 1] !=
104 curve_intervals[interval_offset + last_interval])
109 curve_intervals[interval_offset + last_interval] = last_elem;
111 else if (is_first_selected[curve_index] && last_interval == 1) {
113 curve_intervals[interval_offset + last_interval + 1] =
114 curve_intervals[interval_offset + last_interval];
115 is_first_selected[curve_index] =
false;
118 curve_interval_ranges[curve_index] =
IndexRange(interval_offset, last_interval);
119 calc_curve_offset(curve_index, interval_offset, offsets, new_offsets, curve_interval_ranges);
124 int &interval_offset,
125 int current_interval,
126 const std::optional<IndexRange> prev_range,
133 const int last = offsets[curve_index + 1] - 1;
135 if (prev_range.has_value() && prev_range.value().last() >= offsets[curve_index]) {
138 current_interval - 1,
143 curve_interval_ranges,
148 const int first = offsets[curve_index];
149 curve_interval_ranges[curve_index] =
IndexRange(interval_offset, 1);
150 is_first_selected[curve_index] =
false;
151 curve_intervals[interval_offset] = first;
152 curve_intervals[interval_offset + 1] = last;
153 calc_curve_offset(curve_index, interval_offset, offsets, new_offsets, curve_interval_ranges);
165 std::optional<IndexRange> prev_range;
166 int current_interval = 0;
169 int interval_offset = 0;
170 curve_intervals[interval_offset] = offsets[0];
171 new_offsets[0] = offsets[0];
175 if (range.
first() > offsets[curve_index + 1] - 1) {
184 curve_interval_ranges,
186 }
while (range.
first() > offsets[curve_index + 1] - 1);
187 current_interval = 0;
188 curve_intervals[interval_offset] = offsets[curve_index];
202 current_interval - 1,
203 offsets[curve_index + 1] - 1,
207 curve_interval_ranges,
209 current_interval = 0;
210 curve_intervals[interval_offset] = offsets[curve_index];
223 curve_interval_ranges,
226 }
while (curve_index < offsets.
size() - 1);
247 const int curves_num =
curves.curves_num();
248 const int curve_intervals_size = extruded_points.
size() * 2 + curves_num * 2;
257 Array<int> curve_intervals(curve_intervals_size);
272 curve_interval_ranges,
279 std::array<GVArraySpan, 3> src_selection;
280 std::array<bke::GSpanAttributeWriter, 3> dst_selections;
283 for (
const int selection_i : selection_attr_names.
index_range()) {
284 const StringRef selection_name = selection_attr_names[selection_i];
287 if (!src_selection_array) {
291 src_selection[selection_i] = src_selection_array;
300 for (const int curve : curves_range) {
301 const int first_index = curve_interval_ranges[curve].start();
302 const int first_value = curve_intervals[first_index];
303 bool is_selected = is_first_selected[curve];
305 for (const int i : curve_interval_ranges[curve]) {
306 const int dest_index = new_offsets[curve] + curve_intervals[i] - first_value + i -
308 const int size = curve_intervals[i + 1] - curve_intervals[i] + 1;
310 for (const int selection_i : selection_attr_names.index_range()) {
311 GMutableSpan dst_span = dst_selections[selection_i].span.slice(
312 IndexRange(dest_index, size));
314 src_selection[selection_i].type().copy_assign_n(
315 src_selection[selection_i].slice(IndexRange(curve_intervals[i], size)).data(),
320 fill_selection(dst_span, false);
324 is_selected = !is_selected;
329 for (
const int selection_i : selection_attr_names.index_range()) {
330 dst_selections[selection_i].finish();
342 {
".selection",
".selection_handle_left",
".selection_handle_right"})))
344 const CPPType &type =
attribute.src.type();
346 for (const int i : range) {
347 const int first = intervals[i];
348 const int size = intervals[i + 1] - first + 1;
349 const int dest_index = intervals[i] + i;
350 type.copy_assign_n(attribute.src.slice(IndexRange(first, size)).data(),
351 attribute.dst.span.slice(IndexRange(dest_index, size)).data(),
357 curves_id.geometry.wrap() = std::move(new_curves);
371 ot->name =
"Extrude";
372 ot->description =
"Extrude selected control point(s)";
373 ot->idname =
"CURVES_OT_extrude";
Low-level operations for curves.
void DEG_id_tag_update(ID *id, unsigned int flags)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
const CPPType & type() const
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr int64_t size() const
constexpr T * data() const
constexpr T & last(const int64_t n=0) const
constexpr int64_t size() const
constexpr const T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
static VArray ForSingle(T value, const int64_t size)
GAttributeReader lookup(const StringRef attribute_id) const
void resize(int points_num, int curves_num)
MutableSpan< int > offsets_for_write()
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
Vector< AttributeTransferData > retrieve_attributes_for_transfer(const AttributeAccessor src_attributes, MutableAttributeAccessor dst_attributes, AttrDomainMask domain_mask, const AttributeFilter &attribute_filter={})
auto attribute_filter_from_skip_ref(const Span< StringRef > skip)
static void extrude_curves(Curves &curves_id)
static int curves_extrude_exec(bContext *C, wmOperator *)
VectorSet< Curves * > get_unique_editable_curves(const bContext &C)
static void calc_curves_extrusion(const IndexMask &selection, const Span< int > offsets, MutableSpan< int > new_offsets, MutableSpan< int > curve_intervals, MutableSpan< IndexRange > curve_interval_ranges, MutableSpan< bool > is_first_selected)
static void finish_curve_or_full_copy(int &curve_index, int &interval_offset, int current_interval, const std::optional< IndexRange > prev_range, const Span< int > offsets, MutableSpan< int > new_offsets, MutableSpan< int > curve_intervals, MutableSpan< IndexRange > curve_interval_ranges, MutableSpan< bool > is_first_selected)
static Span< int > compress_intervals(const Span< IndexRange > curve_interval_ranges, MutableSpan< int > intervals)
bool editable_curves_in_edit_mode_poll(bContext *C)
static void finish_curve(int &curve_index, int &interval_offset, int last_interval, int last_elem, const Span< int > offsets, MutableSpan< int > new_offsets, MutableSpan< int > curve_intervals, MutableSpan< IndexRange > curve_interval_ranges, MutableSpan< bool > is_first_selected)
Span< StringRef > get_curves_selection_attribute_names(const bke::CurvesGeometry &curves)
bke::GSpanAttributeWriter ensure_selection_attribute(bke::CurvesGeometry &curves, bke::AttrDomain selection_domain, eCustomDataType create_type, StringRef attribute_name)
static void calc_curve_offset(const int curve_index, int &interval_offset, const Span< int > offsets, MutableSpan< int > new_offsets, MutableSpan< IndexRange > curve_interval_ranges)
IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
void CURVES_OT_extrude(wmOperatorType *ot)
static bool handle_range(const int curve_index, const int interval_offset, const Span< int > offsets, int ¤t_interval, IndexRange &range, MutableSpan< int > curve_intervals, MutableSpan< bool > is_first_selected)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]