Implement support for Append objects in Blender 2.8
Note for users ============== The active_layer option used for the filebrowser operators is now called active_collection. If there is no collections in the scenelayer or if this option is not selected we automatically create a new collection for the new objects. This is the same behaviour of trying to add a new object when there is no collection. Note for developers =================== For those cases I moved the object user count handling from readfile to the scene collection system. It's working fine for those, but we still need to re-visit this for Add objects, and Duplicate - In those cases the usercount is 2 when it should be 1. Reviewers: mont29, sergey Differential Revision: https://developer.blender.org/D2686
This commit is contained in:
parent
65a042b273
commit
984cd29fda
|
@ -118,7 +118,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
|
|||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
SceneLayer *sl = CTX_data_scene_layer(C);
|
||||
Main *mainl = NULL;
|
||||
Library *lib;
|
||||
BlendHandle *bh;
|
||||
|
@ -143,7 +143,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
|
|||
|
||||
BLO_library_link_copypaste(mainl, bh);
|
||||
|
||||
BLO_library_link_end(mainl, &bh, flag, scene, v3d);
|
||||
BLO_library_link_end(mainl, &bh, flag, scene, sl);
|
||||
|
||||
/* mark all library linked objects to be updated */
|
||||
BKE_main_lib_objects_recalc_all(bmain);
|
||||
|
|
|
@ -43,6 +43,7 @@ struct Main;
|
|||
struct MemFile;
|
||||
struct ReportList;
|
||||
struct Scene;
|
||||
struct SceneLayer;
|
||||
struct UserDef;
|
||||
struct View3D;
|
||||
struct bContext;
|
||||
|
@ -114,9 +115,9 @@ struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, con
|
|||
struct ID *BLO_library_link_named_part_ex(
|
||||
struct Main *mainl, BlendHandle **bh,
|
||||
const short idcode, const char *name, const short flag,
|
||||
struct Scene *scene, struct View3D *v3d,
|
||||
struct Scene *scene, struct SceneLayer *sl,
|
||||
const bool use_placeholders, const bool force_indirect);
|
||||
void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d);
|
||||
void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct SceneLayer *sl);
|
||||
|
||||
void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh);
|
||||
|
||||
|
|
|
@ -9956,11 +9956,11 @@ static bool object_in_any_scene(Main *mainvar, Object *ob)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Library *lib, const short flag)
|
||||
static void give_base_to_objects(
|
||||
Main *mainvar, Scene *scene, SceneLayer *sl, SceneCollection *sc, Library *lib, const short flag)
|
||||
{
|
||||
Object *ob;
|
||||
BaseLegacy *base;
|
||||
const unsigned int active_lay = (flag & FILE_ACTIVELAY) ? BKE_screen_view3d_layer_active(v3d, scene) : 0;
|
||||
Base *base;
|
||||
const bool is_link = (flag & FILE_LINK) != 0;
|
||||
|
||||
BLI_assert(scene);
|
||||
|
@ -9980,25 +9980,22 @@ static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Libra
|
|||
}
|
||||
|
||||
if (do_it) {
|
||||
base = MEM_callocN(sizeof(BaseLegacy), __func__);
|
||||
BLI_addtail(&scene->base, base);
|
||||
CLAMP_MIN(ob->id.us, 0);
|
||||
|
||||
BKE_collection_object_add(scene, sc, ob);
|
||||
base = BKE_scene_layer_base_find(sl, ob);
|
||||
BKE_scene_object_base_flag_sync_from_base(base);
|
||||
|
||||
if (active_lay) {
|
||||
ob->lay = active_lay;
|
||||
}
|
||||
if (flag & FILE_AUTOSELECT) {
|
||||
/* Note that link_object_postprocess() already checks for FILE_AUTOSELECT flag,
|
||||
* but it will miss objects from non-instanciated groups... */
|
||||
ob->flag |= SELECT;
|
||||
if (base->flag & BASE_SELECTABLED) {
|
||||
base->flag |= BASE_SELECTED;
|
||||
BKE_scene_base_flag_sync_from_base(base);
|
||||
}
|
||||
/* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
|
||||
}
|
||||
|
||||
base->object = ob;
|
||||
base->lay = ob->lay;
|
||||
BKE_scene_base_flag_sync_from_object(base);
|
||||
|
||||
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;
|
||||
|
@ -10008,12 +10005,12 @@ static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Libra
|
|||
}
|
||||
|
||||
static void give_base_to_groups(
|
||||
Main *mainvar, Scene *scene, View3D *v3d, Library *UNUSED(lib), const short UNUSED(flag))
|
||||
Main *mainvar, Scene *scene, SceneLayer *sl, SceneCollection *sc,
|
||||
Library *UNUSED(lib), const short UNUSED(flag))
|
||||
{
|
||||
Group *group;
|
||||
BaseLegacy *base;
|
||||
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) {
|
||||
|
@ -10024,14 +10021,17 @@ static void give_base_to_groups(
|
|||
/* 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 = active_lay;
|
||||
|
||||
/* assign the base */
|
||||
base = BKE_scene_base_add(scene, ob);
|
||||
base->flag_legacy |= SELECT;
|
||||
BKE_scene_base_flag_sync_from_base(base);
|
||||
BKE_collection_object_add(scene, sc, ob);
|
||||
base = BKE_scene_layer_base_find(sl, ob);
|
||||
|
||||
if (base->flag & BASE_SELECTABLED) {
|
||||
base->flag |= BASE_SELECTED;
|
||||
}
|
||||
|
||||
BKE_scene_object_base_flag_sync_from_base(base);
|
||||
DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
|
||||
scene->basact = base;
|
||||
sl->basact = base;
|
||||
|
||||
/* assign the group */
|
||||
ob->dup_group = group;
|
||||
|
@ -10108,31 +10108,42 @@ static ID *link_named_part(
|
|||
return id;
|
||||
}
|
||||
|
||||
static void link_object_postprocess(ID *id, Scene *scene, View3D *v3d, const short flag)
|
||||
static SceneCollection *get_scene_collection_active_or_create(struct Scene *scene, struct SceneLayer *sl, const short flag)
|
||||
{
|
||||
LayerCollection *lc = NULL;
|
||||
|
||||
if (flag & FILE_ACTIVELAY) {
|
||||
lc = BKE_layer_collection_get_active_ensure(scene, sl);
|
||||
}
|
||||
else {
|
||||
SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
|
||||
lc = BKE_collection_link(sl, sc);
|
||||
}
|
||||
|
||||
return lc->scene_collection;
|
||||
}
|
||||
|
||||
static void link_object_postprocess(ID *id, Scene *scene, SceneLayer *sl, const short flag)
|
||||
{
|
||||
if (scene) {
|
||||
BaseLegacy *base;
|
||||
/* link to scene */
|
||||
Base *base;
|
||||
Object *ob;
|
||||
|
||||
base = MEM_callocN(sizeof(BaseLegacy), "app_nam_part");
|
||||
BLI_addtail(&scene->base, base);
|
||||
SceneCollection *sc;
|
||||
|
||||
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_legacy = ob->flag;
|
||||
id_us_plus_no_lib((ID *)ob);
|
||||
|
||||
sc = get_scene_collection_active_or_create(scene, sl, flag);
|
||||
BKE_collection_object_add(scene, sc, ob);
|
||||
base = BKE_scene_layer_base_find(sl, ob);
|
||||
BKE_scene_object_base_flag_sync_from_base(base);
|
||||
|
||||
if (flag & FILE_AUTOSELECT) {
|
||||
base->flag_legacy |= SELECT;
|
||||
BKE_scene_base_flag_sync_from_base(base);
|
||||
if (base->flag & BASE_SELECTABLED) {
|
||||
base->flag |= BASE_SELECTED;
|
||||
BKE_scene_base_flag_sync_from_base(base);
|
||||
}
|
||||
/* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
|
||||
}
|
||||
}
|
||||
|
@ -10175,12 +10186,12 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh)
|
|||
|
||||
static ID *link_named_part_ex(
|
||||
Main *mainl, FileData *fd, const short idcode, const char *name, const short flag,
|
||||
Scene *scene, View3D *v3d, const bool use_placeholders, const bool force_indirect)
|
||||
Scene *scene, SceneLayer *sl, const bool use_placeholders, const bool force_indirect)
|
||||
{
|
||||
ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect);
|
||||
|
||||
if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */
|
||||
link_object_postprocess(id, scene, v3d, flag);
|
||||
link_object_postprocess(id, scene, sl, flag);
|
||||
}
|
||||
else if (id && (GS(id->name) == ID_GR)) {
|
||||
/* tag as needing to be instantiated */
|
||||
|
@ -10224,11 +10235,11 @@ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcod
|
|||
ID *BLO_library_link_named_part_ex(
|
||||
Main *mainl, BlendHandle **bh,
|
||||
const short idcode, const char *name, const short flag,
|
||||
Scene *scene, View3D *v3d,
|
||||
Scene *scene, SceneLayer *sl,
|
||||
const bool use_placeholders, const bool force_indirect)
|
||||
{
|
||||
FileData *fd = (FileData*)(*bh);
|
||||
return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d, use_placeholders, force_indirect);
|
||||
return link_named_part_ex(mainl, fd, idcode, name, flag, scene, sl, use_placeholders, force_indirect);
|
||||
}
|
||||
|
||||
static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
|
||||
|
@ -10341,7 +10352,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid)
|
|||
}
|
||||
|
||||
/* scene and v3d may be NULL. */
|
||||
static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, View3D *v3d)
|
||||
static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, SceneLayer *sl)
|
||||
{
|
||||
Main *mainvar;
|
||||
Library *curlib;
|
||||
|
@ -10397,10 +10408,11 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
|
|||
* 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);
|
||||
SceneCollection *sc = get_scene_collection_active_or_create(scene, sl, FILE_ACTIVELAY);
|
||||
give_base_to_objects(mainvar, scene, sl, sc, curlib, flag);
|
||||
|
||||
if (flag & FILE_GROUP_INSTANCE) {
|
||||
give_base_to_groups(mainvar, scene, v3d, curlib, flag);
|
||||
give_base_to_groups(mainvar, scene, sl, sc, curlib, flag);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -10426,12 +10438,12 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
|
|||
* \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).
|
||||
* \param sl The scene layer in which to instantiate objects/groups (if NULL, no instantiation is done).
|
||||
*/
|
||||
void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, View3D *v3d)
|
||||
void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, SceneLayer *sl)
|
||||
{
|
||||
FileData *fd = (FileData*)(*bh);
|
||||
library_link_end(mainl, &fd, flag, scene, v3d);
|
||||
library_link_end(mainl, &fd, flag, scene, sl);
|
||||
*bh = (BlendHandle*)fd;
|
||||
}
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
|
|||
if (params->type == FILE_LOADLIB) {
|
||||
params->flag |= RNA_boolean_get(op->ptr, "link") ? FILE_LINK : 0;
|
||||
params->flag |= RNA_boolean_get(op->ptr, "autoselect") ? FILE_AUTOSELECT : 0;
|
||||
params->flag |= RNA_boolean_get(op->ptr, "active_layer") ? FILE_ACTIVELAY : 0;
|
||||
params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVELAY : 0;
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) {
|
||||
|
|
|
@ -119,7 +119,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
|
|||
|
||||
if (RNA_boolean_get(op->ptr, "autoselect"))
|
||||
flag |= FILE_AUTOSELECT;
|
||||
if (RNA_boolean_get(op->ptr, "active_layer"))
|
||||
if (RNA_boolean_get(op->ptr, "active_collection"))
|
||||
flag |= FILE_ACTIVELAY;
|
||||
|
||||
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
|
||||
|
@ -152,7 +152,7 @@ static void VIEW3D_OT_pastebuffer(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
RNA_def_boolean(ot->srna, "autoselect", true, "Select", "Select pasted objects");
|
||||
RNA_def_boolean(ot->srna, "active_layer", true, "Active Layer", "Put pasted objects on the active layer");
|
||||
RNA_def_boolean(ot->srna, "active_collection", true, "Active Collection", "Put pasted objects on the active collection");
|
||||
}
|
||||
|
||||
/* ************************** registration **********************************/
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "BLO_readfile.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_library_remap.h"
|
||||
#include "BKE_global.h"
|
||||
|
@ -68,6 +69,7 @@
|
|||
|
||||
#include "BKE_idcode.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
|
||||
#include "IMB_colormanagement.h"
|
||||
|
@ -131,7 +133,7 @@ static short wm_link_append_flag(wmOperator *op)
|
|||
|
||||
if (RNA_boolean_get(op->ptr, "autoselect"))
|
||||
flag |= FILE_AUTOSELECT;
|
||||
if (RNA_boolean_get(op->ptr, "active_layer"))
|
||||
if (RNA_boolean_get(op->ptr, "active_collection"))
|
||||
flag |= FILE_ACTIVELAY;
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop))
|
||||
flag |= FILE_RELPATH;
|
||||
|
@ -212,7 +214,7 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add(
|
|||
}
|
||||
|
||||
static void wm_link_do(
|
||||
WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d,
|
||||
WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, SceneLayer *sl,
|
||||
const bool use_placeholders, const bool force_indirect)
|
||||
{
|
||||
Main *mainl;
|
||||
|
@ -261,7 +263,7 @@ static void wm_link_do(
|
|||
}
|
||||
|
||||
new_id = BLO_library_link_named_part_ex(
|
||||
mainl, &bh, item->idcode, item->name, flag, scene, v3d, use_placeholders, force_indirect);
|
||||
mainl, &bh, item->idcode, item->name, flag, scene, sl, use_placeholders, force_indirect);
|
||||
|
||||
if (new_id) {
|
||||
/* If the link is successful, clear item's libs 'todo' flags.
|
||||
|
@ -271,7 +273,7 @@ static void wm_link_do(
|
|||
}
|
||||
}
|
||||
|
||||
BLO_library_link_end(mainl, &bh, flag, scene, v3d);
|
||||
BLO_library_link_end(mainl, &bh, flag, scene, sl);
|
||||
BLO_blendhandle_close(bh);
|
||||
}
|
||||
}
|
||||
|
@ -280,6 +282,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
|
|||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
SceneLayer *sl = CTX_data_scene_layer(C);
|
||||
PropertyRNA *prop;
|
||||
WMLinkAppendData *lapp_data;
|
||||
char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
|
||||
|
@ -334,8 +337,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
|
|||
|
||||
/* from here down, no error returns */
|
||||
|
||||
if (scene && RNA_boolean_get(op->ptr, "autoselect")) {
|
||||
BKE_scene_base_deselect_all(scene);
|
||||
if (sl && RNA_boolean_get(op->ptr, "autoselect")) {
|
||||
BKE_scene_layer_base_deselect_all(sl);
|
||||
}
|
||||
|
||||
/* tag everything, all untagged data can be made local
|
||||
|
@ -405,7 +408,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
|
|||
/* XXX We'd need re-entrant locking on Main for this to work... */
|
||||
/* BKE_main_lock(bmain); */
|
||||
|
||||
wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C), false, false);
|
||||
wm_link_do(lapp_data, op->reports, bmain, scene, sl, false, false);
|
||||
|
||||
/* BKE_main_unlock(bmain); */
|
||||
|
||||
|
@ -445,6 +448,15 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
|
|||
* link into other scenes from this blend file */
|
||||
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
|
||||
|
||||
/* TODO(sergey): Use proper flag for tagging here. */
|
||||
|
||||
/* TODO (dalai): Temporary solution!
|
||||
* Ideally we only need to tag the new objects themselves, not the scene. This way we'll avoid flush of
|
||||
* collection properties to all objects and limit update to the particular object only.
|
||||
* But afraid first we need to change collection evaluation in DEG according to depsgraph manifesto.
|
||||
*/
|
||||
DEG_id_tag_update(&scene->id, 0);
|
||||
|
||||
/* recreate dependency graph to include new objects */
|
||||
DEG_scene_relations_rebuild(bmain, scene);
|
||||
|
||||
|
@ -471,8 +483,8 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
|
|||
prop = RNA_def_boolean(ot->srna, "autoselect", true,
|
||||
"Select", "Select new objects");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
prop = RNA_def_boolean(ot->srna, "active_layer", true,
|
||||
"Active Layer", "Put new objects on the active layer");
|
||||
prop = RNA_def_boolean(ot->srna, "active_collection", true,
|
||||
"Active Collection", "Put new objects on the active collection");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
prop = RNA_def_boolean(ot->srna, "instance_groups", is_link,
|
||||
"Instance Groups", "Create Dupli-Group instances for each group");
|
||||
|
|
Loading…
Reference in New Issue