Blender V5.0
draw_cache_impl_curves.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_array_utils.hh"
16#include "BLI_listbase.h"
17#include "BLI_math_base.h"
18#include "BLI_math_vector.hh"
20#include "BLI_span.hh"
21#include "BLI_string_utf8.h"
22#include "BLI_task.hh"
23
24#include "DNA_curves_types.h"
25#include "DNA_object_types.h"
26#include "DNA_userdef_types.h"
27
29
30#include "BKE_crazyspace.hh"
31#include "BKE_curves.hh"
32#include "BKE_curves_utils.hh"
33#include "BKE_customdata.hh"
34#include "BKE_geometry_set.hh"
35
36#include "GPU_batch.hh"
37#include "GPU_capabilities.hh"
38#include "GPU_context.hh"
39#include "GPU_material.hh"
40#include "GPU_texture.hh"
41
42#include "DRW_render.hh"
43
44#include "draw_attributes.hh"
45#include "draw_cache_impl.hh" /* own include */
46#include "draw_cache_inline.hh"
48#include "draw_curves_private.hh" /* own include */
49#include "draw_hair_private.hh"
50
51namespace blender::draw {
52
53#define EDIT_CURVES_NURBS_CONTROL_POINT (1u)
54#define EDIT_CURVES_BEZIER_HANDLE (1u << 1)
55#define EDIT_CURVES_ACTIVE_HANDLE (1u << 2)
56/* Bezier curve control point lying on the curve.
57 * The one between left and right handles. */
58#define EDIT_CURVES_BEZIER_KNOT (1u << 3)
59#define EDIT_CURVES_HANDLE_TYPES_SHIFT (4u)
60
61/* ---------------------------------------------------------------------- */
62
65
66 gpu::Batch *edit_points;
67 gpu::Batch *edit_handles;
68
69 gpu::Batch *sculpt_cage;
71
72 /* Crazy-space point positions for original points. */
74
75 /* Additional data needed for shader to choose color for each point in edit_points_pos.
76 * If first bit is set, then point is NURBS control point. EDIT_CURVES_NURBS_CONTROL_POINT is
77 * used to set and test. If second, then point is Bezier handle point. Set and tested with
78 * EDIT_CURVES_BEZIER_HANDLE.
79 * In Bezier case two handle types of HandleType are also encoded.
80 * Byte structure for Bezier knot point (handle middle point):
81 * | left handle type | right handle type | | BEZIER| NURBS|
82 * | 7 6 | 5 4 | 3 2 | 1 | 0 |
83 *
84 * If it is left or right handle point, then same handle type is repeated in both slots.
85 */
87
88 /* Selection of original points. */
90
92
93 gpu::Batch *edit_curves_lines;
96
97 /* Whether the cache is invalid. */
99};
100
101static bool batch_cache_is_dirty(const Curves &curves)
102{
103 const CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache);
104 return (cache && cache->is_dirty == false);
105}
106
107static void init_batch_cache(Curves &curves)
108{
109 CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache);
110
111 if (!cache) {
112 cache = MEM_new<CurvesBatchCache>(__func__);
113 curves.batch_cache = cache;
114 }
115 else {
116 cache->eval_cache = {};
117 }
118
119 cache->is_dirty = false;
120}
121
140
142{
143 for (const int i : IndexRange(GPU_MAX_ATTR)) {
144 this->evaluated_attributes_buf[i].reset();
145 }
146 for (const int i : IndexRange(GPU_MAX_ATTR)) {
147 this->curve_attributes_buf[i].reset();
148 }
149 this->attr_used.clear();
150}
151
153{
154 /* TODO: more granular update tagging. */
155 this->evaluated_pos_rad_buf.reset();
156 this->evaluated_time_buf.reset();
157 this->curves_length_buf.reset();
158
159 this->points_by_curve_buf.reset();
160 this->evaluated_points_by_curve_buf.reset();
161 this->curves_type_buf.reset();
162 this->curves_resolution_buf.reset();
163 this->curves_cyclic_buf.reset();
164
165 this->handles_positions_left_buf.reset();
166 this->handles_positions_right_buf.reset();
167 this->bezier_offsets_buf.reset();
168
169 this->curves_order_buf.reset();
170 this->control_weights_buf.reset();
171 this->basis_cache_buf.reset();
172 this->basis_cache_offset_buf.reset();
173
174 this->indirection_cylinder_buf.reset();
175 this->indirection_ribbon_buf.reset();
176
177 for (gpu::Batch *&batch : this->batch) {
179 }
180
181 this->discard_attributes();
182}
183
184static void clear_batch_cache(Curves &curves)
185{
186 CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache);
187 if (!cache) {
188 return;
189 }
190
191 cache->eval_cache.clear();
192 clear_edit_data(cache);
193}
194
196{
198 return *static_cast<CurvesBatchCache *>(curves.batch_cache);
199}
200
201static uint32_t bezier_data_value(int8_t handle_type, bool is_active)
202{
204 (is_active ? EDIT_CURVES_ACTIVE_HANDLE : 0);
205}
206
207static int handles_and_points_num(const int points_num, const OffsetIndices<int> bezier_offsets)
208{
209 return points_num + bezier_offsets.total_size() * 2;
210}
211
212static IndexRange handle_range_left(const int points_num, const OffsetIndices<int> bezier_offsets)
213{
214 return IndexRange(points_num, bezier_offsets.total_size());
215}
216
217static IndexRange handle_range_right(const int points_num, const OffsetIndices<int> bezier_offsets)
218{
219 return IndexRange(points_num + bezier_offsets.total_size(), bezier_offsets.total_size());
220}
221
222static void extract_edit_data(const OffsetIndices<int> points_by_curve,
223 const IndexMask &curve_selection,
224 const VArray<bool> &selection_attr,
225 const bool mark_active,
226 const uint32_t fill_value,
228{
229 curve_selection.foreach_index(GrainSize(256), [&](const int curve) {
230 const IndexRange points = points_by_curve[curve];
231 bool is_active = false;
232 if (mark_active) {
233 is_active = array_utils::count_booleans(selection_attr, points) > 0;
234 }
235 uint32_t data_value = fill_value | (is_active ? EDIT_CURVES_ACTIVE_HANDLE : 0u);
236 data.slice(points).fill(data_value);
237 });
238}
239
240static void create_edit_points_data(const OffsetIndices<int> points_by_curve,
241 const IndexMask &catmull_rom_curves,
242 const IndexMask &poly_curves,
243 const IndexMask &bezier_curves,
244 const IndexMask &nurbs_curves,
245 const OffsetIndices<int> bezier_offsets,
246 const bke::CurvesGeometry &curves,
247 gpu::VertBuf &vbo)
248{
249 const int points_num = points_by_curve.total_size();
250 const bke::AttributeAccessor attributes = curves.attributes();
251 const VArray selection = *attributes.lookup_or_default<bool>(
252 ".selection", bke::AttrDomain::Point, true);
253
255 gpu::VertAttrType::UINT_32);
257 GPU_vertbuf_data_alloc(vbo, handles_and_points_num(points_num, bezier_offsets));
258 MutableSpan<uint32_t> data = vbo.data<uint32_t>();
259
260 extract_edit_data(points_by_curve, catmull_rom_curves, selection, false, 0, data);
261
262 extract_edit_data(points_by_curve, poly_curves, selection, false, 0, data);
263
264 if (!bezier_curves.is_empty()) {
265 const VArray<int8_t> type_right = curves.handle_types_left();
266 const VArray<int8_t> types_left = curves.handle_types_right();
267 const VArray selection_left = *attributes.lookup_or_default<bool>(
268 ".selection_handle_left", bke::AttrDomain::Point, true);
269 const VArray selection_right = *attributes.lookup_or_default<bool>(
270 ".selection_handle_right", bke::AttrDomain::Point, true);
271
272 MutableSpan data_left = data.slice(handle_range_left(points_num, bezier_offsets));
273 MutableSpan data_right = data.slice(handle_range_right(points_num, bezier_offsets));
274
275 bezier_curves.foreach_index(GrainSize(256), [&](const int curve, const int64_t pos) {
276 const IndexRange points = points_by_curve[curve];
277 const IndexRange bezier_range = bezier_offsets[pos];
278 for (const int i : points.index_range()) {
279 const int point = points[i];
281
282 const bool selected = selection[point] || selection_left[point] || selection_right[point];
283 const int bezier_point = bezier_range[i];
284 data_left[bezier_point] = bezier_data_value(type_right[point], selected);
285 data_right[bezier_point] = bezier_data_value(types_left[point], selected);
286 }
287 });
288 }
289
291 points_by_curve, nurbs_curves, selection, true, EDIT_CURVES_NURBS_CONTROL_POINT, data);
292}
293
295 const OffsetIndices<int> points_by_curve,
296 const IndexMask &bezier_curves,
297 const OffsetIndices<int> bezier_offsets,
298 const bke::crazyspace::GeometryDeformation deformation,
299 gpu::VertBuf &vbo)
300{
301 const Span<float3> positions = deformation.positions;
302 const int points_num = positions.size();
303
305 "pos", gpu::VertAttrType::SFLOAT_32_32_32);
307 GPU_vertbuf_data_alloc(vbo, handles_and_points_num(points_num, bezier_offsets));
308
310 data.take_front(positions.size()).copy_from(positions);
311
312 if (!bezier_curves.is_empty()) {
313 /* TODO: Use deformed left_handle_positions and left_handle_positions. */
314 const std::optional<Span<float3>> handles_left = curves.handle_positions_left();
315 const std::optional<Span<float3>> handles_right = curves.handle_positions_right();
316 if (handles_left && handles_right) {
318 points_by_curve,
319 bezier_offsets,
320 bezier_curves,
321 *handles_left,
322 data.slice(handle_range_left(points_num, bezier_offsets)));
324 points_by_curve,
325 bezier_offsets,
326 bezier_curves,
327 *handles_right,
328 data.slice(handle_range_right(points_num, bezier_offsets)));
329 }
330 }
331}
332
333static void create_edit_points_selection(const OffsetIndices<int> points_by_curve,
334 const IndexMask &bezier_curves,
335 const OffsetIndices<int> bezier_offsets,
336 const bke::AttributeAccessor attributes,
337 gpu::VertBuf &vbo)
338{
339 static const GPUVertFormat format_data = GPU_vertformat_from_attribute(
340 "selection", gpu::VertAttrType::SFLOAT_32);
341
342 const int points_num = points_by_curve.total_size();
343 GPU_vertbuf_init_with_format(vbo, format_data);
344 GPU_vertbuf_data_alloc(vbo, handles_and_points_num(points_num, bezier_offsets));
345 MutableSpan<float> data = vbo.data<float>();
346
347 const VArray attribute = *attributes.lookup_or_default<float>(
348 ".selection", bke::AttrDomain::Point, 1.0f);
349 attribute.materialize(data.take_front(points_num));
350
351 if (!bezier_curves.is_empty()) {
352 const VArray selection_left = *attributes.lookup_or_default<float>(
353 ".selection_handle_left", bke::AttrDomain::Point, 1.0f);
354 const VArray selection_right = *attributes.lookup_or_default<float>(
355 ".selection_handle_right", bke::AttrDomain::Point, 1.0f);
356
358 bezier_offsets,
359 bezier_curves,
360 selection_left,
361 data.slice(handle_range_left(points_num, bezier_offsets)));
363 bezier_offsets,
364 bezier_curves,
365 selection_right,
366 data.slice(handle_range_right(points_num, bezier_offsets)));
367 }
368}
369
370static void create_lines_ibo_no_cyclic(const OffsetIndices<int> points_by_curve,
371 gpu::IndexBuf &ibo)
372{
373 const int points_num = points_by_curve.total_size();
374 const int curves_num = points_by_curve.size();
375 const int indices_num = points_num + curves_num;
376 GPUIndexBufBuilder builder;
377 GPU_indexbuf_init(&builder, GPU_PRIM_LINE_STRIP, indices_num, points_num);
378 MutableSpan<uint> ibo_data = GPU_indexbuf_get_data(&builder);
379 threading::parallel_for(IndexRange(curves_num), 1024, [&](const IndexRange range) {
380 for (const int curve : range) {
381 const IndexRange points = points_by_curve[curve];
382 const IndexRange ibo_range = IndexRange(points.start() + curve, points.size() + 1);
383 for (const int i : points.index_range()) {
384 ibo_data[ibo_range[i]] = points[i];
385 }
386 ibo_data[ibo_range.last()] = gpu::RESTART_INDEX;
387 }
388 });
389 GPU_indexbuf_build_in_place_ex(&builder, 0, points_num, true, &ibo);
390}
391
392static void create_lines_ibo_with_cyclic(const OffsetIndices<int> points_by_curve,
393 const Span<bool> cyclic,
394 gpu::IndexBuf &ibo)
395{
396 const int points_num = points_by_curve.total_size();
397 const int curves_num = points_by_curve.size();
398 const int indices_num = points_num + curves_num * 2;
399 GPUIndexBufBuilder builder;
400 GPU_indexbuf_init(&builder, GPU_PRIM_LINE_STRIP, indices_num, points_num);
401 MutableSpan<uint> ibo_data = GPU_indexbuf_get_data(&builder);
402 threading::parallel_for(IndexRange(curves_num), 1024, [&](const IndexRange range) {
403 for (const int curve : range) {
404 const IndexRange points = points_by_curve[curve];
405 const IndexRange ibo_range = IndexRange(points.start() + curve * 2, points.size() + 2);
406 for (const int i : points.index_range()) {
407 ibo_data[ibo_range[i]] = points[i];
408 }
409 ibo_data[ibo_range.last(1)] = cyclic[curve] ? points.first() : gpu::RESTART_INDEX;
410 ibo_data[ibo_range.last()] = gpu::RESTART_INDEX;
411 }
412 });
413 GPU_indexbuf_build_in_place_ex(&builder, 0, points_num, true, &ibo);
414}
415
416static void create_lines_ibo_with_cyclic(const OffsetIndices<int> points_by_curve,
417 const VArray<bool> &cyclic,
418 gpu::IndexBuf &ibo)
419{
421 if (cyclic_mix == array_utils::BooleanMix::AllFalse) {
422 create_lines_ibo_no_cyclic(points_by_curve, ibo);
423 }
424 else {
425 const VArraySpan<bool> cyclic_span(cyclic);
426 create_lines_ibo_with_cyclic(points_by_curve, cyclic_span, ibo);
427 }
428}
429
430static void create_segments_with_cyclic(const OffsetIndices<int> points_by_curve,
431 const VArray<bool> &cyclic,
432 const IndexMask &selection,
433 MutableSpan<uint2> lines)
434{
435 selection.foreach_index(GrainSize(512), [&](const int curve) {
436 const IndexRange points = points_by_curve[curve];
437 MutableSpan<uint2> curve_lines = lines.slice(points);
438 for (const int i : points.index_range().drop_back(1)) {
439 curve_lines[i] = uint2(points[i]) + uint2(0, 1);
440 }
441 if (cyclic[curve]) {
442 curve_lines.last() = uint2(points.first(), points.last());
443 }
444 else {
445 curve_lines.last() = uint2(points.last(), points.last());
446 }
447 });
448}
449
450static void calc_edit_handles_ibo(const OffsetIndices<int> points_by_curve,
451 const IndexMask &catmull_rom_curves,
452 const IndexMask &poly_curves,
453 const IndexMask &bezier_curves,
454 const IndexMask &nurbs_curves,
455 const OffsetIndices<int> bezier_offsets,
456 const VArray<bool> &cyclic,
457 gpu::IndexBuf &ibo)
458{
459 /* All curve types have poly-line segments draw of original (non-evaluate) topology to connect
460 * control points. Bezier have exception -- instead there is left and right handle segments. Left
461 * bezier handle segments point to original and handle points and lie at index of curve segment.
462 * Right bezier handle segments point to original and handle points and lie in a sequence after
463 * all other segments. */
464 const int points_num = points_by_curve.total_size();
465 const int extra_bezier_segments = bezier_offsets.total_size();
466
467 /* TODO: Use linestrip if there is no bezier curves. */
468 GPUIndexBufBuilder builder;
469 GPU_indexbuf_init(&builder,
471 points_num + extra_bezier_segments,
472 handles_and_points_num(points_num, bezier_offsets));
474 BLI_assert(lines.size() == points_num + extra_bezier_segments);
475 MutableSpan<uint2> curve_or_handle_segments = lines.take_front(points_num);
476
477#ifdef NDEBUG
478 lines.fill(uint2(std::numeric_limits<uint32_t>::min()));
479#endif
480
482 points_by_curve, cyclic, catmull_rom_curves, curve_or_handle_segments);
483 create_segments_with_cyclic(points_by_curve, cyclic, poly_curves, curve_or_handle_segments);
484 create_segments_with_cyclic(points_by_curve, cyclic, nurbs_curves, curve_or_handle_segments);
485
486 const IndexRange handles_left = handle_range_left(points_num, bezier_offsets);
487 const IndexRange handles_right = handle_range_right(points_num, bezier_offsets);
488
489 bezier_curves.foreach_index(GrainSize(512), [&](const int curve, const int pos) {
490 const IndexRange points = points_by_curve[curve];
491 const IndexRange bezier_point_range = bezier_offsets[pos];
492 for (const int i : points.index_range()) {
493 const int point = points[i];
494 const int bezier_point = bezier_point_range[i];
495 curve_or_handle_segments[point] = uint2(handles_left[bezier_point], point);
496 }
497 });
498
499 MutableSpan<uint2> right_handle_segments = lines.drop_front(points_num);
500 bezier_curves.foreach_index(GrainSize(512), [&](const int curve, const int pos) {
501 const IndexRange points = points_by_curve[curve];
502 const IndexRange bezier_point_range = bezier_offsets[pos];
503 for (const int i : points.index_range()) {
504 const int point = points[i];
505 const int bezier_point = bezier_point_range[i];
506 right_handle_segments[bezier_point] = uint2(handles_right[bezier_point], point);
507 }
508 });
509
510 BLI_assert(!lines.contains(uint2(std::numeric_limits<uint32_t>::min())));
511
513 &builder, 0, handles_and_points_num(points_num, bezier_offsets), false, &ibo);
514}
515
517 const StringRef /*name*/,
519{
522 /* Create a destination buffer for the evaluation. Sized appropriately */
524 return buf;
525}
526
528 const StringRef name,
529 const GPUVertFormat &format,
530 bool &r_is_point_domain)
531{
534
535 const bke::AttributeAccessor attributes = curves.wrap().attributes();
536
537 /* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done
538 * by OpenGL to float4 for a scalar `s` will produce a `float4(s, 0, 0, 1)`. However, following
539 * the Blender convention, it should be `float4(s, s, s, 1)`. This could be resolved using a
540 * similar texture state swizzle to map the attribute correctly as for volume attributes, so we
541 * can control the conversion ourselves. */
543
544 if (!attribute) {
545 /* Attribute doesn't exist or is of an incompatible type.
546 * Replace it with a black curve domain attribute. */
547 /* TODO(fclem): Eventually, this should become unecessary if merge all attributes in one buffer
548 * and use an indirection table. */
549 GPU_vertbuf_data_alloc(*vbo, curves.curves_num());
550 vbo->data<ColorGeometry4f>().fill({0.0f, 0.0f, 0.0f, 1.0f});
551 r_is_point_domain = false;
552 return vbo;
553 }
554
555 r_is_point_domain = attribute.domain == bke::AttrDomain::Point;
556 GPU_vertbuf_data_alloc(*vbo, r_is_point_domain ? curves.points_num() : curves.curves_num());
557 attribute.varray.materialize(vbo->data<ColorGeometry4f>());
558 return vbo;
559}
560
561static std::optional<StringRef> get_first_uv_name(const bke::AttributeAccessor &attributes)
562{
563 std::optional<StringRef> name;
564 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
565 if (iter.data_type == bke::AttrType::Float2) {
566 name = iter.name;
567 iter.stop();
568 }
569 });
570 return name;
571}
572
573static void request_attribute(Curves &curves, const StringRef name)
574{
576
577 VectorSet<std::string> attributes{};
578
579 bke::CurvesGeometry &curves_geometry = curves.geometry.wrap();
580 if (!curves_geometry.attributes().contains(name)) {
581 return;
582 }
583 drw_attributes_add_request(&attributes, name);
584
585 drw_attributes_merge(&cache.attr_used, &attributes);
586}
587
588void drw_curves_get_attribute_sampler_name(const StringRef layer_name, char r_sampler_name[32])
589{
590 char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
591 GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
592 /* Attributes use auto-name. */
593 BLI_snprintf_utf8(r_sampler_name, 32, "a%s", attr_safe_name);
594}
595
597 const bke::CurvesGeometry &curves,
598 const StringRef name,
599 const int index)
600{
601 char sampler_name[32];
603
604 GPUVertFormat format = {0};
605 /* All attributes use float4, see comment below. */
606 /* TODO(fclem): Other types. */
607 GPU_vertformat_attr_add(&format, sampler_name, blender::gpu::VertAttrType::SFLOAT_32_32_32_32);
608
610 curves, name, format, attributes_point_domain[index]);
611
612 /* Existing final data may have been for a different attribute (with a different name or domain),
613 * free the data. */
614 this->evaluated_attributes_buf[index].reset();
615
616 /* Ensure final data for points. */
617 if (attributes_point_domain[index]) {
618 this->ensure_common(curves);
620 this->ensure_bezier(curves);
621 }
623 this->ensure_nurbs(curves);
624 }
625
627 format, name, evaluated_point_count_with_cyclic(curves));
628
629 module.evaluate_curve_attribute(curves.has_curve_with_type(CURVE_TYPE_CATMULL_ROM),
630 curves.has_curve_with_type(CURVE_TYPE_BEZIER),
631 curves.has_curve_with_type(CURVE_TYPE_POLY),
632 curves.has_curve_with_type(CURVE_TYPE_NURBS),
633 curves.has_cyclic_curve(),
634 curves.curves_num(),
635 *this,
636 CURVES_EVAL_FLOAT4,
637 std::move(attr_buf),
638 this->evaluated_attributes_buf[index]);
639 }
640 else {
641 this->curve_attributes_buf[index] = std::move(attr_buf);
642 }
643}
644
646 const bke::CurvesGeometry &curves,
647 const GPUMaterial *gpu_material)
648{
649 const bke::AttributeAccessor attributes = curves.attributes();
650
651 if (gpu_material) {
652 VectorSet<std::string> attrs_needed;
653 ListBase gpu_attrs = GPU_material_attributes(gpu_material);
654 LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
655 StringRef name = gpu_attr->name;
656 if (name.is_empty()) {
657 if (std::optional<StringRef> uv_name = get_first_uv_name(attributes)) {
658 drw_attributes_add_request(&attrs_needed, *uv_name);
659 }
660 }
661 if (!attributes.contains(name)) {
662 continue;
663 }
664 drw_attributes_add_request(&attrs_needed, name);
665 }
666
667 if (!drw_attributes_overlap(&attr_used, &attrs_needed)) {
668 /* Some new attributes have been added, free all and start over. */
669 for (const int i : IndexRange(GPU_MAX_ATTR)) {
670 this->curve_attributes_buf[i].reset();
671 this->evaluated_attributes_buf[i].reset();
672 }
673 drw_attributes_merge(&attr_used, &attrs_needed);
674 }
676 }
677
678 for (const int i : attr_used.index_range()) {
679 if (this->curve_attributes_buf[i] || this->evaluated_attributes_buf[i]) {
680 continue;
681 }
682 ensure_attribute(module, curves, attr_used[i], i);
683 }
684}
685
687{
688 if (this->points_by_curve_buf) {
689 return;
690 }
693 curves.evaluated_points_by_curve().data());
694
695 /* TODO(fclem): Optimize shaders to avoid needing to upload this data if data is uniform.
696 * This concerns all varray. */
700}
701
703{
704 if (this->handles_positions_left_buf) {
705 return;
706 }
707 const Span<float3> left = curves.handle_positions_left().value_or(curves.positions());
708 const Span<float3> right = curves.handle_positions_right().value_or(curves.positions());
712 curves.runtime->evaluated_offsets_cache.data().all_bezier_offsets.as_span());
713}
714
716{
717 if (curves_order_buf) {
718 return;
719 }
720 using BasisCache = bke::curves::nurbs::BasisCache;
721
722 /* TODO(fclem): Optimize shaders to avoid needing to upload this data if data is uniform.
723 * This concerns all varray. */
725 if (curves.nurbs_weights().has_value()) {
727 }
728
730
731 const Span<BasisCache> nurbs_basis_cache = curves.runtime->nurbs_basis_cache.data();
732
733 Vector<int> basis_cache_offset;
734 Vector<uint32_t> basis_cache_packed;
735 for (const BasisCache &cache : nurbs_basis_cache) {
736 basis_cache_offset.append(cache.invalid ? -1 : basis_cache_packed.size());
737 if (!cache.invalid) {
738 basis_cache_packed.extend(cache.start_indices.as_span().cast<uint32_t>());
739 basis_cache_packed.extend(cache.weights.as_span().cast<uint32_t>());
740 }
741 }
742 /* Ensure buffer is not empty. */
743 if (basis_cache_packed.is_empty()) {
744 basis_cache_packed.append(0);
745 }
746
747 this->basis_cache_offset_buf = gpu::VertBuf::from_span(basis_cache_offset.as_span());
748 this->basis_cache_buf = gpu::VertBuf::from_span(basis_cache_packed.as_span());
749}
750
751int CurvesEvalCache::evaluated_point_count_with_cyclic(const bke::CurvesGeometry &curves)
752{
753 if (curves.has_cyclic_curve()) {
754 return curves.evaluated_points_num() + curves.curves_num();
755 }
756 return curves.evaluated_points_num();
757}
758
760{
762 return;
763 }
764
765 if (curves.is_empty()) {
766 /* Can happen when called from `curves_pos_buffer_get()`. Caller has to deal with nullptr. */
767 return;
768 }
769
770 this->ensure_common(curves);
772 this->ensure_bezier(curves);
773 }
775 this->ensure_nurbs(curves);
776 }
777
778 /* TODO(fclem): Optimize shaders to avoid needing to upload this data if data is uniform.
779 * This concerns all varray. */
780 gpu::VertBufPtr points_pos_buf = gpu::VertBuf::from_span(curves.positions());
781 gpu::VertBufPtr points_rad_buf = gpu::VertBuf::from_varray(curves.radius());
782
784 evaluated_point_count_with_cyclic(curves));
785
786 module.evaluate_positions(curves.has_curve_with_type(CURVE_TYPE_CATMULL_ROM),
787 curves.has_curve_with_type(CURVE_TYPE_BEZIER),
788 curves.has_curve_with_type(CURVE_TYPE_POLY),
789 curves.has_curve_with_type(CURVE_TYPE_NURBS),
790 curves.has_cyclic_curve(),
791 curves.curves_num(),
792 *this,
793 std::move(points_pos_buf),
794 std::move(points_rad_buf),
795 evaluated_pos_rad_buf);
796
797 /* TODO(fclem): Make time and length optional. */
799 evaluated_point_count_with_cyclic(curves));
801
802 module.evaluate_curve_length_intercept(curves.has_cyclic_curve(), curves.curves_num(), *this);
803}
804
806 const bke::CurvesGeometry &curves,
807 const int face_per_segment)
808{
809 const bool is_ribbon = face_per_segment < 2;
810
811 gpu::VertBufPtr &indirection_buf = is_ribbon ? this->indirection_ribbon_buf :
813 if (indirection_buf) {
814 return indirection_buf;
815 }
816
817 this->ensure_common(curves);
818
819 indirection_buf = module.evaluate_topology_indirection(curves.curves_num(),
820 curves.evaluated_points_num(),
821 *this,
822 is_ribbon,
823 curves.has_cyclic_curve());
824
825 return indirection_buf;
826}
827
828gpu::Batch *CurvesEvalCache::batch_get(const int evaluated_point_count,
829 const int curve_count,
830 const int face_per_segment,
831 const bool use_cyclic,
832 bool &r_over_limit)
833{
834 gpu::Batch *&batch = this->batch[face_per_segment];
835 if (batch) {
836 return batch;
837 }
838
839 int64_t segment_count = 0;
840 int64_t vert_per_segment = 0;
841 GPUPrimType prim_type = GPU_PRIM_NONE;
842
843 if (face_per_segment == 0) {
844 /* Add one point per curve to restart the primitive. */
845 segment_count = int64_t(evaluated_point_count) + curve_count;
846 if (use_cyclic) {
847 segment_count += curve_count;
848 }
849 /* The last segment is always a restart vertex. However, it is not accounted for inside the
850 * data buffers and can lead to out of bound reads (see #148914). */
851 segment_count -= (segment_count > 0) ? 1 : 0;
852 vert_per_segment = 1;
853 prim_type = GPU_PRIM_LINE_STRIP;
854 }
855 else if (face_per_segment == 1) {
856 /* Add one point per curve to restart the primitive. */
857 segment_count = int64_t(evaluated_point_count) + curve_count;
858 if (use_cyclic) {
859 segment_count += curve_count;
860 }
861 /* The last segment is always a restart vertex. However, it is not accounted for inside the
862 * data buffers and can lead to out of bound reads (see #148914). */
863 segment_count -= (segment_count > 0) ? 1 : 0;
864 vert_per_segment = 2;
865 prim_type = GPU_PRIM_TRI_STRIP;
866 }
867 else if (face_per_segment >= 2) {
868 segment_count = int64_t(evaluated_point_count) - curve_count;
869 if (use_cyclic) {
870 segment_count += curve_count;
871 }
872 /* Add one vertex per segment to restart the primitive. */
873 vert_per_segment = (face_per_segment + 1) * 2 + 1;
874 prim_type = GPU_PRIM_TRI_STRIP;
875 }
876
877 /* Since we rely on buffer textures for reading the indirection buffer we have to abide by their
878 * size limit. This size is low enough on NVidia to discard strands after 130,000,000 points.
879 * We detect this case and display an error message in the viewport. */
880 uint32_t texel_buffer_limit = GPU_max_buffer_texture_size();
881 /* We are also limited by the number of vertices in a batch, which is INT_MAX. */
882 int64_t segment_limit = std::min(int64_t(texel_buffer_limit), int64_t(INT_MAX));
883 if (segment_count > segment_limit) {
884 segment_count = segment_limit;
885 r_over_limit = true;
886 }
887 r_over_limit = false;
888
889 uint32_t vertex_count = segment_count * vert_per_segment;
890 batch = GPU_batch_create_procedural(prim_type, vertex_count);
891 return batch;
892}
893
895{
896 return get_batch_cache(curves_id).eval_cache;
897}
898
900{
901 CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
902 if (cache == nullptr) {
903 return;
904 }
905 switch (mode) {
907 cache->is_dirty = true;
908 break;
909 default:
911 }
912}
913
915{
916 if (!batch_cache_is_dirty(*curves)) {
917 clear_batch_cache(*curves);
918 init_batch_cache(*curves);
919 }
920}
921
923{
924 clear_batch_cache(*curves);
925 CurvesBatchCache *batch_cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
926 MEM_delete(batch_cache);
927 curves->batch_cache = nullptr;
928}
929
931{
932 CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
933 if (cache == nullptr) {
934 return;
935 }
936
937 bool do_discard = false;
938
939 CurvesEvalCache &eval_cache = cache->eval_cache;
940
941 if (drw_attributes_overlap(&eval_cache.attr_used_over_time, &eval_cache.attr_used)) {
942 eval_cache.last_attr_matching_time = ctime;
943 }
944
945 if (ctime - eval_cache.last_attr_matching_time > U.vbotimeout) {
946 do_discard = true;
947 }
948
949 eval_cache.attr_used_over_time.clear();
950
951 if (do_discard) {
953 }
954}
955
957{
958 CurvesBatchCache &cache = get_batch_cache(*curves);
959 return DRW_batch_request(&cache.edit_points);
960}
961
963{
964 CurvesBatchCache &cache = get_batch_cache(*curves);
965 return DRW_batch_request(&cache.sculpt_cage);
966}
967
969{
970 CurvesBatchCache &cache = get_batch_cache(*curves);
971 return DRW_batch_request(&cache.edit_handles);
972}
973
975{
976 CurvesBatchCache &cache = get_batch_cache(*curves);
978}
979
981 const StringRef name,
982 bool &r_is_point_domain,
983 bool &r_valid_attribute)
984{
986
987 request_attribute(*curves, name);
988
989 /* TODO(fclem): Remove Global access. */
991 cache.ensure_attributes(module, curves->geometry.wrap(), nullptr);
992
993 for (const int i : cache.attr_used.index_range()) {
994 if (cache.attr_used[i] == name) {
995 r_valid_attribute = true;
996 if (cache.attributes_point_domain[i]) {
997 r_is_point_domain = true;
998 return cache.evaluated_attributes_buf[i];
999 }
1000 r_is_point_domain = false;
1001 return cache.curve_attributes_buf[i];
1002 }
1003 }
1004 r_valid_attribute = false;
1005 r_is_point_domain = false;
1006 return cache.evaluated_attributes_buf[0];
1007}
1008
1010 const bke::CurvesGeometry &curves,
1011 const bke::crazyspace::GeometryDeformation & /*deformation*/,
1012 CurvesBatchCache &cache)
1013{
1015 "pos", gpu::VertAttrType::SFLOAT_32_32_32);
1016
1017 /* TODO: Deform curves using deformations. */
1018 const Span<float3> positions = curves.evaluated_positions();
1021 cache.edit_curves_lines_pos->data<float3>().copy_from(positions);
1022}
1023
1025{
1027 Object *ob_orig = DEG_get_original(ob);
1028 if (ob_orig == nullptr) {
1029 return;
1030 }
1031 const Curves &curves_orig_id = DRW_object_get_data_for_drawing<Curves>(*ob_orig);
1032
1034 const bke::CurvesGeometry &curves_orig = curves_orig_id.geometry.wrap();
1035
1036 bool is_edit_data_needed = false;
1037
1042 is_edit_data_needed = true;
1043 }
1049 is_edit_data_needed = true;
1050 }
1056 is_edit_data_needed = true;
1057 }
1061 }
1062
1063 const OffsetIndices<int> points_by_curve = curves_orig.points_by_curve();
1064 const VArray<bool> cyclic = curves_orig.cyclic();
1065
1066 const bke::crazyspace::GeometryDeformation deformation =
1067 is_edit_data_needed || DRW_vbo_requested(cache.edit_curves_lines_pos) ?
1070
1072 create_lines_ibo_no_cyclic(points_by_curve, *cache.sculpt_cage_ibo);
1073 }
1074
1076 create_edit_points_position_vbo(curves_orig, deformation, cache);
1077 }
1078
1081 curves_orig.evaluated_points_by_curve(), cyclic, *cache.edit_curves_lines_ibo);
1082 }
1083
1084 if (!is_edit_data_needed) {
1085 return;
1086 }
1087
1088 const IndexRange curves_range = curves_orig.curves_range();
1089 const VArray<int8_t> curve_types = curves_orig.curve_types();
1090 const std::array<int, CURVE_TYPES_NUM> type_counts = curves_orig.curve_type_counts();
1091 const bke::AttributeAccessor attributes = curves_orig.attributes();
1092
1093 IndexMaskMemory memory;
1094 const IndexMask catmull_rom_curves = bke::curves::indices_for_type(
1095 curve_types, type_counts, CURVE_TYPE_CATMULL_ROM, curves_range, memory);
1096 const IndexMask poly_curves = bke::curves::indices_for_type(
1097 curve_types, type_counts, CURVE_TYPE_POLY, curves_range, memory);
1098 const IndexMask bezier_curves = bke::curves::indices_for_type(
1099 curve_types, type_counts, CURVE_TYPE_BEZIER, curves_range, memory);
1100 const IndexMask nurbs_curves = bke::curves::indices_for_type(
1101 curve_types, type_counts, CURVE_TYPE_NURBS, curves_range, memory);
1102
1103 Array<int> bezier_point_offset_data(bezier_curves.size() + 1);
1105 points_by_curve, bezier_curves, bezier_point_offset_data);
1106
1108 create_edit_points_position(curves_orig,
1109 points_by_curve,
1110 bezier_curves,
1111 bezier_offsets,
1112 deformation,
1113 *cache.edit_points_pos);
1114 }
1116 create_edit_points_data(points_by_curve,
1117 catmull_rom_curves,
1118 poly_curves,
1119 bezier_curves,
1120 nurbs_curves,
1121 bezier_offsets,
1122 curves_orig,
1123 *cache.edit_points_data);
1124 }
1127 points_by_curve, bezier_curves, bezier_offsets, attributes, *cache.edit_points_selection);
1128 }
1130 calc_edit_handles_ibo(points_by_curve,
1131 catmull_rom_curves,
1132 poly_curves,
1133 bezier_curves,
1134 nurbs_curves,
1135 bezier_offsets,
1136 cyclic,
1137 *cache.edit_handles_ibo);
1138 }
1139}
1140
1141} // namespace blender::draw
@ BKE_CURVES_BATCH_DIRTY_ALL
Definition BKE_curves.h:37
Low-level operations for curves.
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
size_t size_t size_t BLI_snprintf_utf8(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
T * DEG_get_original(T *id)
Object is a sort of wrapper for general info.
T & DRW_object_get_data_for_drawing(const Object &object)
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:197
blender::gpu::Batch * GPU_batch_create_procedural(GPUPrimType primitive_type, int32_t vertex_count)
Definition gpu_batch.cc:83
uint32_t GPU_max_buffer_texture_size()
void GPU_indexbuf_build_in_place_ex(GPUIndexBufBuilder *builder, uint index_min, uint index_max, bool uses_restart_indices, blender::gpu::IndexBuf *elem)
blender::MutableSpan< uint32_t > GPU_indexbuf_get_data(GPUIndexBufBuilder *)
#define GPU_INDEXBUF_DISCARD_SAFE(elem)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
ListBase GPU_material_attributes(const GPUMaterial *material)
GPUPrimType
@ GPU_PRIM_NONE
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_PRIM_LINE_STRIP
@ GPU_PRIM_TRI_STRIP
static constexpr int GPU_MAX_ATTR
Definition GPU_shader.hh:33
blender::gpu::VertBuf * GPU_vertbuf_create_with_format_ex(const GPUVertFormat &format, GPUUsageType usage)
#define GPU_vertbuf_init_with_format(verts, format)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_USAGE_STATIC
@ GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY
@ GPU_USAGE_DEVICE_ONLY
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, blender::gpu::VertAttrType type)
void GPU_vertformat_safe_attr_name(blender::StringRef attr_name, char *r_safe_name, uint max_len)
static constexpr int GPU_MAX_SAFE_ATTR_NAME
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
Read Guarded memory(de)allocation.
#define U
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
IndexRange index_range() const
constexpr int64_t first() const
constexpr IndexRange drop_back(int64_t n) const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr IndexRange index_range() const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr bool contains(const T &value) const
Definition BLI_span.hh:715
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr MutableSpan< NewT > cast() const
Definition BLI_span.hh:749
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr MutableSpan drop_front(const int64_t n) const
Definition BLI_span.hh:607
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:629
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:689
constexpr int64_t size() const
Definition BLI_span.hh:252
int64_t size() const
void append(const T &value)
bool is_empty() const
void extend(Span< T > array)
Span< T > as_span() const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
bool contains(StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) const
VArray< int8_t > handle_types_left() const
OffsetIndices< int > points_by_curve() const
VArray< int8_t > handle_types_right() const
void ensure_can_interpolate_to_evaluated() const
IndexRange curves_range() const
const std::array< int, CURVE_TYPES_NUM > & curve_type_counts() const
VArray< float > radius() const
std::optional< Span< float > > nurbs_weights() const
VArray< int > resolution() const
std::optional< Span< float3 > > handle_positions_left() const
Span< float3 > positions() const
OffsetIndices< int > evaluated_points_by_curve() const
bool has_curve_with_type(CurveType type) const
std::optional< Span< float3 > > handle_positions_right() const
AttributeAccessor attributes() const
Span< float3 > evaluated_positions() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
VArray< int8_t > nurbs_orders() const
static VertBufPtr device_only(uint size)
static VertBufPtr from_varray(const VArray< T > &array)
static VertBufPtr from_span(const Span< T > data)
MutableSpan< T > data()
void foreach_index(Fn &&fn) const
Utilities for rendering attributes.
#define EDIT_CURVES_ACTIVE_HANDLE
#define EDIT_CURVES_HANDLE_TYPES_SHIFT
#define EDIT_CURVES_BEZIER_KNOT
#define EDIT_CURVES_BEZIER_HANDLE
#define EDIT_CURVES_NURBS_CONTROL_POINT
bool DRW_batch_requested(blender::gpu::Batch *batch, GPUPrimType prim_type)
blender::gpu::Batch * DRW_batch_request(blender::gpu::Batch **batch)
void DRW_vbo_request(blender::gpu::Batch *batch, blender::gpu::VertBuf **vbo)
bool DRW_vbo_requested(blender::gpu::VertBuf *vbo)
void DRW_ibo_request(blender::gpu::Batch *batch, blender::gpu::IndexBuf **ibo)
bool DRW_ibo_requested(blender::gpu::IndexBuf *ibo)
DRWContext & drw_get()
uint pos
format
static int left
void gather_group_to_group(const OffsetIndices< int > src_offsets, const OffsetIndices< int > dst_offsets, const IndexMask &selection, const Span< T > src, MutableSpan< T > dst)
BooleanMix booleans_mix_calc(const VArray< bool > &varray, IndexRange range_to_check)
int64_t count_booleans(const VArray< bool > &varray)
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig)
IndexMask indices_for_type(const VArray< int8_t > &types, const std::array< int, CURVE_TYPES_NUM > &type_counts, const CurveType type, const IndexMask &selection, IndexMaskMemory &memory)
void drw_attributes_add_request(VectorSet< std::string > *attrs, const StringRef name)
static void create_segments_with_cyclic(const OffsetIndices< int > points_by_curve, const VArray< bool > &cyclic, const IndexMask &selection, MutableSpan< uint2 > lines)
void DRW_curves_batch_cache_validate(Curves *curves)
static void request_attribute(Curves &curves, const StringRef name)
static void calc_edit_handles_ibo(const OffsetIndices< int > points_by_curve, const IndexMask &catmull_rom_curves, const IndexMask &poly_curves, const IndexMask &bezier_curves, const IndexMask &nurbs_curves, const OffsetIndices< int > bezier_offsets, const VArray< bool > &cyclic, gpu::IndexBuf &ibo)
static gpu::VertBufPtr alloc_evaluated_point_attribute_vbo(const GPUVertFormat &format, const StringRef, int64_t size)
blender::gpu::Batch * DRW_curves_batch_cache_get_edit_points(Curves *curves)
static bool batch_cache_is_dirty(const Curves &curves)
void DRW_curves_batch_cache_free_old(Curves *curves, int ctime)
CurvesEvalCache & curves_get_eval_cache(Curves &curves_id)
static gpu::VertBufPtr ensure_control_point_attribute(const bke::CurvesGeometry &curves, const StringRef name, const GPUVertFormat &format, bool &r_is_point_domain)
static void clear_edit_data(CurvesBatchCache *cache)
static void create_edit_points_selection(const OffsetIndices< int > points_by_curve, const IndexMask &bezier_curves, const OffsetIndices< int > bezier_offsets, const bke::AttributeAccessor attributes, gpu::VertBuf &vbo)
blender::gpu::Batch * DRW_curves_batch_cache_get_edit_curves_handles(Curves *curves)
static std::optional< StringRef > get_first_uv_name(const bke::AttributeAccessor &attributes)
static void init_batch_cache(Curves &curves)
blender::gpu::Batch * DRW_curves_batch_cache_get_sculpt_curves_cage(Curves *curves)
static void create_lines_ibo_with_cyclic(const OffsetIndices< int > points_by_curve, const Span< bool > cyclic, gpu::IndexBuf &ibo)
void drw_curves_get_attribute_sampler_name(const StringRef layer_name, char r_sampler_name[32])
static void create_edit_points_position_vbo(const bke::CurvesGeometry &curves, const bke::crazyspace::GeometryDeformation &, CurvesBatchCache &cache)
static void clear_batch_cache(Curves &curves)
static CurvesBatchCache & get_batch_cache(Curves &curves)
void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
static uint32_t bezier_data_value(int8_t handle_type, bool is_active)
bool drw_attributes_overlap(const VectorSet< std::string > *a, const VectorSet< std::string > *b)
static void create_edit_points_data(const OffsetIndices< int > points_by_curve, const IndexMask &catmull_rom_curves, const IndexMask &poly_curves, const IndexMask &bezier_curves, const IndexMask &nurbs_curves, const OffsetIndices< int > bezier_offsets, const bke::CurvesGeometry &curves, gpu::VertBuf &vbo)
static void create_edit_points_position(const bke::CurvesGeometry &curves, const OffsetIndices< int > points_by_curve, const IndexMask &bezier_curves, const OffsetIndices< int > bezier_offsets, const bke::crazyspace::GeometryDeformation deformation, gpu::VertBuf &vbo)
static void extract_edit_data(const OffsetIndices< int > points_by_curve, const IndexMask &curve_selection, const VArray< bool > &selection_attr, const bool mark_active, const uint32_t fill_value, MutableSpan< uint32_t > data)
static void create_lines_ibo_no_cyclic(const OffsetIndices< int > points_by_curve, gpu::IndexBuf &ibo)
blender::gpu::Batch * DRW_curves_batch_cache_get_edit_curves_lines(Curves *curves)
static IndexRange handle_range_right(const int points_num, const OffsetIndices< int > bezier_offsets)
void drw_attributes_merge(VectorSet< std::string > *dst, const VectorSet< std::string > *src)
static IndexRange handle_range_left(const int points_num, const OffsetIndices< int > bezier_offsets)
blender::gpu::VertBufPtr & DRW_curves_texture_for_evaluated_attribute(Curves *curves, StringRef name, bool &r_is_point_domain, bool &r_valid_attribute)
void DRW_curves_batch_cache_free(Curves *curves)
void DRW_curves_batch_cache_create_requested(Object *ob)
static int handles_and_points_num(const int points_num, const OffsetIndices< int > bezier_offsets)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
constexpr uint32_t RESTART_INDEX
OffsetIndices< int > gather_selected_offsets(OffsetIndices< int > src_offsets, const IndexMask &selection, int start_offset, MutableSpan< int > dst_offsets)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< uint32_t, 2 > uint2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
static struct PyModuleDef module
Definition python.cpp:796
const char * name
CurvesGeometryRuntimeHandle * runtime
CurvesGeometry geometry
void * batch_cache
DRWData * data
blender::draw::CurvesModule * curves_module
gpu::VertBufPtr evaluated_attributes_buf[GPU_MAX_ATTR]
void ensure_bezier(const bke::CurvesGeometry &curves)
std::array< gpu::Batch *, MAX_FACE_PER_SEGMENT > batch
std::array< bool, GPU_MAX_ATTR > attributes_point_domain
void ensure_common(const bke::CurvesGeometry &curves)
gpu::Batch * batch_get(int evaluated_point_count, int curve_count, int face_per_segment, bool use_cyclic, bool &r_over_limit)
gpu::VertBufPtr & indirection_buf_get(CurvesModule &module, const bke::CurvesGeometry &curves, int face_per_segment)
void ensure_attributes(struct CurvesModule &module, const bke::CurvesGeometry &curves, const GPUMaterial *gpu_material)
void ensure_positions(CurvesModule &module, const bke::CurvesGeometry &curves)
gpu::VertBufPtr curve_attributes_buf[GPU_MAX_ATTR]
VectorSet< std::string > attr_used_over_time
VectorSet< std::string > attr_used
void ensure_attribute(struct CurvesModule &module, const bke::CurvesGeometry &curves, StringRef name, int index)
void ensure_nurbs(const bke::CurvesGeometry &curves)
i
Definition text_draw.cc:230