Asset system: Initial asset identifier type

No user visible changes expected.

`AssetIdentifier` holds information to uniquely identify and locate an
asset. More information:
https://wiki.blender.org/wiki/Source/Architecture/Asset_System/Back_End#Asset_Identifier

For the start this is tied quite a bit to file paths, so that external
assets are assumed to be in the file system.

This is needed to support an "All" asset library (see T102879), which
would contain assets from different locations. Currently the location of
an asset is queried via the file browser backend, which however requires
a common root location. It also moves us further away from the file
browser towards the asset system (see T87235) and allows us to remove
some hacks (see following commit).
This commit is contained in:
Julian Eisel 2022-11-30 18:12:42 +01:00
parent cfaca0d9ab
commit f68da703a5
10 changed files with 150 additions and 33 deletions

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup asset_system
*
* \brief Information to uniquely identify and locate an asset.
*
* https://wiki.blender.org/wiki/Source/Architecture/Asset_System/Back_End#Asset_Identifier
*/
#pragma once
#include <memory>
#include <string>
namespace blender::asset_system {
class AssetIdentifier {
std::shared_ptr<std::string> library_root_path_;
std::string relative_asset_path_;
public:
AssetIdentifier(std::shared_ptr<std::string> library_root_path, std::string relative_asset_path);
AssetIdentifier(AssetIdentifier &&) = default;
AssetIdentifier(const AssetIdentifier &) = default;
std::string full_path() const;
};
} // namespace blender::asset_system

View File

@ -24,6 +24,7 @@ struct Main;
namespace blender::asset_system {
class AssetIdentifier;
class AssetRepresentation;
class AssetStorage;
@ -35,8 +36,10 @@ class AssetStorage;
*/
class AssetLibrary {
/** If this is an asset library on disk, the top-level directory path. Normalized using
* #normalize_directory_path().*/
std::string root_path_;
* #normalize_directory_path(). Shared pointer so assets can safely point to it, and don't have
* to hold a copy (which is the size of `std::string` + the allocated buffer, if no short string
* optimization is used). With thousands of assets this might make a reasonable difference. */
std::shared_ptr<std::string> root_path_;
/** Storage for assets (better said their representations) that are considered to be part of this
* library. Assets are not automatically loaded into this when loading an asset library. Assets
@ -79,10 +82,16 @@ class AssetLibrary {
* representation is not needed anymore, it must be freed using #remove_asset(), or there will be
* leaking that's only cleared when the library storage is destructed (typically on exit or
* loading a different file).
*
* \param relative_asset_path: The path of the asset relative to the asset library root. With
* this the asset must be uniquely identifiable within the asset
* library.
*/
AssetRepresentation &add_external_asset(StringRef name, std::unique_ptr<AssetMetaData> metadata);
AssetRepresentation &add_external_asset(StringRef relative_asset_path,
StringRef name,
std::unique_ptr<AssetMetaData> metadata);
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_local_id_asset(ID &id);
AssetRepresentation &add_local_id_asset(StringRef relative_asset_path, ID &id);
/** Remove an asset from the library that was added using #add_external_asset() or
* #add_local_id_asset(). Can usually be expected to be constant time complexity (worst case may
* differ).
@ -112,6 +121,12 @@ class AssetLibrary {
void on_blend_save_post(Main *bmain, PointerRNA **pointers, int num_pointers);
/**
* Create an asset identifier from the root path of this asset library and the given relative
* asset path (relative to the asset library root directory).
*/
AssetIdentifier derive_asset_identifier(StringRef relative_asset_path);
StringRefNull root_path() const;
private:

View File

@ -16,21 +16,23 @@
#include "BLI_string_ref.hh"
#include "AS_asset_identifier.hh"
struct AssetMetaData;
struct ID;
namespace blender::asset_system {
class AssetRepresentation {
struct ExternalAsset {
std::string name;
std::unique_ptr<AssetMetaData> metadata_ = nullptr;
};
AssetIdentifier identifier_;
/** Indicate if this is a local or external asset, and as such, which of the union members below
* should be used. */
const bool is_local_id_ = false;
struct ExternalAsset {
std::string name;
std::unique_ptr<AssetMetaData> metadata_ = nullptr;
};
union {
ExternalAsset external_asset_;
ID *local_asset_id_ = nullptr; /* Non-owning. */
@ -40,10 +42,12 @@ class AssetRepresentation {
public:
/** Constructs an asset representation for an external ID. The asset will not be editable. */
explicit AssetRepresentation(StringRef name, std::unique_ptr<AssetMetaData> metadata);
AssetRepresentation(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata);
/** Constructs an asset representation for an ID stored in the current file. This makes the asset
* local and fully editable. */
explicit AssetRepresentation(ID &id);
AssetRepresentation(AssetIdentifier &&identifier, ID &id);
AssetRepresentation(AssetRepresentation &&other);
/* Non-copyable type. */
AssetRepresentation(const AssetRepresentation &other) = delete;
@ -55,6 +59,8 @@ class AssetRepresentation {
/* Non-copyable type. */
AssetRepresentation &operator=(const AssetRepresentation &other) = delete;
const AssetIdentifier &get_identifier() const;
StringRefNull get_name() const;
AssetMetaData &get_metadata() const;
/** Returns if this asset is stored inside this current file, and as such fully editable. */
@ -62,3 +68,8 @@ class AssetRepresentation {
};
} // namespace blender::asset_system
/* C-Handle */
struct AssetRepresentation;
const std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);

View File

@ -17,6 +17,7 @@ set(SRC
intern/asset_catalog.cc
intern/asset_catalog_path.cc
intern/asset_catalog_tree.cc
intern/asset_identifier.cc
intern/asset_library.cc
intern/asset_library_service.cc
intern/asset_representation.cc
@ -26,6 +27,7 @@ set(SRC
AS_asset_catalog.hh
AS_asset_catalog_path.hh
AS_asset_catalog_tree.hh
AS_asset_identifier.hh
AS_asset_library.hh
AS_asset_representation.hh
intern/asset_library_service.hh

View File

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup asset_system
*/
#include "BLI_path_util.h"
#include <iostream>
#include "AS_asset_identifier.hh"
namespace blender::asset_system {
AssetIdentifier::AssetIdentifier(std::shared_ptr<std::string> library_root_path,
std::string relative_asset_path)
: library_root_path_(library_root_path), relative_asset_path_(relative_asset_path)
{
}
std::string AssetIdentifier::full_path() const
{
char path[FILE_MAX];
BLI_path_join(path, sizeof(path), library_root_path_->c_str(), relative_asset_path_.c_str());
return path;
}
} // namespace blender::asset_system

View File

@ -7,6 +7,7 @@
#include <memory>
#include "AS_asset_catalog_tree.hh"
#include "AS_asset_identifier.hh"
#include "AS_asset_library.h"
#include "AS_asset_library.hh"
#include "AS_asset_representation.hh"
@ -122,7 +123,7 @@ void AS_asset_library_remap_ids(const IDRemapper *mappings)
namespace blender::asset_system {
AssetLibrary::AssetLibrary(StringRef root_path)
: root_path_(utils::normalize_directory_path(root_path)),
: 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>())
{
@ -147,15 +148,18 @@ void AssetLibrary::refresh()
this->catalog_service->reload_catalogs();
}
AssetRepresentation &AssetLibrary::add_external_asset(StringRef name,
AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_path,
StringRef name,
std::unique_ptr<AssetMetaData> metadata)
{
return asset_storage_->add_external_asset(name, std::move(metadata));
AssetIdentifier identifier = derive_asset_identifier(relative_asset_path);
return asset_storage_->add_external_asset(std::move(identifier), name, std::move(metadata));
}
AssetRepresentation &AssetLibrary::add_local_id_asset(ID &id)
AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id)
{
return asset_storage_->add_local_id_asset(id);
AssetIdentifier identifier = derive_asset_identifier(relative_asset_path);
return asset_storage_->add_local_id_asset(std::move(identifier), id);
}
bool AssetLibrary::remove_asset(AssetRepresentation &asset)
@ -211,6 +215,11 @@ void AssetLibrary::on_blend_save_post(struct Main *main,
}
}
AssetIdentifier AssetLibrary::derive_asset_identifier(StringRef relative_asset_path)
{
return AssetIdentifier(root_path_, relative_asset_path);
}
void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data)
{
if (BLI_uuid_is_nil(asset_data->catalog_id)) {
@ -228,7 +237,7 @@ void AssetLibrary::refresh_catalog_simplename(struct AssetMetaData *asset_data)
StringRefNull AssetLibrary::root_path() const
{
return root_path_;
return *root_path_;
}
Vector<AssetLibraryReference> all_valid_asset_library_refs()

View File

@ -9,6 +9,7 @@
#include "DNA_ID.h"
#include "DNA_asset_types.h"
#include "AS_asset_identifier.hh"
#include "AS_asset_representation.h"
#include "AS_asset_representation.hh"
@ -16,14 +17,17 @@
namespace blender::asset_system {
AssetRepresentation::AssetRepresentation(StringRef name, std::unique_ptr<AssetMetaData> metadata)
: is_local_id_(false), external_asset_()
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata)
: identifier_(identifier), is_local_id_(false), external_asset_()
{
external_asset_.name = name;
external_asset_.metadata_ = std::move(metadata);
}
AssetRepresentation::AssetRepresentation(ID &id) : is_local_id_(true), local_asset_id_(&id)
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier, ID &id)
: identifier_(identifier), is_local_id_(true), local_asset_id_(&id)
{
if (!id.asset_data) {
throw std::invalid_argument("Passed ID is not an asset");
@ -31,7 +35,7 @@ AssetRepresentation::AssetRepresentation(ID &id) : is_local_id_(true), local_ass
}
AssetRepresentation::AssetRepresentation(AssetRepresentation &&other)
: is_local_id_(other.is_local_id_)
: identifier_(std::move(other.identifier_)), is_local_id_(other.is_local_id_)
{
if (is_local_id_) {
local_asset_id_ = other.local_asset_id_;
@ -49,6 +53,11 @@ AssetRepresentation::~AssetRepresentation()
}
}
const AssetIdentifier &AssetRepresentation::get_identifier() const
{
return identifier_;
}
StringRefNull AssetRepresentation::get_name() const
{
if (is_local_id_) {
@ -70,12 +79,20 @@ bool AssetRepresentation::is_local_id() const
} // namespace blender::asset_system
using namespace blender;
const std::string AS_asset_representation_full_path_get(const AssetRepresentation *asset_handle)
{
const asset_system::AssetRepresentation *asset =
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
const asset_system::AssetIdentifier &identifier = asset->get_identifier();
return identifier.full_path();
}
/* ---------------------------------------------------------------------- */
/** \name C-API
* \{ */
using namespace blender;
const char *AS_asset_representation_name_get(const AssetRepresentation *asset_handle)
{
const asset_system::AssetRepresentation *asset =

View File

@ -15,16 +15,18 @@
namespace blender::asset_system {
AssetRepresentation &AssetStorage::add_local_id_asset(ID &id)
AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier, ID &id)
{
return *local_id_assets_.lookup_key_or_add(std::make_unique<AssetRepresentation>(id));
return *local_id_assets_.lookup_key_or_add(
std::make_unique<AssetRepresentation>(std::move(identifier), id));
}
AssetRepresentation &AssetStorage::add_external_asset(StringRef name,
AssetRepresentation &AssetStorage::add_external_asset(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata)
{
return *external_assets_.lookup_key_or_add(
std::make_unique<AssetRepresentation>(name, std::move(metadata)));
std::make_unique<AssetRepresentation>(std::move(identifier), name, std::move(metadata)));
}
bool AssetStorage::remove_asset(AssetRepresentation &asset)

View File

@ -19,6 +19,7 @@ struct IDRemapper;
namespace blender::asset_system {
class AssetIdentifier;
class AssetRepresentation;
class AssetStorage {
@ -32,9 +33,11 @@ class AssetStorage {
public:
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_external_asset(StringRef name, std::unique_ptr<AssetMetaData> metadata);
AssetRepresentation &add_external_asset(AssetIdentifier &&identifier,
StringRef name,
std::unique_ptr<AssetMetaData> metadata);
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_local_id_asset(ID &id);
AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier, ID &id);
/** See #AssetLibrary::remove_asset(). */
bool remove_asset(AssetRepresentation &asset);

View File

@ -3099,8 +3099,8 @@ static void filelist_readjob_list_lib_add_datablock(FileListReadJob *job_params,
datablock_info->asset_data);
BKE_asset_metadata_free(&datablock_info->asset_data);
entry->asset = &filelist->asset_library->add_external_asset(datablock_info->name,
std::move(metadata));
entry->asset = &filelist->asset_library->add_external_asset(
entry->relpath, datablock_info->name, std::move(metadata));
}
}
}
@ -3745,7 +3745,8 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name));
entry = MEM_cnew<FileListInternEntry>(__func__);
entry->relpath = current_relpath_append(job_params, id_code_name);
std::string datablock_path = StringRef(id_code_name) + "/" + (id_iter->name + 2);
entry->relpath = current_relpath_append(job_params, datablock_path.c_str());
entry->name = id_iter->name + 2;
entry->free_name = false;
entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_ASSET;
@ -3755,7 +3756,7 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
id_iter);
entry->local_data.id = id_iter;
if (filelist->asset_library) {
entry->asset = &filelist->asset_library->add_local_id_asset(*id_iter);
entry->asset = &filelist->asset_library->add_local_id_asset(entry->relpath, *id_iter);
}
entries_num++;
BLI_addtail(&tmp_entries, entry);