tornavis/source/blender/asset_system/AS_asset_library.hh

237 lines
9.8 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup asset_system
*/
#pragma once
#include <memory>
#include "AS_asset_catalog.hh"
#include "DNA_asset_types.h"
#include "BLI_set.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
#include "BKE_callbacks.h"
struct AssetLibrary;
struct IDRemapper;
struct Main;
namespace blender::asset_system {
class AssetIdentifier;
class AssetRepresentation;
class AssetStorage;
/**
* AssetLibrary provides access to an asset library's data.
*
* The asset library contains catalogs and storage for asset representations. It could be extended
* to also include asset indexes and more.
*/
class AssetLibrary {
eAssetLibraryType library_type_;
/**
* The name this asset library will be displayed in the UI as. Will also be used as a weak way
* to identify an asset library (e.g. by #AssetWeakReference).
*/
std::string name_;
/** If this is an asset library on disk, the top-level directory path. Normalized using
* #normalize_directory_path(). Shared pointer so assets can safely point to it, and don't have
* to hold a copy (which is the size of `std::string` + the allocated buffer, if no short string
* optimization is used). With thousands of assets this might make a reasonable difference. */
std::shared_ptr<std::string> root_path_;
/**
* 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.
*/
std::unique_ptr<AssetStorage> asset_storage_;
std::function<void(AssetLibrary &self)> on_refresh_;
std::optional<eAssetImportMethod> import_method_;
/** Assets owned by this library may be imported with a different method than set in
* #import_method_ above, it's just a default. */
bool may_override_import_method_ = false;
bool use_relative_path_ = true;
bCallbackFuncStore on_save_callback_store_{};
public:
/* Controlled by #ED_asset_catalogs_set_save_catalogs_when_file_is_saved,
* for managing the "Save Catalog Changes" in the quit-confirmation dialog box. */
static bool save_catalogs_when_file_is_saved;
std::unique_ptr<AssetCatalogService> catalog_service;
friend class AssetLibraryService;
friend class AssetRepresentation;
public:
/**
* \param name: The name this asset library will be displayed in the UI as. Will also be used as
* a weak way to identify an asset library (e.g. by #AssetWeakReference). Make sure
* this is set for any custom (not builtin) asset library. That is,
* #ASSET_LIBRARY_CUSTOM ones.
* \param root_path: If this is an asset library on disk, the top-level directory path.
*/
AssetLibrary(eAssetLibraryType library_type, StringRef name = "", StringRef root_path = "");
~AssetLibrary();
/**
* Execute \a fn for every asset library that is loaded. The asset library is passed to the
* \a fn call.
*
* \param skip_all_library: When true, the \a fn will also be executed for the "All" asset
* library. This is just a combination of the other ones, so usually
* iterating over it is redundant.
*/
static void foreach_loaded(FunctionRef<void(AssetLibrary &)> fn, bool include_all_library);
void load_catalogs();
/** 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).
*
* \param relative_asset_path: The path of the asset relative to the asset library root. With
* this the asset must be uniquely identifiable within the asset
* library.
*/
AssetRepresentation &add_external_asset(StringRef relative_asset_path,
StringRef name,
int id_type,
std::unique_ptr<AssetMetaData> metadata);
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_local_id_asset(StringRef relative_asset_path, ID &id);
/**
* Remove an asset from the library that was added using #add_external_asset() or
* #add_local_id_asset(). Can usually be expected to be constant time complexity (worst case may
* differ).
* \note This is save to call if \a asset is freed (dangling reference), will not perform any
* change then.
* \return True on success, false if the asset couldn't be found inside the library (also the
* case when the reference is dangling).
*/
bool remove_asset(AssetRepresentation &asset);
/**
* Remap ID pointers for local ID assets, see #BKE_lib_remap.h. When an ID pointer would be
* mapped to null (typically when an ID gets removed), the asset is removed, because we don't
* support such empty/null assets.
*/
void remap_ids_and_remove_invalid(const IDRemapper &mappings);
/**
* 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
* catalog definition file is corrupt/lost" scenario that the simple name is
* meant to help recover from.
*/
void refresh_catalog_simplename(AssetMetaData *asset_data);
void on_blend_save_handler_register();
void on_blend_save_handler_unregister();
void on_blend_save_post(Main *bmain, PointerRNA **pointers, int num_pointers);
/**
* Create an asset identifier from the root path of this asset library and the given relative
* asset path (relative to the asset library root directory).
*/
AssetIdentifier asset_identifier_from_library(StringRef relative_asset_path);
std::string resolve_asset_weak_reference_to_full_path(const AssetWeakReference &asset_reference);
eAssetLibraryType library_type() const;
StringRefNull name() const;
StringRefNull root_path() const;
};
Vector<AssetLibraryReference> all_valid_asset_library_refs();
AssetLibraryReference all_library_reference();
} // namespace blender::asset_system
/**
* Load the data for an asset library, but not the asset representations themselves (loading these
* is currently not done in the asset system).
*
* For the "All" asset library (#ASSET_LIBRARY_ALL), every other known asset library will be
* loaded as well. So a call to #AssetLibrary::foreach_loaded() can be expected to iterate over all
* libraries.
*
* \warning Catalogs are reloaded, invalidating catalog pointers. Do not store catalog pointers,
* store CatalogIDs instead and lookup the catalog where needed.
*/
blender::asset_system::AssetLibrary *AS_asset_library_load(
const Main *bmain, const AssetLibraryReference &library_reference);
std::string AS_asset_library_root_path_from_library_ref(
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 AS_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
* #AS_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 AS_asset_library_find_suitable_root_path_from_main(const Main *bmain);
blender::asset_system::AssetCatalogService *AS_asset_library_get_catalog_service(
const ::AssetLibrary *library);
blender::asset_system::AssetCatalogTree *AS_asset_library_get_catalog_tree(
const ::AssetLibrary *library);