diff options
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 43 | ||||
-rw-r--r-- | source/blenderplayer/bad_level_call_stubs/stubs.c | 2 |
2 files changed, 35 insertions, 10 deletions
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c20246bcbfb..d1646137d11 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7651,12 +7651,20 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) BLI_remlink(&main->library, lib); MEM_freeN(lib); - - + + /* Now, since Blender always expect **latest** Main pointer from fd->mainlist to be the active library + * Main pointer, where to add all non-library data-blocks found in file next, we have to switch that + * 'dupli' found Main to latest position in the list! + * Otherwise, you get weird disappearing linked data on a rather unconsistant basis. + * See also T53977 for reproducible case. */ + BLI_remlink(fd->mainlist, newmain); + BLI_addtail(fd->mainlist, newmain); + return; } } } + /* make sure we have full path in lib->filepath */ BLI_strncpy(lib->filepath, lib->name, sizeof(lib->name)); BLI_cleanup_path(fd->relabase, lib->filepath); @@ -10780,6 +10788,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) Main *mainl = mainlist->first; Main *mainptr; ListBase *lbarray[MAX_LIBARRAY]; + GHash *loaded_ids = BLI_ghash_str_new(__func__); int a; bool do_it = true; @@ -10793,7 +10802,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) mainptr= mainl->next; while (mainptr) { if (mainvar_id_tag_any_check(mainptr, LIB_TAG_READ)) { - // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name); + // printf("found LIB_TAG_READ %s (%s)\n", mainptr->curlib->id.name, mainptr->curlib->name); FileData *fd = mainptr->curlib->filedata; @@ -10891,25 +10900,38 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) a = set_listbasepointers(mainptr, lbarray); while (a--) { ID *id = lbarray[a]->first; + ListBase pending_free_ids = {NULL}; while (id) { ID *idn = id->next; if (id->tag & LIB_TAG_READ) { - ID *realid = NULL; BLI_remlink(lbarray[a], id); - link_id_part(basefd->reports, fd, mainptr, id, &realid); + /* 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 library. + * This is absolutely horrible, hence we use a ghash to ensure we go back to a single + * linked data when loading the file... */ + ID **realid = NULL; + if (!BLI_ghash_ensure_p(loaded_ids, id->name, (void ***)&realid)) { + link_id_part(basefd->reports, fd, mainptr, id, realid); + } /* realid shall never be NULL - unless some source file/lib is broken * (known case: some directly linked shapekey from a missing lib...). */ - /* BLI_assert(realid != NULL); */ + /* BLI_assert(*realid != NULL); */ - change_idid_adr(mainlist, basefd, id, realid); + change_idid_adr(mainlist, basefd, id, *realid); - MEM_freeN(id); + /* We cannot free old lib-ref placeholder ID here anymore, since we use its name + * as key in loaded_ids hass. */ + BLI_addtail(&pending_free_ids, id); } id = idn; } + + /* Clear GHash and free all lib-ref placeholders IDs of that type now. */ + BLI_ghash_clear(loaded_ids, NULL, NULL); + BLI_freelistN(&pending_free_ids); } BLO_expand_main(fd, mainptr); } @@ -10917,7 +10939,10 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) mainptr = mainptr->next; } } - + + BLI_ghash_free(loaded_ids, NULL, NULL); + loaded_ids = NULL; + /* test if there are unread libblocks */ /* XXX This code block is kept for 2.77, until we are sure it never gets reached anymore. Can be removed later. */ for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) { diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 5f6b07ec956..4960a9e68d2 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -770,7 +770,7 @@ void RE_point_density_cache(struct Scene *scene, struct ViewLayer *view_layer, s void RE_point_density_minmax(struct Scene *scene, struct ViewLayer *view_layer, struct PointDensity *pd, const bool use_render_params, float r_min[3], float r_max[3]) RET_NONE void RE_point_density_sample(struct Scene *scene, struct ViewLayer *view_layer, struct PointDensity *pd, const int resolution, const bool use_render_params, float *values) RET_NONE void RE_point_density_free(struct PointDensity *pd) RET_NONE -void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) RET_NONE +void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *random, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) RET_NONE void RE_FreeAllPersistentData(void) RET_NONE float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_ZERO void RE_engine_register_pass(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer, const char *name, int channels, const char *chanid, int type) RET_NONE |