diff options
Diffstat (limited to 'source/blender/blenloader')
21 files changed, 560 insertions, 793 deletions
diff --git a/source/blender/blenloader/BLO_blend_validate.h b/source/blender/blenloader/BLO_blend_validate.h index cdbf4bdd952..3a192284661 100644 --- a/source/blender/blenloader/BLO_blend_validate.h +++ b/source/blender/blenloader/BLO_blend_validate.h @@ -28,5 +28,12 @@ struct Main; struct ReportList; +/** + * Check (but do *not* fix) that all linked data-blocks are still valid + * (i.e. pointing to the right library). + */ bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports); +/** + * * Check (and fix if needed) that shape key's 'from' pointer is valid. + */ bool BLO_main_validate_shapekeys(struct Main *bmain, struct ReportList *reports); diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index ca7ea6d8f09..fe8173e335a 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -58,8 +58,8 @@ struct BlendFileReadReport; struct Main; struct ReportList; -/* Blend Write API - * =============== +/* -------------------------------------------------------------------- */ +/** \name Blend Write API * * Most functions fall into one of two categories. Either they write a DNA struct or a raw memory * buffer to the .blend file. @@ -91,19 +91,25 @@ struct ReportList; * The code that reads this data might have to correct its byte-order. For the common cases * there are convenience functions that write and read arrays of simple types such as `int32`. * Those will correct endianness automatically. - */ + * \{ */ -/* Mapping between names and ids. */ +/** + * Mapping between names and ids. + */ int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name); #define BLO_get_struct_id(writer, struct_name) SDNA_TYPE_FROM_STRUCT(struct_name) -/* Write single struct. */ +/** + * Write single struct. + */ void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr); void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr); #define BLO_write_struct(writer, struct_name, data_ptr) \ BLO_write_struct_by_id(writer, BLO_get_struct_id(writer, struct_name), data_ptr) -/* Write single struct at address. */ +/** + * Write single struct at address. + */ void BLO_write_struct_at_address_by_id(BlendWriter *writer, int struct_id, const void *address, @@ -112,7 +118,9 @@ void BLO_write_struct_at_address_by_id(BlendWriter *writer, BLO_write_struct_at_address_by_id( \ writer, BLO_get_struct_id(writer, struct_name), address, data_ptr) -/* Write single struct at address and specify a filecode. */ +/** + * Write single struct at address and specify a file-code. + */ void BLO_write_struct_at_address_by_id_with_filecode( BlendWriter *writer, int filecode, int struct_id, const void *address, const void *data_ptr); #define BLO_write_struct_at_address_with_filecode( \ @@ -120,7 +128,9 @@ void BLO_write_struct_at_address_by_id_with_filecode( BLO_write_struct_at_address_by_id_with_filecode( \ writer, filecode, BLO_get_struct_id(writer, struct_name), address, data_ptr) -/* Write struct array. */ +/** + * Write struct array. + */ void BLO_write_struct_array_by_name(BlendWriter *writer, const char *struct_name, int array_size, @@ -133,14 +143,18 @@ void BLO_write_struct_array_by_id(BlendWriter *writer, BLO_write_struct_array_by_id( \ writer, BLO_get_struct_id(writer, struct_name), array_size, data_ptr) -/* Write struct array at address. */ +/** + * Write struct array at address. + */ void BLO_write_struct_array_at_address_by_id( BlendWriter *writer, int struct_id, int array_size, const void *address, const void *data_ptr); #define BLO_write_struct_array_at_address(writer, struct_name, array_size, address, data_ptr) \ BLO_write_struct_array_at_address_by_id( \ writer, BLO_get_struct_id(writer, struct_name), array_size, address, data_ptr) -/* Write struct list. */ +/** + * Write struct list. + */ void BLO_write_struct_list_by_name(BlendWriter *writer, const char *struct_name, struct ListBase *list); @@ -148,7 +162,9 @@ void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, struct List #define BLO_write_struct_list(writer, struct_name, list_ptr) \ BLO_write_struct_list_by_id(writer, BLO_get_struct_id(writer, struct_name), list_ptr) -/* Write id struct. */ +/** + * Write id struct. + */ void blo_write_id_struct(BlendWriter *writer, int struct_id, const void *id_address, @@ -156,7 +172,9 @@ void blo_write_id_struct(BlendWriter *writer, #define BLO_write_id_struct(writer, struct_name, id_address, id) \ blo_write_id_struct(writer, BLO_get_struct_id(writer, struct_name), id_address, id) -/* Write raw data. */ +/** + * Write raw data. + */ void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_ptr); void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr); void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr); @@ -164,13 +182,23 @@ void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr) void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr); void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr); void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr); +/** + * Write a null terminated string. + */ void BLO_write_string(BlendWriter *writer, const char *data_ptr); /* Misc. */ + +/** + * Sometimes different data is written depending on whether the file is saved to disk or used for + * undo. This function returns true when the current file-writing is done for undo. + */ bool BLO_write_is_undo(BlendWriter *writer); -/* Blend Read Data API - * =================== +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Blend Read Data API * * Generally, for every BLO_write_* call there should be a corresponding BLO_read_* call. * @@ -181,15 +209,18 @@ bool BLO_write_is_undo(BlendWriter *writer); * updated to be NULL. When it was pointing to NULL before, it will stay that way. * * Examples of matching calls: - * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms); - * BLO_read_data_address(reader, &clmd->sim_parms); * - * BLO_write_struct_list(writer, TimeMarker, &action->markers); - * BLO_read_list(reader, &action->markers); + * \code{.c} + * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms); + * BLO_read_data_address(reader, &clmd->sim_parms); * - * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar); - * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar); - */ + * BLO_write_struct_list(writer, TimeMarker, &action->markers); + * BLO_read_list(reader, &action->markers); + * + * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar); + * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar); + * \endcode + * \{ */ void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address); void *BLO_read_get_new_data_address_no_us(BlendDataReader *reader, const void *old_address); @@ -201,10 +232,16 @@ void *BLO_read_get_new_packed_address(BlendDataReader *reader, const void *old_a *((void **)ptr_p) = BLO_read_get_new_packed_address((reader), *(ptr_p)) typedef void (*BlendReadListFn)(BlendDataReader *reader, void *data); +/** + * Updates all ->prev and ->next pointers of the list elements. + * Updates the list->first and list->last pointers. + * When not NULL, calls the callback on every element. + */ void BLO_read_list_cb(BlendDataReader *reader, struct ListBase *list, BlendReadListFn callback); void BLO_read_list(BlendDataReader *reader, struct ListBase *list); /* Update data pointers and correct byte-order if necessary. */ + void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p); void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p); void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p); @@ -213,18 +250,21 @@ void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p); /* Misc. */ + bool BLO_read_requires_endian_switch(BlendDataReader *reader); bool BLO_read_data_is_undo(BlendDataReader *reader); void BLO_read_data_globmap_add(BlendDataReader *reader, void *oldaddr, void *newaddr); void BLO_read_glob_list(BlendDataReader *reader, struct ListBase *list); struct BlendFileReadReport *BLO_read_data_reports(BlendDataReader *reader); -/* Blend Read Lib API - * =================== +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Blend Read Lib API * - * This API does almost the same as the Blend Read Data API. However, now only pointers to ID data - * blocks are updated. - */ + * This API does almost the same as the Blend Read Data API. + * However, now only pointers to ID data blocks are updated. + * \{ */ ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, struct ID *id); @@ -232,30 +272,44 @@ ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, str *((void **)id_ptr_p) = (void *)BLO_read_get_new_id_address((reader), (lib), (ID *)*(id_ptr_p)) /* Misc. */ + bool BLO_read_lib_is_undo(BlendLibReader *reader); struct Main *BLO_read_lib_get_main(BlendLibReader *reader); struct BlendFileReadReport *BLO_read_lib_reports(BlendLibReader *reader); -/* Blend Expand API - * =================== +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Blend Expand API * * BLO_expand has to be called for every data block that should be loaded. If the data block is in - * a separate .blend file, it will be pulled from there. - */ + * a separate `.blend` file, it will be pulled from there. + * \{ */ void BLO_expand_id(BlendExpander *expander, struct ID *id); #define BLO_expand(expander, id) BLO_expand_id(expander, (struct ID *)id) -/* Report API - * =================== - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Report API + * \{ */ +/** + * This function ensures that reports are printed, + * in the case of library linking errors this is important! + * + * bit kludge but better than doubling up on prints, + * we could alternatively have a versions of a report function which forces printing - campbell + */ void BLO_reportf_wrap(struct BlendFileReadReport *reports, eReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4); +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 22182edd070..567886e4d54 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -74,7 +74,7 @@ typedef struct BlendFileData { int fileflags; int globalf; - char filename[1024]; /* 1024 = FILE_MAX */ + char filepath[1024]; /* 1024 = FILE_MAX */ struct bScreen *curscreen; /* TODO: think this isn't needed anymore? */ struct Scene *curscene; @@ -144,19 +144,50 @@ typedef enum eBLOReadSkip { } eBLOReadSkip; #define BLO_READ_SKIP_ALL (BLO_READ_SKIP_USERDEF | BLO_READ_SKIP_DATA) +/** + * Open a blender file from a pathname. The function returns NULL + * and sets a report in the list if it cannot open the file. + * + * \param filepath: The path of the file to open. + * \param reports: If the return value is NULL, errors indicating the cause of the failure. + * \return The data of the file. + */ BlendFileData *BLO_read_from_file(const char *filepath, eBLOReadSkip skip_flags, struct BlendFileReadReport *reports); +/** + * Open a blender file from memory. The function returns NULL + * and sets a report in the list if it cannot open the file. + * + * \param mem: The file data. + * \param memsize: The length of \a mem. + * \param reports: If the return value is NULL, errors indicating the cause of the failure. + * \return The data of the file. + */ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, eBLOReadSkip skip_flags, struct ReportList *reports); +/** + * Used for undo/redo, skips part of libraries reading + * (assuming their data are already loaded & valid). + * + * \param oldmain: old main, + * from which we will keep libraries and other data-blocks that should not have changed. + * \param filename: current file, only for retrieving library data. + */ BlendFileData *BLO_read_from_memfile(struct Main *oldmain, const char *filename, struct MemFile *memfile, const struct BlendFileReadParams *params, struct ReportList *reports); +/** + * Frees a BlendFileData structure and *all* the data associated with it + * (the userdef data, and the main libblock data). + * + * \param bfd: The structure to free. + */ void BLO_blendfiledata_free(BlendFileData *bfd); /** \} */ @@ -170,24 +201,89 @@ typedef struct BLODataBlockInfo { struct AssetMetaData *asset_data; } BLODataBlockInfo; +/** + * Open a blendhandle from a file path. + * + * \param filepath: The file path to open. + * \param reports: Report errors in opening the file (can be NULL). + * \return A handle on success, or NULL on failure. + */ BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct BlendFileReadReport *reports); +/** + * Open a blendhandle from memory. + * + * \param mem: The data to load from. + * \param memsize: The size of the data. + * \return A handle on success, or NULL on failure. + */ BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize, struct BlendFileReadReport *reports); +/** + * Gets the names of all the data-blocks in a file of a certain type + * (e.g. all the scene names in a file). + * + * \param bh: The blendhandle to access. + * \param ofblocktype: The type of names to get. + * \param use_assets_only: Only list IDs marked as assets. + * \param r_tot_names: The length of the returned list. + * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN(). + */ struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_names); +/** + * Gets the names and asset-data (if ID is an asset) of data-blocks in a file of a certain type. + * The data-blocks can be limited to assets. + * + * \param bh: The blendhandle to access. + * \param ofblocktype: The type of names to get. + * \param use_assets_only: Limit the result to assets only. + * \param r_tot_info_items: The length of the returned list. + * \return A BLI_linklist of `BLODataBlockInfo *`. + * The links and #BLODataBlockInfo.asset_data should be freed with MEM_freeN. + */ struct LinkNode * /*BLODataBlockInfo */ BLO_blendhandle_get_datablock_info( BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_info_items); +/** + * Gets the previews of all the data-blocks in a file of a certain type + * (e.g. all the scene previews in a file). + * + * \param bh: The blendhandle to access. + * \param ofblocktype: The type of names to get. + * \param r_tot_prev: The length of the returned list. + * \return A BLI_linklist of #PreviewImage. The #PreviewImage links should be freed with malloc. + */ struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev); +/** + * Get the PreviewImage of a single data block in a file. + * (e.g. all the scene previews in a file). + * + * \param bh: The blendhandle to access. + * \param ofblocktype: The type of names to get. + * \param name: Name of the block without the ID_ prefix, to read the preview image from. + * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned + */ struct PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh, int ofblocktype, const char *name); +/** + * Gets the names of all the linkable data-block types available in a file. + * (e.g. "Scene", "Mesh", "Light", etc.). + * + * \param bh: The blendhandle to access. + * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN(). + */ struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh); +/** + * Close and free a blendhandle. The handle becomes invalid after this call. + * + * \param bh: The handle to close. + */ void BLO_blendhandle_close(BlendHandle *bh); /** \} */ @@ -195,7 +291,25 @@ void BLO_blendhandle_close(BlendHandle *bh); #define BLO_GROUP_MAX 32 #define BLO_EMBEDDED_STARTUP_BLEND "<startup.blend>" +/** + * Check whether given path ends with a blend file compatible extension + * (`.blend`, `.ble` or `.blend.gz`). + * + * \param str: The path to check. + * \return true is this path ends with a blender file extension. + */ bool BLO_has_bfile_extension(const char *str); +/** + * Try to explode given path into its 'library components' + * (i.e. a .blend file, id type/group, and data-block itself). + * + * \param path: the full path to explode. + * \param r_dir: the string that'll contain path up to blend file itself ('library' path). + * WARNING! Must be #FILE_MAX_LIBEXTRA long (it also stores group and name strings)! + * \param r_group: the string that'll contain 'group' part of the path, if any. May be NULL. + * \param r_name: the string that'll contain data's name part of the path, if any. May be NULL. + * \return true if path contains a blend file. + */ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name); /* -------------------------------------------------------------------- */ @@ -212,14 +326,6 @@ typedef enum eBLOLibLinkFlags { BLO_LIBLINK_USE_PLACEHOLDERS = 1 << 16, /** Force loaded ID to be tagged as #LIB_TAG_INDIRECT (used in reload context only). */ BLO_LIBLINK_FORCE_INDIRECT = 1 << 17, - /** - * When set, tag ID types that pass the internal check #library_link_idcode_needs_tag_check - * - * Currently this is only used to instantiate objects in the scene. - * Set this from #BLO_library_link_params_init_with_context so callers - * don't need to remember to set this flag. - */ - BLO_LIBLINK_NEEDS_ID_TAG_DOIT = 1 << 18, /** Set fake user on appended IDs. */ BLO_LIBLINK_APPEND_SET_FAKEUSER = 1 << 19, /** Append (make local) also indirect dependencies of appended IDs coming from other libraries. @@ -241,7 +347,7 @@ typedef enum eBLOLibLinkFlags { * #BLO_library_link_begin, #BLO_library_link_named_part & #BLO_library_link_end. * Wrap these in parameters since it's important both functions receive matching values. */ -struct LibraryLink_Params { +typedef struct LibraryLink_Params { /** The current main database, e.g. #G_MAIN or `CTX_data_main(C)`. */ struct Main *bmain; /** Options for linking, used for instantiating. */ @@ -257,7 +363,7 @@ struct LibraryLink_Params { /** The active 3D viewport (only used to define local-view). */ const struct View3D *v3d; } context; -}; +} LibraryLink_Params; void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, @@ -271,20 +377,45 @@ void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params struct ViewLayer *view_layer, const struct View3D *v3d); +/** + * Initialize the #BlendHandle for linking library data. + * + * \param bh: A blender file handle as returned by + * #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory. + * \param filepath: Used for relative linking, copied to the `lib->filepath`. + * \param params: Settings for linking that don't change from beginning to end of linking. + * \return the library #Main, to be passed to #BLO_library_link_named_part as \a mainl. + */ struct Main *BLO_library_link_begin(BlendHandle **bh, const char *filepath, const struct LibraryLink_Params *params); +/** + * Link a named data-block from an external blend file. + * + * \param mainl: The main database to link from (not the active one). + * \param bh: The blender file handle. + * \param idcode: The kind of data-block to link. + * \param name: The name of the data-block (without the 2 char ID prefix). + * \return the linked ID when found. + */ struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, const short idcode, const char *name, const struct LibraryLink_Params *params); +/** + * Finalize linking from a given .blend file (library). + * Optionally instance the indirect object/collection in the scene when the flags are set. + * \note Do not use \a bh after calling this function, it may frees it. + * + * \param mainl: The main database to link from (not the active one). + * \param bh: The blender file handle (WARNING! may be freed by this function!). + * \param params: Settings for linking that don't change from beginning to end of linking. + */ void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, const struct LibraryLink_Params *params); -int BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh, const uint64_t id_types_mask); - /** * Struct for temporarily loading datablocks from a blend file. */ @@ -314,6 +445,10 @@ void BLO_library_temp_free(TempLibraryContext *temp_lib_ctx); void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname); /* internal function but we need to expose it */ +/** + * Used to link a file (without UI) to the current UI. + * Note that it assumes the old pointers in UI are still valid, so old Main is not freed. + */ void blo_lib_link_restore(struct Main *oldmain, struct Main *newmain, struct wmWindowManager *curwm, @@ -322,29 +457,50 @@ void blo_lib_link_restore(struct Main *oldmain, typedef void (*BLOExpandDoitCallback)(void *fdhandle, struct Main *mainvar, void *idv); +/** + * Set the callback func used over all ID data found by \a BLO_expand_main func. + * + * \param expand_doit_func: Called for each ID block it finds. + */ void BLO_main_expander(BLOExpandDoitCallback expand_doit_func); +/** + * Loop over all ID data in Main to mark relations. + * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding. + * + * \param fdhandle: usually filedata, or own handle. + * \param mainvar: the Main database to expand. + */ void BLO_expand_main(void *fdhandle, struct Main *mainvar); /** * Update defaults in startup.blend, without having to save and embed it. * \note defaults for preferences are stored in `userdef_default.c` and can be updated there. */ +/** + * Update defaults in startup.blend, without having to save and embed the file. + * This function can be emptied each time the startup.blend is updated. + * + * \note Screen data may be cleared at this point, this will happen in the case + * an app-template's data needs to be versioned when read-file is called with "Load UI" disabled. + * Versioning the screen data can be safely skipped without "Load UI" since the screen data + * will have been versioned when it was first loaded. + */ void BLO_update_defaults_startup_blend(struct Main *bmain, const char *app_template); void BLO_update_defaults_workspace(struct WorkSpace *workspace, const char *app_template); /* Disable unwanted experimental feature settings on startup. */ void BLO_sanitize_experimental_features_userpref_blend(struct UserDef *userdef); +/** + * Does a very light reading of given .blend file to extract its stored thumbnail. + * + * \param filepath: The path of the file to extract thumbnail from. + * \return The raw thumbnail + * (MEM-allocated, as stored in file, use #BKE_main_thumbnail_to_imbuf() + * to convert it to ImBuf image). + */ struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath); -void BLO_object_instantiate_object_base_instance_init(struct Main *bmain, - struct Collection *collection, - struct Object *ob, - struct ViewLayer *view_layer, - const struct View3D *v3d, - const int flag, - bool set_active); - /* datafiles (generated theme) */ extern const struct bTheme U_theme_default; extern const struct UserDef U_default; diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h index 4e240e2462b..0e2c22d7e4d 100644 --- a/source/blender/blenloader/BLO_undofile.h +++ b/source/blender/blenloader/BLO_undofile.h @@ -77,7 +77,7 @@ typedef struct { bool memchunk_identical; } UndoReader; -/* actually only used writefile.c */ +/* Actually only used `writefile.c`. */ void BLO_memfile_write_init(MemFileWriteData *mem_data, MemFile *written_memfile, @@ -87,14 +87,31 @@ void BLO_memfile_write_finalize(MemFileWriteData *mem_data); void BLO_memfile_chunk_add(MemFileWriteData *mem_data, const char *buf, size_t size); /* exports */ + +/** + * Not memfile itself. + */ extern void BLO_memfile_free(MemFile *memfile); +/** + * Result is that 'first' is being freed. + * to keep list of memfiles consistent, 'first' is always first in list. + */ extern void BLO_memfile_merge(MemFile *first, MemFile *second); +/** + * Clear is_identical_future before adding next memfile. + */ extern void BLO_memfile_clear_future(MemFile *memfile); -/* utilities */ +/* Utilities. */ + extern struct Main *BLO_memfile_main_get(struct MemFile *memfile, struct Main *bmain, struct Scene **r_scene); +/** + * Saves .blend using undo buffer. + * + * \return success. + */ extern bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename); FileReader *BLO_memfile_new_filereader(MemFile *memfile, int undo_direction); diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h index 746c663926d..9bc3714ff38 100644 --- a/source/blender/blenloader/BLO_writefile.h +++ b/source/blender/blenloader/BLO_writefile.h @@ -21,9 +21,13 @@ /** \file * \ingroup blenloader - * \brief external writefile function prototypes. + * \brief external `writefile.c` function prototypes. */ +#ifdef __cplusplus +extern "C" { +#endif + struct BlendThumbnail; struct Main; struct MemFile; @@ -60,15 +64,25 @@ struct BlendFileWriteParams { const struct BlendThumbnail *thumb; }; +/** + * \return Success. + */ extern bool BLO_write_file(struct Main *mainvar, const char *filepath, const int write_flags, const struct BlendFileWriteParams *params, struct ReportList *reports); +/** + * \return Success. + */ extern bool BLO_write_file_mem(struct Main *mainvar, struct MemFile *compare, struct MemFile *current, int write_flags); /** \} */ + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index b3df5c8aa67..05f74bfa834 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -34,7 +34,6 @@ set(INC ../sequencer ../windowmanager ../../../intern/clog - ../../../intern/ghost ../../../intern/guardedalloc # for writefile.c: dna_type_offsets.h @@ -114,6 +113,7 @@ if(WITH_GTESTS) tests/blendfile_loading_base_test.h ) set(TEST_INC + ../../../intern/ghost ) set(TEST_LIB bf_blenloader diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c index 7d641d976e3..333f6e341c6 100644 --- a/source/blender/blenloader/intern/blend_validate.c +++ b/source/blender/blenloader/intern/blend_validate.c @@ -47,10 +47,6 @@ #include "readfile.h" -/** - * Check (but do *not* fix) that all linked data-blocks are still valid - * (i.e. pointing to the right library). - */ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) { ListBase mainlist; @@ -165,7 +161,6 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) return is_valid; } -/** Check (and fix if needed) that shape key's 'from' pointer is valid. */ bool BLO_main_validate_shapekeys(Main *bmain, ReportList *reports) { ListBase *lb; diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index c0fdfa86907..f3c92aec338 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -61,13 +61,6 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp); /* Access routines used by filesel. */ -/** - * Open a blendhandle from a file path. - * - * \param filepath: The file path to open. - * \param reports: Report errors in opening the file (can be NULL). - * \return A handle on success, or NULL on failure. - */ BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport *reports) { BlendHandle *bh; @@ -77,13 +70,6 @@ BlendHandle *BLO_blendhandle_from_file(const char *filepath, BlendFileReadReport return bh; } -/** - * Open a blendhandle from memory. - * - * \param mem: The data to load from. - * \param memsize: The size of the data. - * \return A handle on success, or NULL on failure. - */ BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize, BlendFileReadReport *reports) @@ -130,16 +116,6 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp) fprintf(fp, "]\n"); } -/** - * Gets the names of all the data-blocks in a file of a certain type - * (e.g. all the scene names in a file). - * - * \param bh: The blendhandle to access. - * \param ofblocktype: The type of names to get. - * \param tot_names: The length of the returned list. - * \param use_assets_only: Only list IDs marked as assets. - * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN(). - */ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, const bool use_assets_only, @@ -169,17 +145,6 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, return names; } -/** - * Gets the names and asset-data (if ID is an asset) of data-blocks in a file of a certain type. - * The data-blocks can be limited to assets. - * - * \param bh: The blendhandle to access. - * \param ofblocktype: The type of names to get. - * \param use_assets_only: Limit the result to assets only. - * \param tot_info_items: The length of the returned list. - * \return A BLI_linklist of BLODataBlockInfo *. The links and #BLODataBlockInfo.asset_data should - * be freed with MEM_freeN. - */ LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh, int ofblocktype, const bool use_assets_only, @@ -267,15 +232,6 @@ static BHead *blo_blendhandle_read_preview_rects(FileData *fd, return bhead; } -/** - * Get the PreviewImage of a single data block in a file. - * (e.g. all the scene previews in a file). - * - * \param bh: The blendhandle to access. - * \param ofblocktype: The type of names to get. - * \param name: Name of the block without the ID_ prefix, to read the preview image from. - * \return PreviewImage or NULL when no preview Images have been found. Caller owns the returned - */ PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh, int ofblocktype, const char *name) @@ -315,15 +271,6 @@ PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh, return NULL; } -/** - * Gets the previews of all the data-blocks in a file of a certain type - * (e.g. all the scene previews in a file). - * - * \param bh: The blendhandle to access. - * \param ofblocktype: The type of names to get. - * \param r_tot_prev: The length of the returned list. - * \return A BLI_linklist of PreviewImage. The PreviewImage links should be freed with malloc. - */ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_tot_prev) { FileData *fd = (FileData *)bh; @@ -384,13 +331,6 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_ return previews; } -/** - * Gets the names of all the linkable data-block types available in a file. - * (e.g. "Scene", "Mesh", "Light", etc.). - * - * \param bh: The blendhandle to access. - * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN(). - */ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) { FileData *fd = (FileData *)bh; @@ -418,11 +358,6 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) return names; } -/** - * Close and free a blendhandle. The handle becomes invalid after this call. - * - * \param bh: The handle to close. - */ void BLO_blendhandle_close(BlendHandle *bh) { FileData *fd = (FileData *)bh; @@ -432,14 +367,6 @@ void BLO_blendhandle_close(BlendHandle *bh) /**********/ -/** - * Open a blender file from a pathname. The function returns NULL - * and sets a report in the list if it cannot open the file. - * - * \param filepath: The path of the file to open. - * \param reports: If the return value is NULL, errors indicating the cause of the failure. - * \return The data of the file. - */ BlendFileData *BLO_read_from_file(const char *filepath, eBLOReadSkip skip_flags, BlendFileReadReport *reports) @@ -457,15 +384,6 @@ BlendFileData *BLO_read_from_file(const char *filepath, return bfd; } -/** - * Open a blender file from memory. The function returns NULL - * and sets a report in the list if it cannot open the file. - * - * \param mem: The file data. - * \param memsize: The length of \a mem. - * \param reports: If the return value is NULL, errors indicating the cause of the failure. - * \return The data of the file. - */ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, eBLOReadSkip skip_flags, @@ -485,14 +403,6 @@ BlendFileData *BLO_read_from_memory(const void *mem, return bfd; } -/** - * Used for undo/redo, skips part of libraries reading - * (assuming their data are already loaded & valid). - * - * \param oldmain: old main, - * from which we will keep libraries and other data-blocks that should not have changed. - * \param filename: current file, only for retrieving library data. - */ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFile *memfile, @@ -548,12 +458,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, return bfd; } -/** - * Frees a BlendFileData structure and *all* the data associated with it - * (the userdef data, and the main libblock data). - * - * \param bfd: The structure to free. - */ void BLO_blendfiledata_free(BlendFileData *bfd) { if (bfd->main) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index e4fe3e8da00..56047bb7f4f 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -195,7 +195,6 @@ static void read_libraries(FileData *basefd, ListBase *mainlist); static void *read_struct(FileData *fd, BHead *bh, const char *blockname); static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name); static BHead *find_bhead_from_idname(FileData *fd, const char *idname); -static bool library_link_idcode_needs_tag_check(const short idcode, const int flag); typedef struct BHeadN { struct BHeadN *next, *prev; @@ -215,13 +214,6 @@ typedef struct BHeadN { * because ID names are used in lookup tables. */ #define BHEAD_USE_READ_ON_DEMAND(bhead) ((bhead)->code == DATA) -/** - * This function ensures that reports are printed, - * in the case of library linking errors this is important! - * - * bit kludge but better than doubling up on prints, - * we could alternatively have a versions of a report function which forces printing - campbell - */ void BLO_reportf_wrap(BlendFileReadReport *reports, eReportType type, const char *format, ...) { char fixed_buf[1024]; /* should be long enough */ @@ -639,7 +631,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab // printf("blo_find_main: converted to %s\n", name1); for (m = mainlist->first; m; m = m->next) { - const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->name; + const char *libname = (m->curlib) ? m->curlib->filepath_abs : m->filepath; if (BLI_path_cmp(name1, libname) == 0) { if (G.debug & G_DEBUG) { @@ -998,13 +990,11 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock) } #endif /* USE_BHEAD_READ_ON_DEMAND */ -/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead) { return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset); } -/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead) { BLI_assert(blo_bhead_is_id_valid_type(bhead)); @@ -1149,6 +1139,10 @@ static int *read_file_thumbnail(FileData *fd) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name File Data API + * \{ */ + static FileData *filedata_new(BlendFileReadReport *reports) { BLI_assert(reports != NULL); @@ -1270,8 +1264,6 @@ static FileData *blo_filedata_from_file_open(const char *filepath, BlendFileRead return blo_filedata_from_file_descriptor(filepath, reports, file); } -/* cannot be called with relative paths anymore! */ -/* on each new library added, it now checks for the current FileData and expands relativeness */ FileData *blo_filedata_from_file(const char *filepath, BlendFileReadReport *reports) { FileData *fd = blo_filedata_from_file_open(filepath, reports); @@ -1412,30 +1404,12 @@ void blo_filedata_free(FileData *fd) /** \name Public Utilities * \{ */ -/** - * Check whether given path ends with a blend file compatible extension - * (`.blend`, `.ble` or `.blend.gz`). - * - * \param str: The path to check. - * \return true is this path ends with a blender file extension. - */ bool BLO_has_bfile_extension(const char *str) { const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL}; return BLI_path_extension_check_array(str, ext_test); } -/** - * Try to explode given path into its 'library components' - * (i.e. a .blend file, id type/group, and data-block itself). - * - * \param path: the full path to explode. - * \param r_dir: the string that'll contain path up to blend file itself ('library' path). - * WARNING! Must be #FILE_MAX_LIBEXTRA long (it also stores group and name strings)! - * \param r_group: the string that'll contain 'group' part of the path, if any. May be NULL. - * \param r_name: the string that'll contain data's name part of the path, if any. May be NULL. - * \return true if path contains a blend file. - */ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name) { /* We might get some data names with slashes, @@ -1496,14 +1470,6 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha return true; } -/** - * Does a very light reading of given .blend file to extract its stored thumbnail. - * - * \param filepath: The path of the file to extract thumbnail from. - * \return The raw thumbnail - * (MEM-allocated, as stored in file, use #BKE_main_thumbnail_to_imbuf() - * to convert it to ImBuf image). - */ BlendThumbnail *BLO_thumbnail_from_file(const char *filepath) { FileData *fd; @@ -1552,7 +1518,6 @@ static void *newdataadr_no_us(FileData *fd, const void *adr) return oldnewmap_lookup_and_inc(fd->datamap, adr, false); } -/* Direct datablocks with global linking. */ void *blo_read_get_new_globaldata_address(FileData *fd, const void *adr) { return oldnewmap_lookup_and_inc(fd->globmap, adr, true); @@ -1574,7 +1539,6 @@ static void *newlibadr(FileData *fd, const void *lib, const void *adr) return oldnewmap_liblookup(fd->libmap, adr, lib); } -/* only lib data */ void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr) { return newlibadr(fd, lib, adr); @@ -1616,12 +1580,6 @@ static void change_link_placeholder_to_real_ID_pointer(ListBase *mainlist, } } -/* lib linked proxy objects point to our local data, we need - * to clear that pointer before reading the undo memfile since - * the object might be removed, it is set again in reading - * if the local object still exists. - * This is only valid for local proxy objects though, linked ones should not be affected here. - */ void blo_clear_proxy_pointers_from_lib(Main *oldmain) { LISTBASE_FOREACH (Object *, ob, &oldmain->objects) { @@ -1681,8 +1639,6 @@ void blo_make_packed_pointer_map(FileData *fd, Main *oldmain) } } -/* set old main packed data to zero if it has been restored */ -/* this works because freeing old main only happens after this call */ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) { OldNew *entry = fd->packedmap->entries; @@ -1719,7 +1675,6 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) } } -/* undo file support: add all library pointers in lookup */ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd) { ListBase *lbarray[INDEX_ID_MAX]; @@ -1736,8 +1691,6 @@ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd) fd->old_mainlist = old_mainlist; } -/* Build a GSet of old main (we only care about local data here, so we can do that after - * split_main() call. */ void blo_make_old_idmap_from_main(FileData *fd, Main *bmain) { if (fd->old_idmap != NULL) { @@ -2771,10 +2724,6 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, } } -/** - * Used to link a file (without UI) to the current UI. - * Note that it assumes the old pointers in UI are still valid, so old Main is not freed. - */ void blo_lib_link_restore(Main *oldmain, Main *newmain, wmWindowManager *curwm, @@ -2903,7 +2852,7 @@ static void lib_link_library(BlendLibReader *UNUSED(reader), Library *UNUSED(lib * in relation to the blend file. */ static void fix_relpaths_library(const char *basepath, Main *main) { - /* BLO_read_from_memory uses a blank filename */ + /* #BLO_read_from_memory uses a blank file-path. */ if (basepath == NULL || basepath[0] == '\0') { LISTBASE_FOREACH (Library *, lib, &main->libraries) { /* when loading a linked lib into a file which has not been saved, @@ -3557,25 +3506,25 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead) bfd->fileflags = fg->fileflags; bfd->globalf = fg->globalf; - BLI_strncpy(bfd->filename, fg->filename, sizeof(bfd->filename)); + STRNCPY(bfd->filepath, fg->filepath); - /* Error in 2.65 and older: main->name was not set if you save from startup + /* Error in 2.65 and older: `main->filepath` was not set if you save from startup * (not after loading file). */ - if (bfd->filename[0] == 0) { + if (bfd->filepath[0] == 0) { if (fd->fileversion < 265 || (fd->fileversion == 265 && fg->subversion < 1)) { if ((G.fileflags & G_FILE_RECOVER_READ) == 0) { - BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename)); + STRNCPY(bfd->filepath, BKE_main_blendfile_path(bfd->main)); } } - /* early 2.50 version patch - filename not in FileGlobal struct at all */ + /* early 2.50 version patch - filepath not in FileGlobal struct at all */ if (fd->fileversion <= 250) { - BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename)); + STRNCPY(bfd->filepath, BKE_main_blendfile_path(bfd->main)); } } if (G.fileflags & G_FILE_RECOVER_READ) { - BLI_strncpy(fd->relabase, fg->filename, sizeof(fd->relabase)); + BLI_strncpy(fd->relabase, fg->filepath, sizeof(fd->relabase)); } bfd->curscreen = fg->curscreen; @@ -3671,7 +3620,7 @@ static void do_versions_after_linking(Main *main, ReportList *reports) CLOG_INFO(&LOG, 2, "Processing %s (%s), %d.%d", - main->curlib ? main->curlib->filepath : main->name, + main->curlib ? main->curlib->filepath : main->filepath, main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile); @@ -3909,7 +3858,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) if ((fd->skip_flags & BLO_READ_SKIP_DATA) == 0) { BLI_addtail(&mainlist, bfd->main); fd->mainlist = &mainlist; - BLI_strncpy(bfd->main->name, filepath, sizeof(bfd->main->name)); + STRNCPY(bfd->main->filepath, filepath); } if (G.background) { @@ -4384,23 +4333,11 @@ static void expand_id(BlendExpander *expander, ID *id) expand_id_embedded_id(expander, id); } -/** - * Set the callback func used over all ID data found by \a BLO_expand_main func. - * - * \param expand_doit_func: Called for each ID block it finds. - */ void BLO_main_expander(BLOExpandDoitCallback expand_doit_func) { expand_doit = expand_doit_func; } -/** - * Loop over all ID data in Main to mark relations. - * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding. - * - * \param fdhandle: usually filedata, or own handle. - * \param mainvar: the Main database to expand. - */ void BLO_expand_main(void *fdhandle, Main *mainvar) { ListBase *lbarray[INDEX_ID_MAX]; @@ -4441,290 +4378,6 @@ void BLO_expand_main(void *fdhandle, Main *mainvar) /** \name Library Linking (helper functions) * \{ */ -static bool object_in_any_scene(Main *bmain, Object *ob) -{ - LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { - if (BKE_scene_object_find(sce, ob)) { - return true; - } - } - - return false; -} - -static bool object_in_any_collection(Main *bmain, Object *ob) -{ - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - if (BKE_collection_has_object(collection, ob)) { - return true; - } - } - - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - if (scene->master_collection != NULL && - BKE_collection_has_object(scene->master_collection, ob)) { - return true; - } - } - - return false; -} - -/** - * Shared operations to perform on the object's base after adding it to the scene. - */ -static void object_base_instance_init( - Object *ob, ViewLayer *view_layer, const View3D *v3d, const int flag, bool set_active) -{ - Base *base = BKE_view_layer_base_find(view_layer, ob); - - if (v3d != NULL) { - base->local_view_bits |= v3d->local_view_uuid; - } - - if (flag & FILE_AUTOSELECT) { - /* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */ - BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK)); - if (base->flag & BASE_SELECTABLE) { - base->flag |= BASE_SELECTED; - } - } - - if (set_active) { - view_layer->basact = base; - } - - BKE_scene_object_base_flag_sync_from_base(base); -} - -/** - * Exported for link/append to create objects as well. - */ -void BLO_object_instantiate_object_base_instance_init(Main *bmain, - Collection *collection, - Object *ob, - ViewLayer *view_layer, - const View3D *v3d, - const int flag, - bool set_active) -{ - /* Auto-select and appending. */ - if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) { - /* While in general the object should not be manipulated, - * when the user requests the object to be selected, ensure it's visible and selectable. */ - ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT); - } - - BKE_collection_object_add(bmain, collection, ob); - - object_base_instance_init(ob, view_layer, v3d, flag, set_active); -} - -static void add_loose_objects_to_scene(Main *mainvar, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d, - Library *lib, - const int flag) -{ - Collection *active_collection = NULL; - const bool do_append = (flag & FILE_LINK) == 0; - - BLI_assert(scene); - - /* Give all objects which are LIB_TAG_INDIRECT a base, - * or for a collection when *lib has been set. */ - LISTBASE_FOREACH (Object *, ob, &mainvar->objects) { - /* NOTE: Even if this is a directly linked object and is tagged for instantiation, it might - * have already been instantiated through one of its owner collections, in which case we do not - * want to re-instantiate it in the active collection here. */ - bool do_it = (ob->id.tag & LIB_TAG_DOIT) != 0 && !BKE_scene_object_find(scene, ob); - if (do_it || - ((ob->id.tag & LIB_TAG_INDIRECT) != 0 && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0)) { - if (do_append) { - if (ob->id.us == 0) { - do_it = true; - } - else if ((ob->id.lib == lib) && !object_in_any_collection(bmain, ob)) { - /* When appending, make sure any indirectly loaded object gets a base, - * when they are not part of any collection yet. */ - do_it = true; - } - } - - if (do_it) { - /* Find or add collection as needed. */ - if (active_collection == NULL) { - if (flag & FILE_ACTIVE_COLLECTION) { - LayerCollection *lc = BKE_layer_collection_get_active(view_layer); - active_collection = lc->collection; - } - else { - active_collection = BKE_collection_add(bmain, scene->master_collection, NULL); - } - } - - CLAMP_MIN(ob->id.us, 0); - ob->mode = OB_MODE_OBJECT; - - /* Do NOT make base active here! screws up GUI stuff, - * if you want it do it at the editor level. */ - const bool set_active = false; - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, flag, set_active); - - ob->id.tag &= ~LIB_TAG_INDIRECT; - ob->id.flag &= ~LIB_INDIRECT_WEAK_LINK; - ob->id.tag |= LIB_TAG_EXTERN; - } - } - } -} - -static void add_loose_object_data_to_scene(Main *mainvar, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d, - const int flag) -{ - if ((flag & BLO_LIBLINK_OBDATA_INSTANCE) == 0) { - return; - } - - Collection *active_collection = scene->master_collection; - if (flag & FILE_ACTIVE_COLLECTION) { - LayerCollection *lc = BKE_layer_collection_get_active(view_layer); - active_collection = lc->collection; - } - - /* Do not re-instantiate obdata IDs that are already instantiated by an object. */ - LISTBASE_FOREACH (Object *, ob, &mainvar->objects) { - if ((ob->id.tag & LIB_TAG_PRE_EXISTING) == 0 && ob->data != NULL) { - ID *obdata = ob->data; - BLI_assert(ID_REAL_USERS(obdata) > 0); - if ((obdata->tag & LIB_TAG_PRE_EXISTING) == 0) { - obdata->tag &= ~LIB_TAG_DOIT; - } - } - } - - /* Loop over all ID types, instancing object-data for ID types that have support for it. */ - ListBase *lbarray[INDEX_ID_MAX]; - int i = set_listbasepointers(mainvar, lbarray); - while (i--) { - const short idcode = BKE_idtype_idcode_from_index(i); - if (!OB_DATA_SUPPORT_ID(idcode)) { - continue; - } - - LISTBASE_FOREACH (ID *, id, lbarray[i]) { - if (id->tag & LIB_TAG_DOIT) { - const int type = BKE_object_obdata_to_type(id); - BLI_assert(type != -1); - Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2); - ob->data = id; - id_us_plus(id); - BKE_object_materials_test(bmain, ob, ob->data); - - /* Do NOT make base active here! screws up GUI stuff, - * if you want it do it at the editor level. */ - bool set_active = false; - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, flag, set_active); - - copy_v3_v3(ob->loc, scene->cursor.location); - } - } - } -} - -static void add_collections_to_scene(Main *mainvar, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d, - Library *lib, - const int flag) -{ - Collection *active_collection = scene->master_collection; - if (flag & FILE_ACTIVE_COLLECTION) { - LayerCollection *lc = BKE_layer_collection_get_active(view_layer); - active_collection = lc->collection; - } - - /* Give all objects which are tagged a base. */ - LISTBASE_FOREACH (Collection *, collection, &mainvar->collections) { - if ((flag & BLO_LIBLINK_COLLECTION_INSTANCE) && (collection->id.tag & LIB_TAG_DOIT)) { - /* Any indirect collection should not have been tagged. */ - BLI_assert((collection->id.tag & LIB_TAG_INDIRECT) == 0); - - /* BKE_object_add(...) messes with the selection. */ - Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2); - ob->type = OB_EMPTY; - ob->empty_drawsize = U.collection_instance_empty_size; - - const bool set_selected = (flag & FILE_AUTOSELECT) != 0; - /* TODO: why is it OK to make this active here but not in other situations? - * See other callers of #object_base_instance_init */ - const bool set_active = set_selected; - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, flag, set_active); - - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); - - /* Assign the collection. */ - ob->instance_collection = collection; - id_us_plus(&collection->id); - ob->transflag |= OB_DUPLICOLLECTION; - copy_v3_v3(ob->loc, scene->cursor.location); - } - /* We do not want to force instantiation of indirectly linked collections, - * not even when appending. Users can now easily instantiate collections (and their objects) - * as needed by themselves. See T67032. */ - else if ((collection->id.tag & LIB_TAG_INDIRECT) == 0) { - bool do_add_collection = (collection->id.tag & LIB_TAG_DOIT) != 0; - if (!do_add_collection) { - /* We need to check that objects in that collections are already instantiated in a scene. - * Otherwise, it's better to add the collection to the scene's active collection, than to - * instantiate its objects in active scene's collection directly. See T61141. - * Note that we only check object directly into that collection, - * not recursively into its children. - */ - LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { - Object *ob = coll_ob->ob; - if ((ob->id.tag & (LIB_TAG_PRE_EXISTING | LIB_TAG_DOIT | LIB_TAG_INDIRECT)) == 0 && - (ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == false)) { - do_add_collection = true; - break; - } - } - } - if (do_add_collection) { - /* Add collection as child of active collection. */ - BKE_collection_child_add(bmain, active_collection, collection); - - if (flag & FILE_AUTOSELECT) { - LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { - Object *ob = coll_ob->ob; - Base *base = BKE_view_layer_base_find(view_layer, ob); - if (base) { - base->flag |= BASE_SELECTED; - BKE_scene_object_base_flag_sync_from_base(base); - } - } - } - - /* Those are kept for safety and consistency, but should not be needed anymore? */ - collection->id.tag &= ~LIB_TAG_INDIRECT; - collection->id.flag &= ~LIB_INDIRECT_WEAK_LINK; - collection->id.tag |= LIB_TAG_EXTERN; - } - } - } -} - /* returns true if the item was found * but it may already have already been appended/linked */ static ID *link_named_part( @@ -4774,75 +4427,9 @@ static ID *link_named_part( /* if we found the id but the id is NULL, this is really bad */ BLI_assert(!((bhead != NULL) && (id == NULL))); - /* Tag as loose object (or data associated with objects) - * needing to be instantiated in #LibraryLink_Params.scene. */ - if ((id != NULL) && (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT)) { - if (library_link_idcode_needs_tag_check(idcode, flag)) { - id->tag |= LIB_TAG_DOIT; - } - } - return id; } -/** - * Simple reader for copy/paste buffers. - */ -int BLO_library_link_copypaste(Main *mainl, BlendHandle *bh, const uint64_t id_types_mask) -{ - FileData *fd = (FileData *)(bh); - BHead *bhead; - int num_directly_linked = 0; - - for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { - ID *id = NULL; - - if (bhead->code == ENDB) { - break; - } - - if (blo_bhead_is_id_valid_type(bhead) && BKE_idtype_idcode_is_linkable((short)bhead->code) && - (id_types_mask == 0 || - (BKE_idtype_idcode_to_idfilter((short)bhead->code) & id_types_mask) != 0)) { - read_libblock(fd, mainl, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_EXTERN, false, &id); - num_directly_linked++; - } - - if (id) { - /* sort by name in list */ - ListBase *lb = which_libbase(mainl, GS(id->name)); - id_sort_by_name(lb, id, NULL); - - /* Tag as loose object (or data associated with objects) - * needing to be instantiated (see also #link_named_part and its usage of - * #BLO_LIBLINK_NEEDS_ID_TAG_DOIT above). */ - if (library_link_idcode_needs_tag_check(GS(id->name), BLO_LIBLINK_NEEDS_ID_TAG_DOIT)) { - id->tag |= LIB_TAG_DOIT; - } - - if (bhead->code == ID_OB) { - /* Instead of instancing Base's directly, postpone until after collections are loaded - * otherwise the base's flag is set incorrectly when collections are used */ - Object *ob = (Object *)id; - ob->mode = OB_MODE_OBJECT; - /* ensure add_loose_objects_to_scene runs on this object */ - BLI_assert(id->us == 0); - } - } - } - - return num_directly_linked; -} - -/** - * Link a named data-block from an external blend file. - * - * \param mainl: The main database to link from (not the active one). - * \param bh: The blender file handle. - * \param idcode: The kind of data-block to link. - * \param name: The name of the data-block (without the 2 char ID prefix). - * \return the linked ID when found. - */ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, @@ -4855,41 +4442,10 @@ ID *BLO_library_link_named_part(Main *mainl, /* common routine to append/link something from a library */ -/** - * Checks if the \a idcode needs to be tagged with #LIB_TAG_DOIT when linking/appending. - */ -static bool library_link_idcode_needs_tag_check(const short idcode, const int flag) -{ - if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) { - /* Always true because of #add_loose_objects_to_scene & #add_collections_to_scene. */ - if (ELEM(idcode, ID_OB, ID_GR)) { - return true; - } - if (flag & BLO_LIBLINK_OBDATA_INSTANCE) { - if (OB_DATA_SUPPORT_ID(idcode)) { - return true; - } - } - } - return false; -} - -/** - * Clears #LIB_TAG_DOIT based on the result of #library_link_idcode_needs_tag_check. - */ -static void library_link_clear_tag(Main *mainvar, const int flag) -{ - for (int i = 0; i < INDEX_ID_MAX; i++) { - const short idcode = BKE_idtype_idcode_from_index(i); - BLI_assert(idcode != -1); - if (library_link_idcode_needs_tag_check(idcode, flag)) { - BKE_main_id_tag_idcode(mainvar, idcode, LIB_TAG_DOIT, false); - } - } -} - -static Main *library_link_begin( - Main *mainvar, FileData **fd, const char *filepath, const int flag, const int id_tag_extra) +static Main *library_link_begin(Main *mainvar, + FileData **fd, + const char *filepath, + const int id_tag_extra) { Main *mainl; @@ -4902,11 +4458,6 @@ static Main *library_link_begin( (*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist"); - if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) { - /* Clear for objects and collections instantiating tag. */ - library_link_clear_tag(mainvar, flag); - } - /* make mains */ blo_split_main((*fd)->mainlist, mainvar); @@ -4945,30 +4496,18 @@ void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params { BLO_library_link_params_init(params, bmain, flag, id_tag_extra); if (scene != NULL) { - /* Tagging is needed for instancing. */ - params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT; - params->context.scene = scene; params->context.view_layer = view_layer; params->context.v3d = v3d; } } -/** - * Initialize the #BlendHandle for linking library data. - * - * \param bh: A blender file handle as returned by - * #BLO_blendhandle_from_file or #BLO_blendhandle_from_memory. - * \param filepath: Used for relative linking, copied to the `lib->filepath`. - * \param params: Settings for linking that don't change from beginning to end of linking. - * \return the library #Main, to be passed to #BLO_library_link_named_part as \a mainl. - */ Main *BLO_library_link_begin(BlendHandle **bh, const char *filepath, const struct LibraryLink_Params *params) { FileData *fd = (FileData *)(*bh); - return library_link_begin(params->bmain, &fd, filepath, params->flag, params->id_tag_extra); + return library_link_begin(params->bmain, &fd, filepath, params->id_tag_extra); } static void split_main_newid(Main *mainptr, Main *main_newid) @@ -4976,7 +4515,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid) /* We only copy the necessary subset of data in this temp main. */ main_newid->versionfile = mainptr->versionfile; main_newid->subversionfile = mainptr->subversionfile; - BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name)); + STRNCPY(main_newid->filepath, mainptr->filepath); main_newid->curlib = mainptr->curlib; ListBase *lbarray[INDEX_ID_MAX]; @@ -4995,19 +4534,7 @@ static void split_main_newid(Main *mainptr, Main *main_newid) } } -/** - * \param scene: The scene in which to instantiate objects/collections - * (if NULL, no instantiation is done). - * \param v3d: The active 3D viewport. - * (only to define active layers for instantiated objects & collections, can be NULL). - */ -static void library_link_end(Main *mainl, - FileData **fd, - Main *bmain, - const int flag, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) +static void library_link_end(Main *mainl, FileData **fd, const int flag) { Main *mainvar; Library *curlib; @@ -5092,22 +4619,6 @@ static void library_link_end(Main *mainl, /* Make all relative paths, relative to the open blend file. */ fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar); - /* Give a base to loose objects and collections. - * Only directly linked objects & collections are instantiated by - * #BLO_library_link_named_part & co, - * here we handle indirect ones and other possible edge-cases. */ - if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) { - /* Should always be true. */ - if (scene != NULL) { - add_collections_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag); - add_loose_objects_to_scene(mainvar, bmain, scene, view_layer, v3d, curlib, flag); - add_loose_object_data_to_scene(mainvar, bmain, scene, view_layer, v3d, flag); - } - - /* Clear objects and collections instantiating tag. */ - library_link_clear_tag(mainvar, flag); - } - /* patch to prevent switch_endian happens twice */ if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) { blo_filedata_free(*fd); @@ -5115,25 +4626,10 @@ static void library_link_end(Main *mainl, } } -/** - * Finalize linking from a given .blend file (library). - * Optionally instance the indirect object/collection in the scene when the flags are set. - * \note Do not use \a bh after calling this function, it may frees it. - * - * \param mainl: The main database to link from (not the active one). - * \param bh: The blender file handle (WARNING! may be freed by this function!). - * \param params: Settings for linking that don't change from beginning to end of linking. - */ void BLO_library_link_end(Main *mainl, BlendHandle **bh, const struct LibraryLink_Params *params) { FileData *fd = (FileData *)(*bh); - library_link_end(mainl, - &fd, - params->bmain, - params->flag, - params->context.scene, - params->context.view_layer, - params->context.v3d); + library_link_end(mainl, &fd, params->flag); *bh = (BlendHandle *)fd; } @@ -5485,11 +4981,6 @@ bool BLO_read_requires_endian_switch(BlendDataReader *reader) return (reader->fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0; } -/** - * Updates all ->prev and ->next pointers of the list elements. - * Updates the list->first and list->last pointers. - * When not NULL, calls the callback on every element. - */ void BLO_read_list_cb(BlendDataReader *reader, ListBase *list, BlendReadListFn callback) { if (BLI_listbase_is_empty(list)) { diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 75152a05063..3b5be3dd013 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -131,6 +131,11 @@ void blo_split_main(ListBase *mainlist, struct Main *main); BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath); +/** + * On each new library added, it now checks for the current #FileData and expands relativeness + * + * cannot be called with relative paths anymore! + */ FileData *blo_filedata_from_file(const char *filepath, struct BlendFileReadReport *reports); FileData *blo_filedata_from_memory(const void *mem, int memsize, @@ -139,10 +144,28 @@ FileData *blo_filedata_from_memfile(struct MemFile *memfile, const struct BlendFileReadParams *params, struct BlendFileReadReport *reports); +/** + * Lib linked proxy objects point to our local data, we need + * to clear that pointer before reading the undo memfile since + * the object might be removed, it is set again in reading + * if the local object still exists. + * This is only valid for local proxy objects though, linked ones should not be affected here. + */ void blo_clear_proxy_pointers_from_lib(struct Main *oldmain); void blo_make_packed_pointer_map(FileData *fd, struct Main *oldmain); +/** + * Set old main packed data to zero if it has been restored + * this works because freeing old main only happens after this call. + */ void blo_end_packed_pointer_map(FileData *fd, struct Main *oldmain); +/** + * Undo file support: add all library pointers in lookup. + */ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd); +/** + * Build a #GSet of old main (we only care about local data here, + * so we can do that after #blo_split_main() call. + */ void blo_make_old_idmap_from_main(FileData *fd, struct Main *bmain); BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, struct AssetMetaData **r_asset_data); @@ -157,23 +180,48 @@ BHead *blo_bhead_first(FileData *fd); BHead *blo_bhead_next(FileData *fd, BHead *thisblock); BHead *blo_bhead_prev(FileData *fd, BHead *thisblock); +/** + * Warning! Caller's responsibility to ensure given bhead **is** an ID one! + */ const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead); +/** + * Warning! Caller's responsibility to ensure given bhead **is** an ID one! + */ struct AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead); /* do versions stuff */ +/** + * Manipulates SDNA before calling #DNA_struct_get_compareflags, + * allowing us to rename structs and struct members. + * + * - This means older versions of Blender won't have access to this data **USE WITH CARE**. + * - These changes are applied on file load (run-time), similar to versioning for compatibility. + * + * \attention ONLY USE THIS KIND OF VERSIONING WHEN `dna_rename_defs.h` ISN'T SUFFICIENT. + */ void blo_do_versions_dna(struct SDNA *sdna, const int versionfile, const int subversionfile); void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, const void *oldaddr, void *newaddr, int nr); +/** + * Only library data. + */ void *blo_do_versions_newlibadr(struct FileData *fd, const void *lib, const void *adr); void *blo_do_versions_newlibadr_us(struct FileData *fd, const void *lib, const void *adr); +/** + * \note this version patch is intended for versions < 2.52.2, + * but was initially introduced in 2.27 already. + */ void blo_do_version_old_trackto_to_constraints(struct Object *ob); void blo_do_versions_key_uidgen(struct Key *key); +/** + * Patching #UserDef struct and Themes. + */ void blo_do_versions_userdef(struct UserDef *userdef); void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *bmain); @@ -193,6 +241,10 @@ void do_versions_after_linking_290(struct Main *bmain, struct ReportList *report void do_versions_after_linking_300(struct Main *bmain, struct ReportList *reports); void do_versions_after_linking_cycles(struct Main *bmain); -/* This is rather unfortunate to have to expose this here, but better use that nasty hack in - * do_version than readfile itself. */ +/** + * Direct data-blocks with global linking. + * + * \note This is rather unfortunate to have to expose this here, + * but better use that nasty hack in do_version than readfile itself. + */ void *blo_read_get_new_globaldata_address(struct FileData *fd, const void *adr); diff --git a/source/blender/blenloader/intern/readfile_tempload.c b/source/blender/blenloader/intern/readfile_tempload.c index 1b1cbb29ef5..311732adf99 100644 --- a/source/blender/blenloader/intern/readfile_tempload.c +++ b/source/blender/blenloader/intern/readfile_tempload.c @@ -39,7 +39,7 @@ TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main, temp_lib_ctx->bf_reports.reports = reports; /* Copy the file path so any path remapping is performed properly. */ - STRNCPY(temp_lib_ctx->bmain_base->name, real_main->name); + STRNCPY(temp_lib_ctx->bmain_base->filepath, real_main->filepath); temp_lib_ctx->blendhandle = BLO_blendhandle_from_file(blend_file_path, &temp_lib_ctx->bf_reports); diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c index 62072cf7df5..dfa6135dac9 100644 --- a/source/blender/blenloader/intern/undofile.c +++ b/source/blender/blenloader/intern/undofile.c @@ -55,7 +55,6 @@ /* **************** support for memory-write, for undo buffers *************** */ -/* not memfile itself */ void BLO_memfile_free(MemFile *memfile) { MemFileChunk *chunk; @@ -69,8 +68,6 @@ void BLO_memfile_free(MemFile *memfile) memfile->size = 0; } -/* to keep list of memfiles consistent, 'first' is always first in list */ -/* result is that 'first' is being freed */ void BLO_memfile_merge(MemFile *first, MemFile *second) { /* We use this mapping to store the memory buffers from second memfile chunks which are not owned @@ -106,7 +103,6 @@ void BLO_memfile_merge(MemFile *first, MemFile *second) BLO_memfile_free(first); } -/* Clear is_identical_future before adding next memfile. */ void BLO_memfile_clear_future(MemFile *memfile) { LISTBASE_FOREACH (MemFileChunk *, chunk, &memfile->chunks) { @@ -216,11 +212,6 @@ struct Main *BLO_memfile_main_get(struct MemFile *memfile, return bmain_undo; } -/** - * Saves .blend using undo buffer. - * - * \return success. - */ bool BLO_memfile_write_file(struct MemFile *memfile, const char *filename) { MemFileChunk *chunk; diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index c4d04392cba..8a22fd07c24 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -1892,7 +1892,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) for (cu = bmain->curves.first; cu; cu = cu->id.next) { if (cu->flag & (CU_FRONT | CU_BACK)) { - if (cu->ext1 != 0.0f || cu->ext2 != 0.0f) { + if (cu->extrude != 0.0f || cu->bevel_radius != 0.0f) { Nurb *nu; for (nu = cu->nurb.first; nu; nu = nu->next) { diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 125f3be0dd1..7a7f12a7e58 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -1321,13 +1321,16 @@ static void version_liboverride_rnacollections_insertion_object_constraints( opop->subitem_local_name, offsetof(bConstraint, name), opop->subitem_local_index); - if (constraint_anchor == NULL || constraint_anchor->next == NULL) { + bConstraint *constraint_src = constraint_anchor != NULL ? constraint_anchor->next : + constraints->first; + + if (constraint_src == NULL) { /* Invalid case, just remove that override property operation. */ - CLOG_ERROR(&LOG, "Could not find anchor or source constraints in stored override data"); + CLOG_ERROR(&LOG, "Could not find source constraint in stored override data"); BKE_lib_override_library_property_operation_delete(op, opop); continue; } - bConstraint *constraint_src = constraint_anchor->next; + opop->subitem_reference_name = opop->subitem_local_name; opop->subitem_local_name = BLI_strdup(constraint_src->name); opop->subitem_reference_index = opop->subitem_local_index; @@ -1350,13 +1353,15 @@ static void version_liboverride_rnacollections_insertion_object(Object *object) opop->subitem_local_name, offsetof(ModifierData, name), opop->subitem_local_index); - if (mod_anchor == NULL || mod_anchor->next == NULL) { + ModifierData *mod_src = mod_anchor != NULL ? mod_anchor->next : object->modifiers.first; + + if (mod_src == NULL) { /* Invalid case, just remove that override property operation. */ - CLOG_ERROR(&LOG, "Could not find anchor or source modifiers in stored override data"); + CLOG_ERROR(&LOG, "Could not find source modifier in stored override data"); BKE_lib_override_library_property_operation_delete(op, opop); continue; } - ModifierData *mod_src = mod_anchor->next; + opop->subitem_reference_name = opop->subitem_local_name; opop->subitem_local_name = BLI_strdup(mod_src->name); opop->subitem_reference_index = opop->subitem_local_index; @@ -1375,13 +1380,17 @@ static void version_liboverride_rnacollections_insertion_object(Object *object) opop->subitem_local_name, offsetof(GpencilModifierData, name), opop->subitem_local_index); - if (gp_mod_anchor == NULL || gp_mod_anchor->next == NULL) { + GpencilModifierData *gp_mod_src = gp_mod_anchor != NULL ? + gp_mod_anchor->next : + object->greasepencil_modifiers.first; + + if (gp_mod_src == NULL) { /* Invalid case, just remove that override property operation. */ - CLOG_ERROR(&LOG, "Could not find anchor GP modifier in stored override data"); + CLOG_ERROR(&LOG, "Could not find source GP modifier in stored override data"); BKE_lib_override_library_property_operation_delete(op, opop); continue; } - GpencilModifierData *gp_mod_src = gp_mod_anchor->next; + opop->subitem_reference_name = opop->subitem_local_name; opop->subitem_local_name = BLI_strdup(gp_mod_src->name); opop->subitem_reference_index = opop->subitem_local_index; @@ -2182,7 +2191,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) if (ntree->type != NTREE_GEOMETRY) { continue; } - version_node_id(ntree, FN_NODE_COMPARE_FLOATS, "FunctionNodeCompareFloats"); + version_node_id(ntree, FN_NODE_COMPARE, "FunctionNodeCompareFloats"); version_node_id(ntree, GEO_NODE_CAPTURE_ATTRIBUTE, "GeometryNodeCaptureAttribute"); version_node_id(ntree, GEO_NODE_MESH_BOOLEAN, "GeometryNodeMeshBoolean"); version_node_id(ntree, GEO_NODE_FILL_CURVE, "GeometryNodeFillCurve"); @@ -2367,8 +2376,8 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /* Special case to handle older in-dev 3.1 files, before change from 3.0 branch gets merged in - * master. */ + /* Special case to handle older in-development 3.1 files, before change from 3.0 branch gets + * merged in master. */ if (!MAIN_VERSION_ATLEAST(bmain, 300, 42) || (bmain->versionfile == 301 && !MAIN_VERSION_ATLEAST(bmain, 301, 3))) { /* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers, @@ -2385,6 +2394,60 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) FOREACH_MAIN_ID_END; } + if (!MAIN_VERSION_ATLEAST(bmain, 301, 4)) { + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + if (ntree->type != NTREE_GEOMETRY) { + continue; + } + version_node_id(ntree, GEO_NODE_CURVE_SPLINE_PARAMETER, "GeometryNodeSplineParameter"); + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == GEO_NODE_CURVE_SPLINE_PARAMETER) { + version_node_add_socket_if_not_exist( + ntree, node, SOCK_OUT, SOCK_INT, PROP_NONE, "Index", "Index"); + } + + /* Convert float compare into a more general compare node. */ + if (node->type == FN_NODE_COMPARE) { + if (node->storage == NULL) { + NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN( + sizeof(NodeFunctionCompare), __func__); + data->data_type = SOCK_FLOAT; + data->operation = node->custom1; + strcpy(node->idname, "FunctionNodeCompare"); + node->update = NODE_UPDATE; + node->storage = data; + } + } + } + } + + /* Add a toggle for the breadcrumbs overlay in the node editor. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) { + if (space->spacetype == SPACE_NODE) { + SpaceNode *snode = (SpaceNode *)space; + snode->overlay.flag |= SN_OVERLAY_SHOW_PATH; + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) { + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + if (ntree->type != NTREE_GEOMETRY) { + continue; + } + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type != GEO_NODE_REALIZE_INSTANCES) { + continue; + } + node->custom1 |= GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR; + } + } + } + /** * Versioning code until next subversion bump goes here. * @@ -2396,5 +2459,21 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + /* Add node storage for map range node. */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == SH_NODE_MAP_RANGE) { + if (node->storage == NULL) { + NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__); + data->clamp = node->custom1; + data->data_type = CD_PROP_FLOAT; + data->interpolation_type = node->custom2; + node->storage = data; + } + } + } + } + FOREACH_NODETREE_END; } } diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc index af765be619f..3deaaa040d6 100644 --- a/source/blender/blenloader/intern/versioning_common.cc +++ b/source/blender/blenloader/intern/versioning_common.cc @@ -61,11 +61,6 @@ ARegion *do_versions_add_region_if_not_found(ListBase *regionbase, return new_region; } -/** - * Rename if the ID doesn't exist. - * - * \return the ID (if found). - */ ID *do_versions_rename_id(Main *bmain, const short id_type, const char *name_src, @@ -104,9 +99,6 @@ static void change_node_socket_name(ListBase *sockets, const char *old_name, con } } -/** - * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used. - */ void version_node_socket_id_delim(bNodeSocket *socket) { StringRef name = socket->name; @@ -165,9 +157,21 @@ void version_node_output_socket_name(bNodeTree *ntree, } } -/** - * Replace the ID name of all nodes in the tree with the given type with the new name. - */ +bNodeSocket *version_node_add_socket_if_not_exist(bNodeTree *ntree, + bNode *node, + eNodeSocketInOut in_out, + int type, + int subtype, + const char *identifier, + const char *name) +{ + bNodeSocket *sock = nodeFindSocket(node, in_out, identifier); + if (sock != nullptr) { + return sock; + } + return nodeAddStaticSocket(ntree, node, in_out, type, subtype, identifier, name); +} + void version_node_id(bNodeTree *ntree, const int node_type, const char *new_name) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -179,23 +183,6 @@ void version_node_id(bNodeTree *ntree, const int node_type, const char *new_name } } -/** - * Adjust animation data for newly added node sockets. - * - * Node sockets are addressed by their index (in their RNA path, and thus FCurves/drivers), and - * thus when a new node is added in the middle of the list, existing animation data needs to be - * adjusted. - * - * Since this is about animation data, it only concerns input sockets. - * - * \param node_tree_type node tree type that has these nodes, for example NTREE_SHADER. - * \param node_type node type to adjust, for example SH_NODE_BSDF_PRINCIPLED. - * \param socket_index_orig the original index of the moved socket; when socket 4 moved to 6, - * pass 4 here. - * \param socket_index_offset the offset of the nodes, so when socket 4 moved to 6, - * pass 2 here. - * \param total_number_of_sockets the total number of sockets in the node. - */ void version_node_socket_index_animdata(Main *bmain, const int node_tree_type, const int node_type, diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h index 7f179800ddd..0613484b754 100644 --- a/source/blender/blenloader/intern/versioning_common.h +++ b/source/blender/blenloader/intern/versioning_common.h @@ -34,6 +34,11 @@ struct ARegion *do_versions_add_region_if_not_found(struct ListBase *regionbase, const char *name, int link_after_region_type); +/** + * Rename if the ID doesn't exist. + * + * \return the ID (if found). + */ ID *do_versions_rename_id(Main *bmain, const short id_type, const char *name_src, @@ -52,6 +57,23 @@ void version_node_output_socket_name(struct bNodeTree *ntree, const char *old_name, const char *new_name); +/** + * Adjust animation data for newly added node sockets. + * + * Node sockets are addressed by their index (in their RNA path, and thus FCurves/drivers), and + * thus when a new node is added in the middle of the list, existing animation data needs to be + * adjusted. + * + * Since this is about animation data, it only concerns input sockets. + * + * \param node_tree_type: Node tree type that has these nodes, for example #NTREE_SHADER. + * \param node_type: Node type to adjust, for example #SH_NODE_BSDF_PRINCIPLED. + * \param socket_index_orig: The original index of the moved socket; when socket 4 moved to 6, + * pass 4 here. + * \param socket_index_offset: The offset of the nodes, so when socket 4 moved to 6, + * pass 2 here. + * \param total_number_of_sockets: The total number of sockets in the node. + */ void version_node_socket_index_animdata( Main *bmain, int node_tree_type, /* NTREE_....., e.g. NTREE_SHADER */ @@ -60,10 +82,24 @@ void version_node_socket_index_animdata( int socket_index_offset, int total_number_of_sockets); +/** + * Replace the ID name of all nodes in the tree with the given type with the new name. + */ void version_node_id(struct bNodeTree *ntree, const int node_type, const char *new_name); +/** + * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used. + */ void version_node_socket_id_delim(bNodeSocket *socket); +struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree, + struct bNode *node, + eNodeSocketInOut in_out, + int type, + int subtype, + const char *identifier, + const char *name); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index fa61b1ca6cd..a5c44ea711b 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -367,15 +367,6 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) } } -/** - * Update defaults in startup.blend, without having to save and embed the file. - * This function can be emptied each time the startup.blend is updated. - * - * \note Screen data may be cleared at this point, this will happen in the case - * an app-template's data needs to be versioned when read-file is called with "Load UI" disabled. - * Versioning the screen data can be safely skipped without "Load UI" since the screen data - * will have been versioned when it was first loaded. - */ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) { /* For all app templates. */ diff --git a/source/blender/blenloader/intern/versioning_dna.c b/source/blender/blenloader/intern/versioning_dna.c index aee54b94833..0a97eedb993 100644 --- a/source/blender/blenloader/intern/versioning_dna.c +++ b/source/blender/blenloader/intern/versioning_dna.c @@ -29,16 +29,6 @@ #include "BLO_readfile.h" #include "readfile.h" -/** - * Manipulates SDNA before calling #DNA_struct_get_compareflags, - * allowing us to rename structs and struct members. - * - * - This means older versions of Blender won't have access to this data **USE WITH CARE**. - * - * - These changes are applied on file load (run-time), similar to versioning for compatibility. - * - * \attention ONLY USE THIS KIND OF VERSIONING WHEN `dna_rename_defs.h` ISN'T SUFFICIENT. - */ void blo_do_versions_dna(SDNA *sdna, const int versionfile, const int subversionfile) { #define DNA_VERSION_ATLEAST(ver, subver) \ diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 37bf4898cb3..2fceb42262e 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -461,8 +461,6 @@ static void do_version_constraints_245(ListBase *lb) } } -/* NOTE: this version patch is intended for versions < 2.52.2, - * but was initially introduced in 2.27 already. */ void blo_do_version_old_trackto_to_constraints(Object *ob) { /* create new trackto constraint from the relationship */ diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 0e5e0b76f43..3338d2f658c 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -399,7 +399,6 @@ static bool keymap_item_has_invalid_wm_context_data_path(wmKeyMapItem *kmi, return false; } -/* patching UserDef struct and Themes */ void blo_do_versions_userdef(UserDef *userdef) { /* #UserDef & #Main happen to have the same struct member. */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 56ff7151cb1..aa3eef4b475 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -50,7 +50,7 @@ * Almost all data in Blender are structures. Each struct saved * gets a BHead header. With BHead the struct can be linked again * and compared with #StructDNA. - + * * WRITE * ===== * @@ -1028,7 +1028,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) /* prevent mem checkers from complaining */ memset(fg._pad, 0, sizeof(fg._pad)); - memset(fg.filename, 0, sizeof(fg.filename)); + memset(fg.filepath, 0, sizeof(fg.filepath)); memset(fg.build_hash, 0, sizeof(fg.build_hash)); fg._pad1 = NULL; @@ -1045,7 +1045,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) fg.globalf = G.f; /* Write information needed for recovery. */ if (fileflags & G_FILE_RECOVER_WRITE) { - BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename)); + STRNCPY(fg.filepath, mainvar->filepath); } sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION); memcpy(fg.subvstr, subvstr, 4); @@ -1312,15 +1312,15 @@ static bool do_history(const char *name, ReportList *reports) /** \name File Writing (Public) * \{ */ -/** - * \return Success. - */ bool BLO_write_file(Main *mainvar, const char *filepath, const int write_flags, const struct BlendFileWriteParams *params, ReportList *reports) { + BLI_assert(!BLI_path_is_rel(filepath)); + BLI_assert(BLI_path_is_abs_from_cwd(filepath)); + char tempname[FILE_MAX + 1]; WriteWrap ww; @@ -1329,10 +1329,12 @@ bool BLO_write_file(Main *mainvar, const bool use_save_as_copy = params->use_save_as_copy; const bool use_userdef = params->use_userdef; const BlendThumbnail *thumb = params->thumb; + const bool relbase_valid = (mainvar->filepath[0] != '\0'); /* path backup/restore */ 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) { BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* save to disk"); @@ -1351,35 +1353,47 @@ bool BLO_write_file(Main *mainvar, return 0; } + if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) { + /* Paths will already be absolute, no remapping to do. */ + if (relbase_valid == false) { + remap_mode = BLO_WRITE_PATH_REMAP_NONE; + } + } + /* Remapping of relative paths to new file location. */ if (remap_mode != BLO_WRITE_PATH_REMAP_NONE) { if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) { - /* Make all relative as none of the existing paths can be relative in an unsaved document. - */ - if (G.relbase_valid == false) { + /* Make all relative as none of the existing paths can be relative in an unsaved document. */ + if (relbase_valid == false) { remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE_ALL; } } + /* The source path only makes sense to set if the file was saved (`relbase_valid`). */ char dir_src[FILE_MAX]; char dir_dst[FILE_MAX]; - BLI_split_dir_part(mainvar->name, dir_src, sizeof(dir_src)); - BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst)); - /* Just in case there is some subtle difference. */ - BLI_path_normalize(mainvar->name, dir_dst); - BLI_path_normalize(mainvar->name, dir_src); + /* Normalize the paths in case there is some subtle difference (so they can be compared). */ + if (relbase_valid) { + BLI_split_dir_part(mainvar->filepath, dir_src, sizeof(dir_src)); + BLI_path_normalize(NULL, dir_src); + } + else { + dir_src[0] = '\0'; + } + BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst)); + BLI_path_normalize(NULL, dir_dst); /* Only for relative, not relative-all, as this means making existing paths relative. */ if (remap_mode == BLO_WRITE_PATH_REMAP_RELATIVE) { - if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) { + if (relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) { /* Saved to same path. Nothing to do. */ remap_mode = BLO_WRITE_PATH_REMAP_NONE; } } else if (remap_mode == BLO_WRITE_PATH_REMAP_ABSOLUTE) { - if (G.relbase_valid == false) { + if (relbase_valid == false) { /* Unsaved, all paths are absolute.Even if the user manages to set a relative path, * there is no base-path that can be used to make it absolute. */ remap_mode = BLO_WRITE_PATH_REMAP_NONE; @@ -1395,6 +1409,7 @@ bool BLO_write_file(Main *mainvar, switch (remap_mode) { case BLO_WRITE_PATH_REMAP_RELATIVE: /* Saved, make relative paths relative to new location (if possible). */ + BLI_assert(relbase_valid); BKE_bpath_relative_rebase(mainvar, dir_src, dir_dst, NULL); break; case BLO_WRITE_PATH_REMAP_RELATIVE_ALL: @@ -1403,6 +1418,7 @@ bool BLO_write_file(Main *mainvar, break; case BLO_WRITE_PATH_REMAP_ABSOLUTE: /* Make all absolute (when requested or unsaved). */ + BLI_assert(relbase_valid); BKE_bpath_absolute_convert(mainvar, dir_src, NULL); break; case BLO_WRITE_PATH_REMAP_NONE: @@ -1452,9 +1468,6 @@ bool BLO_write_file(Main *mainvar, return 1; } -/** - * \return Success. - */ bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags) { bool use_userdef = false; @@ -1577,9 +1590,6 @@ void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr BLO_write_raw(writer, sizeof(float[3]) * (size_t)num, data_ptr); } -/** - * Write a null terminated string. - */ void BLO_write_string(BlendWriter *writer, const char *data_ptr) { if (data_ptr != NULL) { @@ -1587,10 +1597,6 @@ void BLO_write_string(BlendWriter *writer, const char *data_ptr) } } -/** - * Sometimes different data is written depending on whether the file is saved to disk or used for - * undo. This function returns true when the current file-writing is done for undo. - */ bool BLO_write_is_undo(BlendWriter *writer) { return writer->wd->use_memfile; |