diff options
Diffstat (limited to 'source/blender/editors/object/object_add.c')
-rw-r--r-- | source/blender/editors/object/object_add.c | 153 |
1 files changed, 106 insertions, 47 deletions
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 6e973740f7c..a6f7388cb49 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1252,10 +1252,10 @@ static void copy_object_set_idnew(bContext *C) /********************* Make Duplicates Real ************************/ /** - * \note regarding hashing dupli-objects, skip the first member of #DupliObject.persistent_id + * \note regarding hashing dupli-objects when using OB_DUPLIGROUP, 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_group_hash(const void *ptr) { const DupliObject *dob = ptr; unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); @@ -1266,7 +1266,20 @@ static unsigned int dupliobject_hash(const void *ptr) return hash; } -static bool dupliobject_cmp(const void *a_, const void *b_) +/** + * \note regarding hashing dupli-objects when NOT using OB_DUPLIGROUP, 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. + */ +static unsigned int dupliobject_hash(const void *ptr) +{ + const DupliObject *dob = ptr; + unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); + hash ^= (dob->persistent_id[0] ^ 0); + return hash; +} + +/* Compare function that matches dupliobject_group_hash */ +static bool dupliobject_group_cmp(const void *a_, const void *b_) { const DupliObject *a = a_; const DupliObject *b = b_; @@ -1289,6 +1302,24 @@ static bool dupliobject_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_) +{ + 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; + } + + /* matching */ + return false; +} + static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, const bool use_base_parent, const bool use_hierarchy) @@ -1307,13 +1338,18 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (use_hierarchy || use_base_parent) { dupli_gh = BLI_ghash_ptr_new(__func__); if (use_hierarchy) { - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + if (base->object->transflag & OB_DUPLIGROUP) { + parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); + } + else { + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + } } } for (dob = lb->first; dob; dob = dob->next) { Base *basen; - Object *ob = BKE_object_copy(bmain, dob->ob); + Object *ob = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, dob->ob)); /* font duplis can have a totcol without material, we get them from parent * should be implemented better... @@ -1357,6 +1393,11 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, } } + /* Remap new object to itself, and clear again newid pointer of orig object. */ + BKE_libblock_relink(&ob->id); + set_sca_new_poins_ob(ob); + BKE_id_clear_newpoin(&dob->ob->id); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } @@ -1375,9 +1416,14 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, * they won't be read, this is simply for a hash lookup. */ DupliObject dob_key; dob_key.ob = ob_src_par; - memcpy(&dob_key.persistent_id[1], - &dob->persistent_id[1], - sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + if (base->object->transflag & OB_DUPLIGROUP) { + memcpy(&dob_key.persistent_id[1], + &dob->persistent_id[1], + sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + } + else { + dob_key.persistent_id[0] = dob->persistent_id[0]; + } ob_dst_par = BLI_ghash_lookup(parent_gh, &dob_key); } @@ -1442,8 +1488,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (parent_gh) BLI_ghash_free(parent_gh, NULL, NULL); - copy_object_set_idnew(C); - free_object_duplilist(lb); base->object->transflag &= ~OB_DUPLI; @@ -1918,8 +1962,12 @@ void OBJECT_OT_convert(wmOperatorType *ot) /* used below, assumes id.new is correct */ /* leaves selection of base/object unaltered */ +/* Does set ID->newid pointers. */ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base, int dupflag) { +#define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } +#define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } + Base *basen = NULL; Material ***matarar; Object *ob, *obn; @@ -1931,7 +1979,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base ; /* nothing? */ } else { - obn = BKE_object_copy(bmain, ob); + obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); basen = MEM_mallocN(sizeof(Base), "duplibase"); @@ -1953,20 +2001,21 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base /* duplicates using userflags */ if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(&obn->id); + BKE_animdata_copy_id_action(&obn->id, true); } if (dupflag & USER_DUP_MAT) { for (a = 0; a < obn->totcol; a++) { id = (ID *)obn->mat[a]; if (id) { - ID_NEW_US(obn->mat[a]) - else - obn->mat[a] = BKE_material_copy(bmain, obn->mat[a]); + ID_NEW_REMAP_US(obn->mat[a]) + else { + obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a])); + } id_us_min(id); if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(&obn->mat[a]->id); + BKE_animdata_copy_id_action(&obn->mat[a]->id, true); } } } @@ -1978,9 +2027,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base switch (obn->type) { case OB_MESH: if (dupflag & USER_DUP_MESH) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_mesh_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -1988,9 +2037,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_CURVE: if (dupflag & USER_DUP_CURVE) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_curve_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -1998,9 +2047,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_SURF: if (dupflag & USER_DUP_SURF) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_curve_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2008,9 +2057,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_FONT: if (dupflag & USER_DUP_FONT) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_curve_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2018,9 +2067,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_MBALL: if (dupflag & USER_DUP_MBALL) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_mball_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2028,9 +2077,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_LAMP: if (dupflag & USER_DUP_LAMP) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_lamp_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_lamp_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2041,9 +2090,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (obn->pose) BKE_pose_tag_recalc(bmain, obn->pose); if (dupflag & USER_DUP_ARM) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_armature_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data)); BKE_pose_rebuild(obn, obn->data); didit = 1; } @@ -2052,9 +2101,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_LATTICE: if (dupflag != 0) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_lattice_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2062,9 +2111,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_CAMERA: if (dupflag != 0) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_camera_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2072,9 +2121,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_SPEAKER: if (dupflag != 0) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_speaker_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2089,12 +2138,15 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_ACT) { bActuator *act; - BKE_animdata_copy_id_action((ID *)obn->data); + BKE_animdata_copy_id_action((ID *)obn->data, true); if (key) { - BKE_animdata_copy_id_action((ID *)key); + BKE_animdata_copy_id_action((ID *)key, true); } /* Update the duplicated action in the action actuators */ + /* XXX TODO this code is all wrong! actact->act is user-refcounted (see readfile.c), + * and what about other ID pointers of other BGE logic bricks, + * and since this is object-level, why is it only ran if obdata was duplicated??? -mont29 */ for (act = obn->actuators.first; act; act = act->next) { if (act->type == ACT_ACTION) { bActionActuator *actact = (bActionActuator *) act->data; @@ -2111,9 +2163,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base for (a = 0; a < obn->totcol; a++) { id = (ID *)(*matarar)[a]; if (id) { - ID_NEW_US((*matarar)[a]) - else - (*matarar)[a] = BKE_material_copy(bmain, (*matarar)[a]); + ID_NEW_REMAP_US((*matarar)[a]) + else { + (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a])); + } id_us_min(id); } } @@ -2122,6 +2175,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base } } return basen; + +#undef ID_NEW_REMAP_US +#undef ID_NEW_REMAP_US2 } /* single object duplicate, if dupflag==0, fully linked, else it uses the flags given */ @@ -2134,8 +2190,7 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag Base *basen; Object *ob; - BKE_main_id_clear_newpoins(bmain); - clear_sca_new_poins(); /* sensor/contr/act */ + clear_sca_new_poins(); /* BGE logic */ basen = object_add_duplicate_internal(bmain, scene, base, dupflag); if (basen == NULL) { @@ -2154,6 +2209,8 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag ED_render_id_flush_update(bmain, ob->data); } + BKE_main_id_clear_newpoins(bmain); + return basen; } @@ -2165,8 +2222,7 @@ static int duplicate_exec(bContext *C, wmOperator *op) const bool linked = RNA_boolean_get(op->ptr, "linked"); int dupflag = (linked) ? 0 : U.dupflag; - BKE_main_id_clear_newpoins(bmain); - clear_sca_new_poins(); /* sensor/contr/act */ + clear_sca_new_poins(); /* BGE logic */ CTX_DATA_BEGIN (C, Base *, base, selected_bases) { @@ -2192,6 +2248,8 @@ static int duplicate_exec(bContext *C, wmOperator *op) copy_object_set_idnew(C); + BKE_main_id_clear_newpoins(bmain); + DAG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); @@ -2250,8 +2308,7 @@ static int add_named_exec(bContext *C, wmOperator *op) base->flag = ob->flag; /* prepare dupli */ - BKE_main_id_clear_newpoins(bmain); - clear_sca_new_poins(); /* sensor/contr/act */ + clear_sca_new_poins(); /* BGE logic */ basen = object_add_duplicate_internal(bmain, scene, base, dupflag); @@ -2277,6 +2334,8 @@ static int add_named_exec(bContext *C, wmOperator *op) copy_object_set_idnew(C); + BKE_main_id_clear_newpoins(bmain); + DAG_relations_tag_update(bmain); MEM_freeN(base); |