diff options
Diffstat (limited to 'source/blender/blenkernel')
21 files changed, 500 insertions, 154 deletions
diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h index 81b520a1db0..bcbe19c0f3e 100644 --- a/source/blender/blenkernel/BKE_asset.h +++ b/source/blender/blenkernel/BKE_asset.h @@ -23,6 +23,9 @@ struct ID; struct IDProperty; struct PreviewImage; +/** C handle for #bke::AssetRepresentation. */ +typedef struct AssetRepresentation AssetRepresentation; + typedef void (*PreSaveFn)(void *asset_ptr, struct AssetMetaData *asset_data); typedef struct AssetTypeInfo { @@ -68,6 +71,22 @@ struct PreviewImage *BKE_asset_metadata_preview_get_from_id(const struct AssetMe void BKE_asset_metadata_write(struct BlendWriter *writer, struct AssetMetaData *asset_data); void BKE_asset_metadata_read(struct BlendDataReader *reader, struct AssetMetaData *asset_data); +const char *BKE_asset_representation_name_get(const AssetRepresentation *asset) + ATTR_WARN_UNUSED_RESULT; +AssetMetaData *BKE_asset_representation_metadata_get(const AssetRepresentation *asset) + ATTR_WARN_UNUSED_RESULT; +bool BKE_asset_representation_is_local_id(const AssetRepresentation *asset) + ATTR_WARN_UNUSED_RESULT; + #ifdef __cplusplus } #endif + +#ifdef __cplusplus + +# include <memory> + +[[nodiscard]] std::unique_ptr<AssetMetaData> BKE_asset_metadata_move_to_unique_ptr( + AssetMetaData *asset_data); + +#endif diff --git a/source/blender/blenkernel/BKE_asset_library.h b/source/blender/blenkernel/BKE_asset_library.h index 824bc24203d..fc648ff6976 100644 --- a/source/blender/blenkernel/BKE_asset_library.h +++ b/source/blender/blenkernel/BKE_asset_library.h @@ -6,6 +6,7 @@ #pragma once +struct IDRemapper; struct Main; #ifdef __cplusplus @@ -24,41 +25,6 @@ typedef struct AssetLibrary AssetLibrary; */ struct AssetLibrary *BKE_asset_library_load(const char *library_path); -/** - * Try to find an appropriate location for an asset library root from a file or directory path. - * Does not check if \a input_path exists. - * - * The design is made to find an appropriate asset library path from a .blend file path, but - * technically works with any file or directory as \a input_path. - * Design is: - * * If \a input_path lies within a known asset library path (i.e. an asset library registered in - * the Preferences), return the asset library path. - * * Otherwise, if \a input_path has a parent path, return the parent path (e.g. to use the - * directory a .blend file is in as asset library root). - * * If \a input_path is empty or doesn't have a parent path (e.g. because a .blend wasn't saved - * yet), there is no suitable path. The caller has to decide how to handle this case. - * - * \param r_library_path: The returned asset library path with a trailing slash, or an empty string - * if no suitable path is found. Assumed to be a buffer of at least - * #FILE_MAXDIR bytes. - * - * \return True if the function could find a valid, that is, a non-empty path to return in \a - * r_library_path. - */ -bool BKE_asset_library_find_suitable_root_path_from_path( - const char *input_path, char r_library_path[768 /* FILE_MAXDIR */]); -/** - * Uses the current location on disk of the file represented by \a bmain as input to - * #BKE_asset_library_find_suitable_root_path_from_path(). Refer to it for a design - * description. - * - * \return True if the function could find a valid, that is, a non-empty path to return in \a - * r_library_path. If \a bmain wasn't saved into a file yet, the return value will be - * false. - */ -bool BKE_asset_library_find_suitable_root_path_from_main( - const struct Main *bmain, char r_library_path[768 /* FILE_MAXDIR */]); - /** Look up the asset's catalog and copy its simple name into #asset_data. */ void BKE_asset_library_refresh_catalog_simplename(struct AssetLibrary *asset_library, struct AssetMetaData *asset_data); @@ -66,6 +32,10 @@ void BKE_asset_library_refresh_catalog_simplename(struct AssetLibrary *asset_lib /** Return whether any loaded AssetLibrary has unsaved changes to its catalogs. */ bool BKE_asset_library_has_any_unsaved_catalogs(void); +/** An asset library can include local IDs (IDs in the current file). Their pointers need to be + * remapped on change (or assets removed as IDs gets removed). */ +void BKE_asset_library_remap_ids(struct IDRemapper *mappings); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_asset_library.hh b/source/blender/blenkernel/BKE_asset_library.hh index 2058df71f6a..f69847bd1ed 100644 --- a/source/blender/blenkernel/BKE_asset_library.hh +++ b/source/blender/blenkernel/BKE_asset_library.hh @@ -12,6 +12,9 @@ #include "DNA_asset_types.h" +#include "BLI_string_ref.hh" +#include "BLI_vector.hh" + #include "BKE_asset_library.h" #include "BKE_asset_catalog.hh" @@ -19,11 +22,18 @@ #include <memory> +struct AssetLibraryReference; +struct Main; + namespace blender::bke { +class AssetRepresentation; + /** * AssetLibrary provides access to an asset library's data. - * For now this is only for catalogs, later this can be expanded to indexes/caches/more. + * + * The asset library contains catalogs and storage for asset representations. It could be extended + * to also include asset indexes and more. */ struct AssetLibrary { /* Controlled by #ED_asset_catalogs_set_save_catalogs_when_file_is_saved, @@ -35,12 +45,25 @@ struct AssetLibrary { AssetLibrary(); ~AssetLibrary(); - void load(StringRefNull library_root_directory); + void load_catalogs(StringRefNull library_root_directory); /** Load catalogs that have changed on disk. */ void refresh(); /** + * Create a representation of an asset to be considered part of this library. Once the + * representation is not needed anymore, it must be freed using #remove_asset(), or there will be + * leaking that's only cleared when the library storage is destructed (typically on exit or + * loading a different file). + */ + AssetRepresentation &add_external_asset(StringRef name, std::unique_ptr<AssetMetaData> metadata); + AssetRepresentation &add_local_id_asset(ID &id); + /** Remove an asset from the library that was added using #add_external_asset() or + * #add_local_id_asset(). + * \return True on success, false if the asset couldn't be found inside the library. */ + bool remove_asset(AssetRepresentation &asset); + + /** * Update `catalog_simple_name` by looking up the asset's catalog by its ID. * * No-op if the catalog cannot be found. This could be the kind of "the @@ -53,8 +76,27 @@ struct AssetLibrary { void on_blend_save_post(Main *bmain, PointerRNA **pointers, int num_pointers); + void remap_ids(struct IDRemapper &mappings); + private: bCallbackFuncStore on_save_callback_store_{}; + + /** Storage for assets (better said their representations) that are considered to be part of this + * library. Assets are not automatically loaded into this when loading an asset library. Assets + * have to be loaded externally and added to this storage via #add_external_asset() or + * #add_local_id_asset(). So this really is arbitrary storage as far as #AssetLibrary is + * concerned (allowing the API user to manage partial library storage and partial loading, so + * only relevant parts of a library are kept in memory). + * + * For now, multiple parts of Blender just keep adding their own assets to this storage. E.g. + * multiple asset browsers might load multiple representations for the same asset into this. + * Currently there is just no way to properly identify assets, or keep track of which assets are + * already in memory and which not. Neither do we keep track of how many parts of Blender are + * using an asset or an asset library, which is needed to know when assets can be freed. + */ + Vector<std::unique_ptr<AssetRepresentation>> asset_storage_; + + std::optional<int> find_asset_index(const AssetRepresentation &asset); }; Vector<AssetLibraryReference> all_valid_asset_library_refs(); @@ -64,6 +106,40 @@ Vector<AssetLibraryReference> all_valid_asset_library_refs(); blender::bke::AssetLibrary *BKE_asset_library_load(const Main *bmain, const AssetLibraryReference &library_reference); +/** + * Try to find an appropriate location for an asset library root from a file or directory path. + * Does not check if \a input_path exists. + * + * The design is made to find an appropriate asset library path from a .blend file path, but + * technically works with any file or directory as \a input_path. + * Design is: + * * If \a input_path lies within a known asset library path (i.e. an asset library registered in + * the Preferences), return the asset library path. + * * Otherwise, if \a input_path has a parent path, return the parent path (e.g. to use the + * directory a .blend file is in as asset library root). + * * If \a input_path is empty or doesn't have a parent path (e.g. because a .blend wasn't saved + * yet), there is no suitable path. The caller has to decide how to handle this case. + * + * \param r_library_path: The returned asset library path with a trailing slash, or an empty string + * if no suitable path is found. Assumed to be a buffer of at least + * #FILE_MAXDIR bytes. + * + * \return True if the function could find a valid, that is, a non-empty path to return in \a + * r_library_path. + */ +std::string BKE_asset_library_find_suitable_root_path_from_path(blender::StringRefNull input_path); + +/** + * Uses the current location on disk of the file represented by \a bmain as input to + * #BKE_asset_library_find_suitable_root_path_from_path(). Refer to it for a design + * description. + * + * \return True if the function could find a valid, that is, a non-empty path to return in \a + * r_library_path. If \a bmain wasn't saved into a file yet, the return value will be + * false. + */ +std::string BKE_asset_library_find_suitable_root_path_from_main(const struct Main *bmain); + blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service( const ::AssetLibrary *library); blender::bke::AssetCatalogTree *BKE_asset_library_get_catalog_tree(const ::AssetLibrary *library); diff --git a/source/blender/blenkernel/BKE_asset_representation.hh b/source/blender/blenkernel/BKE_asset_representation.hh new file mode 100644 index 00000000000..edaa5a203ba --- /dev/null +++ b/source/blender/blenkernel/BKE_asset_representation.hh @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bke + */ + +#pragma once + +#include <memory> +#include <string> + +#include "BLI_string_ref.hh" + +struct AssetMetaData; +struct ID; + +namespace blender::bke { + +/** + * \brief Abstraction to reference an asset, with necessary data for display & interaction. + * + * https://wiki.blender.org/wiki/Source/Architecture/Asset_System/Back_End#Asset_Representation + */ +class AssetRepresentation { + friend struct AssetLibrary; + + struct ExternalAsset { + std::string name; + std::unique_ptr<AssetMetaData> metadata_ = nullptr; + }; + + /** Indicate if this is a local or external asset, and as such, which of the union members below + * should be used. */ + const bool is_local_id_ = false; + + union { + ExternalAsset external_asset_; + ID *local_asset_id_ = nullptr; /* Non-owning. */ + }; + + public: + /** Constructs an asset representation for an external ID. The asset will not be editable. */ + explicit AssetRepresentation(StringRef name, std::unique_ptr<AssetMetaData> metadata); + /** Constructs an asset representation for an ID stored in the current file. This makes the asset + * local and fully editable. */ + explicit AssetRepresentation(ID &id); + AssetRepresentation(AssetRepresentation &&other); + /* Non-copyable type. */ + AssetRepresentation(const AssetRepresentation &other) = delete; + ~AssetRepresentation(); + + /* Non-move-assignable type. Move construction is fine, but treat the "identity" (e.g. local vs + * external asset) of an asset representation as immutable. */ + AssetRepresentation &operator=(AssetRepresentation &&other) = delete; + /* Non-copyable type. */ + AssetRepresentation &operator=(const AssetRepresentation &other) = delete; + + StringRefNull get_name() const; + AssetMetaData &get_metadata() const; + /** Returns if this asset is stored inside this current file, and as such fully editable. */ + bool is_local_id() const; +}; + +} // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index a797aef73f6..05b9aca7544 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -291,7 +291,11 @@ void psys_set_current_num(struct Object *ob, int index); /* UNUSED */ // struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys); -struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim); +/** + * Initialize/free data for particle simulation evaluation. + */ +void psys_sim_data_init(struct ParticleSimulationData *sim); +void psys_sim_data_free(struct ParticleSimulationData *sim); /** * For a given evaluated particle system get its original. @@ -416,7 +420,7 @@ void psys_get_particle_on_path(struct ParticleSimulationData *sim, struct ParticleKey *state, bool vel); /** - * Gets particle's state at a time. + * Gets particle's state at a time. Must call psys_sim_data_init before this. * \return true if particle exists and can be seen and false if not. */ bool psys_get_particle_state(struct ParticleSimulationData *sim, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 7d43fa7e6af..462ccc19601 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -75,6 +75,7 @@ set(SRC intern/asset_catalog_path.cc intern/asset_library.cc intern/asset_library_service.cc + intern/asset_representation.cc intern/attribute.cc intern/attribute_access.cc intern/attribute_math.cc @@ -324,6 +325,7 @@ set(SRC BKE_asset_catalog_path.hh BKE_asset_library.h BKE_asset_library.hh + BKE_asset_representation.hh BKE_attribute.h BKE_attribute.hh BKE_attribute_math.hh diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc index 67802b1d6b4..7103e017847 100644 --- a/source/blender/blenkernel/intern/asset.cc +++ b/source/blender/blenkernel/intern/asset.cc @@ -27,21 +27,31 @@ using namespace blender; AssetMetaData *BKE_asset_metadata_create() { - AssetMetaData *asset_data = (AssetMetaData *)MEM_callocN(sizeof(*asset_data), __func__); - memcpy(asset_data, DNA_struct_default_get(AssetMetaData), sizeof(*asset_data)); - return asset_data; + const AssetMetaData *default_metadata = DNA_struct_default_get(AssetMetaData); + return MEM_new<AssetMetaData>(__func__, *default_metadata); } void BKE_asset_metadata_free(AssetMetaData **asset_data) { - if ((*asset_data)->properties) { - IDP_FreeProperty((*asset_data)->properties); + (*asset_data)->~AssetMetaData(); + MEM_SAFE_FREE(*asset_data); +} + +AssetMetaData::~AssetMetaData() +{ + if (properties) { + IDP_FreeProperty(properties); } - MEM_SAFE_FREE((*asset_data)->author); - MEM_SAFE_FREE((*asset_data)->description); - BLI_freelistN(&(*asset_data)->tags); + MEM_SAFE_FREE(author); + MEM_SAFE_FREE(description); + BLI_freelistN(&tags); +} - MEM_SAFE_FREE(*asset_data); +std::unique_ptr<AssetMetaData> BKE_asset_metadata_move_to_unique_ptr(AssetMetaData *asset_data) +{ + std::unique_ptr unique_asset_data = std::make_unique<AssetMetaData>(*asset_data); + *asset_data = *DNA_struct_default_get(AssetMetaData); + return unique_asset_data; } static AssetTag *asset_metadata_tag_add(AssetMetaData *asset_data, const char *const name) diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index 62d03b2d79b..a9fe59eba64 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -508,14 +508,13 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing( "catalog definition file should be put"); /* Ask the asset library API for an appropriate location. */ - char suitable_root_path[PATH_MAX]; - const bool asset_lib_root_found = BKE_asset_library_find_suitable_root_path_from_path( - blend_file_path.c_str(), suitable_root_path); - if (asset_lib_root_found) { + const std::string suitable_root_path = BKE_asset_library_find_suitable_root_path_from_path( + blend_file_path); + if (!suitable_root_path.empty()) { char asset_lib_cdf_path[PATH_MAX]; BLI_path_join(asset_lib_cdf_path, sizeof(asset_lib_cdf_path), - suitable_root_path, + suitable_root_path.c_str(), DEFAULT_CATALOG_FILENAME.c_str()); return asset_lib_cdf_path; } diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc index b8420af1168..4dccee425c6 100644 --- a/source/blender/blenkernel/intern/asset_library.cc +++ b/source/blender/blenkernel/intern/asset_library.cc @@ -7,11 +7,14 @@ #include <memory> #include "BKE_asset_library.hh" +#include "BKE_asset_representation.hh" +#include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_preferences.h" #include "BLI_fileops.h" #include "BLI_path_util.h" +#include "BLI_set.hh" #include "DNA_asset_types.h" #include "DNA_userdef_types.h" @@ -50,22 +53,22 @@ bool BKE_asset_library_has_any_unsaved_catalogs() return service->has_any_unsaved_catalogs(); } -bool BKE_asset_library_find_suitable_root_path_from_path(const char *input_path, - char *r_library_path) +std::string BKE_asset_library_find_suitable_root_path_from_path( + const blender::StringRefNull input_path) { if (bUserAssetLibrary *preferences_lib = BKE_preferences_asset_library_containing_path( - &U, input_path)) { - BLI_strncpy(r_library_path, preferences_lib->path, FILE_MAXDIR); - return true; + &U, input_path.c_str())) { + return preferences_lib->path; } - BLI_split_dir_part(input_path, r_library_path, FILE_MAXDIR); - return r_library_path[0] != '\0'; + char buffer[FILE_MAXDIR]; + BLI_split_dir_part(input_path.c_str(), buffer, FILE_MAXDIR); + return buffer; } -bool BKE_asset_library_find_suitable_root_path_from_main(const Main *bmain, char *r_library_path) +std::string BKE_asset_library_find_suitable_root_path_from_main(const Main *bmain) { - return BKE_asset_library_find_suitable_root_path_from_path(bmain->filepath, r_library_path); + return BKE_asset_library_find_suitable_root_path_from_path(bmain->filepath); } blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service( @@ -98,6 +101,13 @@ void BKE_asset_library_refresh_catalog_simplename(struct AssetLibrary *asset_lib lib->refresh_catalog_simplename(asset_data); } +void BKE_asset_library_remap_ids(IDRemapper *mappings) +{ + blender::bke::AssetLibraryService *service = blender::bke::AssetLibraryService::get(); + service->foreach_loaded_asset_library( + [mappings](blender::bke::AssetLibrary &library) { library.remap_ids(*mappings); }); +} + namespace blender::bke { AssetLibrary::AssetLibrary() : catalog_service(std::make_unique<AssetCatalogService>()) @@ -111,7 +121,7 @@ AssetLibrary::~AssetLibrary() } } -void AssetLibrary::load(StringRefNull library_root_directory) +void AssetLibrary::load_catalogs(StringRefNull library_root_directory) { auto catalog_service = std::make_unique<AssetCatalogService>(library_root_directory); catalog_service->load_from_disk(); @@ -123,6 +133,44 @@ void AssetLibrary::refresh() this->catalog_service->reload_catalogs(); } +AssetRepresentation &AssetLibrary::add_external_asset(StringRef name, + std::unique_ptr<AssetMetaData> metadata) +{ + asset_storage_.append(std::make_unique<AssetRepresentation>(name, std::move(metadata))); + return *asset_storage_.last(); +} + +AssetRepresentation &AssetLibrary::add_local_id_asset(ID &id) +{ + asset_storage_.append(std::make_unique<AssetRepresentation>(id)); + return *asset_storage_.last(); +} + +std::optional<int> AssetLibrary::find_asset_index(const AssetRepresentation &asset) +{ + int index = 0; + /* Find index of asset. */ + for (auto &asset_uptr : asset_storage_) { + if (&asset == asset_uptr.get()) { + return index; + } + index++; + } + + return {}; +} + +bool AssetLibrary::remove_asset(AssetRepresentation &asset) +{ + std::optional<int> asset_index = find_asset_index(asset); + if (!asset_index) { + return false; + } + + asset_storage_.remove_and_reorder(*asset_index); + return true; +} + namespace { void asset_library_on_save_post(struct Main *main, struct PointerRNA **pointers, @@ -166,6 +214,28 @@ void AssetLibrary::on_blend_save_post(struct Main *main, } } +void AssetLibrary::remap_ids(IDRemapper &mappings) +{ + Set<AssetRepresentation *> removed_id_assets; + + for (auto &asset_uptr : asset_storage_) { + if (!asset_uptr->is_local_id()) { + continue; + } + + IDRemapperApplyResult result = BKE_id_remapper_apply( + &mappings, &asset_uptr->local_asset_id_, ID_REMAP_APPLY_DEFAULT); + if (result == ID_REMAP_RESULT_SOURCE_UNASSIGNED) { + removed_id_assets.add(asset_uptr.get()); + } + } + + /* Remove the assets from storage. */ + for (AssetRepresentation *asset : removed_id_assets) { + remove_asset(*asset); + } +} + void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data) { if (BLI_uuid_is_nil(asset_data->catalog_id)) { diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc index cd8de7908bf..35441b9b795 100644 --- a/source/blender/blenkernel/intern/asset_library_service.cc +++ b/source/blender/blenkernel/intern/asset_library_service.cc @@ -6,6 +6,7 @@ #include "asset_library_service.hh" +#include "BKE_asset_library.hh" #include "BKE_blender.h" #include "BKE_preferences.h" @@ -47,15 +48,10 @@ AssetLibrary *AssetLibraryService::get_asset_library( { if (library_reference.type == ASSET_LIBRARY_LOCAL) { /* For the "Current File" library we get the asset library root path based on main. */ - char root_path[FILE_MAX]; - if (bmain) { - BKE_asset_library_find_suitable_root_path_from_main(bmain, root_path); - } - else { - root_path[0] = '\0'; - } + std::string root_path = bmain ? BKE_asset_library_find_suitable_root_path_from_main(bmain) : + ""; - if (root_path[0] == '\0') { + if (root_path.empty()) { /* File wasn't saved yet. */ return get_asset_library_current_file(); } @@ -104,7 +100,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(StringRefNull top_l AssetLibrary *lib = lib_uptr.get(); lib->on_blend_save_handler_register(); - lib->load(top_dir_trailing_slash); + lib->load_catalogs(top_dir_trailing_slash); on_disk_libraries_.add_new(top_dir_trailing_slash, std::move(lib_uptr)); CLOG_INFO(&LOG, 2, "get \"%s\" (loaded)", top_dir_trailing_slash.c_str()); @@ -180,4 +176,15 @@ bool AssetLibraryService::has_any_unsaved_catalogs() const return false; } +void AssetLibraryService::foreach_loaded_asset_library(FunctionRef<void(AssetLibrary &)> fn) const +{ + if (current_file_library_) { + fn(*current_file_library_); + } + + for (const auto &asset_lib_uptr : on_disk_libraries_.values()) { + fn(*asset_lib_uptr); + } +} + } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/asset_library_service.hh b/source/blender/blenkernel/intern/asset_library_service.hh index c22c6b182ce..6caaea72875 100644 --- a/source/blender/blenkernel/intern/asset_library_service.hh +++ b/source/blender/blenkernel/intern/asset_library_service.hh @@ -12,10 +12,13 @@ #include "BKE_asset_library.hh" +#include "BLI_function_ref.hh" #include "BLI_map.hh" #include <memory> +struct AssetLibraryReference; + namespace blender::bke { /** @@ -58,11 +61,16 @@ class AssetLibraryService { /** Returns whether there are any known asset libraries with unsaved catalog edits. */ bool has_any_unsaved_catalogs() const; + void foreach_loaded_asset_library(FunctionRef<void(AssetLibrary &)> fn) const; + protected: static std::unique_ptr<AssetLibraryService> instance_; /* Mapping absolute path of the library's top-level directory to the AssetLibrary instance. */ Map<std::string, AssetLibraryPtr> on_disk_libraries_; + /** Library without a known path, i.e. the "Current File" library if the file isn't saved yet. If + * the file was saved, a valid path for the library can be determined and #on_disk_libraries_ + * above should be used. */ AssetLibraryPtr current_file_library_; /* Handlers for managing the life cycle of the AssetLibraryService instance. */ diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc index 7952e7ea3b0..18fdcb80155 100644 --- a/source/blender/blenkernel/intern/asset_library_service_test.cc +++ b/source/blender/blenkernel/intern/asset_library_service_test.cc @@ -8,6 +8,9 @@ #include "BKE_appdir.h" #include "BKE_callbacks.h" +#include "BKE_main.h" + +#include "DNA_asset_types.h" #include "CLG_log.h" @@ -102,6 +105,26 @@ TEST_F(AssetLibraryServiceTest, library_pointers) * cannot be reliably tested by just pointer comparison, though. */ } +TEST_F(AssetLibraryServiceTest, library_from_reference) +{ + AssetLibraryService *service = AssetLibraryService::get(); + AssetLibrary *const lib = service->get_asset_library_on_disk(asset_library_root_); + AssetLibrary *const curfile_lib = service->get_asset_library_current_file(); + + AssetLibraryReference ref{}; + ref.type = ASSET_LIBRARY_LOCAL; + EXPECT_EQ(curfile_lib, service->get_asset_library(nullptr, ref)) + << "Getting the local (current file) reference without a main saved on disk should return " + "the current file library"; + + Main dummy_main{}; + std::string dummy_filepath = asset_library_root_ + SEP + "dummy.blend"; + BLI_strncpy(dummy_main.filepath, dummy_filepath.c_str(), sizeof(dummy_main.filepath)); + EXPECT_EQ(lib, service->get_asset_library(&dummy_main, ref)) + << "Getting the local (current file) reference with a main saved on disk should return " + "the an asset library for this directory"; +} + TEST_F(AssetLibraryServiceTest, library_path_trailing_slashes) { AssetLibraryService *service = AssetLibraryService::get(); diff --git a/source/blender/blenkernel/intern/asset_representation.cc b/source/blender/blenkernel/intern/asset_representation.cc new file mode 100644 index 00000000000..bbaa634d5ad --- /dev/null +++ b/source/blender/blenkernel/intern/asset_representation.cc @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bke + */ + +#include <stdexcept> + +#include "DNA_ID.h" +#include "DNA_asset_types.h" + +#include "BKE_asset.h" +#include "BKE_asset_representation.hh" + +namespace blender::bke { + +AssetRepresentation::AssetRepresentation(StringRef name, std::unique_ptr<AssetMetaData> metadata) + : is_local_id_(false), external_asset_() +{ + external_asset_.name = name; + external_asset_.metadata_ = std::move(metadata); +} + +AssetRepresentation::AssetRepresentation(ID &id) : is_local_id_(true), local_asset_id_(&id) +{ + if (!id.asset_data) { + throw std::invalid_argument("Passed ID is not an asset"); + } +} + +AssetRepresentation::AssetRepresentation(AssetRepresentation &&other) + : is_local_id_(other.is_local_id_) +{ + if (is_local_id_) { + local_asset_id_ = other.local_asset_id_; + other.local_asset_id_ = nullptr; + } + else { + external_asset_ = std::move(other.external_asset_); + } +} + +AssetRepresentation::~AssetRepresentation() +{ + if (!is_local_id_) { + external_asset_.~ExternalAsset(); + } +} + +StringRefNull AssetRepresentation::get_name() const +{ + if (is_local_id_) { + return local_asset_id_->name + 2; + } + + return external_asset_.name; +} + +AssetMetaData &AssetRepresentation::get_metadata() const +{ + return is_local_id_ ? *local_asset_id_->asset_data : *external_asset_.metadata_; +} + +bool AssetRepresentation::is_local_id() const +{ + return is_local_id_; +} + +} // namespace blender::bke + +/* ---------------------------------------------------------------------- */ +/** \name C-API + * \{ */ + +using namespace blender; + +const char *BKE_asset_representation_name_get(const AssetRepresentation *asset_handle) +{ + const bke::AssetRepresentation *asset = reinterpret_cast<const bke::AssetRepresentation *>( + asset_handle); + return asset->get_name().c_str(); +} + +AssetMetaData *BKE_asset_representation_metadata_get(const AssetRepresentation *asset_handle) +{ + const bke::AssetRepresentation *asset = reinterpret_cast<const bke::AssetRepresentation *>( + asset_handle); + return &asset->get_metadata(); +} + +bool BKE_asset_representation_is_local_id(const AssetRepresentation *asset_handle) +{ + const bke::AssetRepresentation *asset = reinterpret_cast<const bke::AssetRepresentation *>( + asset_handle); + return asset->is_local_id(); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/asset_test.cc b/source/blender/blenkernel/intern/asset_test.cc index fa8769862a8..5ff65054926 100644 --- a/source/blender/blenkernel/intern/asset_test.cc +++ b/source/blender/blenkernel/intern/asset_test.cc @@ -13,7 +13,7 @@ namespace blender::bke::tests { TEST(AssetMetadataTest, set_catalog_id) { - AssetMetaData meta; + AssetMetaData meta{}; const bUUID uuid = BLI_uuid_generate_random(); /* Test trivial values. */ diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 1d6092849cc..0ddd53ccb99 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -1495,7 +1495,7 @@ AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid) * require returning a non-owning pointer, which we don't have in the Asset Browser (yet). */ FileDirEntry *file = (FileDirEntry *)CTX_data_pointer_get_type(C, "active_file", &RNA_FileSelectEntry).data; - if (file && file->asset_data) { + if (file && file->asset) { *r_is_valid = true; return (AssetHandle){.file_data = file}; } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index a3d2d73678c..c72f498cd5a 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -1532,18 +1532,8 @@ static void emit_from_particles(Object *flow_ob, sim.scene = scene; sim.ob = flow_ob; sim.psys = psys; - sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - /* prepare curvemapping tables */ - if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) { - BKE_curvemapping_changed_all(psys->part->clumpcurve); - } - if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) { - BKE_curvemapping_changed_all(psys->part->roughcurve); - } - if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) { - BKE_curvemapping_changed_all(psys->part->twistcurve); - } + psys_sim_data_init(&sim); /* initialize particle cache */ if (psys->part->type == PART_HAIR) { @@ -1684,6 +1674,8 @@ static void emit_from_particles(Object *flow_ob, if (particle_vel) { MEM_freeN(particle_vel); } + + psys_sim_data_free(&sim); } } diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index c7643c56212..92b34b9e1af 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -21,6 +21,7 @@ #include "BKE_anim_data.h" #include "BKE_asset.h" +#include "BKE_asset_library.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_key.h" @@ -137,16 +138,16 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i BKE_main_lock(bmain); } + struct IDRemapper *remapper = BKE_id_remapper_create(); + BKE_id_remapper_add(remapper, id, NULL); + if ((flag & LIB_ID_FREE_NO_UI_USER) == 0) { if (free_notifier_reference_cb) { free_notifier_reference_cb(id); } if (remap_editor_id_reference_cb) { - struct IDRemapper *remapper = BKE_id_remapper_create(); - BKE_id_remapper_add(remapper, id, NULL); remap_editor_id_reference_cb(remapper); - BKE_id_remapper_free(remapper); } } @@ -158,6 +159,9 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i } } + BKE_asset_library_remap_ids(remapper); + BKE_id_remapper_free(remapper); + BKE_libblock_free_data(id, (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0); if ((flag & LIB_ID_FREE_NO_MAIN) == 0) { diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 59530a6d6a6..796ed4f8316 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -653,38 +653,29 @@ Material **BKE_object_material_get_p(Object *ob, short act) /* if object cannot have material, (totcolp == NULL) */ totcolp = BKE_object_material_len_p(ob); - if (totcolp == NULL || ob->totcol == 0) { + if (totcolp == NULL || *totcolp == 0) { return NULL; } - /* return NULL for invalid 'act', can happen for mesh face indices */ - if (act > ob->totcol) { - return NULL; - } - if (act <= 0) { - if (act < 0) { - CLOG_ERROR(&LOG, "Negative material index!"); - } - return NULL; - } + /* Clamp to number of slots if index is out of range, same convention as used for rendering. */ + const int slot_index = clamp_i(act - 1, 0, *totcolp - 1); - if (ob->matbits && ob->matbits[act - 1]) { /* in object */ - ma_p = &ob->mat[act - 1]; + /* Fix inconsistency which may happen when library linked data reduces the number of + * slots but object was not updated. Ideally should be fixed elsewhere. */ + if (*totcolp < ob->totcol) { + ob->totcol = *totcolp; } - else { /* in data */ - - /* check for inconsistency */ - if (*totcolp < ob->totcol) { - ob->totcol = *totcolp; - } - if (act > ob->totcol) { - act = ob->totcol; - } + if (slot_index < ob->totcol && ob->matbits && ob->matbits[slot_index]) { + /* Use object material slot. */ + ma_p = &ob->mat[slot_index]; + } + else { + /* Use data material slot. */ matarar = BKE_object_material_array_p(ob); if (matarar && *matarar) { - ma_p = &(*matarar)[act - 1]; + ma_p = &(*matarar)[slot_index]; } else { ma_p = NULL; @@ -717,17 +708,17 @@ static ID *get_evaluated_object_data_with_materials(Object *ob) Material *BKE_object_material_get_eval(Object *ob, short act) { BLI_assert(DEG_is_evaluated_object(ob)); - const int slot_index = act - 1; - if (slot_index < 0) { - return NULL; - } ID *data = get_evaluated_object_data_with_materials(ob); const short *tot_slots_data_ptr = BKE_id_material_len_p(data); const int tot_slots_data = tot_slots_data_ptr ? *tot_slots_data_ptr : 0; - if (slot_index >= tot_slots_data) { + + if (tot_slots_data == 0) { return NULL; } + + /* Clamp to number of slots if index is out of range, same convention as used for rendering. */ + const int slot_index = clamp_i(act - 1, 0, tot_slots_data - 1); const int tot_slots_object = ob->totcol; Material ***materials_data_ptr = BKE_id_material_array_p(data); diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index a41f7c8bce4..5efd44c620b 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -1390,7 +1390,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem RNG *rng = BLI_rng_new_srandom(31415926u + uint(psys->seed)); - psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + psys_sim_data_init(&sim); /* Gather list of objects or single object. */ int totcollection = 0; @@ -1612,17 +1612,13 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem } BLI_rng_free(rng); + psys_sim_data_free(&sim); } /* Clean up. */ if (oblist) { MEM_freeN(oblist); } - - if (psys->lattice_deform_data) { - BKE_lattice_deform_data_destroy(psys->lattice_deform_data); - psys->lattice_deform_data = nullptr; - } } static void make_duplis_particles(const DupliContext *ctx) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 4a0a09bcf56..6a277295efd 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -684,10 +684,13 @@ void psys_set_current_num(Object *ob, int index) } } -struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData *sim) +void psys_sim_data_init(ParticleSimulationData *sim) { - struct LatticeDeformData *lattice_deform_data = NULL; + ParticleSystem *psys = sim->psys; + ParticleSettings *part = psys->part; + /* Prepare lattice deform. */ + psys->lattice_deform_data = NULL; if (psys_in_edit_mode(sim->depsgraph, sim->psys) == 0) { Object *lattice = NULL; ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys); @@ -699,19 +702,39 @@ struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData if (md->mode & mode) { LatticeModifierData *lmd = (LatticeModifierData *)md; lattice = lmd->object; - sim->psys->lattice_strength = lmd->strength; + psys->lattice_strength = lmd->strength; } break; } } if (lattice) { - lattice_deform_data = BKE_lattice_deform_data_create(lattice, NULL); + psys->lattice_deform_data = BKE_lattice_deform_data_create(lattice, NULL); } } - return lattice_deform_data; + /* Prepare curvemapping tables. */ + if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) { + BKE_curvemapping_init(part->clumpcurve); + } + if ((part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && part->roughcurve) { + BKE_curvemapping_init(part->roughcurve); + } + if ((part->child_flag & PART_CHILD_USE_TWIST_CURVE) && part->twistcurve) { + BKE_curvemapping_init(part->twistcurve); + } } + +void psys_sim_data_free(ParticleSimulationData *sim) +{ + ParticleSystem *psys = sim->psys; + + if (psys->lattice_deform_data) { + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; + } +} + void psys_disable_all(Object *ob) { ParticleSystem *psys = ob->particlesystem.first; @@ -2784,7 +2807,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ctx->cfra = cfra; ctx->editupdate = editupdate; - psys->lattice_deform_data = psys_create_lattice_deform_data(&ctx->sim); + psys_sim_data_init(&ctx->sim); /* cache all relevant vertex groups if they exist */ ctx->vg_length = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_LENGTH); @@ -3340,7 +3363,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re cache = psys->pathcache = psys_alloc_path_cache_buffers( &psys->pathcachebufs, totpart, segments + 1); - psys->lattice_deform_data = psys_create_lattice_deform_data(sim); + psys_sim_data_init(sim); ma = BKE_object_material_get(sim->ob, psys->part->omat); if (ma && (psys->part->draw_col == PART_DRAW_COL_MAT)) { copy_v3_v3(col, &ma->r); @@ -3507,10 +3530,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re psys->totcached = totpart; - if (psys->lattice_deform_data) { - BKE_lattice_deform_data_destroy(psys->lattice_deform_data); - psys->lattice_deform_data = NULL; - } + psys_sim_data_free(sim); if (vg_effector) { MEM_freeN(vg_effector); @@ -4867,6 +4887,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, } } } + bool psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *state, @@ -5225,7 +5246,7 @@ void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, Par sim.psys = psys; sim.psmd = psys_get_modifier(ob, psys); - psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + psys_sim_data_init(&sim); if (psys->lattice_deform_data) { ParticleData *pa = psys->particles; @@ -5246,12 +5267,11 @@ void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, Par } } - BKE_lattice_deform_data_destroy(psys->lattice_deform_data); - psys->lattice_deform_data = NULL; - /* protect the applied shape */ psys->flag |= PSYS_EDITED; } + + psys_sim_data_free(&sim); } /* Draw Engine */ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 72094f8cf04..d97a217a734 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -516,10 +516,7 @@ void psys_thread_context_free(ParticleThreadContext *ctx) MEM_freeN(ctx->vg_twist); } - if (ctx->sim.psys->lattice_deform_data) { - BKE_lattice_deform_data_destroy(ctx->sim.psys->lattice_deform_data); - ctx->sim.psys->lattice_deform_data = NULL; - } + psys_sim_data_free(&ctx->sim); /* distribution */ if (ctx->jit) { @@ -3557,12 +3554,12 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra)) invert_m4_m4(ob->world_to_object, ob->object_to_world); - psys->lattice_deform_data = psys_create_lattice_deform_data(sim); - if (psys->totpart == 0) { return; } + psys_sim_data_init(sim); + /* save new keys for elements if needed */ LOOP_PARTICLES { @@ -3596,6 +3593,8 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra)) zero_v3(root->co); } } + + psys_sim_data_free(sim); } /* Code for an adaptive time step based on the Courant-Friedrichs-Lewy @@ -4099,6 +4098,8 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_ disp = psys_get_current_display_percentage(psys, use_render_params); + psys_sim_data_init(sim); + LOOP_PARTICLES { psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra); @@ -4107,8 +4108,6 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_ pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1); } - psys->lattice_deform_data = psys_create_lattice_deform_data(sim); - dietime = pa->dietime; /* update alive status and push events */ @@ -4125,11 +4124,6 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_ pa->alive = PARS_ALIVE; } - if (psys->lattice_deform_data) { - BKE_lattice_deform_data_destroy(psys->lattice_deform_data); - psys->lattice_deform_data = NULL; - } - if (psys_frand(psys, p) > disp) { pa->flag |= PARS_NO_DISP; } @@ -4137,6 +4131,8 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_ pa->flag &= ~PARS_NO_DISP; } } + + psys_sim_data_free(sim); } static bool particles_has_flip(short parttype) @@ -4609,10 +4605,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_ update_children(sim, use_render_params); /* cleanup */ - if (psys->lattice_deform_data) { - BKE_lattice_deform_data_destroy(psys->lattice_deform_data); - psys->lattice_deform_data = NULL; - } + psys_sim_data_free(sim); } void psys_changed_type(Object *ob, ParticleSystem *psys) |