diff options
Diffstat (limited to 'source/blender/blenloader/intern/readfile.c')
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 1120 |
1 files changed, 639 insertions, 481 deletions
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 55cadaef459..a5267175dfa 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_query.h" #include "BKE_idcode.h" #include "BKE_material.h" #include "BKE_main.h" // for Main @@ -254,7 +255,7 @@ void blo_reportf_wrap(ReportList *reports, ReportType type, const char *format, BKE_report(reports, type, fixed_buf); if (G.background == 0) { - printf("%s\n", fixed_buf); + printf("%s: %s\n", BKE_report_type_str(type), fixed_buf); } } @@ -618,7 +619,10 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab m = BKE_main_new(); BLI_addtail(mainlist, m); - lib = BKE_libblock_alloc(m, ID_LI, "lib"); + /* Add library datablock itself to 'main' Main, since libraries are **never** linked data. + * Fixes bug where you could end with all ID_LI datablocks having the same name... */ + lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib"); + lib->id.us = ID_FAKE_USERS(lib); /* Important, consistency with main ID reading code from read_libblock(). */ BLI_strncpy(lib->name, filepath, sizeof(lib->name)); BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath)); @@ -851,6 +855,12 @@ BHead *blo_nextbhead(FileData *fd, BHead *thisblock) return(bhead); } +/* Warning! Caller's responsability to ensure given bhead **is** and ID one! */ +const char *bhead_id_name(const FileData *fd, const BHead *bhead) +{ + return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs); +} + static void decode_blender_header(FileData *fd) { char header[SIZEOFBLENDERHEADER], num[4]; @@ -1290,12 +1300,27 @@ void blo_freefiledata(FileData *fd) /* ************ DIV ****************** */ +/** + * Check whether given path ends with a blend file compatible extension (.blend, .ble or .blend.gz). + * + * \param str The path to check. + * \return true is this path ends with a blender file extension. + */ bool BLO_has_bfile_extension(const char *str) { const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL}; return BLI_testextensie_array(str, ext_test); } +/** + * Try to explode given path into its 'library components' (i.e. a .blend file, id type/group, and datablock itself). + * + * \param path the full path to explode. + * \param r_dir the string that'll contain path up to blend file itself ('library' path). + * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL. + * \param r_name the string that'll contain data's name part of the path, if any. May be NULL. + * \return true if path contains a blend file. + */ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name) { /* We might get some data names with slashes, so we have to go up in path until we find blend file itself, @@ -1320,7 +1345,7 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha while ((slash = (char *)BLI_last_slash(r_dir))) { char tc = *slash; *slash = '\0'; - if (BLO_has_bfile_extension(r_dir)) { + if (BLO_has_bfile_extension(r_dir) && BLI_is_file(r_dir)) { break; } @@ -1352,6 +1377,13 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha return true; } +/** + * Does a very light reading of given .blend file to extract its stored thumbnail. + * + * \param filepath The path of the file to extract thumbnail from. + * \return The raw thumbnail + * (MEM-allocated, as stored in file, use BKE_main_thumbnail_to_imbuf() to convert it to ImBuf image). + */ BlendThumbnail *BLO_thumbnail_from_file(const char *filepath) { FileData *fd; @@ -1465,8 +1497,7 @@ static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user { ID *id = newlibadr(fd, lib, adr); - if (id) - id->us++; + id_us_plus_no_lib(id); return id; } @@ -1533,8 +1564,9 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain) for (; ima; ima = ima->id.next) { if (ima->cache) oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0); - if (ima->gputexture) - oldnewmap_insert(fd->imamap, ima->gputexture, ima->gputexture, 0); + for (a = 0; a < TEXTARGET_COUNT; a++) + if (ima->gputexture[a]) + oldnewmap_insert(fd->imamap, ima->gputexture[a], ima->gputexture[a], 0); if (ima->rr) oldnewmap_insert(fd->imamap, ima->rr, ima->rr, 0); for (a=0; a < IMA_MAX_RENDER_SLOT; a++) @@ -1570,15 +1602,18 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain) for (; ima; ima = ima->id.next) { ima->cache = newimaadr(fd, ima->cache); if (ima->cache == NULL) { - ima->bindcode = 0; ima->tpageflag &= ~IMA_GLBIND_IS_DATA; - ima->gputexture = NULL; + for (i = 0; i < TEXTARGET_COUNT; i++) { + ima->bindcode[i] = 0; + ima->gputexture[i] = NULL; + } ima->rr = NULL; } for (i = 0; i < IMA_MAX_RENDER_SLOT; i++) ima->renders[i] = newimaadr(fd, ima->renders[i]); - ima->gputexture = newimaadr(fd, ima->gputexture); + for (i = 0; i < TEXTARGET_COUNT; i++) + ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]); ima->rr = newimaadr(fd, ima->rr); } for (; sce; sce = sce->id.next) { @@ -1769,9 +1804,9 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) /* undo file support: add all library pointers in lookup */ -void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd) +void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd) { - Main *ptr = mainlist->first; + Main *ptr = old_mainlist->first; ListBase *lbarray[MAX_LIBARRAY]; for (ptr = ptr->next; ptr; ptr = ptr->next) { @@ -1782,6 +1817,8 @@ void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd) oldnewmap_insert(fd->libmap, id, id, GS(id->name)); } } + + fd->old_mainlist = old_mainlist; } @@ -1813,11 +1850,12 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname) if (bh->SDNAnr && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) switch_endian_structs(fd->filesdna, bh); - if (fd->compflags[bh->SDNAnr]) { /* flag==0: doesn't exist anymore */ - if (fd->compflags[bh->SDNAnr] == 2) { + if (fd->compflags[bh->SDNAnr] != SDNA_CMP_REMOVED) { + if (fd->compflags[bh->SDNAnr] == SDNA_CMP_NOT_EQUAL) { temp = DNA_struct_reconstruct(fd->memsdna, fd->filesdna, fd->compflags, bh->SDNAnr, bh->nr, (bh+1)); } else { + /* SDNA_CMP_EQUAL */ temp = MEM_mallocN(bh->len, blockname); memcpy(temp, (bh+1), bh->len); } @@ -2065,6 +2103,7 @@ static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, int switch_endian, Fi /* stub function */ static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endian), FileData *UNUSED(fd)) { + /* Should we do something here, prop should be ensured to be non-NULL first... */ } /* ************ READ IMAGE PREVIEW *************** */ @@ -2123,12 +2162,13 @@ static void lib_link_brush(FileData *fd, Main *main) /* only link ID pointers */ for (brush = main->brush.first; brush; brush = brush->id.next) { - if (brush->id.flag & LIB_NEED_LINK) { - brush->id.flag -= LIB_NEED_LINK; + if (brush->id.tag & LIB_TAG_NEED_LINK) { + brush->id.tag &= ~LIB_TAG_NEED_LINK; brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex); brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex); brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image); + brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush); brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve); } } @@ -2158,8 +2198,8 @@ static void lib_link_palette(FileData *UNUSED(fd), Main *main) /* only link ID pointers */ for (palette = main->palettes.first; palette; palette = palette->id.next) { - if (palette->id.flag & LIB_NEED_LINK) { - palette->id.flag -= LIB_NEED_LINK; + if (palette->id.tag & LIB_TAG_NEED_LINK) { + palette->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -2176,8 +2216,8 @@ static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main) /* only link ID pointers */ for (pc = main->paintcurves.first; pc; pc = pc->id.next) { - if (pc->id.flag & LIB_NEED_LINK) { - pc->id.flag -= LIB_NEED_LINK; + if (pc->id.tag & LIB_TAG_NEED_LINK) { + pc->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -2187,14 +2227,6 @@ static void direct_link_paint_curve(FileData *fd, PaintCurve *pc) pc->points = newdataadr(fd, pc->points); } - -static void direct_link_script(FileData *UNUSED(fd), Script *script) -{ - script->id.us = 1; - SCRIPT_SET_NULL(script); -} - - /* ************ READ PACKEDFILE *************** */ static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf) @@ -2218,13 +2250,13 @@ static void lib_link_ipo(FileData *fd, Main *main) Ipo *ipo; for (ipo = main->ipo.first; ipo; ipo = ipo->id.next) { - if (ipo->id.flag & LIB_NEED_LINK) { + if (ipo->id.tag & LIB_TAG_NEED_LINK) { IpoCurve *icu; for (icu = ipo->curve.first; icu; icu = icu->next) { if (icu->driver) icu->driver->ob = newlibadr(fd, ipo->id.lib, icu->driver->ob); } - ipo->id.flag -= LIB_NEED_LINK; + ipo->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -2440,8 +2472,8 @@ static void lib_link_action(FileData *fd, Main *main) bActionChannel *chan; for (act = main->action.first; act; act = act->id.next) { - if (act->id.flag & LIB_NEED_LINK) { - act->id.flag -= LIB_NEED_LINK; + if (act->id.tag & LIB_TAG_NEED_LINK) { + act->id.tag &= ~LIB_TAG_NEED_LINK; // XXX deprecated - old animation system <<< for (chan=act->chanbase.first; chan; chan=chan->next) { @@ -2652,8 +2684,7 @@ static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock { /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - if (sock->prop) - IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } /* singe node tree (also used for material/scene trees), ntree is not NULL */ @@ -2662,15 +2693,14 @@ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree) bNode *node; bNodeSocket *sock; - if (ntree->adt) lib_link_animdata(fd, &ntree->id, ntree->adt); + lib_link_animdata(fd, &ntree->id, ntree->adt); ntree->gpd = newlibadr_us(fd, id->lib, ntree->gpd); for (node = ntree->nodes.first; node; node = node->next) { /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - if (node->prop) - IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); node->id= newlibadr_us(fd, id->lib, node->id); @@ -2693,8 +2723,8 @@ static void lib_link_nodetree(FileData *fd, Main *main) /* only link ID pointers */ for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { - if (ntree->id.flag & LIB_NEED_LINK) { - ntree->id.flag -= LIB_NEED_LINK; + if (ntree->id.tag & LIB_TAG_NEED_LINK) { + ntree->id.tag &= ~LIB_TAG_NEED_LINK; lib_link_ntree(fd, &ntree->id, ntree); } } @@ -2758,8 +2788,6 @@ static void lib_node_do_versions_group_indices(bNode *gnode) * typedefs */ static void lib_verify_nodetree(Main *main, int UNUSED(open)) { - bNodeTree *ntree; - /* this crashes blender on undo/redo */ #if 0 if (open == 1) { @@ -2786,9 +2814,10 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open)) * we have set the NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2 flag, so at this point we can do the * actual group node updates. */ - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { - if (ntree->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2) + for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { + if (ntree->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2) { has_old_groups = 1; + } } if (has_old_groups) { @@ -2805,8 +2834,9 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open)) } FOREACH_NODETREE_END } - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) + for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { ntree->flag &= ~NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2; + } } { @@ -2912,7 +2942,7 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open)) } /* verify all group user nodes */ - for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { + for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) { ntreeVerifyNodes(main, &ntree->id); } @@ -2957,7 +2987,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree) ntree->adt = newdataadr(fd, ntree->adt); direct_link_animdata(fd, ntree->adt); - ntree->id.flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA); + ntree->id.tag &= ~(LIB_TAG_ID_RECALC|LIB_TAG_ID_RECALC_DATA); link_list(fd, &ntree->nodes); for (node = ntree->nodes.first; node; node = node->next) { @@ -2994,6 +3024,10 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree) NodeShaderScript *nss = (NodeShaderScript *) node->storage; nss->bytecode = newdataadr(fd, nss->bytecode); } + else if (node->type==SH_NODE_TEX_POINTDENSITY) { + NodeShaderTexPointDensity *npd = (NodeShaderTexPointDensity *) node->storage; + memset(&npd->pd, 0, sizeof(npd->pd)); + } } else if (ntree->type==NTREE_COMPOSIT) { if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) @@ -3159,18 +3193,23 @@ static void direct_link_constraints(FileData *fd, ListBase *lb) static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) { - bPoseChannel *pchan; bArmature *arm = ob->data; - int rebuild = 0; if (!pose || !arm) return; /* always rebuild to match proxy or lib changes, but on Undo */ - if (fd->memfile == NULL) - if (ob->proxy || (ob->id.lib==NULL && arm->id.lib)) - rebuild = 1; - + bool rebuild = false; + + if (fd->memfile == NULL) { + if (ob->proxy || (ob->id.lib==NULL && arm->id.lib)) { + rebuild = true; + } + } + + /* avoid string */ + GHash *bone_hash = BKE_armature_bone_from_name_map(arm); + if (ob->proxy) { /* sync proxy layer */ if (pose->proxy_layer) @@ -3178,28 +3217,32 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose) /* sync proxy active bone */ if (pose->proxy_act_bone[0]) { - Bone *bone = BKE_armature_find_bone_name(arm, pose->proxy_act_bone); - if (bone) + Bone *bone = BLI_ghash_lookup(bone_hash, pose->proxy_act_bone); + if (bone) { arm->act_bone = bone; + } } } - - for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) { + + for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) { lib_link_constraints(fd, (ID *)ob, &pchan->constraints); - - /* hurms... loop in a loop, but yah... later... (ton) */ - pchan->bone = BKE_armature_find_bone_name(arm, pchan->name); + + pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name); pchan->custom = newlibadr_us(fd, arm->id.lib, pchan->custom); - if (pchan->bone == NULL) - rebuild= 1; - else if (ob->id.lib==NULL && arm->id.lib) { + if (UNLIKELY(pchan->bone == NULL)) { + rebuild = true; + } + else if ((ob->id.lib == NULL) && arm->id.lib) { /* local pose selection copied to armature, bit hackish */ pchan->bone->flag &= ~BONE_SELECTED; pchan->bone->flag |= pchan->selectflag; } } + + BLI_ghash_free(bone_hash, NULL, NULL); + if (rebuild) { DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); BKE_pose_tag_recalc(bmain, pose); @@ -3211,9 +3254,9 @@ static void lib_link_armature(FileData *fd, Main *main) bArmature *arm; for (arm = main->armature.first; arm; arm = arm->id.next) { - if (arm->id.flag & LIB_NEED_LINK) { - if (arm->adt) lib_link_animdata(fd, &arm->id, arm->adt); - arm->id.flag -= LIB_NEED_LINK; + if (arm->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &arm->id, arm->adt); + arm->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3260,14 +3303,14 @@ static void lib_link_camera(FileData *fd, Main *main) Camera *ca; for (ca = main->camera.first; ca; ca = ca->id.next) { - if (ca->id.flag & LIB_NEED_LINK) { - if (ca->adt) lib_link_animdata(fd, &ca->id, ca->adt); + if (ca->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &ca->id, ca->adt); ca->ipo = newlibadr_us(fd, ca->id.lib, ca->ipo); // XXX deprecated - old animation system - ca->dof_ob = newlibadr_us(fd, ca->id.lib, ca->dof_ob); + ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob); - ca->id.flag -= LIB_NEED_LINK; + ca->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3288,8 +3331,8 @@ static void lib_link_lamp(FileData *fd, Main *main) int a; for (la = main->lamp.first; la; la = la->id.next) { - if (la->id.flag & LIB_NEED_LINK) { - if (la->adt) lib_link_animdata(fd, &la->id, la->adt); + if (la->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &la->id, la->adt); for (a = 0; a < MAX_MTEX; a++) { mtex = la->mtex[a]; @@ -3306,7 +3349,7 @@ static void lib_link_lamp(FileData *fd, Main *main) la->nodetree->id.lib = la->id.lib; } - la->id.flag -= LIB_NEED_LINK; + la->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3357,13 +3400,15 @@ static void lib_link_key(FileData *fd, Main *main) blo_do_versions_key_uidgen(key); } - if (key->id.flag & LIB_NEED_LINK) { - if (key->adt) lib_link_animdata(fd, &key->id, key->adt); + BLI_assert((key->id.tag & LIB_TAG_EXTERN) == 0); + + if (key->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &key->id, key->adt); key->ipo = newlibadr_us(fd, key->id.lib, key->ipo); // XXX deprecated - old animation system key->from = newlibadr(fd, key->id.lib, key->from); - key->id.flag -= LIB_NEED_LINK; + key->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3424,15 +3469,15 @@ static void lib_link_mball(FileData *fd, Main *main) int a; for (mb = main->mball.first; mb; mb = mb->id.next) { - if (mb->id.flag & LIB_NEED_LINK) { - if (mb->adt) lib_link_animdata(fd, &mb->id, mb->adt); + if (mb->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &mb->id, mb->adt); for (a = 0; a < mb->totcol; a++) mb->mat[a] = newlibadr_us(fd, mb->id.lib, mb->mat[a]); mb->ipo = newlibadr_us(fd, mb->id.lib, mb->ipo); // XXX deprecated - old animation system - mb->id.flag -= LIB_NEED_LINK; + mb->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3462,8 +3507,8 @@ static void lib_link_world(FileData *fd, Main *main) int a; for (wrld = main->world.first; wrld; wrld = wrld->id.next) { - if (wrld->id.flag & LIB_NEED_LINK) { - if (wrld->adt) lib_link_animdata(fd, &wrld->id, wrld->adt); + if (wrld->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &wrld->id, wrld->adt); wrld->ipo = newlibadr_us(fd, wrld->id.lib, wrld->ipo); // XXX deprecated - old animation system @@ -3480,7 +3525,7 @@ static void lib_link_world(FileData *fd, Main *main) wrld->nodetree->id.lib = wrld->id.lib; } - wrld->id.flag -= LIB_NEED_LINK; + wrld->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3514,8 +3559,8 @@ static void lib_link_vfont(FileData *UNUSED(fd), Main *main) VFont *vf; for (vf = main->vfont.first; vf; vf = vf->id.next) { - if (vf->id.flag & LIB_NEED_LINK) { - vf->id.flag -= LIB_NEED_LINK; + if (vf->id.tag & LIB_TAG_NEED_LINK) { + vf->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3534,8 +3579,8 @@ static void lib_link_text(FileData *UNUSED(fd), Main *main) Text *text; for (text = main->text.first; text; text = text->id.next) { - if (text->id.flag & LIB_NEED_LINK) { - text->id.flag -= LIB_NEED_LINK; + if (text->id.tag & LIB_TAG_NEED_LINK) { + text->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3576,7 +3621,7 @@ static void direct_link_text(FileData *fd, Text *text) text->flags = (text->flags) & ~TXT_ISEXT; - text->id.us = 1; + id_us_ensure_real(&text->id); } /* ************ READ IMAGE ***************** */ @@ -3586,10 +3631,10 @@ static void lib_link_image(FileData *fd, Main *main) Image *ima; for (ima = main->image.first; ima; ima = ima->id.next) { - if (ima->id.flag & LIB_NEED_LINK) { - if (ima->id.properties) IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + if (ima->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - ima->id.flag -= LIB_NEED_LINK; + ima->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3606,9 +3651,11 @@ static void direct_link_image(FileData *fd, Image *ima) /* if not restored, we keep the binded opengl index */ if (!ima->cache) { - ima->bindcode = 0; ima->tpageflag &= ~IMA_GLBIND_IS_DATA; - ima->gputexture = NULL; + for (int i = 0; i < TEXTARGET_COUNT; i++) { + ima->bindcode[i] = 0; + ima->gputexture[i] = NULL; + } ima->rr = NULL; } @@ -3654,8 +3701,8 @@ static void lib_link_curve(FileData *fd, Main *main) int a; for (cu = main->curve.first; cu; cu = cu->id.next) { - if (cu->id.flag & LIB_NEED_LINK) { - if (cu->adt) lib_link_animdata(fd, &cu->id, cu->adt); + if (cu->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &cu->id, cu->adt); for (a = 0; a < cu->totcol; a++) cu->mat[a] = newlibadr_us(fd, cu->id.lib, cu->mat[a]); @@ -3671,7 +3718,7 @@ static void lib_link_curve(FileData *fd, Main *main) cu->ipo = newlibadr_us(fd, cu->id.lib, cu->ipo); // XXX deprecated - old animation system cu->key = newlibadr_us(fd, cu->id.lib, cu->key); - cu->id.flag -= LIB_NEED_LINK; + cu->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3746,8 +3793,8 @@ static void lib_link_texture(FileData *fd, Main *main) Tex *tex; for (tex = main->tex.first; tex; tex = tex->id.next) { - if (tex->id.flag & LIB_NEED_LINK) { - if (tex->adt) lib_link_animdata(fd, &tex->id, tex->adt); + if (tex->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &tex->id, tex->adt); tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima); tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo); @@ -3765,7 +3812,7 @@ static void lib_link_texture(FileData *fd, Main *main) tex->nodetree->id.lib = tex->id.lib; } - tex->id.flag -= LIB_NEED_LINK; + tex->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3790,6 +3837,7 @@ static void direct_link_texture(FileData *fd, Tex *tex) if (tex->pd->falloff_curve) { direct_link_curvemapping(fd, tex->pd->falloff_curve); } + tex->pd->point_data = NULL; /* runtime data */ } tex->vd = newdataadr(fd, tex->vd); @@ -3826,12 +3874,12 @@ static void lib_link_material(FileData *fd, Main *main) int a; for (ma = main->mat.first; ma; ma = ma->id.next) { - if (ma->id.flag & LIB_NEED_LINK) { - if (ma->adt) lib_link_animdata(fd, &ma->id, ma->adt); + if (ma->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &ma->id, ma->adt); /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - if (ma->id.properties) IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); ma->group = newlibadr_us(fd, ma->id.lib, ma->group); @@ -3849,7 +3897,7 @@ static void lib_link_material(FileData *fd, Main *main) ma->nodetree->id.lib = ma->id.lib; } - ma->id.flag -= LIB_NEED_LINK; + ma->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -3963,7 +4011,7 @@ static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd) if (pd && pd->tex) pd->tex = newlibadr_us(fd, id->lib, pd->tex); if (pd && pd->f_source) - pd->f_source = newlibadr_us(fd, id->lib, pd->f_source); + pd->f_source = newlibadr(fd, id->lib, pd->f_source); } static void lib_link_particlesettings(FileData *fd, Main *main) @@ -3974,8 +4022,8 @@ static void lib_link_particlesettings(FileData *fd, Main *main) int a; for (part = main->particle.first; part; part = part->id.next) { - if (part->id.flag & LIB_NEED_LINK) { - if (part->adt) lib_link_animdata(fd, &part->id, part->adt); + if (part->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &part->id, part->adt); part->ipo = newlibadr_us(fd, part->id.lib, part->ipo); // XXX deprecated - old animation system part->dup_ob = newlibadr(fd, part->id.lib, part->dup_ob); @@ -4056,7 +4104,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main) } } - part->id.flag -= LIB_NEED_LINK; + part->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -4237,8 +4285,7 @@ static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface) * to each image it used. - z0r */ for (i = 0; i < totface; i++, tf++) { tf->tpage= newlibadr(fd, me->id.lib, tf->tpage); - if (tf->tpage && tf->tpage->id.us==0) - tf->tpage->id.us= 1; + id_us_ensure_real(&tf->tpage->id); } } @@ -4267,9 +4314,7 @@ static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata for (j = 0; j < totface; j++, tf++) { tf->tpage = newlibadr(fd, me->id.lib, tf->tpage); - if (tf->tpage && tf->tpage->id.us == 0) { - tf->tpage->id.us = 1; - } + id_us_ensure_real((ID *)tf->tpage); } } } @@ -4280,13 +4325,13 @@ static void lib_link_mesh(FileData *fd, Main *main) Mesh *me; for (me = main->mesh.first; me; me = me->id.next) { - if (me->id.flag & LIB_NEED_LINK) { + if (me->id.tag & LIB_TAG_NEED_LINK) { int i; /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - if (me->id.properties) IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - if (me->adt) lib_link_animdata(fd, &me->id, me->adt); + IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + lib_link_animdata(fd, &me->id, me->adt); /* this check added for python created meshes */ if (me->mat) { @@ -4304,9 +4349,10 @@ static void lib_link_mesh(FileData *fd, Main *main) lib_link_customdata_mtface(fd, me, &me->fdata, me->totface); lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly); - if (me->mr && me->mr->levels.first) + if (me->mr && me->mr->levels.first) { lib_link_customdata_mtface(fd, me, &me->mr->fdata, - ((MultiresLevel*)me->mr->levels.first)->totface); + ((MultiresLevel*)me->mr->levels.first)->totface); + } } } @@ -4314,7 +4360,7 @@ static void lib_link_mesh(FileData *fd, Main *main) convert_tface_mt(fd, main); for (me = main->mesh.first; me; me = me->id.next) { - if (me->id.flag & LIB_NEED_LINK) { + if (me->id.tag & LIB_TAG_NEED_LINK) { /*check if we need to convert mfaces to mpolys*/ if (me->totface && !me->totpoly) { /* temporarily switch main so that reading from @@ -4343,7 +4389,7 @@ static void lib_link_mesh(FileData *fd, Main *main) BKE_mesh_tessface_clear(me); #endif - me->id.flag -= LIB_NEED_LINK; + me->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -4560,13 +4606,13 @@ static void lib_link_latt(FileData *fd, Main *main) Lattice *lt; for (lt = main->latt.first; lt; lt = lt->id.next) { - if (lt->id.flag & LIB_NEED_LINK) { - if (lt->adt) lib_link_animdata(fd, <->id, lt->adt); + if (lt->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, <->id, lt->adt); lt->ipo = newlibadr_us(fd, lt->id.lib, lt->ipo); // XXX deprecated - old animation system lt->key = newlibadr_us(fd, lt->id.lib, lt->key); - lt->id.flag -= LIB_NEED_LINK; + lt->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -4587,15 +4633,15 @@ static void direct_link_latt(FileData *fd, Lattice *lt) /* ************ READ OBJECT ***************** */ -static void lib_link_modifiers__linkModifiers(void *userData, Object *ob, - ID **idpoin) +static void lib_link_modifiers__linkModifiers( + void *userData, Object *ob, ID **idpoin, int cd_flag) { FileData *fd = userData; *idpoin = newlibadr(fd, ob->id.lib, *idpoin); - /* hardcoded bad exception; non-object modifier data gets user count (texture, displace) */ - if (*idpoin && GS((*idpoin)->name)!=ID_OB) - (*idpoin)->us++; + if (*idpoin != NULL && (cd_flag & IDWALK_USER) != 0) { + id_us_plus_no_lib(*idpoin); + } } static void lib_link_modifiers(FileData *fd, Object *ob) { @@ -4613,9 +4659,9 @@ static void lib_link_object(FileData *fd, Main *main) int warn=0, a; for (ob = main->object.first; ob; ob = ob->id.next) { - if (ob->id.flag & LIB_NEED_LINK) { - if (ob->id.properties) IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - if (ob->adt) lib_link_animdata(fd, &ob->id, ob->adt); + if (ob->id.tag & LIB_TAG_NEED_LINK) { + IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + lib_link_animdata(fd, &ob->id, ob->adt); // XXX deprecated - old animation system <<< ob->ipo = newlibadr_us(fd, ob->id.lib, ob->ipo); @@ -4690,7 +4736,7 @@ static void lib_link_object(FileData *fd, Main *main) ob->gpd = newlibadr_us(fd, ob->id.lib, ob->gpd); ob->duplilist = NULL; - ob->id.flag -= LIB_NEED_LINK; + ob->id.tag &= ~LIB_TAG_NEED_LINK; /* if id.us==0 a new base will be created later on */ /* WARNING! Also check expand_object(), should reflect the stuff below. */ @@ -5110,7 +5156,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) else if (md->type == eModifierType_ParticleSystem) { ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; - psmd->dm= NULL; + psmd->dm_final = NULL; + psmd->dm_deformed = NULL; psmd->psys= newdataadr(fd, psmd->psys); psmd->flag &= ~eParticleSystemFlag_psys_updated; psmd->flag |= eParticleSystemFlag_file_loaded; @@ -5209,7 +5256,7 @@ static void direct_link_object(FileData *fd, Object *ob) * Also when linking in a file don't allow edit and pose modes. * See [#34776, #42780] for more information. */ - if (fd->memfile || (ob->id.flag & (LIB_EXTERN | LIB_INDIRECT))) { + if (fd->memfile || (ob->id.tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT))) { ob->mode &= ~(OB_MODE_EDIT | OB_MODE_PARTICLE_EDIT); if (!fd->memfile) { ob->mode &= ~OB_MODE_POSE; @@ -5479,7 +5526,7 @@ static bool scene_validate_setscene__liblink(Scene *sce, const int totscene) if (sce->set == NULL) return 1; for (a = 0, sce_iter = sce; sce_iter->set; sce_iter = sce_iter->set, a++) { - if (sce_iter->id.flag & LIB_NEED_LINK) { + if (sce_iter->id.tag & LIB_TAG_NEED_LINK) { return 1; } @@ -5509,11 +5556,11 @@ static void lib_link_scene(FileData *fd, Main *main) #endif for (sce = main->scene.first; sce; sce = sce->id.next) { - if (sce->id.flag & LIB_NEED_LINK) { + if (sce->id.tag & LIB_TAG_NEED_LINK) { /* Link ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - if (sce->id.properties) IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - if (sce->adt) lib_link_animdata(fd, &sce->id, sce->adt); + IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + lib_link_animdata(fd, &sce->id, sce->adt); lib_link_keyingsets(fd, &sce->id, &sce->keyingsets); @@ -5530,7 +5577,7 @@ static void lib_link_scene(FileData *fd, Main *main) if (sce->toolsettings->sculpt) sce->toolsettings->sculpt->gravity_object = - newlibadr_us(fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object); + newlibadr(fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object); if (sce->toolsettings->imapaint.stencil) sce->toolsettings->imapaint.stencil = @@ -5555,7 +5602,7 @@ static void lib_link_scene(FileData *fd, Main *main) base->object = newlibadr_us(fd, sce->id.lib, base->object); if (base->object == NULL) { - blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB ERROR: object lost from scene: '%s'"), + blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB: object lost from scene: '%s'"), sce->id.name + 2); BLI_remlink(&sce->base, base); if (base == sce->basact) sce->basact = NULL; @@ -5574,16 +5621,10 @@ static void lib_link_scene(FileData *fd, Main *main) } } if (seq->clip) { - seq->clip = newlibadr(fd, sce->id.lib, seq->clip); - if (seq->clip) { - seq->clip->id.us++; - } + seq->clip = newlibadr_us(fd, sce->id.lib, seq->clip); } if (seq->mask) { - seq->mask = newlibadr(fd, sce->id.lib, seq->mask); - if (seq->mask) { - seq->mask->id.us++; - } + seq->mask = newlibadr_us(fd, sce->id.lib, seq->mask); } if (seq->scene_camera) { seq->scene_camera = newlibadr(fd, sce->id.lib, seq->scene_camera); @@ -5597,7 +5638,7 @@ static void lib_link_scene(FileData *fd, Main *main) seq->sound = newlibadr(fd, sce->id.lib, seq->sound); } if (seq->sound) { - seq->sound->id.us++; + id_us_plus_no_lib((ID *)seq->sound); seq->scene_sound = BKE_sound_add_scene_sound_defaults(sce, seq); } } @@ -5664,10 +5705,10 @@ static void lib_link_scene(FileData *fd, Main *main) } else { /* postpone un-setting the flag until we've checked the set-scene */ - sce->id.flag &= ~LIB_NEED_LINK; + sce->id.tag &= ~LIB_TAG_NEED_LINK; } #else - sce->id.flag &= ~LIB_NEED_LINK; + sce->id.tag &= ~LIB_TAG_NEED_LINK; #endif } @@ -5679,8 +5720,8 @@ static void lib_link_scene(FileData *fd, Main *main) #ifdef USE_SETSCENE_CHECK if (need_check_set) { for (sce = main->scene.first; sce; sce = sce->id.next) { - if (sce->id.flag & LIB_NEED_LINK) { - sce->id.flag &= ~LIB_NEED_LINK; + if (sce->id.tag & LIB_TAG_NEED_LINK) { + sce->id.tag &= ~LIB_TAG_NEED_LINK; if (!scene_validate_setscene__liblink(sce, totscene)) { printf("Found cyclic background scene when linking %s\n", sce->id.name + 2); } @@ -5777,7 +5818,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) BKE_sound_create_scene(sce); /* set users to one by default, not in lib-link, this will increase it for compo nodes */ - sce->id.us = 1; + id_us_ensure_real(&sce->id); link_list(fd, &(sce->base)); @@ -5802,6 +5843,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) sce->toolsettings->particle.paintcursor = NULL; sce->toolsettings->particle.scene = NULL; sce->toolsettings->particle.object = NULL; + sce->toolsettings->gp_sculpt.paintcursor = NULL; /* in rare cases this is needed, see [#33806] */ if (sce->toolsettings->vpaint) { @@ -5988,6 +6030,8 @@ static void direct_link_scene(FileData *fd, Scene *sce) } sce->preview = direct_link_preview_image(fd, sce->preview); + + direct_link_curvemapping(fd, &sce->r.mblur_shutter_curve); } /* ************ READ WM ***************** */ @@ -5996,7 +6040,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm) { wmWindow *win; - wm->id.us = 1; + id_us_ensure_real(&wm->id); link_list(fd, &wm->windows); for (win = wm->windows.first; win; win = win->next) { @@ -6019,9 +6063,12 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm) win->drawfail = 0; win->active = 0; - win->cursor = 0; - win->lastcursor = 0; - win->modalcursor = 0; + win->cursor = 0; + win->lastcursor = 0; + win->modalcursor = 0; + win->grabcursor = 0; + win->addmousemove = true; + win->multisamples = 0; win->stereo3d_format = newdataadr(fd, win->stereo3d_format); /* multiview always fallback to anaglyph at file opening @@ -6058,11 +6105,11 @@ static void lib_link_windowmanager(FileData *fd, Main *main) wmWindow *win; for (wm = main->wm.first; wm; wm = wm->id.next) { - if (wm->id.flag & LIB_NEED_LINK) { + if (wm->id.tag & LIB_TAG_NEED_LINK) { for (win = wm->windows.first; win; win = win->next) win->screen = newlibadr(fd, NULL, win->screen); - wm->id.flag -= LIB_NEED_LINK; + wm->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -6075,11 +6122,10 @@ static void lib_link_gpencil(FileData *fd, Main *main) bGPdata *gpd; for (gpd = main->gpencil.first; gpd; gpd = gpd->id.next) { - if (gpd->id.flag & LIB_NEED_LINK) { - gpd->id.flag -= LIB_NEED_LINK; + if (gpd->id.tag & LIB_TAG_NEED_LINK) { + gpd->id.tag &= ~LIB_TAG_NEED_LINK; - if (gpd->adt) - lib_link_animdata(fd, &gpd->id, gpd->adt); + lib_link_animdata(fd, &gpd->id, gpd->adt); } } } @@ -6128,8 +6174,8 @@ static void lib_link_screen(FileData *fd, Main *main) ScrArea *sa; for (sc = main->screen.first; sc; sc = sc->id.next) { - if (sc->id.flag & LIB_NEED_LINK) { - sc->id.us = 1; + if (sc->id.tag & LIB_TAG_NEED_LINK) { + id_us_ensure_real(&sc->id); sc->scene = newlibadr(fd, sc->id.lib, sc->scene); /* this should not happen, but apparently it does somehow. Until we figure out the cause, @@ -6318,7 +6364,7 @@ static void lib_link_screen(FileData *fd, Main *main) } } } - sc->id.flag -= LIB_NEED_LINK; + sc->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -6326,20 +6372,14 @@ static void lib_link_screen(FileData *fd, Main *main) /* how to handle user count on pointer restore */ typedef enum ePointerUserMode { USER_IGNORE = 0, /* ignore user count */ - USER_ONE = 1, /* ensure at least one user (fake also counts) */ - USER_REAL = 2, /* ensure at least one real user (fake user ignored) */ + USER_REAL = 1, /* ensure at least one real user (fake user ignored) */ } ePointerUserMode; static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user) { if (STREQ(newid->name + 2, id->name + 2)) { if (newid->lib == id->lib) { - if (user == USER_ONE) { - if (newid->us == 0) { - newid->us++; - } - } - else if (user == USER_REAL) { + if (user == USER_REAL) { id_us_ensure_real(newid); } return true; @@ -6353,7 +6393,6 @@ static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user) * * user * - USER_IGNORE: no usercount change - * - USER_ONE: ensure a user * - USER_REAL: ensure a real user (even if a fake one is set) */ static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user) @@ -6379,7 +6418,7 @@ static void lib_link_seq_clipboard_pt_restore(ID *id, Main *newmain) if (id) { /* clipboard must ensure this */ BLI_assert(id->newid != NULL); - id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_ONE); + id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_REAL); } } static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt) @@ -6413,7 +6452,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc /* 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_ONE); + win->screen = restore_pointer_by_name(newmain, (ID *)win->screen, USER_REAL); if (win->screen == NULL) win->screen = curscreen; @@ -6426,7 +6465,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_ONE); + sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, USER_REAL); if (sc->scene == NULL) sc->scene = curscene; @@ -6445,10 +6484,10 @@ 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_ONE); + v3d->camera = restore_pointer_by_name(newmain, (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_ONE); + v3d->ob_centre = restore_pointer_by_name(newmain, (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))) { @@ -6498,7 +6537,7 @@ 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_ONE); + ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL); if (ads->filter_grp) ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE); @@ -6528,8 +6567,8 @@ 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_ONE); - saction->ads.source = restore_pointer_by_name(newmain, (ID *)saction->ads.source, USER_ONE); + 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); if (saction->ads.filter_grp) saction->ads.filter_grp = restore_pointer_by_name(newmain, (ID *)saction->ads.filter_grp, USER_IGNORE); @@ -6558,7 +6597,7 @@ 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_ONE); + 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); } else if (sl->spacetype == SPACE_SEQ) { @@ -6567,14 +6606,14 @@ 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_ONE); + sseq->gpd = restore_pointer_by_name(newmain, (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_ONE); + ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL); if (ads->filter_grp) ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE); @@ -6583,13 +6622,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_TEXT) { SpaceText *st = (SpaceText *)sl; - st->text = restore_pointer_by_name(newmain, (ID *)st->text, USER_ONE); + st->text = restore_pointer_by_name(newmain, (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_ONE); + scpt->script = restore_pointer_by_name(newmain, (ID *)scpt->script, USER_REAL); /*sc->script = NULL; - 2.45 set to null, better re-run the script */ if (scpt->script) { @@ -6627,7 +6666,7 @@ 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_ONE); + snode->id = restore_pointer_by_name(newmain, snode->id, USER_REAL); snode->from = restore_pointer_by_name(newmain, snode->from, USER_IGNORE); ntree = nodetree_from_id(snode->id); @@ -6676,7 +6715,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc else if (sl->spacetype == SPACE_LOGIC) { SpaceLogic *slogic = (SpaceLogic *)sl; - slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_ONE); + slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_REAL); } } } @@ -7129,7 +7168,7 @@ static void lib_link_library(FileData *UNUSED(fd), Main *main) { Library *lib; for (lib = main->library.first; lib; lib = lib->id.next) { - lib->id.us = 1; + id_us_ensure_real(&lib->id); } } @@ -7169,15 +7208,11 @@ static void lib_link_speaker(FileData *fd, Main *main) Speaker *spk; for (spk = main->speaker.first; spk; spk = spk->id.next) { - if (spk->id.flag & LIB_NEED_LINK) { - if (spk->adt) lib_link_animdata(fd, &spk->id, spk->adt); - - spk->sound= newlibadr(fd, spk->id.lib, spk->sound); - if (spk->sound) { - spk->sound->id.us++; - } + if (spk->id.tag & LIB_TAG_NEED_LINK) { + lib_link_animdata(fd, &spk->id, spk->adt); - spk->id.flag -= LIB_NEED_LINK; + spk->sound = newlibadr_us(fd, spk->id.lib, spk->sound); + spk->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -7229,8 +7264,8 @@ static void lib_link_sound(FileData *fd, Main *main) bSound *sound; for (sound = main->sound.first; sound; sound = sound->id.next) { - if (sound->id.flag & LIB_NEED_LINK) { - sound->id.flag -= LIB_NEED_LINK; + if (sound->id.tag & LIB_TAG_NEED_LINK) { + sound->id.tag &= ~LIB_TAG_NEED_LINK; sound->ipo = newlibadr_us(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system BKE_sound_load(main, sound); @@ -7250,25 +7285,26 @@ static void lib_link_group(FileData *fd, Main *main) { Group *group; GroupObject *go; - int add_us; + bool add_us; for (group = main->group.first; group; group = group->id.next) { - if (group->id.flag & LIB_NEED_LINK) { - group->id.flag -= LIB_NEED_LINK; + if (group->id.tag & LIB_TAG_NEED_LINK) { + group->id.tag &= ~LIB_TAG_NEED_LINK; - add_us = 0; + add_us = false; for (go = group->gobject.first; go; go = go->next) { go->ob= newlibadr(fd, group->id.lib, go->ob); if (go->ob) { go->ob->flag |= OB_FROMGROUP; /* if group has an object, it increments user... */ - add_us = 1; - if (go->ob->id.us == 0) - go->ob->id.us = 1; + add_us = true; + id_us_ensure_real(&go->ob->id); } } - if (add_us) group->id.us++; + if (add_us) { + id_us_ensure_real(&group->id); + } BKE_group_object_unlink(group, NULL, NULL, NULL); /* removes NULL entries */ } } @@ -7377,12 +7413,11 @@ static void lib_link_movieclip(FileData *fd, Main *main) MovieClip *clip; for (clip = main->movieclip.first; clip; clip = clip->id.next) { - if (clip->id.flag & LIB_NEED_LINK) { + if (clip->id.tag & LIB_TAG_NEED_LINK) { MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object; - if (clip->adt) - lib_link_animdata(fd, &clip->id, clip->adt); + lib_link_animdata(fd, &clip->id, clip->adt); clip->gpd = newlibadr_us(fd, clip->id.lib, clip->gpd); @@ -7393,7 +7428,7 @@ static void lib_link_movieclip(FileData *fd, Main *main) lib_link_movieTracks(fd, clip, &object->tracks); } - clip->id.flag -= LIB_NEED_LINK; + clip->id.tag &= ~LIB_TAG_NEED_LINK; } } } @@ -7457,11 +7492,10 @@ static void lib_link_mask(FileData *fd, Main *main) mask = main->mask.first; while (mask) { - if (mask->id.flag & LIB_NEED_LINK) { + if (mask->id.tag & LIB_TAG_NEED_LINK) { MaskLayer *masklay; - if (mask->adt) - lib_link_animdata(fd, &mask->id, mask->adt); + lib_link_animdata(fd, &mask->id, mask->adt); for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; @@ -7482,7 +7516,7 @@ static void lib_link_mask(FileData *fd, Main *main) } } - mask->id.flag -= LIB_NEED_LINK; + mask->id.tag &= ~LIB_TAG_NEED_LINK; } mask = mask->id.next; } @@ -7499,13 +7533,11 @@ static void lib_link_linestyle(FileData *fd, Main *main) linestyle = main->linestyle.first; while (linestyle) { - if (linestyle->id.flag & LIB_NEED_LINK) { - linestyle->id.flag -= LIB_NEED_LINK; + if (linestyle->id.tag & LIB_TAG_NEED_LINK) { + linestyle->id.tag &= ~LIB_TAG_NEED_LINK; - if (linestyle->id.properties) - IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - if (linestyle->adt) - lib_link_animdata(fd, &linestyle->id, linestyle->adt); + IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + lib_link_animdata(fd, &linestyle->id, linestyle->adt); for (m = linestyle->color_modifiers.first; m; m = m->next) { switch (m->type) { case LS_MODIFIER_DISTANCE_FROM_OBJECT: @@ -7829,40 +7861,94 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id) { - /* this routine reads a libblock and its direct data. Use link functions - * to connect it all + /* this routine reads a libblock and its direct data. Use link functions to connect it all */ ID *id; ListBase *lb; const char *allocname; bool wrong_id = false; - + + /* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile). + * However, some needed by the snapshot being read may have been removed in previous one, and would go missing. + * This leads e.g. to desappearing objects in some undo/redo case, see T34446. + * That means we have to carefully check whether current lib or libdata already exits in old main, if it does + * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */ + if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) { + const char *idname = bhead_id_name(fd, bhead); + + /* printf("Checking %s...\n", idname); */ + + if (bhead->code == ID_LI) { + Main *libmain = fd->old_mainlist->first; + /* Skip oldmain itself... */ + for (libmain = libmain->next; libmain; libmain = libmain->next) { + /* printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); */ + if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) { + Main *oldmain = fd->old_mainlist->first; + /* printf("FOUND!\n"); */ + /* In case of a library, we need to re-add its main to fd->mainlist, because if we have later + * a missing ID_ID, we need to get the correct lib it is linked to! + * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */ + BLI_remlink(fd->old_mainlist, libmain); + BLI_remlink_safe(&oldmain->library, libmain->curlib); + BLI_addtail(fd->mainlist, libmain); + BLI_addtail(&main->library, libmain->curlib); + + if (r_id) { + *r_id = NULL; /* Just in case... */ + } + return blo_nextbhead(fd, bhead); + } + /* printf("nothing...\n"); */ + } + } + else { + /* printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); */ + if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) { + /* printf("FOUND!\n"); */ + /* Even though we found our linked ID, there is no guarantee its address is still the same... */ + if (id != bhead->old) { + oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name)); + } + + /* No need to do anything else for ID_ID, it's assumed already present in its lib's main... */ + if (r_id) { + *r_id = NULL; /* Just in case... */ + } + return blo_nextbhead(fd, bhead); + } + /* printf("nothing...\n"); */ + } + } + /* read libblock */ id = read_struct(fd, bhead, "lib block"); + + if (id) { + const short idcode = (bhead->code == ID_ID) ? GS(id->name) : bhead->code; + /* do after read_struct, for dna reconstruct */ + lb = which_libbase(main, idcode); + if (lb) { + oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); /* for ID_ID check */ + BLI_addtail(lb, id); + } + else { + /* unknown ID type */ + printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8)); + MEM_freeN(id); + id = NULL; + } + } + if (r_id) *r_id = id; if (!id) return blo_nextbhead(fd, bhead); - oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); /* for ID_ID check */ - - /* do after read_struct, for dna reconstruct */ - if (bhead->code == ID_ID) { - lb = which_libbase(main, GS(id->name)); - } - else { - lb = which_libbase(main, bhead->code); - } - - BLI_addtail(lb, id); - - /* clear first 8 bits */ - id->flag = (id->flag & 0xFF00) | flag | LIB_NEED_LINK; + id->tag = flag | LIB_TAG_NEED_LINK; id->lib = main->curlib; - if (id->flag & LIB_FAKEUSER) id->us= 1; - else id->us = 0; + id->us = ID_FAKE_USERS(id); id->icon_id = 0; - id->flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA|LIB_DOIT); /* this case cannot be direct_linked: it's just the ID part */ if (bhead->code == ID_ID) { @@ -7960,9 +8046,6 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID case ID_PA: direct_link_particlesettings(fd, (ParticleSettings*)id); break; - case ID_SCRIPT: - direct_link_script(fd, (Script*)id); - break; case ID_GD: direct_link_gpencil(fd, (bGPdata *)id); break; @@ -8307,26 +8390,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) bhead = NULL; break; - case ID_LI: - /* skip library datablocks in undo, this works together with - * BLO_read_from_memfile, where the old main->library is restored - * overwriting the libraries from the memory file. previously - * it did not save ID_LI/ID_ID blocks in this case, but they are - * needed to make quit.blend recover them correctly. */ - if (fd->memfile) - bhead = blo_nextbhead(fd, bhead); - else - bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL); - break; case ID_ID: - /* same as above */ - if (fd->memfile) - bhead = blo_nextbhead(fd, bhead); - else - /* always adds to the most recently loaded - * ID_LI block, see direct_link_library. - * this is part of the file format definition. */ - bhead = read_libblock(fd, mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL); + /* Always adds to the most recently loaded ID_LI block, see direct_link_library. + * This is part of the file format definition. */ + bhead = read_libblock(fd, mainlist.last, bhead, LIB_TAG_READ | LIB_TAG_EXTERN, NULL); break; /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */ @@ -8334,7 +8401,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) bhead->code = ID_SCR; /* deliberate pass on to default */ default: - bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL); + bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL); } } @@ -8480,11 +8547,6 @@ static BHead *find_bhead_from_idname(FileData *fd, const char *idname) #endif } -const char *bhead_id_name(const FileData *fd, const BHead *bhead) -{ - return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs); -} - static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead) { const char *idname= bhead_id_name(fd, bhead); @@ -8511,7 +8573,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) if (ptr->curlib == NULL) { const char *idname= bhead_id_name(fd, bhead); - blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB ERROR: Data refers to main .blend file: '%s' from %s"), + blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB: Data refers to main .blend file: '%s' from %s"), idname, mainvar->curlib->filepath); return; } @@ -8519,7 +8581,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) id = is_yet_read(fd, ptr, bhead); if (id == NULL) { - read_libblock(fd, ptr, bhead, LIB_READ+LIB_INDIRECT, NULL); + read_libblock(fd, ptr, bhead, LIB_TAG_READ | LIB_TAG_INDIRECT, NULL); // commented because this can print way too much // if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name); @@ -8537,10 +8599,10 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) /* Update: the issue is that in file reading, the oldnewmap is OK, but for existing data, it has to be * inserted in the map to be found! */ - /* Update: previously it was checking for id->flag & LIB_PRE_EXISTING, however that does not affect file - * reading. For file reading we may need to insert it into the libmap as well, because you might have - * two files indirectly linking the same datablock, and in that case we need this in the libmap for the - * fd of both those files. + /* Update: previously it was checking for id->tag & LIB_TAG_PRE_EXISTING, however that + * does not affect file reading. For file reading we may need to insert it into the libmap as well, + * because you might have two files indirectly linking the same datablock, and in that case + * we need this in the libmap for the fd of both those files. * * The crash that this check avoided earlier was because bhead->code wasn't properly passed in, making * change_idid_adr not detect the mapping was for an ID_ID datablock. */ @@ -8557,7 +8619,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) else { id = is_yet_read(fd, mainvar, bhead); if (id == NULL) { - read_libblock(fd, mainvar, bhead, LIB_TESTIND, NULL); + read_libblock(fd, mainvar, bhead, LIB_TAG_TESTIND, NULL); } else { /* this is actually only needed on UI call? when ID was already read before, and another append @@ -8570,7 +8632,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) } } -static void (*expand_doit)(void *, Main *, void *); +static BLOExpandDoitCallback expand_doit; // XXX deprecated - old animation system static void expand_ipo(FileData *fd, Main *mainvar, Ipo *ipo) @@ -9007,8 +9069,8 @@ static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm) #endif } -static void expand_object_expandModifiers(void *userData, Object *UNUSED(ob), - ID **idpoin) +static void expand_object_expandModifiers( + void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag)) { struct { FileData *fd; Main *mainvar; } *data= userData; @@ -9345,11 +9407,23 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd) expand_animdata(fd, mainvar, gpd->adt); } -void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *)) +/** + * Set the callback func used over all ID data found by \a BLO_expand_main func. + * + * \param expand_doit_func Called for each ID block it finds. + */ +void BLO_main_expander(BLOExpandDoitCallback expand_doit_func) { expand_doit = expand_doit_func; } +/** + * Loop over all ID data in Main to mark relations. + * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding. + * + * \param fdhandle usually filedata, or own handle. + * \param mainvar the Main database to expand. + */ void BLO_expand_main(void *fdhandle, Main *mainvar) { ListBase *lbarray[MAX_LIBARRAY]; @@ -9365,7 +9439,7 @@ void BLO_expand_main(void *fdhandle, Main *mainvar) while (a--) { id = lbarray[a]->first; while (id) { - if (id->flag & LIB_NEED_EXPAND) { + if (id->tag & LIB_TAG_NEED_EXPAND) { switch (GS(id->name)) { case ID_OB: expand_object(fd, mainvar, (Object *)id); @@ -9445,7 +9519,7 @@ void BLO_expand_main(void *fdhandle, Main *mainvar) } do_it = true; - id->flag -= LIB_NEED_EXPAND; + id->tag &= ~LIB_TAG_NEED_EXPAND; } id = id->next; @@ -9461,101 +9535,86 @@ static bool object_in_any_scene(Main *mainvar, Object *ob) { Scene *sce; - for (sce= mainvar->scene.first; sce; sce= sce->id.next) { - if (BKE_scene_base_find(sce, ob)) - return 1; + for (sce = mainvar->scene.first; sce; sce = sce->id.next) { + if (BKE_scene_base_find(sce, ob)) { + return true; + } } - return 0; + return false; } -static void give_base_to_objects(Main *mainvar, Scene *sce, Library *lib, const short idcode, const bool is_link, const short active_lay) +static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Library *lib, const short flag) { Object *ob; Base *base; - const bool is_group_append = (is_link == false && idcode == ID_GR); + const unsigned int active_lay = (flag & FILE_ACTIVELAY) ? BKE_screen_view3d_layer_active(v3d, scene) : 0; + const bool is_link = (flag & FILE_LINK) != 0; - /* give all objects which are LIB_INDIRECT a base, or for a group when *lib has been set */ + BLI_assert(scene); + + /* give all objects which are LIB_TAG_INDIRECT a base, or for a group when *lib has been set */ for (ob = mainvar->object.first; ob; ob = ob->id.next) { - if (ob->id.flag & LIB_INDIRECT) { - /* IF below is quite confusing! - * if we are appending, but this object wasnt just added along with a group, - * then this is already used indirectly in the scene somewhere else and we didnt just append it. - * - * (ob->id.flag & LIB_PRE_EXISTING)==0 means that this is a newly appended object - Campbell */ - if (is_group_append==0 || (ob->id.flag & LIB_PRE_EXISTING)==0) { - bool do_it = false; - - if (ob->id.us == 0) { - do_it = true; - } - else if (idcode==ID_GR) { - if ((is_link == false) && (ob->id.lib == lib)) { - if ((ob->flag & OB_FROMGROUP) && object_in_any_scene(mainvar, ob)==0) { - do_it = true; - } - } - } - else { - /* when appending, make sure any indirectly loaded objects - * get a base else they cant be accessed at all [#27437] */ - if ((is_link == false) && (ob->id.lib == lib)) { - /* we may be appending from a scene where we already - * have a linked object which is not in any scene [#27616] */ - if ((ob->id.flag & LIB_PRE_EXISTING)==0) { - if (object_in_any_scene(mainvar, ob)==0) { - do_it = true; - } - } - } - } - - if (do_it) { - base = MEM_callocN(sizeof(Base), "add_ext_base"); - BLI_addtail(&sce->base, base); - - if (active_lay) ob->lay = sce->lay; - - base->lay = ob->lay; - base->object = ob; - base->flag = ob->flag; + if ((ob->id.tag & LIB_TAG_INDIRECT) && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0) { + bool do_it = false; - CLAMP_MIN(ob->id.us, 0); - ob->id.us += 1; - - ob->id.flag -= LIB_INDIRECT; - ob->id.flag |= LIB_EXTERN; + if (ob->id.us == 0) { + do_it = true; + } + else if (!is_link && (ob->id.lib == lib) && (object_in_any_scene(mainvar, ob) == 0)) { + /* When appending, make sure any indirectly loaded objects get a base, else they cant be accessed at all + * (see T27437). */ + do_it = true; + } + + if (do_it) { + base = MEM_callocN(sizeof(Base), __func__); + BLI_addtail(&scene->base, base); + + if (active_lay) { + ob->lay = active_lay; } + + base->lay = ob->lay; + base->object = ob; + base->flag = ob->flag; + + CLAMP_MIN(ob->id.us, 0); + id_us_plus_no_lib((ID *)ob); + + ob->id.tag &= ~LIB_TAG_INDIRECT; + ob->id.tag |= LIB_TAG_EXTERN; } } } } -static void give_base_to_groups(Main *mainvar, Scene *scene) +static void give_base_to_groups( + Main *mainvar, Scene *scene, View3D *v3d, Library *UNUSED(lib), const short UNUSED(flag)) { Group *group; - + Base *base; + Object *ob; + const unsigned int active_lay = BKE_screen_view3d_layer_active(v3d, scene); + /* give all objects which are tagged a base */ for (group = mainvar->group.first; group; group = group->id.next) { - if (group->id.flag & LIB_DOIT) { - Base *base; - Object *ob; - + if (group->id.tag & LIB_TAG_DOIT) { /* any indirect group should not have been tagged */ - BLI_assert((group->id.flag & LIB_INDIRECT)==0); - + BLI_assert((group->id.tag & LIB_TAG_INDIRECT) == 0); + /* BKE_object_add(...) messes with the selection */ ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2); ob->type = OB_EMPTY; - ob->lay = scene->lay; - + ob->lay = active_lay; + /* assign the base */ base = BKE_scene_base_add(scene, ob); base->flag |= SELECT; - base->object->flag= base->flag; + base->object->flag = base->flag; DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); scene->basact = base; - + /* assign the group */ ob->dup_group = group; ob->transflag |= OB_DUPLIGROUP; @@ -9564,18 +9623,39 @@ static void give_base_to_groups(Main *mainvar, Scene *scene) } } +static ID *create_placeholder(Main *mainvar, const char *idname, const short flag) +{ + const short idcode = GS(idname); + ListBase *lb = which_libbase(mainvar, idcode); + ID *ph_id = BKE_libblock_alloc_notest(idcode); + + memcpy(ph_id->name, idname, sizeof(ph_id->name)); + BKE_libblock_init_empty(ph_id); + ph_id->lib = mainvar->curlib; + ph_id->tag = flag | LIB_TAG_MISSING; + ph_id->us = ID_FAKE_USERS(ph_id); + ph_id->icon_id = 0; + + BLI_addtail(lb, ph_id); + id_sort_by_name(lb, ph_id); + + return ph_id; +} + /* returns true if the item was found * but it may already have already been appended/linked */ -static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, const short idcode) +static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name) { - BHead *bhead = find_bhead_from_code_name(fd, idcode, idname); + BHead *bhead = find_bhead_from_code_name(fd, idcode, name); ID *id; + BLI_assert(BKE_idcode_is_linkable(idcode) && BKE_idcode_is_valid(idcode)); + if (bhead) { id = is_yet_read(fd, mainl, bhead); if (id == NULL) { /* not read yet */ - read_libblock(fd, mainl, bhead, LIB_TESTEXT, &id); + read_libblock(fd, mainl, bhead, LIB_TAG_TESTEXT, &id); if (id) { /* sort by name in list */ @@ -9588,9 +9668,9 @@ static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, cons if (G.debug) printf("append: already linked\n"); oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); - if (id->flag & LIB_INDIRECT) { - id->flag -= LIB_INDIRECT; - id->flag |= LIB_EXTERN; + if (id->tag & LIB_TAG_INDIRECT) { + id->tag &= ~LIB_TAG_INDIRECT; + id->tag |= LIB_TAG_EXTERN; } } } @@ -9604,104 +9684,178 @@ static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, cons return id; } -/* simple reader for copy/paste buffers */ -void BLO_library_append_all(Main *mainl, BlendHandle *bh) +static void link_object_postprocess(ID *id, Scene *scene, View3D *v3d, const short flag) +{ + if (scene) { + Base *base; + Object *ob; + + base = MEM_callocN(sizeof(Base), "app_nam_part"); + BLI_addtail(&scene->base, base); + + ob = (Object *)id; + + /* link at active layer (view3d if available in context, else scene one */ + if (flag & FILE_ACTIVELAY) { + ob->lay = BKE_screen_view3d_layer_active(v3d, scene); + } + + ob->mode = OB_MODE_OBJECT; + base->lay = ob->lay; + base->object = ob; + base->flag = ob->flag; + id_us_plus_no_lib((ID *)ob); + + if (flag & FILE_AUTOSELECT) { + base->flag |= SELECT; + base->object->flag = base->flag; + /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */ + } + } +} + +/** + * Simple reader for copy/paste buffers. + */ +void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh) { FileData *fd = (FileData *)(bh); BHead *bhead; - ID *id = NULL; for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) { + ID *id = NULL; + if (bhead->code == ENDB) break; - if (bhead->code == ID_OB) - read_libblock(fd, mainl, bhead, LIB_TESTIND, &id); - + if (ELEM(bhead->code, ID_OB, ID_GR)) { + read_libblock(fd, mainl, bhead, LIB_TAG_TESTIND, &id); + } + + if (id) { /* sort by name in list */ ListBase *lb = which_libbase(mainl, GS(id->name)); id_sort_by_name(lb, id); + + if (bhead->code == ID_OB) { + /* Instead of instancing Base's directly, postpone until after groups are loaded + * otherwise the base's flag is set incorrectly when groups are used */ + Object *ob = (Object *)id; + ob->mode = OB_MODE_OBJECT; + /* ensure give_base_to_objects runs on this object */ + BLI_assert(id->us == 0); + } } } } - -static ID *append_named_part_ex(const bContext *C, Main *mainl, FileData *fd, const char *idname, const int idcode, const int flag) +static ID *link_named_part_ex( + Main *mainl, FileData *fd, const short idcode, const char *name, const short flag, + Scene *scene, View3D *v3d) { - ID *id= append_named_part(mainl, fd, idname, idcode); + ID *id = link_named_part(mainl, fd, idcode, name); if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */ - Scene *scene = CTX_data_scene(C); /* can be NULL */ - if (scene) { - Base *base; - Object *ob; - - base= MEM_callocN(sizeof(Base), "app_nam_part"); - BLI_addtail(&scene->base, base); - - ob = (Object *)id; - - /* link at active layer (view3d if available in context, else scene one */ - if ((flag & FILE_ACTIVELAY)) { - View3D *v3d = CTX_wm_view3d(C); - ob->lay = BKE_screen_view3d_layer_active(v3d, scene); - } - - ob->mode = OB_MODE_OBJECT; - base->lay = ob->lay; - base->object = ob; - ob->id.us++; - - if (flag & FILE_AUTOSELECT) { - base->flag |= SELECT; - base->object->flag = base->flag; - /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */ - } - } + link_object_postprocess(id, scene, v3d, flag); } else if (id && (GS(id->name) == ID_GR)) { - /* tag as needing to be instanced */ + /* tag as needing to be instantiated */ if (flag & FILE_GROUP_INSTANCE) - id->flag |= LIB_DOIT; + id->tag |= LIB_TAG_DOIT; } - + return id; } -ID *BLO_library_append_named_part(Main *mainl, BlendHandle **bh, const char *idname, const int idcode) +/** + * Link a named datablock from an external blend file. + * + * \param mainl The main database to link from (not the active one). + * \param bh The blender file handle. + * \param idcode The kind of datablock to link. + * \param name The name of the datablock (without the 2 char ID prefix). + * \return the linked ID when found. + */ +ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name) { FileData *fd = (FileData*)(*bh); - return append_named_part(mainl, fd, idname, idcode); + return link_named_part(mainl, fd, idcode, name); } -ID *BLO_library_append_named_part_ex(const bContext *C, Main *mainl, BlendHandle **bh, const char *idname, const int idcode, const short flag) +/** + * Link a named datablock from an external blend file. + * Optionally instantiate the object/group in the scene when the flags are set. + * + * \param mainl The main database to link from (not the active one). + * \param bh The blender file handle. + * \param idcode The kind of datablock to link. + * \param name The name of the datablock (without the 2 char ID prefix). + * \param flag Options for linking, used for instantiating. + * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done). + * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL). + * \return the linked ID when found. + */ +ID *BLO_library_link_named_part_ex( + Main *mainl, BlendHandle **bh, + const short idcode, const char *name, const short flag, + Scene *scene, View3D *v3d) { FileData *fd = (FileData*)(*bh); - return append_named_part_ex(C, mainl, fd, idname, idcode, flag); + return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d); } -static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **r_id) +static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id) { - BHead *bhead = find_bhead_from_idname(fd, id->name); + BHead *bhead = NULL; + const bool is_valid = BKE_idcode_is_linkable(GS(id->name)) || ((id->tag & LIB_TAG_EXTERN) == 0); + + if (fd) { + bhead = find_bhead_from_idname(fd, id->name); + } + + id->tag &= ~LIB_TAG_READ; + + if (!is_valid) { + blo_reportf_wrap( + reports, RPT_ERROR, + TIP_("LIB: %s: '%s' is directly linked from '%s' (parent '%s'), but is a non-linkable data type"), + BKE_idcode_to_name(GS(id->name)), + id->name + 2, + mainvar->curlib->filepath, + library_parent_filepath(mainvar->curlib)); + } if (bhead) { - id->flag &= ~LIB_READ; - id->flag |= LIB_NEED_EXPAND; + id->tag |= LIB_TAG_NEED_EXPAND; // printf("read lib block %s\n", id->name); - read_libblock(fd, mainvar, bhead, id->flag, r_id); + read_libblock(fd, mainvar, bhead, id->tag, r_id); + } + else { + blo_reportf_wrap( + reports, RPT_WARNING, + TIP_("LIB: %s: '%s' missing from '%s', parent '%s'"), + BKE_idcode_to_name(GS(id->name)), + id->name + 2, + mainvar->curlib->filepath, + library_parent_filepath(mainvar->curlib)); + + /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */ + if (r_id) { + *r_id = is_valid ? create_placeholder(mainvar, id->name, id->tag) : NULL; + } } } /* common routine to append/link something from a library */ -static Main *library_append_begin(Main *mainvar, FileData **fd, const char *filepath) +static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath) { Main *mainl; (*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist"); - /* clear for group instancing tag */ - BKE_main_id_tag_listbase(&(mainvar->group), false); + /* clear for group instantiating tag */ + BKE_main_id_tag_listbase(&(mainvar->group), LIB_TAG_DOIT, false); /* make mains */ blo_split_main((*fd)->mainlist, mainvar); @@ -9719,77 +9873,72 @@ static Main *library_append_begin(Main *mainvar, FileData **fd, const char *file return mainl; } -Main *BLO_library_append_begin(Main *mainvar, BlendHandle **bh, const char *filepath) +/** + * Initialize the BlendHandle for linking library data. + * + * \param mainvar The current main database, e.g. G.main or CTX_data_main(C). + * \param bh A blender file handle as returned by \a BLO_blendhandle_from_file or \a BLO_blendhandle_from_memory. + * \param filepath Used for relative linking, copied to the \a lib->name. + * \return the library Main, to be passed to \a BLO_library_append_named_part as \a mainl. + */ +Main *BLO_library_link_begin(Main *mainvar, BlendHandle **bh, const char *filepath) { FileData *fd = (FileData*)(*bh); - return library_append_begin(mainvar, &fd, filepath); + return library_link_begin(mainvar, &fd, filepath); } - -/* Context == NULL signifies not to do any scene manipulation */ -static void library_append_end(const bContext *C, Main *mainl, FileData **fd, int idcode, short flag) +/* scene and v3d may be NULL. */ +static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, View3D *v3d) { Main *mainvar; Library *curlib; - + /* expander now is callback function */ BLO_main_expander(expand_doit_library); - + /* make main consistent */ BLO_expand_main(*fd, mainl); - + /* do this when expand found other libs */ read_libraries(*fd, (*fd)->mainlist); - + curlib = mainl->curlib; - + /* make the lib path relative if required */ if (flag & FILE_RELPATH) { /* use the full path, this could have been read by other library even */ BLI_strncpy(curlib->name, curlib->filepath, sizeof(curlib->name)); - + /* uses current .blend file as reference */ BLI_path_rel(curlib->name, G.main->name); } - + blo_join_main((*fd)->mainlist); mainvar = (*fd)->mainlist->first; MEM_freeN((*fd)->mainlist); mainl = NULL; /* blo_join_main free's mainl, cant use anymore */ - + lib_link_all(*fd, mainvar); lib_verify_nodetree(mainvar, false); fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */ - - if (C) { - Scene *scene = CTX_data_scene(C); - - /* give a base to loose objects. If group append, do it for objects too */ - if (scene) { - const bool is_link = (flag & FILE_LINK) != 0; - if (idcode == ID_SCE) { - /* don't instance anything when linking in scenes, assume the scene its self instances the data */ - } - else { - give_base_to_objects(mainvar, scene, curlib, idcode, is_link, flag & FILE_ACTIVELAY); - - if (flag & FILE_GROUP_INSTANCE) { - give_base_to_groups(mainvar, scene); - } - } - } - else { - printf("library_append_end, scene is NULL (objects wont get bases)\n"); + + /* Give a base to loose objects. If group append, do it for objects too. + * Only directly linked objects & groups are instantiated by `BLO_library_link_named_part_ex()` & co, + * here we handle indirect ones and other possible edge-cases. */ + if (scene) { + give_base_to_objects(mainvar, scene, v3d, curlib, flag); + + if (flag & FILE_GROUP_INSTANCE) { + give_base_to_groups(mainvar, scene, v3d, curlib, flag); } } + else { + /* printf("library_append_end, scene is NULL (objects wont get bases)\n"); */ + } + + /* clear group instantiating tag */ + BKE_main_id_tag_listbase(&(mainvar->group), LIB_TAG_DOIT, false); - /* clear group instancing tag */ - BKE_main_id_tag_listbase(&(mainvar->group), false); - - /* has been removed... erm, why? s..ton) */ - /* 20040907: looks like they are give base already in append_named_part(); -Nathan L */ - /* 20041208: put back. It only linked direct, not indirect objects (ton) */ - /* patch to prevent switch_endian happens twice */ if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) { blo_freefiledata(*fd); @@ -9797,10 +9946,21 @@ static void library_append_end(const bContext *C, Main *mainl, FileData **fd, in } } -void BLO_library_append_end(const bContext *C, struct Main *mainl, BlendHandle **bh, int idcode, short flag) +/** + * Finalize linking from a given .blend file (library). + * Optionally instance the indirect object/group in the scene when the flags are set. + * \note Do not use \a bh after calling this function, it may frees it. + * + * \param mainl The main database to link from (not the active one). + * \param bh The blender file handle (WARNING! may be freed by this function!). + * \param flag Options for linking, used for instantiating. + * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done). + * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL). + */ +void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, View3D *v3d) { FileData *fd = (FileData*)(*bh); - library_append_end(C, mainl, &fd, idcode, flag); + library_link_end(mainl, &fd, flag, scene, v3d); *bh = (BlendHandle*)fd; } @@ -9821,7 +9981,7 @@ static int mainvar_count_libread_blocks(Main *mainvar) ID *id; for (id = lbarray[a]->first; id; id = id->next) { - if (id->flag & LIB_READ) + if (id->tag & LIB_TAG_READ) tot++; } } @@ -9847,7 +10007,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) while (mainptr) { int tot = mainvar_count_libread_blocks(mainptr); - // printf("found LIB_READ %s\n", mainptr->curlib->name); + // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name); if (tot) { FileData *fd = mainptr->curlib->filedata; @@ -9887,7 +10047,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) printf(" relative lib: %s\n", mainptr->curlib->name); printf(" enter a new path:\n"); - if (scanf("%s", newlib_path) > 0) { + if (scanf("%1023s", newlib_path) > 0) { /* Warning, keep length in sync with FILE_MAX! */ BLI_strncpy(mainptr->curlib->name, newlib_path, sizeof(mainptr->curlib->name)); BLI_strncpy(mainptr->curlib->filepath, newlib_path, sizeof(mainptr->curlib->filepath)); BLI_cleanup_path(G.main->name, mainptr->curlib->filepath); @@ -9928,6 +10088,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) } else { mainptr->curlib->filedata = NULL; + mainptr->curlib->id.tag |= LIB_TAG_MISSING; } if (fd == NULL) { @@ -9937,37 +10098,31 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) } if (fd) { do_it = true; - a = set_listbasepointers(mainptr, lbarray); - while (a--) { - ID *id = lbarray[a]->first; - - while (id) { - ID *idn = id->next; - if (id->flag & LIB_READ) { - ID *realid = NULL; - BLI_remlink(lbarray[a], id); - - append_id_part(fd, mainptr, id, &realid); - if (!realid) { - blo_reportf_wrap( - fd->reports, RPT_WARNING, - TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"), - BKE_idcode_to_name(GS(id->name)), - id->name + 2, - mainptr->curlib->filepath, - library_parent_filepath(mainptr->curlib)); - } - - change_idid_adr(mainlist, basefd, id, realid); - - MEM_freeN(id); - } - id = idn; + } + a = set_listbasepointers(mainptr, lbarray); + while (a--) { + ID *id = lbarray[a]->first; + + 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); + + /* 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); */ + + change_idid_adr(mainlist, basefd, id, realid); + + MEM_freeN(id); } + id = idn; } - - BLO_expand_main(fd, mainptr); } + BLO_expand_main(fd, mainptr); } mainptr = mainptr->next; @@ -9975,6 +10130,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) } /* 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) { a = set_listbasepointers(mainptr, lbarray); while (a--) { @@ -9982,11 +10138,13 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) for (id = lbarray[a]->first; id; id = idn) { idn = id->next; - if (id->flag & LIB_READ) { + if (id->tag & LIB_TAG_READ) { + BLI_assert(0); BLI_remlink(lbarray[a], id); blo_reportf_wrap( - basefd->reports, RPT_WARNING, - TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s'"), + basefd->reports, RPT_ERROR, + TIP_("LIB: %s: '%s' unread lib block missing from '%s', parent '%s' - " + "Please file a bug report if you see this message"), BKE_idcode_to_name(GS(id->name)), id->name + 2, mainptr->curlib->filepath, |