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_fields.cc')
-rw-r--r--source/blender/blenkernel/intern/geometry_fields.cc171
1 files changed, 171 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc
index 56e9e9dcdff..e242154cb5b 100644
--- a/source/blender/blenkernel/intern/geometry_fields.cc
+++ b/source/blender/blenkernel/intern/geometry_fields.cc
@@ -157,6 +157,12 @@ GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &conte
return {};
}
+std::optional<eAttrDomain> GeometryFieldInput::preferred_domain(
+ const GeometryComponent & /*component*/) const
+{
+ return std::nullopt;
+}
+
GVArray MeshFieldInput::get_varray_for_context(const fn::FieldContext &context,
const IndexMask mask,
ResourceScope & /*scope*/) const
@@ -173,6 +179,11 @@ GVArray MeshFieldInput::get_varray_for_context(const fn::FieldContext &context,
return {};
}
+std::optional<eAttrDomain> MeshFieldInput::preferred_domain(const Mesh & /*mesh*/) const
+{
+ return std::nullopt;
+}
+
GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope & /*scope*/) const
@@ -190,6 +201,12 @@ GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context
return {};
}
+std::optional<eAttrDomain> CurvesFieldInput::preferred_domain(
+ const CurvesGeometry & /*curves*/) const
+{
+ return std::nullopt;
+}
+
GVArray PointCloudFieldInput::get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope & /*scope*/) const
@@ -254,6 +271,20 @@ bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return false;
}
+std::optional<eAttrDomain> AttributeFieldInput::preferred_domain(
+ const GeometryComponent &component) const
+{
+ const std::optional<AttributeAccessor> attributes = component.attributes();
+ if (!attributes.has_value()) {
+ return std::nullopt;
+ }
+ const std::optional<AttributeMetaData> meta_data = attributes->lookup_meta_data(name_);
+ if (!meta_data.has_value()) {
+ return std::nullopt;
+ }
+ return meta_data->domain;
+}
+
static StringRef get_random_id_attribute_name(const eAttrDomain domain)
{
switch (domain) {
@@ -325,6 +356,21 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return false;
}
+std::optional<eAttrDomain> AnonymousAttributeFieldInput::preferred_domain(
+ const GeometryComponent &component) const
+{
+ const std::optional<AttributeAccessor> attributes = component.attributes();
+ if (!attributes.has_value()) {
+ return std::nullopt;
+ }
+ const std::optional<AttributeMetaData> meta_data = attributes->lookup_meta_data(
+ anonymous_id_.get());
+ if (!meta_data.has_value()) {
+ return std::nullopt;
+ }
+ return meta_data->domain;
+}
+
} // namespace blender::bke
/* -------------------------------------------------------------------- */
@@ -360,6 +406,131 @@ bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const
return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
}
+bool try_capture_field_on_geometry(GeometryComponent &component,
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const fn::GField &field)
+{
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ const int domain_size = attributes.domain_size(domain);
+ const CPPType &type = field.cpp_type();
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type);
+
+ if (domain_size == 0) {
+ return attributes.add(attribute_id, domain, data_type, AttributeInitConstruct{});
+ }
+
+ bke::GeometryFieldContext field_context{component, domain};
+ const IndexMask mask{IndexMask(domain_size)};
+ const bke::AttributeValidator validator = attributes.lookup_validator(attribute_id);
+
+ /* Could avoid allocating a new buffer if:
+ * - We are writing to an attribute that exists already with the correct domain and type.
+ * - The field does not depend on that attribute (we can't easily check for that yet). */
+ void *buffer = MEM_mallocN(type.size() * domain_size, __func__);
+
+ fn::FieldEvaluator evaluator{field_context, &mask};
+ evaluator.add_with_destination(validator.validate_field_if_necessary(field),
+ GMutableSpan{type, buffer, domain_size});
+ evaluator.evaluate();
+
+ if (GAttributeWriter attribute = attributes.lookup_for_write(attribute_id)) {
+ if (attribute.domain == domain && attribute.varray.type() == type) {
+ attribute.varray.set_all(buffer);
+ attribute.finish();
+ type.destruct_n(buffer, domain_size);
+ MEM_freeN(buffer);
+ return true;
+ }
+ }
+ attributes.remove(attribute_id);
+ if (attributes.add(attribute_id, domain, data_type, bke::AttributeInitMoveArray{buffer})) {
+ return true;
+ }
+
+ /* If the name corresponds to a builtin attribute, removing the attribute might fail if
+ * it's required, and adding the attribute might fail if the domain or type is incorrect. */
+ type.destruct_n(buffer, domain_size);
+ MEM_freeN(buffer);
+ return false;
+}
+
+std::optional<eAttrDomain> try_detect_field_domain(const GeometryComponent &component,
+ const fn::GField &field)
+{
+ const GeometryComponentType component_type = component.type();
+ if (component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) {
+ return ATTR_DOMAIN_POINT;
+ }
+ if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
+ return ATTR_DOMAIN_INSTANCE;
+ }
+ const std::shared_ptr<const fn::FieldInputs> &field_inputs = field.node().field_inputs();
+ if (!field_inputs) {
+ return std::nullopt;
+ }
+ std::optional<eAttrDomain> output_domain;
+ auto handle_domain = [&](const std::optional<eAttrDomain> domain) {
+ if (!domain.has_value()) {
+ return false;
+ }
+ if (output_domain.has_value()) {
+ if (*output_domain != *domain) {
+ return false;
+ }
+ return true;
+ }
+ output_domain = domain;
+ return true;
+ };
+ if (component_type == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return std::nullopt;
+ }
+ for (const fn::FieldInput &field_input : field_inputs->deduplicated_nodes) {
+ if (auto geometry_field_input = dynamic_cast<const GeometryFieldInput *>(&field_input)) {
+ if (!handle_domain(geometry_field_input->preferred_domain(component))) {
+ return std::nullopt;
+ }
+ }
+ else if (auto mesh_field_input = dynamic_cast<const MeshFieldInput *>(&field_input)) {
+ if (!handle_domain(mesh_field_input->preferred_domain(*mesh))) {
+ return std::nullopt;
+ }
+ }
+ else {
+ return std::nullopt;
+ }
+ }
+ }
+ if (component_type == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const Curves *curves = curve_component.get_for_read();
+ if (curves == nullptr) {
+ return std::nullopt;
+ }
+ for (const fn::FieldInput &field_input : field_inputs->deduplicated_nodes) {
+ if (auto geometry_field_input = dynamic_cast<const GeometryFieldInput *>(&field_input)) {
+ if (!handle_domain(geometry_field_input->preferred_domain(component))) {
+ return std::nullopt;
+ }
+ }
+ else if (auto curves_field_input = dynamic_cast<const CurvesFieldInput *>(&field_input)) {
+ if (!handle_domain(
+ curves_field_input->preferred_domain(CurvesGeometry::wrap(curves->geometry)))) {
+ return std::nullopt;
+ }
+ }
+ else {
+ return std::nullopt;
+ }
+ }
+ }
+ return output_domain;
+}
+
} // namespace blender::bke
/** \} */