Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/geometry_set.cc')
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc387
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;
}