Blender V5.0
spreadsheet_data_source_geometry.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <fmt/format.h>
6
7#include "BLI_listbase.h"
8#include "BLI_math_matrix.hh"
10
11#include "BKE_attribute.hh"
12#include "BKE_context.hh"
13#include "BKE_curves.hh"
14#include "BKE_editmesh.hh"
16#include "BKE_geometry_set.hh"
18#include "BKE_global.hh"
19#include "BKE_grease_pencil.hh"
20#include "BKE_instances.hh"
21#include "BKE_lib_id.hh"
22#include "BKE_mesh.hh"
23#include "BKE_mesh_wrapper.hh"
24#include "BKE_modifier.hh"
25#include "BKE_object_types.hh"
26#include "BKE_volume.hh"
27#include "BKE_volume_grid.hh"
28
30#include "DNA_space_types.h"
31
33
34#include "ED_curves.hh"
35#include "ED_outliner.hh"
36
41
42#include "BLT_translation.hh"
43
44#include "RNA_access.hh"
45#include "RNA_enum_types.hh"
46
47#include "UI_resources.hh"
48
49#include "bmesh.hh"
50
52#include "spreadsheet_intern.hh"
53
54uint64_t SpreadsheetInstanceID::hash() const
55{
57}
58
60{
61 return a.reference_index == b.reference_index;
62}
63
65{
66 return !(a == b);
67}
68
70{
71 return STREQ(a.identifier, b.identifier);
72}
73
75{
76 return !(a == b);
77}
78
80
82 const Mesh &mesh,
83 const bke::AttrDomain domain,
84 FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn)
85{
86 switch (domain) {
88 if (CustomData_has_layer(&mesh.vert_data, CD_ORIGINDEX)) {
89 fn({(char *)"Original Index"}, false);
90 }
91 break;
93 if (CustomData_has_layer(&mesh.edge_data, CD_ORIGINDEX)) {
94 fn({(char *)"Original Index"}, false);
95 }
96 break;
98 if (CustomData_has_layer(&mesh.face_data, CD_ORIGINDEX)) {
99 fn({(char *)"Original Index"}, false);
100 }
101 fn({(char *)"Corner Start"}, false);
102 fn({(char *)"Corner Size"}, false);
103 break;
105 break;
106 default:
108 break;
109 }
110}
111
112static std::unique_ptr<ColumnValues> build_mesh_debug_columns(const Mesh &mesh,
113 const bke::AttrDomain domain,
114 const StringRef name)
115{
116 switch (domain) {
118 if (name == "Original Index") {
119 const int *data = static_cast<const int *>(
121 if (data) {
122 return std::make_unique<ColumnValues>(name,
123 VArray<int>::from_span({data, mesh.verts_num}));
124 }
125 }
126 return {};
127 }
129 if (name == "Original Index") {
130 const int *data = static_cast<const int *>(
132 if (data) {
133 return std::make_unique<ColumnValues>(name,
134 VArray<int>::from_span({data, mesh.edges_num}));
135 }
136 }
137 return {};
138 }
140 if (name == "Original Index") {
141 const int *data = static_cast<const int *>(
143 if (data) {
144 return std::make_unique<ColumnValues>(name,
145 VArray<int>::from_span({data, mesh.faces_num}));
146 }
147 }
148 if (name == "Corner Start") {
149 return std::make_unique<ColumnValues>(
150 name, VArray<int>::from_span(mesh.face_offsets().drop_back(1)));
151 }
152 if (name == "Corner Size") {
153 const OffsetIndices faces = mesh.faces();
154 return std::make_unique<ColumnValues>(
156 return faces[index].size();
157 }));
158 }
159 return {};
160 }
162 return {};
163 }
164 default:
166 return {};
167 }
168}
169
170bool GeometryDataSource::display_attribute(const StringRef name,
171 const bke::AttrDomain domain) const
172{
174 return false;
175 }
176 if (!show_internal_attributes_) {
178 return false;
179 }
180 if (domain == bke::AttrDomain::Instance && name == "instance_transform") {
181 /* Don't display the instance transform attribute, since matrix visualization in the
182 * spreadsheet isn't helpful. */
183 return false;
184 }
185 }
186 return true;
187}
188
190 FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
191{
192 std::optional<const bke::AttributeAccessor> attributes = this->get_component_attributes();
193 if (!attributes.has_value()) {
194 return;
195 }
196 if (attributes->domain_size(domain_) == 0) {
197 return;
198 }
199
200 if (component_->type() == bke::GeometryComponent::Type::Instance) {
201 fn({(char *)"Name"}, false);
202 }
203
204 if (component_->type() == bke::GeometryComponent::Type::GreasePencil) {
205 fn({(char *)"Name"}, false);
206 }
207
208 attributes->foreach_attribute([&](const bke::AttributeIter &iter) {
209 if (iter.domain != domain_) {
210 return;
211 }
212 if (!display_attribute(iter.name, iter.domain)) {
213 return;
214 }
215 SpreadsheetColumnID column_id;
216 column_id.name = (char *)iter.name.data();
217 const bool is_front = iter.name == ".viewer";
218 fn(column_id, is_front);
219 });
220
221 if (component_->type() == bke::GeometryComponent::Type::Instance) {
222 fn({(char *)"Position"}, false);
223 fn({(char *)"Rotation"}, false);
224 fn({(char *)"Scale"}, false);
225 }
226 else if (G.debug_value == 4001 && component_->type() == bke::GeometryComponent::Type::Mesh) {
227 const bke::MeshComponent &component = static_cast<const bke::MeshComponent &>(*component_);
228 if (const Mesh *mesh = component.get()) {
230 }
231 }
232}
233
234std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
235 const SpreadsheetColumnID &column_id) const
236{
237 std::optional<const bke::AttributeAccessor> attributes = this->get_component_attributes();
238 if (!attributes.has_value()) {
239 return {};
240 }
241 const int domain_num = attributes->domain_size(domain_);
242 if (domain_num == 0) {
243 return {};
244 }
245 if (!display_attribute(column_id.name, domain_)) {
246 return {};
247 }
248
249 std::lock_guard lock{mutex_};
250
251 if (component_->type() == bke::GeometryComponent::Type::Instance) {
252 if (const bke::Instances *instances =
253 static_cast<const bke::InstancesComponent &>(*component_).get())
254 {
255 if (STREQ(column_id.name, "Name")) {
256 Span<int> reference_handles = instances->reference_handles();
257 Span<bke::InstanceReference> references = instances->references();
258 return std::make_unique<ColumnValues>(
259 column_id.name,
261 domain_num, [reference_handles, references](int64_t index) {
262 return references[reference_handles[index]];
263 }));
264 }
265 Span<float4x4> transforms = instances->transforms();
266 if (STREQ(column_id.name, "Position")) {
267 return std::make_unique<ColumnValues>(
268 column_id.name, VArray<float3>::from_std_func(domain_num, [transforms](int64_t index) {
269 return transforms[index].location();
270 }));
271 }
272 if (STREQ(column_id.name, "Rotation")) {
273 return std::make_unique<ColumnValues>(
274 column_id.name, VArray<float3>::from_std_func(domain_num, [transforms](int64_t index) {
275 return float3(math::to_euler(math::normalize(transforms[index])));
276 }));
277 }
278 if (STREQ(column_id.name, "Scale")) {
279 return std::make_unique<ColumnValues>(
280 column_id.name, VArray<float3>::from_std_func(domain_num, [transforms](int64_t index) {
281 return math::to_scale<true>(transforms[index]);
282 }));
283 }
284 }
285 }
286 else if (component_->type() == bke::GeometryComponent::Type::GreasePencil) {
287 if (const GreasePencil *grease_pencil =
288 static_cast<const bke::GreasePencilComponent &>(*component_).get())
289 {
290 if (domain_ == bke::AttrDomain::Layer && STREQ(column_id.name, "Name")) {
291 const Span<const bke::greasepencil::Layer *> layers = grease_pencil->layers();
292 return std::make_unique<ColumnValues>(
293 column_id.name,
294 VArray<std::string>::from_std_func(domain_num, [layers](int64_t index) {
295 StringRefNull name = layers[index]->name();
296 if (name.is_empty()) {
297 name = IFACE_("(Layer)");
298 }
299 return std::string(name);
300 }));
301 }
302 }
303 }
304 else if (G.debug_value == 4001 && component_->type() == bke::GeometryComponent::Type::Mesh) {
305 const bke::MeshComponent &component = static_cast<const bke::MeshComponent &>(*component_);
306 if (const Mesh *mesh = component.get()) {
307 if (std::unique_ptr<ColumnValues> values = build_mesh_debug_columns(
308 *mesh, domain_, column_id.name))
309 {
310 return values;
311 }
312 }
313 }
314
315 bke::GAttributeReader attribute = attributes->lookup(column_id.name);
316 if (!attribute) {
317 return {};
318 }
319 GVArray varray = std::move(attribute.varray);
320 if (attribute.domain != domain_) {
321 return {};
322 }
323
324 StringRefNull column_display_name = column_id.name;
325 if (column_display_name == ".viewer") {
326 column_display_name = "Viewer";
327 }
328
329 return std::make_unique<ColumnValues>(column_display_name, std::move(varray));
330}
331
333{
334 std::optional<const bke::AttributeAccessor> attributes = this->get_component_attributes();
335 if (!attributes.has_value()) {
336 return {};
337 }
338 return attributes->domain_size(domain_);
339}
340
342{
343 if (!object_orig_) {
344 return false;
345 }
346 switch (component_->type()) {
348 if (object_orig_->type != OB_MESH) {
349 return false;
350 }
351 if (object_orig_->mode != OB_MODE_EDIT) {
352 return false;
353 }
354 return true;
355 }
357 if (object_orig_->type != OB_CURVES) {
358 return false;
359 }
360 if (!ELEM(object_orig_->mode, OB_MODE_SCULPT_CURVES, OB_MODE_EDIT)) {
361 return false;
362 }
363 return true;
364 }
366 if (object_orig_->type != OB_POINTCLOUD) {
367 return false;
368 }
369 if (object_orig_->mode != OB_MODE_EDIT) {
370 return false;
371 }
372 return true;
373 }
374 default:
375 return false;
376 }
377}
378
380 const Mesh &mesh_orig,
381 IndexMaskMemory &memory)
382{
383 const bke::AttributeAccessor attributes_eval = mesh_eval.attributes();
384 const IndexRange range(attributes_eval.domain_size(bke::AttrDomain::Face));
385 BMesh *bm = mesh_orig.runtime->edit_mesh->bm;
386
388 if (mesh_eval.faces_num == bm->totface) {
389 return IndexMask::from_predicate(range, GrainSize(4096), memory, [&](const int i) {
390 const BMFace *face = BM_face_at_index(bm, i);
392 });
393 }
394 if (const int *orig_indices = static_cast<const int *>(
396 {
397 return IndexMask::from_predicate(range, GrainSize(2048), memory, [&](const int i) {
398 const int orig = orig_indices[i];
399 if (orig == -1) {
400 return false;
401 }
402 const BMFace *face = BM_face_at_index(bm, orig);
404 });
405 }
406 return range;
407}
408
410 const Mesh &mesh_orig,
411 const bke::AttrDomain domain,
412 IndexMaskMemory &memory)
413{
414 const bke::AttributeAccessor attributes_eval = mesh_eval.attributes();
415 const IndexRange range(attributes_eval.domain_size(domain));
416 BMesh *bm = mesh_orig.runtime->edit_mesh->bm;
417
418 switch (domain) {
421 if (mesh_eval.verts_num == bm->totvert) {
422 return IndexMask::from_predicate(range, GrainSize(4096), memory, [&](const int i) {
423 const BMVert *vert = BM_vert_at_index(bm, i);
425 });
426 }
427 if (const int *orig_indices = static_cast<const int *>(
429 {
430 return IndexMask::from_predicate(range, GrainSize(2048), memory, [&](const int i) {
431 const int orig = orig_indices[i];
432 if (orig == -1) {
433 return false;
434 }
435 const BMVert *vert = BM_vert_at_index(bm, orig);
437 });
438 }
439 return range;
440 }
443 if (mesh_eval.edges_num == bm->totedge) {
444 return IndexMask::from_predicate(range, GrainSize(4096), memory, [&](const int i) {
445 const BMEdge *edge = BM_edge_at_index(bm, i);
447 });
448 }
449 if (const int *orig_indices = static_cast<const int *>(
451 {
452 return IndexMask::from_predicate(range, GrainSize(2048), memory, [&](const int i) {
453 const int orig = orig_indices[i];
454 if (orig == -1) {
455 return false;
456 }
457 const BMEdge *edge = BM_edge_at_index(bm, orig);
459 });
460 }
461 return range;
462 }
464 return calc_mesh_selection_mask_faces(mesh_eval, mesh_orig, memory);
465 }
467 IndexMaskMemory face_memory;
469 mesh_eval, mesh_orig, face_memory);
470 if (face_mask.is_empty()) {
471 return {};
472 }
473 if (face_mask.size() == range.size()) {
474 return range;
475 }
476
477 Array<bool> face_selection(range.size(), false);
478 face_mask.to_bools(face_selection);
479
480 const VArray<bool> corner_selection = attributes_eval.adapt_domain<bool>(
482 return IndexMask::from_bools(corner_selection, memory);
483 }
484 default:
486 return range;
487 }
488}
489
491{
492 std::lock_guard lock{mutex_};
493 const IndexMask full_range(this->tot_rows());
494 if (full_range.is_empty()) {
495 return full_range;
496 }
497
498 switch (component_->type()) {
500 BLI_assert(object_orig_->type == OB_MESH);
501 BLI_assert(object_orig_->mode == OB_MODE_EDIT);
502 const Mesh *mesh_eval = geometry_set_.get_mesh();
503 const Mesh *mesh_orig = static_cast<const Mesh *>(object_orig_->data);
504 return calc_mesh_selection_mask(*mesh_eval, *mesh_orig, domain_, memory);
505 }
507 BLI_assert(object_orig_->type == OB_CURVES);
508 const bke::CurveComponent &component = static_cast<const bke::CurveComponent &>(*component_);
509 const Curves &curves_id = *component.get();
510 switch (domain_) {
512 return curves::retrieve_selected_points(curves_id, memory);
514 return curves::retrieve_selected_curves(curves_id, memory);
515 default:
517 }
518 return full_range;
519 }
521 BLI_assert(object_orig_->type == OB_POINTCLOUD);
522 const bke::AttributeAccessor attributes = *component_->attributes();
523 const VArray<bool> selection = *attributes.lookup_or_default(
524 ".selection", bke::AttrDomain::Point, true);
525 return IndexMask::from_bools(selection, memory);
526 }
527 default:
528 return full_range;
529 }
530}
531
532std::optional<const bke::AttributeAccessor> GeometryDataSource::get_component_attributes() const
533{
534 if (component_->type() != bke::GeometryComponent::Type::GreasePencil) {
535 return component_->attributes();
536 }
537 const GreasePencil *grease_pencil = geometry_set_.get_grease_pencil();
538 if (!grease_pencil) {
539 return {};
540 }
541 if (domain_ == bke::AttrDomain::Layer) {
542 return grease_pencil->attributes();
543 }
544 if (layer_index_ >= 0 && layer_index_ < grease_pencil->layers().size()) {
545 if (const bke::greasepencil::Drawing *drawing = grease_pencil->get_eval_drawing(
546 grease_pencil->layer(layer_index_)))
547 {
548 return drawing->strokes().attributes();
549 }
550 }
551 return {};
552}
553
555 FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
556{
557 if (component_->is_empty()) {
558 return;
559 }
560
561 for (const char *name :
562 {"Grid Name", "Data Type", "Class", "Extent", "Voxels", "Leaf Voxels", "Tiles", "Size"})
563 {
564 SpreadsheetColumnID column_id{(char *)name};
565 fn(column_id, false);
566 }
567}
568
569#ifdef WITH_OPENVDB
570static StringRef grid_class_name(const bke::VolumeGridData &grid_data)
571{
572 openvdb::GridClass grid_class = grid_data.grid_class();
573 if (grid_class == openvdb::GridClass::GRID_FOG_VOLUME) {
574 return IFACE_("Fog Volume");
575 }
576 if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) {
577 return IFACE_("Level Set");
578 }
579 return IFACE_("Unknown");
580}
581#endif
582
583std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values(
584 const SpreadsheetColumnID &column_id) const
585{
586 const Volume *volume = component_->get();
587 if (volume == nullptr) {
588 return {};
589 }
590
591#ifdef WITH_OPENVDB
592 const int size = this->tot_rows();
593 if (STREQ(column_id.name, "Grid Name")) {
594 return std::make_unique<ColumnValues>(
595 IFACE_("Grid Name"), VArray<std::string>::from_std_func(size, [volume](int64_t index) {
596 const bke::VolumeGridData *volume_grid = BKE_volume_grid_get(volume, index);
597 return volume_grid->name();
598 }));
599 }
600 if (STREQ(column_id.name, "Data Type")) {
601 return std::make_unique<ColumnValues>(
602 IFACE_("Data Type"), VArray<std::string>::from_std_func(size, [volume](int64_t index) {
603 const bke::VolumeGridData *volume_grid = BKE_volume_grid_get(volume, index);
604 const VolumeGridType type = volume_grid->grid_type();
605 const char *name = nullptr;
607 return IFACE_(name);
608 }));
609 }
610 if (STREQ(column_id.name, "Class")) {
611 return std::make_unique<ColumnValues>(
612 IFACE_("Class"), VArray<std::string>::from_std_func(size, [volume](int64_t index) {
613 return grid_class_name(*BKE_volume_grid_get(volume, index));
614 }));
615 }
616 if (STREQ(column_id.name, "Voxels")) {
617 return std::make_unique<ColumnValues>(
618 IFACE_("Voxels"), VArray<int64_t>::from_std_func(size, [volume](const int64_t index) {
619 return BKE_volume_grid_get(volume, index)->active_voxels();
620 }));
621 }
622 if (STREQ(column_id.name, "Leaf Voxels")) {
623 return std::make_unique<ColumnValues>(
624 IFACE_("Leaf Voxels"), VArray<int64_t>::from_std_func(size, [volume](const int64_t index) {
625 return BKE_volume_grid_get(volume, index)->active_leaf_voxels();
626 }));
627 }
628 if (STREQ(column_id.name, "Tiles")) {
629 return std::make_unique<ColumnValues>(
630 IFACE_("Tiles"), VArray<int64_t>::from_std_func(size, [volume](const int64_t index) {
631 return BKE_volume_grid_get(volume, index)->active_tiles();
632 }));
633 }
634 if (STREQ(column_id.name, "Size")) {
635 return std::make_unique<ColumnValues>(
636 IFACE_("Size"),
638 size,
639 [volume](const int64_t index) {
640 return BKE_volume_grid_get(volume, index)->size_in_bytes();
641 }),
643 }
644 if (STREQ(column_id.name, "Extent")) {
645 return std::make_unique<ColumnValues>(
646 IFACE_("Extent"), VArray<int3>::from_std_func(size, [volume](const int64_t index) {
647 return int3(BKE_volume_grid_get(volume, index)->active_bounds().dim().asPointer());
648 }));
649 }
650#else
651 UNUSED_VARS(column_id);
652#endif
653
654 return {};
655}
656
658{
659 const Volume *volume = component_->get();
660 if (volume == nullptr) {
661 return 0;
662 }
663 return BKE_volume_num_grids(volume);
664}
665
666#ifdef WITH_OPENVDB
667
668VolumeGridDataSource::VolumeGridDataSource(const bke::GVolumeGrid &grid)
669 : grid_(std::make_unique<bke::GVolumeGrid>(grid))
670{
671}
672
673void VolumeGridDataSource::foreach_default_column_ids(
674 FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
675{
676 if (!grid_) {
677 return;
678 }
679
680 for (const char *name :
681 {"Data Type", "Class", "Extent", "Voxels", "Leaf Voxels", "Tiles", "Size"})
682 {
683 SpreadsheetColumnID column_id{(char *)name};
684 fn(column_id, false);
685 }
686}
687
688std::unique_ptr<ColumnValues> VolumeGridDataSource::get_column_values(
689 const SpreadsheetColumnID &column_id) const
690{
691 const bke::VolumeGridData &grid = grid_->get();
692 if (STREQ(column_id.name, "Data Type")) {
693 const VolumeGridType type = grid.grid_type();
694 const char *name = nullptr;
696 return std::make_unique<ColumnValues>(IFACE_("Data Type"),
698 }
699 if (STREQ(column_id.name, "Class")) {
700 const StringRef name = grid_class_name(grid_->get());
701 return std::make_unique<ColumnValues>(IFACE_("Class"),
703 }
704 if (STREQ(column_id.name, "Voxels")) {
705 const int64_t active_voxels = grid.active_voxels();
706 return std::make_unique<ColumnValues>(IFACE_("Voxels"),
707 VArray<int64_t>::from_single(active_voxels, 1));
708 }
709 if (STREQ(column_id.name, "Leaf Voxels")) {
710 const int64_t active_leaf_voxels = grid.active_leaf_voxels();
711 return std::make_unique<ColumnValues>(IFACE_("Leaf Voxels"),
712 VArray<int64_t>::from_single(active_leaf_voxels, 1));
713 }
714 if (STREQ(column_id.name, "Tiles")) {
715 const int64_t active_tiles = grid.active_tiles();
716 return std::make_unique<ColumnValues>(IFACE_("Tiles"),
717 VArray<int64_t>::from_single(active_tiles, 1));
718 }
719 if (STREQ(column_id.name, "Size")) {
720 const int64_t size = grid.size_in_bytes();
721 return std::make_unique<ColumnValues>(
723 }
724 if (STREQ(column_id.name, "Extent")) {
725 const int3 extent = int3(grid.active_bounds().dim().asPointer());
726 return std::make_unique<ColumnValues>(IFACE_("Extent"), VArray<int3>::from_single(extent, 1));
727 }
728 return {};
729}
730
731int VolumeGridDataSource::tot_rows() const
732{
733 return 1;
734}
735
736#endif
737
738ListDataSource::ListDataSource(nodes::ListPtr list) : list_(std::move(list)) {}
739
741 FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
742{
743 if (list_->size() == 0) {
744 return;
745 }
746
747 for (const char *name : {"Value"}) {
748 SpreadsheetColumnID column_id{(char *)name};
749 fn(column_id, false);
750 }
751}
752
753std::unique_ptr<ColumnValues> ListDataSource::get_column_values(
754 const SpreadsheetColumnID &column_id) const
755{
756 if (STREQ(column_id.name, "Value")) {
757 return std::make_unique<ColumnValues>(IFACE_("Value"), list_->varray());
758 }
759 return {};
760}
761
763{
764 return list_->size();
765}
766
767BundleDataSource::BundleDataSource(nodes::BundlePtr bundle) : bundle_(std::move(bundle))
768{
769 this->collect_flat_items(*bundle_, "");
770}
771
773 FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
774{
775 if (bundle_->is_empty()) {
776 return;
777 }
778
779 for (const char *name : {"Identifier", "Type", "Value"}) {
780 SpreadsheetColumnID column_id{(char *)name};
781 fn(column_id, false);
782 }
783}
784
785std::unique_ptr<ColumnValues> BundleDataSource::get_column_values(
786 const SpreadsheetColumnID &column_id) const
787{
788 if (STREQ(column_id.name, "Identifier")) {
789 return std::make_unique<ColumnValues>(IFACE_("Identifier"),
790 VArray<std::string>::from_span(flat_item_keys_));
791 }
792 if (STREQ(column_id.name, "Type")) {
793 return std::make_unique<ColumnValues>(
794 IFACE_("Type"),
796 flat_items_.size(), [items = flat_items_](int64_t index) -> std::string {
797 const nodes::BundleItemValue &value = *items[index];
798 if (const auto *socket_value = std::get_if<nodes::BundleItemSocketValue>(
799 &value.value)) {
800 const bke::SocketValueVariant &value_variant = socket_value->value;
801 const StringRef type_name = IFACE_(socket_value->type->label);
802 if (value_variant.is_single()) {
803 return type_name;
804 }
805 if (value_variant.is_context_dependent_field()) {
806 return fmt::format("{} {}", type_name, IFACE_("Field"));
807 }
808 if (value_variant.is_volume_grid()) {
809 return fmt::format("{} {}", type_name, IFACE_("Grid"));
810 }
811 if (value_variant.is_list()) {
812 return fmt::format("{} {}", type_name, IFACE_("List"));
813 }
814 return type_name;
815 }
816 if (const auto *internal_value = std::get_if<nodes::BundleItemInternalValue>(
817 &value.value)) {
818 return internal_value->value->type_name();
819 }
820 return "";
821 }));
822 }
823 if (STREQ(column_id.name, "Value")) {
824 return std::make_unique<ColumnValues>(
825 IFACE_("Value"),
827 flat_items_.size(),
828 [items = flat_items_](const int64_t index) -> nodes::BundleItemValue {
829 return *items[index];
830 }));
831 }
832 return {};
833}
834
836{
837 return flat_item_keys_.size();
838}
839
840void BundleDataSource::collect_flat_items(const nodes::Bundle &bundle, const StringRef parent_path)
841{
842 const Span<nodes::Bundle::StoredItem> items = bundle.items();
843 for (const nodes::Bundle::StoredItem &item : items) {
844 const std::string path = parent_path.is_empty() ?
845 item.key :
846 nodes::Bundle::combine_path({parent_path, item.key});
847 flat_item_keys_.append(path);
848 flat_items_.append(&item.value);
849 if (const auto *value = std::get_if<nodes::BundleItemSocketValue>(&item.value.value)) {
850 if (value->value.is_single()) {
851 const GPointer ptr = value->value.get_single_ptr();
852 if (ptr.is_type<nodes::BundlePtr>()) {
853 const nodes::BundlePtr child_bundle = *ptr.get<nodes::BundlePtr>();
854 if (child_bundle) {
855 this->collect_flat_items(*child_bundle, path);
856 }
857 }
858 }
859 }
860 }
861}
862
865 : closure_(std::move(closure)), in_out_(in_out)
866{
867}
868
870 FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
871{
872 Vector<StringRefNull> columns_names;
873 if (in_out_ == SPREADSHEET_CLOSURE_NONE) {
874 columns_names.append("Interface");
875 }
876 columns_names.extend({"Identifier", "Type"});
877
878 for (const StringRefNull name : columns_names) {
879 SpreadsheetColumnID column_id{(char *)name.c_str()};
880 fn(column_id, false);
881 }
882}
883
885 const SpreadsheetColumnID &column_id) const
886{
887 const Span<nodes::ClosureSignature::Item> input_items = closure_->signature().inputs;
888 const Span<nodes::ClosureSignature::Item> output_items = closure_->signature().outputs;
889
890 switch (in_out_) {
892 const int items_sum = input_items.size() + output_items.size();
893 if (STREQ(column_id.name, "Identifier")) {
894 return std::make_unique<ColumnValues>(
895 IFACE_("Identifier"),
897 [input_items, output_items](const int64_t index) {
898 if (index < input_items.size()) {
899 return input_items[index].key;
900 }
901 return output_items[index - input_items.size()].key;
902 }));
903 }
904 if (STREQ(column_id.name, "Type")) {
905 return std::make_unique<ColumnValues>(
906 IFACE_("Type"),
908 items_sum, [input_items, output_items](const int64_t index) {
909 if (index < input_items.size()) {
910 return input_items[index].type->label;
911 }
912 return output_items[index - input_items.size()].type->label;
913 }));
914 }
915 if (STREQ(column_id.name, "Interface")) {
916 return std::make_unique<ColumnValues>(
917 IFACE_("Interface"),
919 [inputs_num = input_items.size()](const int64_t index) {
920 if (index < inputs_num) {
921 return IFACE_("Input");
922 }
923 return IFACE_("Output");
924 }));
925 }
926 break;
927 }
931 input_items :
932 output_items;
933 if (STREQ(column_id.name, "Identifier")) {
934 return std::make_unique<ColumnValues>(
935 IFACE_("Identifier"),
937 [items](int64_t index) { return items[index].key; }));
938 }
939 if (STREQ(column_id.name, "Type")) {
940 return std::make_unique<ColumnValues>(
941 IFACE_("Type"), VArray<std::string>::from_func(items.size(), [items](int64_t index) {
942 return items[index].type->label;
943 }));
944 }
945 break;
946 }
947 }
948 return {};
949}
950
952{
953 const int inputs_num = closure_->signature().inputs.size();
954 const int outputs_num = closure_->signature().outputs.size();
955 switch (in_out_) {
957 return inputs_num + outputs_num;
959 return inputs_num;
961 return outputs_num;
962 }
963 return 0;
964}
965
967 : value_gvarray_(GVArray::from_single(*value.type(), 1, value.get()))
968{
969}
970
972 FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
973{
974 for (const char *name : {"Value"}) {
975 SpreadsheetColumnID column_id{(char *)name};
976 fn(column_id, false);
977 }
978}
979
980std::unique_ptr<ColumnValues> SingleValueDataSource::get_column_values(
981 const SpreadsheetColumnID &column_id) const
982{
983 if (STREQ(column_id.name, "Value")) {
984 return std::make_unique<ColumnValues>(IFACE_("Value"), value_gvarray_);
985 }
986 return {};
987}
988
990{
991 return 1;
992}
993
995{
996 switch (reference.type()) {
998 const Object &object = reference.object();
999 return ED_outliner_icon_from_id(object.id);
1000 }
1002 return ICON_OUTLINER_COLLECTION;
1003 }
1005 return ICON_GEOMETRY_SET;
1006 }
1008 break;
1009 }
1010 }
1011 return ICON_NONE;
1012}
1013
1020
1022 Object *object_eval)
1023{
1025 const Object *object_orig = DEG_get_original(object_eval);
1026 if (object_orig->type == OB_MESH) {
1027 const Mesh *mesh = static_cast<const Mesh *>(object_orig->data);
1028 if (object_orig->mode == OB_MODE_EDIT) {
1029 if (const BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
1030 Mesh *new_mesh = BKE_id_new_nomain<Mesh>(nullptr);
1031 /* This is a potentially heavy operation to do on every redraw. The best solution here
1032 * is to display the data directly from the bmesh without a conversion, which can be
1033 * implemented a bit later. */
1034 BM_mesh_bm_to_me_for_eval(*em->bm, *new_mesh, nullptr);
1036 }
1037 }
1038 else {
1041 }
1042 }
1043 else if (object_orig->type == OB_POINTCLOUD) {
1044 const PointCloud *pointcloud = static_cast<const PointCloud *>(object_orig->data);
1047 }
1048 else if (object_orig->type == OB_CURVES) {
1049 const Curves &curves_id = *static_cast<const Curves *>(object_orig->data);
1051 &const_cast<Curves &>(curves_id), bke::GeometryOwnershipType::ReadOnly));
1052 }
1053 else if (object_orig->type == OB_GREASE_PENCIL) {
1054 const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(object_orig->data);
1056 &const_cast<GreasePencil &>(grease_pencil), bke::GeometryOwnershipType::ReadOnly));
1057 }
1058 return {};
1059 }
1060
1061 if (BLI_listbase_is_single(&sspreadsheet->geometry_id.viewer_path.path)) {
1063 }
1064
1065 const nodes::geo_eval_log::ViewerNodeLog *viewer_log =
1067 sspreadsheet->geometry_id.viewer_path);
1068 if (!viewer_log) {
1069 return {};
1070 }
1071
1072 const SpreadsheetTableIDGeometry &table_id = sspreadsheet->geometry_id;
1073 const int item_index = viewer_log->items.index_of_try_as(table_id.viewer_item_identifier);
1074 if (item_index == -1) {
1075 return {};
1076 }
1077
1078 bke::SocketValueVariant value = viewer_log->items[item_index].value;
1079
1080 /* Try to display the previous geometry instead of the value is a field (it will have been
1081 * evaluated on that geometry). */
1082 if (value.is_context_dependent_field()) {
1083 for (int i = item_index - 1; i >= 0; i--) {
1084 const bke::SocketValueVariant &prev_value = viewer_log->items[i].value;
1085 if (!prev_value.is_single()) {
1086 continue;
1087 }
1088 const GPointer ptr = prev_value.get_single_ptr();
1089 if (!ptr.is_type<bke::GeometrySet>()) {
1090 continue;
1091 }
1092 return prev_value;
1093 }
1094 return {};
1095 }
1096
1097 for (const SpreadsheetBundlePathElem &bundle_path_elem :
1098 Span(table_id.bundle_path, table_id.bundle_path_num))
1099 {
1100 if (!value.is_single()) {
1101 return {};
1102 }
1103 const GPointer ptr = value.get_single_ptr();
1104 if (!ptr.is_type<nodes::BundlePtr>()) {
1105 return {};
1106 }
1107 const nodes::BundlePtr &bundle = *ptr.get<nodes::BundlePtr>();
1108 const nodes::BundleItemValue *item = bundle->lookup(bundle_path_elem.identifier);
1109 if (!item) {
1110 return {};
1111 }
1112 const auto *stored_value = std::get_if<nodes::BundleItemSocketValue>(&item->value);
1113 if (!stored_value) {
1114 return {};
1115 }
1116 value = stored_value->value;
1117 }
1118
1119 return value;
1120}
1121
1122std::optional<bke::GeometrySet> root_geometry_set_get(const SpaceSpreadsheet *sspreadsheet,
1123 Object *object_eval)
1124{
1125 bke::SocketValueVariant display_data = geometry_display_data_get(sspreadsheet, object_eval);
1126 if (!display_data.is_single()) {
1127 return std::nullopt;
1128 }
1129 const GPointer ptr = display_data.get_single_ptr();
1130 if (!ptr.is_type<bke::GeometrySet>()) {
1131 return std::nullopt;
1132 }
1133 return display_data.extract<bke::GeometrySet>();
1134}
1135
1137 const Span<SpreadsheetInstanceID> instance_ids)
1138{
1139 bke::GeometrySet geometry = root_geometry;
1140 for (const SpreadsheetInstanceID &instance_id : instance_ids) {
1141 const bke::Instances *instances = geometry.get_instances();
1142 if (!instances) {
1143 /* Return the best available geometry. */
1144 return geometry;
1145 }
1146 const Span<bke::InstanceReference> references = instances->references();
1147 if (instance_id.reference_index < 0 || instance_id.reference_index >= references.size()) {
1148 /* Return the best available geometry. */
1149 return geometry;
1150 }
1151 const bke::InstanceReference &reference = references[instance_id.reference_index];
1152 bke::GeometrySet reference_geometry;
1153 reference.to_geometry_set(reference_geometry);
1154 geometry = reference_geometry;
1155 }
1156 return geometry;
1157}
1158
1159std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval)
1160{
1162
1163 bke::SocketValueVariant display_data = geometry_display_data_get(sspreadsheet, object_eval);
1164 if (display_data.is_context_dependent_field()) {
1165 return {};
1166 }
1167 if (display_data.is_volume_grid()) {
1168#ifdef WITH_OPENVDB
1169 return std::make_unique<VolumeGridDataSource>(display_data.get<bke::GVolumeGrid>());
1170#else
1171 return {};
1172#endif
1173 }
1174 if (display_data.is_list()) {
1175 return std::make_unique<ListDataSource>(display_data.extract<nodes::ListPtr>());
1176 }
1177 if (!display_data.is_single()) {
1178 return {};
1179 }
1180 const GPointer ptr = display_data.get_single_ptr();
1181 if (ptr.is_type<bke::GeometrySet>()) {
1182 const bke::GeometrySet root_geometry_set = display_data.extract<bke::GeometrySet>();
1184 root_geometry_set,
1185 Span{sspreadsheet->geometry_id.instance_ids, sspreadsheet->geometry_id.instance_ids_num});
1186
1187 const bke::AttrDomain domain = (bke::AttrDomain)sspreadsheet->geometry_id.attribute_domain;
1188 const auto component_type = bke::GeometryComponent::Type(
1189 sspreadsheet->geometry_id.geometry_component_type);
1190 const int layer_index = sspreadsheet->geometry_id.layer_index;
1191 if (!geometry_set.has(component_type)) {
1192 return {};
1193 }
1194
1195 if (component_type == bke::GeometryComponent::Type::Volume) {
1196 return std::make_unique<VolumeDataSource>(std::move(geometry_set));
1197 }
1198 Object *object_orig = sspreadsheet->geometry_id.instance_ids_num == 0 ?
1199 DEG_get_original(object_eval) :
1200 nullptr;
1201 return std::make_unique<GeometryDataSource>(object_orig,
1202 std::move(geometry_set),
1203 component_type,
1204 domain,
1205 sspreadsheet->flag &
1207 layer_index);
1208 }
1209 if (ptr.is_type<nodes::BundlePtr>()) {
1210 const nodes::BundlePtr bundle_ptr = display_data.extract<nodes::BundlePtr>();
1211 if (bundle_ptr) {
1212 return std::make_unique<BundleDataSource>(bundle_ptr);
1213 }
1214 return {};
1215 }
1216 if (ptr.is_type<nodes::ClosurePtr>()) {
1217 const auto in_out = SpreadsheetClosureInputOutput(
1218 sspreadsheet->geometry_id.closure_input_output);
1219 const nodes::ClosurePtr closure_ptr = display_data.extract<nodes::ClosurePtr>();
1220 if (closure_ptr) {
1221 return std::make_unique<ClosureSignatureDataSource>(closure_ptr, in_out);
1222 }
1223 return {};
1224 }
1225 const eSpreadsheetColumnValueType column_type = cpp_type_to_column_type(*ptr.type());
1226 if (column_type == SPREADSHEET_VALUE_TYPE_UNKNOWN) {
1227 return {};
1228 }
1229 return std::make_unique<SingleValueDataSource>(ptr);
1230}
1231
1232} // namespace blender::ed::spreadsheet
SpaceSpreadsheet * CTX_wm_space_spreadsheet(const bContext *C)
Low-level operations for curves.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
Low-level operations for grease pencil.
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1519
Volume data-block.
int BKE_volume_num_grids(const Volume *volume)
const blender::bke::VolumeGridData * BKE_volume_grid_get(const Volume *volume, int grid_index)
VolumeGridType
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
#define UNUSED_VARS(...)
#define ELEM(...)
#define STREQ(a, b)
#define IFACE_(msgid)
T * DEG_get_original(T *id)
@ OB_MODE_EDIT
@ OB_MODE_SCULPT_CURVES
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_POINTCLOUD
@ OB_CURVES
@ SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL
eSpreadsheetColumnValueType
@ SPREADSHEET_VALUE_TYPE_UNKNOWN
@ SPREADSHEET_FLAG_SHOW_INTERNAL_ATTRIBUTES
struct SpreadsheetColumnID SpreadsheetColumnID
SpreadsheetClosureInputOutput
@ SPREADSHEET_CLOSURE_INPUT
@ SPREADSHEET_CLOSURE_OUTPUT
@ SPREADSHEET_CLOSURE_NONE
int ED_outliner_icon_from_id(const ID &id)
#define C
Definition RandGen.cpp:29
volatile int lock
@ BM_ELEM_SELECT
#define BM_elem_flag_test_bool(ele, hflag)
BMesh const char void * data
BMesh * bm
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
BLI_INLINE BMEdge * BM_edge_at_index(BMesh *bm, const int index)
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
void BM_mesh_bm_to_me_for_eval(BMesh &bm, Mesh &mesh, const CustomData_MeshMasks *cd_mask_extra)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
AttributeSet attributes
void append(const T &value)
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
constexpr int64_t size() const
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr bool is_empty() const
constexpr const char * data() const
static VArray from_std_func(const int64_t size, std::function< T(int64_t index)> get_func)
static VArray from_single(T value, const int64_t size)
static VArray from_func(const int64_t size, GetFunc get_func)
static VArray from_span(Span< T > values)
void append(const T &value)
void extend(Span< T > array)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
GVArray adapt_domain(const GVArray &varray, const AttrDomain from_domain, const AttrDomain to_domain) const
int domain_size(const AttrDomain domain) const
void to_geometry_set(GeometrySet &r_geometry_set) const
Definition instances.cc:94
Span< InstanceReference > references() const
Definition instances.cc:275
static SocketValueVariant From(T &&value)
std::unique_ptr< ColumnValues > get_column_values(const SpreadsheetColumnID &column_id) const override
void foreach_default_column_ids(FunctionRef< void(const SpreadsheetColumnID &, bool is_extra)> fn) const override
void foreach_default_column_ids(FunctionRef< void(const SpreadsheetColumnID &, bool is_extra)> fn) const override
std::unique_ptr< ColumnValues > get_column_values(const SpreadsheetColumnID &column_id) const override
ClosureSignatureDataSource(nodes::ClosurePtr closure, SpreadsheetClosureInputOutput in_out)
IndexMask apply_selection_filter(IndexMaskMemory &memory) const
std::unique_ptr< ColumnValues > get_column_values(const SpreadsheetColumnID &column_id) const override
void foreach_default_column_ids(FunctionRef< void(const SpreadsheetColumnID &, bool is_extra)> fn) const override
void foreach_default_column_ids(FunctionRef< void(const SpreadsheetColumnID &, bool is_extra)> fn) const override
std::unique_ptr< ColumnValues > get_column_values(const SpreadsheetColumnID &column_id) const override
std::unique_ptr< ColumnValues > get_column_values(const SpreadsheetColumnID &column_id) const override
void foreach_default_column_ids(FunctionRef< void(const SpreadsheetColumnID &, bool is_extra)> fn) const override
void foreach_default_column_ids(FunctionRef< void(const SpreadsheetColumnID &, bool is_extra)> fn) const override
std::unique_ptr< ColumnValues > get_column_values(const SpreadsheetColumnID &column_id) const override
void to_bools(MutableSpan< bool > r_bools) const
Span< StoredItem > items() const
static std::string combine_path(const Span< StringRef > path)
static const ViewerNodeLog * find_viewer_node_log_for_path(const ViewerPath &viewer_path)
CustomIDVectorSet< Item, ItemIdentifierGetter > items
static char faces[256]
#define G(x, y, z)
bool attribute_name_is_anonymous(const StringRef name)
bool allow_procedural_attribute_access(StringRef attribute_name)
GeometrySet object_get_evaluated_geometry_set(const Object &object, bool apply_subdiv=true)
IndexMask retrieve_selected_curves(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
const nodes::geo_eval_log::ViewerNodeLog * viewer_node_log_lookup(const SpaceSpreadsheet &sspreadsheet)
bke::GeometrySet get_geometry_set_for_instance_ids(const bke::GeometrySet &root_geometry, const Span< SpreadsheetInstanceID > instance_ids)
static IndexMask calc_mesh_selection_mask_faces(const Mesh &mesh_eval, const Mesh &mesh_orig, IndexMaskMemory &memory)
bke::SocketValueVariant geometry_display_data_get(const SpaceSpreadsheet *sspreadsheet, Object *object_eval)
int get_instance_reference_icon(const bke::InstanceReference &reference)
std::unique_ptr< DataSource > data_source_from_geometry(const bContext *C, Object *object_eval)
static IndexMask calc_mesh_selection_mask(const Mesh &mesh_eval, const Mesh &mesh_orig, const bke::AttrDomain domain, IndexMaskMemory &memory)
eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
static void add_mesh_debug_column_names(const Mesh &mesh, const bke::AttrDomain domain, FunctionRef< void(const SpreadsheetColumnID &, bool is_extra)> fn)
std::optional< bke::GeometrySet > root_geometry_set_get(const SpaceSpreadsheet *sspreadsheet, Object *object_eval)
static std::unique_ptr< ColumnValues > build_mesh_debug_columns(const Mesh &mesh, const bke::AttrDomain domain, const StringRef name)
ImplicitSharingPtr< Bundle > BundlePtr
ImplicitSharingPtr< List > ListPtr
ImplicitSharingPtr< Closure > ClosurePtr
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
VecBase< int32_t, 3 > int3
const char * name
bool RNA_enum_name_from_value(const EnumPropertyItem *item, int value, const char **r_name)
const EnumPropertyItem rna_enum_volume_grid_data_type_items[]
Definition rna_volume.cc:25
bool operator!=(const SpreadsheetInstanceID &a, const SpreadsheetInstanceID &b)
bool operator==(const SpreadsheetInstanceID &a, const SpreadsheetInstanceID &b)
CustomData edge_data
int edges_num
MeshRuntimeHandle * runtime
CustomData face_data
CustomData vert_data
int faces_num
int verts_num
SpreadsheetTableIDGeometry geometry_id
SpreadsheetBundlePathElem * bundle_path
SpreadsheetInstanceID * instance_ids
static GeometrySet from_grease_pencil(GreasePencil *grease_pencil, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static GeometrySet from_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static GeometrySet from_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static GeometrySet from_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238