Asset System: New "weak" asset reference for storing in .blend files #106026
@ -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;
|
||||
std::string full_library_path() const;
|
||||
};
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct AssetWeakReference;
|
||||
struct IDRemapper;
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -30,7 +31,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,
|
||||
@ -43,6 +44,29 @@ bool AS_asset_library_has_any_unsaved_catalogs(void);
|
||||
* remapped on change (or assets removed as IDs gets removed). */
|
||||
void AS_asset_library_remap_ids(const struct IDRemapper *mappings);
|
||||
|
||||
/**
|
||||
* Attempt to resolve a full path to an asset based on the currently available (not necessary
|
||||
* loaded) asset libraries, and split it into it's directory, ID group and ID name components. The
|
||||
* path is not guaranteed to exist on disk. On failure to resolve the reference, return arguments
|
||||
* will point to null.
|
||||
*
|
||||
* \note Only works for asset libraries on disk (others can't be resolved).
|
||||
*
|
||||
* \param r_path_buffer: Buffer to hold the result in on success. Will be the full path with null
|
||||
* terminators instead of slashes separating the directory, group and name
|
||||
* components.
|
||||
* \param r_dir: Returns the .blend file path with native slashes on success. Optional (passing
|
||||
* null is allowed).
|
||||
* \param r_group: Returns the ID group such as "Object", "Material" or "Brush". Optional (passing
|
||||
* null is allowed).
|
||||
* \param r_name: Returns the ID name on success. Optional (passing null is allowed).
|
||||
*/
|
||||
void AS_asset_full_path_explode_from_weak_ref(const struct AssetWeakReference *asset_reference,
|
||||
char r_path_buffer[1090 /* FILE_MAX_LIBEXTRA */],
|
||||
char **r_dir,
|
||||
char **r_group,
|
||||
char **r_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -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,13 @@ 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). Make sure
|
||||
* this is set for any custom (not builtin) asset library. That is,
|
||||
* #ASSET_LIBRARY_CUSTOM ones.
|
||||
* \param root_path: If this is an asset library on disk, the top-level directory path.
|
||||
*/
|
||||
AssetLibrary(StringRef root_path = "");
|
||||
AssetLibrary(eAssetLibraryType library_type, StringRef name = "", StringRef root_path = "");
|
||||
~AssetLibrary();
|
||||
|
||||
/**
|
||||
@ -147,6 +155,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;
|
||||
@ -27,6 +28,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
|
||||
|
@ -41,6 +41,7 @@ set(SRC
|
||||
)
|
||||
|
||||
set(LIB
|
||||
bf_blenkernel
|
||||
)
|
||||
|
||||
|
||||
@ -53,6 +54,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,6 +4,7 @@
|
||||
* \ingroup asset_system
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "BKE_blendfile.h"
|
||||
@ -20,6 +21,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,7 +46,7 @@ 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;
|
||||
@ -54,7 +54,7 @@ struct ::AssetLibrary *AS_asset_library_load(const char *library_path)
|
||||
lib = service->get_asset_library_current_file();
|
||||
}
|
||||
else {
|
||||
lib = service->get_asset_library_on_disk(library_path);
|
||||
lib = service->get_asset_library_on_disk_custom(name, library_path);
|
||||
}
|
||||
return reinterpret_cast<struct ::AssetLibrary *>(lib);
|
||||
}
|
||||
@ -127,10 +127,70 @@ void AS_asset_library_remap_ids(const IDRemapper *mappings)
|
||||
true);
|
||||
}
|
||||
|
||||
void AS_asset_full_path_explode_from_weak_ref(const AssetWeakReference *asset_reference,
|
||||
char r_path_buffer[1090 /* FILE_MAX_LIBEXTRA */],
|
||||
char **r_dir,
|
||||
char **r_group,
|
||||
char **r_name)
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
std::optional<AssetLibraryService::ExplodedPath> exploded =
|
||||
service->resolve_asset_weak_reference_to_exploded_path(*asset_reference);
|
||||
|
||||
if (!exploded) {
|
||||
if (r_dir) {
|
||||
*r_dir = nullptr;
|
||||
}
|
||||
if (r_group) {
|
||||
*r_group = nullptr;
|
||||
}
|
||||
if (r_name) {
|
||||
*r_name = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BLI_assert(!exploded->group_component.is_empty());
|
||||
BLI_assert(!exploded->name_component.is_empty());
|
||||
|
||||
BLI_strncpy(r_path_buffer, exploded->full_path.c_str(), 1090 /* FILE_MAX_LIBEXTRA */);
|
||||
|
||||
if (!exploded->dir_component.is_empty()) {
|
||||
r_path_buffer[exploded->dir_component.size()] = '\0';
|
||||
r_path_buffer[exploded->dir_component.size() + 1 + exploded->group_component.size()] = '\0';
|
||||
|
||||
if (r_dir) {
|
||||
*r_dir = r_path_buffer;
|
||||
}
|
||||
if (r_group) {
|
||||
*r_group = r_path_buffer + exploded->dir_component.size() + 1;
|
||||
}
|
||||
if (r_name) {
|
||||
*r_name = r_path_buffer + exploded->dir_component.size() + 1 +
|
||||
exploded->group_component.size() + 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
r_path_buffer[exploded->group_component.size()] = '\0';
|
||||
|
||||
if (r_dir) {
|
||||
*r_dir = nullptr;
|
||||
}
|
||||
if (r_group) {
|
||||
*r_group = r_path_buffer;
|
||||
}
|
||||
if (r_name) {
|
||||
*r_name = r_path_buffer + exploded->group_component.size() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 +312,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_;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "BKE_blender.h"
|
||||
#include "BKE_preferences.h"
|
||||
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "DNA_asset_types.h"
|
||||
@ -67,7 +68,7 @@ AssetLibrary *AssetLibraryService::get_asset_library(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AssetLibrary *library = get_asset_library_on_disk(root_path);
|
||||
AssetLibrary *library = get_asset_library_on_disk_builtin(type, root_path);
|
||||
library->import_method_ = ASSET_IMPORT_APPEND_REUSE;
|
||||
|
||||
return library;
|
||||
@ -81,7 +82,7 @@ AssetLibrary *AssetLibraryService::get_asset_library(
|
||||
/* File wasn't saved yet. */
|
||||
return get_asset_library_current_file();
|
||||
}
|
||||
return get_asset_library_on_disk(root_path);
|
||||
return get_asset_library_on_disk_builtin(type, root_path);
|
||||
}
|
||||
case ASSET_LIBRARY_ALL:
|
||||
return get_asset_library_all(bmain);
|
||||
@ -97,7 +98,7 @@ AssetLibrary *AssetLibraryService::get_asset_library(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AssetLibrary *library = get_asset_library_on_disk(root_path);
|
||||
AssetLibrary *library = get_asset_library_on_disk_custom(custom_library->name, root_path);
|
||||
library->import_method_ = eAssetImportMethod(custom_library->import_method);
|
||||
library->may_override_import_method_ = true;
|
||||
|
||||
@ -108,7 +109,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 +127,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,6 +141,24 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(StringRefNull root_
|
||||
return lib;
|
||||
}
|
||||
|
||||
AssetLibrary *AssetLibraryService::get_asset_library_on_disk_custom(StringRef name,
|
||||
StringRefNull root_path)
|
||||
{
|
||||
return get_asset_library_on_disk(ASSET_LIBRARY_CUSTOM, name, root_path);
|
||||
}
|
||||
|
||||
AssetLibrary *AssetLibraryService::get_asset_library_on_disk_builtin(eAssetLibraryType type,
|
||||
StringRefNull root_path)
|
||||
{
|
||||
BLI_assert_msg(
|
||||
type != ASSET_LIBRARY_CUSTOM,
|
||||
"Use `get_asset_library_on_disk_custom()` for libraries of type `ASSET_LIBRARY_CUSTOM`");
|
||||
|
||||
/* Builtin asset libraries don't need a name, the #eAssetLibraryType is enough to identify them
|
||||
* (and doesn't change, unlike the name). */
|
||||
return get_asset_library_on_disk(type, {}, root_path);
|
||||
}
|
||||
|
||||
AssetLibrary *AssetLibraryService::get_asset_library_current_file()
|
||||
{
|
||||
if (current_file_library_) {
|
||||
@ -145,7 +167,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);
|
||||
current_file_library_->on_blend_save_handler_register();
|
||||
}
|
||||
|
||||
@ -190,7 +212,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);
|
||||
|
||||
/* Don't reload catalogs on this initial read, they've just been loaded above. */
|
||||
rebuild_all_library(*all_library_, /*reload_catlogs=*/false);
|
||||
@ -202,6 +224,149 @@ AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
|
||||
return all_library_.get();
|
||||
}
|
||||
|
||||
bUserAssetLibrary *AssetLibraryService::find_custom_preferences_asset_library_from_asset_weak_ref(
|
||||
const AssetWeakReference &asset_reference)
|
||||
{
|
||||
if (!ELEM(asset_reference.asset_library_type, ASSET_LIBRARY_CUSTOM)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return BKE_preferences_asset_library_find_from_name(&U,
|
||||
asset_reference.asset_library_identifier);
|
||||
}
|
||||
|
||||
AssetLibrary *AssetLibraryService::find_loaded_on_disk_asset_library_from_name(
|
||||
StringRef name) const
|
||||
{
|
||||
for (const std::unique_ptr<AssetLibrary> &library : on_disk_libraries_.values()) {
|
||||
if (library->name_ == name) {
|
||||
return library.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string AssetLibraryService::resolve_asset_weak_reference_to_library_path(
|
||||
const AssetWeakReference &asset_reference)
|
||||
{
|
||||
StringRefNull library_path;
|
||||
|
||||
switch (eAssetLibraryType(asset_reference.asset_library_type)) {
|
||||
case ASSET_LIBRARY_CUSTOM: {
|
||||
bUserAssetLibrary *custom_lib = find_custom_preferences_asset_library_from_asset_weak_ref(
|
||||
asset_reference);
|
||||
if (custom_lib) {
|
||||
library_path = custom_lib->path;
|
||||
break;
|
||||
}
|
||||
|
||||
/* A bit of an odd-ball, the API supports loading custom libraries from arbitrary paths (used
|
||||
* by unit tests). So check all loaded on-disk libraries too. */
|
||||
AssetLibrary *loaded_custom_lib = find_loaded_on_disk_asset_library_from_name(
|
||||
asset_reference.asset_library_identifier);
|
||||
if (!loaded_custom_lib) {
|
||||
return "";
|
||||
}
|
||||
|
||||
library_path = *loaded_custom_lib->root_path_;
|
||||
break;
|
||||
}
|
||||
case ASSET_LIBRARY_ESSENTIALS:
|
||||
library_path = essentials_directory_path();
|
||||
break;
|
||||
case ASSET_LIBRARY_LOCAL:
|
||||
case ASSET_LIBRARY_ALL:
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string normalized_library_path = utils::normalize_path(library_path);
|
||||
return normalized_library_path;
|
||||
}
|
||||
|
||||
/* TODO currently only works for asset libraries on disk (custom or essentials asset libraries).
|
||||
* Once there is a proper registry of asset libraries, this could contain an asset library locator
|
||||
* and/or identifier, so a full path (not necessarily file path) can be built for all asset
|
||||
* libraries. */
|
||||
std::string AssetLibraryService::resolve_asset_weak_reference_to_full_path(
|
||||
const AssetWeakReference &asset_reference)
|
||||
{
|
||||
if (asset_reference.relative_asset_identifier[0] == '\0') {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string library_path = resolve_asset_weak_reference_to_library_path(asset_reference);
|
||||
if (library_path.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string normalized_full_path = utils::normalize_path(
|
||||
library_path + SEP_STR + asset_reference.relative_asset_identifier);
|
||||
return normalized_full_path;
|
||||
}
|
||||
|
||||
std::optional<AssetLibraryService::ExplodedPath> AssetLibraryService::
|
||||
resolve_asset_weak_reference_to_exploded_path(const AssetWeakReference &asset_reference)
|
||||
{
|
||||
if (asset_reference.relative_asset_identifier[0] == '\0') {
|
||||
return {};
|
||||
}
|
||||
|
||||
switch (eAssetLibraryType(asset_reference.asset_library_type)) {
|
||||
case ASSET_LIBRARY_LOCAL: {
|
||||
std::string path_in_file = utils::normalize_path(asset_reference.relative_asset_identifier);
|
||||
const int64_t group_len = int64_t(path_in_file.find(SEP));
|
||||
|
||||
ExplodedPath exploded{};
|
||||
exploded.full_path = path_in_file;
|
||||
exploded.group_component = StringRef(exploded.full_path).substr(0, group_len);
|
||||
exploded.name_component = StringRef(exploded.full_path).substr(group_len + 1);
|
||||
|
||||
return exploded;
|
||||
}
|
||||
case ASSET_LIBRARY_CUSTOM:
|
||||
case ASSET_LIBRARY_ESSENTIALS: {
|
||||
std::string full_path = resolve_asset_weak_reference_to_full_path(asset_reference);
|
||||
|
||||
if (full_path.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::vector<std::string> blendfile_extensions = {".blend/", ".blend.gz/", ".ble/"};
|
||||
size_t blendfile_extension_pos = std::string::npos;
|
||||
for (const std::string &blendfile_ext : blendfile_extensions) {
|
||||
size_t ext_pos = full_path.rfind(blendfile_ext);
|
||||
if (ext_pos != std::string::npos &&
|
||||
(blendfile_extension_pos < ext_pos || blendfile_extension_pos == std::string::npos)) {
|
||||
blendfile_extension_pos = ext_pos;
|
||||
}
|
||||
}
|
||||
BLI_assert(blendfile_extension_pos != std::string::npos);
|
||||
|
||||
size_t group_pos = full_path.find(SEP, blendfile_extension_pos);
|
||||
BLI_assert(group_pos != std::string::npos);
|
||||
|
||||
size_t name_pos = full_path.find(SEP, group_pos + 1);
|
||||
BLI_assert(group_pos != std::string::npos);
|
||||
|
||||
const int64_t dir_len = int64_t(group_pos);
|
||||
const int64_t group_len = int64_t(name_pos - group_pos - 1);
|
||||
|
||||
ExplodedPath exploded{};
|
||||
exploded.full_path = full_path;
|
||||
StringRef full_path_ref = exploded.full_path;
|
||||
exploded.dir_component = full_path_ref.substr(0, dir_len);
|
||||
exploded.group_component = full_path_ref.substr(dir_len + 1, group_len);
|
||||
exploded.name_component = full_path_ref.substr(dir_len + 1 + group_len + 1);
|
||||
|
||||
return exploded;
|
||||
}
|
||||
case ASSET_LIBRARY_ALL:
|
||||
return {};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bUserAssetLibrary *AssetLibraryService::find_custom_asset_library_from_library_ref(
|
||||
const AssetLibraryReference &library_reference)
|
||||
{
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "AS_asset_library.hh"
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
@ -61,21 +63,46 @@ class AssetLibraryService {
|
||||
static std::string root_path_from_library_ref(const AssetLibraryReference &library_reference);
|
||||
static bUserAssetLibrary *find_custom_asset_library_from_library_ref(
|
||||
const AssetLibraryReference &library_reference);
|
||||
static bUserAssetLibrary *find_custom_preferences_asset_library_from_asset_weak_ref(
|
||||
const AssetWeakReference &asset_reference);
|
||||
|
||||
AssetLibrary *get_asset_library(const Main *bmain,
|
||||
const AssetLibraryReference &library_reference);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/** Get an asset library of type #ASSET_LIBRARY_CUSTOM. */
|
||||
AssetLibrary *get_asset_library_on_disk_custom(StringRef name, StringRefNull root_path);
|
||||
/** Get a builtin (not user defined) asset library. I.e. a library that is **not** of type
|
||||
* #ASSET_LIBRARY_CUSTOM. */
|
||||
AssetLibrary *get_asset_library_on_disk_builtin(eAssetLibraryType type, StringRefNull root_path);
|
||||
/** Get the "Current File" asset library. */
|
||||
AssetLibrary *get_asset_library_current_file();
|
||||
|
||||
/** Get the "All" asset library, which loads all others and merges them into one. */
|
||||
AssetLibrary *get_asset_library_all(const Main *bmain);
|
||||
|
||||
/** Get a valid library path from the weak reference. Empty if e.g. the reference is to a local
|
||||
* asset. */
|
||||
std::string resolve_asset_weak_reference_to_library_path(
|
||||
const AssetWeakReference &asset_reference);
|
||||
/* See #AS_asset_full_path_resolve_from_weak_ref(). */
|
||||
std::string resolve_asset_weak_reference_to_full_path(const AssetWeakReference &asset_reference);
|
||||
/** Struct to hold results from path explosion functions
|
||||
* (#resolve_asset_weak_reference_to_exploded_path()). */
|
||||
struct ExplodedPath {
|
||||
/* The string buffer containing the fully resolved path, if resolving was successful. */
|
||||
std::string full_path = "";
|
||||
/* Reference into the part of #full_path that is the directory path. */
|
||||
StringRef dir_component = "";
|
||||
/* Reference into the part of #full_path that is the ID group name ("Object", "Brush", ...). */
|
||||
StringRef group_component = "";
|
||||
/* Reference into the part of #full_path that is the ID name. */
|
||||
StringRef name_component = "";
|
||||
};
|
||||
/** Similar to #BKE_blendfile_library_path_explode, returns the full path as
|
||||
* #resolve_asset_weak_reference_to_library_path, with StringRefs to the `dir` (i.e. blendfile
|
||||
* path), `group` (i.e. ID type) and `name` (i.e. ID name) parts. */
|
||||
std::optional<ExplodedPath> resolve_asset_weak_reference_to_exploded_path(
|
||||
const AssetWeakReference &asset_reference);
|
||||
|
||||
/** Returns whether there are any known asset libraries with unsaved catalog edits. */
|
||||
bool has_any_unsaved_catalogs() const;
|
||||
|
||||
@ -87,6 +114,14 @@ class AssetLibraryService {
|
||||
/** Allocate a new instance of the service and assign it to `instance_`. */
|
||||
static void allocate_service_instance();
|
||||
|
||||
AssetLibrary *find_loaded_on_disk_asset_library_from_name(StringRef name) const;
|
||||
|
||||
/**
|
||||
* Get the given asset library. Opens it (i.e. creates a new AssetLibrary instance) if necessary.
|
||||
*/
|
||||
AssetLibrary *get_asset_library_on_disk(eAssetLibraryType library_type,
|
||||
StringRef name,
|
||||
StringRefNull top_level_directory);
|
||||
/**
|
||||
* Ensure the AssetLibraryService instance is destroyed before a new blend file is loaded.
|
||||
* This makes memory management simple, and ensures a fresh start for every blend 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_) {
|
||||
@ -178,4 +187,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));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -27,4 +27,15 @@ std::string normalize_directory_path(StringRef directory)
|
||||
return std::string(dir_normalized);
|
||||
}
|
||||
|
||||
std::string normalize_path(StringRefNull path)
|
||||
{
|
||||
char *buf = BLI_strdupn(path.c_str(), size_t(path.size()));
|
||||
BLI_path_normalize(nullptr, buf);
|
||||
BLI_path_slash_native(buf);
|
||||
|
||||
std::string normalized_path = buf;
|
||||
MEM_freeN(buf);
|
||||
return normalized_path;
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system::utils
|
||||
|
@ -16,4 +16,10 @@ namespace blender::asset_system::utils {
|
||||
*/
|
||||
std::string normalize_directory_path(StringRef directory);
|
||||
|
||||
/**
|
||||
* Returns a normalized file path, with no maximum length.
|
||||
* Slashes are converted to native format.
|
||||
*/
|
||||
std::string normalize_path(StringRefNull path);
|
||||
|
||||
} // namespace blender::asset_system::utils
|
||||
|
@ -92,10 +92,12 @@ 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 lib = service->get_asset_library_on_disk_custom(__func__,
|
||||
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_))
|
||||
EXPECT_EQ(lib, service->get_asset_library_on_disk_custom(__func__, asset_library_root_))
|
||||
<< "Calling twice without destroying in between should return the same instance.";
|
||||
EXPECT_EQ(curfile_lib, service->get_asset_library_current_file())
|
||||
<< "Calling twice without destroying in between should return the same instance.";
|
||||
@ -108,7 +110,9 @@ 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 lib = service->get_asset_library_on_disk_custom(__func__,
|
||||
asset_library_root_);
|
||||
AssetLibrary *const curfile_lib = service->get_asset_library_current_file();
|
||||
|
||||
AssetLibraryReference ref{};
|
||||
@ -143,16 +147,19 @@ 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_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_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_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 +173,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_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 +206,7 @@ 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_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. */
|
||||
|
@ -5,7 +5,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "asset_library_service.hh"
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
#include "BKE_callbacks.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_path_util.h"
|
||||
@ -35,10 +38,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();
|
||||
}
|
||||
@ -56,6 +62,8 @@ class AssetLibraryTestBase : public testing::Test {
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
AssetLibraryService::destroy();
|
||||
|
||||
if (!temp_library_path_.empty()) {
|
||||
BLI_delete(temp_library_path_.c_str(), true, true);
|
||||
temp_library_path_ = "";
|
||||
|
154
source/blender/asset_system/tests/asset_representation_test.cc
Normal file
154
source/blender/asset_system/tests/asset_representation_test.cc
Normal file
@ -0,0 +1,154 @@
|
||||
/* 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:
|
||||
AssetLibrary *get_builtin_library_from_type(eAssetLibraryType type)
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
|
||||
AssetLibraryReference ref{};
|
||||
ref.type = type;
|
||||
return service->get_asset_library(nullptr, ref);
|
||||
}
|
||||
|
||||
AssetRepresentation &add_dummy_asset(AssetLibrary &library, StringRef relative_path)
|
||||
{
|
||||
std::unique_ptr<AssetMetaData> dummy_metadata = std::make_unique<AssetMetaData>();
|
||||
return library.add_external_asset(relative_path, "Some asset name", std::move(dummy_metadata));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(AssetRepresentationTest, weak_reference__current_file)
|
||||
{
|
||||
AssetLibrary *library = get_builtin_library_from_type(ASSET_LIBRARY_LOCAL);
|
||||
AssetRepresentation &asset = add_dummy_asset(*library, "path/to/an/asset");
|
||||
|
||||
{
|
||||
std::unique_ptr<AssetWeakReference> weak_ref = asset.make_weak_reference();
|
||||
EXPECT_EQ(weak_ref->asset_library_type, ASSET_LIBRARY_LOCAL);
|
||||
EXPECT_EQ(weak_ref->asset_library_identifier, nullptr);
|
||||
EXPECT_STREQ(weak_ref->relative_asset_identifier, "path/to/an/asset");
|
||||
}
|
||||
|
||||
{
|
||||
/* Also test the C-API, it moves memory, 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_EQ(c_weak_ref->asset_library_identifier, nullptr);
|
||||
EXPECT_STREQ(c_weak_ref->relative_asset_identifier, "path/to/an/asset");
|
||||
MEM_delete(c_weak_ref);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(AssetRepresentationTest, weak_reference__custom_library)
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
AssetLibrary *const library = service->get_asset_library_on_disk_custom("My custom lib",
|
||||
asset_library_root_);
|
||||
AssetRepresentation &asset = add_dummy_asset(*library, "path/to/an/asset");
|
||||
|
||||
{
|
||||
std::unique_ptr<AssetWeakReference> weak_ref = asset.make_weak_reference();
|
||||
EXPECT_EQ(weak_ref->asset_library_type, ASSET_LIBRARY_CUSTOM);
|
||||
EXPECT_STREQ(weak_ref->asset_library_identifier, "My custom lib");
|
||||
EXPECT_STREQ(weak_ref->relative_asset_identifier, "path/to/an/asset");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(AssetRepresentationTest, weak_reference__resolve_to_full_path__current_file)
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
AssetLibrary *library = get_builtin_library_from_type(ASSET_LIBRARY_LOCAL);
|
||||
AssetRepresentation &asset = add_dummy_asset(*library, "path/to/an/asset");
|
||||
|
||||
std::unique_ptr<AssetWeakReference> weak_ref = asset.make_weak_reference();
|
||||
|
||||
std::string resolved_path = service->resolve_asset_weak_reference_to_full_path(*weak_ref);
|
||||
EXPECT_EQ(resolved_path, "");
|
||||
}
|
||||
|
||||
/* #AssetLibraryService::resolve_asset_weak_reference_to_full_path(). */
|
||||
TEST_F(AssetRepresentationTest, weak_reference__resolve_to_full_path__custom_library)
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
AssetLibrary *const library = service->get_asset_library_on_disk_custom("My custom lib",
|
||||
asset_library_root_);
|
||||
AssetRepresentation &asset = add_dummy_asset(*library, "path/to/an/asset");
|
||||
|
||||
std::unique_ptr<AssetWeakReference> weak_ref = asset.make_weak_reference();
|
||||
|
||||
std::string expected_path = asset_library_root_ + "/" + "path/to/an/asset";
|
||||
char *c_str = expected_path.data();
|
||||
BLI_path_slash_native(c_str);
|
||||
BLI_path_normalize(nullptr, c_str);
|
||||
expected_path = c_str;
|
||||
|
||||
std::string resolved_path = service->resolve_asset_weak_reference_to_full_path(*weak_ref);
|
||||
EXPECT_EQ(resolved_path, expected_path);
|
||||
}
|
||||
|
||||
/* #AssetLibraryService::resolve_asset_weak_reference_to_exploded_path(). */
|
||||
TEST_F(AssetRepresentationTest, weak_reference__resolve_to_exploded_path__current_file)
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
AssetLibrary *library = get_builtin_library_from_type(ASSET_LIBRARY_LOCAL);
|
||||
AssetRepresentation &asset = add_dummy_asset(*library, "path/to/an/asset");
|
||||
|
||||
std::unique_ptr<AssetWeakReference> weak_ref = asset.make_weak_reference();
|
||||
|
||||
std::optional<AssetLibraryService::ExplodedPath> resolved_path =
|
||||
service->resolve_asset_weak_reference_to_exploded_path(*weak_ref);
|
||||
EXPECT_EQ(resolved_path->full_path, "path/to/an/asset");
|
||||
EXPECT_EQ(resolved_path->dir_component, "");
|
||||
EXPECT_EQ(resolved_path->group_component, "path");
|
||||
/* ID names may contain slashes. */
|
||||
EXPECT_EQ(resolved_path->name_component, "to/an/asset");
|
||||
}
|
||||
|
||||
/* #AssetLibraryService::resolve_asset_weak_reference_to_exploded_path(). */
|
||||
TEST_F(AssetRepresentationTest, weak_reference__resolve_to_exploded_path__custom_library)
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
AssetLibrary *const library = service->get_asset_library_on_disk_custom("My custom lib",
|
||||
asset_library_root_);
|
||||
AssetRepresentation &asset = add_dummy_asset(*library, "some.blend/Material/asset/name");
|
||||
|
||||
std::unique_ptr<AssetWeakReference> weak_ref = asset.make_weak_reference();
|
||||
|
||||
std::string expected_full_path = asset_library_root_ + "/some.blend/Material/asset/name";
|
||||
char *c_str = expected_full_path.data();
|
||||
BLI_path_slash_native(c_str);
|
||||
BLI_path_normalize(nullptr, c_str);
|
||||
expected_full_path = c_str;
|
||||
|
||||
std::string expected_dir_path = asset_library_root_ + "/some.blend";
|
||||
c_str = expected_dir_path.data();
|
||||
BLI_path_slash_native(c_str);
|
||||
BLI_path_normalize(nullptr, c_str);
|
||||
expected_dir_path = c_str;
|
||||
|
||||
std::optional<AssetLibraryService::ExplodedPath> resolved_path =
|
||||
service->resolve_asset_weak_reference_to_exploded_path(*weak_ref);
|
||||
EXPECT_EQ(resolved_path->full_path, expected_full_path);
|
||||
EXPECT_EQ(resolved_path->dir_component, expected_dir_path);
|
||||
EXPECT_EQ(resolved_path->group_component, "Material");
|
||||
/* ID names may contain slashes. */
|
||||
EXPECT_EQ(resolved_path->name_component, "asset/name");
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system::tests
|
@ -68,6 +68,13 @@ 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);
|
||||
AssetWeakReference *BKE_asset_weak_reference_copy(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
|
||||
|
95
source/blender/blenkernel/intern/asset_weak_reference.cc
Normal file
95
source/blender/blenkernel/intern/asset_weak_reference.cc
Normal file
@ -0,0 +1,95 @@
|
||||
/* 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()
|
||||
: asset_library_type(0), asset_library_identifier(nullptr), relative_asset_identifier(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
other.asset_library_type = 0; /* Not a valid type. */
|
||||
other.asset_library_identifier = nullptr;
|
||||
other.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;
|
||||
}
|
||||
|
||||
AssetWeakReference *BKE_asset_weak_reference_copy(AssetWeakReference *weak_ref)
|
||||
{
|
||||
if (weak_ref == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AssetWeakReference *weak_ref_copy = MEM_new<AssetWeakReference>(__func__);
|
||||
weak_ref_copy->asset_library_type = weak_ref->asset_library_type;
|
||||
weak_ref_copy->asset_library_identifier = BLI_strdup(weak_ref->asset_library_identifier);
|
||||
weak_ref_copy->relative_asset_identifier = BLI_strdup(weak_ref->relative_asset_identifier);
|
||||
|
||||
return weak_ref_copy;
|
||||
}
|
||||
|
||||
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
|
||||
@ -134,6 +144,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 {
|
||||
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). Null otherwise. */
|
||||
const char *asset_library_identifier;
|
||||
|
||||
const char *relative_asset_identifier;
|
||||
|
||||
#ifdef __cplusplus
|
||||
AssetWeakReference();
|
||||
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
|
||||
} AssetWeakReference;
|
||||
|
||||
/**
|
||||
* To be replaced by #AssetRepresentation!
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user