Welcome to mirror list, hosted at ThFree Co, Russian Federation.

BKE_lib_remap.h « blenkernel « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: a17ef8c7c5da9c3de90ee1838776e04f40984b9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once

/** \file
 * \ingroup bke
 *
 * API to perform remapping from one data-block pointer to another.
 *
 * \note `BKE_lib_` files are for operations over data-blocks themselves, although they might
 * alter Main as well (when creating/renaming/deleting an ID e.g.).
 *
 * \section Function Names
 *
 * \warning Descriptions below is ideal goal, current status of naming does not yet fully follow it
 * (this is WIP).
 *
 * - `BKE_lib_remap_libblock_` should be used for functions performing remapping.
 * - `BKE_lib_remap_callback_` should be used for functions managing remapping callbacks.
 */

#include "BLI_compiler_attrs.h"

#ifdef __cplusplus
extern "C" {
#endif

struct ID;
struct IDRemapper;
struct LinkNode;

/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */

/* Also IDRemap->flag. */
enum {
  /** Do not remap indirect usages of IDs (that is, when user is some linked data). */
  ID_REMAP_SKIP_INDIRECT_USAGE = 1 << 0,
  /**
   * This flag should always be set, *except for 'unlink' scenarios*
   * (only relevant when new_id == NULL).
   * Basically, when unset, NEVER_NULL ID usages will keep pointing to old_id, but (if needed)
   * old_id user count will still be decremented.
   * This is mandatory for 'delete ID' case,
   * but in all other situation this would lead to invalid user counts!
   */
  ID_REMAP_SKIP_NEVER_NULL_USAGE = 1 << 1,
  /**
   * This tells the callback func to flag with #LIB_DOIT all IDs
   * using target one with a 'never NULL' pointer (like e.g. #Object.data).
   */
  ID_REMAP_FLAG_NEVER_NULL_USAGE = 1 << 2,
  /**
   * This tells the callback func to force setting IDs
   * using target one with a 'never NULL' pointer to NULL.
   * \warning Use with extreme care, this will leave database in broken state
   * and can cause crashes very easily!
   */
  ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3,
  /** Do not remap library override pointers. */
  ID_REMAP_SKIP_OVERRIDE_LIBRARY = 1 << 5,
  /** Don't touch the special user counts (use when the 'old' remapped ID remains in use):
   * - Do not transfer 'fake user' status from old to new ID.
   * - Do not clear 'extra user' from old ID. */
  ID_REMAP_SKIP_USER_CLEAR = 1 << 6,
  /**
   * Force internal ID runtime pointers (like `ID.newid`, `ID.orig_id` etc.) to also be processed.
   * This should only be needed in some very specific cases, typically only BKE ID management code
   * should need it (e.g. required from `id_delete` to ensure no runtime pointer remains using
   * freed ones).
   */
  ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS = 1 << 7,
  /** Force handling user count even for IDs that are outside of Main (used in some cases when
   * dealing with IDs temporarily out of Main, but which will be put in it ultimately).
   */
  ID_REMAP_FORCE_USER_REFCOUNT = 1 << 8,
  /**
   * Force obdata pointers to also be processed, even when object (`id_owner`) is in Edit mode.
   * This is required by some tools creating/deleting IDs while operating in Edit mode, like e.g.
   * the 'separate' mesh operator.
   */
  ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 9,
};

typedef enum eIDRemapType {
  /** Remap an ID reference to a new reference. The new reference can also be null. */
  ID_REMAP_TYPE_REMAP = 0,

  /** Cleanup all IDs used by a specific one. */
  ID_REMAP_TYPE_CLEANUP = 1,
} eIDRemapType;

/**
 * Replace all references in given Main using the given \a mappings
 *
 * \note Is preferred over BKE_libblock_remap_locked due to performance.
 */
void BKE_libblock_remap_multiple_locked(struct Main *bmain,
                                        struct IDRemapper *mappings,
                                        short remap_flags);

void BKE_libblock_remap_multiple(struct Main *bmain,
                                 struct IDRemapper *mappings,
                                 short remap_flags);

/**
 * Replace all references in given Main to \a old_id by \a new_id
 * (if \a new_id is NULL, it unlinks \a old_id).
 *
 * \note Requiring new_id to be non-null, this *may* not be the case ultimately,
 * but makes things simpler for now.
 */
void BKE_libblock_remap_locked(struct Main *bmain, void *old_idv, void *new_idv, short remap_flags)
    ATTR_NONNULL(1, 2);
void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, short remap_flags)
    ATTR_NONNULL(1, 2);

/**
 * Unlink given \a id from given \a bmain
 * (does not touch to indirect, i.e. library, usages of the ID).
 *
 * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by
 * #LIB_TAG_DOIT flag (quite obviously, 'non-NULL' usages can never be unlinked by this function).
 */
void BKE_libblock_unlink(struct Main *bmain,
                         void *idv,
                         bool do_flag_never_null,
                         bool do_skip_indirect) ATTR_NONNULL();

/**
 * Similar to libblock_remap, but only affects IDs used by given \a idv ID.
 *
 * \param old_idv: Unlike BKE_libblock_remap, can be NULL,
 * in which case all ID usages by given \a idv will be cleared.
 */
void BKE_libblock_relink_ex(struct Main *bmain,
                            void *idv,
                            void *old_idv,
                            void *new_idv,
                            short remap_flags) ATTR_NONNULL(1, 2);
/**
 * Same as #BKE_libblock_relink_ex, but applies all rules defined in \a id_remapper to \a ids (or
 * does cleanup if `ID_REMAP_TYPE_CLEANUP` is specified as \a remap_type).
 */
void BKE_libblock_relink_multiple(struct Main *bmain,
                                  struct LinkNode *ids,
                                  eIDRemapType remap_type,
                                  struct IDRemapper *id_remapper,
                                  short remap_flags);

/**
 * Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
 * in the dependency tree of IDs for all data-blocks tagged with `LIB_TAG_NEW`.
 *
 * \note `LIB_TAG_NEW` is cleared.
 *
 * Very specific usage, not sure we'll keep it on the long run,
 * currently only used in Object/Collection duplication code.
 */
void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, int remap_flag)
    ATTR_NONNULL();

typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
typedef void (*BKE_library_remap_editor_id_reference_cb)(const struct IDRemapper *mappings);

void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
void BKE_library_callback_remap_editor_id_reference_set(
    BKE_library_remap_editor_id_reference_cb func);

/* IDRemapper */
struct IDRemapper;
typedef enum IDRemapperApplyResult {
  /** No remapping rules available for the source. */
  ID_REMAP_RESULT_SOURCE_UNAVAILABLE,
  /** Source isn't mappable (e.g. NULL). */
  ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE,
  /** Source has been remapped to a new pointer. */
  ID_REMAP_RESULT_SOURCE_REMAPPED,
  /** Source has been set to NULL. */
  ID_REMAP_RESULT_SOURCE_UNASSIGNED,
} IDRemapperApplyResult;

typedef enum IDRemapperApplyOptions {
  /**
   * Update the user count of the old and new ID data-block.
   *
   * For remapping the old ID users will be decremented and the new ID users will be
   * incremented. When un-assigning the old ID users will be decremented.
   *
   * NOTE: Currently unused by main remapping code, since user-count is handled by
   * `foreach_libblock_remap_callback_apply` there, depending on whether the remapped pointer does
   * use it or not. Need for rare cases in UI handling though (see e.g. `image_id_remap` in
   * `space_image.c`).
   */
  ID_REMAP_APPLY_UPDATE_REFCOUNT = (1 << 0),

  /**
   * Make sure that the new ID data-block will have a 'real' user.
   *
   * NOTE: See Note for #ID_REMAP_APPLY_UPDATE_REFCOUNT above.
   */
  ID_REMAP_APPLY_ENSURE_REAL = (1 << 1),

  /**
   * Unassign in stead of remap when the new ID data-block would become id_self.
   *
   * To use this option 'BKE_id_remapper_apply_ex' must be used with a not-null id_self parameter.
   */
  ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF = (1 << 2),

  ID_REMAP_APPLY_DEFAULT = 0,
} IDRemapperApplyOptions;

typedef void (*IDRemapperIterFunction)(struct ID *old_id, struct ID *new_id, void *user_data);

/**
 * Create a new ID Remapper.
 *
 * An ID remapper stores multiple remapping rules.
 */
struct IDRemapper *BKE_id_remapper_create(void);

void BKE_id_remapper_clear(struct IDRemapper *id_remapper);
bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper);
/** Free the given ID Remapper. */
void BKE_id_remapper_free(struct IDRemapper *id_remapper);
/** Add a new remapping. */
void BKE_id_remapper_add(struct IDRemapper *id_remapper, struct ID *old_id, struct ID *new_id);

/**
 * Apply a remapping.
 *
 * Update the id pointer stored in the given r_id_ptr if a remapping rule exists.
 */
IDRemapperApplyResult BKE_id_remapper_apply(const struct IDRemapper *id_remapper,
                                            struct ID **r_id_ptr,
                                            IDRemapperApplyOptions options);
/**
 * Apply a remapping.
 *
 * Use this function when `ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF`. In this case
 * the #id_self parameter is required. Otherwise the #BKE_id_remapper_apply can be used.
 *
 * \param id_self: required for ID_REMAP_APPLY_UNMAP_WHEN_REMAPPING_TO_SELF.
 *     When remapping to id_self it will then be remapped to NULL.
 */
IDRemapperApplyResult BKE_id_remapper_apply_ex(const struct IDRemapper *id_remapper,
                                               struct ID **r_id_ptr,
                                               IDRemapperApplyOptions options,
                                               struct ID *id_self);
bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter);

/**
 * Determine the mapping result, without applying the mapping.
 */
IDRemapperApplyResult BKE_id_remapper_get_mapping_result(const struct IDRemapper *id_remapper,
                                                         struct ID *id,
                                                         IDRemapperApplyOptions options,
                                                         const struct ID *id_self);
void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
                          IDRemapperIterFunction func,
                          void *user_data);

/** Returns a readable string for the given result. Can be used for debugging purposes. */
const char *BKE_id_remapper_result_string(const IDRemapperApplyResult result);
/** Prints out the rules inside the given id_remapper. Can be used for debugging purposes. */
void BKE_id_remapper_print(const struct IDRemapper *id_remapper);

#ifdef __cplusplus
}
#endif