Cleanup id->newid usage, initial work.

This aims at always ensuring that ID.newid (and relevant LIB_TAG_NEW)
stay in clean (i.e. cleared) state by default.

To achieve this, instead of clearing after all id copy call (would be
horribly noisy, and bad for performances), we try to completely remove
the setting of id->newid by default when copying a new ID.

This implies that areas actually needing that info (mainly, object editing
area (make single user...) and make local area) have to ensure they set
it themselves as needed.

This is far from simple change, many complex code paths to consider, so
will need some serious testing. :/
This commit is contained in:
Bastien Montagne 2016-11-30 15:25:54 +01:00
parent 2f6f75613f
commit df63195d2a
20 changed files with 180 additions and 145 deletions

View File

@ -73,7 +73,7 @@ struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action);
bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action);
/* Copy AnimData Actions */
void BKE_animdata_copy_id_action(struct ID *id);
void BKE_animdata_copy_id_action(struct ID *id, const bool set_newid);
/* Merge copies of data from source AnimData block */
typedef enum eAnimData_MergeCopy_Modes {

View File

@ -80,6 +80,7 @@ void id_us_plus(struct ID *id);
void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
void BKE_id_clear_newpoin(struct ID *id);
void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_in_mainlist, const bool lib_local);
bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local);

View File

@ -308,17 +308,19 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action)
return true;
}
void BKE_animdata_copy_id_action(ID *id)
void BKE_animdata_copy_id_action(ID *id, const bool set_newid)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
if (adt->action) {
id_us_min((ID *)adt->action);
adt->action = BKE_action_copy(G.main, adt->action);
adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(G.main, adt->action)) :
BKE_action_copy(G.main, adt->action);
}
if (adt->tmpact) {
id_us_min((ID *)adt->tmpact);
adt->tmpact = BKE_action_copy(G.main, adt->tmpact);
adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(G.main, adt->tmpact)) :
BKE_action_copy(G.main, adt->tmpact);
}
}
}

View File

@ -249,6 +249,9 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
brush_new->id.us = 0;
/* setting newid is mandatory for complex make_lib_local logic... */
ID_NEW_SET(brush, brush_new);
if (!lib_local) {
BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}

View File

@ -1428,7 +1428,6 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
/* test; are group objects all in this scene? */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
ob->id.tag &= ~LIB_TAG_DOIT;
ob->id.newid = NULL; /* newid abuse for GroupObject */
}
for (base = sce->base.first; base; base = base->next)
base->object->id.tag |= LIB_TAG_DOIT;
@ -1459,6 +1458,11 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
group->gobject = listb;
}
}
/* newid abused for GroupObject, cleanup. */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
ob->id.newid = NULL;
}
}
static void dag_scene_tag_rebuild(Scene *sce)

View File

@ -436,7 +436,6 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
Image *BKE_image_copy(Main *bmain, Image *ima)
{
Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type);
ima->id.newid = &nima->id;
BLI_strncpy(nima->name, ima->name, sizeof(ima->name));

View File

@ -263,6 +263,14 @@ void id_fake_user_clear(ID *id)
}
}
void BKE_id_clear_newpoin(ID *id)
{
if (id->newid) {
id->newid->tag &= ~LIB_TAG_NEW;
}
id->newid = NULL;
}
static int id_expand_local_callback(
void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag))
{
@ -326,6 +334,17 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
if (id_copy(bmain, id, &id_new, false)) {
id_new->us = 0;
/* setting newid is mandatory for complex make_lib_local logic... */
ID_NEW_SET(id, id_new);
Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id);
if (key && key_new) {
ID_NEW_SET(key, key_new);
}
bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new);
if (ntree && ntree_new) {
ID_NEW_SET(ntree, ntree_new);
}
if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
@ -337,6 +356,8 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c
/**
* Calls the appropriate make_local method for the block, unless test is set.
*
* \note Always set ID->newid pointer in case it gets duplicated...
*
* \param lib_local Special flag used when making a whole library's content local, it needs specific handling.
*
* \return true if the block can be made local.
@ -561,6 +582,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test)
return false;
}
/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
ID *newid = NULL;
@ -571,11 +593,11 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (RNA_property_editable(ptr, prop)) {
if (id_copy(CTX_data_main(C), id, &newid, false) && newid) {
/* copy animation actions too */
BKE_animdata_copy_id_action(id);
BKE_animdata_copy_id_action(id, false);
/* us is 1 by convention, but RNA_property_pointer_set
* will also increment it, so set it to zero */
newid->us = 0;
/* assign copy */
RNA_id_pointer_create(newid, &idptr);
RNA_property_pointer_set(ptr, prop, idptr);
@ -1120,9 +1142,6 @@ void *BKE_libblock_copy(Main *bmain, ID *id)
memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
}
id->newid = idn;
idn->tag |= LIB_TAG_NEW;
BKE_libblock_copy_data(idn, id, false);
@ -1147,8 +1166,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID));
}
id->newid = idn;
idn->tag |= LIB_TAG_NEW;
idn->us = 1;
BKE_libblock_copy_data(idn, id, do_action);
@ -1662,7 +1679,6 @@ void BKE_library_make_local(
const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name)));
for (; id; id = id->next) {
id->newid = NULL;
id->tag &= ~LIB_TAG_DOIT;
if (id->lib == NULL) {
@ -1862,6 +1878,7 @@ void BKE_library_make_local(
}
}
BKE_main_id_clear_newpoins(bmain);
BLI_memarena_free(linklist_mem);
}

View File

@ -1215,6 +1215,9 @@ void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, con
ob_new->id.us = 0;
ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
/* setting newid is mandatory for complex make_lib_local logic... */
ID_NEW_SET(ob, ob_new);
if (!lib_local) {
BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}

View File

@ -225,8 +225,8 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob)
/* preserve relationships between constraints and rigid bodies after duplication */
void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc)
{
ID_NEW(rbc->ob1);
ID_NEW(rbc->ob2);
ID_NEW_REMAP(rbc->ob1);
ID_NEW_REMAP(rbc->ob2);
}
/* ************************************** */

View File

@ -602,41 +602,41 @@ void set_sca_new_poins_ob(Object *ob)
if (act->flag & ACT_NEW) {
if (act->type==ACT_EDIT_OBJECT) {
bEditObjectActuator *eoa= act->data;
ID_NEW(eoa->ob);
ID_NEW_REMAP(eoa->ob);
}
else if (act->type==ACT_SCENE) {
bSceneActuator *sca= act->data;
ID_NEW(sca->camera);
ID_NEW_REMAP(sca->camera);
}
else if (act->type==ACT_CAMERA) {
bCameraActuator *ca= act->data;
ID_NEW(ca->ob);
ID_NEW_REMAP(ca->ob);
}
else if (act->type==ACT_OBJECT) {
bObjectActuator *oa= act->data;
ID_NEW(oa->reference);
ID_NEW_REMAP(oa->reference);
}
else if (act->type==ACT_MESSAGE) {
bMessageActuator *ma= act->data;
ID_NEW(ma->toObject);
ID_NEW_REMAP(ma->toObject);
}
else if (act->type==ACT_PARENT) {
bParentActuator *para = act->data;
ID_NEW(para->ob);
ID_NEW_REMAP(para->ob);
}
else if (act->type==ACT_ARMATURE) {
bArmatureActuator *aa = act->data;
ID_NEW(aa->target);
ID_NEW(aa->subtarget);
ID_NEW_REMAP(aa->target);
ID_NEW_REMAP(aa->subtarget);
}
else if (act->type==ACT_PROPERTY) {
bPropertyActuator *pa= act->data;
ID_NEW(pa->ob);
ID_NEW_REMAP(pa->ob);
}
else if (act->type==ACT_STEERING) {
bSteeringActuator *sta = act->data;
ID_NEW(sta->navmesh);
ID_NEW(sta->target);
ID_NEW_REMAP(sta->navmesh);
ID_NEW_REMAP(sta->target);
}
}
act= act->next;

View File

@ -186,8 +186,6 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
scen = BKE_libblock_copy(bmain, &sce->id);
BLI_duplicatelist(&(scen->base), &(sce->base));
BKE_main_id_clear_newpoins(bmain);
id_us_plus((ID *)scen->world);
id_us_plus((ID *)scen->set);
/* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */
@ -225,7 +223,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
}
/* copy action and remove animation used by sequencer */
BKE_animdata_copy_id_action(&scen->id);
BKE_animdata_copy_id_action(&scen->id, false);
if (type != SCE_COPY_FULL)
remove_sequencer_fcurves(scen);
@ -318,7 +316,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* camera */
if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) {
ID_NEW(scen->camera);
ID_NEW_REMAP(scen->camera);
}
/* before scene copy */
@ -329,7 +327,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (scen->world) {
id_us_plus((ID *)scen->world);
scen->world = BKE_world_copy(bmain, scen->world);
BKE_animdata_copy_id_action((ID *)scen->world);
BKE_animdata_copy_id_action((ID *)scen->world, false);
}
if (sce->ed) {

View File

@ -320,7 +320,8 @@ void BKE_sequencer_free_clipboard(void)
/* Manage pointers in the clipboard.
* note that these pointers should _never_ be access in the sequencer,
* they are only for storage while in the clipboard
* notice 'newid' is used for temp pointer storage here, validate on access.
* notice 'newid' is used for temp pointer storage here, validate on access (this is safe usage,
* since those datablocks are fully out of Main lists).
*/
#define ID_PT (*id_pt)
static void seqclipboard_ptr_free(ID **id_pt)

View File

@ -8102,6 +8102,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short
id->lib = main->curlib;
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) {

View File

@ -303,7 +303,10 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_LOCAL:
if (id) {
if (id_make_local(CTX_data_main(C), id, false, false)) {
Main *bmain = CTX_data_main(C);
if (id_make_local(bmain, id, false, false)) {
BKE_main_id_clear_newpoins(bmain);
/* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template->ptr, template->prop);
RNA_property_pointer_set(&template->ptr, template->prop, idptr);

View File

@ -1350,7 +1350,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
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...
@ -1394,6 +1394,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);
}
@ -1484,8 +1489,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;
@ -1960,8 +1963,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;
@ -1973,7 +1980,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");
@ -1995,20 +2002,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);
}
}
}
@ -2018,12 +2026,13 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
for (psys = obn->particlesystem.first; psys; psys = psys->next) {
id = (ID *) psys->part;
if (id) {
ID_NEW_US(psys->part)
else
psys->part = BKE_particlesettings_copy(bmain, psys->part);
ID_NEW_REMAP_US(psys->part)
else {
psys->part = ID_NEW_SET(psys->part, BKE_particlesettings_copy(bmain, psys->part));
}
if (dupflag & USER_DUP_ACT) {
BKE_animdata_copy_id_action(&psys->part->id);
BKE_animdata_copy_id_action(&psys->part->id, true);
}
id_us_min(id);
@ -2037,9 +2046,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);
@ -2047,9 +2056,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);
@ -2057,9 +2066,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);
@ -2067,9 +2076,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);
@ -2077,9 +2086,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);
@ -2087,9 +2096,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);
@ -2100,9 +2109,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;
}
@ -2111,9 +2120,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);
@ -2121,9 +2130,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);
@ -2131,9 +2140,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);
@ -2148,12 +2157,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;
@ -2170,9 +2182,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);
}
}
@ -2181,6 +2194,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 */
@ -2193,8 +2209,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) {
@ -2213,6 +2228,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;
}
@ -2224,8 +2241,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)
{
@ -2251,6 +2267,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);
@ -2309,8 +2327,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);
@ -2336,6 +2353,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);

View File

@ -1731,6 +1731,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/**************************** Make Single User ********************************/
/* Warning, sets ID->newid pointers of objects and groups, but does not clear them. */
static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups)
{
Base *base;
@ -1738,18 +1739,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
Group *group, *groupn;
GroupObject *go;
clear_sca_new_poins(); /* sensor/contr/act */
/* newid may still have some trash from Outliner tree building, so clear that first to avoid errors, see T26002.
* We have to clear whole datablocks, not only Object one may be accessed here, see T49905. */
ListBase *lbarray[MAX_LIBARRAY];
int a = set_listbasepointers(bmain, lbarray);
while (a--) {
ListBase *lb = lbarray[a];
for (ID *id = lb->first; id; id = id->next) {
id->newid = NULL;
}
}
clear_sca_new_poins(); /* BGE logic */
/* duplicate (must set newid) */
for (base = FIRSTBASE; base; base = base->next) {
@ -1758,8 +1748,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
if ((base->flag & flag) == flag) {
if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) {
/* base gets copy of object */
obn = BKE_object_copy(bmain, ob);
base->object = obn;
base->object = obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob));
if (copy_groups) {
if (ob->flag & OB_FROMGROUP) {
@ -1789,8 +1778,6 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
/* duplicate groups that consist entirely of duplicated objects */
for (group = bmain->group.first; group; group = group->id.next) {
group->id.newid = NULL;
if (copy_groups && group->gobject.first) {
bool all_duplicated = true;
@ -1802,10 +1789,11 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
}
if (all_duplicated) {
groupn = BKE_group_copy(bmain, group);
groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group));
for (go = groupn->gobject.first; go; go = go->next)
for (go = groupn->gobject.first; go; go = go->next) {
go->ob = (Object *)go->ob->id.newid;
}
}
}
}
@ -1813,8 +1801,8 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
/* group pointers in scene */
BKE_scene_groups_relink(scene);
ID_NEW(scene->camera);
if (v3d) ID_NEW(v3d->camera);
ID_NEW_REMAP(scene->camera);
if (v3d) ID_NEW_REMAP(v3d->camera);
/* object and group pointers */
for (base = FIRSTBASE; base; base = base->next) {
@ -1837,6 +1825,8 @@ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
}
single_object_users(bmain, scene, NULL, OB_DONE, copy_groups);
BKE_main_id_clear_newpoins(bmain);
}
static void new_id_matar(Main *bmain, Material **matar, const int totcol)
@ -1853,9 +1843,8 @@ static void new_id_matar(Main *bmain, Material **matar, const int totcol)
id_us_min(id);
}
else if (id->us > 1) {
matar[a] = BKE_material_copy(bmain, matar[a]);
matar[a] = ID_NEW_SET(id, BKE_material_copy(bmain, matar[a]));
id_us_min(id);
id->newid = (ID *)matar[a];
}
}
}
@ -1883,45 +1872,46 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
switch (ob->type) {
case OB_LAMP:
ob->data = la = BKE_lamp_copy(bmain, ob->data);
ob->data = la = ID_NEW_SET(ob->data, BKE_lamp_copy(bmain, ob->data));
for (a = 0; a < MAX_MTEX; a++) {
if (la->mtex[a]) {
ID_NEW(la->mtex[a]->object);
ID_NEW_REMAP(la->mtex[a]->object);
}
}
break;
case OB_CAMERA:
ob->data = BKE_camera_copy(bmain, ob->data);
ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data));
break;
case OB_MESH:
ob->data = me = BKE_mesh_copy(bmain, ob->data);
if (me->key)
BKE_animdata_copy_id_action((ID *)me->key);
/* Needed to remap texcomesh below. */
me = ob->data = ID_NEW_SET(ob->data, BKE_mesh_copy(bmain, ob->data));
if (me->key) /* We do not need to set me->key->id.newid here... */
BKE_animdata_copy_id_action((ID *)me->key, false);
break;
case OB_MBALL:
ob->data = BKE_mball_copy(bmain, ob->data);
ob->data = ID_NEW_SET(ob->data, BKE_mball_copy(bmain, ob->data));
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
ob->data = cu = BKE_curve_copy(bmain, ob->data);
ID_NEW(cu->bevobj);
ID_NEW(cu->taperobj);
if (cu->key)
BKE_animdata_copy_id_action((ID *)cu->key);
ob->data = cu = ID_NEW_SET(ob->data, BKE_curve_copy(bmain, ob->data));
ID_NEW_REMAP(cu->bevobj);
ID_NEW_REMAP(cu->taperobj);
if (cu->key) /* We do not need to set cu->key->id.newid here... */
BKE_animdata_copy_id_action((ID *)cu->key, false);
break;
case OB_LATTICE:
ob->data = lat = BKE_lattice_copy(bmain, ob->data);
if (lat->key)
BKE_animdata_copy_id_action((ID *)lat->key);
ob->data = lat = ID_NEW_SET(ob->data, BKE_lattice_copy(bmain, ob->data));
if (lat->key) /* We do not need to set lat->key->id.newid here... */
BKE_animdata_copy_id_action((ID *)lat->key, false);
break;
case OB_ARMATURE:
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
ob->data = BKE_armature_copy(bmain, ob->data);
ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data));
BKE_pose_rebuild(ob, ob->data);
break;
case OB_SPEAKER:
ob->data = BKE_speaker_copy(bmain, ob->data);
ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data));
break;
default:
if (G.debug & G_DEBUG)
@ -1934,17 +1924,16 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
* AnimData structure, which is not what we want.
* (sergey)
*/
BKE_animdata_copy_id_action((ID *)ob->data);
BKE_animdata_copy_id_action((ID *)ob->data, false);
id_us_min(id);
id->newid = ob->data;
}
}
}
me = bmain->mesh.first;
while (me) {
ID_NEW(me->texcomesh);
ID_NEW_REMAP(me->texcomesh);
me = me->id.next;
}
}
@ -1958,7 +1947,7 @@ static void single_object_action_users(Scene *scene, const int flag)
ob = base->object;
if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
BKE_animdata_copy_id_action(&ob->id);
BKE_animdata_copy_id_action(&ob->id, false);
}
}
}
@ -1977,11 +1966,11 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
if (ma) {
/* do not test for LIB_TAG_NEW: this functions guaranteed delivers single_users! */
/* do not test for LIB_TAG_NEW or use newid: this functions guaranteed delivers single_users! */
if (ma->id.us > 1) {
man = BKE_material_copy(bmain, ma);
BKE_animdata_copy_id_action(&man->id);
BKE_animdata_copy_id_action(&man->id, false);
man->id.us = 0;
assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF);
@ -1992,7 +1981,7 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo
if (tex->id.us > 1) {
id_us_min(&tex->id);
tex = BKE_texture_copy(bmain, tex);
BKE_animdata_copy_id_action(&tex->id);
BKE_animdata_copy_id_action(&tex->id, false);
man->mtex[b]->tex = tex;
}
}
@ -2018,8 +2007,8 @@ static void do_single_tex_user(Main *bmain, Tex **from)
id_us_min(&tex->id);
}
else if (tex->id.us > 1) {
texn = BKE_texture_copy(bmain, tex);
BKE_animdata_copy_id_action(&texn->id);
texn = ID_NEW_SET(tex, BKE_texture_copy(bmain, tex));
BKE_animdata_copy_id_action(&texn->id, false);
tex->id.newid = (ID *)texn;
id_us_min(&tex->id);
*from = texn;
@ -2096,7 +2085,7 @@ static void single_mat_users_expand(Main *bmain)
if (ma->id.tag & LIB_TAG_NEW)
for (a = 0; a < MAX_MTEX; a++)
if (ma->mtex[a])
ID_NEW(ma->mtex[a]->object);
ID_NEW_REMAP(ma->mtex[a]->object);
}
/* used for copying scenes */
@ -2247,7 +2236,6 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
tag_localizable_objects(C, mode);
BKE_main_id_clear_newpoins(bmain);
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
@ -2264,7 +2252,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
if (ob->id.lib == NULL) {
ID_NEW(ob->parent);
ID_NEW_REMAP(ob->parent);
}
}
CTX_DATA_END;
@ -2335,6 +2323,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
}
BKE_main_id_clear_newpoins(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
@ -2381,8 +2370,6 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
const bool copy_groups = false;
bool update_deps = false;
BKE_main_id_clear_newpoins(bmain);
if (RNA_boolean_get(op->ptr, "object")) {
single_object_users(bmain, scene, v3d, flag, copy_groups);
@ -2406,11 +2393,6 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
single_object_action_users(scene, flag);
}
/* TODO(sergey): This should not be needed, however some tool still could rely
* on the fact, that id->newid is kept NULL by default.
* Need to make sure all the guys are learing newid before they're
* using it, not after.
*/
BKE_main_id_clear_newpoins(bmain);
WM_event_add_notifier(C, NC_WINDOW, NULL);

View File

@ -442,6 +442,9 @@ static void id_local_cb(
if (id_make_local(bmain, tselem->id, false, false) == false) {
id_clear_lib_data(bmain, tselem->id);
}
else {
BKE_main_id_clear_newpoins(bmain);
}
}
}

View File

@ -1645,11 +1645,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
outliner_free_tree(&soops->tree);
outliner_storage_cleanup(soops);
/* clear ob id.new flags */
for (Object *ob = mainvar->object.first; ob; ob = ob->id.next) {
ob->id.newid = NULL;
}
/* options */
if (soops->outlinevis == SO_LIBRARIES) {
Library *lib;
@ -1835,6 +1830,8 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
outliner_sort(&soops->tree);
}
outliner_filter_tree(soops, &soops->tree);
BKE_main_id_clear_newpoins(mainvar);
}

View File

@ -290,9 +290,9 @@ typedef enum ID_Type {
#endif
#define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (*((const short *)(a))))
#define ID_NEW(a) if ( (a) && (a)->id.newid ) (a) = (void *)(a)->id.newid
#define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
#define ID_NEW_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
#define ID_NEW_SET(_id, _idn) \
(((ID *)(_id))->newid = (ID *)(_idn), ((ID *)(_id))->newid->tag |= LIB_TAG_NEW, (void *)((ID *)(_id))->newid)
#define ID_NEW_REMAP(a) if ((a) && (a)->id.newid) (a) = (void *)(a)->id.newid
/* id->flag (persitent). */
enum {

View File

@ -358,7 +358,9 @@ static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_prox
id_make_local(bmain, self, false, false);
}
return self->newid ? self->newid : self;
ID *ret_id = self->newid ? self->newid : self;
BKE_id_clear_newpoin(self);
return ret_id;
}