Cleanup: Deduplicate instances component in spreadsheet

Currently we have a separate `InstancesDataSource`, which does almost
exactly the same thing as `GeometryDataSource`, except that it hardcodes
a few more columns: "Name", "Rotation", and "Scale". We can easily
replace that with a couple of if statements in the geometry data source.

This also makes named attributes on instances display
in the spreadsheet.

Differential Revision: https://developer.blender.org/D13391
This commit is contained in:
Hans Goudey 2021-11-27 17:09:35 -05:00
parent e121b5b66c
commit f7f558e293
2 changed files with 66 additions and 136 deletions

View File

@ -134,6 +134,10 @@ void GeometryDataSource::foreach_default_column_ids(
return;
}
if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
fn({(char *)"Name"}, false);
}
extra_columns_.foreach_default_column_ids(fn);
component_->attribute_foreach(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
@ -148,12 +152,18 @@ void GeometryDataSource::foreach_default_column_ids(
fn(column_id, false);
return true;
});
if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
fn({(char *)"Rotation"}, false);
fn({(char *)"Scale"}, false);
}
}
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
if (component_->attribute_domain_size(domain_) == 0) {
const int domain_size = component_->attribute_domain_size(domain_);
if (domain_size == 0) {
return {};
}
@ -164,6 +174,60 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return extra_column_values;
}
if (component_->type() == GEO_COMPONENT_TYPE_INSTANCES) {
const InstancesComponent &instances = static_cast<const InstancesComponent &>(*component_);
if (STREQ(column_id.name, "Name")) {
Span<int> reference_handles = instances.instance_reference_handles();
Span<InstanceReference> references = instances.references();
std::unique_ptr<ColumnValues> values = column_values_from_function(
SPREADSHEET_VALUE_TYPE_INSTANCES,
"Name",
domain_size,
[reference_handles, references](int index, CellValue &r_cell_value) {
const InstanceReference &reference = references[reference_handles[index]];
switch (reference.type()) {
case InstanceReference::Type::Object: {
Object &object = reference.object();
r_cell_value.value_object = ObjectCellValue{&object};
break;
}
case InstanceReference::Type::Collection: {
Collection &collection = reference.collection();
r_cell_value.value_collection = CollectionCellValue{&collection};
break;
}
case InstanceReference::Type::GeometrySet: {
const GeometrySet &geometry_set = reference.geometry_set();
r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set};
break;
}
case InstanceReference::Type::None: {
break;
}
}
});
return values;
}
Span<float4x4> transforms = instances.instance_transforms();
if (STREQ(column_id.name, "Rotation")) {
return column_values_from_function(
SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
domain_size,
[transforms](int index, CellValue &r_cell_value) {
r_cell_value.value_float3 = transforms[index].to_euler();
});
}
if (STREQ(column_id.name, "Scale")) {
return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
domain_size,
[transforms](int index, CellValue &r_cell_value) {
r_cell_value.value_float3 = transforms[index].scale();
});
}
}
bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
if (!attribute) {
return {};
@ -172,7 +236,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
if (attribute.domain != domain_) {
return {};
}
int domain_size = varray.size();
const CustomDataType type = bke::cpp_type_to_custom_data_type(varray.type());
switch (type) {
case CD_PROP_FLOAT:
@ -387,115 +451,6 @@ void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included)
}
}
void InstancesDataSource::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
if (component_->instances_amount() == 0) {
return;
}
extra_columns_.foreach_default_column_ids(fn);
SpreadsheetColumnID column_id;
column_id.name = (char *)"Name";
fn(column_id, false);
for (const char *name : {"Position", "Rotation", "Scale", "id"}) {
column_id.name = (char *)name;
fn(column_id, false);
}
}
std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
if (component_->instances_amount() == 0) {
return {};
}
std::unique_ptr<ColumnValues> extra_column_values = extra_columns_.get_column_values(column_id);
if (extra_column_values) {
return extra_column_values;
}
const int size = this->tot_rows();
if (STREQ(column_id.name, "Name")) {
Span<int> reference_handles = component_->instance_reference_handles();
Span<InstanceReference> references = component_->references();
std::unique_ptr<ColumnValues> values = column_values_from_function(
SPREADSHEET_VALUE_TYPE_INSTANCES,
"Name",
size,
[reference_handles, references](int index, CellValue &r_cell_value) {
const InstanceReference &reference = references[reference_handles[index]];
switch (reference.type()) {
case InstanceReference::Type::Object: {
Object &object = reference.object();
r_cell_value.value_object = ObjectCellValue{&object};
break;
}
case InstanceReference::Type::Collection: {
Collection &collection = reference.collection();
r_cell_value.value_collection = CollectionCellValue{&collection};
break;
}
case InstanceReference::Type::GeometrySet: {
const GeometrySet &geometry_set = reference.geometry_set();
r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set};
break;
}
case InstanceReference::Type::None: {
break;
}
}
});
return values;
}
Span<float4x4> transforms = component_->instance_transforms();
if (STREQ(column_id.name, "Position")) {
return column_values_from_function(
SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
size,
[transforms](int index, CellValue &r_cell_value) {
r_cell_value.value_float3 = transforms[index].translation();
});
}
if (STREQ(column_id.name, "Rotation")) {
return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
size,
[transforms](int index, CellValue &r_cell_value) {
r_cell_value.value_float3 = transforms[index].to_euler();
});
}
if (STREQ(column_id.name, "Scale")) {
return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
column_id.name,
size,
[transforms](int index, CellValue &r_cell_value) {
r_cell_value.value_float3 = transforms[index].scale();
});
}
Span<int> ids = component_->instance_ids();
if (!ids.is_empty()) {
if (STREQ(column_id.name, "id")) {
/* Make the column a bit wider by default, since the IDs tend to be large numbers. */
return column_values_from_function(
SPREADSHEET_VALUE_TYPE_INT32,
column_id.name,
size,
[ids](int index, CellValue &r_cell_value) { r_cell_value.value_int = ids[index]; },
5.5f);
}
}
return {};
}
int InstancesDataSource::tot_rows() const
{
return component_->instances_amount();
}
void VolumeDataSource::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
@ -771,9 +726,6 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
ExtraColumns extra_columns;
add_fields_as_extra_columns(sspreadsheet, component, extra_columns);
if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
return std::make_unique<InstancesDataSource>(geometry_set, std::move(extra_columns));
}
if (component_type == GEO_COMPONENT_TYPE_VOLUME) {
return std::make_unique<VolumeDataSource>(geometry_set);
}

View File

@ -94,28 +94,6 @@ class GeometryDataSource : public DataSource {
int tot_rows() const override;
};
class InstancesDataSource : public DataSource {
const GeometrySet geometry_set_;
const InstancesComponent *component_;
ExtraColumns extra_columns_;
public:
InstancesDataSource(GeometrySet geometry_set, ExtraColumns extra_columns)
: geometry_set_(std::move(geometry_set)),
component_(geometry_set_.get_component_for_read<InstancesComponent>()),
extra_columns_(std::move(extra_columns))
{
}
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;
int tot_rows() const override;
};
class VolumeDataSource : public DataSource {
const GeometrySet geometry_set_;
const VolumeComponent *component_;