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
This commit is contained in:
		@@ -16,10 +16,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/** \file
 | 
					/** \file
 | 
				
			||||||
 * \ingroup bke
 | 
					 * \ingroup bke
 | 
				
			||||||
 * \attention Based on ghash, difference is ghash is not a fixed size,
 | 
					 *
 | 
				
			||||||
 *   so for BPath we don't need to malloc
 | 
					 * \warning All paths manipulated by this API are assumed to be either constant char buffers of
 | 
				
			||||||
 | 
					 * `FILE_MAX` size, or allocated char buffers not bigger than `FILE_MAX`.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TODO: Make this module handle a bit more safely string length, instead of assuming buffers are
 | 
				
			||||||
 | 
					 * FILE_MAX len etc. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
@@ -31,66 +35,175 @@ struct ListBase;
 | 
				
			|||||||
struct Main;
 | 
					struct Main;
 | 
				
			||||||
struct ReportList;
 | 
					struct ReportList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Function that does something with an ID's file path. Should return 1 if the
 | 
					/** \name Core `foreach_path` API.
 | 
				
			||||||
 * path has changed, and in that case, should write the result to pathOut. */
 | 
					 * \{ */
 | 
				
			||||||
typedef bool (*BPathVisitor)(void *userdata, char *path_dst, const char *path_src);
 | 
					 | 
				
			||||||
/* Executes 'visit' for each path associated with 'id'. */
 | 
					 | 
				
			||||||
void BKE_bpath_traverse_id(struct Main *bmain,
 | 
					 | 
				
			||||||
                           struct ID *id,
 | 
					 | 
				
			||||||
                           BPathVisitor visit_cb,
 | 
					 | 
				
			||||||
                           const int flag,
 | 
					 | 
				
			||||||
                           void *bpath_user_data);
 | 
					 | 
				
			||||||
void BKE_bpath_traverse_id_list(struct Main *bmain,
 | 
					 | 
				
			||||||
                                struct ListBase *lb,
 | 
					 | 
				
			||||||
                                BPathVisitor visit_cb,
 | 
					 | 
				
			||||||
                                const int flag,
 | 
					 | 
				
			||||||
                                void *bpath_user_data);
 | 
					 | 
				
			||||||
void BKE_bpath_traverse_main(struct Main *bmain,
 | 
					 | 
				
			||||||
                             BPathVisitor visit_cb,
 | 
					 | 
				
			||||||
                             const int flag,
 | 
					 | 
				
			||||||
                             void *bpath_user_data);
 | 
					 | 
				
			||||||
bool BKE_bpath_relocate_visitor(void *oldbasepath, char *path_dst, const char *path_src);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Functions for temp backup/restore of paths, path count must NOT change */
 | 
					typedef enum eBPathForeachFlag {
 | 
				
			||||||
void *BKE_bpath_list_backup(struct Main *bmain, const int flag);
 | 
					  /** Flags controlling the behavior of the generic BPath API. */
 | 
				
			||||||
void BKE_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle);
 | 
					 | 
				
			||||||
void BKE_bpath_list_free(void *ls_handle);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					  /** Ensures the `absolute_base_path` member of #BPathForeachPathData is initialized properly with
 | 
				
			||||||
  /* convert paths to absolute */
 | 
					   * the path of the current .blend file. This can be used by the callbacks to convert relative
 | 
				
			||||||
  BKE_BPATH_TRAVERSE_ABS = (1 << 0),
 | 
					   * paths to absolute ones. */
 | 
				
			||||||
  /* skip library paths */
 | 
					  BKE_BPATH_FOREACH_PATH_ABSOLUTE = (1 << 0),
 | 
				
			||||||
  BKE_BPATH_TRAVERSE_SKIP_LIBRARY = (1 << 1),
 | 
					  /** Skip paths of linked IDs. */
 | 
				
			||||||
  /* skip packed data */
 | 
					  BKE_BPATH_FOREACH_PATH_SKIP_LINKED = (1 << 1),
 | 
				
			||||||
  BKE_BPATH_TRAVERSE_SKIP_PACKED = (1 << 2),
 | 
					  /** Skip paths when their matching data is packed. */
 | 
				
			||||||
  /* skip paths where a single dir is used with an array of files, eg.
 | 
					  BKE_BPATH_FOREACH_PATH_SKIP_PACKED = (1 << 2),
 | 
				
			||||||
   * sequence strip images and pointcache. in this case only use the first
 | 
					 | 
				
			||||||
   * file, this is needed for directory manipulation functions which might
 | 
					 | 
				
			||||||
   * otherwise modify the same directory multiple times */
 | 
					 | 
				
			||||||
  BKE_BPATH_TRAVERSE_SKIP_MULTIFILE = (1 << 3),
 | 
					 | 
				
			||||||
  /* reload data (when the path is edited) */
 | 
					 | 
				
			||||||
  BKE_BPATH_TRAVERSE_RELOAD_EDITED = (1 << 4),
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* high level funcs */
 | 
					  /** Flags not affecting the generic BPath API. Those may be used by specific IDTypeInfo
 | 
				
			||||||
 | 
					   * `foreach_path` implementations and/or callbacks to implement specific behaviors. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* creates a text file with missing files if there are any */
 | 
					  /** Skip paths where a single dir is used with an array of files, eg. sequence strip images or
 | 
				
			||||||
 | 
					   * pointcaches. In this case only use the first file path is processed.
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * This is needed for directory manipulation callbacks which might otherwise modify the same
 | 
				
			||||||
 | 
					   * directory multiple times. */
 | 
				
			||||||
 | 
					  BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE = (1 << 8),
 | 
				
			||||||
 | 
					  /** Reload data (when the path is edited).
 | 
				
			||||||
 | 
					   *  \note Ony used by Image IDType currently. */
 | 
				
			||||||
 | 
					  BKE_BPATH_FOREACH_PATH_RELOAD_EDITED = (1 << 9),
 | 
				
			||||||
 | 
					} eBPathForeachFlag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BPathForeachPathData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Callback used to iterate over an ID's file paths.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \note `path`s parameters should be considered as having a maximal `FILE_MAX` string length.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \return `true` if the path has been changed, and in that case, result should be written into
 | 
				
			||||||
 | 
					 * `r_path_dst`. */
 | 
				
			||||||
 | 
					typedef bool (*BPathForeachPathFunctionCallback)(struct BPathForeachPathData *bpath_data,
 | 
				
			||||||
 | 
					                                                 char *r_path_dst,
 | 
				
			||||||
 | 
					                                                 const char *path_src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Storage for common data needed accross the BPath 'foreach_path' code. */
 | 
				
			||||||
 | 
					typedef struct BPathForeachPathData {
 | 
				
			||||||
 | 
					  struct Main *bmain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BPathForeachPathFunctionCallback callback_function;
 | 
				
			||||||
 | 
					  eBPathForeachFlag flag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void *user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* 'Private' data, caller don't need to set those. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** The root to use as base for relative paths. Only set if `BKE_BPATH_FOREACH_PATH_ABSOLUTE`
 | 
				
			||||||
 | 
					   * flag is set, NULL otherwise. */
 | 
				
			||||||
 | 
					  const char *absolute_base_path;
 | 
				
			||||||
 | 
					} BPathForeachPathData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Run `bpath_data.callback_function` on all paths contained in `id`. */
 | 
				
			||||||
 | 
					void BKE_bpath_foreach_path_id(BPathForeachPathData *bpath_data, struct ID *id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Run `bpath_data.callback_function` on all paths of all IDs in `bmain`. */
 | 
				
			||||||
 | 
					void BKE_bpath_foreach_path_main(BPathForeachPathData *bpath_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** \} */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** \name Helpers to handle common cases from `IDTypeInfo`'s `foreach_path` functions.
 | 
				
			||||||
 | 
					 * \{ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* TODO: Investigate using macros around those calls to check a bit better about actual
 | 
				
			||||||
 | 
					 * strings/buffers length (e,g, with static asserts). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Run the callback on a path, replacing the content of the string as needed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param path: A fixed, FILE_MAX-sized char buffer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \return true is \a path was modified, false otherwise.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool BKE_bpath_foreach_path_fixed_process(struct BPathForeachPathData *bpath_data, char *path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Run the callback on a (directory + file) path, replacing the content of the two strings as
 | 
				
			||||||
 | 
					 * needed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param path_dir: A fixed, FILE_MAXDIR-sized char buffer.
 | 
				
			||||||
 | 
					 * \param path_file: A fixed, FILE_MAXFILE-sized char buffer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \return true is \a path_dir and/or \a path_file were modified, false otherwise.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool BKE_bpath_foreach_path_dirfile_fixed_process(struct BPathForeachPathData *bpath_data,
 | 
				
			||||||
 | 
					                                                  char *path_dir,
 | 
				
			||||||
 | 
					                                                  char *path_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Run the callback on a path, replacing the content of the string as needed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param path: A pointer to a MEM-allocated string. If modified, it will be freed and replaced by
 | 
				
			||||||
 | 
					 * a new allocated string.
 | 
				
			||||||
 | 
					 * \note path is expected to be FILE_MAX size or smaller.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \return true is \a path was modified and re-allocated, false otherwise.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool BKE_bpath_foreach_path_allocated_process(struct BPathForeachPathData *bpath_data,
 | 
				
			||||||
 | 
					                                              char **path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** \} */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** \name High level features.
 | 
				
			||||||
 | 
					 * \{ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Check for missing files. */
 | 
				
			||||||
void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *reports);
 | 
					void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *reports);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Recursively search into given search directory, for all file paths of all IDs in given \a
 | 
				
			||||||
 | 
					 * bmain, and replace existing paths as needed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \note The search will happen into the whole search directory tree recursively (with a limit of
 | 
				
			||||||
 | 
					 * MAX_DIR_RECURSE), if several files are found matching a searched filename, the biggest one will
 | 
				
			||||||
 | 
					 * be used. This is so that things like thumbnails don't get selected instead of the actual image
 | 
				
			||||||
 | 
					 * e.g.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param searchpath: The root directory in which the new filepaths should be searched for.
 | 
				
			||||||
 | 
					 * \param find_all: If `true`, also search for files which current path is still valid, if `false`
 | 
				
			||||||
 | 
					 *                  skip those still valid paths.
 | 
				
			||||||
 | 
					 * */
 | 
				
			||||||
void BKE_bpath_missing_files_find(struct Main *bmain,
 | 
					void BKE_bpath_missing_files_find(struct Main *bmain,
 | 
				
			||||||
                                  const char *searchpath,
 | 
					                                  const char *searchpath,
 | 
				
			||||||
                                  struct ReportList *reports,
 | 
					                                  struct ReportList *reports,
 | 
				
			||||||
                                  const bool find_all);
 | 
					                                  const bool find_all);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Rebase all relative file paths in given \a bmain from \a basedir_src to \a basedir_dst. */
 | 
				
			||||||
void BKE_bpath_relative_rebase(struct Main *bmain,
 | 
					void BKE_bpath_relative_rebase(struct Main *bmain,
 | 
				
			||||||
                               const char *basedir_src,
 | 
					                               const char *basedir_src,
 | 
				
			||||||
                               const char *basedir_dst,
 | 
					                               const char *basedir_dst,
 | 
				
			||||||
                               struct ReportList *reports);
 | 
					                               struct ReportList *reports);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Make all absolute file paths in given \a bmain relative to given \a basedir. */
 | 
				
			||||||
void BKE_bpath_relative_convert(struct Main *bmain,
 | 
					void BKE_bpath_relative_convert(struct Main *bmain,
 | 
				
			||||||
                                const char *basedir,
 | 
					                                const char *basedir,
 | 
				
			||||||
                                struct ReportList *reports);
 | 
					                                struct ReportList *reports);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Make all relative file paths in given \a bmain absolute, using given \a basedir as root. */
 | 
				
			||||||
void BKE_bpath_absolute_convert(struct Main *bmain,
 | 
					void BKE_bpath_absolute_convert(struct Main *bmain,
 | 
				
			||||||
                                const char *basedir,
 | 
					                                const char *basedir,
 | 
				
			||||||
                                struct ReportList *reports);
 | 
					                                struct ReportList *reports);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Temp backup of paths from all IDs in given \a bmain.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  \return An opaque handle to pass to #BKE_bpath_list_restore and #BKE_bpath_list_free.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void *BKE_bpath_list_backup(struct Main *bmain, const eBPathForeachFlag flag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Restore the temp backup of paths from \a path_list_handle into all IDs in given \a bmain.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \note This function assumes that the data in given Main did not change (no
 | 
				
			||||||
 | 
					 * addition/deletion/re-ordering of IDs, or their file paths) since the call to
 | 
				
			||||||
 | 
					 * #BKE_bpath_list_backup that generated the given \a path_list_handle. */
 | 
				
			||||||
 | 
					void BKE_bpath_list_restore(struct Main *bmain,
 | 
				
			||||||
 | 
					                            const eBPathForeachFlag flag,
 | 
				
			||||||
 | 
					                            void *path_list_handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Free the temp backup of paths in \a path_list_handle.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \note This function assumes that the path list has already been restored with a call to
 | 
				
			||||||
 | 
					 * #BKE_bpath_list_restore, and is therefore empty. */
 | 
				
			||||||
 | 
					void BKE_bpath_list_free(void *path_list_handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** \} */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,6 +35,7 @@ struct BlendDataReader;
 | 
				
			|||||||
struct BlendExpander;
 | 
					struct BlendExpander;
 | 
				
			||||||
struct BlendLibReader;
 | 
					struct BlendLibReader;
 | 
				
			||||||
struct BlendWriter;
 | 
					struct BlendWriter;
 | 
				
			||||||
 | 
					struct BPathForeachPathData;
 | 
				
			||||||
struct ID;
 | 
					struct ID;
 | 
				
			||||||
struct LibraryForeachIDData;
 | 
					struct LibraryForeachIDData;
 | 
				
			||||||
struct Main;
 | 
					struct Main;
 | 
				
			||||||
@@ -100,6 +101,8 @@ typedef void (*IDTypeForeachCacheFunction)(struct ID *id,
 | 
				
			|||||||
                                           IDTypeForeachCacheFunctionCallback function_callback,
 | 
					                                           IDTypeForeachCacheFunctionCallback function_callback,
 | 
				
			||||||
                                           void *user_data);
 | 
					                                           void *user_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void (*IDTypeForeachPathFunction)(struct ID *id, struct BPathForeachPathData *bpath_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct ID *(*IDTypeEmbeddedOwnerGetFunction)(struct Main *bmain, struct ID *id);
 | 
					typedef struct ID *(*IDTypeEmbeddedOwnerGetFunction)(struct Main *bmain, struct ID *id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (*IDTypeBlendWriteFunction)(struct BlendWriter *writer,
 | 
					typedef void (*IDTypeBlendWriteFunction)(struct BlendWriter *writer,
 | 
				
			||||||
@@ -189,6 +192,11 @@ typedef struct IDTypeInfo {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  IDTypeForeachCacheFunction foreach_cache;
 | 
					  IDTypeForeachCacheFunction foreach_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Iterator over all file paths of given ID.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  IDTypeForeachPathFunction foreach_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * For embedded IDs, return their owner ID.
 | 
					   * For embedded IDs, return their owner ID.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -328,6 +328,7 @@ IDTypeInfo IDType_ID_AC = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = action_foreach_id,
 | 
					    .foreach_id = action_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = action_blend_write,
 | 
					    .blend_write = action_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -330,6 +330,7 @@ IDTypeInfo IDType_ID_AR = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = armature_foreach_id,
 | 
					    .foreach_id = armature_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = armature_blend_write,
 | 
					    .blend_write = armature_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,9 @@
 | 
				
			|||||||
/** \name High Level `.blend` file read/write.
 | 
					/** \name High Level `.blend` file read/write.
 | 
				
			||||||
 * \{ */
 | 
					 * \{ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
 | 
					static bool foreach_path_clean_cb(BPathForeachPathData *UNUSED(bpath_data),
 | 
				
			||||||
 | 
					                                  char *path_dst,
 | 
				
			||||||
 | 
					                                  const char *path_src)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  strcpy(path_dst, path_src);
 | 
					  strcpy(path_dst, path_src);
 | 
				
			||||||
  BLI_path_slash_native(path_dst);
 | 
					  BLI_path_slash_native(path_dst);
 | 
				
			||||||
@@ -86,13 +88,14 @@ static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const c
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* make sure path names are correct for OS */
 | 
					/* make sure path names are correct for OS */
 | 
				
			||||||
static void clean_paths(Main *main)
 | 
					static void clean_paths(Main *bmain)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  Scene *scene;
 | 
					  BKE_bpath_foreach_path_main(&(BPathForeachPathData){.bmain = bmain,
 | 
				
			||||||
 | 
					                                              .callback_function = foreach_path_clean_cb,
 | 
				
			||||||
 | 
					                                              .flag = BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE,
 | 
				
			||||||
 | 
					                                              .user_data = NULL});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
 | 
					  LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (scene = main->scenes.first; scene; scene = scene->id.next) {
 | 
					 | 
				
			||||||
    BLI_path_slash_native(scene->r.pic);
 | 
					    BLI_path_slash_native(scene->r.pic);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -887,7 +890,8 @@ bool BKE_blendfile_write_partial(Main *bmain_src,
 | 
				
			|||||||
  int a, retval;
 | 
					  int a, retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void *path_list_backup = NULL;
 | 
					  void *path_list_backup = NULL;
 | 
				
			||||||
  const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
 | 
					  const eBPathForeachFlag path_list_flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED |
 | 
				
			||||||
 | 
					                                            BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* This is needed to be able to load that file as a real one later
 | 
					  /* This is needed to be able to load that file as a real one later
 | 
				
			||||||
   * (otherwise main->name will not be set at read time). */
 | 
					   * (otherwise main->name will not be set at read time). */
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -160,7 +160,7 @@ TEST_F(BPathTest, list_backup_restore)
 | 
				
			|||||||
  MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
 | 
					  MovieClip *movie_clip = reinterpret_cast<MovieClip *>(bmain->movieclips.first);
 | 
				
			||||||
  BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
 | 
					  BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE, sizeof(movie_clip->filepath));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void *path_list_handle = BKE_bpath_list_backup(bmain, 0);
 | 
					  void *path_list_handle = BKE_bpath_list_backup(bmain, static_cast<eBPathForeachFlag>(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ListBase *path_list = reinterpret_cast<ListBase *>(path_list_handle);
 | 
					  ListBase *path_list = reinterpret_cast<ListBase *>(path_list_handle);
 | 
				
			||||||
  EXPECT_EQ(BLI_listbase_count(path_list), 2);
 | 
					  EXPECT_EQ(BLI_listbase_count(path_list), 2);
 | 
				
			||||||
@@ -169,7 +169,7 @@ TEST_F(BPathTest, list_backup_restore)
 | 
				
			|||||||
  text->filepath = BLI_strdup(TEXT_PATH_ABSOLUTE);
 | 
					  text->filepath = BLI_strdup(TEXT_PATH_ABSOLUTE);
 | 
				
			||||||
  BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_RELATIVE, sizeof(movie_clip->filepath));
 | 
					  BLI_strncpy(movie_clip->filepath, MOVIECLIP_PATH_RELATIVE, sizeof(movie_clip->filepath));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BKE_bpath_list_restore(bmain, 0, path_list_handle);
 | 
					  BKE_bpath_list_restore(bmain, static_cast<eBPathForeachFlag>(0), path_list_handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE);
 | 
					  EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE);
 | 
				
			||||||
  EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
 | 
					  EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "BLT_translation.h"
 | 
					#include "BLT_translation.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_brush.h"
 | 
					#include "BKE_brush.h"
 | 
				
			||||||
#include "BKE_colortools.h"
 | 
					#include "BKE_colortools.h"
 | 
				
			||||||
#include "BKE_context.h"
 | 
					#include "BKE_context.h"
 | 
				
			||||||
@@ -218,6 +219,14 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data)
 | 
				
			|||||||
                                          BKE_texture_mtex_foreach_id(data, &brush->mask_mtex));
 | 
					                                          BKE_texture_mtex_foreach_id(data, &brush->mask_mtex));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void brush_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  Brush *brush = (Brush *)id;
 | 
				
			||||||
 | 
					  if (brush->icon_filepath[0] != '\0') {
 | 
				
			||||||
 | 
					    BKE_bpath_foreach_path_fixed_process(bpath_data, brush->icon_filepath);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
					static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  Brush *brush = (Brush *)id;
 | 
					  Brush *brush = (Brush *)id;
 | 
				
			||||||
@@ -422,6 +431,7 @@ IDTypeInfo IDType_ID_BR = {
 | 
				
			|||||||
    .make_local = brush_make_local,
 | 
					    .make_local = brush_make_local,
 | 
				
			||||||
    .foreach_id = brush_foreach_id,
 | 
					    .foreach_id = brush_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = brush_foreach_path,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = brush_blend_write,
 | 
					    .blend_write = brush_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,7 @@
 | 
				
			|||||||
#include "BLT_translation.h"
 | 
					#include "BLT_translation.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "BKE_anim_data.h"
 | 
					#include "BKE_anim_data.h"
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_cachefile.h"
 | 
					#include "BKE_cachefile.h"
 | 
				
			||||||
#include "BKE_idtype.h"
 | 
					#include "BKE_idtype.h"
 | 
				
			||||||
#include "BKE_lib_id.h"
 | 
					#include "BKE_lib_id.h"
 | 
				
			||||||
@@ -94,6 +95,12 @@ static void cache_file_free_data(ID *id)
 | 
				
			|||||||
  BLI_freelistN(&cache_file->object_paths);
 | 
					  BLI_freelistN(&cache_file->object_paths);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  CacheFile *cache_file = (CacheFile *)id;
 | 
				
			||||||
 | 
					  BKE_bpath_foreach_path_fixed_process(bpath_data, cache_file->filepath);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
					static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  CacheFile *cache_file = (CacheFile *)id;
 | 
					  CacheFile *cache_file = (CacheFile *)id;
 | 
				
			||||||
@@ -142,6 +149,7 @@ IDTypeInfo IDType_ID_CF = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = NULL,
 | 
					    .foreach_id = NULL,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = cache_file_foreach_path,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = cache_file_blend_write,
 | 
					    .blend_write = cache_file_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -190,6 +190,7 @@ IDTypeInfo IDType_ID_CA = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = camera_foreach_id,
 | 
					    .foreach_id = camera_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = camera_blend_write,
 | 
					    .blend_write = camera_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -383,6 +383,7 @@ IDTypeInfo IDType_ID_GR = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = collection_foreach_id,
 | 
					    .foreach_id = collection_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = collection_owner_get,
 | 
					    .owner_get = collection_owner_get,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = collection_blend_write,
 | 
					    .blend_write = collection_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -320,6 +320,7 @@ IDTypeInfo IDType_ID_CU = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = curve_foreach_id,
 | 
					    .foreach_id = curve_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = curve_blend_write,
 | 
					    .blend_write = curve_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -328,6 +328,7 @@ IDTypeInfo IDType_ID_GD = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = greasepencil_foreach_id,
 | 
					    .foreach_id = greasepencil_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = greasepencil_blend_write,
 | 
					    .blend_write = greasepencil_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -190,6 +190,7 @@ IDTypeInfo IDType_ID_HA = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = hair_foreach_id,
 | 
					    .foreach_id = hair_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = hair_blend_write,
 | 
					    .blend_write = hair_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,6 +75,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "BLT_translation.h"
 | 
					#include "BLT_translation.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_colortools.h"
 | 
					#include "BKE_colortools.h"
 | 
				
			||||||
#include "BKE_global.h"
 | 
					#include "BKE_global.h"
 | 
				
			||||||
#include "BKE_icons.h"
 | 
					#include "BKE_icons.h"
 | 
				
			||||||
@@ -252,6 +253,34 @@ static void image_foreach_cache(ID *id,
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  Image *ima = (Image *)id;
 | 
				
			||||||
 | 
					  const eBPathForeachFlag flag = bpath_data->flag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (BKE_image_has_packedfile(ima) && (flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /* Skip empty file paths, these are typically from generated images and
 | 
				
			||||||
 | 
					   * don't make sense to add directories to until the image has been saved
 | 
				
			||||||
 | 
					   * once to give it a meaningful value. */
 | 
				
			||||||
 | 
					  /* TODO re-assess whether this behavior is disired in the new generic code context. */
 | 
				
			||||||
 | 
					  if (!ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED) ||
 | 
				
			||||||
 | 
					      ima->filepath[0] == '\0') {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath)) {
 | 
				
			||||||
 | 
					    if (flag & BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) {
 | 
				
			||||||
 | 
					      if (!BKE_image_has_packedfile(ima) &&
 | 
				
			||||||
 | 
					          /* Image may have been painted onto (and not saved, T44543). */
 | 
				
			||||||
 | 
					          !BKE_image_is_dirty(ima)) {
 | 
				
			||||||
 | 
					        BKE_image_signal(bpath_data->bmain, ima, NULL, IMA_SIGNAL_RELOAD);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
					static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  Image *ima = (Image *)id;
 | 
					  Image *ima = (Image *)id;
 | 
				
			||||||
@@ -377,6 +406,7 @@ IDTypeInfo IDType_ID_IM = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = NULL,
 | 
					    .foreach_id = NULL,
 | 
				
			||||||
    .foreach_cache = image_foreach_cache,
 | 
					    .foreach_cache = image_foreach_cache,
 | 
				
			||||||
 | 
					    .foreach_path = image_foreach_path,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = image_blend_write,
 | 
					    .blend_write = image_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -193,6 +193,7 @@ IDTypeInfo IDType_ID_IP = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = NULL,
 | 
					    .foreach_id = NULL,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = NULL,
 | 
					    .blend_write = NULL,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -221,6 +221,7 @@ IDTypeInfo IDType_ID_KE = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = shapekey_foreach_id,
 | 
					    .foreach_id = shapekey_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    /* A bit weird, due to shapekeys not being strictly speaking embedded data... But they also
 | 
					    /* A bit weird, due to shapekeys not being strictly speaking embedded data... But they also
 | 
				
			||||||
     * share a lot with those (non linkable, only ever used by one owner ID, etc.). */
 | 
					     * share a lot with those (non linkable, only ever used by one owner ID, etc.). */
 | 
				
			||||||
    .owner_get = shapekey_owner_get,
 | 
					    .owner_get = shapekey_owner_get,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -205,6 +205,7 @@ IDTypeInfo IDType_ID_LT = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = lattice_foreach_id,
 | 
					    .foreach_id = lattice_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = lattice_blend_write,
 | 
					    .blend_write = lattice_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,6 +107,8 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = NULL,
 | 
					    .foreach_id = NULL,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = NULL,
 | 
					    .blend_write = NULL,
 | 
				
			||||||
    .blend_read_data = NULL,
 | 
					    .blend_read_data = NULL,
 | 
				
			||||||
@@ -124,19 +126,57 @@ IDTypeInfo IDType_ID_LINK_PLACEHOLDER = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* ************* general ************************ */
 | 
					/* ************* general ************************ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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,
 | 
				
			||||||
 | 
					                                                char *r_path_dst,
 | 
				
			||||||
 | 
					                                                const char *path_src)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  const char **data = bpath_data->user_data;
 | 
				
			||||||
 | 
					  /* 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 "//../" */
 | 
				
			||||||
 | 
					    BLI_path_normalize(base_new, filepath);
 | 
				
			||||||
 | 
					    BLI_path_rel(filepath, base_new);
 | 
				
			||||||
 | 
					    BLI_strncpy(r_path_dst, filepath, FILE_MAX);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Path was not relative to begin with. */
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This has to be called from each make_local_* func, we could call from BKE_lib_id_make_local()
 | 
					 * 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.
 | 
					 * but then the make local functions would not be self contained.
 | 
				
			||||||
 * Also note that the id _must_ have a library - campbell */
 | 
					 * Also note that the id _must_ have a library - campbell */
 | 
				
			||||||
 | 
					/* TODO: This can probably be replaced by an ID-level version of #BKE_bpath_relative_rebase. */
 | 
				
			||||||
static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
 | 
					static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs};
 | 
					  const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BKE_bpath_traverse_id(bmain,
 | 
					  BKE_bpath_foreach_path_id(
 | 
				
			||||||
                        id,
 | 
					      &(BPathForeachPathData){.bmain = bmain,
 | 
				
			||||||
                        BKE_bpath_relocate_visitor,
 | 
					                              .callback_function = lib_id_library_local_paths_callback,
 | 
				
			||||||
                        BKE_BPATH_TRAVERSE_SKIP_MULTIFILE,
 | 
					                              .flag = BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE,
 | 
				
			||||||
                        (void *)bpath_user_data);
 | 
					                              .user_data = (void *)bpath_user_data},
 | 
				
			||||||
 | 
					      id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *cb_data)
 | 
					static int lib_id_clear_library_data_users_update_cb(LibraryIDLinkCallbackData *cb_data)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "BLT_translation.h"
 | 
					#include "BLT_translation.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_idtype.h"
 | 
					#include "BKE_idtype.h"
 | 
				
			||||||
#include "BKE_lib_id.h"
 | 
					#include "BKE_lib_id.h"
 | 
				
			||||||
#include "BKE_lib_query.h"
 | 
					#include "BKE_lib_query.h"
 | 
				
			||||||
@@ -60,6 +61,22 @@ static void library_foreach_id(ID *id, LibraryForeachIDData *data)
 | 
				
			|||||||
  BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lib->parent, IDWALK_CB_NEVER_SELF);
 | 
					  BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, lib->parent, IDWALK_CB_NEVER_SELF);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  Library *lib = (Library *)id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* FIXME: Find if we should respect #BKE_BPATH_FOREACH_PATH_SKIP_PACKED here, and if not, explain
 | 
				
			||||||
 | 
					   * why. */
 | 
				
			||||||
 | 
					  if (lib->packedfile !=
 | 
				
			||||||
 | 
					      NULL /*&& (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0 */) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (BKE_bpath_foreach_path_fixed_process(bpath_data, lib->filepath)) {
 | 
				
			||||||
 | 
					    BKE_library_filepath_set(bpath_data->bmain, lib, lib->filepath);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
IDTypeInfo IDType_ID_LI = {
 | 
					IDTypeInfo IDType_ID_LI = {
 | 
				
			||||||
    .id_code = ID_LI,
 | 
					    .id_code = ID_LI,
 | 
				
			||||||
    .id_filter = 0,
 | 
					    .id_filter = 0,
 | 
				
			||||||
@@ -77,6 +94,7 @@ IDTypeInfo IDType_ID_LI = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = library_foreach_id,
 | 
					    .foreach_id = library_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = library_foreach_path,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = NULL,
 | 
					    .blend_write = NULL,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -203,6 +203,7 @@ IDTypeInfo IDType_ID_LA = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = light_foreach_id,
 | 
					    .foreach_id = light_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = light_blend_write,
 | 
					    .blend_write = light_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,6 +100,7 @@ IDTypeInfo IDType_ID_LP = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = lightprobe_foreach_id,
 | 
					    .foreach_id = lightprobe_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = lightprobe_blend_write,
 | 
					    .blend_write = lightprobe_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -762,6 +762,7 @@ IDTypeInfo IDType_ID_LS = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = linestyle_foreach_id,
 | 
					    .foreach_id = linestyle_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = linestyle_blend_write,
 | 
					    .blend_write = linestyle_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -263,6 +263,7 @@ IDTypeInfo IDType_ID_MSK = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = mask_foreach_id,
 | 
					    .foreach_id = mask_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = mask_blend_write,
 | 
					    .blend_write = mask_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -269,6 +269,7 @@ IDTypeInfo IDType_ID_MA = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = material_foreach_id,
 | 
					    .foreach_id = material_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = material_blend_write,
 | 
					    .blend_write = material_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -197,6 +197,7 @@ IDTypeInfo IDType_ID_MB = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = metaball_foreach_id,
 | 
					    .foreach_id = metaball_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = metaball_blend_write,
 | 
					    .blend_write = metaball_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,6 +48,7 @@
 | 
				
			|||||||
#include "BLT_translation.h"
 | 
					#include "BLT_translation.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "BKE_anim_data.h"
 | 
					#include "BKE_anim_data.h"
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_deform.h"
 | 
					#include "BKE_deform.h"
 | 
				
			||||||
#include "BKE_editmesh.h"
 | 
					#include "BKE_editmesh.h"
 | 
				
			||||||
#include "BKE_global.h"
 | 
					#include "BKE_global.h"
 | 
				
			||||||
@@ -183,6 +184,14 @@ static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  Mesh *me = (Mesh *)id;
 | 
				
			||||||
 | 
					  if (me->ldata.external) {
 | 
				
			||||||
 | 
					    BKE_bpath_foreach_path_fixed_process(bpath_data, me->ldata.external->filename);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
					static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  Mesh *mesh = (Mesh *)id;
 | 
					  Mesh *mesh = (Mesh *)id;
 | 
				
			||||||
@@ -371,6 +380,7 @@ IDTypeInfo IDType_ID_ME = {
 | 
				
			|||||||
    /* make_local */ nullptr,
 | 
					    /* make_local */ nullptr,
 | 
				
			||||||
    /* foreach_id */ mesh_foreach_id,
 | 
					    /* foreach_id */ mesh_foreach_id,
 | 
				
			||||||
    /* foreach_cache */ nullptr,
 | 
					    /* foreach_cache */ nullptr,
 | 
				
			||||||
 | 
					    /* foreach_path */ mesh_foreach_path,
 | 
				
			||||||
    /* owner_get */ nullptr,
 | 
					    /* owner_get */ nullptr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* blend_write */ mesh_blend_write,
 | 
					    /* blend_write */ mesh_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,7 @@
 | 
				
			|||||||
#include "BLT_translation.h"
 | 
					#include "BLT_translation.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "BKE_anim_data.h"
 | 
					#include "BKE_anim_data.h"
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_colortools.h"
 | 
					#include "BKE_colortools.h"
 | 
				
			||||||
#include "BKE_global.h"
 | 
					#include "BKE_global.h"
 | 
				
			||||||
#include "BKE_idtype.h"
 | 
					#include "BKE_idtype.h"
 | 
				
			||||||
@@ -165,6 +166,12 @@ static void movie_clip_foreach_cache(ID *id,
 | 
				
			|||||||
  function_callback(id, &key, (void **)&movie_clip->tracking.camera.intrinsics, 0, user_data);
 | 
					  function_callback(id, &key, (void **)&movie_clip->tracking.camera.intrinsics, 0, user_data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void movie_clip_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  MovieClip *movie_clip = (MovieClip *)id;
 | 
				
			||||||
 | 
					  BKE_bpath_foreach_path_fixed_process(bpath_data, movie_clip->filepath);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_movieTracks(BlendWriter *writer, ListBase *tracks)
 | 
					static void write_movieTracks(BlendWriter *writer, ListBase *tracks)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  MovieTrackingTrack *track;
 | 
					  MovieTrackingTrack *track;
 | 
				
			||||||
@@ -355,6 +362,7 @@ IDTypeInfo IDType_ID_MC = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = movie_clip_foreach_id,
 | 
					    .foreach_id = movie_clip_foreach_id,
 | 
				
			||||||
    .foreach_cache = movie_clip_foreach_cache,
 | 
					    .foreach_cache = movie_clip_foreach_cache,
 | 
				
			||||||
 | 
					    .foreach_path = movie_clip_foreach_path,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = movieclip_blend_write,
 | 
					    .blend_write = movieclip_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,6 +63,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "BKE_anim_data.h"
 | 
					#include "BKE_anim_data.h"
 | 
				
			||||||
#include "BKE_animsys.h"
 | 
					#include "BKE_animsys.h"
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_colortools.h"
 | 
					#include "BKE_colortools.h"
 | 
				
			||||||
#include "BKE_cryptomatte.h"
 | 
					#include "BKE_cryptomatte.h"
 | 
				
			||||||
#include "BKE_global.h"
 | 
					#include "BKE_global.h"
 | 
				
			||||||
@@ -416,6 +417,29 @@ static void node_foreach_cache(ID *id,
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  bNodeTree *ntree = reinterpret_cast<bNodeTree *>(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  switch (ntree->type) {
 | 
				
			||||||
 | 
					    case NTREE_SHADER: {
 | 
				
			||||||
 | 
					      LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
 | 
				
			||||||
 | 
					        if (node->type == SH_NODE_SCRIPT) {
 | 
				
			||||||
 | 
					          NodeShaderScript *nss = reinterpret_cast<NodeShaderScript *>(node->storage);
 | 
				
			||||||
 | 
					          BKE_bpath_foreach_path_fixed_process(bpath_data, nss->filepath);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (node->type == SH_NODE_TEX_IES) {
 | 
				
			||||||
 | 
					          NodeShaderTexIES *ies = reinterpret_cast<NodeShaderTexIES *>(node->storage);
 | 
				
			||||||
 | 
					          BKE_bpath_foreach_path_fixed_process(bpath_data, ies->filepath);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ID *node_owner_get(Main *bmain, ID *id)
 | 
					static ID *node_owner_get(Main *bmain, ID *id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if ((id->flag & LIB_EMBEDDED_DATA) == 0) {
 | 
					  if ((id->flag & LIB_EMBEDDED_DATA) == 0) {
 | 
				
			||||||
@@ -1055,6 +1079,7 @@ IDTypeInfo IDType_ID_NT = {
 | 
				
			|||||||
    /* make_local */ nullptr,
 | 
					    /* make_local */ nullptr,
 | 
				
			||||||
    /* foreach_id */ node_foreach_id,
 | 
					    /* foreach_id */ node_foreach_id,
 | 
				
			||||||
    /* foreach_cache */ node_foreach_cache,
 | 
					    /* foreach_cache */ node_foreach_cache,
 | 
				
			||||||
 | 
					    /* foreach_path */ node_foreach_path,
 | 
				
			||||||
    /* owner_get */ node_owner_get,
 | 
					    /* owner_get */ node_owner_get,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* blend_write */ ntree_blend_write,
 | 
					    /* blend_write */ ntree_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -83,6 +83,7 @@
 | 
				
			|||||||
#include "BKE_animsys.h"
 | 
					#include "BKE_animsys.h"
 | 
				
			||||||
#include "BKE_armature.h"
 | 
					#include "BKE_armature.h"
 | 
				
			||||||
#include "BKE_asset.h"
 | 
					#include "BKE_asset.h"
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_camera.h"
 | 
					#include "BKE_camera.h"
 | 
				
			||||||
#include "BKE_collection.h"
 | 
					#include "BKE_collection.h"
 | 
				
			||||||
#include "BKE_constraint.h"
 | 
					#include "BKE_constraint.h"
 | 
				
			||||||
@@ -548,6 +549,66 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void object_foreach_path_pointcache(ListBase *ptcache_list, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  for (PointCache *cache = (PointCache *)ptcache_list->first; cache != nullptr;
 | 
				
			||||||
 | 
					       cache = cache->next) {
 | 
				
			||||||
 | 
					    if (cache->flag & PTCACHE_DISK_CACHE) {
 | 
				
			||||||
 | 
					      BKE_bpath_foreach_path_fixed_process(bpath_data, cache->path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void object_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  Object *ob = reinterpret_cast<Object *>(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
 | 
				
			||||||
 | 
					    /* TODO: Move that to #ModifierTypeInfo. */
 | 
				
			||||||
 | 
					    switch (md->type) {
 | 
				
			||||||
 | 
					      case eModifierType_Fluidsim: {
 | 
				
			||||||
 | 
					        FluidsimModifierData *fluidmd = reinterpret_cast<FluidsimModifierData *>(md);
 | 
				
			||||||
 | 
					        if (fluidmd->fss) {
 | 
				
			||||||
 | 
					          BKE_bpath_foreach_path_fixed_process(bpath_data, fluidmd->fss->surfdataPath);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      case eModifierType_Fluid: {
 | 
				
			||||||
 | 
					        FluidModifierData *fmd = reinterpret_cast<FluidModifierData *>(md);
 | 
				
			||||||
 | 
					        if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
 | 
				
			||||||
 | 
					          BKE_bpath_foreach_path_fixed_process(bpath_data, fmd->domain->cache_directory);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      case eModifierType_Cloth: {
 | 
				
			||||||
 | 
					        ClothModifierData *clmd = reinterpret_cast<ClothModifierData *>(md);
 | 
				
			||||||
 | 
					        object_foreach_path_pointcache(&clmd->ptcaches, bpath_data);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      case eModifierType_Ocean: {
 | 
				
			||||||
 | 
					        OceanModifierData *omd = reinterpret_cast<OceanModifierData *>(md);
 | 
				
			||||||
 | 
					        BKE_bpath_foreach_path_fixed_process(bpath_data, omd->cachepath);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      case eModifierType_MeshCache: {
 | 
				
			||||||
 | 
					        MeshCacheModifierData *mcmd = reinterpret_cast<MeshCacheModifierData *>(md);
 | 
				
			||||||
 | 
					        BKE_bpath_foreach_path_fixed_process(bpath_data, mcmd->filepath);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (ob->soft != nullptr) {
 | 
				
			||||||
 | 
					    object_foreach_path_pointcache(&ob->soft->shared->ptcaches, bpath_data);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
 | 
				
			||||||
 | 
					    object_foreach_path_pointcache(&psys->ptcaches, bpath_data);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void write_fmaps(BlendWriter *writer, ListBase *fbase)
 | 
					static void write_fmaps(BlendWriter *writer, ListBase *fbase)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
 | 
					  LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
 | 
				
			||||||
@@ -1266,6 +1327,7 @@ IDTypeInfo IDType_ID_OB = {
 | 
				
			|||||||
    /* make_local */ object_make_local,
 | 
					    /* make_local */ object_make_local,
 | 
				
			||||||
    /* foreach_id */ object_foreach_id,
 | 
					    /* foreach_id */ object_foreach_id,
 | 
				
			||||||
    /* foreach_cache */ nullptr,
 | 
					    /* foreach_cache */ nullptr,
 | 
				
			||||||
 | 
					    /* foreach_path */ object_foreach_path,
 | 
				
			||||||
    /* owner_get */ nullptr,
 | 
					    /* owner_get */ nullptr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* blend_write */ object_blend_write,
 | 
					    /* blend_write */ object_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -151,6 +151,7 @@ IDTypeInfo IDType_ID_PAL = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = NULL,
 | 
					    .foreach_id = NULL,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = palette_blend_write,
 | 
					    .blend_write = palette_blend_write,
 | 
				
			||||||
@@ -217,6 +218,7 @@ IDTypeInfo IDType_ID_PC = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = NULL,
 | 
					    .foreach_id = NULL,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = paint_curve_blend_write,
 | 
					    .blend_write = paint_curve_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -508,6 +508,7 @@ IDTypeInfo IDType_ID_PA = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = particle_settings_foreach_id,
 | 
					    .foreach_id = particle_settings_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = particle_settings_blend_write,
 | 
					    .blend_write = particle_settings_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -183,6 +183,7 @@ IDTypeInfo IDType_ID_PT = {
 | 
				
			|||||||
    /* make_local */ nullptr,
 | 
					    /* make_local */ nullptr,
 | 
				
			||||||
    /* foreach_id */ pointcloud_foreach_id,
 | 
					    /* foreach_id */ pointcloud_foreach_id,
 | 
				
			||||||
    /* foreach_cache */ nullptr,
 | 
					    /* foreach_cache */ nullptr,
 | 
				
			||||||
 | 
					    /* foreach_path */ nullptr,
 | 
				
			||||||
    /* owner_get */ nullptr,
 | 
					    /* owner_get */ nullptr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* blend_write */ pointcloud_blend_write,
 | 
					    /* blend_write */ pointcloud_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,6 +71,7 @@
 | 
				
			|||||||
#include "BKE_anim_data.h"
 | 
					#include "BKE_anim_data.h"
 | 
				
			||||||
#include "BKE_animsys.h"
 | 
					#include "BKE_animsys.h"
 | 
				
			||||||
#include "BKE_armature.h"
 | 
					#include "BKE_armature.h"
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_cachefile.h"
 | 
					#include "BKE_cachefile.h"
 | 
				
			||||||
#include "BKE_collection.h"
 | 
					#include "BKE_collection.h"
 | 
				
			||||||
#include "BKE_colortools.h"
 | 
					#include "BKE_colortools.h"
 | 
				
			||||||
@@ -891,6 +892,45 @@ static void scene_foreach_cache(ID *id,
 | 
				
			|||||||
                    user_data);
 | 
					                    user_data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool seq_foreach_path_callback(Sequence *seq, void *user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (SEQ_HAS_PATH(seq)) {
 | 
				
			||||||
 | 
					    StripElem *se = seq->strip->stripdata;
 | 
				
			||||||
 | 
					    BPathForeachPathData *bpath_data = (BPathForeachPathData *)user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM) && se) {
 | 
				
			||||||
 | 
					      BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if ((seq->type == SEQ_TYPE_IMAGE) && se) {
 | 
				
			||||||
 | 
					      /* NOTE: An option not to loop over all strips could be usefull? */
 | 
				
			||||||
 | 
					      unsigned int len = (unsigned int)MEM_allocN_len(se) / (unsigned int)sizeof(*se);
 | 
				
			||||||
 | 
					      unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE) {
 | 
				
			||||||
 | 
					        /* only operate on one path */
 | 
				
			||||||
 | 
					        len = MIN2(1u, len);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (i = 0; i < len; i++, se++) {
 | 
				
			||||||
 | 
					        BKE_bpath_foreach_path_dirfile_fixed_process(bpath_data, seq->strip->dir, se->name);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      /* simple case */
 | 
				
			||||||
 | 
					      BKE_bpath_foreach_path_fixed_process(bpath_data, seq->strip->dir);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void scene_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  Scene *scene = (Scene *)id;
 | 
				
			||||||
 | 
					  if (scene->ed != NULL) {
 | 
				
			||||||
 | 
					    SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_path_callback, bpath_data);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
					static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  Scene *sce = (Scene *)id;
 | 
					  Scene *sce = (Scene *)id;
 | 
				
			||||||
@@ -1610,6 +1650,7 @@ IDTypeInfo IDType_ID_SCE = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = scene_foreach_id,
 | 
					    .foreach_id = scene_foreach_id,
 | 
				
			||||||
    .foreach_cache = scene_foreach_cache,
 | 
					    .foreach_cache = scene_foreach_cache,
 | 
				
			||||||
 | 
					    .foreach_path = scene_foreach_path,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = scene_blend_write,
 | 
					    .blend_write = scene_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -312,6 +312,7 @@ IDTypeInfo IDType_ID_SCR = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = screen_foreach_id,
 | 
					    .foreach_id = screen_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = screen_blend_write,
 | 
					    .blend_write = screen_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -162,6 +162,7 @@ IDTypeInfo IDType_ID_SIM = {
 | 
				
			|||||||
    /* make_local */ nullptr,
 | 
					    /* make_local */ nullptr,
 | 
				
			||||||
    /* foreach_id */ simulation_foreach_id,
 | 
					    /* foreach_id */ simulation_foreach_id,
 | 
				
			||||||
    /* foreach_cache */ nullptr,
 | 
					    /* foreach_cache */ nullptr,
 | 
				
			||||||
 | 
					    /* foreach_path */ nullptr,
 | 
				
			||||||
    /* owner_get */ nullptr,
 | 
					    /* owner_get */ nullptr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* blend_write */ simulation_blend_write,
 | 
					    /* blend_write */ simulation_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,6 +54,7 @@
 | 
				
			|||||||
#  include <AUD_Special.h>
 | 
					#  include <AUD_Special.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_global.h"
 | 
					#include "BKE_global.h"
 | 
				
			||||||
#include "BKE_idtype.h"
 | 
					#include "BKE_idtype.h"
 | 
				
			||||||
#include "BKE_lib_id.h"
 | 
					#include "BKE_lib_id.h"
 | 
				
			||||||
@@ -133,6 +134,17 @@ static void sound_foreach_cache(ID *id,
 | 
				
			|||||||
  function_callback(id, &key, &sound->waveform, 0, user_data);
 | 
					  function_callback(id, &key, &sound->waveform, 0, user_data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sound_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  bSound *sound = (bSound *)id;
 | 
				
			||||||
 | 
					  if (sound->packedfile != NULL && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* FIXME: This does not check for empty path... */
 | 
				
			||||||
 | 
					  BKE_bpath_foreach_path_fixed_process(bpath_data, sound->filepath);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
					static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  bSound *sound = (bSound *)id;
 | 
					  bSound *sound = (bSound *)id;
 | 
				
			||||||
@@ -214,6 +226,7 @@ IDTypeInfo IDType_ID_SO = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = NULL,
 | 
					    .foreach_id = NULL,
 | 
				
			||||||
    .foreach_cache = sound_foreach_cache,
 | 
					    .foreach_cache = sound_foreach_cache,
 | 
				
			||||||
 | 
					    .foreach_path = sound_foreach_path,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = sound_blend_write,
 | 
					    .blend_write = sound_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,6 +107,7 @@ IDTypeInfo IDType_ID_SPK = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = speaker_foreach_id,
 | 
					    .foreach_id = speaker_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = speaker_blend_write,
 | 
					    .blend_write = speaker_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,6 +49,7 @@
 | 
				
			|||||||
#include "DNA_text_types.h"
 | 
					#include "DNA_text_types.h"
 | 
				
			||||||
#include "DNA_userdef_types.h"
 | 
					#include "DNA_userdef_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_idtype.h"
 | 
					#include "BKE_idtype.h"
 | 
				
			||||||
#include "BKE_lib_id.h"
 | 
					#include "BKE_lib_id.h"
 | 
				
			||||||
#include "BKE_main.h"
 | 
					#include "BKE_main.h"
 | 
				
			||||||
@@ -169,6 +170,15 @@ static void text_free_data(ID *id)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void text_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  Text *text = (Text *)id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (text->filepath != NULL) {
 | 
				
			||||||
 | 
					    BKE_bpath_foreach_path_allocated_process(bpath_data, &text->filepath);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void text_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
					static void text_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  Text *text = (Text *)id;
 | 
					  Text *text = (Text *)id;
 | 
				
			||||||
@@ -250,6 +260,7 @@ IDTypeInfo IDType_ID_TXT = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = NULL,
 | 
					    .foreach_id = NULL,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = text_foreach_path,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = text_blend_write,
 | 
					    .blend_write = text_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -219,6 +219,7 @@ IDTypeInfo IDType_ID_TE = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = texture_foreach_id,
 | 
					    .foreach_id = texture_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = texture_blend_write,
 | 
					    .blend_write = texture_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,6 +49,7 @@
 | 
				
			|||||||
#include "DNA_vfont_types.h"
 | 
					#include "DNA_vfont_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "BKE_anim_path.h"
 | 
					#include "BKE_anim_path.h"
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_curve.h"
 | 
					#include "BKE_curve.h"
 | 
				
			||||||
#include "BKE_global.h"
 | 
					#include "BKE_global.h"
 | 
				
			||||||
#include "BKE_idtype.h"
 | 
					#include "BKE_idtype.h"
 | 
				
			||||||
@@ -123,6 +124,21 @@ static void vfont_free_data(ID *id)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void vfont_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  VFont *vfont = (VFont *)id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (vfont->packedfile != NULL && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (BKE_vfont_is_builtin(vfont)) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BKE_bpath_foreach_path_fixed_process(bpath_data, vfont->filepath);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
					static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  VFont *vf = (VFont *)id;
 | 
					  VFont *vf = (VFont *)id;
 | 
				
			||||||
@@ -170,6 +186,7 @@ IDTypeInfo IDType_ID_VF = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = NULL,
 | 
					    .foreach_id = NULL,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = vfont_foreach_path,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = vfont_blend_write,
 | 
					    .blend_write = vfont_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,6 +41,7 @@
 | 
				
			|||||||
#include "BLI_utildefines.h"
 | 
					#include "BLI_utildefines.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "BKE_anim_data.h"
 | 
					#include "BKE_anim_data.h"
 | 
				
			||||||
 | 
					#include "BKE_bpath.h"
 | 
				
			||||||
#include "BKE_geometry_set.hh"
 | 
					#include "BKE_geometry_set.hh"
 | 
				
			||||||
#include "BKE_global.h"
 | 
					#include "BKE_global.h"
 | 
				
			||||||
#include "BKE_idtype.h"
 | 
					#include "BKE_idtype.h"
 | 
				
			||||||
@@ -576,6 +577,17 @@ static void volume_foreach_cache(ID *id,
 | 
				
			|||||||
  function_callback(id, &key, (void **)&volume->runtime.grids, 0, user_data);
 | 
					  function_callback(id, &key, (void **)&volume->runtime.grids, 0, user_data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void volume_foreach_path(ID *id, BPathForeachPathData *bpath_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  Volume *volume = reinterpret_cast<Volume *>(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (volume->packedfile != nullptr && (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BKE_bpath_foreach_path_fixed_process(bpath_data, volume->filepath);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
					static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_address)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  Volume *volume = (Volume *)id;
 | 
					  Volume *volume = (Volume *)id;
 | 
				
			||||||
@@ -653,6 +665,7 @@ IDTypeInfo IDType_ID_VO = {
 | 
				
			|||||||
    /* make_local */ nullptr,
 | 
					    /* make_local */ nullptr,
 | 
				
			||||||
    /* foreach_id */ volume_foreach_id,
 | 
					    /* foreach_id */ volume_foreach_id,
 | 
				
			||||||
    /* foreach_cache */ volume_foreach_cache,
 | 
					    /* foreach_cache */ volume_foreach_cache,
 | 
				
			||||||
 | 
					    /* foreach_path */ volume_foreach_path,
 | 
				
			||||||
    /* owner_get */ nullptr,
 | 
					    /* owner_get */ nullptr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* blend_write */ volume_blend_write,
 | 
					    /* blend_write */ volume_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -195,6 +195,7 @@ IDTypeInfo IDType_ID_WS = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = workspace_foreach_id,
 | 
					    .foreach_id = workspace_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = workspace_blend_write,
 | 
					    .blend_write = workspace_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -200,6 +200,7 @@ IDTypeInfo IDType_ID_WO = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = world_foreach_id,
 | 
					    .foreach_id = world_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = world_blend_write,
 | 
					    .blend_write = world_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1332,7 +1332,8 @@ bool BLO_write_file(Main *mainvar,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* path backup/restore */
 | 
					  /* path backup/restore */
 | 
				
			||||||
  void *path_list_backup = NULL;
 | 
					  void *path_list_backup = NULL;
 | 
				
			||||||
  const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
 | 
					  const eBPathForeachFlag path_list_flag = (BKE_BPATH_FOREACH_PATH_SKIP_LINKED |
 | 
				
			||||||
 | 
					                                            BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
 | 
					  if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
 | 
				
			||||||
    BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* save to disk");
 | 
					    BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* save to disk");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -880,11 +880,12 @@ struct FileCheckCallbackInfo {
 | 
				
			|||||||
  bool external_file_found;
 | 
					  bool external_file_found;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool external_file_check_callback(void *callback_info_ptr,
 | 
					static bool external_file_check_callback(BPathForeachPathData *bpath_data,
 | 
				
			||||||
                                         char * /*path_dst*/,
 | 
					                                         char * /*path_dst*/,
 | 
				
			||||||
                                         const char *path_src)
 | 
					                                         const char *path_src)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  FileCheckCallbackInfo *callback_info = static_cast<FileCheckCallbackInfo *>(callback_info_ptr);
 | 
					  FileCheckCallbackInfo *callback_info = static_cast<FileCheckCallbackInfo *>(
 | 
				
			||||||
 | 
					      bpath_data->user_data);
 | 
				
			||||||
  BKE_reportf(callback_info->reports,
 | 
					  BKE_reportf(callback_info->reports,
 | 
				
			||||||
              RPT_ERROR,
 | 
					              RPT_ERROR,
 | 
				
			||||||
              "Unable to install asset bundle, has external dependency \"%s\"",
 | 
					              "Unable to install asset bundle, has external dependency \"%s\"",
 | 
				
			||||||
@@ -904,12 +905,19 @@ static bool has_external_files(Main *bmain, struct ReportList *reports)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  struct FileCheckCallbackInfo callback_info = {reports, false};
 | 
					  struct FileCheckCallbackInfo callback_info = {reports, false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BKE_bpath_traverse_main(
 | 
					  eBPathForeachFlag flag = static_cast<eBPathForeachFlag>(
 | 
				
			||||||
      bmain,
 | 
					      BKE_BPATH_FOREACH_PATH_SKIP_PACKED        /* Packed files are fine. */
 | 
				
			||||||
      &external_file_check_callback,
 | 
					      | BKE_BPATH_FOREACH_PATH_SKIP_MULTIFILE); /* Only report multifiles once, it's enough. */
 | 
				
			||||||
      BKE_BPATH_TRAVERSE_SKIP_PACKED /* Packed files are fine. */
 | 
					
 | 
				
			||||||
          | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE /* Only report multifiles once, it's enough. */,
 | 
					  BPathForeachPathData bpath_data = {
 | 
				
			||||||
      &callback_info);
 | 
					      /* bmain */ bmain,
 | 
				
			||||||
 | 
					      /* callback_function */ &external_file_check_callback,
 | 
				
			||||||
 | 
					      /* flag */ flag,
 | 
				
			||||||
 | 
					      /* user_data */ &callback_info,
 | 
				
			||||||
 | 
					      /* absolute_base_path */ nullptr,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BKE_bpath_foreach_path_main(&bpath_data);
 | 
				
			||||||
  return callback_info.external_file_found;
 | 
					  return callback_info.external_file_found;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -720,6 +720,7 @@ typedef struct RenderData {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* path to render output */
 | 
					  /* path to render output */
 | 
				
			||||||
  /** 1024 = FILE_MAX. */
 | 
					  /** 1024 = FILE_MAX. */
 | 
				
			||||||
 | 
					  /* NOTE: Excluded from `BKE_bpath_foreach_path_` / `scene_foreach_path` code. */
 | 
				
			||||||
  char pic[1024];
 | 
					  char pic[1024];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* stamps flags. */
 | 
					  /* stamps flags. */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,10 +94,13 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self))
 | 
				
			|||||||
  return ret;
 | 
					  return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool bpy_blend_paths_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
 | 
					static bool bpy_blend_foreach_path_cb(BPathForeachPathData *bpath_data,
 | 
				
			||||||
 | 
					                                      char *UNUSED(path_dst),
 | 
				
			||||||
 | 
					                                      const char *path_src)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  PyList_APPEND((PyObject *)userdata, PyC_UnicodeFromByte(path_src));
 | 
					  PyObject *py_list = bpath_data->user_data;
 | 
				
			||||||
  return false; /* never edits the path */
 | 
					  PyList_APPEND(py_list, PyC_UnicodeFromByte(path_src));
 | 
				
			||||||
 | 
					  return false; /* Never edits the path. */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PyDoc_STRVAR(bpy_blend_paths_doc,
 | 
					PyDoc_STRVAR(bpy_blend_paths_doc,
 | 
				
			||||||
@@ -115,7 +118,7 @@ PyDoc_STRVAR(bpy_blend_paths_doc,
 | 
				
			|||||||
             "   :rtype: list of strings\n");
 | 
					             "   :rtype: list of strings\n");
 | 
				
			||||||
static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
 | 
					static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  int flag = 0;
 | 
					  eBPathForeachFlag flag = 0;
 | 
				
			||||||
  PyObject *list;
 | 
					  PyObject *list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool absolute = false;
 | 
					  bool absolute = false;
 | 
				
			||||||
@@ -137,18 +140,21 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (absolute) {
 | 
					  if (absolute) {
 | 
				
			||||||
    flag |= BKE_BPATH_TRAVERSE_ABS;
 | 
					    flag |= BKE_BPATH_FOREACH_PATH_ABSOLUTE;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (!packed) {
 | 
					  if (!packed) {
 | 
				
			||||||
    flag |= BKE_BPATH_TRAVERSE_SKIP_PACKED;
 | 
					    flag |= BKE_BPATH_FOREACH_PATH_SKIP_PACKED;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (local) {
 | 
					  if (local) {
 | 
				
			||||||
    flag |= BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
 | 
					    flag |= BKE_BPATH_FOREACH_PATH_SKIP_LINKED;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  list = PyList_New(0);
 | 
					  list = PyList_New(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BKE_bpath_traverse_main(G_MAIN, bpy_blend_paths_visit_cb, flag, (void *)list);
 | 
					  BKE_bpath_foreach_path_main(&(BPathForeachPathData){.bmain = G_MAIN,
 | 
				
			||||||
 | 
					                                              .callback_function = bpy_blend_foreach_path_cb,
 | 
				
			||||||
 | 
					                                              .flag = flag,
 | 
				
			||||||
 | 
					                                              .user_data = list});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return list;
 | 
					  return list;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -280,6 +280,7 @@ IDTypeInfo IDType_ID_WM = {
 | 
				
			|||||||
    .make_local = NULL,
 | 
					    .make_local = NULL,
 | 
				
			||||||
    .foreach_id = window_manager_foreach_id,
 | 
					    .foreach_id = window_manager_foreach_id,
 | 
				
			||||||
    .foreach_cache = NULL,
 | 
					    .foreach_cache = NULL,
 | 
				
			||||||
 | 
					    .foreach_path = NULL,
 | 
				
			||||||
    .owner_get = NULL,
 | 
					    .owner_get = NULL,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .blend_write = window_manager_blend_write,
 | 
					    .blend_write = window_manager_blend_write,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user