Asset System: New core type to represent assets (`AssetRepresenation`)

Introduces a new `AssetRepresentation` type, as a runtime only container
to hold asset information. It is supposed to become _the_ main way to
represent and refer to assets in the asset system, see T87235. It can
store things like the asset name, asset traits, preview and other asset
metadata.

Technical documentation:
https://wiki.blender.org/wiki/Source/Architecture/Asset_System/Back_End#Asset_Representation.

By introducing a proper asset representation type, we do an important
step away from the previous, non-optimal representation of assets as
files in the file browser backend, and towards the asset system as
backend. It should replace the temporary & hacky `AssetHandle` design in
the near future. Note that the loading of asset data still happens
through the file browser backend, check the linked to Wiki page for more
information on that.

As a side-effect, asset metadata isn't stored in file browser file
entries when browsing with link/append anymore. Don't think this was
ever used, but scripts may have accessed this. Can be brought back if
there's a need for it.
This commit is contained in:
Julian Eisel 2022-11-09 18:34:31 +01:00
parent 7395062480
commit 1efc94bb2f
Notes: blender-bot 2023-08-23 03:50:38 +02:00
Referenced by commit 1229b96652, Fix empty asset index files after bug in asset loading
Referenced by commit 6a7917162c, Fix asset index only generating empty entries since 1efc94bb2f
Referenced by commit 32757b2429, Fix uninitialized variable use in asset metadata test
Referenced by commit 95077549c1, Fix failure in recently added asset library tests
Referenced by issue #102778, Crash - Blender crashes if an assetbrowser editor has no asset library ref.
Referenced by issue #102610, Regression: Asset disappearing on refresh
Referenced by issue #102481, GN: Crash with Shift+A when using asset files with node groups in them
Referenced by issue #102482, GN: Crash with Shift+A when editing files containing node group assets
Referenced by issue #68935, Unified object and geometry I/O handling
Referenced by issue #111411, Regression: Crash when selecting an object with an orphaned geo node link
30 changed files with 557 additions and 175 deletions

View File

@ -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

View File

@ -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

View File

@ -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,27 +22,50 @@
#include <memory>
struct AssetLibraryReference;
struct Main;
namespace blender::bke {
struct 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,
* for managing the "Save Catalog Changes" in the quit-confirmation dialog box. */
static bool save_catalogs_when_file_is_saved;
/** The directory representing the root of this library. */
std::string root_path;
std::unique_ptr<AssetCatalogService> catalog_service;
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.
*
@ -53,8 +79,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 +109,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);

View File

@ -0,0 +1,66 @@
/* 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.
*
* #AssetRepresentation is the data-structure to store information about a single asset. It doesn't
* contain the asset itself, but information like the metadata and preview, as well as methods to
* interact with them. Think of it like a view on an asset.
*/
class AssetRepresentation {
friend class 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

View File

@ -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

View File

@ -27,23 +27,33 @@ 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);
}
MEM_SAFE_FREE((*asset_data)->author);
MEM_SAFE_FREE((*asset_data)->description);
BLI_freelistN(&(*asset_data)->tags);
(*asset_data)->~AssetMetaData();
MEM_SAFE_FREE(*asset_data);
}
AssetMetaData::~AssetMetaData()
{
if (properties) {
IDP_FreeProperty(properties);
}
MEM_SAFE_FREE(author);
MEM_SAFE_FREE(description);
BLI_freelistN(&tags);
}
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)
{
AssetTag *tag = (AssetTag *)MEM_callocN(sizeof(*tag), __func__);

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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

View File

@ -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. */

View File

@ -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,25 @@ 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{};
BLI_strncpy(dummy_main.filepath, asset_library_root_.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();

View File

@ -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();
}
/** \} */

View File

@ -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};
}

View File

@ -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) {

View File

@ -8,6 +8,9 @@
#include "DNA_space_types.h"
#include "BKE_asset.h"
#include "BKE_asset_representation.hh"
#include "BLO_readfile.h"
#include "ED_asset_handle.h"
@ -17,12 +20,12 @@
const char *ED_asset_handle_get_name(const AssetHandle *asset)
{
return asset->file_data->name;
return BKE_asset_representation_name_get(asset->file_data->asset);
}
AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset)
AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset_handle)
{
return asset->file_data->asset_data;
return BKE_asset_representation_metadata_get(asset_handle->file_data->asset);
}
ID *ED_asset_handle_get_local_id(const AssetHandle *asset)

View File

@ -72,7 +72,7 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle)
if (!handle) {
return nullptr;
}
BLI_assert(handle->file_data->asset_data != nullptr);
BLI_assert(handle->file_data->asset != nullptr);
return reinterpret_cast<AssetTempIDConsumer *>(
MEM_new<AssetTemporaryIDConsumer>(__func__, *handle));
}

View File

@ -1789,7 +1789,6 @@ void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale);
void UI_but_drag_set_asset(uiBut *but,
const struct AssetHandle *asset,
const char *path,
struct AssetMetaData *metadata,
int import_type, /* eFileAssetImportType */
int icon,
struct ImBuf *imb,

View File

@ -27,15 +27,14 @@ void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale)
}
void UI_but_drag_set_asset(uiBut *but,
const AssetHandle *asset,
const AssetHandle *asset_handle,
const char *path,
struct AssetMetaData *metadata,
int import_type,
int icon,
struct ImBuf *imb,
float scale)
{
wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
wmDragAsset *asset_drag = WM_drag_create_asset_data(asset_handle, path, import_type);
/* FIXME: This is temporary evil solution to get scene/view-layer/etc in the copy callback of the
* #wmDropBox.

View File

@ -57,7 +57,6 @@ static void asset_view_item_but_drag_set(uiBut *but,
UI_but_drag_set_asset(but,
asset_handle,
BLI_strdup(blend_path),
ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_asset_handle_get_preview_icon_id(asset_handle),
imbuf,

View File

@ -708,12 +708,11 @@ bool file_set_asset_catalog_filter_settings(
void file_ensure_updated_catalog_filter_data(
FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
const ::AssetLibrary *asset_library)
const bke::AssetLibrary *asset_library)
{
AssetCatalogFilterSettings *filter_settings = reinterpret_cast<AssetCatalogFilterSettings *>(
filter_settings_handle);
const AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(
asset_library);
const AssetCatalogService *catalog_service = asset_library->catalog_service.get();
if (filter_settings->asset_catalog_visibility != FILE_SHOW_ASSETS_ALL_CATALOGS) {
filter_settings->catalog_filter = std::make_unique<AssetCatalogFilter>(

View File

@ -171,7 +171,6 @@ static void file_draw_icon(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
file->asset_data,
asset_params->import_type,
icon,
preview_image,
@ -565,7 +564,6 @@ static void file_draw_preview(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
file->asset_data,
asset_params->import_type,
icon,
imb,

View File

@ -67,8 +67,9 @@ void ED_file_indexer_entries_extend_from_datablock_infos(
}
}
static void ED_file_indexer_entry_free(void *indexer_entry)
static void ED_file_indexer_entry_free(void *indexer_entry_ptr)
{
FileIndexerEntry *indexer_entry = static_cast<FileIndexerEntry *>(indexer_entry_ptr);
MEM_freeN(indexer_entry);
}

View File

@ -218,6 +218,17 @@ void file_path_to_ui_path(const char *path, char *r_pathi, int max_size);
/* C-handle for #ed::asset_browser::AssetCatalogFilterSettings. */
typedef struct FileAssetCatalogFilterSettingsHandle FileAssetCatalogFilterSettingsHandle;
void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library,
struct uiLayout *layout,
SpaceFile *space_file,
FileAssetSelectParams *params);
#ifdef __cplusplus
namespace blender::bke {
struct AssetLibrary;
}
FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings(void);
void file_delete_asset_catalog_filter_settings(
FileAssetCatalogFilterSettingsHandle **filter_settings_handle);
@ -231,15 +242,12 @@ bool file_set_asset_catalog_filter_settings(
bUUID catalog_id);
void file_ensure_updated_catalog_filter_data(
FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
const struct AssetLibrary *asset_library);
const blender::bke::AssetLibrary *asset_library);
bool file_is_asset_visible_in_catalog_filter_settings(
const FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
const AssetMetaData *asset_data);
void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library,
struct uiLayout *layout,
struct SpaceFile *space_file,
struct FileAssetSelectParams *params);
#endif
#ifdef __cplusplus
}

View File

@ -43,6 +43,8 @@
#include "BKE_asset.h"
#include "BKE_asset_library.h"
#include "BKE_asset_library.hh"
#include "BKE_asset_representation.hh"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@ -78,6 +80,8 @@
#include "file_intern.h"
#include "filelist.h"
using namespace blender;
#define FILEDIR_NBR_ENTRIES_UNSET -1
/* ------------------FILELIST------------------------ */
@ -95,7 +99,7 @@ struct FileListInternEntry {
/** Optional argument for shortcuts, aliases etc. */
char *redirection_path;
/** not strictly needed, but used during sorting, avoids to have to recompute it there... */
char *name;
const char *name;
bool free_name;
/**
@ -112,9 +116,8 @@ struct FileListInternEntry {
PreviewImage *preview_image;
} local_data;
/** When the file represents an asset read from another file, it is stored here.
* Owning pointer. */
AssetMetaData *imported_asset_data;
/* References an asset in the asset library storage. */
bke::AssetRepresentation *asset; /* Non-owning. */
/* See #FILE_ENTRY_BLENDERLIB_NO_PREVIEW. */
bool blenderlib_has_no_preview;
@ -210,7 +213,7 @@ struct FileList {
eFileSelectType type;
/* The library this list was created for. Stored here so we know when to re-read. */
AssetLibraryReference *asset_library_ref;
AssetLibrary *asset_library; /* Non-owning pointer. */
bke::AssetLibrary *asset_library; /* Non-owning. */
short flags;
@ -776,8 +779,10 @@ static bool is_filtered_id_file_type(const FileListInternEntry *file,
*/
static AssetMetaData *filelist_file_internal_get_asset_data(const FileListInternEntry *file)
{
const ID *local_id = file->local_data.id;
return local_id ? local_id->asset_data : file->imported_asset_data;
if (!file->asset) {
return nullptr;
}
return &file->asset->get_metadata();
}
static void prepare_filter_asset_library(const FileList *filelist, FileListFilter *filter)
@ -1016,7 +1021,7 @@ void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
void filelist_set_asset_catalog_filter_options(
FileList *filelist,
eFileSel_Params_AssetCatalogVisibility catalog_visibility,
const bUUID *catalog_id)
const ::bUUID *catalog_id)
{
if (!filelist->filter_data.asset_catalog_filter) {
/* There's no filter data yet. */
@ -1362,7 +1367,7 @@ static bool filelist_checkdir_main_assets(struct FileList * /*filelist*/,
static void filelist_entry_clear(FileDirEntry *entry)
{
if (entry->name && ((entry->flags & FILE_ENTRY_NAME_FREE) != 0)) {
MEM_freeN(entry->name);
MEM_freeN((char *)entry->name);
}
if (entry->relpath) {
MEM_freeN(entry->relpath);
@ -1399,8 +1404,13 @@ static void filelist_direntryarr_free(FileDirEntryArr *array)
array->entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET;
}
static void filelist_intern_entry_free(FileListInternEntry *entry)
static void filelist_intern_entry_free(FileList *filelist, FileListInternEntry *entry)
{
if (entry->asset) {
BLI_assert(filelist->asset_library);
filelist->asset_library->remove_asset(*entry->asset);
}
if (entry->relpath) {
MEM_freeN(entry->relpath);
}
@ -1408,19 +1418,16 @@ static void filelist_intern_entry_free(FileListInternEntry *entry)
MEM_freeN(entry->redirection_path);
}
if (entry->name && entry->free_name) {
MEM_freeN(entry->name);
}
/* If we own the asset-data (it was generated from external file data), free it. */
if (entry->imported_asset_data) {
BKE_asset_metadata_free(&entry->imported_asset_data);
MEM_freeN((char *)entry->name);
}
MEM_freeN(entry);
}
static void filelist_intern_free(FileListIntern *filelist_intern)
static void filelist_intern_free(FileList *filelist)
{
FileListIntern *filelist_intern = &filelist->filelist_intern;
LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) {
filelist_intern_entry_free(entry);
filelist_intern_entry_free(filelist, entry);
}
BLI_listbase_clear(&filelist_intern->entries);
@ -1430,8 +1437,9 @@ static void filelist_intern_free(FileListIntern *filelist_intern)
/**
* \return the number of main files removed.
*/
static int filelist_intern_free_main_files(FileListIntern *filelist_intern)
static int filelist_intern_free_main_files(FileList *filelist)
{
FileListIntern *filelist_intern = &filelist->filelist_intern;
int removed_counter = 0;
LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) {
if (!filelist_intern_entry_is_main_file(entry)) {
@ -1439,7 +1447,7 @@ static int filelist_intern_free_main_files(FileListIntern *filelist_intern)
}
BLI_remlink(&filelist_intern->entries, entry);
filelist_intern_entry_free(entry);
filelist_intern_entry_free(filelist, entry);
removed_counter++;
}
@ -1794,7 +1802,7 @@ void filelist_clear_ex(struct FileList *filelist,
filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
}
filelist_intern_free(&filelist->filelist_intern);
filelist_intern_free(filelist);
filelist_direntryarr_free(&filelist->filelist);
@ -1822,7 +1830,7 @@ static void filelist_clear_main_files(FileList *filelist,
filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
}
const int removed_files = filelist_intern_free_main_files(&filelist->filelist_intern);
const int removed_files = filelist_intern_free_main_files(filelist);
filelist->filelist.entries_num -= removed_files;
filelist->filelist.entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET;
@ -1881,7 +1889,7 @@ void filelist_free(struct FileList *filelist)
AssetLibrary *filelist_asset_library(FileList *filelist)
{
return filelist->asset_library;
return reinterpret_cast<::AssetLibrary *>(filelist->asset_library);
}
void filelist_freelib(struct FileList *filelist)
@ -1897,11 +1905,15 @@ BlendHandle *filelist_lib(struct FileList *filelist)
return filelist->libfiledata;
}
static char *fileentry_uiname(const char *root,
const char *relpath,
const eFileSel_File_Types typeflag,
char *buff)
static const char *fileentry_uiname(const char *root, FileListInternEntry *entry, char *buff)
{
if (entry->asset) {
const StringRefNull asset_name = entry->asset->get_name();
return BLI_strdupn(asset_name.c_str(), asset_name.size());
}
const char *relpath = entry->relpath;
const eFileSel_File_Types typeflag = entry->typeflag;
char *name = nullptr;
if (typeflag & FILE_TYPE_FTFONT && !(typeflag & FILE_TYPE_BLENDERLIB)) {
@ -2042,10 +2054,7 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
ret->redirection_path = BLI_strdup(entry->redirection_path);
}
ret->id = entry->local_data.id;
ret->asset_data = entry->imported_asset_data ? entry->imported_asset_data : nullptr;
if (ret->id && (ret->asset_data == nullptr)) {
ret->asset_data = ret->id->asset_data;
}
ret->asset = reinterpret_cast<::AssetRepresentation *>(entry->asset);
/* For some file types the preview is already available. */
if (entry->local_data.preview_image &&
BKE_previewimg_is_finished(entry->local_data.preview_image, ICON_SIZE_PREVIEW)) {
@ -2996,8 +3005,13 @@ static FileListInternEntry *filelist_readjob_list_lib_group_create(const int idc
return entry;
}
static void filelist_readjob_list_lib_add_datablock(ListBase *entries,
const BLODataBlockInfo *datablock_info,
/**
* \warning: This "steals" the asset metadata from \a datablock_info. Not great design but fixing
* this requires redesigning things on the caller side for proper ownership management.
*/
static void filelist_readjob_list_lib_add_datablock(FileList *filelist,
ListBase *entries,
BLODataBlockInfo *datablock_info,
const bool prefix_relpath_with_group_name,
const int idcode,
const char *group_name)
@ -3010,21 +3024,29 @@ static void filelist_readjob_list_lib_add_datablock(ListBase *entries,
entry->relpath = BLI_strdup(datablock_info->name);
}
entry->typeflag |= FILE_TYPE_BLENDERLIB;
if (datablock_info) {
entry->blenderlib_has_no_preview = datablock_info->no_preview_found;
if (datablock_info->asset_data) {
entry->typeflag |= FILE_TYPE_ASSET;
/* Moves ownership! */
entry->imported_asset_data = datablock_info->asset_data;
if (filelist->asset_library) {
/** XXX Moving out the asset metadata like this isn't great. */
std::unique_ptr metadata = BKE_asset_metadata_move_to_unique_ptr(
datablock_info->asset_data);
BKE_asset_metadata_free(&datablock_info->asset_data);
entry->asset = &filelist->asset_library->add_external_asset(datablock_info->name,
std::move(metadata));
}
}
}
entry->blentype = idcode;
BLI_addtail(entries, entry);
}
static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
static void filelist_readjob_list_lib_add_datablocks(FileList *filelist,
ListBase *entries,
LinkNode *datablock_infos,
const bool prefix_relpath_with_group_name,
const int idcode,
@ -3033,19 +3055,21 @@ static void filelist_readjob_list_lib_add_datablocks(ListBase *entries,
for (LinkNode *ln = datablock_infos; ln; ln = ln->next) {
struct BLODataBlockInfo *datablock_info = static_cast<BLODataBlockInfo *>(ln->link);
filelist_readjob_list_lib_add_datablock(
entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
filelist, entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name);
}
}
static void filelist_readjob_list_lib_add_from_indexer_entries(
FileList *filelist,
ListBase *entries,
const FileIndexerEntries *indexer_entries,
const bool prefix_relpath_with_group_name)
{
for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) {
const FileIndexerEntry *indexer_entry = (const FileIndexerEntry *)ln->link;
FileIndexerEntry *indexer_entry = static_cast<FileIndexerEntry *>(ln->link);
const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode);
filelist_readjob_list_lib_add_datablock(entries,
filelist_readjob_list_lib_add_datablock(filelist,
entries,
&indexer_entry->datablock_info,
prefix_relpath_with_group_name,
indexer_entry->idcode,
@ -3073,7 +3097,8 @@ typedef struct FileIndexer {
void *user_data;
} FileIndexer;
static int filelist_readjob_list_lib_populate_from_index(ListBase *entries,
static int filelist_readjob_list_lib_populate_from_index(FileList *filelist,
ListBase *entries,
const ListLibOptions options,
const int read_from_index,
const FileIndexerEntries *indexer_entries)
@ -3085,11 +3110,12 @@ static int filelist_readjob_list_lib_populate_from_index(ListBase *entries,
navigate_to_parent_len = 1;
}
filelist_readjob_list_lib_add_from_indexer_entries(entries, indexer_entries, true);
filelist_readjob_list_lib_add_from_indexer_entries(filelist, entries, indexer_entries, true);
return read_from_index + navigate_to_parent_len;
}
static int filelist_readjob_list_lib(const char *root,
static int filelist_readjob_list_lib(FileList *filelist,
const char *root,
ListBase *entries,
const ListLibOptions options,
FileIndexer *indexer_runtime)
@ -3128,7 +3154,7 @@ static int filelist_readjob_list_lib(const char *root,
dir, &indexer_entries, &read_from_index, indexer_runtime->user_data);
if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) {
int entries_read = filelist_readjob_list_lib_populate_from_index(
entries, options, read_from_index, &indexer_entries);
filelist, entries, options, read_from_index, &indexer_entries);
ED_file_indexer_entries_clear(&indexer_entries);
return entries_read;
}
@ -3158,7 +3184,8 @@ static int filelist_readjob_list_lib(const char *root,
const int idcode = groupname_to_code(group);
LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info(
libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &datablock_len);
filelist_readjob_list_lib_add_datablocks(entries, datablock_infos, false, idcode, group);
filelist_readjob_list_lib_add_datablocks(
filelist, entries, datablock_infos, false, idcode, group);
BLI_linklist_freeN(datablock_infos);
}
else {
@ -3177,7 +3204,7 @@ static int filelist_readjob_list_lib(const char *root,
LinkNode *group_datablock_infos = BLO_blendhandle_get_datablock_info(
libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len);
filelist_readjob_list_lib_add_datablocks(
entries, group_datablock_infos, true, idcode, group_name);
filelist, entries, group_datablock_infos, true, idcode, group_name);
if (use_indexer) {
ED_file_indexer_entries_extend_from_datablock_infos(
&indexer_entries, group_datablock_infos, idcode);
@ -3529,7 +3556,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
list_lib_options |= LIST_LIB_ASSETS_ONLY;
}
entries_num = filelist_readjob_list_lib(
subdir, &entries, list_lib_options, &indexer_runtime);
filelist, subdir, &entries, list_lib_options, &indexer_runtime);
if (entries_num > 0) {
is_lib = true;
}
@ -3550,7 +3577,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
MEM_freeN(entry->relpath);
entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//'
* added by BLI_path_rel to rel_subdir. */
entry->name = fileentry_uiname(root, entry->relpath, entry->typeflag, dir);
entry->name = fileentry_uiname(root, entry, dir);
entry->free_name = true;
if (filelist_readjob_should_recurse_into_entry(
@ -3626,20 +3653,6 @@ static void filelist_readjob_lib(FileListReadJob *job_params,
filelist_readjob_do(true, job_params, stop, do_update, progress);
}
static void filelist_asset_library_path(const FileListReadJob *job_params,
char r_library_root_path[FILE_MAX])
{
if (job_params->filelist->type == FILE_MAIN_ASSET) {
/* For the "Current File" library (#FILE_MAIN_ASSET) we get the asset library root path based
* on main. */
BKE_asset_library_find_suitable_root_path_from_main(job_params->current_main,
r_library_root_path);
}
else {
BLI_strncpy(r_library_root_path, job_params->tmp_filelist->filelist.root, FILE_MAX);
}
}
/**
* Load asset library data, which currently means loading the asset catalogs for the library.
*/
@ -3657,12 +3670,10 @@ static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params
return;
}
char library_root_path[FILE_MAX];
filelist_asset_library_path(job_params, library_root_path);
/* Load asset catalogs, into the temp filelist for thread-safety.
* #filelist_readjob_endjob() will move it into the real filelist. */
tmp_filelist->asset_library = BKE_asset_library_load(library_root_path);
tmp_filelist->asset_library = BKE_asset_library_load(job_params->current_main,
*job_params->filelist->asset_library_ref);
*do_update = true;
}
@ -3699,6 +3710,9 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
entry->local_data.preview_image = BKE_asset_metadata_preview_get_from_id(id_iter->asset_data,
id_iter);
entry->local_data.id = id_iter;
if (filelist->asset_library) {
entry->asset = &filelist->asset_library->add_local_id_asset(*id_iter);
}
entries_num++;
BLI_addtail(&tmp_entries, entry);
}

View File

@ -950,7 +950,7 @@ static int /*eContextResult*/ file_context(const bContext *C,
for (int file_index = 0; file_index < num_files_filtered; file_index++) {
if (filelist_entry_is_selected(sfile->files, file_index)) {
FileDirEntry *entry = filelist_file(sfile->files, file_index);
if (entry->asset_data) {
if (entry->asset) {
CTX_data_list_add(result, &screen->id, &RNA_FileSelectEntry, entry);
}
}

View File

@ -42,6 +42,10 @@ typedef struct AssetFilterSettings {
* more than that from the file. So pointers to other IDs or ID data are strictly forbidden.
*/
typedef struct AssetMetaData {
#ifdef __cplusplus
~AssetMetaData();
#endif
/** Runtime type, to reference event callbacks. Only valid for local assets. */
struct AssetTypeInfo *local_type_info;
@ -114,6 +118,8 @@ typedef struct AssetLibraryReference {
} AssetLibraryReference;
/**
* To be replaced by #AssetRepresentation!
*
* Not part of the core design, we should try to get rid of it. Only needed to wrap FileDirEntry
* into a type with PropertyGroup as base, so we can have an RNA collection of #AssetHandle's to
* pass to the UI.

View File

@ -1107,7 +1107,7 @@ typedef struct FileDirEntry {
uint32_t uid; /* FileUID */
/* Name needs freeing if FILE_ENTRY_NAME_FREE is set. Otherwise this is a direct pointer to a
* name buffer. */
char *name;
const char *name;
uint64_t size;
int64_t time;
@ -1134,7 +1134,7 @@ typedef struct FileDirEntry {
/** If this file represents an asset, its asset data is here. Note that we may show assets of
* external files in which case this is set but not the id above.
* Note comment for FileListInternEntry.local_data, the same applies here! */
struct AssetMetaData *asset_data;
struct AssetRepresentation *asset;
/* The icon_id for the preview image. */
int preview_icon_id;

View File

@ -540,6 +540,7 @@ static const EnumPropertyItem rna_enum_curve_display_handle_items[] = {
# include "BLI_string.h"
# include "BKE_anim_data.h"
# include "BKE_asset.h"
# include "BKE_brush.h"
# include "BKE_colortools.h"
# include "BKE_context.h"
@ -2761,18 +2762,24 @@ static PointerRNA rna_FileBrowser_FileSelectEntry_asset_data_get(PointerRNA *ptr
{
const FileDirEntry *entry = ptr->data;
if (!entry->asset) {
return PointerRNA_NULL;
}
AssetMetaData *asset_data = BKE_asset_representation_metadata_get(entry->asset);
/* Note that the owning ID of the RNA pointer (`ptr->owner_id`) has to be set carefully:
* Local IDs (`entry->id`) own their asset metadata themselves. Asset metadata from other blend
* files are owned by the file browser (`entry`). Only if this is set correctly, we can tell from
* the metadata RNA pointer if the metadata is stored locally and can thus be edited or not. */
if (entry->id) {
if (BKE_asset_representation_is_local_id(entry->asset)) {
PointerRNA id_ptr;
RNA_id_pointer_create(entry->id, &id_ptr);
return rna_pointer_inherit_refine(&id_ptr, &RNA_AssetMetaData, entry->asset_data);
return rna_pointer_inherit_refine(&id_ptr, &RNA_AssetMetaData, asset_data);
}
return rna_pointer_inherit_refine(ptr, &RNA_AssetMetaData, entry->asset_data);
return rna_pointer_inherit_refine(ptr, &RNA_AssetMetaData, asset_data);
}
static int rna_FileBrowser_FileSelectEntry_name_editable(PointerRNA *ptr, const char **r_info)
@ -2782,7 +2789,7 @@ static int rna_FileBrowser_FileSelectEntry_name_editable(PointerRNA *ptr, const
/* This actually always returns 0 (the name is never editable) but we want to get a disabled
* message returned to `r_info` in some cases. */
if (entry->asset_data) {
if (entry->asset) {
PointerRNA asset_data_ptr = rna_FileBrowser_FileSelectEntry_asset_data_get(ptr);
/* Get disabled hint from asset metadata polling. */
rna_AssetMetaData_editable(&asset_data_ptr, r_info);

View File

@ -1302,7 +1302,6 @@ bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode);
* \note Does not store \a asset in any way, so it's fine to pass a temporary.
*/
wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset,
struct AssetMetaData *metadata,
const char *path,
int import_type);
struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode);

View File

@ -556,15 +556,12 @@ bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
return WM_drag_get_local_ID(drag, idcode) || WM_drag_get_asset_data(drag, idcode);
}
wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset,
AssetMetaData *metadata,
const char *path,
int import_type)
wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset, const char *path, int import_type)
{
wmDragAsset *asset_drag = MEM_new<wmDragAsset>(__func__);
BLI_strncpy(asset_drag->name, ED_asset_handle_get_name(asset), sizeof(asset_drag->name));
asset_drag->metadata = metadata;
asset_drag->metadata = ED_asset_handle_get_metadata(asset);
asset_drag->path = path;
asset_drag->id_type = ED_asset_handle_get_id_type(asset);
asset_drag->import_type = import_type;
@ -733,12 +730,11 @@ void WM_drag_add_asset_list_item(
drag_asset->asset_data.local_id = local_id;
}
else {
AssetMetaData *metadata = ED_asset_handle_get_metadata(asset);
char asset_blend_path[FILE_MAX_LIBEXTRA];
ED_asset_handle_get_full_library_path(C, asset_library_ref, asset, asset_blend_path);
drag_asset->is_external = true;
drag_asset->asset_data.external_info = WM_drag_create_asset_data(
asset, metadata, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);
asset, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);
}
BLI_addtail(&drag->asset_items, drag_asset);
}