Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenloader/intern/readfile.c
| Show First 20 Lines • Show All 458 Lines • ▼ Show 20 Lines | static void add_main_to_main(Main *mainvar, Main *from) | ||||
| } | } | ||||
| } | } | ||||
| void blo_join_main(ListBase *mainlist) | void blo_join_main(ListBase *mainlist) | ||||
| { | { | ||||
| Main *tojoin, *mainl; | Main *tojoin, *mainl; | ||||
| mainl = mainlist->first; | mainl = mainlist->first; | ||||
| if (mainl->id_map != NULL) { | |||||
| /* Cannot keep this since we add some IDs from joined mains. */ | |||||
| BKE_main_idmap_destroy(mainl->id_map); | |||||
| mainl->id_map = NULL; | |||||
| } | |||||
| while ((tojoin = mainl->next)) { | while ((tojoin = mainl->next)) { | ||||
| add_main_to_main(mainl, tojoin); | add_main_to_main(mainl, tojoin); | ||||
| BLI_remlink(mainlist, tojoin); | BLI_remlink(mainlist, tojoin); | ||||
| BKE_main_free(tojoin); | BKE_main_free(tojoin); | ||||
| } | } | ||||
| } | } | ||||
| static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint lib_main_array_len) | static void split_libdata(ListBase *lb_src, Main **lib_main_array, const uint lib_main_array_len) | ||||
| { | { | ||||
| for (ID *id = lb_src->first, *idnext; id; id = idnext) { | for (ID *id = lb_src->first, *idnext; id; id = idnext) { | ||||
| idnext = id->next; | idnext = id->next; | ||||
brecht: I would destroy this before joining, not after.
Not that it makes a big difference now, but… | |||||
| if (id->lib) { | if (id->lib) { | ||||
| if (((uint)id->lib->temp_index < lib_main_array_len) && | if (((uint)id->lib->temp_index < lib_main_array_len) && | ||||
| /* this check should never fail, just in case 'id->lib' is a dangling pointer. */ | /* this check should never fail, just in case 'id->lib' is a dangling pointer. */ | ||||
| (lib_main_array[id->lib->temp_index]->curlib == id->lib)) { | (lib_main_array[id->lib->temp_index]->curlib == id->lib)) { | ||||
| Main *mainvar = lib_main_array[id->lib->temp_index]; | Main *mainvar = lib_main_array[id->lib->temp_index]; | ||||
| ListBase *lb_dst = which_libbase(mainvar, GS(id->name)); | ListBase *lb_dst = which_libbase(mainvar, GS(id->name)); | ||||
| BLI_remlink(lb_src, id); | BLI_remlink(lb_src, id); | ||||
| Show All 11 Lines | |||||
| { | { | ||||
| mainlist->first = mainlist->last = main; | mainlist->first = mainlist->last = main; | ||||
| main->next = NULL; | main->next = NULL; | ||||
| if (BLI_listbase_is_empty(&main->libraries)) { | if (BLI_listbase_is_empty(&main->libraries)) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (main->id_map != NULL) { | |||||
| /* Cannot keep this since we remove some IDs from given main. */ | |||||
| BKE_main_idmap_destroy(main->id_map); | |||||
| main->id_map = NULL; | |||||
| } | |||||
| /* (Library.temp_index -> Main), lookup table */ | /* (Library.temp_index -> Main), lookup table */ | ||||
| const uint lib_main_array_len = BLI_listbase_count(&main->libraries); | const uint lib_main_array_len = BLI_listbase_count(&main->libraries); | ||||
| Main **lib_main_array = MEM_malloc_arrayN(lib_main_array_len, sizeof(*lib_main_array), __func__); | Main **lib_main_array = MEM_malloc_arrayN(lib_main_array_len, sizeof(*lib_main_array), __func__); | ||||
| int i = 0; | int i = 0; | ||||
| for (Library *lib = main->libraries.first; lib; lib = lib->id.next, i++) { | for (Library *lib = main->libraries.first; lib; lib = lib->id.next, i++) { | ||||
| Main *libmain = BKE_main_new(); | Main *libmain = BKE_main_new(); | ||||
| libmain->curlib = lib; | libmain->curlib = lib; | ||||
| ▲ Show 20 Lines • Show All 2,691 Lines • ▼ Show 20 Lines | static ID *create_placeholder(Main *mainvar, const short idcode, const char *idname, const int tag) | ||||
| ph_id->lib = mainvar->curlib; | ph_id->lib = mainvar->curlib; | ||||
| ph_id->tag = tag | LIB_TAG_MISSING; | ph_id->tag = tag | LIB_TAG_MISSING; | ||||
| ph_id->us = ID_FAKE_USERS(ph_id); | ph_id->us = ID_FAKE_USERS(ph_id); | ||||
| ph_id->icon_id = 0; | ph_id->icon_id = 0; | ||||
| BLI_addtail(lb, ph_id); | BLI_addtail(lb, ph_id); | ||||
| id_sort_by_name(lb, ph_id, NULL); | id_sort_by_name(lb, ph_id, NULL); | ||||
| if (mainvar->id_map != NULL) { | |||||
| BKE_main_idmap_insert_id(mainvar->id_map, ph_id); | |||||
| } | |||||
| if ((tag & LIB_TAG_TEMP_MAIN) == 0) { | if ((tag & LIB_TAG_TEMP_MAIN) == 0) { | ||||
| BKE_lib_libblock_session_uuid_ensure(ph_id); | BKE_lib_libblock_session_uuid_ensure(ph_id); | ||||
| } | } | ||||
| return ph_id; | return ph_id; | ||||
| } | } | ||||
| static void placeholders_ensure_valid(Main *bmain) | static void placeholders_ensure_valid(Main *bmain) | ||||
| ▲ Show 20 Lines • Show All 442 Lines • ▼ Show 20 Lines | static BHead *read_libblock(FileData *fd, | ||||
| * When datablocks are changed but still exist, we restore them at the old | * When datablocks are changed but still exist, we restore them at the old | ||||
| * address and inherit recalc flags for the dependency graph. */ | * address and inherit recalc flags for the dependency graph. */ | ||||
| ID *id_old = NULL; | ID *id_old = NULL; | ||||
| if (fd->memfile != NULL) { | if (fd->memfile != NULL) { | ||||
| if (read_libblock_undo_restore(fd, main, bhead, tag, &id_old)) { | if (read_libblock_undo_restore(fd, main, bhead, tag, &id_old)) { | ||||
| if (r_id) { | if (r_id) { | ||||
| *r_id = id_old; | *r_id = id_old; | ||||
| } | } | ||||
| if (main->id_map != NULL) { | |||||
| BKE_main_idmap_insert_id(main->id_map, id_old); | |||||
| } | |||||
| return blo_bhead_next(fd, bhead); | return blo_bhead_next(fd, bhead); | ||||
| } | } | ||||
| } | } | ||||
| /* Read libblock struct. */ | /* Read libblock struct. */ | ||||
| ID *id = read_struct(fd, bhead, "lib block"); | ID *id = read_struct(fd, bhead, "lib block"); | ||||
| if (id == NULL) { | if (id == NULL) { | ||||
| if (r_id) { | if (r_id) { | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | if (placeholder_set_indirect_extern) { | ||||
| id_tag |= LIB_TAG_INDIRECT; | id_tag |= LIB_TAG_INDIRECT; | ||||
| } | } | ||||
| else { | else { | ||||
| id_tag |= LIB_TAG_EXTERN; | id_tag |= LIB_TAG_EXTERN; | ||||
| } | } | ||||
| } | } | ||||
| direct_link_id(fd, main, id_tag, id, id_old); | direct_link_id(fd, main, id_tag, id, id_old); | ||||
| if (main->id_map != NULL) { | |||||
| BKE_main_idmap_insert_id(main->id_map, id); | |||||
| } | |||||
| return blo_bhead_next(fd, bhead); | return blo_bhead_next(fd, bhead); | ||||
| } | } | ||||
| /* Read datablock contents. | /* Read datablock contents. | ||||
| * Use convenient malloc name for debugging and better memory link prints. */ | * Use convenient malloc name for debugging and better memory link prints. */ | ||||
| const char *allocname = dataname(idcode); | const char *allocname = dataname(idcode); | ||||
| bhead = read_data_into_datamap(fd, bhead, allocname); | bhead = read_data_into_datamap(fd, bhead, allocname); | ||||
| const bool success = direct_link_id(fd, main, id_tag, id, id_old); | const bool success = direct_link_id(fd, main, id_tag, id, id_old); | ||||
| oldnewmap_clear(fd->datamap); | oldnewmap_clear(fd->datamap); | ||||
| if (!success) { | if (!success) { | ||||
| /* XXX This is probably working OK currently given the very limited scope of that flag. | /* XXX This is probably working OK currently given the very limited scope of that flag. | ||||
| * However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has | * However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has | ||||
| * been added to the fd->libmap mapping, which in theory could lead to nice crashes... | * been added to the fd->libmap mapping, which in theory could lead to nice crashes... | ||||
| * This should be properly solved at some point. */ | * This should be properly solved at some point. */ | ||||
| BKE_id_free(main, id); | BKE_id_free(main, id); | ||||
| if (r_id != NULL) { | if (r_id != NULL) { | ||||
| *r_id = NULL; | *r_id = NULL; | ||||
| } | } | ||||
| } | } | ||||
| else if (id_old) { | else if (id_old) { | ||||
| /* For undo, store contents read into id at id_old. */ | /* For undo, store contents read into id at id_old. */ | ||||
| read_libblock_undo_restore_at_old_address(fd, main, id, id_old); | read_libblock_undo_restore_at_old_address(fd, main, id, id_old); | ||||
| if (main->id_map != NULL) { | |||||
| BKE_main_idmap_insert_id(main->id_map, id_old); | |||||
| } | |||||
| } | |||||
| else if (main->id_map != NULL) { | |||||
| BKE_main_idmap_insert_id(main->id_map, id); | |||||
| } | } | ||||
| return bhead; | return bhead; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| ▲ Show 20 Lines • Show All 535 Lines • ▼ Show 20 Lines | if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) { | ||||
| /* Make all relative paths, relative to the open blend file. */ | /* Make all relative paths, relative to the open blend file. */ | ||||
| fix_relpaths_library(fd->relabase, bfd->main); | fix_relpaths_library(fd->relabase, bfd->main); | ||||
| link_global(fd, bfd); /* as last */ | link_global(fd, bfd); /* as last */ | ||||
| } | } | ||||
| fd->mainlist = NULL; /* Safety, this is local variable, shall not be used afterward. */ | fd->mainlist = NULL; /* Safety, this is local variable, shall not be used afterward. */ | ||||
| BLI_assert(bfd->main->id_map == NULL); | |||||
| return bfd; | return bfd; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Library Linking | /** \name Library Linking | ||||
| * | * | ||||
| ▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | #ifdef USE_GHASH_BHEAD | ||||
| return BLI_ghash_lookup(fd->bhead_idname_hash, idname); | return BLI_ghash_lookup(fd->bhead_idname_hash, idname); | ||||
| #else | #else | ||||
| return find_bhead_from_code_name(fd, GS(idname), idname + 2); | return find_bhead_from_code_name(fd, GS(idname), idname + 2); | ||||
| #endif | #endif | ||||
| } | } | ||||
| static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead) | static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead) | ||||
| { | { | ||||
| if (mainvar->id_map == NULL) { | |||||
| mainvar->id_map = BKE_main_idmap_create(mainvar, false, NULL, MAIN_IDMAP_TYPE_NAME); | |||||
| } | |||||
| BLI_assert(BKE_main_idmap_main_get(mainvar->id_map) == mainvar); | |||||
| const char *idname = blo_bhead_id_name(fd, bhead); | const char *idname = blo_bhead_id_name(fd, bhead); | ||||
| /* which_libbase can be NULL, intentionally not using idname+2 */ | |||||
| return BLI_findstring(which_libbase(mainvar, GS(idname)), idname, offsetof(ID, name)); | ID *id = BKE_main_idmap_lookup_name(mainvar->id_map, GS(idname), idname + 2, mainvar->curlib); | ||||
| BLI_assert(id == BLI_findstring(which_libbase(mainvar, GS(idname)), idname, offsetof(ID, name))); | |||||
| return id; | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Library Linking (expand pointers) | /** \name Library Linking (expand pointers) | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 734 Lines • ▼ Show 20 Lines | static void library_link_end(Main *mainl, | ||||
| const int flag, | const int flag, | ||||
| Scene *scene, | Scene *scene, | ||||
| ViewLayer *view_layer, | ViewLayer *view_layer, | ||||
| const View3D *v3d) | const View3D *v3d) | ||||
| { | { | ||||
| Main *mainvar; | Main *mainvar; | ||||
| Library *curlib; | Library *curlib; | ||||
| if (mainl->id_map == NULL) { | |||||
| mainl->id_map = BKE_main_idmap_create(mainl, false, NULL, MAIN_IDMAP_TYPE_NAME); | |||||
| } | |||||
| /* expander now is callback function */ | /* expander now is callback function */ | ||||
| BLO_main_expander(expand_doit_library); | BLO_main_expander(expand_doit_library); | ||||
| /* make main consistent */ | /* make main consistent */ | ||||
| BLO_expand_main(*fd, mainl); | BLO_expand_main(*fd, mainl); | ||||
| /* do this when expand found other libs */ | /* do this when expand found other libs */ | ||||
| read_libraries(*fd, (*fd)->mainlist); | read_libraries(*fd, (*fd)->mainlist); | ||||
| ▲ Show 20 Lines • Show All 189 Lines • ▼ Show 20 Lines | static void read_library_linked_ids(FileData *basefd, | ||||
| while (a--) { | while (a--) { | ||||
| ID *id = lbarray[a]->first; | ID *id = lbarray[a]->first; | ||||
| ListBase pending_free_ids = {NULL}; | ListBase pending_free_ids = {NULL}; | ||||
| while (id) { | while (id) { | ||||
| ID *id_next = id->next; | ID *id_next = id->next; | ||||
| if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) { | if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) { | ||||
| BLI_remlink(lbarray[a], id); | BLI_remlink(lbarray[a], id); | ||||
| if (mainvar->id_map != NULL) { | |||||
| BKE_main_idmap_remove_id(mainvar->id_map, id); | |||||
| } | |||||
| /* When playing with lib renaming and such, you may end with cases where | /* When playing with lib renaming and such, you may end with cases where | ||||
| * you have more than one linked ID of the same data-block from same | * you have more than one linked ID of the same data-block from same | ||||
| * library. This is absolutely horrible, hence we use a ghash to ensure | * library. This is absolutely horrible, hence we use a ghash to ensure | ||||
| * we go back to a single linked data when loading the file. */ | * we go back to a single linked data when loading the file. */ | ||||
| ID **realid = NULL; | ID **realid = NULL; | ||||
| if (!BLI_ghash_ensure_p(loaded_ids, id->name, (void ***)&realid)) { | if (!BLI_ghash_ensure_p(loaded_ids, id->name, (void ***)&realid)) { | ||||
| read_library_linked_id(basefd, fd, mainvar, id, realid); | read_library_linked_id(basefd, fd, mainvar, id, realid); | ||||
| ▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | for (Main *mainptr = mainl->next; mainptr; mainptr = mainptr->next) { | ||||
| mainptr->curlib->id.name, | mainptr->curlib->id.name, | ||||
| mainptr->curlib->filepath); | mainptr->curlib->filepath); | ||||
| /* Open file if it has not been done yet. */ | /* Open file if it has not been done yet. */ | ||||
| FileData *fd = read_library_file_data(basefd, mainlist, mainl, mainptr); | FileData *fd = read_library_file_data(basefd, mainlist, mainl, mainptr); | ||||
| if (fd) { | if (fd) { | ||||
| do_it = true; | do_it = true; | ||||
| if (mainptr->id_map == NULL) { | |||||
| mainptr->id_map = BKE_main_idmap_create(mainptr, false, NULL, MAIN_IDMAP_TYPE_NAME); | |||||
| } | |||||
| } | } | ||||
| /* Read linked data-locks for each link placeholder, and replace | /* Read linked data-locks for each link placeholder, and replace | ||||
| * the placeholder with the real data-lock. */ | * the placeholder with the real data-lock. */ | ||||
| read_library_linked_ids(basefd, fd, mainlist, mainptr); | read_library_linked_ids(basefd, fd, mainlist, mainptr); | ||||
| /* Test if linked data-locks need to read further linked data-locks | /* Test if linked data-locks need to read further linked data-locks | ||||
| * and create link placeholders for them. */ | * and create link placeholders for them. */ | ||||
| ▲ Show 20 Lines • Show All 259 Lines • Show Last 20 Lines | |||||
I would destroy this before joining, not after.
Not that it makes a big difference now, but imagine add_main_to_main uses this map in the future.