From faa24698a5f83c0a50e03ea5dac3c38ca4e8760f Mon Sep 17 00:00:00 2001 From: Falk David Date: Thu, 12 Oct 2023 16:51:44 +0200 Subject: [PATCH] GPv3: Implement expanding of Grease Pencil component in the spreadsheet This patch adds the ability for users to expand the grease pencil component in the spreadsheet and see the values for each `CurvesGeometry` in each layer. It also makes it so that all the geometry components can be expanded for consistency. Pull Request: https://projects.blender.org/blender/blender/pulls/113507 --- .../space_spreadsheet/space_spreadsheet.cc | 8 ++ .../spreadsheet_data_source_geometry.cc | 72 +++++++++--- .../spreadsheet_data_source_geometry.hh | 7 ++ .../spreadsheet_dataset_draw.cc | 104 +++++++++++++++--- source/blender/makesdna/DNA_space_types.h | 3 + source/blender/nodes/NOD_geometry_exec.hh | 1 + 6 files changed, 168 insertions(+), 27 deletions(-) diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 74f20e58e5d..83dbd8f9727 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -513,6 +513,10 @@ static void spreadsheet_main_region_listener(const wmRegionListenerParams *param ED_region_tag_redraw(region); break; } + case NC_GPENCIL: { + ED_region_tag_redraw(region); + break; + } case NC_VIEWER_PATH: { if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { ED_region_tag_redraw(region); @@ -566,6 +570,10 @@ static void spreadsheet_header_region_listener(const wmRegionListenerParams *par ED_region_tag_redraw(region); break; } + case NC_GPENCIL: { + ED_region_tag_redraw(region); + break; + } case NC_VIEWER_PATH: { if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { ED_region_tag_redraw(region); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 406cb8f6841..67b094ebbc8 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -11,7 +11,9 @@ #include "BKE_curves.hh" #include "BKE_editmesh.h" #include "BKE_geometry_fields.hh" +#include "BKE_geometry_set.hh" #include "BKE_global.h" +#include "BKE_grease_pencil.hh" #include "BKE_instances.hh" #include "BKE_lib_id.h" #include "BKE_mesh.hh" @@ -173,12 +175,11 @@ static std::unique_ptr build_mesh_debug_columns(const Mesh &mesh, void GeometryDataSource::foreach_default_column_ids( FunctionRef fn) const { - if (!component_->attributes().has_value()) { + std::optional attributes = this->get_component_attributes(); + if (!attributes.has_value()) { return; } - const bke::AttributeAccessor attributes = *component_->attributes(); - - if (attributes.domain_size(domain_) == 0) { + if (attributes->domain_size(domain_) == 0) { return; } @@ -186,9 +187,13 @@ void GeometryDataSource::foreach_default_column_ids( fn({(char *)"Name"}, false); } + if (component_->type() == bke::GeometryComponent::Type::GreasePencil) { + fn({(char *)"Name"}, false); + } + extra_columns_.foreach_default_column_ids(fn); - attributes.for_all( + attributes->for_all( [&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) { if (meta_data.domain != domain_) { return true; @@ -221,11 +226,11 @@ void GeometryDataSource::foreach_default_column_ids( std::unique_ptr GeometryDataSource::get_column_values( const SpreadsheetColumnID &column_id) const { - if (!component_->attributes().has_value()) { + std::optional attributes = this->get_component_attributes(); + if (!attributes.has_value()) { return {}; } - const bke::AttributeAccessor attributes = *component_->attributes(); - const int domain_num = attributes.domain_size(domain_); + const int domain_num = attributes->domain_size(domain_); if (domain_num == 0) { return {}; } @@ -266,6 +271,19 @@ std::unique_ptr GeometryDataSource::get_column_values( } } } + else if (component_->type() == bke::GeometryComponent::Type::GreasePencil) { + if (const GreasePencil *grease_pencil = + static_cast(*component_).get()) + { + if (domain_ == ATTR_DOMAIN_LAYER && STREQ(column_id.name, "Name")) { + const Span layers = grease_pencil->layers(); + return std::make_unique( + column_id.name, VArray::ForFunc(domain_num, [layers](int64_t index) { + return std::string(layers[index]->name()); + })); + } + } + } else if (G.debug_value == 4001 && component_->type() == bke::GeometryComponent::Type::Mesh) { const bke::MeshComponent &component = static_cast(*component_); if (const Mesh *mesh = component.get()) { @@ -277,7 +295,7 @@ std::unique_ptr GeometryDataSource::get_column_values( } } - bke::GAttributeReader attribute = attributes.lookup(column_id.name); + bke::GAttributeReader attribute = attributes->lookup(column_id.name); if (!attribute) { return {}; } @@ -296,11 +314,11 @@ std::unique_ptr GeometryDataSource::get_column_values( int GeometryDataSource::tot_rows() const { - if (!component_->attributes().has_value()) { + std::optional attributes = this->get_component_attributes(); + if (!attributes.has_value()) { return {}; } - const bke::AttributeAccessor attributes = *component_->attributes(); - return attributes.domain_size(domain_); + return attributes->domain_size(domain_); } bool GeometryDataSource::has_selection_filter() const @@ -421,6 +439,28 @@ IndexMask GeometryDataSource::apply_selection_filter(IndexMaskMemory &memory) co } } +std::optional GeometryDataSource::get_component_attributes() const +{ + if (component_->type() != bke::GeometryComponent::Type::GreasePencil) { + return component_->attributes(); + } + const GreasePencil *grease_pencil = geometry_set_.get_grease_pencil(); + if (!grease_pencil) { + return {}; + } + if (domain_ == ATTR_DOMAIN_LAYER) { + return grease_pencil->attributes(); + } + if (layer_index_ >= 0 && layer_index_ < grease_pencil->layers().size()) { + if (const bke::greasepencil::Drawing *drawing = + bke::greasepencil::get_eval_grease_pencil_layer_drawing(*grease_pencil, layer_index_)) + { + return drawing->strokes().attributes(); + } + } + return {}; +} + void VolumeDataSource::foreach_default_column_ids( FunctionRef fn) const { @@ -524,6 +564,11 @@ bke::GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *ss geometry_set.replace_curves(&const_cast(curves_id), bke::GeometryOwnershipType::ReadOnly); } + else if (object_orig->type == OB_GREASE_PENCIL) { + const GreasePencil &grease_pencil = *static_cast(object_orig->data); + geometry_set.replace_grease_pencil(&const_cast(grease_pencil), + bke::GeometryOwnershipType::ReadOnly); + } } else { if (BLI_listbase_is_single(&sspreadsheet->viewer_path.path)) { @@ -555,6 +600,7 @@ std::unique_ptr data_source_from_geometry(const bContext *C, Object SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain; const auto component_type = bke::GeometryComponent::Type(sspreadsheet->geometry_component_type); + const int active_layer_index = sspreadsheet->active_layer_index; bke::GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval); if (!geometry_set.has(component_type)) { return {}; @@ -564,7 +610,7 @@ std::unique_ptr data_source_from_geometry(const bContext *C, Object return std::make_unique(std::move(geometry_set)); } return std::make_unique( - object_eval, std::move(geometry_set), component_type, domain); + object_eval, std::move(geometry_set), component_type, domain, active_layer_index); } } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index 53f18a679e0..dfc7f5429eb 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -43,6 +43,8 @@ class GeometryDataSource : public DataSource { const bke::GeometrySet geometry_set_; const bke::GeometryComponent *component_; eAttrDomain domain_; + /* Layer index for grease pencil component. */ + int layer_index_; ExtraColumns extra_columns_; /* Some data is computed on the fly only when it is requested. Computing it does not change the @@ -56,11 +58,13 @@ class GeometryDataSource : public DataSource { bke::GeometrySet geometry_set, const bke::GeometryComponent::Type component_type, const eAttrDomain domain, + const int layer_index = -1, ExtraColumns extra_columns = {}) : object_eval_(object_eval), geometry_set_(std::move(geometry_set)), component_(geometry_set_.get_component(component_type)), domain_(domain), + layer_index_(layer_index), extra_columns_(std::move(extra_columns)) { } @@ -80,6 +84,9 @@ class GeometryDataSource : public DataSource { const SpreadsheetColumnID &column_id) const override; int tot_rows() const override; + + private: + std::optional get_component_attributes() const; }; class VolumeDataSource : public DataSource { diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 0ca2d8ac6f8..95925d93add 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -8,6 +8,8 @@ #include "DNA_windowmanager_types.h" #include "BKE_context.h" +#include "BKE_curves.hh" +#include "BKE_grease_pencil.hh" #include "BKE_volume.h" #include "RNA_access.hh" @@ -30,6 +32,7 @@ class GeometryDataSetTreeView; class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { bke::GeometryComponent::Type component_type_; + std::optional layer_index_; std::optional domain_; BIFIconID icon_; @@ -38,6 +41,15 @@ class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { StringRef label, BIFIconID icon); GeometryDataSetTreeViewItem(bke::GeometryComponent::Type component_type, + int layer_index, + StringRef label, + BIFIconID icon); + GeometryDataSetTreeViewItem(bke::GeometryComponent::Type component_type, + eAttrDomain domain, + StringRef label, + BIFIconID icon); + GeometryDataSetTreeViewItem(bke::GeometryComponent::Type component_type, + int layer_index, eAttrDomain domain, StringRef label, BIFIconID icon); @@ -70,6 +82,47 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView { { } + void build_grease_pencil() + { + if (!U.experimental.use_grease_pencil_version3) { + return; + } + + GeometryDataSetTreeViewItem &grease_pencil = this->add_tree_item( + bke::GeometryComponent::Type::GreasePencil, + IFACE_("Grease Pencil"), + ICON_OUTLINER_DATA_GREASEPENCIL); + GeometryDataSetTreeViewItem &grease_pencil_layers = + grease_pencil.add_tree_item( + bke::GeometryComponent::Type::GreasePencil, + ATTR_DOMAIN_LAYER, + IFACE_("Layer"), + ICON_OUTLINER_DATA_GP_LAYER); + + if (!geometry_set_.has_grease_pencil()) { + return; + } + + const Span layers = + geometry_set_.get_grease_pencil()->layers(); + for (const int layer_i : layers.index_range()) { + const bke::greasepencil::Layer *layer = layers[layer_i]; + GeometryDataSetTreeViewItem &curve = + grease_pencil_layers.add_tree_item( + bke::GeometryComponent::Type::GreasePencil, layer_i, layer->name(), ICON_CURVE_DATA); + curve.add_tree_item(bke::GeometryComponent::Type::GreasePencil, + layer_i, + ATTR_DOMAIN_POINT, + IFACE_("Control Point"), + ICON_CURVE_BEZCIRCLE); + curve.add_tree_item(bke::GeometryComponent::Type::GreasePencil, + layer_i, + ATTR_DOMAIN_CURVE, + IFACE_("Spline"), + ICON_CURVE_PATH); + } + } + void build_tree() override { GeometryDataSetTreeViewItem &mesh = this->add_tree_item( @@ -94,18 +147,7 @@ class GeometryDataSetTreeView : public ui::AbstractTreeView { curve.add_tree_item( bke::GeometryComponent::Type::Curve, ATTR_DOMAIN_CURVE, IFACE_("Spline"), ICON_CURVE_PATH); - if (U.experimental.use_grease_pencil_version3) { - GeometryDataSetTreeViewItem &grease_pencil = - this->add_tree_item( - bke::GeometryComponent::Type::GreasePencil, - IFACE_("Grease Pencil"), - ICON_OUTLINER_DATA_GREASEPENCIL); - grease_pencil.add_tree_item( - bke::GeometryComponent::Type::GreasePencil, - ATTR_DOMAIN_LAYER, - IFACE_("Layer"), - ICON_OUTLINER_DATA_GP_LAYER); - } + this->build_grease_pencil(); GeometryDataSetTreeViewItem &pointcloud = this->add_tree_item( bke::GeometryComponent::Type::PointCloud, IFACE_("Point Cloud"), ICON_POINTCLOUD_DATA); @@ -131,6 +173,12 @@ GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem( label_ = label; this->set_collapsed(false); } +GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem( + bke::GeometryComponent::Type component_type, int layer_index, StringRef label, BIFIconID icon) + : component_type_(component_type), layer_index_(layer_index), icon_(icon) +{ + label_ = label; +} GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem( bke::GeometryComponent::Type component_type, eAttrDomain domain, @@ -140,6 +188,16 @@ GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem( { label_ = label; } +GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem( + bke::GeometryComponent::Type component_type, + int layer_index, + eAttrDomain domain, + StringRef label, + BIFIconID icon) + : component_type_(component_type), layer_index_(layer_index), domain_(domain), icon_(icon) +{ + label_ = label; +} void GeometryDataSetTreeViewItem::on_activate(bContext &C) { @@ -149,6 +207,9 @@ void GeometryDataSetTreeViewItem::on_activate(bContext &C) if (domain_) { tree_view.sspreadsheet_.attribute_domain = *domain_; } + if (layer_index_) { + tree_view.sspreadsheet_.active_layer_index = *layer_index_; + } PointerRNA ptr = RNA_pointer_create(&tree_view.screen_.id, &RNA_SpaceSpreadsheet, &sspreadsheet); RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain")); RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type")); @@ -180,13 +241,19 @@ std::optional GeometryDataSetTreeViewItem::should_be_active() const return false; } + if (!layer_index_) { + return sspreadsheet.geometry_component_type == uint8_t(component_type_) && + sspreadsheet.attribute_domain == *domain_; + } + return sspreadsheet.geometry_component_type == uint8_t(component_type_) && - sspreadsheet.attribute_domain == *domain_; + sspreadsheet.attribute_domain == *domain_ && + sspreadsheet.active_layer_index == *layer_index_; } bool GeometryDataSetTreeViewItem::supports_collapsing() const { - return false; + return true; } GeometryDataSetTreeView &GeometryDataSetTreeViewItem::get_tree() const @@ -211,6 +278,15 @@ std::optional GeometryDataSetTreeViewItem::count() const return std::nullopt; } + if (component_type_ == bke::GeometryComponent::Type::GreasePencil && layer_index_) { + if (const bke::greasepencil::Drawing *drawing = + bke::greasepencil::get_eval_grease_pencil_layer_drawing(*geometry.get_grease_pencil(), + *layer_index_)) + { + return drawing->strokes().attributes().domain_size(*domain_); + } + } + if (const bke::GeometryComponent *component = geometry.get_component(component_type_)) { return component->attribute_domain_size(*domain_); } diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 5c8c055ca50..9eced9bae75 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1985,9 +1985,12 @@ typedef struct SpaceSpreadsheet { uint8_t attribute_domain; /* eSpaceSpreadsheet_ObjectEvalState. */ uint8_t object_eval_state; + /* Active grease pencil layer index for grease pencil component. */ + int active_layer_index; /* eSpaceSpreadsheet_Flag. */ uint32_t flag; + char _pad1[4]; SpaceSpreadsheet_Runtime *runtime; } SpaceSpreadsheet; diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index c859c83bda4..2432e03e25d 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -41,6 +41,7 @@ using bke::GeometryComponentEditData; using bke::GeometrySet; using bke::GreasePencilComponent; using bke::GSpanAttributeWriter; +using bke::GreasePencilComponent; using bke::InstancesComponent; using bke::MeshComponent; using bke::MutableAttributeAccessor;