From 441a440cbbb700511d6d1ec01e2f149355adcc02 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Jun 2016 16:07:13 +1000 Subject: readfile: optimization for undo Was using O(n^2) lookup on ID's with undo. This caused undo to hang with 1000's of data-blocks (especially with heavy scenes & outliner-space, which doesn't even need to be visible to cause a slow-down). Internally this uses a ghash per id-type, which is lazy-initialized. Each key uses the name and library since there may be name collisions between libraries. Developer Notes: - Adds small `BKE_main_idmap_*` API. - Needed to change linking order for this to build. --- build_files/cmake/macros.cmake | 2 +- source/blender/blenkernel/BKE_library_idmap.h | 50 +++++++ source/blender/blenkernel/CMakeLists.txt | 2 + source/blender/blenkernel/intern/library_idmap.c | 174 +++++++++++++++++++++++ source/blender/blenloader/intern/readfile.c | 156 ++++++++++++-------- 5 files changed, 323 insertions(+), 61 deletions(-) create mode 100644 source/blender/blenkernel/BKE_library_idmap.h create mode 100644 source/blender/blenkernel/intern/library_idmap.c diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index d34b55e14e0..3aa938b63d7 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -552,11 +552,11 @@ function(SETUP_BLENDER_SORTED_LIBS) bf_modifiers bf_bmesh bf_gpu + bf_blenloader bf_blenkernel bf_physics bf_nodes bf_rna - bf_blenloader bf_imbuf bf_blenlib bf_depsgraph diff --git a/source/blender/blenkernel/BKE_library_idmap.h b/source/blender/blenkernel/BKE_library_idmap.h new file mode 100644 index 00000000000..971586ea8b7 --- /dev/null +++ b/source/blender/blenkernel/BKE_library_idmap.h @@ -0,0 +1,50 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_LIBRARY_IDMAP_H__ +#define __BKE_LIBRARY_IDMAP_H__ + +/** \file BKE_library_idmap.h + * \ingroup bke + */ + +#include "BLI_compiler_attrs.h" + +struct ID; +struct Main; +struct IDNameLib_Map; + +struct IDNameLib_Map *BKE_main_idmap_create( + struct Main *bmain) + ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BKE_main_idmap_destroy( + struct IDNameLib_Map *id_typemap) + ATTR_NONNULL(); +struct Main *BKE_main_idmap_main_get( + struct IDNameLib_Map *id_typemap) + ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct ID *BKE_main_idmap_lookup( + struct IDNameLib_Map *id_typemap, + short id_type, const char *name, const struct Library *lib) + ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3); +struct ID *BKE_main_idmap_lookup_id( + struct IDNameLib_Map *id_typemap, const struct ID *id) + ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); + +#endif /* __BKE_LIBRARY_IDMAP_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index afab0ccc5a5..86264224851 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -121,6 +121,7 @@ set(SRC intern/lamp.c intern/lattice.c intern/library.c + intern/library_idmap.c intern/library_query.c intern/linestyle.c intern/mask.c @@ -244,6 +245,7 @@ set(SRC BKE_lamp.h BKE_lattice.h BKE_library.h + BKE_library_idmap.h BKE_library_query.h BKE_linestyle.h BKE_main.h diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c new file mode 100644 index 00000000000..fd78d9b23ce --- /dev/null +++ b/source/blender/blenkernel/intern/library_idmap.c @@ -0,0 +1,174 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_listbase.h" + +#include "DNA_ID.h" + +#include "BKE_idcode.h" +#include "BKE_library.h" +#include "BKE_library_idmap.h" /* own include */ + +/** \file blender/blenkernel/intern/library_map.c + * \ingroup bke + * + * Utility functions for faster ID lookups. + */ + +/** \name BKE_main_idmap API + * + * Cache ID (name, library lookups). + * This doesn't account for adding/removing data-blocks, + * and should only be used when performing many lookups. + * + * \note GHash's are initialized on demand, + * since its likely some types will never have lookups run on them, + * so its a waste to create and never use. + * \{ */ + +struct IDNameLib_Key { + /** ``ID.name + 2``: without the ID type prefix, since each id type gets it's own 'map' */ + const char *name; + /** ``ID.lib``: */ + const Library *lib; +}; + +struct IDNameLib_TypeMap { + GHash *map; + short id_type; + /* only for storage of keys in the ghash, avoid many single allocs */ + struct IDNameLib_Key *keys; +}; + +/** + * Opaque structure, external API users only see this. + */ +struct IDNameLib_Map { + struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY]; + struct Main *bmain; +}; + +static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id_map, short id_type) +{ + for (int i = 0; i < MAX_LIBARRAY; i++) { + if (id_map->type_maps[i].id_type == id_type) { + return &id_map->type_maps[i]; + } + } + return NULL; +} + +struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain) +{ + struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__); + + int index = 0; + while (index < MAX_LIBARRAY) { + id_map->type_maps[index].map = NULL; + id_map->type_maps[index].id_type = BKE_idcode_iter_step(&index); + } + BLI_assert(index == MAX_LIBARRAY); + + id_map->bmain = bmain; + + return id_map; +} + +struct Main *BKE_main_idmap_main_get(struct IDNameLib_Map *id_map) +{ + return id_map->bmain; +} + +static unsigned int idkey_hash(const void *ptr) +{ + const struct IDNameLib_Key *idkey = ptr; + unsigned int key = BLI_ghashutil_strhash(idkey->name); + if (idkey->lib) { + key ^= BLI_ghashutil_ptrhash(idkey->lib); + } + return key; +} + +static bool idkey_cmp(const void *a, const void *b) +{ + const struct IDNameLib_Key *idkey_a = a; + const struct IDNameLib_Key *idkey_b = b; + return strcmp(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib); +} + +ID *BKE_main_idmap_lookup(struct IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib) +{ + struct IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type); + + if (UNLIKELY(type_map == NULL)) { + return NULL; + } + + /* lazy init */ + if (type_map->map == NULL) { + ListBase *lb = which_libbase(id_map->bmain, id_type); + const int lb_len = BLI_listbase_count(lb); + if (lb_len == 0) { + return NULL; + } + type_map->map = BLI_ghash_new_ex(idkey_hash, idkey_cmp, __func__, lb_len); + type_map->keys = MEM_mallocN(sizeof(struct IDNameLib_Key) * lb_len, __func__); + + GHash *map = type_map->map; + struct IDNameLib_Key *key = type_map->keys; + + for (ID *id = lb->first; id; id = id->next, key++) { + key->name = id->name + 2; + key->lib = id->lib; + BLI_ghash_insert(map, key, id); + } + } + + const struct IDNameLib_Key key_lookup = {name, lib}; + return BLI_ghash_lookup(type_map->map, &key_lookup); +} + +ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const ID *id) +{ + return BKE_main_idmap_lookup(id_map, GS(id->name), id->name + 2, id->lib); +} + +void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map) +{ + struct IDNameLib_TypeMap *type_map = id_map->type_maps; + for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) { + if (type_map->map) { + BLI_ghash_free(type_map->map, NULL, NULL); + type_map->map = NULL; + MEM_freeN(type_map->keys); + } + } + + MEM_freeN(id_map); +} + +/** \} */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index fd105f6aafa..621088c5a3c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -124,6 +124,7 @@ #include "BKE_global.h" // for G #include "BKE_group.h" #include "BKE_library.h" // for which_libbase +#include "BKE_library_idmap.h" #include "BKE_library_query.h" #include "BKE_idcode.h" #include "BKE_material.h" @@ -211,6 +212,9 @@ /* use GHash for BHead name-based lookups (speeds up linking) */ #define USE_GHASH_BHEAD +/* Use GHash for restoring pointers by name */ +#define USE_GHASH_RESTORE_POINTER + /***/ typedef struct OldNew { @@ -6389,68 +6393,96 @@ typedef enum ePointerUserMode { USER_REAL = 1, /* ensure at least one real user (fake user ignored) */ } ePointerUserMode; -static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user) +static void restore_pointer_user(ID *id, ID *newid, ePointerUserMode user) { - if (STREQ(newid->name + 2, id->name + 2)) { - if (newid->lib == id->lib) { - if (user == USER_REAL) { - id_us_ensure_real(newid); + BLI_assert(STREQ(newid->name + 2, id->name + 2)); + BLI_assert(newid->lib == id->lib); + UNUSED_VARS_NDEBUG(id); + + if (user == USER_REAL) { + id_us_ensure_real(newid); + } +} + +#ifndef USE_GHASH_RESTORE_POINTER +/** + * A version of #restore_pointer_by_name that performs a full search (slow!). + * Use only for limited lookups, when the overhead of + * creating a #IDNameLib_Map for a single lookup isn't worthwhile. + */ +static void *restore_pointer_by_name_main(Main *mainp, ID *id, ePointerUserMode user) +{ + if (id) { + ListBase *lb = which_libbase(mainp, GS(id->name)); + if (lb) { /* there's still risk of checking corrupt mem (freed Ids in oops) */ + ID *idn = lb->first; + for (; idn; idn = idn->next) { + if (STREQ(idn->name + 2, id->name + 2)) { + if (idn->lib == id->lib) { + restore_pointer_user(id, idn, user); + break; + } + } } - return true; + return idn; } } - return false; + return NULL; } +#endif /** * Only for undo files, or to restore a screen after reading without UI... * - * user + * \param user: * - USER_IGNORE: no usercount change * - USER_REAL: ensure a real user (even if a fake one is set) + * \param id_map: lookup table, use when performing many lookups. + * this could be made an optional agument (falling back to a full lookup), + * however at the moment it's always available. */ -static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user) +static void *restore_pointer_by_name(struct IDNameLib_Map *id_map, ID *id, ePointerUserMode user) { +#ifdef USE_GHASH_RESTORE_POINTER if (id) { - ListBase *lb = which_libbase(mainp, GS(id->name)); - if (lb) { // there's still risk of checking corrupt mem (freed Ids in oops) - ID *idn = lb->first; - - for (; idn; idn = idn->next) { - if (restore_pointer(id, idn, user)) - break; - } - - return idn; + /* use fast lookup when available */ + ID *idn = BKE_main_idmap_lookup_id(id_map, id); + if (idn) { + restore_pointer_user(id, idn, user); } + return idn; } return NULL; +#else + Main *mainp = BKE_main_idmap_main_get(id_map); + return restore_pointer_by_name_main(mainp, id, user); +#endif } -static void lib_link_seq_clipboard_pt_restore(ID *id, Main *newmain) +static void lib_link_seq_clipboard_pt_restore(ID *id, struct IDNameLib_Map *id_map) { if (id) { /* clipboard must ensure this */ BLI_assert(id->newid != NULL); - id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_REAL); + id->newid = restore_pointer_by_name(id_map, id->newid, USER_REAL); } } static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt) { - Main *newmain = (Main *)arg_pt; + struct IDNameLib_Map *id_map = arg_pt; - lib_link_seq_clipboard_pt_restore((ID *)seq->scene, newmain); - lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, newmain); - lib_link_seq_clipboard_pt_restore((ID *)seq->clip, newmain); - lib_link_seq_clipboard_pt_restore((ID *)seq->mask, newmain); - lib_link_seq_clipboard_pt_restore((ID *)seq->sound, newmain); + lib_link_seq_clipboard_pt_restore((ID *)seq->scene, id_map); + lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, id_map); + lib_link_seq_clipboard_pt_restore((ID *)seq->clip, id_map); + lib_link_seq_clipboard_pt_restore((ID *)seq->mask, id_map); + lib_link_seq_clipboard_pt_restore((ID *)seq->sound, id_map); return 1; } -static void lib_link_clipboard_restore(Main *newmain) +static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map) { /* update IDs stored in sequencer clipboard */ - BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, newmain); + BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map); } /* called from kernel/blender.c */ @@ -6462,11 +6494,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc wmWindowManager *wm; bScreen *sc; ScrArea *sa; - + + struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain); + /* first windowmanager */ for (wm = newmain->wm.first; wm; wm = wm->id.next) { for (win= wm->windows.first; win; win= win->next) { - win->screen = restore_pointer_by_name(newmain, (ID *)win->screen, USER_REAL); + win->screen = restore_pointer_by_name(id_map, (ID *)win->screen, USER_REAL); if (win->screen == NULL) win->screen = curscreen; @@ -6479,7 +6513,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc for (sc = newmain->screen.first; sc; sc = sc->id.next) { Scene *oldscene = sc->scene; - sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, USER_REAL); + sc->scene= restore_pointer_by_name(id_map, (ID *)sc->scene, USER_REAL); if (sc->scene == NULL) sc->scene = curscene; @@ -6498,16 +6532,16 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc if (v3d->scenelock) v3d->camera = NULL; /* always get from scene */ else - v3d->camera = restore_pointer_by_name(newmain, (ID *)v3d->camera, USER_REAL); + v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL); if (v3d->camera == NULL) v3d->camera = sc->scene->camera; - v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_REAL); + v3d->ob_centre = restore_pointer_by_name(id_map, (ID *)v3d->ob_centre, USER_REAL); for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) { - if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) { + if ((bgpic->ima = restore_pointer_by_name(id_map, (ID *)bgpic->ima, USER_IGNORE))) { id_us_plus((ID *)bgpic->ima); } - if ((bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_IGNORE))) { + if ((bgpic->clip = restore_pointer_by_name(id_map, (ID *)bgpic->clip, USER_IGNORE))) { id_us_plus((ID *)bgpic->clip); } } @@ -6551,10 +6585,10 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc bDopeSheet *ads = sipo->ads; if (ads) { - ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL); + ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL); if (ads->filter_grp) - ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE); + ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE); } /* force recalc of list of channels (i.e. includes calculating F-Curve colors) @@ -6564,7 +6598,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc } else if (sl->spacetype == SPACE_BUTS) { SpaceButs *sbuts = (SpaceButs *)sl; - sbuts->pinid = restore_pointer_by_name(newmain, sbuts->pinid, USER_IGNORE); + sbuts->pinid = restore_pointer_by_name(id_map, sbuts->pinid, USER_IGNORE); if (sbuts->pinid == NULL) { sbuts->flag &= ~SB_PIN_CONTEXT; } @@ -6581,11 +6615,11 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_ACTION) { SpaceAction *saction = (SpaceAction *)sl; - saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, USER_REAL); - saction->ads.source = restore_pointer_by_name(newmain, (ID *)saction->ads.source, USER_REAL); + saction->action = restore_pointer_by_name(id_map, (ID *)saction->action, USER_REAL); + saction->ads.source = restore_pointer_by_name(id_map, (ID *)saction->ads.source, USER_REAL); if (saction->ads.filter_grp) - saction->ads.filter_grp = restore_pointer_by_name(newmain, (ID *)saction->ads.filter_grp, USER_IGNORE); + saction->ads.filter_grp = restore_pointer_by_name(id_map, (ID *)saction->ads.filter_grp, USER_IGNORE); /* force recalc of list of channels, potentially updating the active action @@ -6596,7 +6630,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)sl; - sima->image = restore_pointer_by_name(newmain, (ID *)sima->image, USER_REAL); + sima->image = restore_pointer_by_name(id_map, (ID *)sima->image, USER_REAL); /* this will be freed, not worth attempting to find same scene, * since it gets initialized later */ @@ -6611,8 +6645,8 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data * so assume that here we're doing for undo only... */ - sima->gpd = restore_pointer_by_name(newmain, (ID *)sima->gpd, USER_REAL); - sima->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sima->mask_info.mask, USER_REAL); + sima->gpd = restore_pointer_by_name(id_map, (ID *)sima->gpd, USER_REAL); + sima->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sima->mask_info.mask, USER_REAL); } else if (sl->spacetype == SPACE_SEQ) { SpaceSeq *sseq = (SpaceSeq *)sl; @@ -6620,29 +6654,29 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data * so assume that here we're doing for undo only... */ - sseq->gpd = restore_pointer_by_name(newmain, (ID *)sseq->gpd, USER_REAL); + sseq->gpd = restore_pointer_by_name(id_map, (ID *)sseq->gpd, USER_REAL); } else if (sl->spacetype == SPACE_NLA) { SpaceNla *snla = (SpaceNla *)sl; bDopeSheet *ads = snla->ads; if (ads) { - ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL); + ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL); if (ads->filter_grp) - ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE); + ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE); } } else if (sl->spacetype == SPACE_TEXT) { SpaceText *st = (SpaceText *)sl; - st->text = restore_pointer_by_name(newmain, (ID *)st->text, USER_REAL); + st->text = restore_pointer_by_name(id_map, (ID *)st->text, USER_REAL); if (st->text == NULL) st->text = newmain->text.first; } else if (sl->spacetype == SPACE_SCRIPT) { SpaceScript *scpt = (SpaceScript *)sl; - scpt->script = restore_pointer_by_name(newmain, (ID *)scpt->script, USER_REAL); + scpt->script = restore_pointer_by_name(id_map, (ID *)scpt->script, USER_REAL); /*sc->script = NULL; - 2.45 set to null, better re-run the script */ if (scpt->script) { @@ -6652,7 +6686,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_OUTLINER) { SpaceOops *so= (SpaceOops *)sl; - so->search_tse.id = restore_pointer_by_name(newmain, so->search_tse.id, USER_IGNORE); + so->search_tse.id = restore_pointer_by_name(id_map, so->search_tse.id, USER_IGNORE); if (so->treestore) { TreeStoreElem *tselem; @@ -6662,7 +6696,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc while ((tselem = BLI_mempool_iterstep(&iter))) { /* Do not try to restore pointers to drivers/sequence/etc., can crash in undo case! */ if (TSE_IS_REAL_ID(tselem)) { - tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE); + tselem->id = restore_pointer_by_name(id_map, tselem->id, USER_IGNORE); } else { tselem->id = NULL; @@ -6680,14 +6714,14 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc bNodeTree *ntree; /* node tree can be stored locally in id too, link this first */ - snode->id = restore_pointer_by_name(newmain, snode->id, USER_REAL); - snode->from = restore_pointer_by_name(newmain, snode->from, USER_IGNORE); + snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL); + snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE); ntree = nodetree_from_id(snode->id); if (ntree) snode->nodetree = ntree; else - snode->nodetree = restore_pointer_by_name(newmain, (ID*)snode->nodetree, USER_REAL); + snode->nodetree = restore_pointer_by_name(id_map, (ID*)snode->nodetree, USER_REAL); for (path = snode->treepath.first; path; path = path->next) { if (path == snode->treepath.first) { @@ -6695,7 +6729,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc path->nodetree = snode->nodetree; } else - path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, USER_REAL); + path->nodetree= restore_pointer_by_name(id_map, (ID*)path->nodetree, USER_REAL); if (!path->nodetree) break; @@ -6721,22 +6755,24 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_CLIP) { SpaceClip *sclip = (SpaceClip *)sl; - sclip->clip = restore_pointer_by_name(newmain, (ID *)sclip->clip, USER_REAL); - sclip->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sclip->mask_info.mask, USER_REAL); + sclip->clip = restore_pointer_by_name(id_map, (ID *)sclip->clip, USER_REAL); + sclip->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sclip->mask_info.mask, USER_REAL); sclip->scopes.ok = 0; } else if (sl->spacetype == SPACE_LOGIC) { SpaceLogic *slogic = (SpaceLogic *)sl; - slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_REAL); + slogic->gpd = restore_pointer_by_name(id_map, (ID *)slogic->gpd, USER_REAL); } } } } /* update IDs stored in all possible clipboards */ - lib_link_clipboard_restore(newmain); + lib_link_clipboard_restore(id_map); + + BKE_main_idmap_destroy(id_map); } static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) -- cgit v1.2.3