Blender V4.5
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.h"
22#include "BLI_task.hh"
23#include "BLI_utildefines.h"
24
25#include "DNA_curves_types.h"
26#include "DNA_object_types.h"
27#include "DNA_userdef_types.h"
28
30
31#include "BKE_crazyspace.hh"
32#include "BKE_curves.hh"
33#include "BKE_curves_utils.hh"
34#include "BKE_customdata.hh"
35#include "BKE_geometry_set.hh"
36
37#include "GPU_batch.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"
47#include "draw_curves_private.hh" /* own include */
48
49namespace blender::draw {
50
51#define EDIT_CURVES_NURBS_CONTROL_POINT (1u)
52#define EDIT_CURVES_BEZIER_HANDLE (1u << 1)
53#define EDIT_CURVES_ACTIVE_HANDLE (1u << 2)
54/* Bezier curve control point lying on the curve.
55 * The one between left and right handles. */
56#define EDIT_CURVES_BEZIER_KNOT (1u << 3)
57#define EDIT_CURVES_HANDLE_TYPES_SHIFT (4u)
58
59/* ---------------------------------------------------------------------- */
60
63
64 gpu::Batch *edit_points;
65 gpu::Batch *edit_handles;
66
67 gpu::Batch *sculpt_cage;
69
70 /* Crazy-space point positions for original points. */
72
73 /* Additional data needed for shader to choose color for each point in edit_points_pos.
74 * If first bit is set, then point is NURBS control point. EDIT_CURVES_NURBS_CONTROL_POINT is
75 * used to set and test. If second, then point is Bezier handle point. Set and tested with
76 * EDIT_CURVES_BEZIER_HANDLE.
77 * In Bezier case two handle types of HandleType are also encoded.
78 * Byte structure for Bezier knot point (handle middle point):
79 * | left handle type | right handle type | | BEZIER| NURBS|
80 * | 7 6 | 5 4 | 3 2 | 1 | 0 |
81 *
82 * If it is left or right handle point, then same handle type is repeated in both slots.
83 */
85
86 /* Selection of original points. */
88
90
91 gpu::Batch *edit_curves_lines;
94
95 /* Whether the cache is invalid. */
97
104};
105
106static bool batch_cache_is_dirty(const Curves &curves)
107{
108 const CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache);
109 return (cache && cache->is_dirty == false);
110}
111
112static void init_batch_cache(Curves &curves)
113{
114 CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache);
115
116 if (!cache) {
117 cache = MEM_new<CurvesBatchCache>(__func__);
118 curves.batch_cache = cache;
119 }
120 else {
121 cache->eval_cache = {};
122 }
123
124 cache->is_dirty = false;
125}
126
127static void discard_attributes(CurvesEvalCache &eval_cache)
128{
129 for (const int i : IndexRange(GPU_MAX_ATTR)) {
131 }
132
133 for (const int j : IndexRange(GPU_MAX_ATTR)) {
135 }
136
137 eval_cache.final.attr_used.clear();
138}
139
158
159static void clear_final_data(CurvesEvalFinalCache &final_cache)
160{
163 for (const int j : IndexRange(GPU_MAX_ATTR)) {
165 }
166}
167
168static void clear_eval_data(CurvesEvalCache &eval_cache)
169{
170 /* TODO: more granular update tagging. */
175
176 clear_final_data(eval_cache.final);
177
178 discard_attributes(eval_cache);
179}
180
181static void clear_batch_cache(Curves &curves)
182{
183 CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves.batch_cache);
184 if (!cache) {
185 return;
186 }
187
189 clear_edit_data(cache);
190}
191
193{
195 return *static_cast<CurvesBatchCache *>(curves.batch_cache);
196}
197
202
203static void fill_points_position_time_vbo(const OffsetIndices<int> points_by_curve,
204 const Span<float3> positions,
206 MutableSpan<float> hairLength_data)
207{
208 threading::parallel_for(points_by_curve.index_range(), 1024, [&](const IndexRange range) {
209 for (const int i_curve : range) {
210 const IndexRange points = points_by_curve[i_curve];
211
212 Span<float3> curve_positions = positions.slice(points);
213 MutableSpan<PositionAndParameter> curve_posTime_data = posTime_data.slice(points);
214
215 float total_len = 0.0f;
216 for (const int i_point : curve_positions.index_range()) {
217 if (i_point > 0) {
218 total_len += math::distance(curve_positions[i_point - 1], curve_positions[i_point]);
219 }
220 curve_posTime_data[i_point].position = curve_positions[i_point];
221 curve_posTime_data[i_point].parameter = total_len;
222 }
223 hairLength_data[i_curve] = total_len;
224
225 /* Assign length value. */
226 if (total_len > 0.0f) {
227 const float factor = 1.0f / total_len;
228 /* Divide by total length to have a [0-1] number. */
229 for (const int i_point : curve_positions.index_range()) {
230 curve_posTime_data[i_point].parameter *= factor;
231 }
232 }
233 }
234 });
235}
236
238 CurvesEvalCache &cache)
239{
240 GPUVertFormat format = {0};
242
246
247 GPUVertFormat length_format = {0};
248 GPU_vertformat_attr_add(&length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
249
253
254 /* TODO: Only create hairLength VBO when necessary. */
256 curves.positions(),
258 cache.proc_length_buf->data<float>());
259}
260
261static uint32_t bezier_data_value(int8_t handle_type, bool is_active)
262{
264 (is_active ? EDIT_CURVES_ACTIVE_HANDLE : 0);
265}
266
267static int handles_and_points_num(const int points_num, const OffsetIndices<int> bezier_offsets)
268{
269 return points_num + bezier_offsets.total_size() * 2;
270}
271
272static IndexRange handle_range_left(const int points_num, const OffsetIndices<int> bezier_offsets)
273{
274 return IndexRange(points_num, bezier_offsets.total_size());
275}
276
277static IndexRange handle_range_right(const int points_num, const OffsetIndices<int> bezier_offsets)
278{
279 return IndexRange(points_num + bezier_offsets.total_size(), bezier_offsets.total_size());
280}
281
282static void extract_edit_data(const OffsetIndices<int> points_by_curve,
283 const IndexMask &curve_selection,
284 const VArray<bool> &selection_attr,
285 const bool mark_active,
286 const uint32_t fill_value,
288{
289 curve_selection.foreach_index(GrainSize(256), [&](const int curve) {
290 const IndexRange points = points_by_curve[curve];
291 bool is_active = false;
292 if (mark_active) {
293 is_active = array_utils::count_booleans(selection_attr, points) > 0;
294 }
295 uint32_t data_value = fill_value | (is_active ? EDIT_CURVES_ACTIVE_HANDLE : 0u);
296 data.slice(points).fill(data_value);
297 });
298}
299
300static void create_edit_points_data(const OffsetIndices<int> points_by_curve,
301 const IndexMask &catmull_rom_curves,
302 const IndexMask &poly_curves,
303 const IndexMask &bezier_curves,
304 const IndexMask &nurbs_curves,
305 const OffsetIndices<int> bezier_offsets,
306 const bke::CurvesGeometry &curves,
307 gpu::VertBuf &vbo)
308{
309 const int points_num = points_by_curve.total_size();
310 const bke::AttributeAccessor attributes = curves.attributes();
311 const VArray selection = *attributes.lookup_or_default<bool>(
312 ".selection", bke::AttrDomain::Point, true);
313
315 "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
317 GPU_vertbuf_data_alloc(vbo, handles_and_points_num(points_num, bezier_offsets));
318 MutableSpan<uint32_t> data = vbo.data<uint32_t>();
319
320 extract_edit_data(points_by_curve, catmull_rom_curves, selection, false, 0, data);
321
322 extract_edit_data(points_by_curve, poly_curves, selection, false, 0, data);
323
324 if (!bezier_curves.is_empty()) {
325 const VArray<int8_t> type_right = curves.handle_types_left();
326 const VArray<int8_t> types_left = curves.handle_types_right();
327 const VArray selection_left = *attributes.lookup_or_default<bool>(
328 ".selection_handle_left", bke::AttrDomain::Point, true);
329 const VArray selection_right = *attributes.lookup_or_default<bool>(
330 ".selection_handle_right", bke::AttrDomain::Point, true);
331
332 MutableSpan data_left = data.slice(handle_range_left(points_num, bezier_offsets));
333 MutableSpan data_right = data.slice(handle_range_right(points_num, bezier_offsets));
334
335 bezier_curves.foreach_index(GrainSize(256), [&](const int curve, const int64_t pos) {
336 const IndexRange points = points_by_curve[curve];
337 const IndexRange bezier_range = bezier_offsets[pos];
338 for (const int i : points.index_range()) {
339 const int point = points[i];
341
342 const bool selected = selection[point] || selection_left[point] || selection_right[point];
343 const int bezier_point = bezier_range[i];
344 data_left[bezier_point] = bezier_data_value(type_right[point], selected);
345 data_right[bezier_point] = bezier_data_value(types_left[point], selected);
346 }
347 });
348 }
349
351 points_by_curve, nurbs_curves, selection, true, EDIT_CURVES_NURBS_CONTROL_POINT, data);
352}
353
355 const OffsetIndices<int> points_by_curve,
356 const IndexMask &bezier_curves,
357 const OffsetIndices<int> bezier_offsets,
358 const bke::crazyspace::GeometryDeformation deformation,
359 gpu::VertBuf &vbo)
360{
361 const Span<float3> positions = deformation.positions;
362 const int points_num = positions.size();
363
365 "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
367 GPU_vertbuf_data_alloc(vbo, handles_and_points_num(points_num, bezier_offsets));
368
370 data.take_front(positions.size()).copy_from(positions);
371
372 /* TODO: Use deformed left_handle_positions and left_handle_positions. */
374 bezier_offsets,
375 bezier_curves,
376 curves.handle_positions_left(),
377 data.slice(handle_range_left(points_num, bezier_offsets)));
379 bezier_offsets,
380 bezier_curves,
381 curves.handle_positions_right(),
382 data.slice(handle_range_right(points_num, bezier_offsets)));
383}
384
385static void create_edit_points_selection(const OffsetIndices<int> points_by_curve,
386 const IndexMask &bezier_curves,
387 const OffsetIndices<int> bezier_offsets,
388 const bke::AttributeAccessor attributes,
389 gpu::VertBuf &vbo)
390{
391 static const GPUVertFormat format_data = GPU_vertformat_from_attribute(
392 "selection", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
393
394 const int points_num = points_by_curve.total_size();
395 GPU_vertbuf_init_with_format(vbo, format_data);
396 GPU_vertbuf_data_alloc(vbo, handles_and_points_num(points_num, bezier_offsets));
397 MutableSpan<float> data = vbo.data<float>();
398
399 const VArray attribute = *attributes.lookup_or_default<float>(
400 ".selection", bke::AttrDomain::Point, 1.0f);
401 attribute.materialize(data.take_front(points_num));
402
403 if (bezier_curves.is_empty()) {
404 return;
405 }
406
407 const VArray selection_left = *attributes.lookup_or_default<float>(
408 ".selection_handle_left", bke::AttrDomain::Point, 1.0f);
409 const VArray selection_right = *attributes.lookup_or_default<float>(
410 ".selection_handle_right", bke::AttrDomain::Point, 1.0f);
411
413 bezier_offsets,
414 bezier_curves,
415 selection_left,
416 data.slice(handle_range_left(points_num, bezier_offsets)));
418 bezier_offsets,
419 bezier_curves,
420 selection_right,
421 data.slice(handle_range_right(points_num, bezier_offsets)));
422}
423
424static void create_lines_ibo_no_cyclic(const OffsetIndices<int> points_by_curve,
425 gpu::IndexBuf &ibo)
426{
427 const int points_num = points_by_curve.total_size();
428 const int curves_num = points_by_curve.size();
429 const int indices_num = points_num + curves_num;
430 GPUIndexBufBuilder builder;
431 GPU_indexbuf_init(&builder, GPU_PRIM_LINE_STRIP, indices_num, points_num);
432 MutableSpan<uint> ibo_data = GPU_indexbuf_get_data(&builder);
433 threading::parallel_for(IndexRange(curves_num), 1024, [&](const IndexRange range) {
434 for (const int curve : range) {
435 const IndexRange points = points_by_curve[curve];
436 const IndexRange ibo_range = IndexRange(points.start() + curve, points.size() + 1);
437 for (const int i : points.index_range()) {
438 ibo_data[ibo_range[i]] = points[i];
439 }
440 ibo_data[ibo_range.last()] = gpu::RESTART_INDEX;
441 }
442 });
443 GPU_indexbuf_build_in_place_ex(&builder, 0, points_num, true, &ibo);
444}
445
446static void create_lines_ibo_with_cyclic(const OffsetIndices<int> points_by_curve,
447 const Span<bool> cyclic,
448 gpu::IndexBuf &ibo)
449{
450 const int points_num = points_by_curve.total_size();
451 const int curves_num = points_by_curve.size();
452 const int indices_num = points_num + curves_num * 2;
453 GPUIndexBufBuilder builder;
454 GPU_indexbuf_init(&builder, GPU_PRIM_LINE_STRIP, indices_num, points_num);
455 MutableSpan<uint> ibo_data = GPU_indexbuf_get_data(&builder);
456 threading::parallel_for(IndexRange(curves_num), 1024, [&](const IndexRange range) {
457 for (const int curve : range) {
458 const IndexRange points = points_by_curve[curve];
459 const IndexRange ibo_range = IndexRange(points.start() + curve * 2, points.size() + 2);
460 for (const int i : points.index_range()) {
461 ibo_data[ibo_range[i]] = points[i];
462 }
463 ibo_data[ibo_range.last(1)] = cyclic[curve] ? points.first() : gpu::RESTART_INDEX;
464 ibo_data[ibo_range.last()] = gpu::RESTART_INDEX;
465 }
466 });
467 GPU_indexbuf_build_in_place_ex(&builder, 0, points_num, true, &ibo);
468}
469
470static void create_lines_ibo_with_cyclic(const OffsetIndices<int> points_by_curve,
471 const VArray<bool> &cyclic,
472 gpu::IndexBuf &ibo)
473{
475 if (cyclic_mix == array_utils::BooleanMix::AllFalse) {
476 create_lines_ibo_no_cyclic(points_by_curve, ibo);
477 }
478 else {
479 const VArraySpan<bool> cyclic_span(cyclic);
480 create_lines_ibo_with_cyclic(points_by_curve, cyclic_span, ibo);
481 }
482}
483
484static void extract_curve_lines(const OffsetIndices<int> points_by_curve,
485 const VArray<bool> &cyclic,
486 const IndexMask &selection,
487 const int cyclic_segment_offset,
488 MutableSpan<uint2> lines)
489{
490 selection.foreach_index(GrainSize(512), [&](const int curve) {
491 const IndexRange points = points_by_curve[curve];
492 MutableSpan<uint2> curve_lines = lines.slice(points.start() + cyclic_segment_offset,
493 points.size() + 1);
494 for (const int i : IndexRange(points.size() - 1)) {
495 const int point = points[i];
496 curve_lines[i] = uint2(point, point + 1);
497 }
498 if (cyclic[curve]) {
499 curve_lines.last() = uint2(points.first(), points.last());
500 }
501 else {
502 curve_lines.last() = uint2(points.last(), points.last());
503 }
504 });
505}
506
507static void calc_edit_handles_ibo(const OffsetIndices<int> points_by_curve,
508 const IndexMask &catmull_rom_curves,
509 const IndexMask &poly_curves,
510 const IndexMask &bezier_curves,
511 const IndexMask &nurbs_curves,
512 const OffsetIndices<int> bezier_offsets,
513 const VArray<bool> &cyclic,
514 gpu::IndexBuf &ibo)
515{
516 const int curves_num = points_by_curve.size();
517 const int points_num = points_by_curve.total_size();
518 const int non_bezier_points_num = points_num - bezier_offsets.total_size();
519 const int non_bezier_curves_num = curves_num - bezier_curves.size();
520
521 int lines_num = 0;
522 /* Lines for all non-cyclic non-Bezier segments. */
523 lines_num += non_bezier_points_num;
524 /* Lines for all potential non-Bezier cyclic segments. */
525 lines_num += non_bezier_curves_num;
526 /* Lines for all Bezier handles. */
527 lines_num += bezier_offsets.total_size() * 2;
528
529 GPUIndexBufBuilder builder;
531 &builder, GPU_PRIM_LINES, lines_num, handles_and_points_num(points_num, bezier_offsets));
533
534 int cyclic_segment_offset = 0;
535 extract_curve_lines(points_by_curve, cyclic, catmull_rom_curves, cyclic_segment_offset, lines);
536 cyclic_segment_offset += catmull_rom_curves.size();
537
538 extract_curve_lines(points_by_curve, cyclic, poly_curves, cyclic_segment_offset, lines);
539 cyclic_segment_offset += catmull_rom_curves.size();
540
541 if (!bezier_curves.is_empty()) {
542 const IndexRange handles_left = handle_range_left(points_num, bezier_offsets);
543 const IndexRange handles_right = handle_range_right(points_num, bezier_offsets);
544
545 MutableSpan lines_left = lines.slice(
546 handle_range_left(non_bezier_points_num, bezier_offsets).shift(non_bezier_curves_num));
547 MutableSpan lines_right = lines.slice(
548 handle_range_right(non_bezier_points_num, bezier_offsets).shift(non_bezier_curves_num));
549
550 bezier_curves.foreach_index(GrainSize(512), [&](const int curve, const int pos) {
551 const IndexRange points = points_by_curve[curve];
552 const IndexRange bezier_point_range = bezier_offsets[pos];
553 for (const int i : points.index_range()) {
554 const int point = points[i];
555 const int bezier_point = bezier_point_range[i];
556 lines_left[bezier_point] = uint2(handles_left[bezier_point], point);
557 lines_right[bezier_point] = uint2(handles_right[bezier_point], point);
558 }
559 });
560 }
561
562 extract_curve_lines(points_by_curve, cyclic, nurbs_curves, cyclic_segment_offset, lines);
563
565 &builder, 0, handles_and_points_num(points_num, bezier_offsets), false, &ibo);
566}
567
569 const GPUVertFormat &format,
570 const int index,
571 const char * /*name*/)
572{
575
576 /* Create a destination buffer for the transform feedback. Sized appropriately */
577 /* Those are points! not line segments. */
579 cache.final.resolution * cache.curves_num);
580}
581
583 const StringRef name,
584 const GPUVertFormat &format,
585 bool &r_is_point_domain)
586{
589
590 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
591 const bke::AttributeAccessor attributes = curves.wrap().attributes();
592
593 /* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done
594 * by OpenGL to float4 for a scalar `s` will produce a `float4(s, 0, 0, 1)`. However, following
595 * the Blender convention, it should be `float4(s, s, s, 1)`. This could be resolved using a
596 * similar texture state swizzle to map the attribute correctly as for volume attributes, so we
597 * can control the conversion ourselves. */
598 const bke::AttributeReader<ColorGeometry4f> attribute = attributes.lookup<ColorGeometry4f>(name);
599 if (!attribute) {
600 GPU_vertbuf_data_alloc(*vbo, curves.curves_num());
601 vbo->data<ColorGeometry4f>().fill({0.0f, 0.0f, 0.0f, 1.0f});
602 r_is_point_domain = false;
603 return vbo;
604 }
605
606 r_is_point_domain = attribute.domain == bke::AttrDomain::Point;
607 GPU_vertbuf_data_alloc(*vbo, r_is_point_domain ? curves.points_num() : curves.curves_num());
608 attribute.varray.materialize(vbo->data<ColorGeometry4f>());
609 return vbo;
610}
611
612static void ensure_final_attribute(const Curves &curves,
613 const StringRef name,
614 const int index,
615 CurvesEvalCache &cache)
616{
617 char sampler_name[32];
618 drw_curves_get_attribute_sampler_name(name, sampler_name);
619
620 GPUVertFormat format = {0};
621 /* All attributes use float4, see comment below. */
623
624 if (!cache.proc_attributes_buf[index]) {
626 curves, name, format, cache.proc_attributes_point_domain[index]);
627 cache.proc_attributes_buf[index] = vbo.release();
628 }
629
630 /* Existing final data may have been for a different attribute (with a different name or domain),
631 * free the data. */
633
634 /* Ensure final data for points. */
635 if (cache.proc_attributes_point_domain[index]) {
636 alloc_final_attribute_vbo(cache, format, index, sampler_name);
637 }
638}
639
640static void fill_curve_offsets_vbos(const OffsetIndices<int> points_by_curve,
641 GPUVertBufRaw &data_step,
642 GPUVertBufRaw &seg_step)
643{
644 for (const int i : points_by_curve.index_range()) {
645 const IndexRange points = points_by_curve[i];
646
647 *(uint *)GPU_vertbuf_raw_step(&data_step) = points.start();
648 *(uint *)GPU_vertbuf_raw_step(&seg_step) = points.size() - 1;
649 }
650}
651
652static void create_curve_offsets_vbos(const OffsetIndices<int> points_by_curve,
653 CurvesEvalCache &cache)
654{
655 GPUVertBufRaw data_step, seg_step;
656
657 GPUVertFormat format_data = {0};
658 uint data_id = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
659
660 GPUVertFormat format_seg = {0};
661 uint seg_id = GPU_vertformat_attr_add(&format_seg, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
662
663 /* Curve Data. */
667 GPU_vertbuf_attr_get_raw_data(cache.proc_strand_buf, data_id, &data_step);
668
672 GPU_vertbuf_attr_get_raw_data(cache.proc_strand_seg_buf, seg_id, &seg_step);
673
674 fill_curve_offsets_vbos(points_by_curve, data_step, seg_step);
675}
676
678{
679 /* Same format as proc_point_buf. */
680 GPUVertFormat format = {0};
682
685
686 /* Create a destination buffer for the transform feedback. Sized appropriately */
687
688 /* Those are points! not line segments. */
689 uint point_len = cache.final.resolution * cache.curves_num;
690 /* Avoid creating null sized VBO which can lead to crashes on certain platforms. */
691 point_len = max_ii(1, point_len);
692
693 GPU_vertbuf_data_alloc(*cache.final.proc_buf, point_len);
694}
695
696static void calc_final_indices(const bke::CurvesGeometry &curves,
697 CurvesEvalCache &cache,
698 const int thickness_res)
699{
700 BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
701 /* Determine prim type and element count.
702 * NOTE: Metal backend uses non-restart prim types for optimal HW performance. */
703 bool use_strip_prims = (GPU_backend_get_type() != GPU_BACKEND_METAL);
704 int verts_per_curve;
705 GPUPrimType prim_type;
706
707 if (use_strip_prims) {
708 /* +1 for primitive restart */
709 verts_per_curve = cache.final.resolution * thickness_res;
710 prim_type = (thickness_res == 1) ? GPU_PRIM_LINE_STRIP : GPU_PRIM_TRI_STRIP;
711 }
712 else {
713 /* Use full primitive type. */
714 prim_type = (thickness_res == 1) ? GPU_PRIM_LINES : GPU_PRIM_TRIS;
715 int verts_per_segment = ((prim_type == GPU_PRIM_LINES) ? 2 : 6);
716 verts_per_curve = (cache.final.resolution - 1) * verts_per_segment;
717 }
718
720 "dummy", GPU_COMP_U32, 1, GPU_FETCH_INT);
721
723 GPU_vertbuf_data_alloc(*vbo, 1);
724
725 gpu::IndexBuf *ibo = nullptr;
727 if (curves.curves_num()) {
728 ibo = GPU_indexbuf_build_curves_on_device(prim_type, curves.curves_num(), verts_per_curve);
729 owns_flag |= GPU_BATCH_OWNS_INDEX;
730 }
731 cache.final.proc_hairs = GPU_batch_create_ex(prim_type, vbo, ibo, owns_flag);
732}
733
734static bool ensure_attributes(const Curves &curves,
735 CurvesBatchCache &cache,
736 const GPUMaterial *gpu_material)
737{
738 const CustomData &cd_curve = curves.geometry.curve_data;
739 const CustomData &cd_point = curves.geometry.point_data;
740 CurvesEvalFinalCache &final_cache = cache.eval_cache.final;
741
742 if (gpu_material) {
743 /* The following code should be kept in sync with `mesh_cd_calc_used_gpu_layers`. */
744 VectorSet<std::string> attrs_needed;
745 ListBase gpu_attrs = GPU_material_attributes(gpu_material);
746 LISTBASE_FOREACH (const GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
747 StringRef name = gpu_attr->name;
748 eCustomDataType type = eCustomDataType(gpu_attr->type);
749 int layer = -1;
750 std::optional<bke::AttrDomain> domain;
751
752 if (gpu_attr->type == CD_AUTO_FROM_NAME) {
753 /* We need to deduce what exact layer is used.
754 *
755 * We do it based on the specified name.
756 */
757 if (!name.is_empty()) {
758 layer = CustomData_get_named_layer(&cd_curve, CD_PROP_FLOAT2, name);
759 type = CD_MTFACE;
760 domain = bke::AttrDomain::Curve;
761
762 if (layer == -1) {
763 /* Try to match a generic attribute, we use the first attribute domain with a
764 * matching name. */
765 if (drw_custom_data_match_attribute(cd_point, name, &layer, &type)) {
766 domain = bke::AttrDomain::Point;
767 }
768 else if (drw_custom_data_match_attribute(cd_curve, name, &layer, &type)) {
769 domain = bke::AttrDomain::Curve;
770 }
771 else {
772 domain.reset();
773 layer = -1;
774 }
775 }
776
777 if (layer == -1) {
778 continue;
779 }
780 }
781 else {
782 /* Fall back to the UV layer, which matches old behavior. */
783 type = CD_MTFACE;
784 }
785 }
786 else {
787 if (drw_custom_data_match_attribute(cd_curve, name, &layer, &type)) {
788 domain = bke::AttrDomain::Curve;
789 }
790 else if (drw_custom_data_match_attribute(cd_point, name, &layer, &type)) {
791 domain = bke::AttrDomain::Point;
792 }
793 }
794
795 switch (type) {
796 case CD_MTFACE: {
797 if (layer == -1) {
798 layer = !name.is_empty() ?
801 if (layer != -1) {
802 domain = bke::AttrDomain::Curve;
803 }
804 }
805 if (layer == -1) {
806 layer = !name.is_empty() ?
809 if (layer != -1) {
810 domain = bke::AttrDomain::Point;
811 }
812 }
813
814 if (layer != -1 && !name.is_empty() && domain.has_value()) {
816 domain == bke::AttrDomain::Curve ? &cd_curve : &cd_point, CD_PROP_FLOAT2, layer);
817 }
818
819 if (layer != -1 && domain.has_value()) {
820 drw_attributes_add_request(&attrs_needed, name);
821 }
822 break;
823 }
824
825 case CD_TANGENT:
826 case CD_ORCO:
827 break;
828
830 case CD_PROP_COLOR:
832 case CD_PROP_FLOAT3:
833 case CD_PROP_BOOL:
834 case CD_PROP_INT8:
835 case CD_PROP_INT32:
836 case CD_PROP_INT16_2D:
837 case CD_PROP_INT32_2D:
838 case CD_PROP_FLOAT:
839 case CD_PROP_FLOAT2: {
840 if (layer != -1 && domain.has_value()) {
841 drw_attributes_add_request(&attrs_needed, name);
842 }
843 break;
844 }
845 default:
846 break;
847 }
848 }
849
850 if (!drw_attributes_overlap(&final_cache.attr_used, &attrs_needed)) {
851 /* Some new attributes have been added, free all and start over. */
852 for (const int i : IndexRange(GPU_MAX_ATTR)) {
855 }
856 drw_attributes_merge(&final_cache.attr_used, &attrs_needed, cache.render_mutex);
857 }
858 drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, cache.render_mutex);
859 }
860
861 bool need_tf_update = false;
862
863 for (const int i : final_cache.attr_used.index_range()) {
864 if (cache.eval_cache.final.attributes_buf[i] != nullptr) {
865 continue;
866 }
867
868 ensure_final_attribute(curves, final_cache.attr_used[i], i, cache.eval_cache);
870 need_tf_update = true;
871 }
872 }
873
874 return need_tf_update;
875}
876
877static void request_attribute(Curves &curves, const StringRef name)
878{
879 CurvesBatchCache &cache = get_batch_cache(curves);
880 CurvesEvalFinalCache &final_cache = cache.eval_cache.final;
881
882 VectorSet<std::string> attributes{};
883
884 bke::CurvesGeometry &curves_geometry = curves.geometry.wrap();
885 if (!curves_geometry.attributes().contains(name)) {
886 return;
887 }
888 drw_attributes_add_request(&attributes, name);
889
890 drw_attributes_merge(&final_cache.attr_used, &attributes, cache.render_mutex);
891}
892
893void drw_curves_get_attribute_sampler_name(const StringRef layer_name, char r_sampler_name[32])
894{
895 char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
896 GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
897 /* Attributes use auto-name. */
898 BLI_snprintf(r_sampler_name, 32, "a%s", attr_safe_name);
899}
900
902 CurvesEvalCache **r_cache,
903 const GPUMaterial *gpu_material,
904 const int subdiv,
905 const int thickness_res)
906{
907 const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
908 bool need_ft_update = false;
909
910 CurvesBatchCache &cache = get_batch_cache(*curves_id);
911 CurvesEvalCache &eval_cache = cache.eval_cache;
912
913 if (eval_cache.final.hair_subdiv != subdiv || eval_cache.final.thickres != thickness_res) {
914 /* If the subdivision or indexing settings have changed, the evaluation cache is cleared. */
915 clear_final_data(eval_cache.final);
916 eval_cache.final.hair_subdiv = subdiv;
917 eval_cache.final.thickres = thickness_res;
918 }
919
920 eval_cache.curves_num = curves.curves_num();
921 eval_cache.points_num = curves.points_num();
922
923 const int steps = 3; /* TODO: don't hard-code? */
924 eval_cache.final.resolution = 1 << (steps + subdiv);
925
926 /* Refreshed on combing and simulation. */
927 if (eval_cache.proc_point_buf == nullptr || DRW_vbo_requested(eval_cache.proc_point_buf)) {
928 create_points_position_time_vbo(curves, eval_cache);
929 need_ft_update = true;
930 }
931
932 /* Refreshed if active layer or custom data changes. */
933 if (eval_cache.proc_strand_buf == nullptr) {
934 create_curve_offsets_vbos(curves.points_by_curve(), eval_cache);
935 }
936
937 /* Refreshed only on subdiv count change. */
938 if (eval_cache.final.proc_buf == nullptr) {
939 alloc_final_points_vbo(eval_cache);
940 need_ft_update = true;
941 }
942
943 if (eval_cache.final.proc_hairs == nullptr) {
944 calc_final_indices(curves, eval_cache, thickness_res);
945 }
946 eval_cache.final.thickres = thickness_res;
947
948 need_ft_update |= ensure_attributes(*curves_id, cache, gpu_material);
949
950 *r_cache = &eval_cache;
951 return need_ft_update;
952}
953
955{
956 CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
957 if (cache == nullptr) {
958 return;
959 }
960 switch (mode) {
962 cache->is_dirty = true;
963 break;
964 default:
966 }
967}
968
970{
971 if (!batch_cache_is_dirty(*curves)) {
972 clear_batch_cache(*curves);
973 init_batch_cache(*curves);
974 }
975}
976
978{
979 clear_batch_cache(*curves);
980 CurvesBatchCache *batch_cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
981 MEM_delete(batch_cache);
982 curves->batch_cache = nullptr;
983}
984
986{
987 CurvesBatchCache *cache = static_cast<CurvesBatchCache *>(curves->batch_cache);
988 if (cache == nullptr) {
989 return;
990 }
991
992 bool do_discard = false;
993
994 CurvesEvalFinalCache &final_cache = cache->eval_cache.final;
995
996 if (drw_attributes_overlap(&final_cache.attr_used_over_time, &final_cache.attr_used)) {
997 final_cache.last_attr_matching_time = ctime;
998 }
999
1000 if (ctime - final_cache.last_attr_matching_time > U.vbotimeout) {
1001 do_discard = true;
1002 }
1003
1004 final_cache.attr_used_over_time.clear();
1005
1006 if (do_discard) {
1008 }
1009}
1010
1012{
1013 CurvesBatchCache &cache = get_batch_cache(*curves);
1014 return DRW_batch_request(&cache.edit_points);
1015}
1016
1018{
1019 CurvesBatchCache &cache = get_batch_cache(*curves);
1020 return DRW_batch_request(&cache.sculpt_cage);
1021}
1022
1024{
1025 CurvesBatchCache &cache = get_batch_cache(*curves);
1026 return DRW_batch_request(&cache.edit_handles);
1027}
1028
1030{
1031 CurvesBatchCache &cache = get_batch_cache(*curves);
1032 return DRW_batch_request(&cache.edit_curves_lines);
1033}
1034
1036 const StringRef name,
1037 bool *r_is_point_domain)
1038{
1039 CurvesBatchCache &cache = get_batch_cache(*curves);
1040 CurvesEvalFinalCache &final_cache = cache.eval_cache.final;
1041
1042 request_attribute(*curves, name);
1043
1044 int request_i = -1;
1045 for (const int i : final_cache.attr_used.index_range()) {
1046 if (final_cache.attr_used[i] == name) {
1047 request_i = i;
1048 break;
1049 }
1050 }
1051 if (request_i == -1) {
1052 *r_is_point_domain = false;
1053 return nullptr;
1054 }
1055 if (cache.eval_cache.proc_attributes_point_domain[request_i]) {
1056 *r_is_point_domain = true;
1057 return &final_cache.attributes_buf[request_i];
1058 }
1059 *r_is_point_domain = false;
1060 return &cache.eval_cache.proc_attributes_buf[request_i];
1061}
1062
1064 const bke::CurvesGeometry &curves,
1065 const bke::crazyspace::GeometryDeformation & /*deformation*/,
1066 CurvesBatchCache &cache)
1067{
1069 "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1070
1071 /* TODO: Deform curves using deformations. */
1072 const Span<float3> positions = curves.evaluated_positions();
1075 cache.edit_curves_lines_pos->data<float3>().copy_from(positions);
1076}
1077
1079{
1081 Object *ob_orig = DEG_get_original(ob);
1082 if (ob_orig == nullptr) {
1083 return;
1084 }
1085 const Curves &curves_orig_id = DRW_object_get_data_for_drawing<Curves>(*ob_orig);
1086
1088 const bke::CurvesGeometry &curves_orig = curves_orig_id.geometry.wrap();
1089
1090 bool is_edit_data_needed = false;
1091
1096 is_edit_data_needed = true;
1097 }
1103 is_edit_data_needed = true;
1104 }
1110 is_edit_data_needed = true;
1111 }
1115 }
1116
1117 const OffsetIndices<int> points_by_curve = curves_orig.points_by_curve();
1118 const VArray<bool> cyclic = curves_orig.cyclic();
1119
1120 const bke::crazyspace::GeometryDeformation deformation =
1121 is_edit_data_needed || DRW_vbo_requested(cache.edit_curves_lines_pos) ?
1124
1126 create_lines_ibo_no_cyclic(points_by_curve, *cache.sculpt_cage_ibo);
1127 }
1128
1130 create_edit_points_position_vbo(curves_orig, deformation, cache);
1131 }
1132
1135 curves_orig.evaluated_points_by_curve(), cyclic, *cache.edit_curves_lines_ibo);
1136 }
1137
1138 if (!is_edit_data_needed) {
1139 return;
1140 }
1141
1142 const IndexRange curves_range = curves_orig.curves_range();
1143 const VArray<int8_t> curve_types = curves_orig.curve_types();
1144 const std::array<int, CURVE_TYPES_NUM> type_counts = curves_orig.curve_type_counts();
1145 const bke::AttributeAccessor attributes = curves_orig.attributes();
1146
1147 IndexMaskMemory memory;
1148 const IndexMask catmull_rom_curves = bke::curves::indices_for_type(
1149 curve_types, type_counts, CURVE_TYPE_CATMULL_ROM, curves_range, memory);
1150 const IndexMask poly_curves = bke::curves::indices_for_type(
1151 curve_types, type_counts, CURVE_TYPE_POLY, curves_range, memory);
1152 const IndexMask bezier_curves = bke::curves::indices_for_type(
1153 curve_types, type_counts, CURVE_TYPE_BEZIER, curves_range, memory);
1154 const IndexMask nurbs_curves = bke::curves::indices_for_type(
1155 curve_types, type_counts, CURVE_TYPE_NURBS, curves_range, memory);
1156
1157 Array<int> bezier_point_offset_data(bezier_curves.size() + 1);
1159 points_by_curve, bezier_curves, bezier_point_offset_data);
1160
1162 create_edit_points_position(curves_orig,
1163 points_by_curve,
1164 bezier_curves,
1165 bezier_offsets,
1166 deformation,
1167 *cache.edit_points_pos);
1168 }
1170 create_edit_points_data(points_by_curve,
1171 catmull_rom_curves,
1172 poly_curves,
1173 bezier_curves,
1174 nurbs_curves,
1175 bezier_offsets,
1176 curves_orig,
1177 *cache.edit_points_data);
1178 }
1181 points_by_curve, bezier_curves, bezier_offsets, attributes, *cache.edit_points_selection);
1182 }
1184 calc_edit_handles_ibo(points_by_curve,
1185 catmull_rom_curves,
1186 poly_curves,
1187 bezier_curves,
1188 nurbs_curves,
1189 bezier_offsets,
1190 cyclic,
1191 *cache.edit_handles_ibo);
1192 }
1193}
1194
1195} // 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.
int CustomData_get_named_layer(const CustomData *data, eCustomDataType type, blender::StringRef name)
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_render_layer(const CustomData *data, eCustomDataType type)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
MINLINE int max_ii(int a, int b)
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
T * DEG_get_original(T *id)
@ CURVE_TYPE_BEZIER
@ CURVE_TYPE_NURBS
@ CURVE_TYPE_POLY
@ CURVE_TYPE_CATMULL_ROM
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_PROP_COLOR
@ CD_PROP_QUATERNION
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_PROP_INT16_2D
@ CD_AUTO_FROM_NAME
Object is a sort of wrapper for general info.
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:51
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:204
eGPUBatchFlag
Definition GPU_batch.hh:36
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:50
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:41
eGPUBackendType GPU_backend_get_type()
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)
blender::gpu::IndexBuf * GPU_indexbuf_build_curves_on_device(GPUPrimType prim_type, uint curves_num, uint verts_per_curve)
ListBase GPU_material_attributes(const GPUMaterial *material)
GPUPrimType
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_PRIM_LINE_STRIP
@ GPU_PRIM_TRI_STRIP
@ GPU_PRIM_TRIS
static constexpr int GPU_MAX_ATTR
Definition GPU_shader.hh:34
void GPU_vertbuf_attr_get_raw_data(blender::gpu::VertBuf *, uint a_idx, GPUVertBufRaw *access)
GPU_INLINE void * GPU_vertbuf_raw_step(GPUVertBufRaw *a)
#define GPU_vertbuf_create_with_format(format)
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
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT
void GPU_vertformat_safe_attr_name(blender::StringRef attr_name, char *r_safe_name, uint max_len)
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
static constexpr int GPU_MAX_SAFE_ATTR_NAME
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, const GPUVertCompType comp_type, const uint comp_len, const GPUVertFetchMode fetch_mode)
@ GPU_COMP_F32
@ GPU_COMP_U32
Read Guarded memory(de)allocation.
#define U
BMesh const char void * data
long long int int64_t
IndexRange index_range() const
constexpr int64_t first() 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 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 T & last(const int64_t n=0) const
Definition BLI_span.hh:689
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr bool is_empty() const
bool contains(StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
VArray< int8_t > handle_types_left() const
OffsetIndices< int > points_by_curve() const
VArray< int8_t > handle_types_right() const
IndexRange curves_range() const
const std::array< int, CURVE_TYPES_NUM > & curve_type_counts() const
Span< float3 > handle_positions_left() const
Span< float3 > positions() const
OffsetIndices< int > evaluated_points_by_curve() const
Span< float3 > handle_positions_right() const
AttributeAccessor attributes() const
Span< float3 > evaluated_positions() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
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)
Mesh & DRW_object_get_data_for_drawing(const Object &object)
#define MAX_THICKRES
uint pos
VecBase< uint, 2 > uint2
format
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 clear_eval_data(CurvesEvalCache &eval_cache)
void DRW_curves_batch_cache_validate(Curves *curves)
static void create_points_position_time_vbo(const bke::CurvesGeometry &curves, CurvesEvalCache &cache)
static void alloc_final_attribute_vbo(CurvesEvalCache &cache, const GPUVertFormat &format, const int index, const char *)
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)
blender::gpu::Batch * DRW_curves_batch_cache_get_edit_points(Curves *curves)
static bool batch_cache_is_dirty(const Curves &curves)
static void fill_points_position_time_vbo(const OffsetIndices< int > points_by_curve, const Span< float3 > positions, MutableSpan< PositionAndParameter > posTime_data, MutableSpan< float > hairLength_data)
void DRW_curves_batch_cache_free_old(Curves *curves, int ctime)
static gpu::VertBufPtr ensure_control_point_attribute(const Curves &curves_id, 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 void alloc_final_points_vbo(CurvesEvalCache &cache)
static void init_batch_cache(Curves &curves)
blender::gpu::Batch * DRW_curves_batch_cache_get_sculpt_curves_cage(Curves *curves)
void drw_attributes_merge(VectorSet< std::string > *dst, const VectorSet< std::string > *src, Mutex &render_mutex)
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_curve_offsets_vbos(const OffsetIndices< int > points_by_curve, CurvesEvalCache &cache)
static void calc_final_indices(const bke::CurvesGeometry &curves, CurvesEvalCache &cache, const int thickness_res)
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 bool ensure_attributes(const Curves &curves, CurvesBatchCache &cache, const GPUMaterial *gpu_material)
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)
bool curves_ensure_procedural_data(Curves *curves_id, CurvesEvalCache **r_cache, const GPUMaterial *gpu_material, const int subdiv, const int thickness_res)
static void fill_curve_offsets_vbos(const OffsetIndices< int > points_by_curve, GPUVertBufRaw &data_step, GPUVertBufRaw &seg_step)
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)
gpu::VertBuf ** DRW_curves_texture_for_evaluated_attribute(Curves *curves, StringRef name, bool *r_is_point_domain)
static void create_lines_ibo_no_cyclic(const OffsetIndices< int > points_by_curve, gpu::IndexBuf &ibo)
static void discard_attributes(CurvesEvalCache &eval_cache)
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)
static void extract_curve_lines(const OffsetIndices< int > points_by_curve, const VArray< bool > &cyclic, const IndexMask &selection, const int cyclic_segment_offset, MutableSpan< uint2 > lines)
static IndexRange handle_range_left(const int points_num, const OffsetIndices< int > bezier_offsets)
void DRW_curves_batch_cache_free(Curves *curves)
void DRW_curves_batch_cache_create_requested(Object *ob)
static void clear_final_data(CurvesEvalFinalCache &final_cache)
static int handles_and_points_num(const int points_num, const OffsetIndices< int > bezier_offsets)
bool drw_custom_data_match_attribute(const CustomData &custom_data, const StringRef name, int *r_layer_index, eCustomDataType *r_type)
static void ensure_final_attribute(const Curves &curves, const StringRef name, const int index, CurvesEvalCache &cache)
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
std::mutex Mutex
Definition BLI_mutex.hh:47
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
VecBase< float, 3 > float3
static const int steps
CustomData point_data
CustomData curve_data
CurvesGeometry geometry
void * batch_cache
gpu::VertBuf * proc_attributes_buf[GPU_MAX_ATTR]
std::array< bool, GPU_MAX_ATTR > proc_attributes_point_domain
VectorSet< std::string > attr_used_over_time
gpu::VertBuf * attributes_buf[GPU_MAX_ATTR]
i
Definition text_draw.cc:230