2023-05-31 16:19:06 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2005-12-12 16:29:47 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup bke
|
2012-03-24 02:51:46 +00:00
|
|
|
*
|
|
|
|
|
* Contains management of ID's and libraries
|
|
|
|
|
* allocate and free of all library data
|
2011-02-27 20:40:57 +00:00
|
|
|
*/
|
|
|
|
|
|
2023-07-22 11:27:25 +10:00
|
|
|
#include <cctype>
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <cstring>
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2019-02-01 12:44:19 +11:00
|
|
|
#include "CLG_log.h"
|
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
|
|
/* all types are needed here, in order to do memory operations */
|
2020-04-21 14:56:02 +02:00
|
|
|
#include "DNA_ID.h"
|
2010-08-04 04:01:27 +00:00
|
|
|
#include "DNA_anim_types.h"
|
2020-12-15 10:47:58 +11:00
|
|
|
#include "DNA_collection_types.h"
|
2023-03-13 10:42:51 +01:00
|
|
|
#include "DNA_gpencil_legacy_types.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "DNA_key_types.h"
|
2010-08-04 04:01:27 +00:00
|
|
|
#include "DNA_node_types.h"
|
Main Workspace Integration
This commit does the main integration of workspaces, which is a design we agreed on during the 2.8 UI workshop (see https://wiki.blender.org/index.php/Dev:2.8/UI/Workshop_Writeup)
Workspaces should generally be stable, I'm not aware of any remaining bugs (or I've forgotten them :) ). If you find any, let me know!
(Exception: mode switching button might get out of sync with actual mode in some cases, would consider that a limitation/ToDo. Needs to be resolved at some point.)
== Main Changes/Features
* Introduces the new Workspaces as data-blocks.
* Allow storing a number of custom workspaces as part of the user configuration. Needs further work to allow adding and deleting individual workspaces.
* Bundle a default workspace configuration with Blender (current screen-layouts converted to workspaces).
* Pressing button to add a workspace spawns a menu to select between "Duplicate Current" and the workspaces from the user configuration. If no workspaces are stored in the user configuration, the default workspaces are listed instead.
* Store screen-layouts (`bScreen`) per workspace.
* Store an active screen-layout per workspace. Changing the workspace will enable this layout.
* Store active mode in workspace. Changing the workspace will also enter the mode of the new workspace. (Note that we still store the active mode in the object, moving this completely to workspaces is a separate project.)
* Store an active render layer per workspace.
* Moved mode switch from 3D View header to Info Editor header.
* Store active scene in window (not directly workspace related, but overlaps quite a bit).
* Removed 'Use Global Scene' User Preference option.
* Compatibility with old files - a new workspace is created for every screen-layout of old files. Old Blender versions should be able to read files saved with workspace support as well.
* Default .blend only contains one workspace ("General").
* Support appending workspaces.
Opening files without UI and commandline rendering should work fine.
Note that the UI is temporary! We plan to introduce a new global topbar
that contains the workspace options and tabs for switching workspaces.
== Technical Notes
* Workspaces are data-blocks.
* Adding and removing `bScreen`s should be done through `ED_workspace_layout` API now.
* A workspace can be active in multiple windows at the same time.
* The mode menu (which is now in the Info Editor header) doesn't display "Grease Pencil Edit" mode anymore since its availability depends on the active editor. Will be fixed by making Grease Pencil an own object type (as planned).
* The button to change the active workspace object mode may get out of sync with the mode of the active object. Will either be resolved by moving mode out of object data, or we'll disable workspace modes again (there's a `#define USE_WORKSPACE_MODE` for that).
* Screen-layouts (`bScreen`) are IDs and thus stored in a main list-base. Had to add a wrapper `WorkSpaceLayout` so we can store them in a list-base within workspaces, too. On the long run we could completely replace `bScreen` by workspace structs.
* `WorkSpace` types use some special compiler trickery to allow marking structs and struct members as private. BKE_workspace API should be used for accessing those.
* Added scene operators `SCENE_OT_`. Was previously done through screen operators.
== BPY API Changes
* Removed `Screen.scene`, added `Window.scene`
* Removed `UserPreferencesView.use_global_scene`
* Added `Context.workspace`, `Window.workspace` and `BlendData.workspaces`
* Added `bpy.types.WorkSpace` containing `screens`, `object_mode` and `render_layer`
* Added Screen.layout_name for the layout name that'll be displayed in the UI (may differ from internal name)
== What's left?
* There are a few open design questions (T50521). We should find the needed answers and implement them.
* Allow adding and removing individual workspaces from workspace configuration (needs UI design).
* Get the override system ready and support overrides per workspace.
* Support custom UI setups as part of workspaces (hidden panels, hidden buttons, customizable toolbars, etc).
* Allow enabling add-ons per workspace.
* Support custom workspace keymaps.
* Remove special exception for workspaces in linking code (so they're always appended, never linked). Depends on a few things, so best to solve later.
* Get the topbar done.
* Workspaces need a proper icon, current one is just a placeholder :)
Reviewed By: campbellbarton, mont29
Tags: #user_interface, #bf_blender_2.8
Maniphest Tasks: T50521
Differential Revision: https://developer.blender.org/D2451
2017-06-01 19:56:58 +02:00
|
|
|
#include "DNA_workspace_types.h"
|
2010-08-04 04:01:27 +00:00
|
|
|
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2019-12-17 11:22:42 +01:00
|
|
|
|
2020-03-20 11:55:34 +01:00
|
|
|
#include "BLI_alloca.h"
|
2023-11-30 22:18:21 +01:00
|
|
|
#include "BLI_array.hh"
|
2019-12-17 11:22:42 +01:00
|
|
|
#include "BLI_blenlib.h"
|
2016-11-01 13:39:31 +01:00
|
|
|
#include "BLI_ghash.h"
|
2016-10-19 14:29:43 +02:00
|
|
|
#include "BLI_linklist.h"
|
|
|
|
|
#include "BLI_memarena.h"
|
2023-10-18 17:15:30 +02:00
|
|
|
#include "BLI_string_utils.hh"
|
2018-05-04 12:53:20 +02:00
|
|
|
|
2015-08-16 17:32:01 +10:00
|
|
|
#include "BLT_translation.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2020-04-03 13:07:36 +02:00
|
|
|
#include "BKE_anim_data.h"
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_armature.hh"
|
|
|
|
|
#include "BKE_asset.hh"
|
2013-03-25 08:29:06 +00:00
|
|
|
#include "BKE_bpath.h"
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_context.hh"
|
2013-01-13 12:25:56 +00:00
|
|
|
#include "BKE_global.h"
|
2023-03-13 10:42:51 +01:00
|
|
|
#include "BKE_gpencil_legacy.h"
|
2013-01-13 12:25:56 +00:00
|
|
|
#include "BKE_idprop.h"
|
2020-03-05 10:54:00 +01:00
|
|
|
#include "BKE_idtype.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "BKE_key.h"
|
2020-02-10 12:58:59 +01:00
|
|
|
#include "BKE_lib_id.h"
|
2023-08-02 15:00:40 +02:00
|
|
|
#include "BKE_lib_override.hh"
|
2020-02-10 12:58:59 +01:00
|
|
|
#include "BKE_lib_query.h"
|
2023-11-30 19:51:22 +01:00
|
|
|
#include "BKE_lib_remap.hh"
|
2023-12-01 19:43:16 +01:00
|
|
|
#include "BKE_main.hh"
|
2023-11-27 16:21:49 +01:00
|
|
|
#include "BKE_main_namemap.hh"
|
Orange: more noodle updates!
**** NEW: Group Nodes
Node trees usually become messy and confusing quickly, so we need
not only a way to collapse Nodes into single 'groups', but also a
way to re-use that data to create libraries of effects.
This has been done by making a new Library data type, the NodeTree.
Everything that has been grouped is stored here, and available for
re-use, appending or linking. These NodeTrees are fully generic,
i.e. can store shader trees, composit trees, and so on. The 'type'
value as stored in the NodeTree will keep track of internal type
definitions and execute/drawing callbacks. Needless to say, re-using
shader trees in a composit tree is a bit useless, and will be
prevented in the browsing code. :)
So; any NodeTree can become a "Goup Node" inside in a NodeTree. This
Group Node then works just like any Node.
To prevent the current code to become too complex, I've disabled
the possibility to insert Groups inside of Groups. That might be
enabled later, but is a real nasty piece of code to get OK.
Since Group Nodes are a dynamic Node type, a lot of work has been
done to ensure Node definitions can be dynamic too, but still allow
to be stored in files, and allow to be verified for type-definition
changes on reloading. This system needs a little bit maturing still,
so the Python gurus should better wait a little bit! (Also for me to
write the definite API docs for it).
What works now:
- Press CTRL+G to create a new Group. The grouping code checks for
impossible selections (like an unselected node between selected nodes).
Everthing that's selected then gets removed from the current tree, and
inserted in a new NodeTree library data block. A Group Node then is
added which links to this new NodeTree.
- Press ALT+G to ungroup. This will not delete the NodeTree library
data, but just duplicate the Group into the current tree.
- Press TAB, or click on the NodeTree icon to edit Groups. Note that
NodeTrees are instances, so editing one Group will also change the
other users.
This also means that when removing nodes in a Group (or hiding sockets
or changing internal links) this is immediately corrected for all users
of this Group, also in other Materials.
- While editing Groups, only the internal Nodes can be edited. A single
click outside of the Group boundary will close this 'edit mode'.
What needs to be done:
- SHIFT+A menu in toolbox style, also including a list of Groups
- Enable the single-user button in the Group Node
- Displaying all (visible) internal group UI elements in the Node Panel
- Enable Library linking and prevent editing of Groups then.
**** NEW: Socket Visibility control
Node types will be generated with a lot of possible inputs or outputs,
and drawing all sockets all the time isn't very useful then.
A new option in the Node header ('plus' icon) allows to either hide all
unused sockets (first keypress) or to reveil them (when there are hidden
sockets, the icon displays black, otherwise it's blended).
Hidden sockets in Nodes also are not exported to a Group, so this way
you can control what options (in/outputs) exactly are available.
To be done:
- a way to hide individual sockets, like with a RMB click on it.
**** NEW: Nodes now render!
This is still quite primitive, more on a level to replace the (now
obsolete and disabled) Material Layers.
What needs to be done:
- make the "Geometry" node work properly, also for AA textures
- make the Texture Node work (does very little at the moment)
- give Material Nodes all inputs as needed (like Map-to Panel)
- find a way to export more data from a Material Node, like the
shadow value, or light intensity only, etc
Very important also to separate from the Material Buttons the
"global" options, like "Ztransp" or "Wire" or "Halo". These can not
be set for each Material-Node individually.
Also note that the Preview Render (Buttons window) now renders a bit
differently. This was a horrid piece of antique code, using a totally
incompatible way of rendering. Target is to fully re-use internal
render code for previews.
OK... that's it mostly. Now test!
2006-01-02 13:06:05 +00:00
|
|
|
#include "BKE_node.h"
|
2019-02-19 19:33:31 -03:00
|
|
|
#include "BKE_rigidbody.h"
|
Orange: more noodle updates!
**** NEW: Group Nodes
Node trees usually become messy and confusing quickly, so we need
not only a way to collapse Nodes into single 'groups', but also a
way to re-use that data to create libraries of effects.
This has been done by making a new Library data type, the NodeTree.
Everything that has been grouped is stored here, and available for
re-use, appending or linking. These NodeTrees are fully generic,
i.e. can store shader trees, composit trees, and so on. The 'type'
value as stored in the NodeTree will keep track of internal type
definitions and execute/drawing callbacks. Needless to say, re-using
shader trees in a composit tree is a bit useless, and will be
prevented in the browsing code. :)
So; any NodeTree can become a "Goup Node" inside in a NodeTree. This
Group Node then works just like any Node.
To prevent the current code to become too complex, I've disabled
the possibility to insert Groups inside of Groups. That might be
enabled later, but is a real nasty piece of code to get OK.
Since Group Nodes are a dynamic Node type, a lot of work has been
done to ensure Node definitions can be dynamic too, but still allow
to be stored in files, and allow to be verified for type-definition
changes on reloading. This system needs a little bit maturing still,
so the Python gurus should better wait a little bit! (Also for me to
write the definite API docs for it).
What works now:
- Press CTRL+G to create a new Group. The grouping code checks for
impossible selections (like an unselected node between selected nodes).
Everthing that's selected then gets removed from the current tree, and
inserted in a new NodeTree library data block. A Group Node then is
added which links to this new NodeTree.
- Press ALT+G to ungroup. This will not delete the NodeTree library
data, but just duplicate the Group into the current tree.
- Press TAB, or click on the NodeTree icon to edit Groups. Note that
NodeTrees are instances, so editing one Group will also change the
other users.
This also means that when removing nodes in a Group (or hiding sockets
or changing internal links) this is immediately corrected for all users
of this Group, also in other Materials.
- While editing Groups, only the internal Nodes can be edited. A single
click outside of the Group boundary will close this 'edit mode'.
What needs to be done:
- SHIFT+A menu in toolbox style, also including a list of Groups
- Enable the single-user button in the Group Node
- Displaying all (visible) internal group UI elements in the Node Panel
- Enable Library linking and prevent editing of Groups then.
**** NEW: Socket Visibility control
Node types will be generated with a lot of possible inputs or outputs,
and drawing all sockets all the time isn't very useful then.
A new option in the Node header ('plus' icon) allows to either hide all
unused sockets (first keypress) or to reveil them (when there are hidden
sockets, the icon displays black, otherwise it's blended).
Hidden sockets in Nodes also are not exported to a Group, so this way
you can control what options (in/outputs) exactly are available.
To be done:
- a way to hide individual sockets, like with a RMB click on it.
**** NEW: Nodes now render!
This is still quite primitive, more on a level to replace the (now
obsolete and disabled) Material Layers.
What needs to be done:
- make the "Geometry" node work properly, also for AA textures
- make the Texture Node work (does very little at the moment)
- give Material Nodes all inputs as needed (like Map-to Panel)
- find a way to export more data from a Material Node, like the
shadow value, or light intensity only, etc
Very important also to separate from the Material Buttons the
"global" options, like "Ztransp" or "Wire" or "Halo". These can not
be set for each Material-Node individually.
Also note that the Preview Render (Buttons window) now renders a bit
differently. This was a horrid piece of antique code, using a totally
incompatible way of rendering. Target is to fully re-use internal
render code for previews.
OK... that's it mostly. Now test!
2006-01-02 13:06:05 +00:00
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph.hh"
|
|
|
|
|
#include "DEG_depsgraph_build.hh"
|
|
|
|
|
#include "DEG_depsgraph_query.hh"
|
Depsgraph: New dependency graph integration commit
This commit integrates the work done so far on the new dependency graph system,
where goal was to replace legacy depsgraph with the new one, supporting loads of
neat features like:
- More granular dependency relation nature, which solves issues with fake cycles
in the dependencies.
- Move towards all-animatable, by better integration of drivers into the system.
- Lay down some basis for upcoming copy-on-write, overrides and so on.
The new system is living side-by-side with the previous one and disabled by
default, so nothing will become suddenly broken. The way to enable new depsgraph
is to pass `--new-depsgraph` command line argument.
It's a bit early to consider the system production-ready, there are some TODOs
and issues were discovered during the merge period, they'll be addressed ASAP.
But it's important to merge, because it's the only way to attract artists to
really start testing this system.
There are number of assorted documents related on the design of the new system:
* http://wiki.blender.org/index.php/User:Aligorith/GSoC2013_Depsgraph#Design_Documents
* http://wiki.blender.org/index.php/User:Nazg-gul/DependencyGraph
There are also some user-related information online:
* http://code.blender.org/2015/02/blender-dependency-graph-branch-for-users/
* http://code.blender.org/2015/03/more-dependency-graph-tricks/
Kudos to everyone who was involved into the project:
- Joshua "Aligorith" Leung -- design specification, initial code
- Lukas "lukas_t" Toenne -- integrating code into blender, with further fixes
- Sergey "Sergey" "Sharybin" -- some mocking around, trying to wrap up the
project and so
- Bassam "slikdigit" Kurdali -- stressing the new system, reporting all the
issues and recording/writing documentation.
- Everyone else who i forgot to mention here :)
2015-05-12 15:05:57 +05:00
|
|
|
|
2023-08-10 22:40:27 +02:00
|
|
|
#include "RNA_access.hh"
|
2011-06-29 05:07:12 +00:00
|
|
|
|
2023-08-28 15:01:05 +02:00
|
|
|
#include "BLO_read_write.hh"
|
2020-08-28 15:45:11 +02:00
|
|
|
|
2016-11-08 17:54:14 +01:00
|
|
|
#include "atomic_ops.h"
|
|
|
|
|
|
2023-11-30 19:51:22 +01:00
|
|
|
#include "lib_intern.hh"
|
2023-05-11 12:23:50 +02:00
|
|
|
|
2017-05-04 15:07:21 +02:00
|
|
|
//#define DEBUG_TIME
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_TIME
|
|
|
|
|
# include "PIL_time_utildefines.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
static CLG_LogRef LOG = {"bke.lib_id"};
|
2019-02-01 12:44:19 +11:00
|
|
|
|
2020-03-19 19:37:00 +01:00
|
|
|
IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
|
2023-07-17 10:46:26 +02:00
|
|
|
/*id_code*/ ID_LINK_PLACEHOLDER,
|
|
|
|
|
/*id_filter*/ 0,
|
|
|
|
|
/*main_listbase_index*/ INDEX_ID_NULL,
|
|
|
|
|
/*struct_size*/ sizeof(ID),
|
|
|
|
|
/*name*/ "LinkPlaceholder",
|
2023-10-22 08:47:26 +02:00
|
|
|
/*name_plural*/ N_("link_placeholders"),
|
2023-07-17 10:46:26 +02:00
|
|
|
/*translation_context*/ BLT_I18NCONTEXT_ID_ID,
|
|
|
|
|
/*flags*/ IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING,
|
|
|
|
|
/*asset_type_info*/ nullptr,
|
|
|
|
|
|
|
|
|
|
/*init_data*/ nullptr,
|
|
|
|
|
/*copy_data*/ nullptr,
|
|
|
|
|
/*free_data*/ nullptr,
|
|
|
|
|
/*make_local*/ nullptr,
|
|
|
|
|
/*foreach_id*/ nullptr,
|
|
|
|
|
/*foreach_cache*/ nullptr,
|
|
|
|
|
/*foreach_path*/ nullptr,
|
|
|
|
|
/*owner_pointer_get*/ nullptr,
|
|
|
|
|
|
|
|
|
|
/*blend_write*/ nullptr,
|
|
|
|
|
/*blend_read_data*/ nullptr,
|
2023-03-11 18:07:59 +01:00
|
|
|
/*blend_read_after_liblink*/ nullptr,
|
2023-07-17 10:46:26 +02:00
|
|
|
|
|
|
|
|
/*blend_read_undo_preserve*/ nullptr,
|
|
|
|
|
|
|
|
|
|
/*lib_override_apply_post*/ nullptr,
|
2020-03-19 19:37:00 +01:00
|
|
|
};
|
|
|
|
|
|
2018-06-17 17:05:51 +02:00
|
|
|
/* GS reads the memory pointed at in a specific ordering.
|
2012-03-03 20:19:11 +00:00
|
|
|
* only use this definition, makes little and big endian systems
|
|
|
|
|
* work fine, in conjunction with MAKE_ID */
|
2009-09-04 21:02:43 +00:00
|
|
|
|
2003-04-26 11:56:44 +00:00
|
|
|
/* ************* general ************************ */
|
2002-10-12 11:37:38 +00:00
|
|
|
|
Refactor BKE_bpath module.
The main goal of this refactor is to make BPath module use `IDTypeInfo`,
and move each ID-specific part of the `foreach_path` looper into their
own IDTypeInfo struct, using a new `foreach_path` callback.
Additionally, following improvements/cleanups are included:
* Attempt to get better, more consistent namings.
** In particular, move from `path_visitor` to more standard `foreach_path`.
* Update and extend documentation.
** API doc was moved to header, according to recent discussions on this
topic.
* Remove `BKE_bpath_relocate_visitor` from API, this is specific
callback that belongs in `lib_id.c` user code.
NOTE: This commit is expected to be 100% non-behavioral-change. This
implies that several potential further changes were only noted as
comments (like using a more generic solution for
`lib_id_library_local_paths`, addressing inconsistencies like path of
packed libraries always being skipped, regardless of the
`BKE_BPATH_FOREACH_PATH_SKIP_PACKED` `eBPathForeachFlag` flag value,
etc.).
NOTE: basic unittests were added to master already in
rBdcc500e5a265093bc9cc.
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D13381
2021-11-29 14:20:58 +01:00
|
|
|
/**
|
|
|
|
|
* Rewrites a relative path to be relative to the main file - unless the path is
|
|
|
|
|
* absolute, in which case it is not altered.
|
|
|
|
|
*/
|
|
|
|
|
static bool lib_id_library_local_paths_callback(BPathForeachPathData *bpath_data,
|
2023-06-23 10:09:01 +10:00
|
|
|
char *path_dst,
|
|
|
|
|
size_t path_dst_maxncpy,
|
Refactor BKE_bpath module.
The main goal of this refactor is to make BPath module use `IDTypeInfo`,
and move each ID-specific part of the `foreach_path` looper into their
own IDTypeInfo struct, using a new `foreach_path` callback.
Additionally, following improvements/cleanups are included:
* Attempt to get better, more consistent namings.
** In particular, move from `path_visitor` to more standard `foreach_path`.
* Update and extend documentation.
** API doc was moved to header, according to recent discussions on this
topic.
* Remove `BKE_bpath_relocate_visitor` from API, this is specific
callback that belongs in `lib_id.c` user code.
NOTE: This commit is expected to be 100% non-behavioral-change. This
implies that several potential further changes were only noted as
comments (like using a more generic solution for
`lib_id_library_local_paths`, addressing inconsistencies like path of
packed libraries always being skipped, regardless of the
`BKE_BPATH_FOREACH_PATH_SKIP_PACKED` `eBPathForeachFlag` flag value,
etc.).
NOTE: basic unittests were added to master already in
rBdcc500e5a265093bc9cc.
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D13381
2021-11-29 14:20:58 +01:00
|
|
|
const char *path_src)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
const char **data = static_cast<const char **>(bpath_data->user_data);
|
Refactor BKE_bpath module.
The main goal of this refactor is to make BPath module use `IDTypeInfo`,
and move each ID-specific part of the `foreach_path` looper into their
own IDTypeInfo struct, using a new `foreach_path` callback.
Additionally, following improvements/cleanups are included:
* Attempt to get better, more consistent namings.
** In particular, move from `path_visitor` to more standard `foreach_path`.
* Update and extend documentation.
** API doc was moved to header, according to recent discussions on this
topic.
* Remove `BKE_bpath_relocate_visitor` from API, this is specific
callback that belongs in `lib_id.c` user code.
NOTE: This commit is expected to be 100% non-behavioral-change. This
implies that several potential further changes were only noted as
comments (like using a more generic solution for
`lib_id_library_local_paths`, addressing inconsistencies like path of
packed libraries always being skipped, regardless of the
`BKE_BPATH_FOREACH_PATH_SKIP_PACKED` `eBPathForeachFlag` flag value,
etc.).
NOTE: basic unittests were added to master already in
rBdcc500e5a265093bc9cc.
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D13381
2021-11-29 14:20:58 +01:00
|
|
|
/* be sure there is low chance of the path being too short */
|
|
|
|
|
char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
|
|
|
|
|
const char *base_new = data[0];
|
|
|
|
|
const char *base_old = data[1];
|
|
|
|
|
|
|
|
|
|
if (BLI_path_is_rel(base_old)) {
|
|
|
|
|
CLOG_ERROR(&LOG, "old base path '%s' is not absolute.", base_old);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make referenced file absolute. This would be a side-effect of
|
|
|
|
|
* BLI_path_normalize, but we do it explicitly so we know if it changed. */
|
|
|
|
|
BLI_strncpy(filepath, path_src, FILE_MAX);
|
|
|
|
|
if (BLI_path_abs(filepath, base_old)) {
|
|
|
|
|
/* Path was relative and is now absolute. Remap.
|
|
|
|
|
* Important BLI_path_normalize runs before the path is made relative
|
|
|
|
|
* because it won't work for paths that start with "//../" */
|
2023-04-24 11:31:31 +10:00
|
|
|
BLI_path_normalize(filepath);
|
Refactor BKE_bpath module.
The main goal of this refactor is to make BPath module use `IDTypeInfo`,
and move each ID-specific part of the `foreach_path` looper into their
own IDTypeInfo struct, using a new `foreach_path` callback.
Additionally, following improvements/cleanups are included:
* Attempt to get better, more consistent namings.
** In particular, move from `path_visitor` to more standard `foreach_path`.
* Update and extend documentation.
** API doc was moved to header, according to recent discussions on this
topic.
* Remove `BKE_bpath_relocate_visitor` from API, this is specific
callback that belongs in `lib_id.c` user code.
NOTE: This commit is expected to be 100% non-behavioral-change. This
implies that several potential further changes were only noted as
comments (like using a more generic solution for
`lib_id_library_local_paths`, addressing inconsistencies like path of
packed libraries always being skipped, regardless of the
`BKE_BPATH_FOREACH_PATH_SKIP_PACKED` `eBPathForeachFlag` flag value,
etc.).
NOTE: basic unittests were added to master already in
rBdcc500e5a265093bc9cc.
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D13381
2021-11-29 14:20:58 +01:00
|
|
|
BLI_path_rel(filepath, base_new);
|
2023-06-23 10:09:01 +10:00
|
|
|
BLI_strncpy(path_dst, filepath, path_dst_maxncpy);
|
Refactor BKE_bpath module.
The main goal of this refactor is to make BPath module use `IDTypeInfo`,
and move each ID-specific part of the `foreach_path` looper into their
own IDTypeInfo struct, using a new `foreach_path` callback.
Additionally, following improvements/cleanups are included:
* Attempt to get better, more consistent namings.
** In particular, move from `path_visitor` to more standard `foreach_path`.
* Update and extend documentation.
** API doc was moved to header, according to recent discussions on this
topic.
* Remove `BKE_bpath_relocate_visitor` from API, this is specific
callback that belongs in `lib_id.c` user code.
NOTE: This commit is expected to be 100% non-behavioral-change. This
implies that several potential further changes were only noted as
comments (like using a more generic solution for
`lib_id_library_local_paths`, addressing inconsistencies like path of
packed libraries always being skipped, regardless of the
`BKE_BPATH_FOREACH_PATH_SKIP_PACKED` `eBPathForeachFlag` flag value,
etc.).
NOTE: basic unittests were added to master already in
rBdcc500e5a265093bc9cc.
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D13381
2021-11-29 14:20:58 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Path was not relative to begin with. */
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-04 10:38:30 +01:00
|
|
|
/**
|
|
|
|
|
* This has to be called from each make_local_* func, we could call from BKE_lib_id_make_local()
|
|
|
|
|
* but then the make local functions would not be self contained.
|
2023-05-27 15:10:58 +10:00
|
|
|
*
|
|
|
|
|
* NOTE(@ideasman42): that the id _must_ have a library.
|
|
|
|
|
* TODO: This can probably be replaced by an ID-level version of #BKE_bpath_relative_rebase.
|
|
|
|
|
*/
|
2020-03-04 10:38:30 +01:00
|
|
|
static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
|
2011-11-01 06:26:55 +00:00
|
|
|
{
|
2020-06-23 09:54:07 +10:00
|
|
|
const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs};
|
2011-11-01 06:26:55 +00:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
BPathForeachPathData path_data{};
|
|
|
|
|
path_data.bmain = bmain;
|
|
|
|
|
path_data.callback_function = lib_id_library_local_paths_callback;
|
|
|
|
|
path_data.flag = BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE;
|
|
|
|
|
path_data.user_data = (void *)bpath_user_data;
|
|
|
|
|
BKE_bpath_foreach_path_id(&path_data, id);
|
2011-11-01 06:26:55 +00:00
|
|
|
}
|
|
|
|
|
|
Fix T77774: New undo code broken by 'make local' behavior.
This is actually a nice issue due to too much optimization...
* Making an ID local just reuse the linked one whenever possible, instead of
actually making a copy of it.
* Therefore, the collection containing that ID is seen as unchanged, since
the pointer itself remained the same.
* But on undo step, there is no way to reuse that local object, which then
gets deleted, and linked one gets re-created - at a different address.
* Collection, however, since unchanged, is not updated at all and thus keeps
reference to the to-be-deleted local object, instead of the linked one.
* Issue gets even worse with viewlayers, this leads to the crash.
To address this, this patch adds a 'virtual' update flags that does nothing
in update case, but will ensure that the affected IDs using the one made local
are properly detected as changed across the relevant undo step.
Note that the recalc flags were chosen mostly for a logical reason, and also
because they are already properly dealt with and cleared by undo code,
so this looks like the optimal solution.
Reviewed By: brecht
Maniphest Tasks: T77774
Differential Revision: https://developer.blender.org/D8006
2020-06-15 15:10:17 +02:00
|
|
|
static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *cb_data)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(cb_data->user_data);
|
Fix T77774: New undo code broken by 'make local' behavior.
This is actually a nice issue due to too much optimization...
* Making an ID local just reuse the linked one whenever possible, instead of
actually making a copy of it.
* Therefore, the collection containing that ID is seen as unchanged, since
the pointer itself remained the same.
* But on undo step, there is no way to reuse that local object, which then
gets deleted, and linked one gets re-created - at a different address.
* Collection, however, since unchanged, is not updated at all and thus keeps
reference to the to-be-deleted local object, instead of the linked one.
* Issue gets even worse with viewlayers, this leads to the crash.
To address this, this patch adds a 'virtual' update flags that does nothing
in update case, but will ensure that the affected IDs using the one made local
are properly detected as changed across the relevant undo step.
Note that the recalc flags were chosen mostly for a logical reason, and also
because they are already properly dealt with and cleared by undo code,
so this looks like the optimal solution.
Reviewed By: brecht
Maniphest Tasks: T77774
Differential Revision: https://developer.blender.org/D8006
2020-06-15 15:10:17 +02:00
|
|
|
if (*cb_data->id_pointer == id) {
|
2022-11-25 15:19:46 +01:00
|
|
|
/* Even though the ID itself remain the same after being made local, from depsgraph point of
|
|
|
|
|
* view this is a different ID. Hence we need to tag all of its users for COW update. */
|
2021-08-05 11:29:46 +02:00
|
|
|
DEG_id_tag_update_ex(
|
2023-05-16 18:14:43 +02:00
|
|
|
cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO | ID_RECALC_COPY_ON_WRITE);
|
Fix T77774: New undo code broken by 'make local' behavior.
This is actually a nice issue due to too much optimization...
* Making an ID local just reuse the linked one whenever possible, instead of
actually making a copy of it.
* Therefore, the collection containing that ID is seen as unchanged, since
the pointer itself remained the same.
* But on undo step, there is no way to reuse that local object, which then
gets deleted, and linked one gets re-created - at a different address.
* Collection, however, since unchanged, is not updated at all and thus keeps
reference to the to-be-deleted local object, instead of the linked one.
* Issue gets even worse with viewlayers, this leads to the crash.
To address this, this patch adds a 'virtual' update flags that does nothing
in update case, but will ensure that the affected IDs using the one made local
are properly detected as changed across the relevant undo step.
Note that the recalc flags were chosen mostly for a logical reason, and also
because they are already properly dealt with and cleared by undo code,
so this looks like the optimal solution.
Reviewed By: brecht
Maniphest Tasks: T77774
Differential Revision: https://developer.blender.org/D8006
2020-06-15 15:10:17 +02:00
|
|
|
return IDWALK_RET_STOP_ITER;
|
|
|
|
|
}
|
|
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 12:55:15 +02:00
|
|
|
void BKE_lib_id_clear_library_data(Main *bmain, ID *id, const int flags)
|
2020-03-04 10:38:30 +01:00
|
|
|
{
|
2020-03-12 18:05:20 +01:00
|
|
|
const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 &&
|
|
|
|
|
(id->flag & LIB_EMBEDDED_DATA) == 0;
|
2020-03-04 10:38:30 +01:00
|
|
|
|
2022-07-27 12:09:32 +02:00
|
|
|
if (id_in_mainlist) {
|
|
|
|
|
BKE_main_namemap_remove_name(bmain, id, id->name + 2);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-04 10:38:30 +01:00
|
|
|
lib_id_library_local_paths(bmain, id->lib, id);
|
|
|
|
|
|
|
|
|
|
id_fake_user_clear(id);
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
id->lib = nullptr;
|
2020-03-04 10:38:30 +01:00
|
|
|
id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
|
|
|
|
|
id->flag &= ~LIB_INDIRECT_WEAK_LINK;
|
|
|
|
|
if (id_in_mainlist) {
|
2023-07-17 10:46:26 +02:00
|
|
|
if (BKE_id_new_name_validate(bmain, which_libbase(bmain, GS(id->name)), id, nullptr, false)) {
|
2020-03-04 10:38:30 +01:00
|
|
|
bmain->is_memfile_undo_written = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Fix T77774: New undo code broken by 'make local' behavior.
This is actually a nice issue due to too much optimization...
* Making an ID local just reuse the linked one whenever possible, instead of
actually making a copy of it.
* Therefore, the collection containing that ID is seen as unchanged, since
the pointer itself remained the same.
* But on undo step, there is no way to reuse that local object, which then
gets deleted, and linked one gets re-created - at a different address.
* Collection, however, since unchanged, is not updated at all and thus keeps
reference to the to-be-deleted local object, instead of the linked one.
* Issue gets even worse with viewlayers, this leads to the crash.
To address this, this patch adds a 'virtual' update flags that does nothing
in update case, but will ensure that the affected IDs using the one made local
are properly detected as changed across the relevant undo step.
Note that the recalc flags were chosen mostly for a logical reason, and also
because they are already properly dealt with and cleared by undo code,
so this looks like the optimal solution.
Reviewed By: brecht
Maniphest Tasks: T77774
Differential Revision: https://developer.blender.org/D8006
2020-06-15 15:10:17 +02:00
|
|
|
/* Conceptually, an ID made local is not the same as the linked one anymore. Reflect that by
|
|
|
|
|
* regenerating its session UUID. */
|
2021-03-09 23:46:14 +11:00
|
|
|
if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) {
|
|
|
|
|
BKE_lib_libblock_session_uuid_renew(id);
|
|
|
|
|
}
|
Fix T77774: New undo code broken by 'make local' behavior.
This is actually a nice issue due to too much optimization...
* Making an ID local just reuse the linked one whenever possible, instead of
actually making a copy of it.
* Therefore, the collection containing that ID is seen as unchanged, since
the pointer itself remained the same.
* But on undo step, there is no way to reuse that local object, which then
gets deleted, and linked one gets re-created - at a different address.
* Collection, however, since unchanged, is not updated at all and thus keeps
reference to the to-be-deleted local object, instead of the linked one.
* Issue gets even worse with viewlayers, this leads to the crash.
To address this, this patch adds a 'virtual' update flags that does nothing
in update case, but will ensure that the affected IDs using the one made local
are properly detected as changed across the relevant undo step.
Note that the recalc flags were chosen mostly for a logical reason, and also
because they are already properly dealt with and cleared by undo code,
so this looks like the optimal solution.
Reviewed By: brecht
Maniphest Tasks: T77774
Differential Revision: https://developer.blender.org/D8006
2020-06-15 15:10:17 +02:00
|
|
|
|
2021-12-02 11:16:22 +01:00
|
|
|
if (ID_IS_ASSET(id)) {
|
|
|
|
|
if ((flags & LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR) != 0) {
|
|
|
|
|
BKE_asset_metadata_free(&id->asset_data);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Assets should always have a fake user. Ensure this is the case after "Make Local". */
|
|
|
|
|
id_fake_user_set(id);
|
|
|
|
|
}
|
2021-10-21 12:55:15 +02:00
|
|
|
}
|
|
|
|
|
|
Fix T77774: New undo code broken by 'make local' behavior.
This is actually a nice issue due to too much optimization...
* Making an ID local just reuse the linked one whenever possible, instead of
actually making a copy of it.
* Therefore, the collection containing that ID is seen as unchanged, since
the pointer itself remained the same.
* But on undo step, there is no way to reuse that local object, which then
gets deleted, and linked one gets re-created - at a different address.
* Collection, however, since unchanged, is not updated at all and thus keeps
reference to the to-be-deleted local object, instead of the linked one.
* Issue gets even worse with viewlayers, this leads to the crash.
To address this, this patch adds a 'virtual' update flags that does nothing
in update case, but will ensure that the affected IDs using the one made local
are properly detected as changed across the relevant undo step.
Note that the recalc flags were chosen mostly for a logical reason, and also
because they are already properly dealt with and cleared by undo code,
so this looks like the optimal solution.
Reviewed By: brecht
Maniphest Tasks: T77774
Differential Revision: https://developer.blender.org/D8006
2020-06-15 15:10:17 +02:00
|
|
|
/* We need to tag this IDs and all of its users, conceptually new local ID and original linked
|
2020-06-25 23:13:02 +10:00
|
|
|
* ones are two completely different data-blocks that were virtually remapped, even though in
|
Fix T77774: New undo code broken by 'make local' behavior.
This is actually a nice issue due to too much optimization...
* Making an ID local just reuse the linked one whenever possible, instead of
actually making a copy of it.
* Therefore, the collection containing that ID is seen as unchanged, since
the pointer itself remained the same.
* But on undo step, there is no way to reuse that local object, which then
gets deleted, and linked one gets re-created - at a different address.
* Collection, however, since unchanged, is not updated at all and thus keeps
reference to the to-be-deleted local object, instead of the linked one.
* Issue gets even worse with viewlayers, this leads to the crash.
To address this, this patch adds a 'virtual' update flags that does nothing
in update case, but will ensure that the affected IDs using the one made local
are properly detected as changed across the relevant undo step.
Note that the recalc flags were chosen mostly for a logical reason, and also
because they are already properly dealt with and cleared by undo code,
so this looks like the optimal solution.
Reviewed By: brecht
Maniphest Tasks: T77774
Differential Revision: https://developer.blender.org/D8006
2020-06-15 15:10:17 +02:00
|
|
|
* reality they remain the same data. For undo this info is critical now. */
|
|
|
|
|
DEG_id_tag_update_ex(bmain, id, ID_RECALC_COPY_ON_WRITE);
|
|
|
|
|
ID *id_iter;
|
|
|
|
|
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
|
|
|
|
|
BKE_library_foreach_ID_link(
|
|
|
|
|
bmain, id_iter, lib_id_clear_library_data_users_update_cb, id, IDWALK_READONLY);
|
|
|
|
|
}
|
|
|
|
|
FOREACH_MAIN_ID_END;
|
|
|
|
|
|
2020-05-25 15:11:36 +02:00
|
|
|
/* Internal shape key blocks inside data-blocks also stores id->lib,
|
|
|
|
|
* make sure this stays in sync (note that we do not need any explicit handling for real EMBEDDED
|
|
|
|
|
* IDs here, this is down automatically in `lib_id_expand_local_cb()`. */
|
|
|
|
|
Key *key = BKE_key_from_id(id);
|
2023-07-17 10:46:26 +02:00
|
|
|
if (key != nullptr) {
|
2021-10-21 12:55:15 +02:00
|
|
|
BKE_lib_id_clear_library_data(bmain, &key->id, flags);
|
2020-03-04 10:38:30 +01:00
|
|
|
}
|
2021-08-05 11:29:46 +02:00
|
|
|
|
2022-11-25 15:19:46 +01:00
|
|
|
/* Even though the ID itself remain the same after being made local, from depsgraph point of view
|
|
|
|
|
* this is a different ID. Hence we rebuild depsgraph relationships. */
|
2021-08-05 11:29:46 +02:00
|
|
|
DEG_relations_tag_update(bmain);
|
2020-03-04 10:38:30 +01:00
|
|
|
}
|
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
void id_lib_extern(ID *id)
|
|
|
|
|
{
|
2017-11-06 17:17:10 +01:00
|
|
|
if (id && ID_IS_LINKED(id)) {
|
2020-03-19 19:37:00 +01:00
|
|
|
BLI_assert(BKE_idtype_idcode_is_linkable(GS(id->name)));
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
if (id->tag & LIB_TAG_INDIRECT) {
|
2019-01-30 11:38:13 +01:00
|
|
|
id->tag &= ~LIB_TAG_INDIRECT;
|
2019-09-16 14:52:06 +02:00
|
|
|
id->flag &= ~LIB_INDIRECT_WEAK_LINK;
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
id->tag |= LIB_TAG_EXTERN;
|
2023-07-17 10:46:26 +02:00
|
|
|
id->lib->parent = nullptr;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-16 14:52:06 +02:00
|
|
|
void id_lib_indirect_weak_link(ID *id)
|
|
|
|
|
{
|
|
|
|
|
if (id && ID_IS_LINKED(id)) {
|
2020-03-19 19:37:00 +01:00
|
|
|
BLI_assert(BKE_idtype_idcode_is_linkable(GS(id->name)));
|
2019-09-16 14:52:06 +02:00
|
|
|
if (id->tag & LIB_TAG_INDIRECT) {
|
|
|
|
|
id->flag |= LIB_INDIRECT_WEAK_LINK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-18 08:41:38 +00:00
|
|
|
void id_us_ensure_real(ID *id)
|
|
|
|
|
{
|
2012-12-19 01:28:00 +00:00
|
|
|
if (id) {
|
2015-11-10 16:20:28 +01:00
|
|
|
const int limit = ID_FAKE_USERS(id);
|
2016-01-04 20:17:23 +01:00
|
|
|
id->tag |= LIB_TAG_EXTRAUSER;
|
2015-11-10 16:20:28 +01:00
|
|
|
if (id->us <= limit) {
|
2016-01-04 20:17:23 +01:00
|
|
|
if (id->us < limit || ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER_SET))) {
|
2019-02-01 12:44:19 +11:00
|
|
|
CLOG_ERROR(&LOG,
|
|
|
|
|
"ID user count error: %s (from '%s')",
|
|
|
|
|
id->name,
|
2020-06-23 09:54:07 +10:00
|
|
|
id->lib ? id->lib->filepath_abs : "[Main]");
|
2015-11-10 16:20:28 +01:00
|
|
|
}
|
|
|
|
|
id->us = limit + 1;
|
2016-01-04 20:17:23 +01:00
|
|
|
id->tag |= LIB_TAG_EXTRAUSER_SET;
|
2012-12-19 01:28:00 +00:00
|
|
|
}
|
2012-12-18 08:41:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 12:09:36 +01:00
|
|
|
void id_us_clear_real(ID *id)
|
2016-01-04 20:17:23 +01:00
|
|
|
{
|
|
|
|
|
if (id && (id->tag & LIB_TAG_EXTRAUSER)) {
|
|
|
|
|
if (id->tag & LIB_TAG_EXTRAUSER_SET) {
|
|
|
|
|
id->us--;
|
|
|
|
|
BLI_assert(id->us >= ID_FAKE_USERS(id));
|
|
|
|
|
}
|
|
|
|
|
id->tag &= ~(LIB_TAG_EXTRAUSER | LIB_TAG_EXTRAUSER_SET);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-14 15:05:52 +01:00
|
|
|
void id_us_plus_no_lib(ID *id)
|
|
|
|
|
{
|
|
|
|
|
if (id) {
|
|
|
|
|
if ((id->tag & LIB_TAG_EXTRAUSER) && (id->tag & LIB_TAG_EXTRAUSER_SET)) {
|
|
|
|
|
BLI_assert(id->us >= 1);
|
|
|
|
|
/* No need to increase count, just tag extra user as no more set.
|
|
|
|
|
* Avoids annoying & inconsistent +1 in user count. */
|
|
|
|
|
id->tag &= ~LIB_TAG_EXTRAUSER_SET;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_assert(id->us >= 0);
|
|
|
|
|
id->us++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
void id_us_plus(ID *id)
|
|
|
|
|
{
|
2012-03-24 06:18:31 +00:00
|
|
|
if (id) {
|
2016-03-14 15:05:52 +01:00
|
|
|
id_us_plus_no_lib(id);
|
2015-11-13 15:34:07 +01:00
|
|
|
id_lib_extern(id);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-27 00:03:49 +00:00
|
|
|
void id_us_min(ID *id)
|
|
|
|
|
{
|
2012-03-24 06:18:31 +00:00
|
|
|
if (id) {
|
2015-11-10 16:20:28 +01:00
|
|
|
const int limit = ID_FAKE_USERS(id);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-11-09 20:06:46 +01:00
|
|
|
if (id->us <= limit) {
|
2022-05-27 19:15:58 +02:00
|
|
|
if (!ID_TYPE_IS_DEPRECATED(GS(id->name))) {
|
2023-01-03 10:19:27 +11:00
|
|
|
/* Do not assert on deprecated ID types, we cannot really ensure that their ID
|
|
|
|
|
* reference-counting is valid. */
|
2020-10-07 10:18:05 +02:00
|
|
|
CLOG_ERROR(&LOG,
|
|
|
|
|
"ID user decrement error: %s (from '%s'): %d <= %d",
|
|
|
|
|
id->name,
|
|
|
|
|
id->lib ? id->lib->filepath_abs : "[Main]",
|
|
|
|
|
id->us,
|
|
|
|
|
limit);
|
2020-04-09 11:19:11 +02:00
|
|
|
}
|
2015-11-09 20:06:46 +01:00
|
|
|
id->us = limit;
|
2012-03-31 00:59:17 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2010-12-17 14:20:20 +00:00
|
|
|
id->us--;
|
2012-03-31 00:59:17 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-20 16:47:43 +01:00
|
|
|
if ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER)) {
|
2019-04-27 12:07:07 +10:00
|
|
|
/* We need an extra user here, but never actually incremented user count for it so far,
|
|
|
|
|
* do it now. */
|
2016-02-20 16:47:43 +01:00
|
|
|
id_us_ensure_real(id);
|
|
|
|
|
}
|
2010-12-17 14:20:20 +00:00
|
|
|
}
|
2009-05-27 00:03:49 +00:00
|
|
|
}
|
|
|
|
|
|
2015-11-09 20:59:42 +01:00
|
|
|
void id_fake_user_set(ID *id)
|
|
|
|
|
{
|
|
|
|
|
if (id && !(id->flag & LIB_FAKEUSER)) {
|
|
|
|
|
id->flag |= LIB_FAKEUSER;
|
|
|
|
|
id_us_plus(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void id_fake_user_clear(ID *id)
|
|
|
|
|
{
|
|
|
|
|
if (id && (id->flag & LIB_FAKEUSER)) {
|
|
|
|
|
id->flag &= ~LIB_FAKEUSER;
|
|
|
|
|
id_us_min(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-16 12:16:35 +02:00
|
|
|
void BKE_id_newptr_and_tag_clear(ID *id)
|
2016-11-30 15:25:54 +01:00
|
|
|
{
|
2021-09-16 12:14:21 +02:00
|
|
|
/* We assume that if this ID has no new ID, its embedded data has not either. */
|
2023-07-17 10:46:26 +02:00
|
|
|
if (id->newid == nullptr) {
|
2021-09-16 12:14:21 +02:00
|
|
|
return;
|
2016-11-30 15:25:54 +01:00
|
|
|
}
|
2021-09-16 12:14:21 +02:00
|
|
|
|
|
|
|
|
id->newid->tag &= ~LIB_TAG_NEW;
|
2023-07-17 10:46:26 +02:00
|
|
|
id->newid = nullptr;
|
2021-09-16 12:14:21 +02:00
|
|
|
|
|
|
|
|
/* Deal with embedded data too. */
|
2021-09-16 12:39:40 +02:00
|
|
|
/* NOTE: even though ShapeKeys are not technically embedded data currently, they behave as such
|
|
|
|
|
* in most cases, so for sake of consistency treat them as such here. Also mirrors the behavior
|
|
|
|
|
* in `BKE_lib_id_make_local`. */
|
2021-09-16 12:14:21 +02:00
|
|
|
Key *key = BKE_key_from_id(id);
|
2023-07-17 10:46:26 +02:00
|
|
|
if (key != nullptr) {
|
2021-09-16 12:16:35 +02:00
|
|
|
BKE_id_newptr_and_tag_clear(&key->id);
|
2021-09-16 12:14:21 +02:00
|
|
|
}
|
|
|
|
|
bNodeTree *ntree = ntreeFromID(id);
|
2023-07-17 10:46:26 +02:00
|
|
|
if (ntree != nullptr) {
|
2021-09-16 12:16:35 +02:00
|
|
|
BKE_id_newptr_and_tag_clear(&ntree->id);
|
2021-09-16 12:14:21 +02:00
|
|
|
}
|
|
|
|
|
if (GS(id->name) == ID_SCE) {
|
|
|
|
|
Collection *master_collection = ((Scene *)id)->master_collection;
|
2023-07-17 10:46:26 +02:00
|
|
|
if (master_collection != nullptr) {
|
2021-09-16 12:16:35 +02:00
|
|
|
BKE_id_newptr_and_tag_clear(&master_collection->id);
|
2021-09-16 12:14:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2016-11-30 15:25:54 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-04 10:38:30 +01:00
|
|
|
static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
|
2016-07-11 16:41:59 +02:00
|
|
|
{
|
2020-05-25 15:26:58 +02:00
|
|
|
Main *bmain = cb_data->bmain;
|
2023-05-16 18:14:43 +02:00
|
|
|
ID *self_id = cb_data->self_id;
|
2020-02-13 12:56:10 +01:00
|
|
|
ID **id_pointer = cb_data->id_pointer;
|
|
|
|
|
int const cb_flag = cb_data->cb_flag;
|
2021-10-21 12:55:15 +02:00
|
|
|
const int flags = POINTER_AS_INT(cb_data->user_data);
|
2020-05-25 15:11:36 +02:00
|
|
|
|
|
|
|
|
if (cb_flag & IDWALK_CB_LOOPBACK) {
|
2020-08-29 13:41:02 +10:00
|
|
|
/* We should never have anything to do with loop-back pointers here. */
|
2020-05-25 15:11:36 +02:00
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-14 13:25:06 +02:00
|
|
|
if (cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_EMBEDDED_NOT_OWNING)) {
|
2020-08-27 15:48:01 +02:00
|
|
|
/* Embedded data-blocks need to be made fully local as well.
|
|
|
|
|
* Note however that in some cases (when owner ID had to be duplicated instead of being made
|
|
|
|
|
* local directly), its embedded IDs should also have already been duplicated, and hence be
|
|
|
|
|
* fully local here already. */
|
2023-07-17 10:46:26 +02:00
|
|
|
if (*id_pointer != nullptr && ID_IS_LINKED(*id_pointer)) {
|
2023-05-16 18:14:43 +02:00
|
|
|
BLI_assert(*id_pointer != self_id);
|
2020-05-25 15:11:36 +02:00
|
|
|
|
2021-10-21 12:55:15 +02:00
|
|
|
BKE_lib_id_clear_library_data(bmain, *id_pointer, flags);
|
2020-05-25 15:11:36 +02:00
|
|
|
}
|
2017-01-30 21:34:23 +01:00
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-27 12:07:07 +10:00
|
|
|
/* Can happen that we get un-linkable ID here, e.g. with shape-key referring to itself
|
|
|
|
|
* (through drivers)...
|
2016-11-09 16:42:28 +01:00
|
|
|
* Just skip it, shape key can only be either indirectly linked, or fully local, period.
|
2022-09-16 18:13:19 +10:00
|
|
|
* And let's curse one more time that stupid useless shape-key ID type! */
|
2023-05-16 18:14:43 +02:00
|
|
|
if (*id_pointer && *id_pointer != self_id &&
|
2020-03-19 19:37:00 +01:00
|
|
|
BKE_idtype_idcode_is_linkable(GS((*id_pointer)->name)))
|
|
|
|
|
{
|
2016-07-11 21:27:15 +02:00
|
|
|
id_lib_extern(*id_pointer);
|
2016-07-11 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 12:55:15 +02:00
|
|
|
void BKE_lib_id_expand_local(Main *bmain, ID *id, const int flags)
|
2016-07-11 16:41:59 +02:00
|
|
|
{
|
2021-10-21 12:55:15 +02:00
|
|
|
BKE_library_foreach_ID_link(
|
|
|
|
|
bmain, id, lib_id_expand_local_cb, POINTER_FROM_INT(flags), IDWALK_READONLY);
|
2016-07-11 16:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-25 16:15:37 +02:00
|
|
|
/**
|
|
|
|
|
* Ensure new (copied) ID is fully made local.
|
|
|
|
|
*/
|
2023-05-11 12:23:50 +02:00
|
|
|
void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id, const int flags)
|
2016-07-25 16:15:37 +02:00
|
|
|
{
|
2017-11-06 17:17:10 +01:00
|
|
|
if (ID_IS_LINKED(old_id)) {
|
2021-10-21 12:55:15 +02:00
|
|
|
BKE_lib_id_expand_local(bmain, new_id, flags);
|
2020-03-04 10:38:30 +01:00
|
|
|
lib_id_library_local_paths(bmain, old_id->lib, new_id);
|
2016-07-25 16:15:37 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-24 17:38:36 +01:00
|
|
|
void BKE_lib_id_make_local_generic_action_define(
|
2023-06-03 08:36:28 +10:00
|
|
|
Main *bmain, ID *id, int flags, bool *r_force_local, bool *r_force_copy)
|
2016-07-20 19:49:45 +02:00
|
|
|
{
|
2021-09-09 10:48:26 +02:00
|
|
|
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
|
|
|
|
|
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
|
2021-09-06 17:37:04 +02:00
|
|
|
BLI_assert(force_copy == false || force_copy != force_local);
|
|
|
|
|
|
2022-01-24 17:38:36 +01:00
|
|
|
if (force_local || force_copy) {
|
2022-01-26 16:06:22 +11:00
|
|
|
/* Already set by caller code, nothing to do here. */
|
2022-01-24 17:38:36 +01:00
|
|
|
*r_force_local = force_local;
|
|
|
|
|
*r_force_copy = force_copy;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
|
2016-07-20 19:49:45 +02:00
|
|
|
bool is_local = false, is_lib = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-01-24 17:38:36 +01:00
|
|
|
/* - no user (neither lib nor local): make local (happens e.g. with UI-used only data).
|
|
|
|
|
* - only lib users: do nothing (unless force_local is set)
|
|
|
|
|
* - only local users: make local
|
2016-07-20 19:49:45 +02:00
|
|
|
* - mixed: make copy
|
2019-04-27 12:07:07 +10:00
|
|
|
* In case we make a whole lib's content local,
|
|
|
|
|
* we always want to localize, and we skip remapping (done later).
|
2016-07-20 19:49:45 +02:00
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-01-24 17:38:36 +01:00
|
|
|
BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
|
|
|
|
|
if (!lib_local && !is_local && !is_lib) {
|
|
|
|
|
force_local = true;
|
|
|
|
|
}
|
|
|
|
|
else if (lib_local || is_local) {
|
|
|
|
|
if (!is_lib) {
|
|
|
|
|
force_local = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
force_copy = true;
|
2021-09-09 10:48:26 +02:00
|
|
|
}
|
2016-07-20 19:49:45 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-01-24 17:38:36 +01:00
|
|
|
*r_force_local = force_local;
|
|
|
|
|
*r_force_copy = force_copy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
|
|
|
|
|
{
|
|
|
|
|
if (!ID_IS_LINKED(id)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool force_local, force_copy;
|
|
|
|
|
BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
|
|
|
|
|
|
2021-09-09 10:48:26 +02:00
|
|
|
if (force_local) {
|
2021-10-21 12:55:15 +02:00
|
|
|
BKE_lib_id_clear_library_data(bmain, id, flags);
|
2023-06-27 11:49:56 +02:00
|
|
|
if ((flags & LIB_ID_MAKELOCAL_LIBOVERRIDE_CLEAR) != 0) {
|
2023-10-10 16:52:59 +02:00
|
|
|
BKE_lib_override_library_make_local(bmain, id);
|
2023-06-27 11:49:56 +02:00
|
|
|
}
|
2021-10-21 12:55:15 +02:00
|
|
|
BKE_lib_id_expand_local(bmain, id, flags);
|
2021-09-09 10:48:26 +02:00
|
|
|
}
|
|
|
|
|
else if (force_copy) {
|
2023-06-27 11:49:56 +02:00
|
|
|
const int copy_flags =
|
|
|
|
|
(LIB_ID_COPY_DEFAULT |
|
|
|
|
|
((flags & LIB_ID_MAKELOCAL_LIBOVERRIDE_CLEAR) != 0 ? LIB_ID_COPY_NO_LIB_OVERRIDE : 0));
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id_new = BKE_id_copy_ex(bmain, id, nullptr, copy_flags);
|
2021-09-09 10:48:26 +02:00
|
|
|
|
|
|
|
|
/* Should not fail in expected use cases,
|
|
|
|
|
* but a few ID types cannot be copied (LIB, WM, SCR...). */
|
2023-07-17 10:46:26 +02:00
|
|
|
if (id_new != nullptr) {
|
2021-09-09 10:48:26 +02:00
|
|
|
id_new->us = 0;
|
|
|
|
|
|
|
|
|
|
/* setting newid is mandatory for complex make_lib_local logic... */
|
|
|
|
|
ID_NEW_SET(id, id_new);
|
|
|
|
|
Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id);
|
|
|
|
|
if (key && key_new) {
|
|
|
|
|
ID_NEW_SET(key, key_new);
|
|
|
|
|
}
|
|
|
|
|
bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new);
|
|
|
|
|
if (ntree && ntree_new) {
|
|
|
|
|
ID_NEW_SET(ntree, ntree_new);
|
|
|
|
|
}
|
|
|
|
|
if (GS(id->name) == ID_SCE) {
|
|
|
|
|
Collection *master_collection = ((Scene *)id)->master_collection,
|
|
|
|
|
*master_collection_new = ((Scene *)id_new)->master_collection;
|
|
|
|
|
if (master_collection && master_collection_new) {
|
|
|
|
|
ID_NEW_SET(master_collection, master_collection_new);
|
2020-05-25 15:11:36 +02:00
|
|
|
}
|
2021-09-09 10:48:26 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-01-24 17:38:36 +01:00
|
|
|
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
|
2021-09-09 10:48:26 +02:00
|
|
|
if (!lib_local) {
|
|
|
|
|
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
|
2016-07-20 19:49:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-16 11:45:06 +02:00
|
|
|
bool BKE_lib_id_make_local(Main *bmain, ID *id, const int flags)
|
2009-09-04 21:02:43 +00:00
|
|
|
{
|
2020-03-04 11:42:15 +01:00
|
|
|
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
|
|
|
|
|
|
2019-04-27 12:07:07 +10:00
|
|
|
/* We don't care whether ID is directly or indirectly linked
|
|
|
|
|
* in case we are making a whole lib local... */
|
2016-08-05 14:45:21 +02:00
|
|
|
if (!lib_local && (id->tag & LIB_TAG_INDIRECT)) {
|
2013-03-10 05:46:24 +00:00
|
|
|
return false;
|
2016-08-05 14:45:21 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-05 10:54:00 +01:00
|
|
|
const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_id(id);
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (idtype_info == nullptr) {
|
2021-09-16 11:45:06 +02:00
|
|
|
BLI_assert_msg(0, "IDType Missing IDTypeInfo");
|
2020-03-05 10:54:00 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-16 11:45:06 +02:00
|
|
|
BLI_assert((idtype_info->flags & IDTYPE_FLAGS_NO_LIBLINKING) == 0);
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (idtype_info->make_local != nullptr) {
|
2021-09-16 11:45:06 +02:00
|
|
|
idtype_info->make_local(bmain, id, flags);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BKE_lib_id_make_local_generic(bmain, id, flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2009-09-04 21:02:43 +00:00
|
|
|
}
|
|
|
|
|
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
struct IDCopyLibManagementData {
|
|
|
|
|
const ID *id_src;
|
2017-08-14 15:40:54 +02:00
|
|
|
ID *id_dst;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
int flag;
|
|
|
|
|
};
|
|
|
|
|
|
2022-09-16 18:13:19 +10:00
|
|
|
/** Increases user-count as required, and remap self ID pointers. */
|
2020-02-13 12:56:10 +01:00
|
|
|
static int id_copy_libmanagement_cb(LibraryIDLinkCallbackData *cb_data)
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
{
|
2020-02-13 12:56:10 +01:00
|
|
|
ID **id_pointer = cb_data->id_pointer;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
ID *id = *id_pointer;
|
2020-02-13 12:56:10 +01:00
|
|
|
const int cb_flag = cb_data->cb_flag;
|
2023-07-20 11:30:25 +10:00
|
|
|
IDCopyLibManagementData *data = static_cast<IDCopyLibManagementData *>(cb_data->user_data);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
|
|
|
|
|
/* Remap self-references to new copied ID. */
|
|
|
|
|
if (id == data->id_src) {
|
2023-07-09 21:22:31 +10:00
|
|
|
/* We cannot use self_id here, it is not *always* id_dst (thanks to confounded node-trees!). */
|
2017-08-14 15:40:54 +02:00
|
|
|
id = *id_pointer = data->id_dst;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Increase used IDs refcount if needed and required. */
|
|
|
|
|
if ((data->flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0 && (cb_flag & IDWALK_CB_USER)) {
|
2021-05-18 18:42:29 +02:00
|
|
|
if ((data->flag & LIB_ID_CREATE_NO_MAIN) != 0) {
|
2023-05-16 18:14:43 +02:00
|
|
|
BLI_assert(cb_data->self_id->tag & LIB_TAG_NO_MAIN);
|
2021-05-18 18:42:29 +02:00
|
|
|
id_us_plus_no_lib(id);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
id_us_plus(id);
|
|
|
|
|
}
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-04 15:34:31 +01:00
|
|
|
bool BKE_id_copy_is_allowed(const ID *id)
|
|
|
|
|
{
|
2022-05-27 19:15:58 +02:00
|
|
|
#define LIB_ID_TYPES_NOCOPY ID_LI, ID_SCR, ID_WM, ID_WS /* Not supported */
|
2019-02-04 15:34:31 +01:00
|
|
|
|
2022-05-27 19:15:58 +02:00
|
|
|
return !ID_TYPE_IS_DEPRECATED(GS(id->name)) && !ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY);
|
2019-02-04 15:34:31 +01:00
|
|
|
|
|
|
|
|
#undef LIB_ID_TYPES_NOCOPY
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-07 14:27:33 +02:00
|
|
|
ID *BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
|
2009-09-04 21:02:43 +00:00
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *newid = (r_newid != nullptr) ? *r_newid : nullptr;
|
2017-10-19 13:55:08 +02:00
|
|
|
/* Make sure destination pointer is all good. */
|
|
|
|
|
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0) {
|
2023-07-17 10:46:26 +02:00
|
|
|
newid = nullptr;
|
2017-10-19 13:55:08 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2023-07-17 10:46:26 +02:00
|
|
|
if (newid != nullptr) {
|
2019-01-16 16:14:10 +01:00
|
|
|
/* Allow some garbage non-initialized memory to go in, and clean it up here. */
|
2023-07-17 10:46:26 +02:00
|
|
|
const size_t size = BKE_libblock_get_alloc_info(GS(id->name), nullptr);
|
2020-10-07 14:27:33 +02:00
|
|
|
memset(newid, 0, size);
|
2017-10-19 13:55:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
/* Early output if source is nullptr. */
|
|
|
|
|
if (id == nullptr) {
|
|
|
|
|
return nullptr;
|
2019-01-16 16:14:10 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-05 10:54:00 +01:00
|
|
|
const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_id(id);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (idtype_info != nullptr) {
|
2020-03-05 10:54:00 +01:00
|
|
|
if ((idtype_info->flags & IDTYPE_FLAGS_NO_COPY) != 0) {
|
2023-07-17 10:46:26 +02:00
|
|
|
return nullptr;
|
2020-03-05 10:54:00 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-07 14:27:33 +02:00
|
|
|
BKE_libblock_copy_ex(bmain, id, &newid, flag);
|
2020-03-05 10:54:00 +01:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (idtype_info->copy_data != nullptr) {
|
2020-10-07 14:27:33 +02:00
|
|
|
idtype_info->copy_data(bmain, newid, id, flag);
|
2020-03-05 10:54:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2021-07-15 18:23:28 +10:00
|
|
|
BLI_assert_msg(0, "IDType Missing IDTypeInfo");
|
2009-09-04 21:02:43 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
/* Update ID refcount, remap pointers to self in new ID. */
|
2023-07-17 10:46:26 +02:00
|
|
|
IDCopyLibManagementData data{};
|
|
|
|
|
data.id_src = id;
|
|
|
|
|
data.id_dst = newid;
|
|
|
|
|
data.flag = flag;
|
2020-10-07 14:27:33 +02:00
|
|
|
BKE_library_foreach_ID_link(bmain, newid, id_copy_libmanagement_cb, &data, IDWALK_NOP);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
/* 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) {
|
2017-12-06 12:59:00 +01:00
|
|
|
BLI_assert((flag & LIB_ID_COPY_KEEP_LIB) == 0);
|
2021-10-21 12:55:15 +02:00
|
|
|
lib_id_copy_ensure_local(bmain, id, newid, 0);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
2017-12-06 12:59:00 +01:00
|
|
|
else {
|
2020-10-07 14:27:33 +02:00
|
|
|
newid->lib = id->lib;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (r_newid != nullptr) {
|
2020-10-07 14:27:33 +02:00
|
|
|
*r_newid = newid;
|
2017-12-06 12:59:00 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-07 14:27:33 +02:00
|
|
|
return newid;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
|
|
|
|
|
2020-10-07 16:13:01 +02:00
|
|
|
ID *BKE_id_copy(Main *bmain, const ID *id)
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
return BKE_id_copy_ex(bmain, id, nullptr, LIB_ID_COPY_DEFAULT);
|
2009-09-04 21:02:43 +00:00
|
|
|
}
|
|
|
|
|
|
2021-09-30 15:22:16 +02:00
|
|
|
ID *BKE_id_copy_for_duplicate(Main *bmain,
|
|
|
|
|
ID *id,
|
|
|
|
|
const eDupli_ID_Flags duplicate_flags,
|
|
|
|
|
const int copy_flags)
|
2020-06-17 17:01:21 +02:00
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
if (id == nullptr) {
|
2020-07-09 15:33:34 +02:00
|
|
|
return id;
|
2020-06-17 17:01:21 +02:00
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
if (id->newid == nullptr) {
|
2020-07-09 15:33:34 +02:00
|
|
|
const bool do_linked_id = (duplicate_flags & USER_DUP_LINKED_ID) != 0;
|
|
|
|
|
if (!(do_linked_id || !ID_IS_LINKED(id))) {
|
|
|
|
|
return id;
|
|
|
|
|
}
|
2020-06-17 17:01:21 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id_new = BKE_id_copy_ex(bmain, id, nullptr, copy_flags);
|
2020-07-09 15:33:34 +02:00
|
|
|
/* Copying add one user by default, need to get rid of that one. */
|
|
|
|
|
id_us_min(id_new);
|
|
|
|
|
ID_NEW_SET(id, id_new);
|
|
|
|
|
|
|
|
|
|
/* Shape keys are always copied with their owner ID, by default. */
|
|
|
|
|
ID *key_new = (ID *)BKE_key_from_id(id_new);
|
|
|
|
|
ID *key = (ID *)BKE_key_from_id(id);
|
2023-07-17 10:46:26 +02:00
|
|
|
if (key != nullptr) {
|
2020-07-09 15:33:34 +02:00
|
|
|
ID_NEW_SET(key, key_new);
|
|
|
|
|
}
|
2020-06-17 17:01:21 +02:00
|
|
|
|
2023-07-09 21:22:31 +10:00
|
|
|
/* NOTE: embedded data (root node-trees and master collections) should never be referenced by
|
2020-07-09 15:33:34 +02:00
|
|
|
* anything else, so we do not need to set their newid pointer and flag. */
|
|
|
|
|
|
|
|
|
|
BKE_animdata_duplicate_id_action(bmain, id_new, duplicate_flags);
|
2023-07-17 10:46:26 +02:00
|
|
|
if (key_new != nullptr) {
|
2020-08-25 11:49:43 +02:00
|
|
|
BKE_animdata_duplicate_id_action(bmain, key_new, duplicate_flags);
|
2020-06-17 17:01:21 +02:00
|
|
|
}
|
2023-07-09 21:22:31 +10:00
|
|
|
/* Note that actions of embedded data (root node-trees and master collections) are handled
|
|
|
|
|
* by #BKE_animdata_duplicate_id_action as well. */
|
2020-06-17 17:01:21 +02:00
|
|
|
}
|
|
|
|
|
return id->newid;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-03 10:54:11 +02:00
|
|
|
static int foreach_assign_id_to_orig_callback(LibraryIDLinkCallbackData *cb_data)
|
|
|
|
|
{
|
|
|
|
|
ID **id_p = cb_data->id_pointer;
|
|
|
|
|
|
|
|
|
|
if (*id_p) {
|
|
|
|
|
ID *id = *id_p;
|
|
|
|
|
*id_p = DEG_get_original_id(id);
|
|
|
|
|
|
|
|
|
|
/* If the ID changes increase the user count.
|
|
|
|
|
*
|
|
|
|
|
* This means that the reference to evaluated ID has been changed with a reference to the
|
|
|
|
|
* original ID which implies that the user count of the original ID is increased.
|
|
|
|
|
*
|
|
|
|
|
* The evaluated IDs do not maintain their user counter, so do not change it to avoid issues
|
|
|
|
|
* with the user counter going negative. */
|
|
|
|
|
if (*id_p != id) {
|
|
|
|
|
if ((cb_data->cb_flag & IDWALK_CB_USER) != 0) {
|
|
|
|
|
id_us_plus(*id_p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ID *BKE_id_copy_for_use_in_bmain(Main *bmain, const ID *id)
|
|
|
|
|
{
|
|
|
|
|
ID *newid = BKE_id_copy(bmain, id);
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (newid == nullptr) {
|
2022-08-03 10:54:11 +02:00
|
|
|
return newid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Assign ID references directly used by the given ID to their original complementary parts.
|
|
|
|
|
*
|
|
|
|
|
* For example, when is called on an evaluated object will assign object->data to its original
|
|
|
|
|
* pointer, the evaluated object->data will be kept unchanged. */
|
2023-07-17 10:46:26 +02:00
|
|
|
BKE_library_foreach_ID_link(
|
|
|
|
|
nullptr, newid, foreach_assign_id_to_orig_callback, nullptr, IDWALK_NOP);
|
2022-08-03 10:54:11 +02:00
|
|
|
|
|
|
|
|
/* Shape keys reference on evaluated ID is preserved to keep driver paths available, but the key
|
|
|
|
|
* data is likely to be invalid now due to modifiers, so clear the shape key reference avoiding
|
|
|
|
|
* any possible shape corruption. */
|
|
|
|
|
if (DEG_is_evaluated_id(id)) {
|
|
|
|
|
Key **key_p = BKE_key_from_id_p(newid);
|
|
|
|
|
if (key_p) {
|
2023-07-17 10:46:26 +02:00
|
|
|
*key_p = nullptr;
|
2022-08-03 10:54:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return newid;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-17 17:17:02 +02:00
|
|
|
static void id_embedded_swap(ID **embedded_id_a,
|
|
|
|
|
ID **embedded_id_b,
|
|
|
|
|
const bool do_full_id,
|
2023-07-18 14:18:07 +10:00
|
|
|
IDRemapper *remapper_id_a,
|
|
|
|
|
IDRemapper *remapper_id_b);
|
2023-04-17 17:17:02 +02:00
|
|
|
|
2019-11-25 01:14:39 +11:00
|
|
|
/**
|
|
|
|
|
* Does a mere memory swap over the whole IDs data (including type-specific memory).
|
|
|
|
|
* \note Most internal ID data itself is not swapped (only IDProperties are).
|
|
|
|
|
*/
|
2023-04-17 17:17:02 +02:00
|
|
|
static void id_swap(Main *bmain,
|
|
|
|
|
ID *id_a,
|
|
|
|
|
ID *id_b,
|
|
|
|
|
const bool do_full_id,
|
|
|
|
|
const bool do_self_remap,
|
2023-07-20 11:30:25 +10:00
|
|
|
IDRemapper *input_remapper_id_a,
|
|
|
|
|
IDRemapper *input_remapper_id_b,
|
2023-04-17 17:17:02 +02:00
|
|
|
const int self_remap_flags)
|
2017-11-29 13:13:16 +01:00
|
|
|
{
|
|
|
|
|
BLI_assert(GS(id_a->name) == GS(id_b->name));
|
|
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
IDRemapper *remapper_id_a = input_remapper_id_a;
|
|
|
|
|
IDRemapper *remapper_id_b = input_remapper_id_b;
|
2023-04-17 17:17:02 +02:00
|
|
|
if (do_self_remap) {
|
2023-07-17 10:46:26 +02:00
|
|
|
if (remapper_id_a == nullptr) {
|
2023-04-17 17:17:02 +02:00
|
|
|
remapper_id_a = BKE_id_remapper_create();
|
|
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
if (remapper_id_b == nullptr) {
|
2023-04-17 17:17:02 +02:00
|
|
|
remapper_id_b = BKE_id_remapper_create();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-20 11:55:34 +01:00
|
|
|
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id_a);
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(id_type != nullptr);
|
2020-03-20 11:55:34 +01:00
|
|
|
const size_t id_struct_size = id_type->struct_size;
|
|
|
|
|
|
2017-11-29 13:13:16 +01:00
|
|
|
const ID id_a_back = *id_a;
|
|
|
|
|
const ID id_b_back = *id_b;
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
char *id_swap_buff = static_cast<char *>(alloca(id_struct_size));
|
2017-11-29 13:13:16 +01:00
|
|
|
|
2020-03-20 11:55:34 +01:00
|
|
|
memcpy(id_swap_buff, id_a, id_struct_size);
|
|
|
|
|
memcpy(id_a, id_b, id_struct_size);
|
|
|
|
|
memcpy(id_b, id_swap_buff, id_struct_size);
|
2017-11-29 13:13:16 +01:00
|
|
|
|
2020-03-17 11:13:14 +01:00
|
|
|
if (!do_full_id) {
|
|
|
|
|
/* Restore original ID's internal data. */
|
|
|
|
|
*id_a = id_a_back;
|
|
|
|
|
*id_b = id_b_back;
|
2017-11-29 13:13:16 +01:00
|
|
|
|
2020-03-17 11:13:14 +01:00
|
|
|
/* Exception: IDProperties. */
|
|
|
|
|
id_a->properties = id_b_back.properties;
|
|
|
|
|
id_b->properties = id_a_back.properties;
|
2020-06-26 17:55:23 +02:00
|
|
|
/* Exception: recalc flags. */
|
|
|
|
|
id_a->recalc = id_b_back.recalc;
|
|
|
|
|
id_b->recalc = id_a_back.recalc;
|
2020-03-17 11:13:14 +01:00
|
|
|
}
|
2017-11-29 13:13:16 +01:00
|
|
|
|
2023-04-17 17:17:02 +02:00
|
|
|
id_embedded_swap((ID **)BKE_ntree_ptr_from_id(id_a),
|
|
|
|
|
(ID **)BKE_ntree_ptr_from_id(id_b),
|
|
|
|
|
do_full_id,
|
|
|
|
|
remapper_id_a,
|
|
|
|
|
remapper_id_b);
|
|
|
|
|
if (GS(id_a->name) == ID_SCE) {
|
|
|
|
|
Scene *scene_a = (Scene *)id_a;
|
|
|
|
|
Scene *scene_b = (Scene *)id_b;
|
|
|
|
|
id_embedded_swap((ID **)&scene_a->master_collection,
|
|
|
|
|
(ID **)&scene_b->master_collection,
|
|
|
|
|
do_full_id,
|
|
|
|
|
remapper_id_a,
|
|
|
|
|
remapper_id_b);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (remapper_id_a != nullptr) {
|
2023-04-17 17:17:02 +02:00
|
|
|
BKE_id_remapper_add(remapper_id_a, id_b, id_a);
|
|
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
if (remapper_id_b != nullptr) {
|
2023-04-17 17:17:02 +02:00
|
|
|
BKE_id_remapper_add(remapper_id_b, id_a, id_b);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-19 08:02:41 +10:00
|
|
|
/* Finalize remapping of internal references to self broken by swapping, if requested. */
|
2023-04-17 17:17:02 +02:00
|
|
|
if (do_self_remap) {
|
2023-11-30 23:03:39 +01:00
|
|
|
BKE_libblock_relink_multiple(
|
|
|
|
|
bmain, {id_a}, ID_REMAP_TYPE_REMAP, remapper_id_a, self_remap_flags);
|
|
|
|
|
BKE_libblock_relink_multiple(
|
|
|
|
|
bmain, {id_b}, ID_REMAP_TYPE_REMAP, remapper_id_b, self_remap_flags);
|
2023-04-17 17:17:02 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (input_remapper_id_a == nullptr && remapper_id_a != nullptr) {
|
2023-04-17 17:17:02 +02:00
|
|
|
BKE_id_remapper_free(remapper_id_a);
|
|
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
if (input_remapper_id_b == nullptr && remapper_id_b != nullptr) {
|
2023-04-17 17:17:02 +02:00
|
|
|
BKE_id_remapper_free(remapper_id_b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Conceptually, embedded IDs are part of their owner's data. However, some parts of the code
|
2023-04-19 08:02:41 +10:00
|
|
|
* (like e.g. the depsgraph) may treat them as independent IDs, so swapping them here and
|
2023-04-17 17:17:02 +02:00
|
|
|
* switching their pointers in the owner IDs allows to help not break cached relationships and
|
|
|
|
|
* such (by preserving the pointer values). */
|
|
|
|
|
static void id_embedded_swap(ID **embedded_id_a,
|
|
|
|
|
ID **embedded_id_b,
|
|
|
|
|
const bool do_full_id,
|
2023-07-20 11:30:25 +10:00
|
|
|
IDRemapper *remapper_id_a,
|
|
|
|
|
IDRemapper *remapper_id_b)
|
2023-04-17 17:17:02 +02:00
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
if (embedded_id_a != nullptr && *embedded_id_a != nullptr) {
|
|
|
|
|
BLI_assert(embedded_id_b != nullptr);
|
2023-04-24 15:30:04 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (*embedded_id_b == nullptr) {
|
|
|
|
|
/* Cannot swap anything if one of the embedded IDs is nullptr. */
|
2023-04-24 15:30:04 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2023-04-17 17:17:02 +02:00
|
|
|
|
|
|
|
|
/* Do not remap internal references to itself here, since embedded IDs pointers also need to be
|
|
|
|
|
* potentially remapped in owner ID's data, which will also handle embedded IDs data. */
|
2023-07-17 10:46:26 +02:00
|
|
|
id_swap(nullptr,
|
|
|
|
|
*embedded_id_a,
|
|
|
|
|
*embedded_id_b,
|
|
|
|
|
do_full_id,
|
|
|
|
|
false,
|
|
|
|
|
remapper_id_a,
|
|
|
|
|
remapper_id_b,
|
|
|
|
|
0);
|
2023-04-17 17:17:02 +02:00
|
|
|
/* Manual 'remap' of owning embedded pointer in owner ID. */
|
|
|
|
|
SWAP(ID *, *embedded_id_a, *embedded_id_b);
|
|
|
|
|
|
|
|
|
|
/* Restore internal pointers to the swapped embedded IDs in their owners' data. This also
|
|
|
|
|
* includes the potential self-references inside the embedded IDs themselves. */
|
2023-07-17 10:46:26 +02:00
|
|
|
if (remapper_id_a != nullptr) {
|
2023-04-17 17:17:02 +02:00
|
|
|
BKE_id_remapper_add(remapper_id_a, *embedded_id_b, *embedded_id_a);
|
|
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
if (remapper_id_b != nullptr) {
|
2023-04-17 17:17:02 +02:00
|
|
|
BKE_id_remapper_add(remapper_id_b, *embedded_id_a, *embedded_id_b);
|
|
|
|
|
}
|
2020-03-17 11:13:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-17 17:17:02 +02:00
|
|
|
void BKE_lib_id_swap(
|
|
|
|
|
Main *bmain, ID *id_a, ID *id_b, const bool do_self_remap, const int self_remap_flags)
|
2020-03-17 11:13:14 +01:00
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
id_swap(bmain, id_a, id_b, false, do_self_remap, nullptr, nullptr, self_remap_flags);
|
2020-03-17 11:13:14 +01:00
|
|
|
}
|
|
|
|
|
|
2023-04-17 17:17:02 +02:00
|
|
|
void BKE_lib_id_swap_full(
|
|
|
|
|
Main *bmain, ID *id_a, ID *id_b, const bool do_self_remap, const int self_remap_flags)
|
2020-03-17 11:13:14 +01:00
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
id_swap(bmain, id_a, id_b, true, do_self_remap, nullptr, nullptr, self_remap_flags);
|
2017-11-29 13:13:16 +01:00
|
|
|
}
|
|
|
|
|
|
2013-03-10 05:46:24 +00:00
|
|
|
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
|
2011-06-29 04:34:20 +00:00
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *newid = nullptr;
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2023-04-04 09:12:37 +02:00
|
|
|
if (id && (ID_REAL_USERS(id) > 1)) {
|
2019-04-27 12:07:07 +10:00
|
|
|
/* If property isn't editable,
|
|
|
|
|
* we're going to have an extra block hanging around until we save. */
|
2011-06-29 04:34:20 +00:00
|
|
|
if (RNA_property_editable(ptr, prop)) {
|
2018-06-12 12:28:14 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2019-03-10 15:23:59 +01:00
|
|
|
/* copy animation actions too */
|
2023-07-17 10:46:26 +02:00
|
|
|
newid = BKE_id_copy_ex(bmain, id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
|
|
|
|
|
if (newid != nullptr) {
|
2018-11-02 14:31:13 +01:00
|
|
|
/* us is 1 by convention with new IDs, but RNA_property_pointer_set
|
|
|
|
|
* will also increment it, decrement it here. */
|
|
|
|
|
id_us_min(newid);
|
2016-11-30 15:25:54 +01:00
|
|
|
|
2011-06-29 04:34:20 +00:00
|
|
|
/* assign copy */
|
2023-09-06 00:48:50 +02:00
|
|
|
PointerRNA idptr = RNA_id_pointer_create(newid);
|
2023-07-17 10:46:26 +02:00
|
|
|
RNA_property_pointer_set(ptr, prop, idptr, nullptr);
|
2011-06-29 04:34:20 +00:00
|
|
|
RNA_property_update(C, ptr, prop);
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-06-12 09:04:10 +10:00
|
|
|
/* tag grease pencil data-block and disable onion */
|
2023-03-08 12:35:58 +01:00
|
|
|
if (GS(id->name) == ID_GD_LEGACY) {
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
|
|
|
|
DEG_id_tag_update(newid, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
2018-08-15 16:07:16 +02:00
|
|
|
bGPdata *gpd = (bGPdata *)newid;
|
|
|
|
|
gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-10 05:46:24 +00:00
|
|
|
return true;
|
2011-06-29 04:34:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2013-03-10 05:46:24 +00:00
|
|
|
return false;
|
2011-06-29 04:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
2020-02-13 12:56:10 +01:00
|
|
|
static int libblock_management_us_plus(LibraryIDLinkCallbackData *cb_data)
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
{
|
2020-02-13 12:56:10 +01:00
|
|
|
ID **id_pointer = cb_data->id_pointer;
|
|
|
|
|
const int cb_flag = cb_data->cb_flag;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
if (cb_flag & IDWALK_CB_USER) {
|
|
|
|
|
id_us_plus(*id_pointer);
|
|
|
|
|
}
|
|
|
|
|
if (cb_flag & IDWALK_CB_USER_ONE) {
|
|
|
|
|
id_us_ensure_real(*id_pointer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-13 12:56:10 +01:00
|
|
|
static int libblock_management_us_min(LibraryIDLinkCallbackData *cb_data)
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
{
|
2020-02-13 12:56:10 +01:00
|
|
|
ID **id_pointer = cb_data->id_pointer;
|
|
|
|
|
const int cb_flag = cb_data->cb_flag;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
if (cb_flag & IDWALK_CB_USER) {
|
|
|
|
|
id_us_min(*id_pointer);
|
|
|
|
|
}
|
|
|
|
|
/* We can do nothing in IDWALK_CB_USER_ONE case! */
|
|
|
|
|
|
|
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_libblock_management_main_add(Main *bmain, void *idv)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(idv);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(bmain != nullptr);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
if ((id->tag & LIB_TAG_NO_MAIN) == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((id->tag & LIB_TAG_NOT_ALLOCATED) != 0) {
|
|
|
|
|
/* We cannot add non-allocated ID to Main! */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We cannot allow non-userrefcounting IDs in Main database! */
|
|
|
|
|
if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0) {
|
2023-07-17 10:46:26 +02:00
|
|
|
BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, nullptr, IDWALK_NOP);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ListBase *lb = which_libbase(bmain, GS(id->name));
|
|
|
|
|
BKE_main_lock(bmain);
|
|
|
|
|
BLI_addtail(lb, id);
|
2021-06-01 11:39:28 +02:00
|
|
|
/* We need to allow adding extra datablocks into libraries too, e.g. to support generating new
|
|
|
|
|
* overrides for recursive resync. */
|
2023-07-17 10:46:26 +02:00
|
|
|
BKE_id_new_name_validate(bmain, lb, id, nullptr, true);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
/* alphabetic insertion: is in new_id */
|
|
|
|
|
id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT);
|
2018-03-19 14:17:59 +01:00
|
|
|
bmain->is_memfile_undo_written = false;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
BKE_main_unlock(bmain);
|
2020-03-05 16:17:14 +01:00
|
|
|
|
|
|
|
|
BKE_lib_libblock_session_uuid_ensure(id);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_libblock_management_main_remove(Main *bmain, void *idv)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(idv);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(bmain != nullptr);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For now, allow userrefcounting IDs to get out of Main - can be handy in some cases... */
|
|
|
|
|
|
|
|
|
|
ListBase *lb = which_libbase(bmain, GS(id->name));
|
|
|
|
|
BKE_main_lock(bmain);
|
|
|
|
|
BLI_remlink(lb, id);
|
IDManagement: Speedup ID unique name assignment by tracking used names/basenames/suffixes
An implementation of T73412, roughly as outlined there:
Track the names that are in use, as well as base names (before
numeric suffix) plus a bit map for each base name, indicating which
numeric suffixes are already used. This is done per-Main/Library,
per-object-type.
Timings (Windows, VS2022 Release build, AMD Ryzen 5950X):
- Scene with 10k cubes, Shift+D to duplicate them all: 8.7s -> 1.9s.
Name map memory usage for resulting 20k objects: 4.3MB.
- Importing a 2.5GB .obj file of exported Blender 3.0 splash scene
(24k objects), using the new C++ importer: 34.2s-> 22.0s. Name map
memory usage for resulting scene: 8.6MB.
- Importing Disney Moana USD scene (almost half a million objects):
56min -> 10min. Name map usage: ~100MB. Blender crashes later on
when trying to render it, in the same place in both cases, but
that's for another day.
Reviewed By: Bastien Montagne
Differential Revision: https://developer.blender.org/D14162
2022-07-20 14:27:14 +03:00
|
|
|
BKE_main_namemap_remove_name(bmain, id, id->name + 2);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
id->tag |= LIB_TAG_NO_MAIN;
|
2018-03-19 14:17:59 +01:00
|
|
|
bmain->is_memfile_undo_written = false;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
BKE_main_unlock(bmain);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_libblock_management_usercounts_set(Main *bmain, void *idv)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(idv);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
|
|
|
|
|
if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
BKE_library_foreach_ID_link(bmain, id, libblock_management_us_plus, nullptr, IDWALK_NOP);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
id->tag &= ~LIB_TAG_NO_USER_REFCOUNT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(idv);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
|
|
|
|
|
/* We do not allow IDs in Main database to not be userrefcounting. */
|
|
|
|
|
if ((id->tag & LIB_TAG_NO_USER_REFCOUNT) != 0 || (id->tag & LIB_TAG_NO_MAIN) != 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
BKE_library_foreach_ID_link(bmain, id, libblock_management_us_min, nullptr, IDWALK_NOP);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
id->tag |= LIB_TAG_NO_USER_REFCOUNT;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-15 19:35:35 +01:00
|
|
|
void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
|
|
|
|
|
{
|
|
|
|
|
ID *id;
|
|
|
|
|
if (value) {
|
2023-07-17 10:46:26 +02:00
|
|
|
for (id = static_cast<ID *>(lb->first); id; id = static_cast<ID *>(id->next)) {
|
2016-02-15 19:35:35 +01:00
|
|
|
id->tag |= tag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const int ntag = ~tag;
|
2023-07-17 10:46:26 +02:00
|
|
|
for (id = static_cast<ID *>(lb->first); id; id = static_cast<ID *>(id->next)) {
|
2016-02-15 19:35:35 +01:00
|
|
|
id->tag &= ntag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
void BKE_main_id_tag_idcode(Main *mainvar, const short type, const int tag, const bool value)
|
2016-02-15 19:35:35 +01:00
|
|
|
{
|
|
|
|
|
ListBase *lb = which_libbase(mainvar, type);
|
|
|
|
|
|
|
|
|
|
BKE_main_id_tag_listbase(lb, tag, value);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
void BKE_main_id_tag_all(Main *mainvar, const int tag, const bool value)
|
2016-02-15 19:35:35 +01:00
|
|
|
{
|
2021-03-04 18:39:07 +01:00
|
|
|
ListBase *lbarray[INDEX_ID_MAX];
|
2016-02-15 19:35:35 +01:00
|
|
|
int a;
|
|
|
|
|
|
|
|
|
|
a = set_listbasepointers(mainvar, lbarray);
|
|
|
|
|
while (a--) {
|
|
|
|
|
BKE_main_id_tag_listbase(lbarray[a], tag, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
|
2007-04-20 18:48:30 +00:00
|
|
|
{
|
|
|
|
|
ID *id;
|
|
|
|
|
if (value) {
|
2023-07-17 10:46:26 +02:00
|
|
|
for (id = static_cast<ID *>(lb->first); id; id = static_cast<ID *>(id->next)) {
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
id->tag |= flag;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
|
else {
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
const int nflag = ~flag;
|
2023-07-17 10:46:26 +02:00
|
|
|
for (id = static_cast<ID *>(lb->first); id; id = static_cast<ID *>(id->next)) {
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
id->tag &= nflag;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2007-04-20 18:48:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Split id->flag in two, persistent flags and runtime tags.
This is purely internal sanitizing/cleanup, no change in behavior is expected at all.
This change was also needed because we were getting short on ID flags, and
future enhancement of 'user_one' ID behavior requires two new ones.
id->flag remains for persistent data (fakeuser only, so far!), this also allows us
100% backward & forward compatibility.
New id->tag is used for most flags. Though written in .blend files, its content
is cleared at read time.
Note that .blend file version was bumped, so that we can clear runtimeflags from
old .blends, important in case we add new persistent flags in future.
Also, behavior of tags (either status ones, or whether they need to be cleared before/after use)
has been added as comments to their declaration.
Reviewers: sergey, campbellbarton
Differential Revision: https://developer.blender.org/D1683
2015-12-27 11:53:50 +01:00
|
|
|
void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
|
2007-04-20 18:48:30 +00:00
|
|
|
{
|
2021-03-04 18:39:07 +01:00
|
|
|
ListBase *lbarray[INDEX_ID_MAX];
|
2007-04-20 18:48:30 +00:00
|
|
|
int a;
|
2013-12-30 13:25:27 +11:00
|
|
|
a = set_listbasepointers(bmain, lbarray);
|
|
|
|
|
while (a--) {
|
|
|
|
|
BKE_main_id_flag_listbase(lbarray[a], flag, value);
|
|
|
|
|
}
|
2007-04-20 18:48:30 +00:00
|
|
|
}
|
|
|
|
|
|
IDManagement: Speedup ID unique name assignment by tracking used names/basenames/suffixes
An implementation of T73412, roughly as outlined there:
Track the names that are in use, as well as base names (before
numeric suffix) plus a bit map for each base name, indicating which
numeric suffixes are already used. This is done per-Main/Library,
per-object-type.
Timings (Windows, VS2022 Release build, AMD Ryzen 5950X):
- Scene with 10k cubes, Shift+D to duplicate them all: 8.7s -> 1.9s.
Name map memory usage for resulting 20k objects: 4.3MB.
- Importing a 2.5GB .obj file of exported Blender 3.0 splash scene
(24k objects), using the new C++ importer: 34.2s-> 22.0s. Name map
memory usage for resulting scene: 8.6MB.
- Importing Disney Moana USD scene (almost half a million objects):
56min -> 10min. Name map usage: ~100MB. Blender crashes later on
when trying to render it, in the same place in both cases, but
that's for another day.
Reviewed By: Bastien Montagne
Differential Revision: https://developer.blender.org/D14162
2022-07-20 14:27:14 +03:00
|
|
|
void BKE_main_id_repair_duplicate_names_listbase(Main *bmain, ListBase *lb)
|
2019-01-29 23:43:11 +11:00
|
|
|
{
|
|
|
|
|
int lb_len = 0;
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (ID *, id, lb) {
|
2021-08-26 15:01:14 +02:00
|
|
|
if (!ID_IS_LINKED(id)) {
|
2019-01-29 23:43:11 +11:00
|
|
|
lb_len += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (lb_len <= 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-29 23:43:11 +11:00
|
|
|
/* Fill an array because renaming sorts. */
|
2023-07-17 10:46:26 +02:00
|
|
|
ID **id_array = static_cast<ID **>(MEM_mallocN(sizeof(*id_array) * lb_len, __func__));
|
2019-01-29 23:43:11 +11:00
|
|
|
GSet *gset = BLI_gset_str_new_ex(__func__, lb_len);
|
|
|
|
|
int i = 0;
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (ID *, id, lb) {
|
2021-08-26 15:01:14 +02:00
|
|
|
if (!ID_IS_LINKED(id)) {
|
2019-01-29 23:43:11 +11:00
|
|
|
id_array[i] = id;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < lb_len; i++) {
|
|
|
|
|
if (!BLI_gset_add(gset, id_array[i]->name + 2)) {
|
2023-07-17 10:46:26 +02:00
|
|
|
BKE_id_new_name_validate(bmain, lb, id_array[i], nullptr, false);
|
2019-01-29 23:43:11 +11:00
|
|
|
}
|
|
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_gset_free(gset, nullptr);
|
2019-01-29 23:43:11 +11:00
|
|
|
MEM_freeN(id_array);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-30 13:25:27 +11:00
|
|
|
void BKE_main_lib_objects_recalc_all(Main *bmain)
|
2009-09-12 19:54:39 +00:00
|
|
|
{
|
2009-09-14 12:30:49 +00:00
|
|
|
Object *ob;
|
|
|
|
|
|
|
|
|
|
/* flag for full recalc */
|
2023-07-17 10:46:26 +02:00
|
|
|
for (ob = static_cast<Object *>(bmain->objects.first); ob;
|
|
|
|
|
ob = static_cast<Object *>(ob->id.next)) {
|
2017-11-06 17:17:10 +01:00
|
|
|
if (ID_IS_LINKED(ob)) {
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
|
2015-06-29 12:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-01-09 19:13:26 +06:00
|
|
|
|
2017-04-06 16:11:50 +02:00
|
|
|
DEG_id_type_tag(bmain, ID_OB);
|
2009-09-12 19:54:39 +00:00
|
|
|
}
|
2007-04-20 18:48:30 +00:00
|
|
|
|
2003-04-26 11:56:44 +00:00
|
|
|
/* *********** ALLOC AND FREE *****************
|
2012-03-03 20:19:11 +00:00
|
|
|
*
|
2012-05-05 14:03:12 +00:00
|
|
|
* BKE_libblock_free(ListBase *lb, ID *id )
|
2019-06-12 09:04:10 +10:00
|
|
|
* provide a list-basis and data-block, but only ID is read
|
2012-03-03 20:19:11 +00:00
|
|
|
*
|
2012-05-05 14:03:12 +00:00
|
|
|
* void *BKE_libblock_alloc(ListBase *lb, type, name)
|
2012-03-03 20:19:11 +00:00
|
|
|
* inserts in list and returns a new ID
|
|
|
|
|
*
|
|
|
|
|
* **************************** */
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2017-06-13 17:42:31 +02:00
|
|
|
size_t BKE_libblock_get_alloc_info(short type, const char **name)
|
|
|
|
|
{
|
2020-03-20 11:21:02 +01:00
|
|
|
const IDTypeInfo *id_type = BKE_idtype_get_info_from_idcode(type);
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (id_type == nullptr) {
|
|
|
|
|
if (name != nullptr) {
|
|
|
|
|
*name = nullptr;
|
2020-03-20 11:21:02 +01:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (name != nullptr) {
|
2020-03-20 11:21:02 +01:00
|
|
|
*name = id_type->name;
|
2017-06-13 17:42:31 +02:00
|
|
|
}
|
2020-03-20 11:21:02 +01:00
|
|
|
return id_type->struct_size;
|
2017-06-13 17:42:31 +02:00
|
|
|
}
|
|
|
|
|
|
First step to handle missing libs/datablocks when reading a file.
Idea is, instead of ignoring completely missing linked datablocks, to
create void placeholders for them.
That way, you can work on your file, save it, and find again your missing data once
lib becomes available again. Or you can edit missing lib's path (in Outliner),
save and reload the file, and you are done.
Also, Outliner now shows broken libraries (and placeholders) with a 'broken lib' icon.
Future plans are also to be able to relocate missing libs and reload them at runtime.
Code notes:
- Placeholder ID is just a regular datablock of same type as expected linked one,
with 'default' data, and a LIB_MISSING bitflag set.
- To allow creation of such datablocks, creation of datablocks in BKE was split in two step:
+ Allocation of memory itself.
+ Setting of all internal data to default values.
See also the design task (T43351).
Reviewed by @campbellbarton, thanks a bunch!
Differential Revision: https://developer.blender.org/D1394
2015-10-20 14:44:57 +02:00
|
|
|
void *BKE_libblock_alloc_notest(short type)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2017-06-13 17:42:31 +02:00
|
|
|
const char *name;
|
|
|
|
|
size_t size = BKE_libblock_get_alloc_info(type, &name);
|
|
|
|
|
if (size != 0) {
|
|
|
|
|
return MEM_callocN(size, name);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2021-07-15 18:23:28 +10:00
|
|
|
BLI_assert_msg(0, "Request to allocate unknown data type");
|
2023-07-17 10:46:26 +02:00
|
|
|
return nullptr;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int flag)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
BLI_assert((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != nullptr);
|
2020-10-06 17:43:12 +02:00
|
|
|
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_LOCAL) == 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(BKE_libblock_alloc_notest(type));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (id) {
|
2017-08-10 10:27:47 +02:00
|
|
|
if ((flag & LIB_ID_CREATE_NO_MAIN) != 0) {
|
|
|
|
|
id->tag |= LIB_TAG_NO_MAIN;
|
|
|
|
|
}
|
|
|
|
|
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0) {
|
|
|
|
|
id->tag |= LIB_TAG_NO_USER_REFCOUNT;
|
|
|
|
|
}
|
2020-10-06 17:43:12 +02:00
|
|
|
if (flag & LIB_ID_CREATE_LOCAL) {
|
|
|
|
|
id->tag |= LIB_TAG_LOCALIZED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2005-12-21 22:21:43 +00:00
|
|
|
id->icon_id = 0;
|
2017-08-10 10:27:47 +02:00
|
|
|
*((short *)id->name) = type;
|
2017-08-09 14:38:07 +02:00
|
|
|
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
id->us = 1;
|
|
|
|
|
}
|
|
|
|
|
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
2021-10-19 08:39:10 -05:00
|
|
|
/* Note that 2.8x versioning has tested not to cause conflicts. Node trees are
|
|
|
|
|
* skipped in this check to allow adding a geometry node tree for versioning. */
|
|
|
|
|
BLI_assert(bmain->is_locked_for_linking == false || ELEM(type, ID_WS, ID_GR, ID_NT));
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
ListBase *lb = which_libbase(bmain, type);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
BKE_main_lock(bmain);
|
|
|
|
|
BLI_addtail(lb, id);
|
IDManagement: Speedup ID unique name assignment by tracking used names/basenames/suffixes
An implementation of T73412, roughly as outlined there:
Track the names that are in use, as well as base names (before
numeric suffix) plus a bit map for each base name, indicating which
numeric suffixes are already used. This is done per-Main/Library,
per-object-type.
Timings (Windows, VS2022 Release build, AMD Ryzen 5950X):
- Scene with 10k cubes, Shift+D to duplicate them all: 8.7s -> 1.9s.
Name map memory usage for resulting 20k objects: 4.3MB.
- Importing a 2.5GB .obj file of exported Blender 3.0 splash scene
(24k objects), using the new C++ importer: 34.2s-> 22.0s. Name map
memory usage for resulting scene: 8.6MB.
- Importing Disney Moana USD scene (almost half a million objects):
56min -> 10min. Name map usage: ~100MB. Blender crashes later on
when trying to render it, in the same place in both cases, but
that's for another day.
Reviewed By: Bastien Montagne
Differential Revision: https://developer.blender.org/D14162
2022-07-20 14:27:14 +03:00
|
|
|
BKE_id_new_name_validate(bmain, lb, id, name, false);
|
2018-03-19 14:17:59 +01:00
|
|
|
bmain->is_memfile_undo_written = false;
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
/* alphabetic insertion: is in new_id */
|
|
|
|
|
BKE_main_unlock(bmain);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-27 12:09:32 +02:00
|
|
|
/* 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. */
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(bmain->curlib == nullptr || bmain->curlib->runtime.name_map == nullptr);
|
2021-10-21 15:04:39 +02:00
|
|
|
/* 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;
|
|
|
|
|
|
2021-07-03 23:08:40 +10:00
|
|
|
/* TODO: to be removed from here! */
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) {
|
|
|
|
|
DEG_id_type_tag(bmain, type);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-10 10:26:22 +02:00
|
|
|
else {
|
|
|
|
|
BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
|
|
|
|
|
}
|
2021-01-11 16:41:22 +01:00
|
|
|
|
|
|
|
|
/* We also need to ensure a valid `session_uuid` for some non-main data (like embedded IDs).
|
|
|
|
|
* IDs not allocated however should not need those (this would e.g. avoid generating session
|
|
|
|
|
* uuids for depsgraph CoW IDs, if it was using this function). */
|
|
|
|
|
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) == 0) {
|
|
|
|
|
BKE_lib_libblock_session_uuid_ensure(id);
|
|
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
First step to handle missing libs/datablocks when reading a file.
Idea is, instead of ignoring completely missing linked datablocks, to
create void placeholders for them.
That way, you can work on your file, save it, and find again your missing data once
lib becomes available again. Or you can edit missing lib's path (in Outliner),
save and reload the file, and you are done.
Also, Outliner now shows broken libraries (and placeholders) with a 'broken lib' icon.
Future plans are also to be able to relocate missing libs and reload them at runtime.
Code notes:
- Placeholder ID is just a regular datablock of same type as expected linked one,
with 'default' data, and a LIB_MISSING bitflag set.
- To allow creation of such datablocks, creation of datablocks in BKE was split in two step:
+ Allocation of memory itself.
+ Setting of all internal data to default values.
See also the design task (T43351).
Reviewed by @campbellbarton, thanks a bunch!
Differential Revision: https://developer.blender.org/D1394
2015-10-20 14:44:57 +02:00
|
|
|
void BKE_libblock_init_empty(ID *id)
|
|
|
|
|
{
|
2020-03-05 10:54:00 +01:00
|
|
|
const IDTypeInfo *idtype_info = BKE_idtype_get_info_from_id(id);
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (idtype_info != nullptr) {
|
|
|
|
|
if (idtype_info->init_data != nullptr) {
|
2020-03-05 10:54:00 +01:00
|
|
|
idtype_info->init_data(id);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-15 18:23:28 +10:00
|
|
|
BLI_assert_msg(0, "IDType Missing IDTypeInfo");
|
First step to handle missing libs/datablocks when reading a file.
Idea is, instead of ignoring completely missing linked datablocks, to
create void placeholders for them.
That way, you can work on your file, save it, and find again your missing data once
lib becomes available again. Or you can edit missing lib's path (in Outliner),
save and reload the file, and you are done.
Also, Outliner now shows broken libraries (and placeholders) with a 'broken lib' icon.
Future plans are also to be able to relocate missing libs and reload them at runtime.
Code notes:
- Placeholder ID is just a regular datablock of same type as expected linked one,
with 'default' data, and a LIB_MISSING bitflag set.
- To allow creation of such datablocks, creation of datablocks in BKE was split in two step:
+ Allocation of memory itself.
+ Setting of all internal data to default values.
See also the design task (T43351).
Reviewed by @campbellbarton, thanks a bunch!
Differential Revision: https://developer.blender.org/D1394
2015-10-20 14:44:57 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:53:08 +01:00
|
|
|
void BKE_libblock_runtime_reset_remapping_status(ID *id)
|
|
|
|
|
{
|
|
|
|
|
id->runtime.remap.status = 0;
|
|
|
|
|
id->runtime.remap.skipped_refcounted = 0;
|
|
|
|
|
id->runtime.remap.skipped_direct = 0;
|
|
|
|
|
id->runtime.remap.skipped_indirect = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-05 16:17:14 +01:00
|
|
|
/* ********** ID session-wise UUID management. ********** */
|
|
|
|
|
static uint global_session_uuid = 0;
|
|
|
|
|
|
|
|
|
|
void BKE_lib_libblock_session_uuid_ensure(ID *id)
|
|
|
|
|
{
|
|
|
|
|
if (id->session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
|
2021-03-09 01:01:31 +11:00
|
|
|
BLI_assert((id->tag & LIB_TAG_TEMP_MAIN) == 0); /* Caller must ensure this. */
|
2020-03-05 16:17:14 +01:00
|
|
|
id->session_uuid = atomic_add_and_fetch_uint32(&global_session_uuid, 1);
|
|
|
|
|
/* In case overflow happens, still assign a valid ID. This way opening files many times works
|
|
|
|
|
* correctly. */
|
|
|
|
|
if (UNLIKELY(id->session_uuid == MAIN_ID_SESSION_UUID_UNSET)) {
|
|
|
|
|
id->session_uuid = atomic_add_and_fetch_uint32(&global_session_uuid, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-21 18:26:32 +02:00
|
|
|
void BKE_lib_libblock_session_uuid_renew(ID *id)
|
|
|
|
|
{
|
|
|
|
|
id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
|
|
|
|
|
BKE_lib_libblock_session_uuid_ensure(id);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-04 12:53:20 +02:00
|
|
|
void *BKE_id_new(Main *bmain, const short type, const char *name)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(bmain != nullptr);
|
2018-05-04 12:53:20 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (name == nullptr) {
|
2020-03-19 19:37:00 +01:00
|
|
|
name = DATA_(BKE_idtype_idcode_to_name(type));
|
2018-05-04 12:53:20 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(BKE_libblock_alloc(bmain, type, name, 0));
|
2018-05-04 12:53:20 +02:00
|
|
|
BKE_libblock_init_empty(id);
|
|
|
|
|
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *BKE_id_new_nomain(const short type, const char *name)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
if (name == nullptr) {
|
2020-03-19 19:37:00 +01:00
|
|
|
name = DATA_(BKE_idtype_idcode_to_name(type));
|
2018-05-04 12:53:20 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(BKE_libblock_alloc(
|
|
|
|
|
nullptr,
|
|
|
|
|
type,
|
|
|
|
|
name,
|
|
|
|
|
LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_DEG_TAG));
|
2018-05-04 12:53:20 +02:00
|
|
|
BKE_libblock_init_empty(id);
|
|
|
|
|
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-16 22:55:44 +02:00
|
|
|
void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int orig_flag)
|
2010-02-15 08:50:04 +00:00
|
|
|
{
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
ID *new_id = *r_newid;
|
2019-09-16 22:55:44 +02:00
|
|
|
int flag = orig_flag;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-05-24 12:11:10 +02:00
|
|
|
const bool is_embedded_id = (id->flag & LIB_EMBEDDED_DATA) != 0;
|
2019-09-12 12:24:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != nullptr);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
|
2020-10-06 17:43:12 +02:00
|
|
|
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_LOCAL) == 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-05-24 12:11:10 +02:00
|
|
|
/* Embedded ID handling.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: This makes copying code of embedded IDs non-reentrant (i.e. copying an embedded ID as
|
|
|
|
|
* part of another embedded ID would not work properly). This is not an issue currently, but may
|
|
|
|
|
* need to be addressed in the future. */
|
2023-07-17 10:46:26 +02:00
|
|
|
if ((bmain != nullptr) && is_embedded_id) {
|
2019-09-02 14:18:12 +02:00
|
|
|
flag |= LIB_ID_CREATE_NO_MAIN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The id->flag bits to copy over. */
|
2020-03-11 12:47:25 +01:00
|
|
|
const int copy_idflag_mask = LIB_EMBEDDED_DATA;
|
2019-09-02 14:18:12 +02:00
|
|
|
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
|
|
|
|
|
/* r_newid already contains pointer to allocated memory. */
|
2021-07-03 23:08:40 +10:00
|
|
|
/* TODO: do we want to memset(0) whole mem before filling it? */
|
2023-05-09 12:50:37 +10:00
|
|
|
STRNCPY(new_id->name, id->name);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
new_id->us = 0;
|
|
|
|
|
new_id->tag |= LIB_TAG_NOT_ALLOCATED | LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT;
|
2021-07-03 23:08:40 +10:00
|
|
|
/* TODO: Do we want/need to copy more from ID struct itself? */
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2023-07-17 10:46:26 +02:00
|
|
|
new_id = static_cast<ID *>(BKE_libblock_alloc(bmain, GS(id->name), id->name + 2, flag));
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(new_id != nullptr);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-05-18 12:53:28 +10:00
|
|
|
if ((flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) != 0) {
|
|
|
|
|
new_id->tag |= LIB_TAG_COPIED_ON_WRITE;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
new_id->tag &= ~LIB_TAG_COPIED_ON_WRITE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
const size_t id_len = BKE_libblock_get_alloc_info(GS(new_id->name), nullptr);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
const size_t id_offset = sizeof(ID);
|
2023-07-18 14:18:07 +10:00
|
|
|
if (int(id_len) - int(id_offset) > 0) { /* signed to allow neg result */ /* XXX ????? */
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
const char *cp = (const char *)id;
|
|
|
|
|
char *cpn = (char *)new_id;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
memcpy(cpn + id_offset, cp + id_offset, id_len - id_offset);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-09-16 22:55:44 +02:00
|
|
|
new_id->flag = (new_id->flag & ~copy_idflag_mask) | (id->flag & copy_idflag_mask);
|
2019-08-22 20:43:19 +03:00
|
|
|
|
2023-05-24 12:11:10 +02:00
|
|
|
/* 'Private ID' data handling. */
|
|
|
|
|
if (is_embedded_id && (orig_flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
|
|
|
|
new_id->tag &= ~LIB_TAG_NO_MAIN;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-16 18:13:19 +10:00
|
|
|
/* We do not want any handling of user-count in code duplicating the data here, we do that all
|
2019-10-14 11:12:13 +02:00
|
|
|
* at once in id_copy_libmanagement_cb() at the end. */
|
|
|
|
|
const int copy_data_flag = orig_flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
|
|
|
|
|
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
if (id->properties) {
|
2019-10-14 11:12:13 +02:00
|
|
|
new_id->properties = IDP_CopyProperty_ex(id->properties, copy_data_flag);
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-09-17 16:22:29 +02:00
|
|
|
/* This is never duplicated, only one existing ID should have a given weak ref to library/ID. */
|
2023-07-17 10:46:26 +02:00
|
|
|
new_id->library_weak_reference = nullptr;
|
2021-09-17 16:22:29 +02:00
|
|
|
|
2021-04-10 15:16:38 +02:00
|
|
|
if ((orig_flag & LIB_ID_COPY_NO_LIB_OVERRIDE) == 0) {
|
2021-01-15 17:44:35 +01:00
|
|
|
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
|
|
|
|
|
/* We do not want to copy existing override rules here, as they would break the proper
|
|
|
|
|
* remapping between IDs. Proper overrides rules will be re-generated anyway. */
|
|
|
|
|
BKE_lib_override_library_copy(new_id, id, false);
|
|
|
|
|
}
|
|
|
|
|
else if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id)) {
|
|
|
|
|
/* Just ensure virtual overrides do get properly tagged, there is not actual override data to
|
|
|
|
|
* copy here. */
|
|
|
|
|
new_id->flag |= LIB_EMBEDDED_DATA_LIB_OVERRIDE;
|
|
|
|
|
}
|
2017-11-29 15:05:03 +01:00
|
|
|
}
|
|
|
|
|
|
2018-11-07 13:55:29 +01:00
|
|
|
if (id_can_have_animdata(new_id)) {
|
2018-05-03 11:07:09 +02:00
|
|
|
IdAdtTemplate *iat = (IdAdtTemplate *)new_id;
|
2018-11-07 13:55:29 +01:00
|
|
|
|
|
|
|
|
/* the duplicate should get a copy of the animdata */
|
|
|
|
|
if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) {
|
2023-07-09 21:22:31 +10:00
|
|
|
/* Note that even though horrors like root node-trees are not in bmain, the actions they use
|
2019-09-19 13:18:52 +10:00
|
|
|
* in their anim data *are* in bmain... super-mega-hooray. */
|
2019-10-14 11:12:13 +02:00
|
|
|
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);
|
2018-11-07 13:55:29 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2023-07-17 10:46:26 +02:00
|
|
|
iat->adt = nullptr;
|
2018-11-07 13:55:29 +01:00
|
|
|
}
|
2018-05-03 11:07:09 +02:00
|
|
|
}
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
|
|
|
|
|
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
2017-08-07 20:48:22 +02:00
|
|
|
DEG_id_type_tag(bmain, GS(new_id->name));
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*r_newid = new_id;
|
2010-02-15 08:50:04 +00:00
|
|
|
}
|
|
|
|
|
|
2017-06-14 22:36:30 +02:00
|
|
|
void *BKE_libblock_copy(Main *bmain, const ID *id)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2011-11-07 04:36:37 +00:00
|
|
|
ID *idn;
|
2010-10-07 10:04:07 +00:00
|
|
|
|
Refactor ID copying (and to some extent, ID freeing).
This will allow much finer controll over how we copy data-blocks, from
full copy in Main database, to "lighter" ones (out of Main, inside an
already allocated datablock, etc.).
This commit also transfers a llot of what was previously handled by
per-ID-type custom code to generic ID handling code in BKE_library.
Hopefully will avoid in future inconsistencies and missing bits we had
all over the codebase in the past.
It also adds missing copying handling for a few types, most notably
Scene (which where using a fully customized handling previously).
Note that the type of allocation used during copying (regular in Main,
allocated but outside of Main, or not allocated by ID handling code at
all) is stored in ID's, which allows to handle them correctly when
freeing. This needs to be taken care of with caution when doing 'weird'
unusual things with ID copying and/or allocation!
As a final note, while rather noisy, this commit will hopefully not
break too much existing branches, old 'API' has been kept for the main
part, as a wrapper around new code. Cleaning it up will happen later.
Design task : T51804
Phab Diff: D2714
2017-08-07 16:39:55 +02:00
|
|
|
BKE_libblock_copy_ex(bmain, id, &idn, 0);
|
2010-10-07 10:04:07 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
return idn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ***************** ID ************************ */
|
2021-12-07 17:19:15 +11:00
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
ID *BKE_libblock_find_name(Main *bmain, const short type, const char *name)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2014-07-23 20:20:59 +10:00
|
|
|
ListBase *lb = which_libbase(bmain, type);
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(lb != nullptr);
|
|
|
|
|
return static_cast<ID *>(BLI_findstring(lb, name, offsetof(ID, name) + 2));
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
ID *BKE_libblock_find_session_uuid(Main *bmain, const short type, const uint32_t session_uuid)
|
2021-11-05 11:19:12 -05:00
|
|
|
{
|
|
|
|
|
ListBase *lb = which_libbase(bmain, type);
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(lb != nullptr);
|
2021-11-05 11:19:12 -05:00
|
|
|
LISTBASE_FOREACH (ID *, id, lb) {
|
|
|
|
|
if (id->session_uuid == session_uuid) {
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
return nullptr;
|
2021-11-05 11:19:12 -05:00
|
|
|
}
|
|
|
|
|
|
2019-12-19 21:58:59 +01:00
|
|
|
void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2019-12-19 21:58:59 +01:00
|
|
|
#define ID_SORT_STEP_SIZE 512
|
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
ID *idtest;
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2012-05-06 17:22:54 +00:00
|
|
|
/* insert alphabetically */
|
2019-12-19 21:58:59 +01:00
|
|
|
if (lb->first == lb->last) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_remlink(lb, id);
|
|
|
|
|
|
|
|
|
|
/* Check if we can actually insert id before or after id_sorting_hint, if given. */
|
2023-07-17 10:46:26 +02:00
|
|
|
if (!ELEM(id_sorting_hint, nullptr, id) && id_sorting_hint->lib == id->lib) {
|
2019-12-19 21:58:59 +01:00
|
|
|
BLI_assert(BLI_findindex(lb, id_sorting_hint) >= 0);
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id_sorting_hint_next = static_cast<ID *>(id_sorting_hint->next);
|
2019-12-19 21:58:59 +01:00
|
|
|
if (BLI_strcasecmp(id_sorting_hint->name, id->name) < 0 &&
|
2023-07-17 10:46:26 +02:00
|
|
|
(id_sorting_hint_next == nullptr || id_sorting_hint_next->lib != id->lib ||
|
2019-12-19 21:58:59 +01:00
|
|
|
BLI_strcasecmp(id_sorting_hint_next->name, id->name) > 0))
|
|
|
|
|
{
|
|
|
|
|
BLI_insertlinkafter(lb, id_sorting_hint, id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id_sorting_hint_prev = static_cast<ID *>(id_sorting_hint->prev);
|
2019-12-19 21:58:59 +01:00
|
|
|
if (BLI_strcasecmp(id_sorting_hint->name, id->name) > 0 &&
|
2023-07-17 10:46:26 +02:00
|
|
|
(id_sorting_hint_prev == nullptr || id_sorting_hint_prev->lib != id->lib ||
|
2019-12-19 21:58:59 +01:00
|
|
|
BLI_strcasecmp(id_sorting_hint_prev->name, id->name) < 0))
|
|
|
|
|
{
|
|
|
|
|
BLI_insertlinkbefore(lb, id_sorting_hint, id);
|
|
|
|
|
return;
|
ID Management: Improve speed of code used when creating/renaming and ID.
This alone can make e.g. adding 40k IDs with default name (i.e. 'fully
constant' case in table below) about 15-20% faster:
| Number and type of names of IDs | old code | new code | speed improvement |
| -------------------------------- | -------- | -------- | ----------------- |
| 40K, mixed (14k rand, 26k const) | 75s | 62s | 21% |
| 40K, fully random | 90s | 76s | 18% |
| 40K, fully constant | 94s | 77s | 22% |
Idea is to use a first pass, where we just check one item every nth ones,
until we have found the chunk in which we want to insert the new item,
then do a basic linear comparison with all items in that chunk as before.
Also, list is now walked backward, as in most common 'massive insertion'
cases new ID's names have higher number, hence ends up towards the end of
the list.
This new sorting function can be between a few percents and 50% quicker than
original code, depending on various factors (like length of common parts of
ID names, whether new IDs should be added towards the end or not, how high
in numbering we are, etc.).
Note: another, full bisecting approach was also tried, which gives a massive
reduction of comparisons (from n items to log2(n)), but it only gave minor
improvements of speed from original fully linear code, while adding a fair
amount of complexity to the logic. Only case it was shining was the unlikely
'very long, almost similar ID names' case (since `strcasecmp()` is rather
costly then).
2019-12-13 19:18:01 +01:00
|
|
|
}
|
2019-12-19 21:58:59 +01:00
|
|
|
}
|
ID Management: Improve speed of code used when creating/renaming and ID.
This alone can make e.g. adding 40k IDs with default name (i.e. 'fully
constant' case in table below) about 15-20% faster:
| Number and type of names of IDs | old code | new code | speed improvement |
| -------------------------------- | -------- | -------- | ----------------- |
| 40K, mixed (14k rand, 26k const) | 75s | 62s | 21% |
| 40K, fully random | 90s | 76s | 18% |
| 40K, fully constant | 94s | 77s | 22% |
Idea is to use a first pass, where we just check one item every nth ones,
until we have found the chunk in which we want to insert the new item,
then do a basic linear comparison with all items in that chunk as before.
Also, list is now walked backward, as in most common 'massive insertion'
cases new ID's names have higher number, hence ends up towards the end of
the list.
This new sorting function can be between a few percents and 50% quicker than
original code, depending on various factors (like length of common parts of
ID names, whether new IDs should be added towards the end or not, how high
in numbering we are, etc.).
Note: another, full bisecting approach was also tried, which gives a massive
reduction of comparisons (from n items to log2(n)), but it only gave minor
improvements of speed from original fully linear code, while adding a fair
amount of complexity to the logic. Only case it was shining was the unlikely
'very long, almost similar ID names' case (since `strcasecmp()` is rather
costly then).
2019-12-13 19:18:01 +01:00
|
|
|
|
2019-12-19 21:58:59 +01:00
|
|
|
void *item_array[ID_SORT_STEP_SIZE];
|
|
|
|
|
int item_array_index;
|
|
|
|
|
|
|
|
|
|
/* Step one: We go backward over a whole chunk of items at once, until we find a limit item
|
|
|
|
|
* that is lower than, or equal (should never happen!) to the one we want to insert. */
|
2021-07-03 23:08:40 +10:00
|
|
|
/* NOTE: We start from the end, because in typical 'heavy' case (insertion of lots of IDs at
|
2019-12-19 21:58:59 +01:00
|
|
|
* once using the same base name), newly inserted items will generally be towards the end
|
|
|
|
|
* (higher extension numbers). */
|
2021-05-19 17:04:10 +02:00
|
|
|
bool is_in_library = false;
|
|
|
|
|
item_array_index = ID_SORT_STEP_SIZE - 1;
|
2023-07-17 10:46:26 +02:00
|
|
|
for (idtest = static_cast<ID *>(lb->last); idtest != nullptr;
|
|
|
|
|
idtest = static_cast<ID *>(idtest->prev))
|
|
|
|
|
{
|
2021-05-19 17:04:10 +02:00
|
|
|
if (is_in_library) {
|
|
|
|
|
if (idtest->lib != id->lib) {
|
|
|
|
|
/* We got out of expected library 'range' in the list, so we are done here and can move on
|
|
|
|
|
* to the next step. */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (idtest->lib == id->lib) {
|
|
|
|
|
/* We are entering the expected library 'range' of IDs in the list. */
|
|
|
|
|
is_in_library = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!is_in_library) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-19 21:58:59 +01:00
|
|
|
item_array[item_array_index] = idtest;
|
|
|
|
|
if (item_array_index == 0) {
|
2021-05-19 17:04:10 +02:00
|
|
|
if (BLI_strcasecmp(idtest->name, id->name) <= 0) {
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2019-12-19 21:58:59 +01:00
|
|
|
item_array_index = ID_SORT_STEP_SIZE;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2021-05-19 17:04:10 +02:00
|
|
|
item_array_index--;
|
2019-12-19 21:58:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Step two: we go forward in the selected chunk of items and check all of them, as we know
|
|
|
|
|
* that our target is in there. */
|
|
|
|
|
|
|
|
|
|
/* If we reached start of the list, current item_array_index is off-by-one.
|
|
|
|
|
* Otherwise, we already know that it points to an item lower-or-equal-than the one we want to
|
|
|
|
|
* insert, no need to redo the check for that one.
|
|
|
|
|
* So we can increment that index in any case. */
|
|
|
|
|
for (item_array_index++; item_array_index < ID_SORT_STEP_SIZE; item_array_index++) {
|
2023-07-17 10:46:26 +02:00
|
|
|
idtest = static_cast<ID *>(item_array[item_array_index]);
|
2021-05-19 17:04:10 +02:00
|
|
|
if (BLI_strcasecmp(idtest->name, id->name) > 0) {
|
2019-12-19 21:58:59 +01:00
|
|
|
BLI_insertlinkbefore(lb, idtest, id);
|
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-12-19 21:58:59 +01:00
|
|
|
if (item_array_index == ID_SORT_STEP_SIZE) {
|
2023-07-17 10:46:26 +02:00
|
|
|
if (idtest == nullptr) {
|
|
|
|
|
/* If idtest is nullptr here, it means that in the first loop, the last comparison was
|
2021-05-19 17:04:10 +02:00
|
|
|
* performed exactly on the first item of the list, and that it also failed. And that the
|
|
|
|
|
* second loop was not walked at all.
|
|
|
|
|
*
|
|
|
|
|
* In other words, if `id` is local, all the items in the list are greater than the inserted
|
|
|
|
|
* one, so we can put it at the start of the list. Or, if `id` is linked, it is the first one
|
|
|
|
|
* of its library, and we can put it at the very end of the list. */
|
|
|
|
|
if (ID_IS_LINKED(id)) {
|
|
|
|
|
BLI_addtail(lb, id);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_addhead(lb, id);
|
|
|
|
|
}
|
2019-12-19 21:58:59 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_insertlinkafter(lb, idtest, id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
ID Management: Improve speed of code used when creating/renaming and ID.
This alone can make e.g. adding 40k IDs with default name (i.e. 'fully
constant' case in table below) about 15-20% faster:
| Number and type of names of IDs | old code | new code | speed improvement |
| -------------------------------- | -------- | -------- | ----------------- |
| 40K, mixed (14k rand, 26k const) | 75s | 62s | 21% |
| 40K, fully random | 90s | 76s | 18% |
| 40K, fully constant | 94s | 77s | 22% |
Idea is to use a first pass, where we just check one item every nth ones,
until we have found the chunk in which we want to insert the new item,
then do a basic linear comparison with all items in that chunk as before.
Also, list is now walked backward, as in most common 'massive insertion'
cases new ID's names have higher number, hence ends up towards the end of
the list.
This new sorting function can be between a few percents and 50% quicker than
original code, depending on various factors (like length of common parts of
ID names, whether new IDs should be added towards the end or not, how high
in numbering we are, etc.).
Note: another, full bisecting approach was also tried, which gives a massive
reduction of comparisons (from n items to log2(n)), but it only gave minor
improvements of speed from original fully linear code, while adding a fair
amount of complexity to the logic. Only case it was shining was the unlikely
'very long, almost similar ID names' case (since `strcasecmp()` is rather
costly then).
2019-12-13 19:18:01 +01:00
|
|
|
#undef ID_SORT_STEP_SIZE
|
2019-12-19 21:58:59 +01:00
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
|
IDManagement: Speedup ID unique name assignment by tracking used names/basenames/suffixes
An implementation of T73412, roughly as outlined there:
Track the names that are in use, as well as base names (before
numeric suffix) plus a bit map for each base name, indicating which
numeric suffixes are already used. This is done per-Main/Library,
per-object-type.
Timings (Windows, VS2022 Release build, AMD Ryzen 5950X):
- Scene with 10k cubes, Shift+D to duplicate them all: 8.7s -> 1.9s.
Name map memory usage for resulting 20k objects: 4.3MB.
- Importing a 2.5GB .obj file of exported Blender 3.0 splash scene
(24k objects), using the new C++ importer: 34.2s-> 22.0s. Name map
memory usage for resulting scene: 8.6MB.
- Importing Disney Moana USD scene (almost half a million objects):
56min -> 10min. Name map usage: ~100MB. Blender crashes later on
when trying to render it, in the same place in both cases, but
that's for another day.
Reviewed By: Bastien Montagne
Differential Revision: https://developer.blender.org/D14162
2022-07-20 14:27:14 +03:00
|
|
|
bool BKE_id_new_name_validate(
|
2023-06-03 08:36:28 +10:00
|
|
|
Main *bmain, ListBase *lb, ID *id, const char *tname, const bool do_linked_data)
|
2007-03-21 02:23:28 +00:00
|
|
|
{
|
2021-05-19 17:45:47 +02:00
|
|
|
bool result = false;
|
2012-05-06 17:22:54 +00:00
|
|
|
char name[MAX_ID_NAME - 2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-02 17:04:21 +10:00
|
|
|
/* If library, don't rename (unless explicitly required), but do ensure proper sorting. */
|
2021-06-01 11:39:28 +02:00
|
|
|
if (!do_linked_data && ID_IS_LINKED(id)) {
|
2023-07-17 10:46:26 +02:00
|
|
|
id_sort_by_name(lb, id, nullptr);
|
2021-05-19 17:45:47 +02:00
|
|
|
|
|
|
|
|
return result;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-04-14 14:23:31 +02:00
|
|
|
/* If no name given, use name of current ID. */
|
2023-07-17 10:46:26 +02:00
|
|
|
if (tname == nullptr) {
|
2012-05-06 17:22:54 +00:00
|
|
|
tname = id->name + 2;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2023-04-14 14:23:31 +02:00
|
|
|
/* Make a copy of given name (tname args can be const). */
|
2023-05-09 12:50:37 +10:00
|
|
|
STRNCPY(name, tname);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (name[0] == '\0') {
|
2019-03-06 11:16:48 +01:00
|
|
|
/* Disallow empty names. */
|
2023-05-13 17:38:48 +10:00
|
|
|
STRNCPY_UTF8(name, DATA_(BKE_idtype_idcode_to_name(GS(id->name))));
|
2010-08-30 08:28:48 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* disallow non utf8 chars,
|
2012-03-18 07:38:51 +00:00
|
|
|
* the interface checks for this but new ID's based on file names don't */
|
2021-08-23 15:01:50 +10:00
|
|
|
BLI_str_utf8_invalid_strip(name, strlen(name));
|
2010-08-30 08:28:48 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-08 16:16:49 +02:00
|
|
|
result = BKE_main_namemap_get_name(bmain, id, name, false);
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2023-06-19 20:06:55 +10:00
|
|
|
BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
|
2023-07-17 10:46:26 +02:00
|
|
|
id_sort_by_name(lb, id, nullptr);
|
2007-03-21 02:23:28 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-27 22:44:02 +10:00
|
|
|
void BKE_main_id_newptr_and_tag_clear(Main *bmain)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
|
ID *id;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-21 04:40:16 +10:00
|
|
|
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
2021-09-16 12:16:35 +02:00
|
|
|
BKE_id_newptr_and_tag_clear(id);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2019-02-18 16:15:01 +01:00
|
|
|
FOREACH_MAIN_ID_END;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-02-13 12:56:10 +01:00
|
|
|
static int id_refcount_recompute_callback(LibraryIDLinkCallbackData *cb_data)
|
2019-05-22 21:08:51 +02:00
|
|
|
{
|
2020-02-13 12:56:10 +01:00
|
|
|
ID **id_pointer = cb_data->id_pointer;
|
|
|
|
|
const int cb_flag = cb_data->cb_flag;
|
2023-07-18 14:18:07 +10:00
|
|
|
const bool do_linked_only = bool(POINTER_AS_INT(cb_data->user_data));
|
2019-05-22 21:08:51 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (*id_pointer == nullptr) {
|
2019-05-22 23:34:07 +02:00
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
|
|
|
|
if (do_linked_only && !ID_IS_LINKED(*id_pointer)) {
|
|
|
|
|
return IDWALK_RET_NOP;
|
|
|
|
|
}
|
2019-05-22 21:08:51 +02:00
|
|
|
|
2019-05-22 23:34:07 +02:00
|
|
|
if (cb_flag & IDWALK_CB_USER) {
|
|
|
|
|
/* Do not touch to direct/indirect linked status here... */
|
|
|
|
|
id_us_plus_no_lib(*id_pointer);
|
|
|
|
|
}
|
|
|
|
|
if (cb_flag & IDWALK_CB_USER_ONE) {
|
|
|
|
|
id_us_ensure_real(*id_pointer);
|
|
|
|
|
}
|
2019-05-22 21:08:51 +02:00
|
|
|
|
2019-05-22 23:34:07 +02:00
|
|
|
return IDWALK_RET_NOP;
|
2019-05-22 21:08:51 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
void BKE_main_id_refcount_recompute(Main *bmain, const bool do_linked_only)
|
2019-05-22 21:08:51 +02:00
|
|
|
{
|
2019-05-22 23:34:07 +02:00
|
|
|
ID *id;
|
|
|
|
|
|
2019-05-22 23:50:39 +02:00
|
|
|
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
|
|
|
|
if (!ID_IS_LINKED(id) && do_linked_only) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
id->us = ID_FAKE_USERS(id);
|
|
|
|
|
/* Note that we keep EXTRAUSER tag here, since some UI users may define it too... */
|
|
|
|
|
if (id->tag & LIB_TAG_EXTRAUSER) {
|
|
|
|
|
id->tag &= ~(LIB_TAG_EXTRAUSER | LIB_TAG_EXTRAUSER_SET);
|
|
|
|
|
id_us_ensure_real(id);
|
2019-05-22 23:34:07 +02:00
|
|
|
}
|
2023-05-13 19:26:02 +02:00
|
|
|
if (ELEM(GS(id->name), ID_SCE, ID_WM, ID_WS)) {
|
|
|
|
|
/* These IDs should always have a 'virtual' user. */
|
|
|
|
|
id_us_ensure_real(id);
|
|
|
|
|
}
|
2019-05-22 23:34:07 +02:00
|
|
|
}
|
2019-05-22 23:50:39 +02:00
|
|
|
FOREACH_MAIN_ID_END;
|
2019-05-22 23:34:07 +02:00
|
|
|
|
2022-09-16 18:13:19 +10:00
|
|
|
/* Go over whole Main database to re-generate proper user-counts. */
|
2019-05-22 23:50:39 +02:00
|
|
|
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
|
|
|
|
BKE_library_foreach_ID_link(bmain,
|
|
|
|
|
id,
|
|
|
|
|
id_refcount_recompute_callback,
|
2023-07-18 14:18:07 +10:00
|
|
|
POINTER_FROM_INT(int(do_linked_only)),
|
2020-02-18 11:21:34 +01:00
|
|
|
IDWALK_READONLY | IDWALK_INCLUDE_UI);
|
2019-05-22 23:34:07 +02:00
|
|
|
}
|
2019-05-22 23:50:39 +02:00
|
|
|
FOREACH_MAIN_ID_END;
|
2019-05-22 23:34:07 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-30 21:47:48 +01:00
|
|
|
static void library_make_local_copying_check(ID *id,
|
|
|
|
|
GSet *loop_tags,
|
|
|
|
|
MainIDRelations *id_relations,
|
|
|
|
|
GSet *done_ids)
|
|
|
|
|
{
|
|
|
|
|
if (BLI_gset_haskey(done_ids, id)) {
|
|
|
|
|
return; /* Already checked, nothing else to do. */
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
|
|
|
|
|
BLI_ghash_lookup(id_relations->relations_from_pointers, id));
|
2017-01-30 21:47:48 +01:00
|
|
|
BLI_gset_insert(loop_tags, id);
|
2023-07-17 10:46:26 +02:00
|
|
|
for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr;
|
2021-01-21 14:52:40 +01:00
|
|
|
from_id_entry = from_id_entry->next)
|
|
|
|
|
{
|
2020-04-10 10:52:18 +02:00
|
|
|
/* Our oh-so-beloved 'from' pointers... Those should always be ignored here, since the actual
|
|
|
|
|
* relation we want to check is in the other way around. */
|
2021-01-21 14:52:40 +01:00
|
|
|
if (from_id_entry->usage_flag & IDWALK_CB_LOOPBACK) {
|
2020-04-10 10:52:18 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-01-21 14:52:40 +01:00
|
|
|
ID *from_id = from_id_entry->id_pointer.from;
|
|
|
|
|
|
2020-06-13 12:50:07 +10:00
|
|
|
/* Shape-keys are considered 'private' to their owner ID here, and never tagged
|
2020-04-10 10:52:18 +02:00
|
|
|
* (since they cannot be linked), so we have to switch effective parent to their owner.
|
|
|
|
|
*/
|
2021-01-21 14:52:40 +01:00
|
|
|
if (GS(from_id->name) == ID_KE) {
|
|
|
|
|
from_id = ((Key *)from_id)->from;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-26 15:01:14 +02:00
|
|
|
if (!ID_IS_LINKED(from_id)) {
|
2017-01-30 21:47:48 +01:00
|
|
|
/* Local user, early out to avoid some gset querying... */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-01-21 14:52:40 +01:00
|
|
|
if (!BLI_gset_haskey(done_ids, from_id)) {
|
|
|
|
|
if (BLI_gset_haskey(loop_tags, from_id)) {
|
2017-01-30 21:47:48 +01:00
|
|
|
/* We are in a 'dependency loop' of IDs, this does not say us anything, skip it.
|
2022-11-02 10:14:37 +11:00
|
|
|
* Note that this is the situation that can lead to archipelagos of linked data-blocks
|
2019-04-27 12:07:07 +10:00
|
|
|
* (since all of them have non-local users, they would all be duplicated,
|
|
|
|
|
* leading to a loop of unused linked data-blocks that cannot be freed since they all use
|
|
|
|
|
* each other...). */
|
2017-01-30 21:47:48 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
/* Else, recursively check that user ID. */
|
2021-01-21 14:52:40 +01:00
|
|
|
library_make_local_copying_check(from_id, loop_tags, id_relations, done_ids);
|
2017-01-30 21:47:48 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-01-21 14:52:40 +01:00
|
|
|
if (from_id->tag & LIB_TAG_DOIT) {
|
2019-04-27 12:07:07 +10:00
|
|
|
/* This user will be fully local in future, so far so good,
|
|
|
|
|
* nothing to do here but check next user. */
|
2017-01-30 21:47:48 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2019-04-27 12:07:07 +10:00
|
|
|
/* This user won't be fully local in future, so current ID won't be either.
|
|
|
|
|
* And we are done checking it. */
|
2017-01-30 21:47:48 +01:00
|
|
|
id->tag &= ~LIB_TAG_DOIT;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BLI_gset_add(done_ids, id);
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_gset_remove(loop_tags, id, nullptr);
|
2017-01-30 21:47:48 +01:00
|
|
|
}
|
|
|
|
|
|
2016-11-01 13:39:31 +01:00
|
|
|
void BKE_library_make_local(Main *bmain,
|
|
|
|
|
const Library *lib,
|
|
|
|
|
GHash *old_to_new_ids,
|
|
|
|
|
const bool untagged_only,
|
|
|
|
|
const bool set_fake)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2023-05-27 15:10:58 +10:00
|
|
|
/* NOTE: Old (2.77) version was simply making (tagging) data-blocks as local,
|
|
|
|
|
* without actually making any check whether they were also indirectly used or not...
|
|
|
|
|
*
|
|
|
|
|
* Current version uses regular id_make_local callback, with advanced pre-processing step to
|
|
|
|
|
* detect all cases of IDs currently indirectly used, but which will be used by local data only
|
|
|
|
|
* once this function is finished. This allows to avoid any unneeded duplication of IDs, and
|
|
|
|
|
* hence all time lost afterwards to remove orphaned linked data-blocks. */
|
2021-12-07 17:19:15 +11:00
|
|
|
|
2021-03-04 18:39:07 +01:00
|
|
|
ListBase *lbarray[INDEX_ID_MAX];
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
LinkNode *todo_ids = nullptr;
|
|
|
|
|
LinkNode *copied_ids = nullptr;
|
2016-11-11 22:29:54 +01:00
|
|
|
MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__);
|
2016-10-19 14:29:43 +02:00
|
|
|
|
2017-05-04 15:07:21 +02:00
|
|
|
GSet *done_ids = BLI_gset_ptr_new(__func__);
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_TIME
|
|
|
|
|
TIMEIT_START(make_local);
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-02-18 11:21:34 +01:00
|
|
|
BKE_main_relations_create(bmain, 0);
|
2017-01-30 21:47:48 +01:00
|
|
|
|
2017-05-04 15:07:21 +02:00
|
|
|
#ifdef DEBUG_TIME
|
|
|
|
|
printf("Pre-compute current ID relations: Done.\n");
|
|
|
|
|
TIMEIT_VALUE_PRINT(make_local);
|
|
|
|
|
#endif
|
2017-01-30 21:47:48 +01:00
|
|
|
|
2019-06-12 09:04:10 +10:00
|
|
|
/* Step 1: Detect data-blocks to make local. */
|
2019-04-16 01:50:35 +02:00
|
|
|
for (int a = set_listbasepointers(bmain, lbarray); a--;) {
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(lbarray[a]->first);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-10 11:32:48 +11:00
|
|
|
/* Do not explicitly make local non-linkable IDs (shape-keys, in fact),
|
2019-06-12 09:04:10 +10:00
|
|
|
* they are assumed to be handled by real data-blocks responsible of them. */
|
2020-03-19 19:37:00 +01:00
|
|
|
const bool do_skip = (id && !BKE_idtype_idcode_is_linkable(GS(id->name)));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
for (; id; id = static_cast<ID *>(id->next)) {
|
2017-01-30 21:47:48 +01:00
|
|
|
ID *ntree = (ID *)ntreeFromID(id);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-10-19 14:29:43 +02:00
|
|
|
id->tag &= ~LIB_TAG_DOIT;
|
2023-07-17 10:46:26 +02:00
|
|
|
if (ntree != nullptr) {
|
2017-01-30 21:47:48 +01:00
|
|
|
ntree->tag &= ~LIB_TAG_DOIT;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-28 19:28:59 +02:00
|
|
|
if (!ID_IS_LINKED(id)) {
|
2016-11-11 22:29:54 +01:00
|
|
|
id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
|
2019-09-16 14:52:06 +02:00
|
|
|
id->flag &= ~LIB_INDIRECT_WEAK_LINK;
|
2020-11-12 11:48:59 +01:00
|
|
|
if (ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
|
2023-07-17 10:46:26 +02:00
|
|
|
ELEM(lib, nullptr, id->override_library->reference->lib) &&
|
2020-11-12 11:48:59 +01:00
|
|
|
((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
|
|
|
|
|
{
|
2023-10-10 16:52:59 +02:00
|
|
|
/* Validating liboverride hierarchy root pointers will happen later in this function,
|
|
|
|
|
* rather than doing it for each and every localized ID. */
|
|
|
|
|
BKE_lib_override_library_make_local(nullptr, id);
|
2020-10-21 16:58:06 +02:00
|
|
|
}
|
2016-11-11 22:29:54 +01:00
|
|
|
}
|
2019-04-27 12:07:07 +10:00
|
|
|
/* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so it's possible to tag data
|
|
|
|
|
* you don't want to be made local, used for appending data,
|
2021-06-22 10:42:32 -07:00
|
|
|
* so any libdata already linked won't become local (very nasty
|
2017-01-30 21:47:48 +01:00
|
|
|
* to discover all your links are lost after appending).
|
2016-11-10 17:05:36 +01:00
|
|
|
* Also, never ever make proxified objects local, would not make any sense. */
|
2017-01-30 21:47:48 +01:00
|
|
|
/* Some more notes:
|
2022-03-10 11:32:48 +11:00
|
|
|
* - Shape-keys are never tagged here (since they are not linkable).
|
|
|
|
|
* - Node-trees used in materials etc. have to be tagged manually,
|
2019-04-27 12:07:07 +10:00
|
|
|
* since they do not exist in Main (!).
|
|
|
|
|
* This is ok-ish on 'make local' side of things
|
|
|
|
|
* (since those are handled by their 'owner' IDs),
|
2017-01-30 21:47:48 +01:00
|
|
|
* but complicates slightly the pre-processing of relations between IDs at step 2... */
|
2016-11-11 22:29:54 +01:00
|
|
|
else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
|
2023-07-17 10:46:26 +02:00
|
|
|
ELEM(lib, nullptr, id->lib) &&
|
2016-11-11 22:29:54 +01:00
|
|
|
((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
|
|
|
|
|
{
|
|
|
|
|
BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem);
|
|
|
|
|
id->tag |= LIB_TAG_DOIT;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-09 21:22:31 +10:00
|
|
|
/* Tag those nasty non-ID node-trees,
|
2019-04-27 12:07:07 +10:00
|
|
|
* but do not add them to todo list, making them local is handled by 'owner' ID.
|
|
|
|
|
* This is needed for library_make_local_copying_check() to work OK at step 2. */
|
2023-07-17 10:46:26 +02:00
|
|
|
if (ntree != nullptr) {
|
2017-01-30 21:47:48 +01:00
|
|
|
ntree->tag |= LIB_TAG_DOIT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Linked ID that we won't be making local (needed info for step 2, see below). */
|
|
|
|
|
BLI_gset_add(done_ids, id);
|
2016-11-11 22:29:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-04 14:02:05 +01:00
|
|
|
|
2017-05-04 15:07:21 +02:00
|
|
|
#ifdef DEBUG_TIME
|
2019-06-12 09:04:10 +10:00
|
|
|
printf("Step 1: Detect data-blocks to make local: Done.\n");
|
2017-05-04 15:07:21 +02:00
|
|
|
TIMEIT_VALUE_PRINT(make_local);
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-06-12 09:04:10 +10:00
|
|
|
/* Step 2: Check which data-blocks we can directly make local
|
2019-04-27 12:07:07 +10:00
|
|
|
* (because they are only used by already, or future, local data),
|
|
|
|
|
* others will need to be duplicated. */
|
2017-01-30 21:47:48 +01:00
|
|
|
GSet *loop_tags = BLI_gset_ptr_new(__func__);
|
|
|
|
|
for (LinkNode *it = todo_ids; it; it = it->next) {
|
2023-07-17 10:46:26 +02:00
|
|
|
library_make_local_copying_check(
|
|
|
|
|
static_cast<ID *>(it->link), loop_tags, bmain->relations, done_ids);
|
2018-02-15 23:36:11 +11:00
|
|
|
BLI_assert(BLI_gset_len(loop_tags) == 0);
|
2017-01-30 21:47:48 +01:00
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_gset_free(loop_tags, nullptr);
|
|
|
|
|
BLI_gset_free(done_ids, nullptr);
|
2017-01-30 21:47:48 +01:00
|
|
|
|
|
|
|
|
/* Next step will most likely add new IDs, better to get rid of this mapping now. */
|
|
|
|
|
BKE_main_relations_free(bmain);
|
2016-11-11 22:29:54 +01:00
|
|
|
|
2017-05-04 15:07:21 +02:00
|
|
|
#ifdef DEBUG_TIME
|
2019-06-12 09:04:10 +10:00
|
|
|
printf("Step 2: Check which data-blocks we can directly make local: Done.\n");
|
2017-05-04 15:07:21 +02:00
|
|
|
TIMEIT_VALUE_PRINT(make_local);
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-11-11 22:29:54 +01:00
|
|
|
/* Step 3: Make IDs local, either directly (quick and simple), or using generic process,
|
2019-04-27 12:07:07 +10:00
|
|
|
* which involves more complex checks and might instead
|
|
|
|
|
* create a local copy of original linked ID. */
|
2016-11-11 22:29:54 +01:00
|
|
|
for (LinkNode *it = todo_ids, *it_next; it; it = it_next) {
|
|
|
|
|
it_next = it->next;
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(it->link);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-11-11 22:29:54 +01:00
|
|
|
if (id->tag & LIB_TAG_DOIT) {
|
2019-05-22 23:50:39 +02:00
|
|
|
/* We know all users of this object are local or will be made fully local, even if
|
|
|
|
|
* currently there are some indirect usages. So instead of making a copy that we'll likely
|
|
|
|
|
* get rid of later, directly make that data block local.
|
2019-04-27 12:07:07 +10:00
|
|
|
* Saves a tremendous amount of time with complex scenes... */
|
2021-10-21 12:55:15 +02:00
|
|
|
BKE_lib_id_clear_library_data(bmain, id, 0);
|
|
|
|
|
BKE_lib_id_expand_local(bmain, id, 0);
|
2016-11-11 22:29:54 +01:00
|
|
|
id->tag &= ~LIB_TAG_DOIT;
|
2019-06-24 14:57:52 +02:00
|
|
|
|
|
|
|
|
if (GS(id->name) == ID_OB) {
|
|
|
|
|
BKE_rigidbody_ensure_local_object(bmain, (Object *)id);
|
|
|
|
|
}
|
2016-11-11 22:29:54 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2022-02-03 17:57:40 +01:00
|
|
|
/* In this specific case, we do want to make ID local even if it has no local usage yet... */
|
|
|
|
|
BKE_lib_id_make_local(bmain, id, LIB_ID_MAKELOCAL_FULL_LIBRARY);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-11-11 22:29:54 +01:00
|
|
|
if (id->newid) {
|
2019-06-24 14:57:52 +02:00
|
|
|
if (GS(id->newid->name) == ID_OB) {
|
|
|
|
|
BKE_rigidbody_ensure_local_object(bmain, (Object *)id->newid);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-11 22:29:54 +01:00
|
|
|
/* Reuse already allocated LinkNode (transferring it from todo_ids to copied_ids). */
|
|
|
|
|
BLI_linklist_prepend_nlink(&copied_ids, id, it);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-11-11 22:29:54 +01:00
|
|
|
if (set_fake) {
|
|
|
|
|
if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
|
|
|
|
|
/* do not set fake user on objects, groups (instancing) */
|
|
|
|
|
id_fake_user_set(id);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-04 14:02:05 +01:00
|
|
|
|
2017-05-04 15:07:21 +02:00
|
|
|
#ifdef DEBUG_TIME
|
|
|
|
|
printf("Step 3: Make IDs local: Done.\n");
|
|
|
|
|
TIMEIT_VALUE_PRINT(make_local);
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-04-27 12:07:07 +10:00
|
|
|
/* At this point, we are done with directly made local IDs.
|
|
|
|
|
* Now we have to handle duplicated ones, since their
|
2016-11-11 22:29:54 +01:00
|
|
|
* remaining linked original counterpart may not be needed anymore... */
|
2023-07-17 10:46:26 +02:00
|
|
|
todo_ids = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-27 12:07:07 +10:00
|
|
|
/* Step 4: We have to remap local usages of old (linked) ID to new (local)
|
|
|
|
|
* ID in a separated loop,
|
2016-11-11 22:29:54 +01:00
|
|
|
* as lbarray ordering is not enough to ensure us we did catch all dependencies
|
2023-02-12 14:37:16 +11:00
|
|
|
* (e.g. if making local a parent object before its child...). See #48907. */
|
2021-07-03 23:08:40 +10:00
|
|
|
/* TODO: This is now the biggest step by far (in term of processing time).
|
2019-04-27 12:07:07 +10:00
|
|
|
* We may be able to gain here by using again main->relations mapping, but...
|
|
|
|
|
* this implies BKE_libblock_remap & co to be able to update main->relations on the fly.
|
|
|
|
|
* Have to think about it a bit more, and see whether new code is OK first, anyway. */
|
2016-10-19 14:29:43 +02:00
|
|
|
for (LinkNode *it = copied_ids; it; it = it->next) {
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id = static_cast<ID *>(it->link);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
BLI_assert(id->newid != nullptr);
|
2021-08-26 15:01:14 +02:00
|
|
|
BLI_assert(ID_IS_LINKED(id));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-10-19 14:29:43 +02:00
|
|
|
BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
|
2016-11-01 13:39:31 +01:00
|
|
|
if (old_to_new_ids) {
|
|
|
|
|
BLI_ghash_insert(old_to_new_ids, id, id->newid);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-22 23:50:39 +02:00
|
|
|
/* Special hack for groups... Thing is, since we can't instantiate them here, we need to
|
|
|
|
|
* ensure they remain 'alive' (only instantiation is a real group 'user'... *sigh* See
|
2023-02-12 14:37:16 +11:00
|
|
|
* #49722. */
|
2016-11-11 23:15:55 +01:00
|
|
|
if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
|
|
|
|
|
id_us_ensure_real(id->newid);
|
|
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2006-03-05 17:35:06 +00:00
|
|
|
|
2023-10-10 16:52:59 +02:00
|
|
|
/* Making some liboverride local may have had some impact on validity of liboverrides hierarchy
|
|
|
|
|
* roots, these need to be re-validated/re-generated. */
|
|
|
|
|
BKE_lib_override_library_main_hierarchy_root_ensure(bmain);
|
|
|
|
|
|
2017-05-04 15:07:21 +02:00
|
|
|
#ifdef DEBUG_TIME
|
|
|
|
|
printf("Step 4: Remap local usages of old (linked) ID to new (local) ID: Done.\n");
|
|
|
|
|
TIMEIT_VALUE_PRINT(make_local);
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-05-05 09:49:30 +02:00
|
|
|
/* This is probably more of a hack than something we should do here, but...
|
2019-05-22 23:50:39 +02:00
|
|
|
* Issue is, the whole copying + remapping done in complex cases above may leave pose-channels
|
|
|
|
|
* of armatures in complete invalid state (more precisely, the bone pointers of the
|
2023-05-24 11:21:18 +10:00
|
|
|
* pose-channels - very crappy cross-data-blocks relationship), so we tag it to be fully
|
2019-05-22 23:50:39 +02:00
|
|
|
* recomputed, but this does not seems to be enough in some cases, and evaluation code ends up
|
|
|
|
|
* trying to evaluate a not-yet-updated armature object's deformations.
|
2017-05-05 09:49:30 +02:00
|
|
|
* Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */
|
2023-07-17 10:46:26 +02:00
|
|
|
for (Object *ob = static_cast<Object *>(bmain->objects.first); ob;
|
|
|
|
|
ob = static_cast<Object *>(ob->id.next))
|
|
|
|
|
{
|
|
|
|
|
if (ob->data != nullptr && ob->type == OB_ARMATURE && ob->pose != nullptr &&
|
2017-05-05 09:49:30 +02:00
|
|
|
ob->pose->flag & POSE_RECALC)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
BKE_pose_rebuild(bmain, ob, static_cast<bArmature *>(ob->data), true);
|
2017-05-05 09:49:30 +02:00
|
|
|
}
|
2019-04-16 01:49:03 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-05-05 09:49:30 +02:00
|
|
|
#ifdef DEBUG_TIME
|
|
|
|
|
printf("Hack: Forcefully rebuild armature object poses: Done.\n");
|
|
|
|
|
TIMEIT_VALUE_PRINT(make_local);
|
2017-01-30 21:47:48 +01:00
|
|
|
#endif
|
2016-10-19 14:29:43 +02:00
|
|
|
|
2021-05-27 22:44:02 +10:00
|
|
|
BKE_main_id_newptr_and_tag_clear(bmain);
|
2016-10-19 14:29:43 +02:00
|
|
|
BLI_memarena_free(linklist_mem);
|
2017-05-04 15:07:21 +02:00
|
|
|
|
|
|
|
|
#ifdef DEBUG_TIME
|
|
|
|
|
printf("Cleanup and finish: Done.\n");
|
|
|
|
|
TIMEIT_END(make_local);
|
|
|
|
|
#endif
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-28 17:17:25 +11:00
|
|
|
void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
|
ListBase *lb;
|
|
|
|
|
ID *idtest;
|
|
|
|
|
|
2015-12-28 17:17:25 +11:00
|
|
|
lb = which_libbase(bmain, GS(name));
|
2023-07-17 10:46:26 +02:00
|
|
|
if (lb == nullptr) {
|
2012-05-06 17:22:54 +00:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2003-04-26 11:56:44 +00:00
|
|
|
/* search for id */
|
2023-07-17 10:46:26 +02:00
|
|
|
idtest = static_cast<ID *>(BLI_findstring(lb, name + 2, offsetof(ID, name) + 2));
|
|
|
|
|
if (idtest != nullptr && !ID_IS_LINKED(idtest)) {
|
2019-03-06 11:20:23 +01:00
|
|
|
/* BKE_id_new_name_validate also takes care of sorting. */
|
2023-07-17 10:46:26 +02:00
|
|
|
BKE_id_new_name_validate(bmain, lb, idtest, nullptr, false);
|
2019-01-29 14:28:55 +11:00
|
|
|
bmain->is_memfile_undo_written = false;
|
2012-11-18 02:41:55 +00:00
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-28 17:17:25 +11:00
|
|
|
void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2021-06-01 11:49:15 +02:00
|
|
|
BLI_assert(!ID_IS_LINKED(id));
|
IDManagement: Speedup ID unique name assignment by tracking used names/basenames/suffixes
An implementation of T73412, roughly as outlined there:
Track the names that are in use, as well as base names (before
numeric suffix) plus a bit map for each base name, indicating which
numeric suffixes are already used. This is done per-Main/Library,
per-object-type.
Timings (Windows, VS2022 Release build, AMD Ryzen 5950X):
- Scene with 10k cubes, Shift+D to duplicate them all: 8.7s -> 1.9s.
Name map memory usage for resulting 20k objects: 4.3MB.
- Importing a 2.5GB .obj file of exported Blender 3.0 splash scene
(24k objects), using the new C++ importer: 34.2s-> 22.0s. Name map
memory usage for resulting scene: 8.6MB.
- Importing Disney Moana USD scene (almost half a million objects):
56min -> 10min. Name map usage: ~100MB. Blender crashes later on
when trying to render it, in the same place in both cases, but
that's for another day.
Reviewed By: Bastien Montagne
Differential Revision: https://developer.blender.org/D14162
2022-07-20 14:27:14 +03:00
|
|
|
BKE_main_namemap_remove_name(bmain, id, id->name + 2);
|
2015-12-28 17:17:25 +11:00
|
|
|
ListBase *lb = which_libbase(bmain, GS(id->name));
|
IDManagement: Speedup ID unique name assignment by tracking used names/basenames/suffixes
An implementation of T73412, roughly as outlined there:
Track the names that are in use, as well as base names (before
numeric suffix) plus a bit map for each base name, indicating which
numeric suffixes are already used. This is done per-Main/Library,
per-object-type.
Timings (Windows, VS2022 Release build, AMD Ryzen 5950X):
- Scene with 10k cubes, Shift+D to duplicate them all: 8.7s -> 1.9s.
Name map memory usage for resulting 20k objects: 4.3MB.
- Importing a 2.5GB .obj file of exported Blender 3.0 splash scene
(24k objects), using the new C++ importer: 34.2s-> 22.0s. Name map
memory usage for resulting scene: 8.6MB.
- Importing Disney Moana USD scene (almost half a million objects):
56min -> 10min. Name map usage: ~100MB. Blender crashes later on
when trying to render it, in the same place in both cases, but
that's for another day.
Reviewed By: Bastien Montagne
Differential Revision: https://developer.blender.org/D14162
2022-07-20 14:27:14 +03:00
|
|
|
if (BKE_id_new_name_validate(bmain, lb, id, name, false)) {
|
2019-01-29 14:28:55 +11:00
|
|
|
bmain->is_memfile_undo_written = false;
|
|
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2010-07-31 01:06:08 +00:00
|
|
|
|
2020-06-10 15:08:23 +02:00
|
|
|
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separator_char)
|
2018-10-31 12:18:36 +01:00
|
|
|
{
|
2023-06-19 20:06:55 +10:00
|
|
|
BLI_strncpy(name, id->name + 2, MAX_ID_FULL_NAME);
|
2018-10-31 12:18:36 +01:00
|
|
|
|
2021-08-26 15:01:14 +02:00
|
|
|
if (ID_IS_LINKED(id)) {
|
2018-10-31 12:18:36 +01:00
|
|
|
const size_t idname_len = strlen(id->name + 2);
|
|
|
|
|
const size_t libname_len = strlen(id->lib->id.name + 2);
|
|
|
|
|
|
2020-06-10 15:08:23 +02:00
|
|
|
name[idname_len] = separator_char ? separator_char : ' ';
|
2018-10-31 12:18:36 +01:00
|
|
|
name[idname_len + 1] = '[';
|
2023-06-19 20:06:55 +10:00
|
|
|
BLI_strncpy(name + idname_len + 2, id->lib->id.name + 2, MAX_ID_FULL_NAME - (idname_len + 2));
|
2018-10-31 12:18:36 +01:00
|
|
|
name[idname_len + 2 + libname_len] = ']';
|
|
|
|
|
name[idname_len + 2 + libname_len + 1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-10 15:08:23 +02:00
|
|
|
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
|
|
|
|
|
const ID *id,
|
2020-06-29 17:19:43 +02:00
|
|
|
const bool add_lib_hint,
|
2020-07-23 17:24:17 +10:00
|
|
|
char separator_char,
|
|
|
|
|
int *r_prefix_len)
|
2010-07-31 01:06:08 +00:00
|
|
|
{
|
2020-06-29 17:19:43 +02:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
if (add_lib_hint) {
|
|
|
|
|
name[i++] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_OVERRIDE_LIBRARY(id) ? 'O' : ' ';
|
|
|
|
|
}
|
|
|
|
|
name[i++] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
|
|
|
|
|
name[i++] = ' ';
|
2010-07-31 01:06:08 +00:00
|
|
|
|
2020-06-29 17:19:43 +02:00
|
|
|
BKE_id_full_name_get(name + i, id, separator_char);
|
2020-07-23 17:24:17 +10:00
|
|
|
|
|
|
|
|
if (r_prefix_len) {
|
|
|
|
|
*r_prefix_len = i;
|
|
|
|
|
}
|
2010-07-31 01:06:08 +00:00
|
|
|
}
|
2011-10-23 17:52:20 +00:00
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
char *BKE_id_to_unique_string_key(const ID *id)
|
2018-08-23 08:37:32 +02:00
|
|
|
{
|
2021-08-26 15:01:14 +02:00
|
|
|
if (!ID_IS_LINKED(id)) {
|
2018-12-20 09:31:56 +11:00
|
|
|
return BLI_strdup(id->name);
|
|
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
|
/* Prefix with an ascii character in the range of 32..96 (visible)
|
|
|
|
|
* this ensures we can't have a library ID pair that collide.
|
|
|
|
|
* Where 'LIfooOBbarOBbaz' could be ('LIfoo, OBbarOBbaz') or ('LIfooOBbar', 'OBbaz'). */
|
|
|
|
|
const char ascii_len = strlen(id->lib->id.name + 2) + 32;
|
|
|
|
|
return BLI_sprintfN("%c%s%s", ascii_len, id->lib->id.name, id->name);
|
2018-08-23 08:37:32 +02:00
|
|
|
}
|
|
|
|
|
|
2016-11-08 17:54:14 +01:00
|
|
|
void BKE_id_tag_set_atomic(ID *id, int tag)
|
|
|
|
|
{
|
2017-11-23 16:14:53 +01:00
|
|
|
atomic_fetch_and_or_int32(&id->tag, tag);
|
2016-11-08 17:54:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_id_tag_clear_atomic(ID *id, int tag)
|
|
|
|
|
{
|
2017-11-23 16:14:53 +01:00
|
|
|
atomic_fetch_and_and_int32(&id->tag, ~tag);
|
2016-11-08 17:54:14 +01:00
|
|
|
}
|
2018-06-22 11:37:08 +02:00
|
|
|
|
2018-11-09 10:44:02 -02:00
|
|
|
bool BKE_id_is_in_global_main(ID *id)
|
2018-06-25 12:02:57 +02:00
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
/* We do not want to fail when id is nullptr here, even though this is a bit strange behavior...
|
2019-05-22 23:50:39 +02:00
|
|
|
*/
|
2023-07-17 10:46:26 +02:00
|
|
|
return (id == nullptr || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1);
|
2018-06-22 11:37:08 +02:00
|
|
|
}
|
2018-08-23 16:13:52 +02:00
|
|
|
|
2020-12-11 23:16:29 +01:00
|
|
|
bool BKE_id_can_be_asset(const ID *id)
|
|
|
|
|
{
|
|
|
|
|
return !ID_IS_LINKED(id) && !ID_IS_OVERRIDE_LIBRARY(id) &&
|
|
|
|
|
BKE_idtype_idcode_is_linkable(GS(id->name));
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-08 13:06:40 +02:00
|
|
|
ID *BKE_id_owner_get(ID *id)
|
|
|
|
|
{
|
|
|
|
|
const IDTypeInfo *idtype = BKE_idtype_get_info_from_id(id);
|
2023-07-17 10:46:26 +02:00
|
|
|
if (idtype->owner_pointer_get != nullptr) {
|
2022-09-08 16:32:35 +02:00
|
|
|
ID **owner_id_pointer = idtype->owner_pointer_get(id);
|
2023-07-17 10:46:26 +02:00
|
|
|
if (owner_id_pointer != nullptr) {
|
2022-09-08 16:32:35 +02:00
|
|
|
return *owner_id_pointer;
|
|
|
|
|
}
|
2022-09-08 13:06:40 +02:00
|
|
|
}
|
2023-07-17 10:46:26 +02:00
|
|
|
return nullptr;
|
2022-09-08 13:06:40 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-31 17:31:32 +02:00
|
|
|
bool BKE_id_is_editable(const Main *bmain, const ID *id)
|
2022-03-28 17:34:36 +02:00
|
|
|
{
|
|
|
|
|
return !(ID_IS_LINKED(id) || BKE_lib_override_library_is_system_defined(bmain, id));
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-23 16:13:52 +02:00
|
|
|
/************************* Datablock order in UI **************************/
|
|
|
|
|
|
|
|
|
|
static int *id_order_get(ID *id)
|
|
|
|
|
{
|
|
|
|
|
/* Only for workspace tabs currently. */
|
|
|
|
|
switch (GS(id->name)) {
|
|
|
|
|
case ID_WS:
|
|
|
|
|
return &((WorkSpace *)id)->order;
|
|
|
|
|
default:
|
2023-07-17 10:46:26 +02:00
|
|
|
return nullptr;
|
2018-08-23 16:13:52 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int id_order_compare(const void *a, const void *b)
|
|
|
|
|
{
|
2023-07-17 10:46:26 +02:00
|
|
|
ID *id_a = static_cast<ID *>(((LinkData *)a)->data);
|
|
|
|
|
ID *id_b = static_cast<ID *>(((LinkData *)b)->data);
|
2018-08-23 16:13:52 +02:00
|
|
|
|
|
|
|
|
int *order_a = id_order_get(id_a);
|
|
|
|
|
int *order_b = id_order_get(id_b);
|
|
|
|
|
|
|
|
|
|
if (order_a && order_b) {
|
|
|
|
|
if (*order_a < *order_b) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
if (*order_a > *order_b) {
|
2018-08-23 16:13:52 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strcmp(id_a->name, id_b->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
|
|
|
|
|
{
|
|
|
|
|
BLI_listbase_clear(ordered_lb);
|
|
|
|
|
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (ID *, id, lb) {
|
2018-08-23 16:13:52 +02:00
|
|
|
BLI_addtail(ordered_lb, BLI_genericNodeN(id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_listbase_sort(ordered_lb, id_order_compare);
|
|
|
|
|
|
|
|
|
|
int num = 0;
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (LinkData *, link, ordered_lb) {
|
2023-07-17 10:46:26 +02:00
|
|
|
int *order = id_order_get(static_cast<ID *>(link->data));
|
2018-08-23 16:13:52 +02:00
|
|
|
if (order) {
|
|
|
|
|
*order = num++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
|
|
|
|
|
{
|
|
|
|
|
int *id_order = id_order_get(id);
|
|
|
|
|
int relative_order;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-23 16:13:52 +02:00
|
|
|
if (relative) {
|
|
|
|
|
relative_order = *id_order_get(relative);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
relative_order = (after) ? BLI_listbase_count(lb) : 0;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-23 16:13:52 +02:00
|
|
|
if (after) {
|
|
|
|
|
/* Insert after. */
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (ID *, other, lb) {
|
2018-08-23 16:13:52 +02:00
|
|
|
int *order = id_order_get(other);
|
|
|
|
|
if (*order > relative_order) {
|
|
|
|
|
(*order)++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-23 16:13:52 +02:00
|
|
|
*id_order = relative_order + 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Insert before. */
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (ID *, other, lb) {
|
2018-08-23 16:13:52 +02:00
|
|
|
int *order = id_order_get(other);
|
|
|
|
|
if (*order < relative_order) {
|
|
|
|
|
(*order)--;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-23 16:13:52 +02:00
|
|
|
*id_order = relative_order - 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-28 15:45:11 +02:00
|
|
|
|
|
|
|
|
void BKE_id_blend_write(BlendWriter *writer, ID *id)
|
|
|
|
|
{
|
2020-12-11 18:15:25 +01:00
|
|
|
if (id->asset_data) {
|
|
|
|
|
BKE_asset_metadata_write(writer, id->asset_data);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-17 10:46:26 +02:00
|
|
|
if (id->library_weak_reference != nullptr) {
|
2021-09-17 16:22:29 +02:00
|
|
|
BLO_write_struct(writer, LibraryWeakReference, id->library_weak_reference);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-28 15:45:11 +02:00
|
|
|
/* ID_WM's id->properties are considered runtime only, and never written in .blend file. */
|
|
|
|
|
if (id->properties && !ELEM(GS(id->name), ID_WM)) {
|
|
|
|
|
IDP_BlendWrite(writer, id->properties);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-14 16:26:11 +02:00
|
|
|
BKE_animdata_blend_write(writer, id);
|
|
|
|
|
|
2020-08-28 15:45:11 +02:00
|
|
|
if (id->override_library) {
|
|
|
|
|
BLO_write_struct(writer, IDOverrideLibrary, id->override_library);
|
|
|
|
|
|
|
|
|
|
BLO_write_struct_list(writer, IDOverrideLibraryProperty, &id->override_library->properties);
|
|
|
|
|
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
|
|
|
|
|
BLO_write_string(writer, op->rna_path);
|
|
|
|
|
|
|
|
|
|
BLO_write_struct_list(writer, IDOverrideLibraryPropertyOperation, &op->operations);
|
|
|
|
|
LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
|
|
|
|
|
if (opop->subitem_reference_name) {
|
|
|
|
|
BLO_write_string(writer, opop->subitem_reference_name);
|
|
|
|
|
}
|
|
|
|
|
if (opop->subitem_local_name) {
|
|
|
|
|
BLO_write_string(writer, opop->subitem_local_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|