diff options
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_duplilist.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_geometry_set.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_geometry_set.hh | 45 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_object.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/geometry_component_instances.cc | 15 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/geometry_set.cc | 37 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/geometry_set_instances.cc | 12 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 13 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object_dupli.cc | 97 |
9 files changed, 200 insertions, 27 deletions
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h index c142d5338d1..989b68f4ccb 100644 --- a/source/blender/blenkernel/BKE_duplilist.h +++ b/source/blender/blenkernel/BKE_duplilist.h @@ -31,6 +31,7 @@ struct ListBase; struct Object; struct ParticleSystem; struct Scene; +struct ID; /* ---------------------------------------------------- */ /* Dupli-Geometry */ @@ -42,7 +43,10 @@ void free_object_duplilist(struct ListBase *lb); typedef struct DupliObject { struct DupliObject *next, *prev; + /* Object whose geometry is instanced. */ struct Object *ob; + /* Data owned by the object above that is instanced. This might not be the same as `ob->data`. */ + struct ID *ob_data; float mat[4][4]; float orco[3], uv[2]; diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h index 5f6a9ec7b91..17cdb9d6a42 100644 --- a/source/blender/blenkernel/BKE_geometry_set.h +++ b/source/blender/blenkernel/BKE_geometry_set.h @@ -41,7 +41,7 @@ typedef enum GeometryComponentType { void BKE_geometry_set_free(struct GeometrySet *geometry_set); -bool BKE_geometry_set_has_instances(const struct GeometrySet *geometry_set); +bool BKE_object_has_geometry_set_instances(const struct Object *ob); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index dd921d0d373..c3d594d7dcd 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -289,6 +289,7 @@ struct GeometrySet { void clear(); + bool owns_direct_data() const; void ensure_owns_direct_data(); /* Utility methods for creation. */ @@ -453,12 +454,14 @@ class InstanceReference { None, Object, Collection, + GeometrySet, }; private: Type type_ = Type::None; /** Depending on the type this is either null, an Object or Collection pointer. */ void *data_ = nullptr; + std::unique_ptr<GeometrySet> geometry_set_; public: InstanceReference() = default; @@ -471,6 +474,19 @@ class InstanceReference { { } + InstanceReference(GeometrySet geometry_set) + : type_(Type::GeometrySet), + geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set))) + { + } + + InstanceReference(const InstanceReference &src) : type_(src.type_), data_(src.data_) + { + if (src.type_ == Type::GeometrySet) { + geometry_set_ = std::make_unique<GeometrySet>(*src.geometry_set_); + } + } + Type type() const { return type_; @@ -488,14 +504,37 @@ class InstanceReference { return *(Collection *)data_; } + const GeometrySet &geometry_set() const + { + BLI_assert(type_ == Type::GeometrySet); + return *geometry_set_; + } + + bool owns_direct_data() const + { + if (type_ != Type::GeometrySet) { + /* The object and collection instances are not direct data. */ + return true; + } + return geometry_set_->owns_direct_data(); + } + + void ensure_owns_direct_data() + { + if (type_ != Type::GeometrySet) { + return; + } + geometry_set_->ensure_owns_direct_data(); + } + uint64_t hash() const { - return blender::get_default_hash(data_); + return blender::get_default_hash_2(data_, geometry_set_.get()); } friend bool operator==(const InstanceReference &a, const InstanceReference &b) { - return a.data_ == b.data_; + return a.data_ == b.data_ && a.geometry_set_.get() == b.geometry_set_.get(); } }; @@ -535,7 +574,7 @@ class InstancesComponent : public GeometryComponent { void reserve(int min_capacity); void resize(int capacity); - int add_reference(InstanceReference reference); + int add_reference(const InstanceReference &reference); void add_instance(int instance_handle, const blender::float4x4 &transform, const int id = -1); blender::Span<InstanceReference> references() const; diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index a823602e341..31b3cd66cbb 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -458,6 +458,8 @@ void BKE_object_modifiers_lib_link_common(void *userData, struct ID **idpoin, int cb_flag); +void BKE_object_replace_data_on_shallow_copy(struct Object *ob, struct ID *new_data); + struct PartEff; struct PartEff *BKE_object_do_version_give_parteff_245(struct Object *ob); diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 3b1b7456162..26ef827d36d 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -122,7 +122,7 @@ blender::Span<int> InstancesComponent::instance_ids() const * If the reference exists already, the handle of the existing reference is returned. * Otherwise a new handle is added. */ -int InstancesComponent::add_reference(InstanceReference reference) +int InstancesComponent::add_reference(const InstanceReference &reference) { return references_.index_of_or_add_as(reference); } @@ -144,14 +144,23 @@ bool InstancesComponent::is_empty() const bool InstancesComponent::owns_direct_data() const { - /* The object and collection instances are not direct data. Instance transforms are direct data - * and are always owned. Therefore, instance components always own all their direct data. */ + for (const InstanceReference &reference : references_) { + if (!reference.owns_direct_data()) { + return false; + } + } return true; } void InstancesComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); + for (const InstanceReference &const_reference : references_) { + /* Const cast is fine because we are not changing anything that would change the hash of the + * reference. */ + InstanceReference &reference = const_cast<InstanceReference &>(const_reference); + reference.ensure_owns_direct_data(); + } } static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids) diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 07b4e715ea9..dafebef1812 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -218,6 +218,16 @@ void GeometrySet::ensure_owns_direct_data() } } +bool GeometrySet::owns_direct_data() const +{ + for (const GeometryComponentPtr &component : components_.values()) { + if (!component->owns_direct_data()) { + return false; + } + } + return true; +} + /* Returns a read-only mesh or null. */ const Mesh *GeometrySet::get_mesh_for_read() const { @@ -376,9 +386,32 @@ void BKE_geometry_set_free(GeometrySet *geometry_set) delete geometry_set; } -bool BKE_geometry_set_has_instances(const GeometrySet *geometry_set) +bool BKE_object_has_geometry_set_instances(const Object *ob) { - return geometry_set->get_component_for_read<InstancesComponent>() != nullptr; + const GeometrySet *geometry_set = ob->runtime.geometry_set_eval; + 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 (ob->type == OB_CURVE) { + return has_mesh || has_pointcloud || has_volume; + } + return false; } /** \} */ diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index d281407dd5a..0e19324a3c1 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -168,6 +168,11 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set, collection, instance_transform, r_sets); break; } + case InstanceReference::Type::GeometrySet: { + const GeometrySet &geometry_set = reference.geometry_set(); + geometry_set_collect_recursive(geometry_set, instance_transform, r_sets); + break; + } case InstanceReference::Type::None: { break; } @@ -290,6 +295,13 @@ static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_se } break; } + case InstanceReference::Type::GeometrySet: { + const GeometrySet &geometry_set = reference.geometry_set(); + if (!instances_attribute_foreach_recursive(geometry_set, callback, limit, count)) { + return false; + } + break; + } case InstanceReference::Type::None: { break; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 062264c5729..bca1afbf101 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1979,8 +1979,7 @@ int BKE_object_visibility(const Object *ob, const int dag_eval_mode) visibility |= OB_VISIBLE_INSTANCES; } - if (ob->runtime.geometry_set_eval != NULL && - BKE_geometry_set_has_instances(ob->runtime.geometry_set_eval)) { + if (BKE_object_has_geometry_set_instances(ob)) { visibility |= OB_VISIBLE_INSTANCES; } @@ -5737,3 +5736,13 @@ void BKE_object_modifiers_lib_link_common(void *userData, id_us_plus_no_lib(*idpoin); } } + +void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data) +{ + ob->type = BKE_object_obdata_to_type(new_data); + ob->data = new_data; + ob->runtime.geometry_set_eval = NULL; + ob->runtime.data_eval = NULL; + ob->runtime.bb->flag |= BOUNDBOX_DIRTY; + ob->id.py_instance = NULL; +} diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index a46ac4b1175..47d4d03d1e1 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -194,6 +194,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, } dob->ob = ob; + dob->ob_data = (ID *)ob->data; mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat); dob->type = ctx->gen->type; @@ -834,14 +835,59 @@ static const DupliGenerator gen_dupli_verts_pointcloud = { /** \name Instances Geometry Component Implementation * \{ */ -static void make_duplis_instances_component(const DupliContext *ctx) +static void make_duplis_geometry_set_impl(const DupliContext *ctx, + const GeometrySet &geometry_set, + const float parent_transform[4][4], + bool geometry_set_is_instance) { - const InstancesComponent *component = - ctx->object->runtime.geometry_set_eval->get_component_for_read<InstancesComponent>(); + int component_index = 0; + if (ctx->object->type != OB_MESH || geometry_set_is_instance) { + const Mesh *mesh = geometry_set.get_mesh_for_read(); + if (mesh != nullptr) { + DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); + dupli->ob_data = (ID *)mesh; + } + } + if (ctx->object->type != OB_VOLUME || geometry_set_is_instance) { + const Volume *volume = geometry_set.get_volume_for_read(); + if (volume != nullptr) { + DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); + dupli->ob_data = (ID *)volume; + } + } + if (ctx->object->type != OB_CURVE || geometry_set_is_instance) { + const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>(); + if (curve_component != nullptr) { + const Curve *curve = curve_component->get_curve_for_render(); + if (curve != nullptr) { + DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); + dupli->ob_data = (ID *)curve; + } + } + } + if (ctx->object->type != OB_POINTCLOUD || geometry_set_is_instance) { + const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read(); + if (pointcloud != nullptr) { + DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); + dupli->ob_data = (ID *)pointcloud; + } + } + const bool creates_duplis_for_components = component_index >= 1; + + const InstancesComponent *component = geometry_set.get_component_for_read<InstancesComponent>(); if (component == nullptr) { return; } + const DupliContext *instances_ctx = ctx; + /* Create a sub-context if some duplis were created above. This is to avoid dupli id collisions + * between the instances component below and the other components above. */ + DupliContext new_instances_ctx; + if (creates_duplis_for_components) { + copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index); + instances_ctx = &new_instances_ctx; + } + Span<float4x4> instance_offset_matrices = component->instance_transforms(); Span<int> instance_reference_handles = component->instance_reference_handles(); Span<int> almost_unique_ids = component->almost_unique_ids(); @@ -855,13 +901,13 @@ static void make_duplis_instances_component(const DupliContext *ctx) case InstanceReference::Type::Object: { Object &object = reference.object(); float matrix[4][4]; - mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrices[i].values); - make_dupli(ctx, &object, matrix, id); + mul_m4_m4m4(matrix, parent_transform, instance_offset_matrices[i].values); + make_dupli(instances_ctx, &object, matrix, id); float space_matrix[4][4]; mul_m4_m4m4(space_matrix, instance_offset_matrices[i].values, object.imat); - mul_m4_m4_pre(space_matrix, ctx->object->obmat); - make_recursive_duplis(ctx, &object, space_matrix, id); + mul_m4_m4_pre(space_matrix, parent_transform); + make_recursive_duplis(instances_ctx, &object, space_matrix, id); break; } case InstanceReference::Type::Collection: { @@ -870,23 +916,36 @@ static void make_duplis_instances_component(const DupliContext *ctx) unit_m4(collection_matrix); sub_v3_v3(collection_matrix[3], collection.instance_offset); mul_m4_m4_pre(collection_matrix, instance_offset_matrices[i].values); - mul_m4_m4_pre(collection_matrix, ctx->object->obmat); + mul_m4_m4_pre(collection_matrix, parent_transform); + + DupliContext sub_ctx; + copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id); - eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); + eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph); + int object_id = 0; FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (&collection, object, mode) { - if (object == ctx->object) { + if (object == instances_ctx->object) { continue; } float instance_matrix[4][4]; mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); - make_dupli(ctx, object, instance_matrix, id); - make_recursive_duplis(ctx, object, collection_matrix, id); + make_dupli(&sub_ctx, object, instance_matrix, object_id++); + make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++); } FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; break; } + case InstanceReference::Type::GeometrySet: { + float new_transform[4][4]; + mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values); + + DupliContext sub_ctx; + copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id); + make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true); + break; + } case InstanceReference::Type::None: { break; } @@ -894,9 +953,15 @@ static void make_duplis_instances_component(const DupliContext *ctx) } } -static const DupliGenerator gen_dupli_instances_component = { +static void make_duplis_geometry_set(const DupliContext *ctx) +{ + const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval; + make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false); +} + +static const DupliGenerator gen_dupli_geometry_set = { 0, - make_duplis_instances_component, + make_duplis_geometry_set, }; /** \} */ @@ -1567,8 +1632,8 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) } if (ctx->object->runtime.geometry_set_eval != nullptr) { - if (BKE_geometry_set_has_instances(ctx->object->runtime.geometry_set_eval)) { - return &gen_dupli_instances_component; + if (BKE_object_has_geometry_set_instances(ctx->object)) { + return &gen_dupli_geometry_set; } } |