diff options
Diffstat (limited to 'source/blender/blenkernel/intern/geometry_set.cc')
-rw-r--r-- | source/blender/blenkernel/intern/geometry_set.cc | 387 |
1 files changed, 245 insertions, 142 deletions
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 0aac6ae3adf..c1e386c626b 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -17,6 +17,8 @@ #include "BLI_map.hh" #include "BLI_task.hh" +#include "BLT_translation.h" + #include "BKE_attribute.h" #include "BKE_attribute_access.hh" #include "BKE_geometry_set.hh" @@ -105,105 +107,105 @@ bool GeometryComponent::is_empty() const /** \name Geometry Set * \{ */ -/* This method can only be used when the geometry set is mutable. It returns a mutable geometry - * component of the given type. - */ +GeometrySet::GeometrySet() = default; +GeometrySet::GeometrySet(const GeometrySet &other) = default; +GeometrySet::GeometrySet(GeometrySet &&other) = default; +GeometrySet::~GeometrySet() = default; +GeometrySet &GeometrySet::operator=(const GeometrySet &other) = default; +GeometrySet &GeometrySet::operator=(GeometrySet &&other) = default; + GeometryComponent &GeometrySet::get_component_for_write(GeometryComponentType component_type) { - return components_.add_or_modify( - component_type, - [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & { - /* If the component did not exist before, create a new one. */ - new (value_ptr) GeometryComponentPtr(GeometryComponent::create(component_type)); - return **value_ptr; - }, - [&](GeometryComponentPtr *value_ptr) -> GeometryComponent & { - GeometryComponentPtr &value = *value_ptr; - if (value->is_mutable()) { - /* If the referenced component is already mutable, return it directly. */ - return *value; - } - /* If the referenced component is shared, make a copy. The copy is not shared and is - * therefore mutable. */ - GeometryComponent *copied_component = value->copy(); - value = GeometryComponentPtr{copied_component}; - return *copied_component; - }); + GeometryComponentPtr &component_ptr = components_[component_type]; + if (!component_ptr) { + /* If the component did not exist before, create a new one. */ + component_ptr = GeometryComponent::create(component_type); + return *component_ptr; + } + if (component_ptr->is_mutable()) { + /* If the referenced component is already mutable, return it directly. */ + return *component_ptr; + } + /* If the referenced component is shared, make a copy. The copy is not shared and is + * therefore mutable. */ + component_ptr = component_ptr->copy(); + return *component_ptr; } -/* Get the component of the given type. Might return null if the component does not exist yet. */ -const GeometryComponent *GeometrySet::get_component_for_read( - GeometryComponentType component_type) const +GeometryComponent *GeometrySet::get_component_ptr(GeometryComponentType type) { - const GeometryComponentPtr *component = components_.lookup_ptr(component_type); - if (component != nullptr) { - return component->get(); + if (this->has(type)) { + return &this->get_component_for_write(type); } return nullptr; } +const GeometryComponent *GeometrySet::get_component_for_read( + GeometryComponentType component_type) const +{ + return components_[component_type].get(); +} + bool GeometrySet::has(const GeometryComponentType component_type) const { - return components_.contains(component_type); + return components_[component_type].has_value(); } void GeometrySet::remove(const GeometryComponentType component_type) { - components_.remove(component_type); + components_[component_type].reset(); } -/** - * Remove all geometry components with types that are not in the provided list. - */ void GeometrySet::keep_only(const blender::Span<GeometryComponentType> component_types) { - for (auto it = components_.keys().begin(); it != components_.keys().end(); ++it) { - const GeometryComponentType type = *it; - if (!component_types.contains(type)) { - components_.remove(it); + for (GeometryComponentPtr &component_ptr : components_) { + if (component_ptr) { + if (!component_types.contains(component_ptr->type())) { + component_ptr.reset(); + } } } } void GeometrySet::add(const GeometryComponent &component) { - BLI_assert(!components_.contains(component.type())); + BLI_assert(!components_[component.type()]); component.user_add(); - GeometryComponentPtr component_ptr{const_cast<GeometryComponent *>(&component)}; - components_.add_new(component.type(), std::move(component_ptr)); + components_[component.type()] = const_cast<GeometryComponent *>(&component); } -/** - * Get all geometry components in this geometry set for read-only access. - */ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const { Vector<const GeometryComponent *> components; - for (const GeometryComponentPtr &ptr : components_.values()) { - components.append(ptr.get()); + for (const GeometryComponentPtr &component_ptr : components_) { + if (component_ptr) { + components.append(component_ptr.get()); + } } return components; } -void GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const +bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const { + bool have_minmax = false; const PointCloud *pointcloud = this->get_pointcloud_for_read(); if (pointcloud != nullptr) { - BKE_pointcloud_minmax(pointcloud, *r_min, *r_max); + have_minmax |= BKE_pointcloud_minmax(pointcloud, *r_min, *r_max); } const Mesh *mesh = this->get_mesh_for_read(); if (mesh != nullptr) { - BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max); + have_minmax |= BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max); } const Volume *volume = this->get_volume_for_read(); if (volume != nullptr) { - BKE_volume_min_max(volume, *r_min, *r_max); + have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max); } const CurveEval *curve = this->get_curve_for_read(); if (curve != nullptr) { /* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */ - curve->bounds_min_max(*r_min, *r_max, true); + have_minmax |= curve->bounds_min_max(*r_min, *r_max, true); } + return have_minmax; } std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set) @@ -213,203 +215,220 @@ std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set) return stream; } -/* Remove all geometry components from the geometry set. */ void GeometrySet::clear() { - components_.clear(); + for (GeometryComponentPtr &component_ptr : components_) { + component_ptr.reset(); + } } -/* Make sure that the geometry can be cached. This does not ensure ownership of object/collection - * instances. */ void GeometrySet::ensure_owns_direct_data() { - for (GeometryComponentType type : components_.keys()) { - const GeometryComponent *component = this->get_component_for_read(type); - if (!component->owns_direct_data()) { - GeometryComponent &component_for_write = this->get_component_for_write(type); - component_for_write.ensure_owns_direct_data(); + for (GeometryComponentPtr &component_ptr : components_) { + if (!component_ptr) { + continue; + } + if (component_ptr->owns_direct_data()) { + continue; } + GeometryComponent &component_for_write = this->get_component_for_write(component_ptr->type()); + component_for_write.ensure_owns_direct_data(); } } bool GeometrySet::owns_direct_data() const { - for (const GeometryComponentPtr &component : components_.values()) { - if (!component->owns_direct_data()) { - return false; + for (const GeometryComponentPtr &component_ptr : components_) { + if (component_ptr) { + if (!component_ptr->owns_direct_data()) { + return false; + } } } return true; } -/* Returns a read-only mesh or null. */ const Mesh *GeometrySet::get_mesh_for_read() const { const MeshComponent *component = this->get_component_for_read<MeshComponent>(); return (component == nullptr) ? nullptr : component->get_for_read(); } -/* Returns true when the geometry set has a mesh component that has a mesh. */ bool GeometrySet::has_mesh() const { const MeshComponent *component = this->get_component_for_read<MeshComponent>(); return component != nullptr && component->has_mesh(); } -/* Returns a read-only point cloud of null. */ const PointCloud *GeometrySet::get_pointcloud_for_read() const { const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>(); return (component == nullptr) ? nullptr : component->get_for_read(); } -/* Returns a read-only volume or null. */ const Volume *GeometrySet::get_volume_for_read() const { const VolumeComponent *component = this->get_component_for_read<VolumeComponent>(); return (component == nullptr) ? nullptr : component->get_for_read(); } -/* Returns a read-only curve or null. */ const CurveEval *GeometrySet::get_curve_for_read() const { const CurveComponent *component = this->get_component_for_read<CurveComponent>(); return (component == nullptr) ? nullptr : component->get_for_read(); } -/* Returns true when the geometry set has a point cloud component that has a point cloud. */ bool GeometrySet::has_pointcloud() const { const PointCloudComponent *component = this->get_component_for_read<PointCloudComponent>(); return component != nullptr && component->has_pointcloud(); } -/* Returns true when the geometry set has an instances component that has at least one instance. */ bool GeometrySet::has_instances() const { const InstancesComponent *component = this->get_component_for_read<InstancesComponent>(); return component != nullptr && component->instances_amount() >= 1; } -/* Returns true when the geometry set has a volume component that has a volume. */ bool GeometrySet::has_volume() const { const VolumeComponent *component = this->get_component_for_read<VolumeComponent>(); return component != nullptr && component->has_volume(); } -/* Returns true when the geometry set has a curve component that has a curve. */ bool GeometrySet::has_curve() const { const CurveComponent *component = this->get_component_for_read<CurveComponent>(); return component != nullptr && component->has_curve(); } -/* Returns true when the geometry set has any data that is not an instance. */ bool GeometrySet::has_realized_data() const { - if (components_.is_empty()) { - return false; - } - if (components_.size() > 1) { - return true; + for (const GeometryComponentPtr &component_ptr : components_) { + if (component_ptr) { + if (component_ptr->type() != GEO_COMPONENT_TYPE_INSTANCES) { + return true; + } + } } - /* Check if the only component is an #InstancesComponent. */ - return this->get_component_for_read<InstancesComponent>() == nullptr; + return false; } -/* Return true if the geometry set has any component that isn't empty. */ bool GeometrySet::is_empty() const { - if (components_.is_empty()) { - return true; - } - return !(this->has_mesh() || this->has_curve() || this->has_pointcloud() || + return !(this->has_mesh() || this->has_curve() || this->has_pointcloud() || this->has_volume() || this->has_instances()); } -/* Create a new geometry set that only contains the given mesh. */ GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership) { GeometrySet geometry_set; - MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>(); - component.replace(mesh, ownership); + if (mesh != nullptr) { + MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>(); + component.replace(mesh, ownership); + } return geometry_set; } -/* Create a new geometry set that only contains the given point cloud. */ GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership) { GeometrySet geometry_set; - PointCloudComponent &component = geometry_set.get_component_for_write<PointCloudComponent>(); - component.replace(pointcloud, ownership); + if (pointcloud != nullptr) { + PointCloudComponent &component = geometry_set.get_component_for_write<PointCloudComponent>(); + component.replace(pointcloud, ownership); + } return geometry_set; } -/* Create a new geometry set that only contains the given curve. */ GeometrySet GeometrySet::create_with_curve(CurveEval *curve, GeometryOwnershipType ownership) { GeometrySet geometry_set; - CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>(); - component.replace(curve, ownership); + if (curve != nullptr) { + CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>(); + component.replace(curve, ownership); + } return geometry_set; } -/* Clear the existing mesh and replace it with the given one. */ void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership) { + if (mesh == nullptr) { + this->remove<MeshComponent>(); + return; + } + if (mesh == this->get_mesh_for_read()) { + return; + } + this->remove<MeshComponent>(); MeshComponent &component = this->get_component_for_write<MeshComponent>(); component.replace(mesh, ownership); } -/* Clear the existing curve and replace it with the given one. */ void GeometrySet::replace_curve(CurveEval *curve, GeometryOwnershipType ownership) { + if (curve == nullptr) { + this->remove<CurveComponent>(); + return; + } + if (curve == this->get_curve_for_read()) { + return; + } + this->remove<CurveComponent>(); CurveComponent &component = this->get_component_for_write<CurveComponent>(); component.replace(curve, ownership); } -/* Clear the existing point cloud and replace with the given one. */ void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership) { - PointCloudComponent &pointcloud_component = this->get_component_for_write<PointCloudComponent>(); - pointcloud_component.replace(pointcloud, ownership); + if (pointcloud == nullptr) { + this->remove<PointCloudComponent>(); + return; + } + if (pointcloud == this->get_pointcloud_for_read()) { + return; + } + this->remove<PointCloudComponent>(); + PointCloudComponent &component = this->get_component_for_write<PointCloudComponent>(); + component.replace(pointcloud, ownership); } -/* Clear the existing volume and replace with the given one. */ void GeometrySet::replace_volume(Volume *volume, GeometryOwnershipType ownership) { - VolumeComponent &volume_component = this->get_component_for_write<VolumeComponent>(); - volume_component.replace(volume, ownership); + if (volume == nullptr) { + this->remove<VolumeComponent>(); + return; + } + if (volume == this->get_volume_for_read()) { + return; + } + this->remove<VolumeComponent>(); + VolumeComponent &component = this->get_component_for_write<VolumeComponent>(); + component.replace(volume, ownership); } -/* Returns a mutable mesh or null. No ownership is transferred. */ Mesh *GeometrySet::get_mesh_for_write() { - MeshComponent &component = this->get_component_for_write<MeshComponent>(); - return component.get_for_write(); + MeshComponent *component = this->get_component_ptr<MeshComponent>(); + return component == nullptr ? nullptr : component->get_for_write(); } -/* Returns a mutable point cloud or null. No ownership is transferred. */ PointCloud *GeometrySet::get_pointcloud_for_write() { - PointCloudComponent &component = this->get_component_for_write<PointCloudComponent>(); - return component.get_for_write(); + PointCloudComponent *component = this->get_component_ptr<PointCloudComponent>(); + return component == nullptr ? nullptr : component->get_for_write(); } -/* Returns a mutable volume or null. No ownership is transferred. */ Volume *GeometrySet::get_volume_for_write() { - VolumeComponent &component = this->get_component_for_write<VolumeComponent>(); - return component.get_for_write(); + VolumeComponent *component = this->get_component_ptr<VolumeComponent>(); + return component == nullptr ? nullptr : component->get_for_write(); } -/* Returns a mutable curve or null. No ownership is transferred. */ CurveEval *GeometrySet::get_curve_for_write() { - CurveComponent &component = this->get_component_for_write<CurveComponent>(); - return component.get_for_write(); + CurveComponent *component = this->get_component_ptr<CurveComponent>(); + return component == nullptr ? nullptr : component->get_for_write(); } void GeometrySet::attribute_foreach(const Span<GeometryComponentType> component_types, @@ -461,19 +480,23 @@ void GeometrySet::gather_attributes_for_propagation( return; } } - if (attribute_id.is_anonymous()) { - if (!BKE_anonymous_attribute_id_has_strong_references(&attribute_id.anonymous_id())) { - /* Don't propagate anonymous attributes that are not used anymore. */ - return; - } + + if (!attribute_id.should_be_kept()) { + return; } + + AttributeDomain domain = meta_data.domain; + if (dst_component_type != GEO_COMPONENT_TYPE_INSTANCES && domain == ATTR_DOMAIN_INSTANCE) { + domain = ATTR_DOMAIN_POINT; + } + auto add_info = [&](AttributeKind *attribute_kind) { - attribute_kind->domain = meta_data.domain; + attribute_kind->domain = domain; attribute_kind->data_type = meta_data.data_type; }; auto modify_info = [&](AttributeKind *attribute_kind) { attribute_kind->domain = bke::attribute_domain_highest_priority( - {attribute_kind->domain, meta_data.domain}); + {attribute_kind->domain, domain}); attribute_kind->data_type = bke::attribute_data_type_highest_complexity( {attribute_kind->data_type, meta_data.data_type}); }; @@ -482,6 +505,40 @@ void GeometrySet::gather_attributes_for_propagation( delete dummy_component; } +static void gather_component_types_recursive(const GeometrySet &geometry_set, + const bool include_instances, + const bool ignore_empty, + Vector<GeometryComponentType> &r_types) +{ + for (const GeometryComponent *component : geometry_set.get_components_for_read()) { + if (ignore_empty) { + if (component->is_empty()) { + continue; + } + } + r_types.append_non_duplicates(component->type()); + } + if (!include_instances) { + return; + } + const InstancesComponent *instances = geometry_set.get_component_for_read<InstancesComponent>(); + if (instances == nullptr) { + return; + } + instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) { + gather_component_types_recursive( + instance_geometry_set, include_instances, ignore_empty, r_types); + }); +} + +blender::Vector<GeometryComponentType> GeometrySet::gather_component_types( + const bool include_instances, bool ignore_empty) const +{ + Vector<GeometryComponentType> types; + gather_component_types_recursive(*this, include_instances, ignore_empty, types); + return types; +} + static void gather_mutable_geometry_sets(GeometrySet &geometry_set, Vector<GeometrySet *> &r_geometry_sets) { @@ -502,10 +559,6 @@ static void gather_mutable_geometry_sets(GeometrySet &geometry_set, } } -/** - * Modify every (recursive) instance separately. This is often more efficient than realizing all - * instances just to change the same thing on all of them. - */ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback) { Vector<GeometrySet *> geometry_sets; @@ -517,6 +570,48 @@ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Mesh and Curve Normals Field Input + * \{ */ + +namespace blender::bke { + +GVArray NormalFieldInput::get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask mask) const +{ + if (component.type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + if (const Mesh *mesh = mesh_component.get_for_read()) { + return mesh_normals_varray(mesh_component, *mesh, mask, domain); + } + } + else if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + return curve_normals_varray(curve_component, domain); + } + return {}; +} + +std::string NormalFieldInput::socket_inspection_name() const +{ + return TIP_("Normal"); +} + +uint64_t NormalFieldInput::hash() const +{ + return 213980475983; +} + +bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const +{ + return dynamic_cast<const NormalFieldInput *>(&other) != nullptr; +} + +} // namespace blender::bke + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name C API * \{ */ @@ -531,24 +626,32 @@ bool BKE_object_has_geometry_set_instances(const Object *ob) if (geometry_set == nullptr) { return false; } - if (geometry_set->has_instances()) { - return true; - } - const bool has_mesh = geometry_set->has_mesh(); - const bool has_pointcloud = geometry_set->has_pointcloud(); - const bool has_volume = geometry_set->has_volume(); - const bool has_curve = geometry_set->has_curve(); - if (ob->type == OB_MESH) { - return has_pointcloud || has_volume || has_curve; - } - if (ob->type == OB_POINTCLOUD) { - return has_mesh || has_volume || has_curve; - } - if (ob->type == OB_VOLUME) { - return has_mesh || has_pointcloud || has_curve; - } - if (ELEM(ob->type, OB_CURVE, OB_FONT)) { - return has_mesh || has_pointcloud || has_volume; + for (const GeometryComponent *component : geometry_set->get_components_for_read()) { + if (component->is_empty()) { + continue; + } + const GeometryComponentType type = component->type(); + bool is_instance = false; + switch (type) { + case GEO_COMPONENT_TYPE_MESH: + is_instance = ob->type != OB_MESH; + break; + case GEO_COMPONENT_TYPE_POINT_CLOUD: + is_instance = ob->type != OB_POINTCLOUD; + break; + case GEO_COMPONENT_TYPE_INSTANCES: + is_instance = true; + break; + case GEO_COMPONENT_TYPE_VOLUME: + is_instance = ob->type != OB_VOLUME; + break; + case GEO_COMPONENT_TYPE_CURVE: + is_instance = !ELEM(ob->type, OB_CURVE, OB_FONT); + break; + } + if (is_instance) { + return true; + } } return false; } |