Blender V4.5
draw_pbvh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11
12#include "BLI_map.hh"
13#include "BLI_math_geom.h"
15#include "BLI_utildefines.h"
16#include "BLI_vector.hh"
17
18#include "DNA_object_types.h"
19
20#include "BKE_attribute.hh"
21#include "BKE_attribute_math.hh"
22#include "BKE_customdata.hh"
23#include "BKE_mesh.hh"
24#include "BKE_paint.hh"
25#include "BKE_paint_bvh.hh"
26#include "BKE_subdiv_ccg.hh"
27
29
30#include "GPU_batch.hh"
31
32#include "DRW_engine.hh"
33#include "DRW_pbvh.hh"
34#include "DRW_render.hh"
35
36#include "attribute_convert.hh"
37#include "bmesh.hh"
38
39namespace blender {
40
41template<> struct DefaultHash<draw::pbvh::AttributeRequest> {
43 {
44 using namespace draw::pbvh;
45 if (const CustomRequest *request_type = std::get_if<CustomRequest>(&value)) {
46 return get_default_hash(*request_type);
47 }
48 const GenericRequest &attr = std::get<GenericRequest>(value);
49 return get_default_hash(attr);
50 }
51};
52
53} // namespace blender
54
55namespace blender::draw::pbvh {
56
61
75 OrigMeshData(const Mesh &mesh)
76 : active_color(mesh.active_color_attribute),
77 default_color(mesh.default_color_attribute),
80 face_set_default(mesh.face_sets_color_default),
81 face_set_seed(mesh.face_sets_color_seed),
83 {
84 }
85};
86
91class DrawCacheImpl : public DrawCache {
92 struct AttributeData {
102 BitVector<> dirty_nodes;
107 void tag_dirty(const IndexMask &node_mask);
108 };
109
111 BitVector<> use_flat_layout_;
113 Array<int> material_indices_;
114
116 Vector<gpu::IndexBufPtr> lines_ibos_;
118 Vector<gpu::IndexBufPtr> lines_ibos_coarse_;
120 Vector<gpu::IndexBufPtr> tris_ibos_;
122 Vector<gpu::IndexBufPtr> tris_ibos_coarse_;
128
130 Vector<gpu::Batch *> lines_batches_;
132 Vector<gpu::Batch *> lines_batches_coarse_;
139
148 BitVector<> dirty_topology_;
149
150 public:
151 ~DrawCacheImpl() override;
152
153 void tag_positions_changed(const IndexMask &node_mask) override;
154 void tag_visibility_changed(const IndexMask &node_mask) override;
155 void tag_topology_changed(const IndexMask &node_mask) override;
156 void tag_face_sets_changed(const IndexMask &node_mask) override;
157 void tag_masks_changed(const IndexMask &node_mask) override;
158 void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name) override;
159
161 const ViewportRequest &request,
162 const IndexMask &nodes_to_update) override;
163
165 const ViewportRequest &request,
166 const IndexMask &nodes_to_update) override;
167
168 Span<int> ensure_material_indices(const Object &object) override;
169
170 private:
175 void free_nodes_with_changed_topology(const bke::pbvh::Tree &pbvh);
176
177 BitSpan ensure_use_flat_layout(const Object &object, const OrigMeshData &orig_mesh_data);
178
179 Span<gpu::VertBufPtr> ensure_attribute_data(const Object &object,
180 const OrigMeshData &orig_mesh_data,
181 const AttributeRequest &attr,
182 const IndexMask &node_mask);
183
184 Span<gpu::IndexBufPtr> ensure_tri_indices(const Object &object,
185 const OrigMeshData &orig_mesh_data,
186 const IndexMask &node_mask,
187 bool coarse);
188
189 Span<gpu::IndexBufPtr> ensure_lines_indices(const Object &object,
190 const OrigMeshData &orig_mesh_data,
191 const IndexMask &node_mask,
192 bool coarse);
193};
194
195void DrawCacheImpl::AttributeData::tag_dirty(const IndexMask &node_mask)
196{
197 this->dirty_nodes.resize(std::max(this->dirty_nodes.size(), node_mask.min_array_size()), false);
198 node_mask.set_bits(this->dirty_nodes);
199}
200
202{
203 if (DrawCacheImpl::AttributeData *data = attribute_vbos_.lookup_ptr(CustomRequest::Position)) {
204 data->tag_dirty(node_mask);
205 }
206 if (DrawCacheImpl::AttributeData *data = attribute_vbos_.lookup_ptr(CustomRequest::Normal)) {
207 data->tag_dirty(node_mask);
208 }
209}
210
212{
213 dirty_topology_.resize(std::max(dirty_topology_.size(), node_mask.min_array_size()), false);
214 node_mask.set_bits(dirty_topology_);
215}
216
218{
221 this->tag_visibility_changed(node_mask);
222}
223
225{
226 if (DrawCacheImpl::AttributeData *data = attribute_vbos_.lookup_ptr(CustomRequest::FaceSet)) {
227 data->tag_dirty(node_mask);
228 }
229}
230
232{
233 if (DrawCacheImpl::AttributeData *data = attribute_vbos_.lookup_ptr(CustomRequest::Mask)) {
234 data->tag_dirty(node_mask);
235 }
236}
237
238void DrawCacheImpl::tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
239{
240 for (const auto &[data_request, data] : attribute_vbos_.items()) {
241 if (const GenericRequest *request = std::get_if<GenericRequest>(&data_request)) {
242 if (*request == attribute_name) {
243 data.tag_dirty(node_mask);
244 }
245 }
246 }
247}
248
249DrawCache &ensure_draw_data(std::unique_ptr<bke::pbvh::DrawCache> &ptr)
250{
251 if (!ptr) {
252 ptr = std::make_unique<DrawCacheImpl>();
253 }
254 return dynamic_cast<DrawCache &>(*ptr);
255}
256
258 const IndexMask &node_mask)
259{
260 IndexMaskMemory memory;
261 const IndexMask mask = IndexMask::from_intersection(node_mask, ibos.index_range(), memory);
262 mask.foreach_index([&](const int i) { ibos[i].reset(); });
263}
264
266 const IndexMask &node_mask)
267{
268 IndexMaskMemory memory;
269 const IndexMask mask = IndexMask::from_intersection(node_mask, vbos.index_range(), memory);
270 mask.foreach_index([&](const int i) { vbos[i].reset(); });
271}
272
274 const IndexMask &node_mask)
275{
276 IndexMaskMemory memory;
277 const IndexMask mask = IndexMask::from_intersection(node_mask, batches.index_range(), memory);
278 mask.foreach_index([&](const int i) { GPU_BATCH_DISCARD_SAFE(batches[i]); });
279}
280
282{
284 "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
285 return format;
286}
287
289{
292 return format;
293}
294
296{
298 "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
299 return format;
300}
301
303{
306 return format;
307}
308
309static GPUVertFormat attribute_format(const OrigMeshData &orig_mesh_data,
310 const StringRef name,
311 const eCustomDataType data_type)
312{
314
315 bool is_render, is_active;
316 const char *prefix = "a";
317
318 if (CD_TYPE_AS_MASK(data_type) & CD_MASK_COLOR_ALL) {
319 prefix = "c";
320 is_active = orig_mesh_data.active_color == name;
321 is_render = orig_mesh_data.default_color == name;
322 }
323 if (data_type == CD_PROP_FLOAT2) {
324 prefix = "u";
325 is_active = orig_mesh_data.active_uv_map == name;
326 is_render = orig_mesh_data.default_uv_map == name;
327 }
328
329 DRW_cdlayer_attr_aliases_add(&format, prefix, data_type, name, is_render, is_active);
330 return format;
331}
332
334{
337 return short4(result.x, result.y, result.z, 0);
338}
339
340template<typename T>
342 const Span<int> corner_verts,
343 const Span<T> attribute,
344 const Span<int> face_indices,
345 gpu::VertBuf &vbo)
346{
347 using Converter = AttributeConverter<T>;
348 using VBOType = typename Converter::VBOType;
349 VBOType *data = vbo.data<VBOType>().data();
350 for (const int face : face_indices) {
351 for (const int vert : corner_verts.slice(faces[face])) {
352 *data = Converter::convert(attribute[vert]);
353 data++;
354 }
355 }
356}
357
358template<typename T>
360 const Span<T> attribute,
361 const Span<int> face_indices,
362 gpu::VertBuf &vbo)
363{
364 using Converter = AttributeConverter<T>;
365 using VBOType = typename Converter::VBOType;
366
367 VBOType *data = vbo.data<VBOType>().data();
368 for (const int face : face_indices) {
369 const int face_size = faces[face].size();
370 std::fill_n(data, face_size, Converter::convert(attribute[face]));
371 data += face_size;
372 }
373}
374
375template<typename T>
377 const Span<T> attribute,
378 const Span<int> face_indices,
379 gpu::VertBuf &vbo)
380{
381 using Converter = AttributeConverter<T>;
382 using VBOType = typename Converter::VBOType;
383
384 VBOType *data = vbo.data<VBOType>().data();
385 for (const int face : face_indices) {
386 for (const int corner : faces[face]) {
387 *data = Converter::convert(attribute[corner]);
388 data++;
389 }
390 }
391}
392
393template<typename T> const T &bmesh_cd_vert_get(const BMVert &vert, const int offset)
394{
395 return *static_cast<const T *>(POINTER_OFFSET(vert.head.data, offset));
396}
397
398template<typename T> const T &bmesh_cd_loop_get(const BMLoop &loop, const int offset)
399{
400 return *static_cast<const T *>(POINTER_OFFSET(loop.head.data, offset));
401}
402
403template<typename T> const T &bmesh_cd_face_get(const BMFace &face, const int offset)
404{
405 return *static_cast<const T *>(POINTER_OFFSET(face.head.data, offset));
406}
407
408template<typename T>
409void extract_data_vert_bmesh(const Set<BMFace *, 0> &faces, const int cd_offset, gpu::VertBuf &vbo)
410{
411 using Converter = AttributeConverter<T>;
412 using VBOType = typename Converter::VBOType;
413 VBOType *data = vbo.data<VBOType>().data();
414
415 for (const BMFace *face : faces) {
417 continue;
418 }
419 const BMLoop *l = face->l_first;
420 *data = Converter::convert(bmesh_cd_vert_get<T>(*l->prev->v, cd_offset));
421 data++;
422 *data = Converter::convert(bmesh_cd_vert_get<T>(*l->v, cd_offset));
423 data++;
424 *data = Converter::convert(bmesh_cd_vert_get<T>(*l->next->v, cd_offset));
425 data++;
426 }
427}
428
429template<typename T>
430void extract_data_face_bmesh(const Set<BMFace *, 0> &faces, const int cd_offset, gpu::VertBuf &vbo)
431{
432 using Converter = AttributeConverter<T>;
433 using VBOType = typename Converter::VBOType;
434 VBOType *data = vbo.data<VBOType>().data();
435
436 for (const BMFace *face : faces) {
438 continue;
439 }
440 std::fill_n(data, 3, Converter::convert(bmesh_cd_face_get<T>(*face, cd_offset)));
441 data += 3;
442 }
443}
444
445template<typename T>
447 const int cd_offset,
448 gpu::VertBuf &vbo)
449{
450 using Converter = AttributeConverter<T>;
451 using VBOType = typename Converter::VBOType;
452 VBOType *data = vbo.data<VBOType>().data();
453
454 for (const BMFace *face : faces) {
456 continue;
457 }
458 const BMLoop *l = face->l_first;
459 *data = Converter::convert(bmesh_cd_loop_get<T>(*l->prev, cd_offset));
460 data++;
461 *data = Converter::convert(bmesh_cd_loop_get<T>(*l, cd_offset));
462 data++;
463 *data = Converter::convert(bmesh_cd_loop_get<T>(*l->next, cd_offset));
464 data++;
465 }
466}
467
469{
470 return std::count_if(faces.begin(), faces.end(), [&](const BMFace *face) {
471 return !BM_elem_flag_test_bool(face, BM_ELEM_HIDDEN);
472 });
473}
474
476{
477 free_batches(lines_batches_, lines_batches_.index_range());
478 free_batches(lines_batches_coarse_, lines_batches_coarse_.index_range());
479 for (MutableSpan<gpu::Batch *> batches : tris_batches_.values()) {
480 free_batches(batches, batches.index_range());
481 }
482}
483
484void DrawCacheImpl::free_nodes_with_changed_topology(const bke::pbvh::Tree &pbvh)
485{
486 /* NOTE: Theoretically we shouldn't need to free batches with a changed triangle count, but
487 * currently it's the simplest way to reallocate all the GPU data while keeping everything in a
488 * consistent state. */
489 IndexMaskMemory memory;
490 const IndexMask nodes_to_free = IndexMask::from_bits(dirty_topology_, memory);
491 if (nodes_to_free.is_empty()) {
492 return;
493 }
494
495 dirty_topology_.clear_and_shrink();
496
497 free_ibos(lines_ibos_, nodes_to_free);
498 free_ibos(lines_ibos_coarse_, nodes_to_free);
499 free_ibos(tris_ibos_, nodes_to_free);
500 free_ibos(tris_ibos_coarse_, nodes_to_free);
501 if (pbvh.type() == bke::pbvh::Type::BMesh) {
502 /* For BMesh, VBOs are only filled with data for visible triangles, and topology can also
503 * completely change due to dynamic topology, so VBOs must be rebuilt from scratch. For other
504 * types, actual topology doesn't change, and visibility changes are accounted for by the index
505 * buffers. */
506 for (AttributeData &data : attribute_vbos_.values()) {
507 free_vbos(data.vbos, nodes_to_free);
508 }
509 }
510
511 free_batches(lines_batches_, nodes_to_free);
512 free_batches(lines_batches_coarse_, nodes_to_free);
513 for (MutableSpan<gpu::Batch *> batches : tris_batches_.values()) {
514 free_batches(batches, nodes_to_free);
515 }
516}
517
519 const GPUVertFormat &format,
520 const IndexMask &node_mask,
522{
525 node_mask.foreach_index(GrainSize(64), [&](const int i) {
526 if (!vbos[i]) {
528 }
529 GPU_vertbuf_data_alloc(*vbos[i], nodes[i].corners_num());
530 });
531}
532
534 const GPUVertFormat &format,
535 const BitSpan use_flat_layout,
536 const IndexMask &node_mask,
538{
541 const SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
542 node_mask.foreach_index(GrainSize(64), [&](const int i) {
543 if (!vbos[i]) {
545 }
546 const int verts_per_grid = use_flat_layout[i] ? square_i(subdiv_ccg.grid_size - 1) * 4 :
547 square_i(subdiv_ccg.grid_size);
548 const int verts_num = nodes[i].grids().size() * verts_per_grid;
549 GPU_vertbuf_data_alloc(*vbos[i], verts_num);
550 });
551}
552
554 const GPUVertFormat &format,
555 const IndexMask &node_mask,
557{
560 node_mask.foreach_index(GrainSize(64), [&](const int i) {
561 if (!vbos[i]) {
563 }
565 &const_cast<bke::pbvh::BMeshNode &>(nodes[i]));
566 const int verts_num = count_visible_tris_bmesh(faces) * 3;
567 GPU_vertbuf_data_alloc(*vbos[i], verts_num);
568 });
569}
570
571static void update_positions_mesh(const Object &object,
572 const IndexMask &node_mask,
574{
577 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(object);
578 const OffsetIndices<int> faces = mesh.faces();
579 const Span<int> corner_verts = mesh.corner_verts();
580 const Span<float3> vert_positions = bke::pbvh::vert_positions_eval_from_eval(object);
581 ensure_vbos_allocated_mesh(object, position_format(), node_mask, vbos);
582 node_mask.foreach_index(GrainSize(1), [&](const int i) {
584 faces, corner_verts, vert_positions, nodes[i].faces(), *vbos[i]);
585 });
586}
587
588static void update_normals_mesh(const Object &object,
589 const IndexMask &node_mask,
591{
594 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(object);
595 const OffsetIndices<int> faces = mesh.faces();
596 const Span<int> corner_verts = mesh.corner_verts();
597 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval_from_eval(object);
598 const Span<float3> face_normals = bke::pbvh::face_normals_eval_from_eval(object);
599 const bke::AttributeAccessor attributes = mesh.attributes();
600 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
601 ensure_vbos_allocated_mesh(object, normal_format(), node_mask, vbos);
602 node_mask.foreach_index(GrainSize(1), [&](const int i) {
603 short4 *data = vbos[i]->data<short4>().data();
604
605 for (const int face : nodes[i].faces()) {
606 if (!sharp_faces.is_empty() && sharp_faces[face]) {
607 const int face_size = faces[face].size();
608 std::fill_n(data, face_size, normal_float_to_short(face_normals[face]));
609 data += face_size;
610 }
611 else {
612 for (const int vert : corner_verts.slice(faces[face])) {
613 *data = normal_float_to_short(vert_normals[vert]);
614 data++;
615 }
616 }
617 }
618 });
619}
620
621BLI_NOINLINE static void update_masks_mesh(const Object &object,
622 const OrigMeshData &orig_mesh_data,
623 const IndexMask &node_mask,
625{
628 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(object);
629 const OffsetIndices<int> faces = mesh.faces();
630 const Span<int> corner_verts = mesh.corner_verts();
631 const VArraySpan mask = *orig_mesh_data.attributes.lookup<float>(".sculpt_mask",
633 ensure_vbos_allocated_mesh(object, mask_format(), node_mask, vbos);
634 if (!mask.is_empty()) {
635 node_mask.foreach_index(GrainSize(1), [&](const int i) {
636 float *data = vbos[i]->data<float>().data();
637 for (const int face : nodes[i].faces()) {
638 for (const int vert : corner_verts.slice(faces[face])) {
639 *data = mask[vert];
640 data++;
641 }
642 }
643 });
644 }
645 else {
646 node_mask.foreach_index(GrainSize(64),
647 [&](const int i) { vbos[i]->data<float>().fill(0.0f); });
648 }
649}
650
651BLI_NOINLINE static void update_face_sets_mesh(const Object &object,
652 const OrigMeshData &orig_mesh_data,
653 const IndexMask &node_mask,
655{
658 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(object);
659 const OffsetIndices<int> faces = mesh.faces();
660 const int color_default = orig_mesh_data.face_set_default;
661 const int color_seed = orig_mesh_data.face_set_seed;
662 const VArraySpan face_sets = *orig_mesh_data.attributes.lookup<int>(".sculpt_face_set",
664 ensure_vbos_allocated_mesh(object, face_set_format(), node_mask, vbos);
665 if (!face_sets.is_empty()) {
666 node_mask.foreach_index(GrainSize(1), [&](const int i) {
667 uchar4 *data = vbos[i]->data<uchar4>().data();
668 for (const int face : nodes[i].faces()) {
669 const int id = face_sets[face];
670
671 uchar4 fset_color(UCHAR_MAX);
672 if (id != color_default) {
673 BKE_paint_face_set_overlay_color_get(id, color_seed, fset_color);
674 }
675 else {
676 /* Skip for the default color face set to render it white. */
677 fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
678 }
679
680 const int face_size = faces[face].size();
681 std::fill_n(data, face_size, fset_color);
682 data += face_size;
683 }
684 });
685 }
686 else {
687 node_mask.foreach_index(GrainSize(64),
688 [&](const int i) { vbos[i]->data<uchar4>().fill(uchar4(255)); });
689 }
690}
691
693 const OrigMeshData &orig_mesh_data,
694 const IndexMask &node_mask,
695 const StringRef name,
697{
700 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(object);
701 const OffsetIndices<int> faces = mesh.faces();
702 const Span<int> corner_verts = mesh.corner_verts();
703 const bke::AttributeAccessor attributes = orig_mesh_data.attributes;
704 const bke::GAttributeReader attr = attributes.lookup(name);
705 if (!attr || attr.domain == bke::AttrDomain::Edge) {
706 return;
707 }
710 object, attribute_format(orig_mesh_data, name, data_type), node_mask, vbos);
711 node_mask.foreach_index(GrainSize(1), [&](const int i) {
713 using T = decltype(dummy);
714 if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
715 const VArraySpan<T> src = attr.varray.typed<T>();
716 switch (attr.domain) {
717 case bke::AttrDomain::Point:
718 extract_data_vert_mesh<T>(faces, corner_verts, src, nodes[i].faces(), *vbos[i]);
719 break;
720 case bke::AttrDomain::Face:
721 extract_data_face_mesh<T>(faces, src, nodes[i].faces(), *vbos[i]);
722 break;
723 case bke::AttrDomain::Corner:
724 extract_data_corner_mesh<T>(faces, src, nodes[i].faces(), *vbos[i]);
725 break;
726 default:
727 BLI_assert_unreachable();
728 }
729 }
730 });
731 });
732}
733
734BLI_NOINLINE static void fill_positions_grids(const Object &object,
735 const BitSpan use_flat_layout,
736 const IndexMask &node_mask,
738{
741 const SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
742 const Span<float3> positions = subdiv_ccg.positions;
743 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
744 ensure_vbos_allocated_grids(object, position_format(), use_flat_layout, node_mask, vbos);
745 node_mask.foreach_index(GrainSize(1), [&](const int i) {
746 float3 *data = vbos[i]->data<float3>().data();
747 if (use_flat_layout[i]) {
748 const int grid_size_1 = key.grid_size - 1;
749 for (const int grid : nodes[i].grids()) {
750 const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
751 for (int y = 0; y < grid_size_1; y++) {
752 for (int x = 0; x < grid_size_1; x++) {
753 *data = grid_positions[CCG_grid_xy_to_index(key.grid_size, x, y)];
754 data++;
755 *data = grid_positions[CCG_grid_xy_to_index(key.grid_size, x + 1, y)];
756 data++;
757 *data = grid_positions[CCG_grid_xy_to_index(key.grid_size, x + 1, y + 1)];
758 data++;
759 *data = grid_positions[CCG_grid_xy_to_index(key.grid_size, x, y + 1)];
760 data++;
761 }
762 }
763 }
764 }
765 else {
766 for (const int grid : nodes[i].grids()) {
767 const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
768 std::copy_n(grid_positions.data(), grid_positions.size(), data);
769 data += grid_positions.size();
770 }
771 }
772 });
773}
774
775BLI_NOINLINE static void fill_normals_grids(const Object &object,
776 const OrigMeshData &orig_mesh_data,
777 const BitSpan use_flat_layout,
778 const IndexMask &node_mask,
780{
783 const SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
784 const Span<float3> positions = subdiv_ccg.positions;
785 const Span<float3> normals = subdiv_ccg.normals;
786 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
787 const Span<int> grid_to_face_map = subdiv_ccg.grid_to_face_map;
788 const bke::AttributeAccessor attributes = orig_mesh_data.attributes;
789 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
790 ensure_vbos_allocated_grids(object, normal_format(), use_flat_layout, node_mask, vbos);
791 node_mask.foreach_index(GrainSize(1), [&](const int i) {
792 short4 *data = vbos[i]->data<short4>().data();
793
794 if (use_flat_layout[i]) {
795 const int grid_size_1 = key.grid_size - 1;
796 for (const int grid : nodes[i].grids()) {
797 const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
798 const Span<float3> grid_normals = normals.slice(bke::ccg::grid_range(key, grid));
799 if (!sharp_faces.is_empty() && sharp_faces[grid_to_face_map[grid]]) {
800 for (int y = 0; y < grid_size_1; y++) {
801 for (int x = 0; x < grid_size_1; x++) {
802 float3 no;
804 grid_positions[CCG_grid_xy_to_index(key.grid_size, x, y + 1)],
805 grid_positions[CCG_grid_xy_to_index(key.grid_size, x + 1, y + 1)],
806 grid_positions[CCG_grid_xy_to_index(key.grid_size, x + 1, y)],
807 grid_positions[CCG_grid_xy_to_index(key.grid_size, x, y)]);
808 std::fill_n(data, 4, normal_float_to_short(no));
809 data += 4;
810 }
811 }
812 }
813 else {
814 for (int y = 0; y < grid_size_1; y++) {
815 for (int x = 0; x < grid_size_1; x++) {
816 std::fill_n(
817 data,
818 4,
820 data += 4;
821 }
822 }
823 }
824 }
825 }
826 else {
827 /* The non-flat VBO layout does not support sharp faces. */
828 for (const int grid : nodes[i].grids()) {
829 for (const float3 &normal : normals.slice(bke::ccg::grid_range(key, grid))) {
830 *data = normal_float_to_short(normal);
831 data++;
832 }
833 }
834 }
835 });
836}
837
838BLI_NOINLINE static void fill_masks_grids(const Object &object,
839 const BitSpan use_flat_layout,
840 const IndexMask &node_mask,
842{
845 const SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
846 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
847 const Span<float> masks = subdiv_ccg.masks;
848 ensure_vbos_allocated_grids(object, mask_format(), use_flat_layout, node_mask, vbos);
849 if (!masks.is_empty()) {
850 node_mask.foreach_index(GrainSize(1), [&](const int i) {
851 float *data = vbos[i]->data<float>().data();
852 if (use_flat_layout[i]) {
853 const int grid_size_1 = key.grid_size - 1;
854 for (const int grid : nodes[i].grids()) {
855 const Span<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
856 for (int y = 0; y < grid_size_1; y++) {
857 for (int x = 0; x < grid_size_1; x++) {
858 *data = grid_masks[CCG_grid_xy_to_index(key.grid_size, x, y)];
859 data++;
860 *data = grid_masks[CCG_grid_xy_to_index(key.grid_size, x + 1, y)];
861 data++;
862 *data = grid_masks[CCG_grid_xy_to_index(key.grid_size, x + 1, y + 1)];
863 data++;
864 *data = grid_masks[CCG_grid_xy_to_index(key.grid_size, x, y + 1)];
865 data++;
866 }
867 }
868 }
869 }
870 else {
871 for (const int grid : nodes[i].grids()) {
872 const Span<float> grid_masks = masks.slice(bke::ccg::grid_range(key, grid));
873 std::copy_n(grid_masks.data(), grid_masks.size(), data);
874 data += grid_masks.size();
875 }
876 }
877 });
878 }
879 else {
880 node_mask.foreach_index(GrainSize(64),
881 [&](const int i) { vbos[i]->data<float>().fill(0.0f); });
882 }
883}
884
885BLI_NOINLINE static void fill_face_sets_grids(const Object &object,
886 const OrigMeshData &orig_mesh_data,
887 const BitSpan use_flat_layout,
888 const IndexMask &node_mask,
890{
893 const SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
894 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
895 const int color_default = orig_mesh_data.face_set_default;
896 const int color_seed = orig_mesh_data.face_set_seed;
897 const Span<int> grid_to_face_map = subdiv_ccg.grid_to_face_map;
898 const bke::AttributeAccessor attributes = orig_mesh_data.attributes;
899 ensure_vbos_allocated_grids(object, face_set_format(), use_flat_layout, node_mask, vbos);
900 if (const VArray<int> face_sets = *attributes.lookup<int>(".sculpt_face_set",
902 {
903 const VArraySpan<int> face_sets_span(face_sets);
904 node_mask.foreach_index(GrainSize(1), [&](const int i) {
905 const Span<int> grids = nodes[i].grids();
906 const int verts_per_grid = use_flat_layout[i] ? square_i(key.grid_size - 1) * 4 :
907 square_i(key.grid_size);
908 uchar4 *data = vbos[i]->data<uchar4>().data();
909 for (const int i : grids.index_range()) {
910 uchar4 color{UCHAR_MAX};
911 const int fset = face_sets[grid_to_face_map[grids[i]]];
912 if (fset != color_default) {
914 }
915
916 std::fill_n(data, verts_per_grid, color);
917 data += verts_per_grid;
918 }
919 });
920 }
921 else {
922 node_mask.foreach_index(GrainSize(1),
923 [&](const int i) { vbos[i]->data<uchar4>().fill(uchar4{UCHAR_MAX}); });
924 }
925}
926
928 const IndexMask &node_mask,
930{
933 ensure_vbos_allocated_bmesh(object, position_format(), node_mask, vbos);
934 node_mask.foreach_index(GrainSize(1), [&](const int i) {
935 float3 *data = vbos[i]->data<float3>().data();
936 for (const BMFace *face :
938 {
940 continue;
941 }
942 const BMLoop *l = face->l_first;
943 *data = l->prev->v->co;
944 data++;
945 *data = l->v->co;
946 data++;
947 *data = l->next->v->co;
948 data++;
949 }
950 });
951}
952
953BLI_NOINLINE static void update_normals_bmesh(const Object &object,
954 const IndexMask &node_mask,
956{
959 ensure_vbos_allocated_bmesh(object, normal_format(), node_mask, vbos);
960 node_mask.foreach_index(GrainSize(1), [&](const int i) {
961 short4 *data = vbos[i]->data<short4>().data();
962 for (const BMFace *face :
964 {
966 continue;
967 }
969 const BMLoop *l = face->l_first;
970 *data = normal_float_to_short(l->prev->v->no);
971 data++;
972 *data = normal_float_to_short(l->v->no);
973 data++;
974 *data = normal_float_to_short(l->next->v->no);
975 data++;
976 }
977 else {
978 std::fill_n(data, 3, normal_float_to_short(face->no));
979 data += 3;
980 }
981 }
982 });
983}
984
985BLI_NOINLINE static void update_masks_bmesh(const Object &object,
986 const IndexMask &node_mask,
988{
991 const BMesh &bm = *object.sculpt->bm;
992 const int cd_offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
993 ensure_vbos_allocated_bmesh(object, mask_format(), node_mask, vbos);
994 if (cd_offset != -1) {
995 node_mask.foreach_index(GrainSize(1), [&](const int i) {
996 float *data = vbos[i]->data<float>().data();
997 for (const BMFace *face :
999 {
1000 if (BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
1001 continue;
1002 }
1003 const BMLoop *l = face->l_first;
1004 *data = bmesh_cd_vert_get<float>(*l->prev->v, cd_offset);
1005 data++;
1006 *data = bmesh_cd_vert_get<float>(*l->v, cd_offset);
1007 data++;
1008 *data = bmesh_cd_vert_get<float>(*l->next->v, cd_offset);
1009 data++;
1010 }
1011 });
1012 }
1013 else {
1014 node_mask.foreach_index(GrainSize(64),
1015 [&](const int i) { vbos[i]->data<float>().fill(0.0f); });
1016 }
1017}
1018
1020 const OrigMeshData &orig_mesh_data,
1021 const IndexMask &node_mask,
1023{
1024 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1026 const BMesh &bm = *object.sculpt->bm;
1027 const int color_default = orig_mesh_data.face_set_default;
1028 const int color_seed = orig_mesh_data.face_set_seed;
1029 const int offset = CustomData_get_offset_named(&bm.pdata, CD_PROP_INT32, ".sculpt_face_set");
1030 ensure_vbos_allocated_bmesh(object, face_set_format(), node_mask, vbos);
1031 if (offset != -1) {
1032 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1033 uchar4 *data = vbos[i]->data<uchar4>().data();
1034 for (const BMFace *face :
1036 {
1037 if (BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
1038 continue;
1039 }
1040 uchar4 color{UCHAR_MAX};
1041 const int fset = bmesh_cd_face_get<int>(*face, offset);
1042 if (fset != color_default) {
1044 }
1045 std::fill_n(data, 3, color);
1046 data += 3;
1047 }
1048 });
1049 }
1050 else {
1051 node_mask.foreach_index(GrainSize(64),
1052 [&](const int i) { vbos[i]->data<uchar4>().fill(uchar4(255)); });
1053 }
1054}
1055
1057 const int offset = -1;
1060 operator bool() const
1061 {
1062 return offset != -1;
1063 }
1064};
1065
1067{
1068 for (const CustomDataLayer &layer : Span(bm.vdata.layers, bm.vdata.totlayer)) {
1069 if (layer.name == name) {
1070 return {layer.offset, bke::AttrDomain::Point, eCustomDataType(layer.type)};
1071 }
1072 }
1073 for (const CustomDataLayer &layer : Span(bm.edata.layers, bm.edata.totlayer)) {
1074 if (layer.name == name) {
1075 return {layer.offset, bke::AttrDomain::Edge, eCustomDataType(layer.type)};
1076 }
1077 }
1078 for (const CustomDataLayer &layer : Span(bm.pdata.layers, bm.pdata.totlayer)) {
1079 if (layer.name == name) {
1080 return {layer.offset, bke::AttrDomain::Face, eCustomDataType(layer.type)};
1081 }
1082 }
1083 for (const CustomDataLayer &layer : Span(bm.ldata.layers, bm.ldata.totlayer)) {
1084 if (layer.name == name) {
1085 return {layer.offset, bke::AttrDomain::Corner, eCustomDataType(layer.type)};
1086 }
1087 }
1088 return {};
1089}
1090
1092 const OrigMeshData &orig_mesh_data,
1093 const IndexMask &node_mask,
1094 const StringRef name,
1096{
1097 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1099 const BMesh &bm = *object.sculpt->bm;
1101 if (attr.domain == bke::AttrDomain::Edge) {
1102 return;
1103 }
1104
1105 if (!attr) {
1107 object, attribute_format(orig_mesh_data, name, CD_PROP_FLOAT3), node_mask, vbos);
1108 node_mask.foreach_index(GrainSize(1),
1109 [&](const int i) { vbos[i]->data<float3>().fill(float3(0.0f)); });
1110 return;
1111 }
1112
1114 object, attribute_format(orig_mesh_data, name, attr.type), node_mask, vbos);
1115 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1117 using T = decltype(dummy);
1118 const auto &faces = BKE_pbvh_bmesh_node_faces(&const_cast<bke::pbvh::BMeshNode &>(nodes[i]));
1119 if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
1120 switch (attr.domain) {
1121 case bke::AttrDomain::Point:
1122 extract_data_vert_bmesh<T>(faces, attr.offset, *vbos[i]);
1123 break;
1124 case bke::AttrDomain::Face:
1125 extract_data_face_bmesh<T>(faces, attr.offset, *vbos[i]);
1126 break;
1127 case bke::AttrDomain::Corner:
1128 extract_data_corner_bmesh<T>(faces, attr.offset, *vbos[i]);
1129 break;
1130 default:
1131 BLI_assert_unreachable();
1132 }
1133 }
1134 });
1135 });
1136}
1137
1139 const Span<bool> hide_poly,
1140 const Span<int> face_indices)
1141{
1142 int corners_count = 0;
1143 for (const int face : face_indices) {
1144 if (!hide_poly.is_empty() && hide_poly[face]) {
1145 continue;
1146 }
1147 corners_count += faces[face].size();
1148 }
1149
1150 GPUIndexBufBuilder builder;
1151 GPU_indexbuf_init(&builder, GPU_PRIM_LINES, corners_count, INT_MAX);
1153
1154 int node_corner_offset = 0;
1155 int line_index = 0;
1156 for (const int face_index : face_indices) {
1157 const int face_size = faces[face_index].size();
1158 if (!hide_poly.is_empty() && hide_poly[face_index]) {
1159 node_corner_offset += face_size;
1160 continue;
1161 }
1162 for (const int i : IndexRange(face_size)) {
1163 const int next = (i == face_size - 1) ? 0 : i + 1;
1164 data[line_index] = uint2(i, next) + node_corner_offset;
1165 line_index++;
1166 }
1167
1168 node_corner_offset += face_size;
1169 }
1170
1171 return gpu::IndexBufPtr(GPU_indexbuf_build_ex(&builder, 0, node_corner_offset, false));
1172}
1173
1175 const int visible_faces_num)
1176{
1177 GPUIndexBufBuilder builder;
1178 GPU_indexbuf_init(&builder, GPU_PRIM_LINES, visible_faces_num * 3, INT_MAX);
1179
1181
1182 int line_index = 0;
1183 int vert_index = 0;
1184
1185 for (const BMFace *face : faces) {
1186 if (BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
1187 continue;
1188 }
1189
1190 data[line_index] = uint2(vert_index, vert_index + 1);
1191 line_index++;
1192 data[line_index] = uint2(vert_index + 1, vert_index + 2);
1193 line_index++;
1194 data[line_index] = uint2(vert_index + 2, vert_index);
1195 line_index++;
1196
1197 vert_index += 3;
1198 }
1199
1200 return gpu::IndexBufPtr(GPU_indexbuf_build_ex(&builder, 0, visible_faces_num * 3, false));
1201}
1202
1203static void create_tri_index_grids(const Span<int> grid_indices,
1204 const BitGroupVector<> &grid_hidden,
1205 const int gridsize,
1206 const int skip,
1207 const int totgrid,
1209{
1210 int tri_index = 0;
1211 int offset = 0;
1212 const int grid_vert_len = gridsize * gridsize;
1213 for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
1214 uint v0, v1, v2, v3;
1215
1216 const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
1217 grid_hidden[grid_indices[i]];
1218
1219 for (int y = 0; y < gridsize - skip; y += skip) {
1220 for (int x = 0; x < gridsize - skip; x += skip) {
1221 /* Skip hidden grid face */
1222 if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
1223 continue;
1224 }
1225 /* Indices in a Clockwise QUAD disposition. */
1226 v0 = offset + CCG_grid_xy_to_index(gridsize, x, y);
1227 v1 = offset + CCG_grid_xy_to_index(gridsize, x + skip, y);
1228 v2 = offset + CCG_grid_xy_to_index(gridsize, x + skip, y + skip);
1229 v3 = offset + CCG_grid_xy_to_index(gridsize, x, y + skip);
1230
1231 data[tri_index] = uint3(v0, v2, v1);
1232 tri_index++;
1233 data[tri_index] = uint3(v0, v3, v2);
1234 tri_index++;
1235 }
1236 }
1237 }
1238}
1239
1240static void create_tri_index_grids_flat_layout(const Span<int> grid_indices,
1241 const BitGroupVector<> &grid_hidden,
1242 const int gridsize,
1243 const int skip,
1244 const int totgrid,
1246{
1247 int tri_index = 0;
1248 int offset = 0;
1249 const int grid_vert_len = square_uint(gridsize - 1) * 4;
1250 for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
1251 const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
1252 grid_hidden[grid_indices[i]];
1253
1254 uint v0, v1, v2, v3;
1255 for (int y = 0; y < gridsize - skip; y += skip) {
1256 for (int x = 0; x < gridsize - skip; x += skip) {
1257 /* Skip hidden grid face */
1258 if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
1259 continue;
1260 }
1261
1262 v0 = (y * (gridsize - 1) + x) * 4;
1263
1264 if (skip > 1) {
1265 v1 = (y * (gridsize - 1) + x + skip - 1) * 4;
1266 v2 = ((y + skip - 1) * (gridsize - 1) + x + skip - 1) * 4;
1267 v3 = ((y + skip - 1) * (gridsize - 1) + x) * 4;
1268 }
1269 else {
1270 v1 = v2 = v3 = v0;
1271 }
1272
1273 /* VBO data are in a Clockwise QUAD disposition. Note
1274 * that vertices might be in different quads if we're
1275 * building a coarse index buffer.
1276 */
1277 v0 += offset;
1278 v1 += offset + 1;
1279 v2 += offset + 2;
1280 v3 += offset + 3;
1281
1282 data[tri_index] = uint3(v0, v2, v1);
1283 tri_index++;
1284 data[tri_index] = uint3(v0, v3, v2);
1285 tri_index++;
1286 }
1287 }
1288 }
1289}
1290
1291static void create_lines_index_grids(const Span<int> grid_indices,
1292 int display_gridsize,
1293 const BitGroupVector<> &grid_hidden,
1294 const int gridsize,
1295 const int skip,
1296 const int totgrid,
1298{
1299 int line_index = 0;
1300 int offset = 0;
1301 const int grid_vert_len = gridsize * gridsize;
1302 for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
1303 uint v0, v1, v2, v3;
1304 bool grid_visible = false;
1305
1306 const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
1307 grid_hidden[grid_indices[i]];
1308
1309 for (int y = 0; y < gridsize - skip; y += skip) {
1310 for (int x = 0; x < gridsize - skip; x += skip) {
1311 /* Skip hidden grid face */
1312 if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
1313 continue;
1314 }
1315 /* Indices in a Clockwise QUAD disposition. */
1316 v0 = offset + CCG_grid_xy_to_index(gridsize, x, y);
1317 v1 = offset + CCG_grid_xy_to_index(gridsize, x + skip, y);
1318 v2 = offset + CCG_grid_xy_to_index(gridsize, x + skip, y + skip);
1319 v3 = offset + CCG_grid_xy_to_index(gridsize, x, y + skip);
1320
1321 data[line_index] = uint2(v0, v1);
1322 line_index++;
1323 data[line_index] = uint2(v0, v3);
1324 line_index++;
1325
1326 if (y / skip + 2 == display_gridsize) {
1327 data[line_index] = uint2(v2, v3);
1328 line_index++;
1329 }
1330 grid_visible = true;
1331 }
1332
1333 if (grid_visible) {
1334 data[line_index] = uint2(v1, v2);
1335 line_index++;
1336 }
1337 }
1338 }
1339}
1340
1342 int display_gridsize,
1343 const BitGroupVector<> &grid_hidden,
1344 const int gridsize,
1345 const int skip,
1346 const int totgrid,
1348{
1349 int line_index = 0;
1350 int offset = 0;
1351 const int grid_vert_len = square_uint(gridsize - 1) * 4;
1352 for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
1353 bool grid_visible = false;
1354 const BoundedBitSpan gh = grid_hidden.is_empty() ? BoundedBitSpan() :
1355 grid_hidden[grid_indices[i]];
1356
1357 uint v0, v1, v2, v3;
1358 for (int y = 0; y < gridsize - skip; y += skip) {
1359 for (int x = 0; x < gridsize - skip; x += skip) {
1360 /* Skip hidden grid face */
1361 if (!gh.is_empty() && paint_is_grid_face_hidden(gh, gridsize, x, y)) {
1362 continue;
1363 }
1364
1365 v0 = (y * (gridsize - 1) + x) * 4;
1366
1367 if (skip > 1) {
1368 v1 = (y * (gridsize - 1) + x + skip - 1) * 4;
1369 v2 = ((y + skip - 1) * (gridsize - 1) + x + skip - 1) * 4;
1370 v3 = ((y + skip - 1) * (gridsize - 1) + x) * 4;
1371 }
1372 else {
1373 v1 = v2 = v3 = v0;
1374 }
1375
1376 /* VBO data are in a Clockwise QUAD disposition. Note
1377 * that vertices might be in different quads if we're
1378 * building a coarse index buffer.
1379 */
1380 v0 += offset;
1381 v1 += offset + 1;
1382 v2 += offset + 2;
1383 v3 += offset + 3;
1384
1385 data[line_index] = uint2(v0, v1);
1386 line_index++;
1387 data[line_index] = uint2(v0, v3);
1388 line_index++;
1389
1390 if (y / skip + 2 == display_gridsize) {
1391 data[line_index] = uint2(v2, v3);
1392 line_index++;
1393 }
1394 grid_visible = true;
1395 }
1396
1397 if (grid_visible) {
1398 data[line_index] = uint2(v1, v2);
1399 line_index++;
1400 }
1401 }
1402 }
1403}
1404
1405static Array<int> calc_material_indices(const Object &object, const OrigMeshData &orig_mesh_data)
1406{
1407 const SculptSession &ss = *object.sculpt;
1408 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1409 switch (pbvh.type()) {
1410 case bke::pbvh::Type::Mesh: {
1412 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(object);
1413 const bke::AttributeAccessor attributes = mesh.attributes();
1414 const VArray material_indices = *attributes.lookup<int>("material_index",
1416 if (!material_indices) {
1417 return {};
1418 }
1419 Array<int> node_materials(nodes.size());
1420 threading::parallel_for(nodes.index_range(), 64, [&](const IndexRange range) {
1421 for (const int i : range) {
1422 const Span<int> face_indices = nodes[i].faces();
1423 if (face_indices.is_empty()) {
1424 continue;
1425 }
1426 node_materials[i] = material_indices[face_indices.first()];
1427 }
1428 });
1429 return node_materials;
1430 }
1433 /* Use original mesh data because evaluated mesh is empty. */
1434 const bke::AttributeAccessor attributes = orig_mesh_data.attributes;
1435 const VArray material_indices = *attributes.lookup<int>("material_index",
1437 if (!material_indices) {
1438 return {};
1439 }
1440 Array<int> node_materials(nodes.size());
1441 const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1442 const Span<int> grid_faces = subdiv_ccg.grid_to_face_map;
1443 threading::parallel_for(nodes.index_range(), 64, [&](const IndexRange range) {
1444 for (const int i : range) {
1445 const Span<int> grids = nodes[i].grids();
1446 if (grids.is_empty()) {
1447 continue;
1448 }
1449 node_materials[i] = material_indices[grid_faces[grids.first()]];
1450 }
1451 });
1452 return node_materials;
1453 }
1455 return {};
1456 }
1458 return {};
1459}
1460
1461static BitVector<> calc_use_flat_layout(const Object &object, const OrigMeshData &orig_mesh_data)
1462{
1463 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1464 switch (pbvh.type()) {
1466 /* NOTE: Theoretically it would be possible to used vertex indexed buffers if there are no
1467 * face corner attributes, sharp faces, or face sets. */
1468 return {};
1471 const bke::AttributeAccessor attributes = orig_mesh_data.attributes;
1472 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
1473 if (sharp_faces.is_empty()) {
1474 return BitVector<>(nodes.size(), false);
1475 }
1476
1477 const SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1478 const Span<int> grid_to_face_map = subdiv_ccg.grid_to_face_map;
1479
1480 /* Use boolean array instead of #BitVector for parallelized writing. */
1481 Array<bool> use_flat_layout(nodes.size());
1482 threading::parallel_for(nodes.index_range(), 4, [&](const IndexRange range) {
1483 for (const int i : range) {
1484 const Span<int> grids = nodes[i].grids();
1485 if (grids.is_empty()) {
1486 continue;
1487 }
1488 use_flat_layout[i] = std::any_of(grids.begin(), grids.end(), [&](const int grid) {
1489 return sharp_faces[grid_to_face_map[grid]];
1490 });
1491 }
1492 });
1493 return BitVector<>(use_flat_layout);
1494 }
1496 return {};
1497 }
1499 return {};
1500}
1501
1503 const Span<int3> corner_tris,
1504 const Span<bool> hide_poly,
1505 const bke::pbvh::MeshNode &node)
1506{
1507 const Span<int> face_indices = node.faces();
1508 int tris_num = 0;
1509 if (hide_poly.is_empty()) {
1510 tris_num = poly_to_tri_count(face_indices.size(), node.corners_num());
1511 }
1512 else {
1513 for (const int face : face_indices) {
1514 if (hide_poly[face]) {
1515 continue;
1516 }
1517 tris_num += bke::mesh::face_triangles_num(faces[face].size());
1518 }
1519 }
1520
1521 GPUIndexBufBuilder builder;
1522 GPU_indexbuf_init(&builder, GPU_PRIM_TRIS, tris_num, INT_MAX);
1524
1525 int tri_index = 0;
1526 int node_corner_offset = 0;
1527 for (const int face_index : face_indices) {
1528 const IndexRange face = faces[face_index];
1529 if (!hide_poly.is_empty() && hide_poly[face_index]) {
1530 node_corner_offset += face.size();
1531 continue;
1532 }
1533 for (const int3 &tri : corner_tris.slice(bke::mesh::face_triangles_range(faces, face_index))) {
1534 for (int i : IndexRange(3)) {
1535 const int corner = tri[i];
1536 const int index_in_face = corner - face.first();
1537 data[tri_index][i] = node_corner_offset + index_in_face;
1538 }
1539 tri_index++;
1540 }
1541 node_corner_offset += face.size();
1542 }
1543
1544 return gpu::IndexBufPtr(GPU_indexbuf_build_ex(&builder, 0, node_corner_offset, false));
1545}
1546
1548 const BitGroupVector<> &grid_hidden,
1549 const bool do_coarse,
1550 const Span<int> grid_indices,
1551 const bool use_flat_layout)
1552{
1553 int gridsize = key.grid_size;
1554 int display_gridsize = gridsize;
1555 int totgrid = grid_indices.size();
1556 int skip = 1;
1557
1558 const int display_level = do_coarse ? 0 : key.level;
1559
1560 if (display_level < key.level) {
1561 display_gridsize = (1 << display_level) + 1;
1562 skip = 1 << (key.level - display_level - 1);
1563 }
1564
1565 uint visible_quad_len = bke::pbvh::count_grid_quads(
1566 grid_hidden, grid_indices, key.grid_size, display_gridsize);
1567
1568 GPUIndexBufBuilder builder;
1569 GPU_indexbuf_init(&builder, GPU_PRIM_TRIS, 2 * visible_quad_len, INT_MAX);
1570
1572
1573 if (use_flat_layout) {
1574 create_tri_index_grids_flat_layout(grid_indices, grid_hidden, gridsize, skip, totgrid, data);
1575 }
1576 else {
1577 create_tri_index_grids(grid_indices, grid_hidden, gridsize, skip, totgrid, data);
1578 }
1579
1580 return gpu::IndexBufPtr(GPU_indexbuf_build_ex(&builder, 0, 6 * visible_quad_len, false));
1581}
1582
1584 const BitGroupVector<> &grid_hidden,
1585 const bool do_coarse,
1586 const Span<int> grid_indices,
1587 const bool use_flat_layout)
1588{
1589 int gridsize = key.grid_size;
1590 int display_gridsize = gridsize;
1591 int totgrid = grid_indices.size();
1592 int skip = 1;
1593
1594 const int display_level = do_coarse ? 0 : key.level;
1595
1596 if (display_level < key.level) {
1597 display_gridsize = (1 << display_level) + 1;
1598 skip = 1 << (key.level - display_level - 1);
1599 }
1600
1601 GPUIndexBufBuilder builder;
1603 &builder, GPU_PRIM_LINES, 2 * totgrid * display_gridsize * (display_gridsize - 1), INT_MAX);
1604
1606
1607 if (use_flat_layout) {
1609 grid_indices, display_gridsize, grid_hidden, gridsize, skip, totgrid, data);
1610 }
1611 else {
1613 grid_indices, display_gridsize, grid_hidden, gridsize, skip, totgrid, data);
1614 }
1615
1617 &builder, 0, 2 * totgrid * display_gridsize * (display_gridsize - 1), false));
1618}
1619
1620Span<gpu::IndexBufPtr> DrawCacheImpl::ensure_lines_indices(const Object &object,
1621 const OrigMeshData &orig_mesh_data,
1622 const IndexMask &node_mask,
1623 const bool coarse)
1624{
1625 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1626 Vector<gpu::IndexBufPtr> &ibos = coarse ? lines_ibos_coarse_ : lines_ibos_;
1627 ibos.resize(pbvh.nodes_num());
1628
1629 IndexMaskMemory memory;
1630 const IndexMask nodes_to_calculate = IndexMask::from_predicate(
1631 node_mask, GrainSize(8196), memory, [&](const int i) { return !ibos[i]; });
1632
1633 switch (pbvh.type()) {
1634 case bke::pbvh::Type::Mesh: {
1636 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(object);
1637 const OffsetIndices<int> faces = mesh.faces();
1638 const bke::AttributeAccessor attributes = orig_mesh_data.attributes;
1639 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1640 nodes_to_calculate.foreach_index(GrainSize(1), [&](const int i) {
1641 ibos[i] = create_lines_index_faces(faces, hide_poly, nodes[i].faces());
1642 });
1643 break;
1644 }
1646 const Span<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
1647 nodes_to_calculate.foreach_index(GrainSize(1), [&](const int i) {
1648 const SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1649 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1651 key, subdiv_ccg.grid_hidden, coarse, nodes[i].grids(), use_flat_layout_[i]);
1652 });
1653 break;
1654 }
1656 const Span<bke::pbvh::BMeshNode> nodes = pbvh.nodes<bke::pbvh::BMeshNode>();
1657 nodes_to_calculate.foreach_index(GrainSize(1), [&](const int i) {
1658 const Set<BMFace *, 0> &faces = BKE_pbvh_bmesh_node_faces(
1659 &const_cast<bke::pbvh::BMeshNode &>(nodes[i]));
1660 const int visible_faces_num = count_visible_tris_bmesh(faces);
1661 ibos[i] = create_lines_index_bmesh(faces, visible_faces_num);
1662 });
1663 break;
1664 }
1665 }
1666
1667 return ibos;
1668}
1669
1670BitSpan DrawCacheImpl::ensure_use_flat_layout(const Object &object,
1671 const OrigMeshData &orig_mesh_data)
1672{
1673 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1674 if (use_flat_layout_.size() != pbvh.nodes_num()) {
1675 use_flat_layout_ = calc_use_flat_layout(object, orig_mesh_data);
1676 }
1677 return use_flat_layout_;
1678}
1679
1681 const IndexMask &node_mask)
1682{
1683 node_mask.foreach_index([&](const int i) { GPU_vertbuf_use(vbos[i].get()); });
1684}
1685
1686Span<gpu::VertBufPtr> DrawCacheImpl::ensure_attribute_data(const Object &object,
1687 const OrigMeshData &orig_mesh_data,
1688 const AttributeRequest &attr,
1689 const IndexMask &node_mask)
1690{
1691 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1692 AttributeData &data = attribute_vbos_.lookup_or_add_default(attr);
1693 Vector<gpu::VertBufPtr> &vbos = data.vbos;
1694 vbos.resize(pbvh.nodes_num());
1695
1696 /* The nodes we recompute here are a combination of:
1697 * 1. null VBOs, which correspond to nodes that either haven't been drawn before, or have been
1698 * cleared completely by #free_nodes_with_changed_topology.
1699 * 2. Nodes that have been tagged dirty as their values are changed.
1700 * We also only process a subset of the nodes referenced by the caller, for example to only
1701 * recompute visible nodes. */
1702 IndexMaskMemory memory;
1703 const IndexMask empty_mask = IndexMask::from_predicate(
1704 node_mask, GrainSize(8196), memory, [&](const int i) { return !vbos[i]; });
1705 const IndexMask dirty_mask = IndexMask::from_bits(
1706 node_mask.slice_content(data.dirty_nodes.index_range()), data.dirty_nodes, memory);
1707 const IndexMask mask = IndexMask::from_union(empty_mask, dirty_mask, memory);
1708
1709 switch (pbvh.type()) {
1710 case bke::pbvh::Type::Mesh: {
1711 if (const CustomRequest *request_type = std::get_if<CustomRequest>(&attr)) {
1712 switch (*request_type) {
1714 update_positions_mesh(object, mask, vbos);
1715 break;
1717 update_normals_mesh(object, mask, vbos);
1718 break;
1720 update_masks_mesh(object, orig_mesh_data, mask, vbos);
1721 break;
1723 update_face_sets_mesh(object, orig_mesh_data, mask, vbos);
1724 break;
1725 }
1726 }
1727 else {
1729 object, orig_mesh_data, mask, std::get<GenericRequest>(attr), vbos);
1730 }
1731 break;
1732 }
1734 if (const CustomRequest *request_type = std::get_if<CustomRequest>(&attr)) {
1735 switch (*request_type) {
1737 fill_positions_grids(object, use_flat_layout_, mask, vbos);
1738 break;
1740 fill_normals_grids(object, orig_mesh_data, use_flat_layout_, mask, vbos);
1741 break;
1743 fill_masks_grids(object, use_flat_layout_, mask, vbos);
1744 break;
1746 fill_face_sets_grids(object, orig_mesh_data, use_flat_layout_, mask, vbos);
1747 break;
1748 }
1749 }
1750 else {
1752 attribute_format(orig_mesh_data, "Dummy", CD_PROP_FLOAT3),
1753 use_flat_layout_,
1754 mask,
1755 vbos);
1756 mask.foreach_index(GrainSize(1),
1757 [&](const int i) { vbos[i]->data<float3>().fill(float3(0.0f)); });
1758 }
1759 break;
1760 }
1762 if (const CustomRequest *request_type = std::get_if<CustomRequest>(&attr)) {
1763 switch (*request_type) {
1765 update_positions_bmesh(object, mask, vbos);
1766 break;
1768 update_normals_bmesh(object, mask, vbos);
1769 break;
1771 update_masks_bmesh(object, mask, vbos);
1772 break;
1774 update_face_sets_bmesh(object, orig_mesh_data, mask, vbos);
1775 break;
1776 }
1777 }
1778 else {
1780 object, orig_mesh_data, mask, std::get<GenericRequest>(attr), vbos);
1781 }
1782 break;
1783 }
1784 }
1785
1786 /* TODO: It would be good to deallocate the bit vector if all of the bits have been reset to
1787 * avoid unnecessary processing in subsequent redraws. */
1788 dirty_mask.foreach_index_optimized<int>([&](const int i) { data.dirty_nodes[i].reset(); });
1789
1790 flush_vbo_data(vbos, mask);
1791
1792 return vbos;
1793}
1794
1795Span<gpu::IndexBufPtr> DrawCacheImpl::ensure_tri_indices(const Object &object,
1796 const OrigMeshData &orig_mesh_data,
1797 const IndexMask &node_mask,
1798 const bool coarse)
1799{
1800 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1801 switch (pbvh.type()) {
1802 case bke::pbvh::Type::Mesh: {
1803 const Span<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
1804
1805 Vector<gpu::IndexBufPtr> &ibos = tris_ibos_;
1806 ibos.resize(nodes.size());
1807
1808 /* Whenever a node's visible triangle count has changed the index buffers are freed, so we
1809 * only recalculate null IBOs here. A new mask is recalculated for more even task
1810 * distribution between threads. */
1811 IndexMaskMemory memory;
1812 const IndexMask nodes_to_calculate = IndexMask::from_predicate(
1813 node_mask, GrainSize(8196), memory, [&](const int i) { return !ibos[i]; });
1814
1815 const Mesh &mesh = DRW_object_get_data_for_drawing<Mesh>(object);
1816 const OffsetIndices<int> faces = mesh.faces();
1817 const Span<int3> corner_tris = mesh.corner_tris();
1818 const bke::AttributeAccessor attributes = orig_mesh_data.attributes;
1819 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
1820 nodes_to_calculate.foreach_index(GrainSize(1), [&](const int i) {
1821 ibos[i] = create_tri_index_mesh(faces, corner_tris, hide_poly, nodes[i]);
1822 });
1823 return ibos;
1824 }
1826 /* Unlike the other geometry types, multires grids use indexed vertex buffers because when
1827 * there are no flat faces, vertices can be shared between neighboring quads. This results in
1828 * a 4x decrease in the amount of data uploaded. Theoretically it also means freeing VBOs
1829 * because of visibility changes is unnecessary.
1830 *
1831 * TODO: With the "flat layout" and no hidden faces, the index buffers are unnecessary, we
1832 * should avoid creating them in that case. */
1833 const Span<bke::pbvh::GridsNode> nodes = pbvh.nodes<bke::pbvh::GridsNode>();
1834
1835 Vector<gpu::IndexBufPtr> &ibos = coarse ? tris_ibos_coarse_ : tris_ibos_;
1836 ibos.resize(nodes.size());
1837
1838 /* Whenever a node's visible triangle count has changed the index buffers are freed, so we
1839 * only recalculate null IBOs here. A new mask is recalculated for more even task
1840 * distribution between threads. */
1841 IndexMaskMemory memory;
1842 const IndexMask nodes_to_calculate = IndexMask::from_predicate(
1843 node_mask, GrainSize(8196), memory, [&](const int i) { return !ibos[i]; });
1844
1845 const SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1846 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1847
1848 nodes_to_calculate.foreach_index(GrainSize(1), [&](const int i) {
1849 ibos[i] = create_tri_index_grids(
1850 key, subdiv_ccg.grid_hidden, coarse, nodes[i].grids(), use_flat_layout_[i]);
1851 });
1852 return ibos;
1853 }
1855 return {};
1856 }
1858 return {};
1859}
1860
1862 const ViewportRequest &request,
1863 const IndexMask &nodes_to_update)
1864{
1865 const Object &object_orig = *DEG_get_original(&object);
1866 const OrigMeshData orig_mesh_data{*static_cast<const Mesh *>(object_orig.data)};
1867 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1868
1869 this->ensure_use_flat_layout(object, orig_mesh_data);
1870 this->free_nodes_with_changed_topology(pbvh);
1871
1872 const Span<gpu::IndexBufPtr> ibos = this->ensure_tri_indices(
1873 object, orig_mesh_data, nodes_to_update, request.use_coarse_grids);
1874
1875 for (const AttributeRequest &attr : request.attributes) {
1876 this->ensure_attribute_data(object, orig_mesh_data, attr, nodes_to_update);
1877 }
1878
1879 /* Collect VBO spans in a different loop because #ensure_attribute_data invalidates the allocated
1880 * arrays when its map is changed. */
1882 for (const AttributeRequest &attr : request.attributes) {
1883 if (const AttributeData *attr_data = attribute_vbos_.lookup_ptr(attr)) {
1884 attr_vbos.append(attr_data->vbos);
1885 }
1886 }
1887
1888 /* Except for the first iteration of the draw loop, we only need to rebuild batches for nodes
1889 * with changed topology (visible triangle count). */
1890 Vector<gpu::Batch *> &batches = tris_batches_.lookup_or_add_default(request);
1891 batches.resize(pbvh.nodes_num(), nullptr);
1892 nodes_to_update.foreach_index(GrainSize(64), [&](const int i) {
1893 if (!batches[i]) {
1894 batches[i] = GPU_batch_create(
1895 GPU_PRIM_TRIS, nullptr, ibos.is_empty() ? nullptr : ibos[i].get());
1896 for (const Span<gpu::VertBufPtr> vbos : attr_vbos) {
1897 GPU_batch_vertbuf_add(batches[i], vbos[i].get(), false);
1898 }
1899 }
1900 });
1901
1902 return batches;
1903}
1904
1906 const ViewportRequest &request,
1907 const IndexMask &nodes_to_update)
1908{
1909 const Object &object_orig = *DEG_get_original(&object);
1910 const OrigMeshData orig_mesh_data(*static_cast<const Mesh *>(object_orig.data));
1911 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1912
1913 this->ensure_use_flat_layout(object, orig_mesh_data);
1914 this->free_nodes_with_changed_topology(pbvh);
1915
1916 const Span<gpu::VertBufPtr> position = this->ensure_attribute_data(
1917 object, orig_mesh_data, CustomRequest::Position, nodes_to_update);
1918 const Span<gpu::IndexBufPtr> lines = this->ensure_lines_indices(
1919 object, orig_mesh_data, nodes_to_update, request.use_coarse_grids);
1920
1921 /* Except for the first iteration of the draw loop, we only need to rebuild batches for nodes
1922 * with changed topology (visible triangle count). */
1923 Vector<gpu::Batch *> &batches = request.use_coarse_grids ? lines_batches_coarse_ :
1924 lines_batches_;
1925 batches.resize(pbvh.nodes_num(), nullptr);
1926 nodes_to_update.foreach_index(GrainSize(64), [&](const int i) {
1927 if (!batches[i]) {
1928 batches[i] = GPU_batch_create(GPU_PRIM_LINES, nullptr, lines[i].get());
1929 GPU_batch_vertbuf_add(batches[i], position[i].get(), false);
1930 }
1931 });
1932
1933 return batches;
1934}
1935
1937{
1938 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
1939 if (material_indices_.size() != pbvh.nodes_num()) {
1940 const Object &object_orig = *DEG_get_original(&object);
1941 const OrigMeshData orig_mesh_data(*static_cast<const Mesh *>(object_orig.data));
1942 material_indices_ = calc_material_indices(object, orig_mesh_data);
1943 }
1944 return material_indices_;
1945}
1946
1947} // namespace blender::draw::pbvh
int CCG_grid_xy_to_index(const int grid_size, const int x, const int y)
Definition BKE_ccg.hh:77
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
const char * CustomData_get_render_layer_name(const CustomData *data, eCustomDataType type)
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
#define CD_TYPE_AS_MASK(_type)
void BKE_paint_face_set_overlay_color_get(int face_set, int seed, uchar r_color[4])
Definition paint.cc:2952
bool paint_is_grid_face_hidden(blender::BoundedBitSpan grid_hidden, int gridsize, int x, int y)
Definition paint.cc:1987
A BVH for high poly meshes.
const blender::Set< BMFace *, 0 > & BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::BMeshNode *node)
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_NOINLINE
MINLINE int square_i(int a)
MINLINE unsigned int square_uint(unsigned int a)
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:58
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
MINLINE void normal_float_to_short_v3(short out[3], const float in[3])
unsigned int uint
#define POINTER_OFFSET(v, ofs)
T * DEG_get_original(T *id)
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
struct Mesh Mesh
Object is a sort of wrapper for general info.
struct Object Object
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
Definition GPU_batch.hh:148
int GPU_batch_vertbuf_add(blender::gpu::Batch *batch, blender::gpu::VertBuf *vertex_buf, bool own_vbo)
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:204
blender::MutableSpan< uint32_t > GPU_indexbuf_get_data(GPUIndexBufBuilder *)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
blender::gpu::IndexBuf * GPU_indexbuf_build_ex(GPUIndexBufBuilder *builder, uint index_min, uint index_max, bool uses_restart_indices)
@ GPU_PRIM_LINES
@ GPU_PRIM_TRIS
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_use(blender::gpu::VertBuf *)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
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_I16
@ GPU_COMP_U8
@ BM_ELEM_HIDDEN
@ BM_ELEM_SMOOTH
#define BM_elem_flag_test(ele, hflag)
BMesh const char void * data
BMesh * bm
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void foreach_index(Fn &&fn) const
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:639
ValueIterator values() const &
Definition BLI_map.hh:884
constexpr int64_t size() const
Definition BLI_span.hh:252
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_bits(BitSpan bits, IndexMaskMemory &memory)
static IndexMask from_union(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
static IndexMask from_intersection(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
constexpr int64_t first() const
constexpr int64_t size() const
constexpr T * data() const
Definition BLI_span.hh:539
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
void append(const T &value)
void resize(const int64_t new_size)
void resize(const int64_t new_size_in_bits, const bool value=false)
GAttributeReader lookup(const StringRef attribute_id) const
Span< NodeT > nodes() const
void tag_visibility_changed(const IndexMask &node_mask) override
Definition draw_pbvh.cc:211
void tag_positions_changed(const IndexMask &node_mask) override
Definition draw_pbvh.cc:201
Span< int > ensure_material_indices(const Object &object) override
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name) override
Definition draw_pbvh.cc:238
Span< gpu::Batch * > ensure_tris_batches(const Object &object, const ViewportRequest &request, const IndexMask &nodes_to_update) override
void tag_masks_changed(const IndexMask &node_mask) override
Definition draw_pbvh.cc:231
void tag_topology_changed(const IndexMask &node_mask) override
Definition draw_pbvh.cc:217
void tag_face_sets_changed(const IndexMask &node_mask) override
Definition draw_pbvh.cc:224
Span< gpu::Batch * > ensure_lines_batches(const Object &object, const ViewportRequest &request, const IndexMask &nodes_to_update) override
MutableSpan< T > data()
IndexMask slice_content(IndexRange range) const
void set_bits(MutableBitSpan r_bits, int64_t offset=0) const
void foreach_index(Fn &&fn) const
Mesh & DRW_object_get_data_for_drawing(const Object &object)
static float normals[][3]
#define CD_MASK_COLOR_ALL
format
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong * next
#define T
static char faces[256]
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
IndexRange grid_range(const int grid_area, const int grid)
int face_triangles_num(const int face_size)
Definition BKE_mesh.hh:334
IndexRange face_triangles_range(OffsetIndices< int > faces, int face_i)
Definition BKE_mesh.hh:343
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2912
Span< float3 > vert_normals_eval_from_eval(const Object &object_eval)
Definition pbvh.cc:2441
int count_grid_quads(const BitGroupVector<> &grid_hidden, Span< int > grid_indices, int gridsize, int display_gridsize)
Definition pbvh.cc:1421
Span< float3 > vert_positions_eval_from_eval(const Object &object_eval)
Definition pbvh.cc:2422
Span< float3 > face_normals_eval_from_eval(const Object &object_eval)
Definition pbvh.cc:2448
eCustomDataType cpp_type_to_custom_data_type(const CPPType &type)
void extract_data_vert_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< T > attribute, const Span< int > face_indices, gpu::VertBuf &vbo)
Definition draw_pbvh.cc:341
static BLI_NOINLINE void flush_vbo_data(const Span< gpu::VertBufPtr > vbos, const IndexMask &node_mask)
static BLI_NOINLINE void update_face_sets_bmesh(const Object &object, const OrigMeshData &orig_mesh_data, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
static BLI_NOINLINE void fill_masks_grids(const Object &object, const BitSpan use_flat_layout, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:838
static BLI_NOINLINE void ensure_vbos_allocated_bmesh(const Object &object, const GPUVertFormat &format, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:553
static BLI_NOINLINE void update_positions_bmesh(const Object &object, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:927
void extract_data_corner_mesh(const OffsetIndices< int > faces, const Span< T > attribute, const Span< int > face_indices, gpu::VertBuf &vbo)
Definition draw_pbvh.cc:376
static BMeshAttributeLookup lookup_bmesh_attribute(const BMesh &bm, const StringRef name)
static void update_normals_mesh(const Object &object, const IndexMask &node_mask, MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:588
static int count_visible_tris_bmesh(const Set< BMFace *, 0 > &faces)
Definition draw_pbvh.cc:468
const T & bmesh_cd_loop_get(const BMLoop &loop, const int offset)
Definition draw_pbvh.cc:398
static gpu::IndexBufPtr create_lines_index_faces(const OffsetIndices< int > faces, const Span< bool > hide_poly, const Span< int > face_indices)
static BitVector calc_use_flat_layout(const Object &object, const OrigMeshData &orig_mesh_data)
static const GPUVertFormat & normal_format()
Definition draw_pbvh.cc:288
static const GPUVertFormat & face_set_format()
Definition draw_pbvh.cc:302
DrawCache & ensure_draw_data(std::unique_ptr< bke::pbvh::DrawCache > &ptr)
Definition draw_pbvh.cc:249
static const GPUVertFormat & position_format()
Definition draw_pbvh.cc:281
static BLI_NOINLINE void update_generic_attribute_mesh(const Object &object, const OrigMeshData &orig_mesh_data, const IndexMask &node_mask, const StringRef name, MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:692
static BLI_NOINLINE void update_masks_bmesh(const Object &object, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:985
static void create_lines_index_grids_flat_layout(const Span< int > grid_indices, int display_gridsize, const BitGroupVector<> &grid_hidden, const int gridsize, const int skip, const int totgrid, MutableSpan< uint2 > data)
const T & bmesh_cd_face_get(const BMFace &face, const int offset)
Definition draw_pbvh.cc:403
static void create_lines_index_grids(const Span< int > grid_indices, int display_gridsize, const BitGroupVector<> &grid_hidden, const int gridsize, const int skip, const int totgrid, MutableSpan< uint2 > data)
static BLI_NOINLINE void update_generic_attribute_bmesh(const Object &object, const OrigMeshData &orig_mesh_data, const IndexMask &node_mask, const StringRef name, const MutableSpan< gpu::VertBufPtr > vbos)
static GPUVertFormat attribute_format(const OrigMeshData &orig_mesh_data, const StringRef name, const eCustomDataType data_type)
Definition draw_pbvh.cc:309
void extract_data_face_bmesh(const Set< BMFace *, 0 > &faces, const int cd_offset, gpu::VertBuf &vbo)
Definition draw_pbvh.cc:430
static Array< int > calc_material_indices(const Object &object, const OrigMeshData &orig_mesh_data)
short4 normal_float_to_short(const float3 &value)
Definition draw_pbvh.cc:333
static BLI_NOINLINE void free_vbos(const MutableSpan< gpu::VertBufPtr > vbos, const IndexMask &node_mask)
Definition draw_pbvh.cc:265
static BLI_NOINLINE void fill_face_sets_grids(const Object &object, const OrigMeshData &orig_mesh_data, const BitSpan use_flat_layout, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:885
static gpu::IndexBufPtr create_tri_index_mesh(const OffsetIndices< int > faces, const Span< int3 > corner_tris, const Span< bool > hide_poly, const bke::pbvh::MeshNode &node)
static BLI_NOINLINE void free_batches(const MutableSpan< gpu::Batch * > batches, const IndexMask &node_mask)
Definition draw_pbvh.cc:273
void extract_data_vert_bmesh(const Set< BMFace *, 0 > &faces, const int cd_offset, gpu::VertBuf &vbo)
Definition draw_pbvh.cc:409
void extract_data_face_mesh(const OffsetIndices< int > faces, const Span< T > attribute, const Span< int > face_indices, gpu::VertBuf &vbo)
Definition draw_pbvh.cc:359
static BLI_NOINLINE void update_masks_mesh(const Object &object, const OrigMeshData &orig_mesh_data, const IndexMask &node_mask, MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:621
static void create_tri_index_grids(const Span< int > grid_indices, const BitGroupVector<> &grid_hidden, const int gridsize, const int skip, const int totgrid, MutableSpan< uint3 > data)
static void update_positions_mesh(const Object &object, const IndexMask &node_mask, MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:571
static BLI_NOINLINE void update_normals_bmesh(const Object &object, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:953
void extract_data_corner_bmesh(const Set< BMFace *, 0 > &faces, const int cd_offset, gpu::VertBuf &vbo)
Definition draw_pbvh.cc:446
static void create_tri_index_grids_flat_layout(const Span< int > grid_indices, const BitGroupVector<> &grid_hidden, const int gridsize, const int skip, const int totgrid, MutableSpan< uint3 > data)
static BLI_NOINLINE void ensure_vbos_allocated_mesh(const Object &object, const GPUVertFormat &format, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:518
static BLI_NOINLINE void fill_normals_grids(const Object &object, const OrigMeshData &orig_mesh_data, const BitSpan use_flat_layout, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:775
static BLI_NOINLINE void ensure_vbos_allocated_grids(const Object &object, const GPUVertFormat &format, const BitSpan use_flat_layout, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:533
static BLI_NOINLINE void fill_positions_grids(const Object &object, const BitSpan use_flat_layout, const IndexMask &node_mask, const MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:734
static gpu::IndexBufPtr create_lines_index_bmesh(const Set< BMFace *, 0 > &faces, const int visible_faces_num)
static BLI_NOINLINE void free_ibos(const MutableSpan< gpu::IndexBufPtr > ibos, const IndexMask &node_mask)
Definition draw_pbvh.cc:257
const T & bmesh_cd_vert_get(const BMVert &vert, const int offset)
Definition draw_pbvh.cc:393
static const GPUVertFormat & mask_format()
Definition draw_pbvh.cc:295
std::string GenericRequest
Definition DRW_pbvh.hh:39
static BLI_NOINLINE void update_face_sets_mesh(const Object &object, const OrigMeshData &orig_mesh_data, const IndexMask &node_mask, MutableSpan< gpu::VertBufPtr > vbos)
Definition draw_pbvh.cc:651
std::variant< CustomRequest, GenericRequest > AttributeRequest
Definition DRW_pbvh.hh:48
GPUVertFormat init_format_for_attribute(const eCustomDataType data_type, const StringRef vbo_name)
void DRW_cdlayer_attr_aliases_add(GPUVertFormat *format, const char *base_name, int data_type, blender::StringRef layer_name, bool is_active_render, bool is_active_layer)
std::unique_ptr< IndexBuf, IndexBufDeleter > IndexBufPtr
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
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
blender::VecBase< int16_t, 3 > short3
VecBase< uint32_t, 3 > uint3
blender::VecBase< int16_t, 4 > short4
blender::VecBase< uint8_t, 4 > uchar4
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
BMHeader head
void * data
BMHeader head
BMHeader head
int grid_size
Definition BKE_ccg.hh:33
int level
Definition BKE_ccg.hh:26
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:415
blender::BitGroupVector grid_hidden
blender::Span< int > grid_to_face_map
uint64_t operator()(const draw::pbvh::AttributeRequest &value) const
Definition draw_pbvh.cc:42
bke::AttributeAccessor attributes
Definition draw_pbvh.cc:74
Vector< AttributeRequest > attributes
Definition DRW_pbvh.hh:51
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4227