UI: Asset Shelf (Experimental Feature) #104831
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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!
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue