Core: Add proper support to add or copy IDs into libraries. #108328

Merged
Bastien Montagne merged 2 commits from mont29/blender:F-idcopy-linkeddata into main 2024-03-06 17:05:21 +01:00
39 changed files with 456 additions and 100 deletions

View File

@ -8,6 +8,8 @@
* \ingroup bke
*/
#include <optional>
#include "BLI_sys_types.h" /* for bool */
struct AnimData;
@ -15,6 +17,7 @@ struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct ID;
struct Library;
struct LibraryForeachIDData;
struct Main;
struct ReportList;
@ -84,12 +87,29 @@ void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data);
/**
* Make a copy of the given AnimData - to be used when copying data-blocks.
* \param flag: Control ID pointers management,
* see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.hh
*
* \note: Regarding handling of IDs managed by the #AnimData struct, this function follows the
* behaviors of the generic #BKE_id_copy_ex, please see its documetation for more details.
*
* \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in
* #BKE_lib_id.hh
*
* \return The copied animdata.
*/
AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, int flag);
mont29 marked this conversation as resolved Outdated

Use std::nullopt

I am not really sure std::optional<Library *> is the most clear API. At least not without extra elaboration between difference between using std::nullopt and nullptr.

Note that it might be the proper choice for the API, I am just lacking some background information.

for default behavior (i.e. behavior of the #BKE_animdata_copy function).

It would be easier to understand if the behavior is described explicitly, rather than referring to "default" or "same as BKE_animdata_copy". Something like: When library is passed as std::nullopt the new data-block is assigned to the same library as the source.

> Use std::nullopt I am not really sure `std::optional<Library *>` is the most clear API. At least not without extra elaboration between difference between using `std::nullopt` and `nullptr`. Note that it might be the proper choice for the API, I am just lacking some background information. > for default behavior (i.e. behavior of the #BKE_animdata_copy function). It would be easier to understand if the behavior is described explicitly, rather than referring to "default" or "same as BKE_animdata_copy". Something like: `When library is passed as std::nullopt the new data-block is assigned to the same library as the source`.

Using std::nullopt (and std::optional in fact) is the simplest, least noisy way to avoid having two dedicated codepaths all over the place, since we cannot rely on nullptr as a 'do not use' value here (null library actually means 'local ID'...).

Unfortunately the 'default behavior' is far from simple and clear - it changes depending on whether we are copying a 'regular' Main ID, vs. a non-main one, and a few other parameters.

Using `std::nullopt` (and `std::optional` in fact) is the simplest, least noisy way to avoid having two dedicated codepaths all over the place, since we cannot rely on `nullptr` as a 'do not use' value here (null library actually means 'local ID'...). Unfortunately the 'default behavior' is far from simple and clear - it changes depending on whether we are copying a 'regular' Main ID, vs. a non-main one, and a few other parameters.

Using std::nullopt (and std::optional in fact) is the simplest, least noisy way to avoid having two dedicated codepaths all over the place, since we cannot rely on nullptr as a 'do not use' value here (null library actually means 'local ID'...).

I think simple tweak would be welcome then: \param owner_library the Library to 'assign' the newly created ID to. Use nullptr to make ID not use any library. Use std::nullopt for default behavior (i.e. behavior of the #BKE_animdata_copy function).. It will help a lot to people who do not have that much proficiency in the low-level code.

Unfortunately the 'default behavior' is far from simple and clear - it changes depending on whether we are copying a 'regular' Main ID, vs. a non-main one, and a few other parameters.

That's not very great, as it is not documented, so referring to BKE_animdata_copy does not really help understanding what's going on. Are there some simple rules to word it something like "The behavior of the library assignment could be tricky for certain cases. For simple cases when copying user-facing IDs the library of the new ID is the same as the source. " ?

> Using std::nullopt (and std::optional in fact) is the simplest, least noisy way to avoid having two dedicated codepaths all over the place, since we cannot rely on nullptr as a 'do not use' value here (null library actually means 'local ID'...). I think simple tweak would be welcome then: `\param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID not use any library. Use std::nullopt for default behavior (i.e. behavior of the #BKE_animdata_copy function).`. It will help a lot to people who do not have that much proficiency in the low-level code. > Unfortunately the 'default behavior' is far from simple and clear - it changes depending on whether we are copying a 'regular' Main ID, vs. a non-main one, and a few other parameters. That's not very great, as it is not documented, so referring to `BKE_animdata_copy` does not really help understanding what's going on. Are there some simple rules to word it something like "The behavior of the library assignment could be tricky for certain cases. For simple cases when copying user-facing IDs the library of the new ID is the same as the source. <and maybe some other very common use-cases>" ?

In most typical cases, copied or created IDs are local data (nullptr lib). Added some comments there (and in BKE_lib_id itself).

In most typical cases, copied or created IDs are local data (`nullptr` lib). Added some comments there (and in `BKE_lib_id` itself).
/**
* Same as #BKE_animdata_copy, but allows to duplicate Action IDs into a library.
mont29 marked this conversation as resolved Outdated

struct AnimData -> AnimData

`struct AnimData` -> `AnimData`
*
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
* not use any library (i.e. become a local ID). Use `std::nullopt` for default behavior (i.e.
* behavior of the #BKE_animdata_copy function).
*/
AnimData *BKE_animdata_copy_in_lib(Main *bmain,
std::optional<Library *> owner_library,
AnimData *adt,
int flag);
/**
* \param flag: Control ID pointers management,
* see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.hh

View File

@ -10,6 +10,8 @@
* ID type structure, helping to factorize common operations and data for all data-block types.
*/
#include <optional>
#include "BLI_sys_types.h"
struct AssetTypeInfo;
@ -18,6 +20,7 @@ struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct ID;
struct Library;
struct LibraryForeachIDData;
struct Main;
@ -63,7 +66,8 @@ bool BKE_idtype_cache_key_cmp(const void *key_a_v, const void *key_b_v);
using IDTypeInitDataFunction = void (*)(ID *id);
/** \param flag: Copying options (see BKE_lib_id.hh's LIB_ID_COPY_... flags for more). */
using IDTypeCopyDataFunction = void (*)(Main *bmain, ID *id_dst, const ID *id_src, int flag);
using IDTypeCopyDataFunction = void (*)(
Main *bmain, std::optional<Library *> owner_library, ID *id_dst, const ID *id_src, int flag);
using IDTypeFreeDataFunction = void (*)(ID *id);

View File

@ -30,6 +30,8 @@
* specific cases requiring advanced (and potentially dangerous) handling.
*/
#include <optional>
#include "BLI_compiler_attrs.h"
#include "BLI_set.hh"
#include "BLI_utildefines.h"
@ -57,13 +59,29 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name);
*/
void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
/**
* Allocates and returns a block of the specified type, with the specified name
* Allocates and returns an ID block of the specified type, with the specified name
* (adjusted as necessary to ensure uniqueness), and appended to the specified list.
* The user count is set to 1, all other content (apart from name and links) being
* initialized to zero.
*
* \note: By default, IDs allocated in a Main database will get the current library of the Main,
* i.e. usually (besides in readfile case), they will have a `nullptr` `lib` pointer and be local
* data. IDs allocated outside of a Main database will always get a `nullptr` `lib` pointer.
*/
void *BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag)
ATTR_WARN_UNUSED_RESULT;
/**
* Same as for #BKE_libblock_alloc, but allows creating a data-block for a given owner library.
*
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
* not use any library (i.e. become a local ID). Use `std::nullopt` for default behavior (i.e.
* behavior of the #BKE_libblock_alloc function).
*/
void *BKE_libblock_alloc_in_lib(Main *bmain,
std::optional<Library *> owner_library,
short type,
const char *name,
int flag) ATTR_WARN_UNUSED_RESULT;
/**
* Initialize an ID of given type, such that it has valid 'empty' data.
* ID is assumed to be just calloc'ed.
@ -102,9 +120,24 @@ void BKE_lib_libblock_session_uid_renew(ID *id);
/**
* Generic helper to create a new empty data-block of given type in given \a bmain database.
*
* \note: By default, IDs created in a Main database will get the current library of the Main,
* i.e. usually (besides in readfile case), they will have a `nullptr` `lib` pointer and be local
* data. IDs created outside of a Main database will always get a `nullptr` `lib` pointer.
* \param name: can be NULL, in which case we get default name for this ID type.
*/
void *BKE_id_new(Main *bmain, short type, const char *name);
/**
* Same as for #BKE_id_new, but allows creating a data-block for (whithin) a given owner library.
*
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
* not use any library (i.e. become a local ID). Use `std::nullopt` for default behavior (i.e.
* behavior of the #BKE_id_new function).
*/
void *BKE_id_new_in_lib(Main *bmain,
std::optional<Library *> owner_library,
short type,
const char *name);
/**
* Generic helper to create a new temporary empty data-block of given type,
* *outside* of any Main database.
@ -163,8 +196,6 @@ enum {
/* *** Ideally we should not have those, but we need them for now... *** */
/** EXCEPTION! Deep-copy actions used by animation-data of copied ID. */
LIB_ID_COPY_ACTIONS = 1 << 24,
/** Keep the library pointer when copying data-block outside of bmain. */
LIB_ID_COPY_KEEP_LIB = 1 << 25,
/** EXCEPTION! Deep-copy shape-keys used by copied obdata ID. */
LIB_ID_COPY_SHAPEKEY = 1 << 26,
/** EXCEPTION! Specific deep-copy of node trees used e.g. for rendering purposes. */
@ -188,8 +219,28 @@ enum {
};
void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, int orig_flag);
/**
* Same as #BKE_libblock_copy_ex, but allows copying data into a library, and not as local data
* only.
*
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
* not use any library (i.e. become a local ID). Use std::nullopt for default behavior (i.e.
* behavior of the #BKE_libblock_copy_ex function).
*/
void BKE_libblock_copy_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const ID *id,
ID **r_newid,
int orig_flag);
/**
* Used everywhere in blenkernel.
*
* \note Typically, the newly copied ID will be a local data (its `lib` pointer will be `nullptr`).
* In practice, ID copying follows the same behavior as ID creation (see #BKE_libblock_alloc
* documentation), with one special case: when the special flag #LIB_ID_CREATE_NO_ALLOCATE is
* specified, the copied ID will have the same library as the source ID.
*
*/
void *BKE_libblock_copy(Main *bmain, const ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@ -436,6 +487,11 @@ bool BKE_id_copy_is_allowed(const ID *id);
*
* \note User-count of new copy is always set to 1.
*
* \note Typically, the newly copied ID will be a local data (its `lib` pointer will be `nullptr`).
* In practice, ID copying follows the same behavior as ID creation (see #BKE_libblock_alloc
* documentation), with one special case: when the special flag #LIB_ID_CREATE_NO_ALLOCATE is
* specified, the copied ID will have the same library as the source ID.
*
* \param bmain: Main database, may be NULL only if LIB_ID_CREATE_NO_MAIN is specified.
* \param id: Source data-block.
* \param r_newid: Pointer to new (copied) ID pointer, may be NULL.
@ -445,6 +501,17 @@ bool BKE_id_copy_is_allowed(const ID *id);
* \return NULL when copying that ID type is not supported, the new copy otherwise.
*/
ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, int flag);
/**
* Enable coying non-local data into libraries.
*
* See #BKE_id_copy_ex for details.
*
* \param owner_library the Library to 'assign' the newly created ID to. Use `nullptr` to make ID
* not use any library (i.e. become a local ID). Use std::nullopt for default behavior (i.e.
* behavior of the #BKE_id_copy_ex function).
*/
struct ID *BKE_id_copy_in_lib(
Main *bmain, std::optional<Library *> owner_library, const ID *id, ID **r_newid, int flag);
/**
* Invoke the appropriate copy method for the block and return the new id as result.
*

View File

@ -10,6 +10,7 @@
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -97,7 +98,11 @@ static CLG_LogRef LOG = {"bke.action"};
*
* \param flag: Copying options (see BKE_lib_id.hh's LIB_ID_COPY_... flags for more).
*/
static void action_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag)
static void action_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int flag)
{
bAction *action_dst = (bAction *)id_dst;
const bAction *action_src = (const bAction *)id_src;

View File

@ -8,6 +8,7 @@
#include "MEM_guardedalloc.h"
#include <cstring>
#include <optional>
#include "BKE_action.h"
#include "BKE_anim_data.hh"
@ -303,7 +304,10 @@ void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
/* Copying -------------------------------------------- */
AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
AnimData *BKE_animdata_copy_in_lib(Main *bmain,
std::optional<Library *> owner_library,
AnimData *adt,
const int flag)
{
AnimData *dadt;
@ -333,8 +337,10 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
flag;
BLI_assert(bmain != nullptr);
BLI_assert(dadt->action == nullptr || dadt->action != dadt->tmpact);
dadt->action = (bAction *)BKE_id_copy_ex(bmain, (ID *)dadt->action, nullptr, id_copy_flag);
dadt->tmpact = (bAction *)BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, nullptr, id_copy_flag);
dadt->action = reinterpret_cast<bAction *>(BKE_id_copy_in_lib(
bmain, owner_library, reinterpret_cast<ID *>(dadt->action), nullptr, id_copy_flag));
dadt->tmpact = reinterpret_cast<bAction *>(BKE_id_copy_in_lib(
bmain, owner_library, reinterpret_cast<ID *>(dadt->tmpact), nullptr, id_copy_flag));
}
else if (do_id_user) {
id_us_plus((ID *)dadt->action);
@ -355,6 +361,11 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
return dadt;
}
AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
{
return BKE_animdata_copy_in_lib(bmain, std::nullopt, adt, flag);
}
bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
{
AnimData *adt;

View File

@ -13,6 +13,7 @@
#include <cstdlib>
#include <cstring>
#include <limits>
#include <optional>
#include "MEM_guardedalloc.h"
@ -130,7 +131,11 @@ static void copy_bone_collection(bArmature *armature_dst,
*
* \param flag: Copying options (see BKE_lib_id.hh's LIB_ID_COPY_... flags for more).
*/
static void armature_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag)
static void armature_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int flag)
{
bArmature *armature_dst = (bArmature *)id_dst;
const bArmature *armature_src = (const bArmature *)id_src;

View File

@ -5,6 +5,7 @@
/** \file
* \ingroup bke
*/
#include <optional>
#include "MEM_guardedalloc.h"
@ -55,7 +56,11 @@ static void brush_init_data(ID *id)
BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
}
static void brush_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag)
static void brush_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int flag)
{
Brush *brush_dst = (Brush *)id_dst;
const Brush *brush_src = (const Brush *)id_src;

View File

@ -7,6 +7,7 @@
*/
#include <cstring>
#include <optional>
#include "DNA_cachefile_types.h"
#include "DNA_object_types.h"
@ -59,6 +60,7 @@ static void cache_file_init_data(ID *id)
}
static void cache_file_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)

View File

@ -8,6 +8,7 @@
#include <cstddef>
#include <cstdlib>
#include <optional>
/* Allow using deprecated functionality for .blend file I/O. */
#define DNA_DEPRECATED_ALLOW
@ -68,7 +69,11 @@ static void camera_init_data(ID *id)
*
* \param flag: Copying options (see BKE_lib_id.hh's LIB_ID_COPY_... flags for more).
*/
static void camera_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag)
static void camera_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int flag)
{
Camera *cam_dst = (Camera *)id_dst;
const Camera *cam_src = (const Camera *)id_src;

View File

@ -12,6 +12,7 @@
#include "CLG_log.h"
#include <cstring>
#include <optional>
#include "BLI_blenlib.h"
#include "BLI_iterator.h"
@ -132,7 +133,11 @@ static void collection_init_data(ID *id)
*
* \param flag: Copying options (see BKE_lib_id.hh's LIB_ID_COPY_... flags for more).
*/
static void collection_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void collection_copy_data(Main *bmain,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int flag)
{
Collection *collection_dst = (Collection *)id_dst;
const Collection *collection_src = (const Collection *)id_src;
@ -929,13 +934,15 @@ Collection *BKE_collection_master_add(Scene *scene)
BLI_assert(scene != nullptr && scene->master_collection == nullptr);
/* Not an actual datablock, but owned by scene. */
Collection *master_collection = static_cast<Collection *>(
BKE_libblock_alloc(nullptr, ID_GR, BKE_SCENE_COLLECTION_NAME, LIB_ID_CREATE_NO_MAIN));
Collection *master_collection = static_cast<Collection *>(BKE_libblock_alloc_in_lib(
nullptr, scene->id.lib, ID_GR, BKE_SCENE_COLLECTION_NAME, LIB_ID_CREATE_NO_MAIN));
master_collection->id.flag |= LIB_EMBEDDED_DATA;
master_collection->owner_id = &scene->id;
master_collection->flag |= COLLECTION_IS_MASTER;
master_collection->color_tag = COLLECTION_COLOR_NONE;
BLI_assert(scene->id.lib == master_collection->id.lib);
return master_collection;
}

View File

@ -9,6 +9,7 @@
#include <cmath> /* floor */
#include <cstdlib>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -79,7 +80,11 @@ static void curve_init_data(ID *id)
MEMCPY_STRUCT_AFTER(curve, DNA_struct_default_get(Curve), id);
}
static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void curve_copy_data(Main *bmain,
std::optional<Library *> owner_library,
ID *id_dst,
const ID *id_src,
const int flag)
{
Curve *curve_dst = (Curve *)id_dst;
const Curve *curve_src = (const Curve *)id_src;
@ -97,7 +102,7 @@ static void curve_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
curve_dst->bevel_profile = BKE_curveprofile_copy(curve_src->bevel_profile);
if (curve_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &curve_src->key->id, (ID **)&curve_dst->key, flag);
BKE_id_copy_in_lib(bmain, owner_library, &curve_src->key->id, (ID **)&curve_dst->key, flag);
/* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
curve_dst->key->from = &curve_dst->id;
}

View File

@ -8,6 +8,7 @@
#include <cmath>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -61,7 +62,11 @@ static void curves_init_data(ID *id)
new (&curves->geometry) blender::bke::CurvesGeometry();
}
static void curves_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/)
static void curves_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)
{
Curves *curves_dst = (Curves *)id_dst;
const Curves *curves_src = (const Curves *)id_src;

View File

@ -11,6 +11,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <optional>
#include "CLG_log.h"
@ -59,6 +60,7 @@
static CLG_LogRef LOG = {"bke.gpencil"};
static void greasepencil_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)
@ -1059,7 +1061,7 @@ bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool in
}
/* Copy internal data (layers, etc.) */
greasepencil_copy_data(bmain, &gpd_dst->id, &gpd_src->id, 0);
greasepencil_copy_data(bmain, std::nullopt, &gpd_dst->id, &gpd_src->id, 0);
/* return new */
return gpd_dst;

View File

@ -7,6 +7,7 @@
*/
#include <iostream>
#include <optional>
#include "BKE_action.h"
#include "BKE_anim_data.hh"
@ -88,6 +89,7 @@ static void grease_pencil_init_data(ID *id)
}
static void grease_pencil_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)

View File

@ -12,6 +12,7 @@
#include <cstring>
#include <ctime>
#include <fcntl.h>
#include <optional>
#ifndef WIN32
# include <unistd.h>
#else
@ -156,7 +157,11 @@ static void image_init_data(ID *id)
}
}
static void image_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag)
static void image_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int flag)
{
Image *image_dst = (Image *)id_dst;
const Image *image_src = (const Image *)id_src;

View File

@ -9,6 +9,7 @@
#include <cmath>
#include <cstddef>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -54,7 +55,11 @@
#include "BLO_read_write.hh"
static void shapekey_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/)
static void shapekey_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)
{
Key *key_dst = (Key *)id_dst;
const Key *key_src = (const Key *)id_src;

View File

@ -56,7 +56,11 @@ static void lattice_init_data(ID *id)
BKE_lattice_resize(lattice, 2, 2, 2, nullptr); /* creates a uniform lattice */
}
static void lattice_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void lattice_copy_data(Main *bmain,
std::optional<Library *> owner_library,
ID *id_dst,
const ID *id_src,
const int flag)
{
Lattice *lattice_dst = (Lattice *)id_dst;
const Lattice *lattice_src = (const Lattice *)id_src;
@ -64,7 +68,8 @@ static void lattice_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const i
lattice_dst->def = static_cast<BPoint *>(MEM_dupallocN(lattice_src->def));
if (lattice_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &lattice_src->key->id, (ID **)&lattice_dst->key, flag);
BKE_id_copy_in_lib(
bmain, owner_library, &lattice_src->key->id, (ID **)&lattice_dst->key, flag);
/* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
lattice_dst->key->from = &lattice_dst->id;
}

View File

@ -626,19 +626,28 @@ bool BKE_id_copy_is_allowed(const ID *id)
#undef LIB_ID_TYPES_NOCOPY
}
ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
ID *BKE_id_copy_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const ID *id,
ID **r_newid,
const int flag)
{
ID *newid = (r_newid != nullptr) ? *r_newid : nullptr;
BLI_assert_msg(newid || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0,
"Copying with 'no allocate' behavior should always get a non-null new ID buffer");
/* Make sure destination pointer is all good. */
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0) {
newid = nullptr;
}
else {
if (newid != nullptr) {
/* Allow some garbage non-initialized memory to go in, and clean it up here. */
const size_t size = BKE_libblock_get_alloc_info(GS(id->name), nullptr);
memset(newid, 0, size);
if (!newid) {
/* Invalid case, already caught by the assert above. */
return nullptr;
}
/* Allow some garbage non-initialized memory to go in, and clean it up here. */
const size_t size = BKE_libblock_get_alloc_info(GS(id->name), nullptr);
memset(newid, 0, size);
}
/* Early output if source is nullptr. */
@ -653,16 +662,21 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
return nullptr;
}
BKE_libblock_copy_ex(bmain, id, &newid, flag);
BKE_libblock_copy_in_lib(bmain, owner_library, id, &newid, flag);
if (idtype_info->copy_data != nullptr) {
idtype_info->copy_data(bmain, newid, id, flag);
idtype_info->copy_data(bmain, owner_library, newid, id, flag);
}
}
else {
BLI_assert_msg(0, "IDType Missing IDTypeInfo");
}
BLI_assert_msg(newid, "Could not get an allocated new ID to copy into");
if (!newid) {
return nullptr;
}
/* Update ID refcount, remap pointers to self in new ID. */
IDCopyLibManagementData data{};
data.id_src = id;
@ -673,11 +687,20 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
/* Do not make new copy local in case we are copying outside of main...
* XXX TODO: is this behavior OK, or should we need own flag to control that? */
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
BLI_assert((flag & LIB_ID_COPY_KEEP_LIB) == 0);
lib_id_copy_ensure_local(bmain, id, newid, 0);
BLI_assert(!owner_library || newid->lib == *owner_library);
if (!ID_IS_LINKED(newid)) {
lib_id_copy_ensure_local(bmain, id, newid, 0);
}
}
else {
newid->lib = id->lib;
/* NOTE: Do not call `ensure_local` for IDs copied outside of Main, even if they do become
* local.
*
* Most of the time, this would not be the desired behavior currently.
*
* In the few cases where this is actually needed (e.g. from liboverride resync code, see
* #lib_override_library_create_from), calling code is responsible for this. */
newid->lib = owner_library ? *owner_library : id->lib;
}
if (r_newid != nullptr) {
@ -687,9 +710,14 @@ ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
return newid;
}
ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
{
return BKE_id_copy_in_lib(bmain, std::nullopt, id, r_newid, flag);
}
ID *BKE_id_copy(Main *bmain, const ID *id)
{
return BKE_id_copy_ex(bmain, id, nullptr, LIB_ID_COPY_DEFAULT);
return BKE_id_copy_in_lib(bmain, std::nullopt, id, nullptr, LIB_ID_COPY_DEFAULT);
}
ID *BKE_id_copy_for_duplicate(Main *bmain,
@ -1220,7 +1248,11 @@ void *BKE_libblock_alloc_notest(short type)
return nullptr;
}
void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag)
void *BKE_libblock_alloc_in_lib(Main *bmain,
std::optional<Library *> owner_library,
short type,
const char *name,
const int flag)
{
BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != nullptr);
@ -1250,20 +1282,44 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
BLI_assert(bmain->is_locked_for_linking == false || ELEM(type, ID_WS, ID_GR, ID_NT));
ListBase *lb = which_libbase(bmain, type);
/* This is important in 'readfile doversion after liblink' context mainly, but is a good
* behavior for consistency in general: ID created for a Main should get that main's current
* library pointer.
mont29 marked this conversation as resolved Outdated

assignement -> assignment?

assignement -> assignment?
*
* NOTE: A bit convoluted.
* - When Main has a defined `curlib`, it is assumed to be a split main containing only IDs
* from that library. In that case, the library can be set later, and it avoids
* synchronization issues in the namemap between the one of that temp 'library' Main and
* the library ID runtime namemap itself. In a way, the ID can be assumed local to the
* current Main, for its assignment to this Main.
* - In all other cases, the Main is assumed 'complete', i.e. containing all local and
* linked IDs, In that case, it is critical that the ID gets the correct library assigned
* now, to ensure that the call to #BKE_id_new_name_validate gives a fully valid result
* once it has been assigned to the current Main.
*/
if (bmain->curlib) {
id->lib = nullptr;
}

What are the consequences of this change? Is it just potentially performance, or could it also lead to functional changes?
Shall the library assignment be delayed for until after the unique name is ensured to minimize the amount of functional changes?

What are the consequences of this change? Is it just potentially performance, or could it also lead to functional changes? Shall the library assignment be delayed for until after the unique name is ensured to minimize the amount of functional changes?

Well, it is delayed in 'split Main' case (i.e. readfile situation, where we have on e Main for each library). For regular monolithic Main case however, it is critical for the lib pointer to have its definitive value before we call this function, to ensure that a 'linked' ID gets a lib-relative unique name (and is sorted appropriately) in the Main.

The change from false to true here simply ensures that the name validation does not skip linked data, which becomes mandatory in this PR, since it allows creating linked IDs at runtime.

Well, it is delayed in 'split Main' case (i.e. readfile situation, where we have on e Main for each library). For regular monolithic Main case however, it is critical for the `lib` pointer to have its definitive value _before_ we call this function, to ensure that a 'linked' ID gets a lib-relative unique name (and is sorted appropriately) in the Main. The change from `false` to `true` here simply ensures that the name validation does not skip linked data, which becomes mandatory in this PR, since it allows creating linked IDs at runtime.
else {
id->lib = owner_library ? *owner_library : nullptr;
}
BKE_main_lock(bmain);
BLI_addtail(lb, id);
BKE_id_new_name_validate(bmain, lb, id, name, false);
BKE_id_new_name_validate(bmain, lb, id, name, true);
bmain->is_memfile_undo_written = false;
/* alphabetic insertion: is in new_id */
BKE_main_unlock(bmain);
/* Split Main case, now the ID should get the Main's #curlib. */
if (bmain->curlib) {
BLI_assert(!owner_library || *owner_library == bmain->curlib);
id->lib = bmain->curlib;
}
/* This assert avoids having to keep name_map consistency when changing the library of an ID,
* if this check is not true anymore it will have to be done here too. */
BLI_assert(bmain->curlib == nullptr || bmain->curlib->runtime.name_map == nullptr);
/* This is important in 'readfile doversion after liblink' context mainly, but is a good
* consistency change in general: ID created for a Main should get that main's current
* library pointer. */
id->lib = bmain->curlib;
/* TODO: to be removed from here! */
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) {
@ -1272,6 +1328,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
}
else {
BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
id->lib = owner_library ? *owner_library : nullptr;
}
/* We also need to ensure a valid `session_uid` for some non-main data (like embedded IDs).
@ -1285,6 +1342,11 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
return id;
}
void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag)
{
return BKE_libblock_alloc_in_lib(bmain, std::nullopt, type, name, flag);
}
void BKE_libblock_init_empty(ID *id)
{
const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_id(id);
@ -1329,7 +1391,11 @@ void BKE_lib_libblock_session_uid_renew(ID *id)
BKE_lib_libblock_session_uid_ensure(id);
}
void *BKE_id_new(Main *bmain, const short type, const char *name)
void *BKE_id_new_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const short type,
const char *name)
{
BLI_assert(bmain != nullptr);
@ -1337,12 +1403,17 @@ void *BKE_id_new(Main *bmain, const short type, const char *name)
name = DATA_(BKE_idtype_idcode_to_name(type));
}
ID *id = static_cast<ID *>(BKE_libblock_alloc(bmain, type, name, 0));
ID *id = static_cast<ID *>(BKE_libblock_alloc_in_lib(bmain, owner_library, type, name, 0));
BKE_libblock_init_empty(id);
return id;
}
void *BKE_id_new(Main *bmain, const short type, const char *name)
{
return BKE_id_new_in_lib(bmain, std::nullopt, type, name);
}
void *BKE_id_new_nomain(const short type, const char *name)
{
if (name == nullptr) {
@ -1359,7 +1430,11 @@ void *BKE_id_new_nomain(const short type, const char *name)
return id;
}
void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int orig_flag)
void BKE_libblock_copy_in_lib(Main *bmain,
std::optional<Library *> owner_library,
const ID *id,
ID **r_newid,
const int orig_flag)
{
ID *new_id = *r_newid;
int flag = orig_flag;
@ -1388,10 +1463,12 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
STRNCPY(new_id->name, id->name);
new_id->us = 0;
new_id->tag |= LIB_TAG_NOT_ALLOCATED | LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT;
new_id->lib = owner_library ? *owner_library : id->lib;
/* TODO: Do we want/need to copy more from ID struct itself? */
}
else {
new_id = static_cast<ID *>(BKE_libblock_alloc(bmain, GS(id->name), id->name + 2, flag));
new_id = static_cast<ID *>(
BKE_libblock_alloc_in_lib(bmain, owner_library, GS(id->name), id->name + 2, flag));
}
BLI_assert(new_id != nullptr);
@ -1451,7 +1528,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
* in their anim data *are* in bmain... super-mega-hooray. */
BLI_assert((copy_data_flag & LIB_ID_COPY_ACTIONS) == 0 ||
(copy_data_flag & LIB_ID_CREATE_NO_MAIN) == 0);
iat->adt = BKE_animdata_copy(bmain, iat->adt, copy_data_flag);
iat->adt = BKE_animdata_copy_in_lib(bmain, owner_library, iat->adt, copy_data_flag);
}
else {
iat->adt = nullptr;
@ -1465,11 +1542,16 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
*r_newid = new_id;
}
void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int orig_flag)
{
BKE_libblock_copy_in_lib(bmain, std::nullopt, id, r_newid, orig_flag);
}
void *BKE_libblock_copy(Main *bmain, const ID *id)
{
ID *idn;
BKE_libblock_copy_ex(bmain, id, &idn, 0);
BKE_libblock_copy_in_lib(bmain, std::nullopt, id, &idn, 0);
return idn;
}

View File

@ -253,11 +253,17 @@ static ID *lib_override_library_create_from(Main *bmain,
const int lib_id_copy_flags)
{
/* NOTE: do not copy possible override data from the reference here. */
ID *local_id = BKE_id_copy_ex(bmain,
reference_id,
nullptr,
LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE |
lib_id_copy_flags);
ID *local_id = BKE_id_copy_in_lib(
bmain,
owner_library,
reference_id,
nullptr,
(LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE | lib_id_copy_flags));
if (local_id == nullptr) {
return nullptr;
}
BLI_assert(local_id->lib == owner_library);
id_us_min(local_id);
/* In case we could not get an override ID with the exact same name as its linked reference,
* ensure we at least get a uniquely named override ID over the whole current Main data, to
@ -271,16 +277,14 @@ static ID *lib_override_library_create_from(Main *bmain,
id_sort_by_name(which_libbase(bmain, GS(local_id->name)), local_id, nullptr);
}
if (local_id == nullptr) {
return nullptr;
}
id_us_min(local_id);
/* TODO: Handle this properly in LIB_NO_MAIN case as well (i.e. resync case). Or offload to
* generic ID copy code? Would probably be better to have a version of #BKE_id_copy_ex that takes
* an extra `target_lib` parameter. */
local_id->lib = owner_library;
if ((lib_id_copy_flags & LIB_ID_CREATE_NO_MAIN) != 0 && owner_library == nullptr) {
/* In `NO_MAIN` case, generic `BKE_id_copy` code won't call this.

Is this TODO still relevant?

Is this TODO still relevant?

Probably not, nor the code in the if just below... But would rather cleanup this in a separate commit tbh :)

_Probably_ not, nor the code in the `if` just below... But would rather cleanup this in a separate commit tbh :)
* In liboverride resync case however, the currently not-in-Main new IDs will be added back to
* Main later, so ensure that their linked dependencies and paths are properly handled here.
*
* NOTE: This is likely not the best place to do this. Ideally, #BKE_libblock_management_main_add
* e.g. should take care of this. But for the time being, this works and has been battle-proofed.
*/
if ((lib_id_copy_flags & LIB_ID_CREATE_NO_MAIN) != 0 && !ID_IS_LINKED(local_id)) {
lib_id_copy_ensure_local(bmain, reference_id, local_id, 0);
}

View File

@ -7,6 +7,7 @@
*/
#include <cstdlib>
#include <optional>
#include "MEM_guardedalloc.h"
@ -53,7 +54,11 @@ static void light_init_data(ID *id)
*
* \param flag: Copying options (see BKE_lib_id.hh's LIB_ID_COPY_... flags for more).
*/
static void light_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void light_copy_data(Main *bmain,
std::optional<Library *> owner_library,
ID *id_dst,
const ID *id_src,
const int flag)
{
Light *la_dst = (Light *)id_dst;
const Light *la_src = (const Light *)id_src;
@ -67,8 +72,11 @@ static void light_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
la_dst->nodetree = ntreeLocalize(la_src->nodetree);
}
else {
BKE_id_copy_ex(
bmain, (ID *)la_src->nodetree, (ID **)&la_dst->nodetree, flag_private_id_data);
BKE_id_copy_in_lib(bmain,
owner_library,
(ID *)la_src->nodetree,
(ID **)&la_dst->nodetree,
flag_private_id_data);
}
la_dst->nodetree->owner_id = &la_dst->id;
}

View File

@ -9,6 +9,8 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <optional>
#include <fmt/format.h>
#include "MEM_guardedalloc.h"
@ -50,7 +52,11 @@ static void linestyle_init_data(ID *id)
BKE_linestyle_geometry_modifier_add(linestyle, nullptr, LS_MODIFIER_SAMPLING);
}
static void linestyle_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void linestyle_copy_data(Main *bmain,
std::optional<Library *> owner_library,
ID *id_dst,
const ID *id_src,
const int flag)
{
FreestyleLineStyle *linestyle_dst = (FreestyleLineStyle *)id_dst;
const FreestyleLineStyle *linestyle_src = (const FreestyleLineStyle *)id_src;
@ -68,10 +74,11 @@ static void linestyle_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const
}
if (linestyle_src->nodetree) {
BKE_id_copy_ex(bmain,
(ID *)linestyle_src->nodetree,
(ID **)&linestyle_dst->nodetree,
flag_private_id_data);
BKE_id_copy_in_lib(bmain,
owner_library,
(ID *)linestyle_src->nodetree,
(ID **)&linestyle_dst->nodetree,
flag_private_id_data);
linestyle_dst->nodetree->owner_id = &linestyle_dst->id;
}

View File

@ -401,6 +401,7 @@ bool BKE_main_namemap_get_name(Main *bmain, ID *id, char *name, const bool do_un
* truncated name again. */
is_name_changed = true;
}
return is_name_changed;
}

View File

@ -8,6 +8,7 @@
#include <cstddef>
#include <cstring>
#include <optional>
#include "CLG_log.h"
@ -49,7 +50,11 @@
static CLG_LogRef LOG = {"bke.mask"};
static void mask_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/)
static void mask_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)
{
Mask *mask_dst = (Mask *)id_dst;
const Mask *mask_src = (const Mask *)id_src;

View File

@ -9,6 +9,7 @@
#include <cmath>
#include <cstddef>
#include <cstring>
#include <optional>
#include "CLG_log.h"
@ -91,7 +92,11 @@ static void material_init_data(ID *id)
*((short *)id->name) = ID_MA;
}
static void material_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void material_copy_data(Main *bmain,
std::optional<Library *> owner_library,
ID *id_dst,
const ID *id_src,
const int flag)
{
Material *material_dst = (Material *)id_dst;
const Material *material_src = (const Material *)id_src;
@ -105,10 +110,11 @@ static void material_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const
material_dst->nodetree = ntreeLocalize(material_src->nodetree);
}
else {
BKE_id_copy_ex(bmain,
(ID *)material_src->nodetree,
(ID **)&material_dst->nodetree,
flag_private_id_data);
BKE_id_copy_in_lib(bmain,
owner_library,
(ID *)material_src->nodetree,
(ID **)&material_dst->nodetree,
flag_private_id_data);
}
material_dst->nodetree->owner_id = &material_dst->id;
}

View File

@ -15,6 +15,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -64,7 +65,11 @@ static void metaball_init_data(ID *id)
MEMCPY_STRUCT_AFTER(metaball, DNA_struct_default_get(MetaBall), id);
}
static void metaball_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/)
static void metaball_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)
{
MetaBall *metaball_dst = (MetaBall *)id_dst;
const MetaBall *metaball_src = (const MetaBall *)id_src;

View File

@ -6,6 +6,8 @@
* \ingroup bke
*/
#include <optional>
#include "MEM_guardedalloc.h"
/* Allow using deprecated functionality for .blend file I/O. */
@ -99,7 +101,11 @@ static void mesh_init_data(ID *id)
mesh->face_sets_color_seed = BLI_hash_int(BLI_time_now_seconds_i() & UINT_MAX);
}
static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void mesh_copy_data(Main *bmain,
std::optional<Library *> owner_library,
ID *id_dst,
const ID *id_src,
const int flag)
{
Mesh *mesh_dst = reinterpret_cast<Mesh *>(id_dst);
const Mesh *mesh_src = reinterpret_cast<const Mesh *>(id_src);
@ -193,7 +199,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
/* TODO: Do we want to add flag to prevent this? */
if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &mesh_src->key->id, (ID **)&mesh_dst->key, flag);
BKE_id_copy_in_lib(bmain, owner_library, &mesh_src->key->id, (ID **)&mesh_dst->key, flag);
/* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
mesh_dst->key->from = &mesh_dst->id;
}

View File

@ -9,6 +9,7 @@
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <optional>
#ifndef WIN32
# include <unistd.h>
@ -81,7 +82,11 @@ static void movie_clip_init_data(ID *id)
BKE_color_managed_colorspace_settings_init(&movie_clip->colorspace_settings);
}
static void movie_clip_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag)
static void movie_clip_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int flag)
{
MovieClip *movie_clip_dst = (MovieClip *)id_dst;
const MovieClip *movie_clip_src = (const MovieClip *)id_src;

View File

@ -14,6 +14,7 @@
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <optional>
/* Allow using deprecated functionality for .blend file I/O. */
#define DNA_DEPRECATED_ALLOW
@ -150,7 +151,11 @@ static void ntree_init_data(ID *id)
ntree_set_typeinfo(ntree, nullptr);
}
static void ntree_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int flag)
static void ntree_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int flag)
{
bNodeTree *ntree_dst = reinterpret_cast<bNodeTree *>(id_dst);
const bNodeTree *ntree_src = reinterpret_cast<const bNodeTree *>(id_src);

View File

@ -12,6 +12,7 @@
#include <cmath>
#include <cstdio>
#include <cstring>
#include <optional>
#include "CLG_log.h"
@ -188,7 +189,11 @@ static void object_init_data(ID *id)
animviz_settings_init(&ob->avs);
}
static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void object_copy_data(Main *bmain,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int flag)
{
Object *ob_dst = (Object *)id_dst;
const Object *ob_src = (const Object *)id_src;

View File

@ -8,6 +8,7 @@
#include <cstdlib>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -100,7 +101,11 @@ static void palette_init_data(ID *id)
id_fake_user_set(&palette->id);
}
static void palette_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/)
static void palette_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)
{
Palette *palette_dst = (Palette *)id_dst;
const Palette *palette_src = (const Palette *)id_src;
@ -172,6 +177,7 @@ IDTypeInfo IDType_ID_PAL = {
};
static void paint_curve_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)

View File

@ -13,6 +13,7 @@
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -99,6 +100,7 @@ static void particle_settings_init(ID *id)
}
static void particle_settings_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)

View File

@ -6,6 +6,8 @@
* \ingroup bke
*/
#include <optional>
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
@ -68,6 +70,7 @@ static void pointcloud_init_data(ID *id)
}
static void pointcloud_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)

View File

@ -12,6 +12,7 @@
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -251,7 +252,11 @@ static void scene_copy_markers(Scene *scene_dst, const Scene *scene_src, const i
}
}
static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void scene_copy_data(Main *bmain,
std::optional<Library *> owner_library,
ID *id_dst,
const ID *id_src,
const int flag)
{
Scene *scene_dst = (Scene *)id_dst;
const Scene *scene_src = (const Scene *)id_src;
@ -266,10 +271,11 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
/* Master Collection */
if (scene_src->master_collection) {
BKE_id_copy_ex(bmain,
(ID *)scene_src->master_collection,
(ID **)&scene_dst->master_collection,
flag_private_id_data);
BKE_id_copy_in_lib(bmain,
owner_library,
reinterpret_cast<ID *>(scene_src->master_collection),
reinterpret_cast<ID **>(&scene_dst->master_collection),
flag_private_id_data);
scene_dst->master_collection->owner_id = &scene_dst->id;
}
@ -293,8 +299,11 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
BKE_keyingsets_copy(&(scene_dst->keyingsets), &(scene_src->keyingsets));
if (scene_src->nodetree) {
BKE_id_copy_ex(
bmain, (ID *)scene_src->nodetree, (ID **)&scene_dst->nodetree, flag_private_id_data);
BKE_id_copy_in_lib(bmain,
owner_library,
(ID *)scene_src->nodetree,
(ID **)&scene_dst->nodetree,
flag_private_id_data);
BKE_libblock_relink_ex(bmain,
scene_dst->nodetree,
(void *)(&scene_src->id),

View File

@ -8,6 +8,7 @@
#include <cstdlib>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -58,7 +59,11 @@
static void sound_free_audio(bSound *sound);
static void sound_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/)
static void sound_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)
{
bSound *sound_dst = (bSound *)id_dst;
const bSound *sound_src = (const bSound *)id_src;

View File

@ -9,6 +9,7 @@
#include <cstdlib> /* abort */
#include <cstring> /* strstr */
#include <cwctype>
#include <optional>
#include <sys/stat.h>
#include <sys/types.h>
@ -101,7 +102,11 @@ static void text_init_data(ID *id)
*
* \param flag: Copying options (see BKE_lib_id.hh's LIB_ID_COPY_... flags for more).
*/
static void text_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/)
static void text_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)
{
Text *text_dst = (Text *)id_dst;
const Text *text_src = (Text *)id_src;

View File

@ -10,6 +10,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -65,7 +66,11 @@ static void texture_init_data(ID *id)
BKE_imageuser_default(&texture->iuser);
}
static void texture_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void texture_copy_data(Main *bmain,
std::optional<Library *> owner_library,
ID *id_dst,
const ID *id_src,
const int flag)
{
Tex *texture_dst = (Tex *)id_dst;
const Tex *texture_src = (const Tex *)id_src;
@ -90,8 +95,11 @@ static void texture_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const i
texture_dst->nodetree = ntreeLocalize(texture_src->nodetree);
}
else {
BKE_id_copy_ex(
bmain, (ID *)texture_src->nodetree, (ID **)&texture_dst->nodetree, flag_private_id_data);
BKE_id_copy_in_lib(bmain,
owner_library,
(ID *)texture_src->nodetree,
(ID **)&texture_dst->nodetree,
flag_private_id_data);
}
texture_dst->nodetree->owner_id = &texture_dst->id;
}

View File

@ -12,6 +12,7 @@
#include <cstdlib>
#include <cstring>
#include <cwctype>
#include <optional>
#include "CLG_log.h"
@ -82,7 +83,11 @@ static void vfont_init_data(ID *id)
}
}
static void vfont_copy_data(Main * /*bmain*/, ID *id_dst, const ID * /*id_src*/, const int flag)
static void vfont_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID * /*id_src*/,
const int flag)
{
VFont *vfont_dst = (VFont *)id_dst;

View File

@ -6,6 +6,8 @@
* \ingroup bke
*/
#include <optional>
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
@ -148,7 +150,11 @@ static void volume_init_data(ID *id)
STRNCPY(volume->velocity_grid, "velocity");
}
static void volume_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, const int /*flag*/)
static void volume_copy_data(Main * /*bmain*/,
std::optional<Library *> /*owner_library*/,
ID *id_dst,
const ID *id_src,
const int /*flag*/)
{
Volume *volume_dst = (Volume *)id_dst;
const Volume *volume_src = (const Volume *)id_src;

View File

@ -9,6 +9,7 @@
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <optional>
#include "MEM_guardedalloc.h"
@ -81,7 +82,11 @@ static void world_init_data(ID *id)
*
* \param flag: Copying options (see BKE_lib_id.hh's LIB_ID_COPY_... flags for more).
*/
static void world_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
static void world_copy_data(Main *bmain,
std::optional<Library *> owner_library,
ID *id_dst,
const ID *id_src,
const int flag)
{
World *wrld_dst = (World *)id_dst;
const World *wrld_src = (const World *)id_src;
@ -95,8 +100,11 @@ static void world_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
wrld_dst->nodetree = ntreeLocalize(wrld_src->nodetree);
}
else {
BKE_id_copy_ex(
bmain, (ID *)wrld_src->nodetree, (ID **)&wrld_dst->nodetree, flag_private_id_data);
BKE_id_copy_in_lib(bmain,
owner_library,
(ID *)wrld_src->nodetree,
(ID **)&wrld_dst->nodetree,
flag_private_id_data);
}
wrld_dst->nodetree->owner_id = &wrld_dst->id;
}