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')
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h4
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh45
-rw-r--r--source/blender/blenkernel/BKE_object.h2
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc15
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc37
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc12
-rw-r--r--source/blender/blenkernel/intern/object.c13
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc97
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;
}
}