UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
20 changed files with 313 additions and 35 deletions
Showing only changes of commit 557da13294 - Show all commits

View File

@ -13,6 +13,10 @@
#include <memory>
#include <string>
#include "BLI_string_ref.hh"
struct AssetWeakReference;
namespace blender::asset_system {
class AssetIdentifier {
@ -24,6 +28,8 @@ class AssetIdentifier {
AssetIdentifier(AssetIdentifier &&) = default;
AssetIdentifier(const AssetIdentifier &) = default;
StringRefNull library_relative_identifier() const;
std::string full_path() const;
};

View File

@ -30,7 +30,7 @@ void AS_asset_libraries_exit(void);
*
* To get the in-memory-only "current file" asset library, pass an empty path.
*/
struct AssetLibrary *AS_asset_library_load(const char *library_path);
struct AssetLibrary *AS_asset_library_load(const char *name, const char *library_path);
/** Look up the asset's catalog and copy its simple name into #asset_data. */
void AS_asset_library_refresh_catalog_simplename(struct AssetLibrary *asset_library,

View File

@ -35,6 +35,10 @@ class AssetStorage;
* 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
@ -77,9 +81,11 @@ class AssetLibrary {
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).
* \param root_path: If this is an asset library on disk, the top-level directory path.
*/
AssetLibrary(StringRef root_path = "");
AssetLibrary(eAssetLibraryType library_type, StringRef name, StringRef root_path = "");
~AssetLibrary();
/**
@ -147,6 +153,8 @@ class AssetLibrary {
*/
AssetIdentifier asset_identifier_from_library(StringRef relative_asset_path);
eAssetLibraryType library_type() const;
StringRefNull name() const;
StringRefNull root_path() const;
};

View File

@ -13,6 +13,7 @@ extern "C" {
#endif
struct AssetMetaData;
struct AssetWeakReference;
/** C handle for #asset_system::AssetRepresentation. */
typedef struct AssetRepresentation AssetRepresentation;
@ -25,6 +26,13 @@ bool AS_asset_representation_is_local_id(const AssetRepresentation *asset) ATTR_
bool AS_asset_representation_is_never_link(const AssetRepresentation *asset)
ATTR_WARN_UNUSED_RESULT;
/**
* C version of #AssetRepresentation::make_weak_reference. Returned pointer needs freeing with
* #MEM_delete() or #BKE_asset_weak_reference_free().
*/
AssetWeakReference *AS_asset_representation_weak_reference_create(const AssetRepresentation *asset)
ATTR_WARN_UNUSED_RESULT;
#ifdef __cplusplus
}
#endif

View File

@ -71,6 +71,12 @@ class AssetRepresentation {
const AssetIdentifier &get_identifier() const;
/** Create a weak reference for this asset that can be written to files, but can break under a
* number of conditions.
* A weak reference can only be created if an asset representation is owned by an asset library.
*/
std::unique_ptr<AssetWeakReference> make_weak_reference() const;
StringRefNull get_name() const;
AssetMetaData &get_metadata() const;
/** Get the import method to use for this asset. A different one may be used if

View File

@ -53,6 +53,7 @@ if(WITH_GTESTS)
tests/asset_catalog_tree_test.cc
tests/asset_library_service_test.cc
tests/asset_library_test.cc
tests/asset_representation_test.cc
tests/asset_library_test_common.hh
)

View File

@ -4,9 +4,10 @@
* \ingroup asset_system
*/
#include "BLI_path_util.h"
#include <iostream>
#include "BLI_path_util.h"
#include "AS_asset_identifier.hh"
namespace blender::asset_system {
@ -17,6 +18,11 @@ AssetIdentifier::AssetIdentifier(std::shared_ptr<std::string> library_root_path,
{
}
StringRefNull AssetIdentifier::library_relative_identifier() const
{
return relative_asset_path_;
}
std::string AssetIdentifier::full_path() const
{
char path[FILE_MAX];

View File

@ -46,15 +46,15 @@ asset_system::AssetLibrary *AS_asset_library_load(const Main *bmain,
* Loading an asset library at this point only means loading the catalogs. Later on this should
* invoke reading of asset representations too.
*/
struct ::AssetLibrary *AS_asset_library_load(const char *library_path)
struct ::AssetLibrary *AS_asset_library_load(const char *name, const char *library_path)
{
AssetLibraryService *service = AssetLibraryService::get();
asset_system::AssetLibrary *lib;
if (library_path == nullptr || library_path[0] == '\0') {
lib = service->get_asset_library_current_file();
lib = service->get_asset_library_current_file(name);
}
else {
lib = service->get_asset_library_on_disk(library_path);
lib = service->get_asset_library_on_disk(ASSET_LIBRARY_CUSTOM, name, library_path);
}
return reinterpret_cast<struct ::AssetLibrary *>(lib);
}
@ -129,8 +129,10 @@ void AS_asset_library_remap_ids(const IDRemapper *mappings)
namespace blender::asset_system {
AssetLibrary::AssetLibrary(StringRef root_path)
: root_path_(std::make_shared<std::string>(utils::normalize_directory_path(root_path))),
AssetLibrary::AssetLibrary(eAssetLibraryType library_type, StringRef name, StringRef root_path)
: library_type_(library_type),
name_(name),
root_path_(std::make_shared<std::string>(utils::normalize_directory_path(root_path))),
asset_storage_(std::make_unique<AssetStorage>()),
catalog_service(std::make_unique<AssetCatalogService>())
{
@ -252,6 +254,16 @@ void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data)
STRNCPY(asset_data->catalog_simple_name, catalog->simple_name.c_str());
}
eAssetLibraryType AssetLibrary::library_type() const
{
return library_type_;
}
StringRefNull AssetLibrary::name() const
{
return name_;
}
StringRefNull AssetLibrary::root_path() const
{
return *root_path_;

View File

@ -67,7 +67,7 @@ AssetLibrary *AssetLibraryService::get_asset_library(
return nullptr;
}
AssetLibrary *library = get_asset_library_on_disk(root_path);
AssetLibrary *library = get_asset_library_on_disk(type, "Essentials", root_path);
library->import_method_ = ASSET_IMPORT_APPEND_REUSE;
return library;
@ -79,12 +79,12 @@ AssetLibrary *AssetLibraryService::get_asset_library(
if (root_path.empty()) {
/* File wasn't saved yet. */
return get_asset_library_current_file();
return get_asset_library_current_file("Current File");
}
return get_asset_library_on_disk(root_path);
return get_asset_library_on_disk(type, "Current File", root_path);
}
case ASSET_LIBRARY_ALL:
return get_asset_library_all(bmain);
return get_asset_library_all("All", bmain);
case ASSET_LIBRARY_CUSTOM: {
bUserAssetLibrary *custom_library = find_custom_asset_library_from_library_ref(
library_reference);
@ -97,7 +97,7 @@ AssetLibrary *AssetLibraryService::get_asset_library(
return nullptr;
}
AssetLibrary *library = get_asset_library_on_disk(root_path);
AssetLibrary *library = get_asset_library_on_disk(type, custom_library->name, root_path);
library->import_method_ = eAssetImportMethod(custom_library->import_method);
library->may_override_import_method_ = true;
@ -108,7 +108,9 @@ AssetLibrary *AssetLibraryService::get_asset_library(
return nullptr;
}
AssetLibrary *AssetLibraryService::get_asset_library_on_disk(StringRefNull root_path)
AssetLibrary *AssetLibraryService::get_asset_library_on_disk(eAssetLibraryType library_type,
StringRef name,
StringRefNull root_path)
{
BLI_assert_msg(!root_path.is_empty(),
"top level directory must be given for on-disk asset library");
@ -124,7 +126,8 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(StringRefNull root_
return lib;
}
std::unique_ptr lib_uptr = std::make_unique<AssetLibrary>(normalized_root_path);
std::unique_ptr lib_uptr = std::make_unique<AssetLibrary>(
library_type, name, normalized_root_path);
AssetLibrary *lib = lib_uptr.get();
lib->on_blend_save_handler_register();
@ -137,7 +140,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(StringRefNull root_
return lib;
}
AssetLibrary *AssetLibraryService::get_asset_library_current_file()
AssetLibrary *AssetLibraryService::get_asset_library_current_file(StringRef name)
{
if (current_file_library_) {
CLOG_INFO(&LOG, 2, "get current file lib (cached)");
@ -145,7 +148,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_current_file()
}
else {
CLOG_INFO(&LOG, 2, "get current file lib (loaded)");
current_file_library_ = std::make_unique<AssetLibrary>();
current_file_library_ = std::make_unique<AssetLibrary>(ASSET_LIBRARY_LOCAL, name);
current_file_library_->on_blend_save_handler_register();
}
@ -170,7 +173,7 @@ static void rebuild_all_library(AssetLibrary &all_library, const bool reload_cat
all_library.catalog_service->rebuild_tree();
}
AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
AssetLibrary *AssetLibraryService::get_asset_library_all(StringRef name, const Main *bmain)
{
/* (Re-)load all other asset libraries. */
for (AssetLibraryReference &library_ref : all_valid_asset_library_refs()) {
@ -190,7 +193,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
}
CLOG_INFO(&LOG, 2, "get all lib (loaded)");
all_library_ = std::make_unique<AssetLibrary>();
all_library_ = std::make_unique<AssetLibrary>(ASSET_LIBRARY_ALL, name);
/* Don't reload catalogs on this initial read, they've just been loaded above. */
rebuild_all_library(*all_library_, /*reload_catlogs=*/false);

View File

@ -68,13 +68,15 @@ class AssetLibraryService {
/**
* Get the given asset library. Opens it (i.e. creates a new AssetLibrary instance) if necessary.
*/
AssetLibrary *get_asset_library_on_disk(StringRefNull top_level_directory);
AssetLibrary *get_asset_library_on_disk(eAssetLibraryType library_type,
StringRef name,
StringRefNull top_level_directory);
/** Get the "Current File" asset library. */
AssetLibrary *get_asset_library_current_file();
AssetLibrary *get_asset_library_current_file(StringRef name);
/** Get the "All" asset library, which loads all others and merges them into one. */
AssetLibrary *get_asset_library_all(const Main *bmain);
AssetLibrary *get_asset_library_all(StringRef name, const Main *bmain);
/** Returns whether there are any known asset libraries with unsaved catalog edits. */
bool has_any_unsaved_catalogs() const;

View File

@ -67,6 +67,15 @@ const AssetIdentifier &AssetRepresentation::get_identifier() const
return identifier_;
}
std::unique_ptr<AssetWeakReference> AssetRepresentation::make_weak_reference() const
{
if (!owner_asset_library_) {
return nullptr;
}
return AssetWeakReference::make_reference(*owner_asset_library_, identifier_);
}
StringRefNull AssetRepresentation::get_name() const
{
if (is_local_id_) {
@ -159,4 +168,12 @@ bool AS_asset_representation_is_local_id(const AssetRepresentation *asset_handle
return asset->is_local_id();
}
AssetWeakReference *AS_asset_representation_weak_reference_create(const AssetRepresentation *asset_handle)
{
const asset_system::AssetRepresentation *asset =
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
std::unique_ptr<AssetWeakReference> weak_ref = asset->make_weak_reference();
return MEM_new<AssetWeakReference>(__func__, std::move(*weak_ref));
}
/** \} */

View File

@ -92,12 +92,18 @@ TEST_F(AssetLibraryServiceTest, get_destroy)
TEST_F(AssetLibraryServiceTest, library_pointers)
{
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();
EXPECT_EQ(lib, service->get_asset_library_on_disk(asset_library_root_))
const std::string lib_name_on_disk = std::string(__func__) + " on disk";
const std::string lib_name_curfile = std::string(__func__) + " current file";
AssetLibrary *const lib = service->get_asset_library_on_disk(
ASSET_LIBRARY_CUSTOM, lib_name_on_disk, asset_library_root_);
AssetLibrary *const curfile_lib = service->get_asset_library_current_file(lib_name_curfile);
EXPECT_EQ(lib,
service->get_asset_library_on_disk(
ASSET_LIBRARY_CUSTOM, lib_name_on_disk, asset_library_root_))
<< "Calling twice without destroying in between should return the same instance.";
EXPECT_EQ(curfile_lib, service->get_asset_library_current_file())
EXPECT_EQ(curfile_lib, service->get_asset_library_current_file(lib_name_curfile))
<< "Calling twice without destroying in between should return the same instance.";
/* NOTE: there used to be a test for the opposite here, that after a call to
@ -108,8 +114,13 @@ TEST_F(AssetLibraryServiceTest, library_pointers)
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();
const std::string lib_name_on_disk = std::string(__func__) + " on disk";
const std::string lib_name_curfile = std::string(__func__) + " current file";
AssetLibrary *const lib = service->get_asset_library_on_disk(
ASSET_LIBRARY_CUSTOM, lib_name_on_disk, asset_library_root_);
AssetLibrary *const curfile_lib = service->get_asset_library_current_file(lib_name_curfile);
AssetLibraryReference ref{};
ref.type = ASSET_LIBRARY_LOCAL;
@ -143,16 +154,20 @@ TEST_F(AssetLibraryServiceTest, library_path_trailing_slashes)
BLI_path_slash_ensure(asset_lib_with_slash, PATH_MAX);
AssetLibrary *const lib_no_slash = service->get_asset_library_on_disk(asset_lib_no_slash);
AssetLibrary *const lib_no_slash = service->get_asset_library_on_disk(
ASSET_LIBRARY_CUSTOM, __func__, asset_lib_no_slash);
EXPECT_EQ(lib_no_slash, service->get_asset_library_on_disk(asset_lib_with_slash))
EXPECT_EQ(
lib_no_slash,
service->get_asset_library_on_disk(ASSET_LIBRARY_CUSTOM, __func__, asset_lib_with_slash))
<< "With or without trailing slash shouldn't matter.";
}
TEST_F(AssetLibraryServiceTest, catalogs_loaded)
{
AssetLibraryService *const service = AssetLibraryService::get();
AssetLibrary *const lib = service->get_asset_library_on_disk(asset_library_root_);
AssetLibrary *const lib = service->get_asset_library_on_disk(
ASSET_LIBRARY_CUSTOM, __func__, asset_library_root_);
AssetCatalogService *const cat_service = lib->catalog_service.get();
const bUUID UUID_POSES_ELLIE("df60e1f6-2259-475b-93d9-69a1b4a8db78");
@ -166,7 +181,8 @@ TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs)
EXPECT_FALSE(service->has_any_unsaved_catalogs())
<< "Empty AssetLibraryService should have no unsaved catalogs";
AssetLibrary *const lib = service->get_asset_library_on_disk(asset_library_root_);
AssetLibrary *const lib = service->get_asset_library_on_disk(
ASSET_LIBRARY_CUSTOM, __func__, asset_library_root_);
AssetCatalogService *const cat_service = lib->catalog_service.get();
EXPECT_FALSE(service->has_any_unsaved_catalogs())
<< "Unchanged AssetLibrary should have no unsaved catalogs";
@ -198,7 +214,8 @@ TEST_F(AssetLibraryServiceTest, has_any_unsaved_catalogs_after_write)
ASSERT_EQ(0, BLI_copy(original_cdf_file.c_str(), writable_cdf_file.c_str()));
AssetLibraryService *const service = AssetLibraryService::get();
AssetLibrary *const lib = service->get_asset_library_on_disk(writable_dir);
AssetLibrary *const lib = service->get_asset_library_on_disk(
ASSET_LIBRARY_CUSTOM, __func__, writable_dir);
EXPECT_FALSE(service->has_any_unsaved_catalogs())
<< "Unchanged AssetLibrary should have no unsaved catalogs";

View File

@ -43,7 +43,7 @@ TEST_F(AssetLibraryTest, AS_asset_library_load)
/* Load the asset library. */
const std::string library_path = test_files_dir + "/" + "asset_library";
::AssetLibrary *library_c_ptr = AS_asset_library_load(library_path.data());
::AssetLibrary *library_c_ptr = AS_asset_library_load(__func__, library_path.data());
ASSERT_NE(nullptr, library_c_ptr);
/* Check that it can be cast to the C++ type and has a Catalog Service. */
@ -71,7 +71,7 @@ TEST_F(AssetLibraryTest, load_nonexistent_directory)
/* Load the asset library. */
const std::string library_path = test_files_dir + "/" +
"asset_library/this/subdir/does/not/exist";
::AssetLibrary *library_c_ptr = AS_asset_library_load(library_path.data());
::AssetLibrary *library_c_ptr = AS_asset_library_load(__func__, library_path.data());
ASSERT_NE(nullptr, library_c_ptr);
/* Check that it can be cast to the C++ type and has a Catalog Service. */

View File

@ -6,6 +6,7 @@
#include <vector>
#include "BKE_appdir.h"
#include "BKE_callbacks.h"
#include "BLI_fileops.h"
#include "BLI_path_util.h"
@ -35,10 +36,13 @@ class AssetLibraryTestBase : public testing::Test {
{
testing::Test::SetUpTestSuite();
CLG_init();
/* Current File library needs this. */
BKE_callback_global_init();
}
static void TearDownTestSuite()
{
BKE_callback_global_finalize();
CLG_exit();
testing::Test::TearDownTestSuite();
}

View File

@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "asset_library_service.hh"
#include "asset_library_test_common.hh"
#include "AS_asset_representation.h"
#include "AS_asset_representation.hh"
#include "DNA_asset_types.h"
#include "testing/testing.h"
namespace blender::asset_system::tests {
/** Sets up asset library loading so we have a library to load asset representations into (required
* for some functionality to perform work). */
class AssetRepresentationTest : public AssetLibraryTestBase {
public:
using AssetLibraryTestBase::SetUpTestSuite;
using AssetLibraryTestBase::TearDownTestSuite;
};
TEST_F(AssetRepresentationTest, weak_reference)
{
AssetLibraryService *service = AssetLibraryService::get();
AssetLibraryReference ref{};
ref.type = ASSET_LIBRARY_LOCAL;
AssetLibrary *library = service->get_asset_library(nullptr, ref);
std::unique_ptr<AssetMetaData> dummy_metadata = std::make_unique<AssetMetaData>();
AssetRepresentation &asset = library->add_external_asset(
"path/to/an/asset", "Some Asset Name", std::move(dummy_metadata));
std::unique_ptr<AssetWeakReference> weak_ref = asset.make_weak_reference();
EXPECT_EQ(weak_ref->asset_library_type, ASSET_LIBRARY_LOCAL);
EXPECT_STREQ(weak_ref->asset_library_identifier, "Current File");
EXPECT_STREQ(weak_ref->relative_asset_identifier, "path/to/an/asset");
/* Repeat the test with the C-API, which moves data into a guarded allocated block, so worth
* testing. */
AssetWeakReference *c_weak_ref = AS_asset_representation_weak_reference_create(
reinterpret_cast<::AssetRepresentation *>(&asset));
EXPECT_EQ(c_weak_ref->asset_library_type, ASSET_LIBRARY_LOCAL);
EXPECT_STREQ(c_weak_ref->asset_library_identifier, "Current File");
EXPECT_STREQ(c_weak_ref->relative_asset_identifier, "path/to/an/asset");
MEM_delete(c_weak_ref);
}
} // namespace blender::asset_system::tests

View File

@ -68,6 +68,12 @@ 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);
/** Frees the weak reference and its data, and nulls the given pointer. */
void BKE_asset_weak_reference_free(AssetWeakReference **weak_ref);
void BKE_asset_weak_reference_write(struct BlendWriter *writer,
const AssetWeakReference *weak_ref);
void BKE_asset_weak_reference_read(struct BlendDataReader *reader, AssetWeakReference *weak_ref);
#ifdef __cplusplus
}
#endif

View File

@ -72,6 +72,7 @@ set(SRC
intern/armature_selection.cc
intern/armature_update.c
intern/asset.cc
intern/asset_weak_reference.cc
intern/attribute.cc
intern/attribute_access.cc
intern/attribute_math.cc

View File

@ -25,6 +25,8 @@
using namespace blender;
/* Asset Metadata Core API -------------------------------------------- */
AssetMetaData *BKE_asset_metadata_create()
{
const AssetMetaData *default_metadata = DNA_struct_default_get(AssetMetaData);

View File

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include <memory>
#include "AS_asset_identifier.hh"
#include "AS_asset_library.hh"
#include "BKE_asset.h"
#include "BLO_read_write.h"
#include "DNA_asset_types.h"
#include "MEM_guardedalloc.h"
using namespace blender;
/* #AssetWeakReference -------------------------------------------- */
AssetWeakReference::AssetWeakReference(AssetWeakReference &&other)
: asset_library_type(other.asset_library_type),
asset_library_identifier(other.asset_library_identifier),
relative_asset_identifier(other.relative_asset_identifier)
{
asset_library_type = 0; /* Not a valid type. */
asset_library_identifier = nullptr;
relative_asset_identifier = nullptr;
}
AssetWeakReference::~AssetWeakReference()
{
MEM_delete(asset_library_identifier);
MEM_delete(relative_asset_identifier);
}
void BKE_asset_weak_reference_free(AssetWeakReference **weak_ref)
{
MEM_delete(*weak_ref);
*weak_ref = nullptr;
}
std::unique_ptr<AssetWeakReference> AssetWeakReference::make_reference(
const asset_system::AssetLibrary &library,
const asset_system::AssetIdentifier &asset_identifier)
{
std::unique_ptr weak_ref = std::make_unique<AssetWeakReference>();
weak_ref->asset_library_type = library.library_type();
StringRefNull name = library.name();
if (!name.is_empty()) {
weak_ref->asset_library_identifier = BLI_strdupn(name.c_str(), name.size());
}
StringRefNull relative_identifier = asset_identifier.library_relative_identifier();
weak_ref->relative_asset_identifier = BLI_strdupn(relative_identifier.c_str(),
relative_identifier.size());
return weak_ref;
}
void BKE_asset_weak_reference_write(BlendWriter *writer, const AssetWeakReference *weak_ref)
{
BLO_write_struct(writer, AssetWeakReference, weak_ref);
BLO_write_string(writer, weak_ref->asset_library_identifier);
BLO_write_string(writer, weak_ref->relative_asset_identifier);
}
void BKE_asset_weak_reference_read(BlendDataReader *reader, AssetWeakReference *weak_ref)
{
BLO_read_data_address(reader, &weak_ref->asset_library_identifier);
BLO_read_data_address(reader, &weak_ref->relative_asset_identifier);
}

View File

@ -10,6 +10,16 @@
#include "DNA_listBase.h"
#include "DNA_uuid_types.h"
#ifdef __cplusplus
# include <memory>
namespace blender::asset_system {
class AssetLibrary;
class AssetIdentifier;
} // namespace blender::asset_system
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -128,6 +138,48 @@ typedef struct AssetLibraryReference {
int custom_library_index;
} AssetLibraryReference;
/**
* Information to refer to an asset (may be stored in files) on a "best effort" basis. It should
* work well enough for many common cases, but can break. For example when the location of the
* asset changes, the available asset libraries in the Preferences change, an asset library is
* renamed, or when a file storing this is opened on a different system (with different
* Preferences).
*
* #AssetWeakReference is similar to #AssetIdentifier, but is designed for file storage, not for
* runtime references.
*
* It has two main components:
* - A reference to the asset library: The #eAssetLibraryType and if that is not enough to identify
* the library, a library name (typically given by the user, but may change).
* - An identifier for the asset within the library: A relative path currently, which can break if
* the asset is moved. Could also be a unique key for a database for example.
*
* \note Needs freeing through the destructor, so either use a smart pointer or #MEM_delete() for
* explicit freeing.
*/
typedef struct AssetWeakReference {
#ifdef __cplusplus
AssetWeakReference() = default;
AssetWeakReference(AssetWeakReference &&);
AssetWeakReference(const AssetWeakReference &) = delete;
/** Enables use with `std::unique_ptr<AssetWeakReference>`. */
~AssetWeakReference();
static std::unique_ptr<AssetWeakReference> make_reference(
const blender::asset_system::AssetLibrary &library,
const blender::asset_system::AssetIdentifier &asset_identifier);
#endif
char _pad[6];
short asset_library_type; /* #eAssetLibraryType */
/** If #asset_library_type is not enough to identify the asset library, this string can provide
* further location info. Allocated string. */
const char *asset_library_identifier;
const char *relative_asset_identifier;
} AssetWeakReference;
/**
* To be replaced by #AssetRepresentation!
*