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:
-rw-r--r--source/blender/editors/object/object_add.c144
1 files changed, 101 insertions, 43 deletions
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 033bc57f502..51b40a968ed 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1658,54 +1658,80 @@ static void copy_object_set_idnew(bContext *C)
/** \name Make Instanced Objects Real Operator
* \{ */
+/* XXX TODO That whole hierarchy handling based on persistent_id tricks is
+ * very confusing and convoluted, and it will fail in many cases besides basic ones.
+ * Think this should be replaced by a proper tree-like representation of the instantiations,
+ * should help a lot in both readability, and precise consistent rebuilding of hierarchy.
+ */
+
/**
- * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION,
+ * \note regarding hashing dupli-objects which come from OB_DUPLICOLLECTION,
* skip the first member of #DupliObject.persistent_id
* since its a unique index and we only want to know if the group objects are from the same
* dupli-group instance.
+ *
+ * \note regarding hashing dupli-objects which come from non-OB_DUPLICOLLECTION,
+ * include the first member of #DupliObject.persistent_id
+ * since its the index of the vertex/face the object is instantiated on and we want to identify
+ * objects on the same vertex/face.
+ * In other words, we consider each group of objects from a same item as being
+ * the 'local group' where to check for parents.
*/
-static unsigned int dupliobject_group_hash(const void *ptr)
+static unsigned int dupliobject_hash(const void *ptr)
{
const DupliObject *dob = ptr;
unsigned int hash = BLI_ghashutil_ptrhash(dob->ob);
- unsigned int i;
- for (i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
- hash ^= (dob->persistent_id[i] ^ i);
+
+ if (dob->type == OB_DUPLICOLLECTION) {
+ for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
+ hash ^= (dob->persistent_id[i] ^ i);
+ }
+ }
+ else {
+ hash ^= (dob->persistent_id[0] ^ 0);
}
return hash;
}
/**
- * \note regarding hashing dupli-objects when NOT using OB_DUPLICOLLECTION,
- * include the first member of #DupliObject.persistent_id
- * since its the index of the vertex/face the object is instantiated on and we want to identify
- * objects on the same vertex/face.
+ * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION,
+ * skip the first member of #DupliObject.persistent_id
+ * since its a unique index and we only want to know if the group objects are from the same
+ * dupli-group instance.
*/
-static unsigned int dupliobject_hash(const void *ptr)
+static unsigned int dupliobject_instancer_hash(const void *ptr)
{
const DupliObject *dob = ptr;
- unsigned int hash = BLI_ghashutil_ptrhash(dob->ob);
- hash ^= (dob->persistent_id[0] ^ 0);
+ unsigned int hash = BLI_ghashutil_inthash(dob->persistent_id[0]);
+ for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
+ hash ^= (dob->persistent_id[i] ^ i);
+ }
return hash;
}
-/* Compare function that matches dupliobject_group_hash */
-static bool dupliobject_group_cmp(const void *a_, const void *b_)
+/* Compare function that matches dupliobject_hash */
+static bool dupliobject_cmp(const void *a_, const void *b_)
{
const DupliObject *a = a_;
const DupliObject *b = b_;
- unsigned int i;
if (a->ob != b->ob) {
return true;
}
- for (i = 1; (i < MAX_DUPLI_RECUR); i++) {
- if (a->persistent_id[i] != b->persistent_id[i]) {
- return true;
+ if (ELEM(a->type, b->type, OB_DUPLICOLLECTION)) {
+ for (int i = 1; (i < MAX_DUPLI_RECUR); i++) {
+ if (a->persistent_id[i] != b->persistent_id[i]) {
+ return true;
+ }
+ else if (a->persistent_id[i] == INT_MAX) {
+ break;
+ }
}
- else if (a->persistent_id[i] == INT_MAX) {
- break;
+ }
+ else {
+ if (a->persistent_id[0] != b->persistent_id[0]) {
+ return true;
}
}
@@ -1713,18 +1739,19 @@ static bool dupliobject_group_cmp(const void *a_, const void *b_)
return false;
}
-/* Compare function that matches dupliobject_hash */
-static bool dupliobject_cmp(const void *a_, const void *b_)
+/* Compare function that matches dupliobject_instancer_hash. */
+static bool dupliobject_instancer_cmp(const void *a_, const void *b_)
{
const DupliObject *a = a_;
const DupliObject *b = b_;
- if (a->ob != b->ob) {
- return true;
- }
-
- if (a->persistent_id[0] != b->persistent_id[0]) {
- return true;
+ for (int i = 0; (i < MAX_DUPLI_RECUR); i++) {
+ if (a->persistent_id[i] != b->persistent_id[i]) {
+ return true;
+ }
+ else if (a->persistent_id[i] == INT_MAX) {
+ break;
+ }
}
/* matching */
@@ -1739,7 +1766,7 @@ static void make_object_duplilist_real(
Depsgraph *depsgraph = CTX_data_depsgraph(C);
ListBase *lb_duplis;
DupliObject *dob;
- GHash *dupli_gh, *parent_gh = NULL;
+ GHash *dupli_gh, *parent_gh = NULL, *instancer_gh = NULL;
if (!(base->object->transflag & OB_DUPLI)) {
return;
@@ -1750,11 +1777,11 @@ static void make_object_duplilist_real(
dupli_gh = BLI_ghash_ptr_new(__func__);
if (use_hierarchy) {
- if (base->object->transflag & OB_DUPLICOLLECTION) {
- parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__);
- }
- else {
- parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
+ parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
+
+ if (use_base_parent) {
+ instancer_gh = BLI_ghash_new(
+ dupliobject_instancer_hash, dupliobject_instancer_cmp, __func__);
}
}
@@ -1788,7 +1815,12 @@ static void make_object_duplilist_real(
ob_dst->parent = NULL;
BKE_constraints_free(&ob_dst->constraints);
ob_dst->runtime.curve_cache = NULL;
+ const bool is_dupli_instancer = (ob_dst->transflag & OB_DUPLI) != 0;
ob_dst->transflag &= ~OB_DUPLI;
+ /* Remove instantiated collection, it's annoying to keep it here
+ * (and get potentially a lot of usages of it then...). */
+ id_us_min((ID *)ob_dst->instance_collection);
+ ob_dst->instance_collection = NULL;
copy_m4_m4(ob_dst->obmat, dob->mat);
BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false);
@@ -1802,6 +1834,13 @@ static void make_object_duplilist_real(
if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) {
*val = ob_dst;
}
+
+ if (is_dupli_instancer && instancer_gh) {
+ /* Same as above, we may have several 'hits'. */
+ if (!BLI_ghash_ensure_p(instancer_gh, dob, &val)) {
+ *val = ob_dst;
+ }
+ }
}
}
@@ -1825,7 +1864,8 @@ static void make_object_duplilist_real(
* they won't be read, this is simply for a hash lookup. */
DupliObject dob_key;
dob_key.ob = ob_src_par;
- if (base->object->transflag & OB_DUPLICOLLECTION) {
+ dob_key.type = dob->type;
+ if (dob->type == OB_DUPLICOLLECTION) {
memcpy(&dob_key.persistent_id[1],
&dob->persistent_id[1],
sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1));
@@ -1848,15 +1888,30 @@ static void make_object_duplilist_real(
ob_dst->parent = ob_dst_par;
}
- else if (use_base_parent) {
- ob_dst->parent = base->object;
- ob_dst->partype = PAROBJECT;
- }
}
- else if (use_base_parent) {
- /* since we are ignoring the internal hierarchy - parent all to the
- * base object */
- ob_dst->parent = base->object;
+ if (use_base_parent && ob_dst->parent == NULL) {
+ Object *ob_dst_par = NULL;
+
+ if (instancer_gh != NULL) {
+ /* OK to keep most of the members uninitialized,
+ * they won't be read, this is simply for a hash lookup. */
+ DupliObject dob_key;
+ /* We are looking one step upper in hierarchy, so we need to 'shift' the persitent_id,
+ * ignoring the first item.
+ * We only check on persistent_id here, since we have no idea what object it might be. */
+ memcpy(&dob_key.persistent_id[0],
+ &dob->persistent_id[1],
+ sizeof(dob_key.persistent_id[0]) * (MAX_DUPLI_RECUR - 1));
+ ob_dst_par = BLI_ghash_lookup(instancer_gh, &dob_key);
+ }
+
+ if (ob_dst_par == NULL) {
+ /* Default to parenting to root object...
+ * Always the case when use_hierarchy is false. */
+ ob_dst_par = base->object;
+ }
+
+ ob_dst->parent = ob_dst_par;
ob_dst->partype = PAROBJECT;
}
@@ -1885,6 +1940,9 @@ static void make_object_duplilist_real(
if (parent_gh) {
BLI_ghash_free(parent_gh, NULL, NULL);
}
+ if (instancer_gh) {
+ BLI_ghash_free(instancer_gh, NULL, NULL);
+ }
free_object_duplilist(lb_duplis);