Asset data can now be copied in Python via assignment to `id.asset_data`, so for example `dest.asset_data = source.asset_data`. This copies the description, license, author, etc. fields, as well as the tags and the asset catalog assignment. This is intended to be used in the pose library, when updating a pose by simply creating a new asset and having that replace the old one. This is intentionally taking a copy, even though the above use case could have sufficed with a higher-level 'move' function. By exposing this as a copy, it can be used in a wider range of situations, from whatever Python code wants to use it. This could include copying the asset data from the active asset to all the other selected ones. Any pre-existing asset data is freed before the copy is assigned. The target ID MUST be marked as asset already for the assignment to work. Assigning `None` to clear the asset status is not allowed. Instead `.asset_mark()` resp. `.asset_clear()` should be used. This limitation is in place to simplify the API, and to ensure that there is only one way in which assets are marked/cleared, making it easier to change the internals of the asset system without API changes. Example code: ```python src = bpy.data.objects['Suzanne'] dst = bpy.data.objects['Cube'] dst.asset_mark() dst.asset_data = src.asset_data ``` Pull Request: https://projects.blender.org/blender/blender/pulls/108547
234 lines
6.5 KiB
C++
234 lines
6.5 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
*/
|
|
|
|
#include <cstring>
|
|
|
|
#include "DNA_ID.h"
|
|
#include "DNA_defaults.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_string.h"
|
|
#include "BLI_string_ref.hh"
|
|
#include "BLI_string_utils.h"
|
|
#include "BLI_uuid.h"
|
|
|
|
#include "BKE_asset.h"
|
|
#include "BKE_icons.h"
|
|
#include "BKE_idprop.h"
|
|
|
|
#include "BLO_read_write.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
using namespace blender;
|
|
|
|
AssetMetaData *BKE_asset_metadata_create()
|
|
{
|
|
const AssetMetaData *default_metadata = DNA_struct_default_get(AssetMetaData);
|
|
return MEM_new<AssetMetaData>(__func__, *default_metadata);
|
|
}
|
|
|
|
void BKE_asset_metadata_free(AssetMetaData **asset_data)
|
|
{
|
|
MEM_delete(*asset_data);
|
|
*asset_data = nullptr;
|
|
}
|
|
|
|
AssetMetaData *BKE_asset_metadata_copy(const AssetMetaData *source)
|
|
{
|
|
AssetMetaData *copy = BKE_asset_metadata_create();
|
|
|
|
copy->local_type_info = source->local_type_info;
|
|
|
|
if (source->properties) {
|
|
copy->properties = IDP_CopyProperty(source->properties);
|
|
}
|
|
|
|
BKE_asset_metadata_catalog_id_set(copy, source->catalog_id, source->catalog_simple_name);
|
|
|
|
if (source->author) {
|
|
copy->author = BLI_strdup(source->author);
|
|
}
|
|
if (source->description) {
|
|
copy->description = BLI_strdup(source->description);
|
|
}
|
|
if (source->copyright) {
|
|
copy->copyright = BLI_strdup(source->copyright);
|
|
}
|
|
if (source->license) {
|
|
copy->license = BLI_strdup(source->license);
|
|
}
|
|
|
|
BLI_duplicatelist(©->tags, &source->tags);
|
|
copy->active_tag = source->active_tag;
|
|
copy->tot_tags = source->tot_tags;
|
|
|
|
return copy;
|
|
}
|
|
|
|
AssetMetaData::~AssetMetaData()
|
|
{
|
|
if (properties) {
|
|
IDP_FreeProperty(properties);
|
|
}
|
|
MEM_SAFE_FREE(author);
|
|
MEM_SAFE_FREE(description);
|
|
MEM_SAFE_FREE(copyright);
|
|
MEM_SAFE_FREE(license);
|
|
BLI_freelistN(&tags);
|
|
}
|
|
|
|
static AssetTag *asset_metadata_tag_add(AssetMetaData *asset_data, const char *const name)
|
|
{
|
|
AssetTag *tag = (AssetTag *)MEM_callocN(sizeof(*tag), __func__);
|
|
STRNCPY(tag->name, name);
|
|
|
|
BLI_addtail(&asset_data->tags, tag);
|
|
asset_data->tot_tags++;
|
|
/* Invariant! */
|
|
BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
|
|
|
|
return tag;
|
|
}
|
|
|
|
AssetTag *BKE_asset_metadata_tag_add(AssetMetaData *asset_data, const char *name)
|
|
{
|
|
AssetTag *tag = asset_metadata_tag_add(asset_data, name);
|
|
BLI_uniquename(&asset_data->tags, tag, name, '.', offsetof(AssetTag, name), sizeof(tag->name));
|
|
return tag;
|
|
}
|
|
|
|
AssetTagEnsureResult BKE_asset_metadata_tag_ensure(AssetMetaData *asset_data, const char *name)
|
|
{
|
|
AssetTagEnsureResult result = {nullptr};
|
|
if (!name[0]) {
|
|
return result;
|
|
}
|
|
|
|
AssetTag *tag = (AssetTag *)BLI_findstring(&asset_data->tags, name, offsetof(AssetTag, name));
|
|
|
|
if (tag) {
|
|
result.tag = tag;
|
|
result.is_new = false;
|
|
return result;
|
|
}
|
|
|
|
tag = asset_metadata_tag_add(asset_data, name);
|
|
|
|
result.tag = tag;
|
|
result.is_new = true;
|
|
return result;
|
|
}
|
|
|
|
void BKE_asset_metadata_tag_remove(AssetMetaData *asset_data, AssetTag *tag)
|
|
{
|
|
BLI_assert(BLI_findindex(&asset_data->tags, tag) >= 0);
|
|
BLI_freelinkN(&asset_data->tags, tag);
|
|
asset_data->tot_tags--;
|
|
/* Invariant! */
|
|
BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
|
|
}
|
|
|
|
void BKE_asset_library_reference_init_default(AssetLibraryReference *library_ref)
|
|
{
|
|
memcpy(library_ref, DNA_struct_default_get(AssetLibraryReference), sizeof(*library_ref));
|
|
}
|
|
|
|
void BKE_asset_metadata_catalog_id_clear(AssetMetaData *asset_data)
|
|
{
|
|
asset_data->catalog_id = BLI_uuid_nil();
|
|
asset_data->catalog_simple_name[0] = '\0';
|
|
}
|
|
|
|
void BKE_asset_metadata_catalog_id_set(AssetMetaData *asset_data,
|
|
const ::bUUID catalog_id,
|
|
const char *catalog_simple_name)
|
|
{
|
|
asset_data->catalog_id = catalog_id;
|
|
|
|
constexpr size_t max_simple_name_length = sizeof(asset_data->catalog_simple_name);
|
|
|
|
/* The substr() call is necessary to make copy() copy the first N characters (instead of refusing
|
|
* to copy and producing an empty string). */
|
|
StringRef trimmed_id =
|
|
StringRef(catalog_simple_name).trim().substr(0, max_simple_name_length - 1);
|
|
trimmed_id.copy(asset_data->catalog_simple_name, max_simple_name_length);
|
|
}
|
|
|
|
void BKE_asset_metadata_idprop_ensure(AssetMetaData *asset_data, IDProperty *prop)
|
|
{
|
|
if (!asset_data->properties) {
|
|
IDPropertyTemplate val = {0};
|
|
asset_data->properties = IDP_New(IDP_GROUP, &val, "AssetMetaData.properties");
|
|
}
|
|
/* Important: The property may already exist. For now just allow always allow a newly allocated
|
|
* property, and replace the existing one as a way of updating. */
|
|
IDP_ReplaceInGroup(asset_data->properties, prop);
|
|
}
|
|
|
|
IDProperty *BKE_asset_metadata_idprop_find(const AssetMetaData *asset_data, const char *name)
|
|
{
|
|
if (!asset_data->properties) {
|
|
return nullptr;
|
|
}
|
|
return IDP_GetPropertyFromGroup(asset_data->properties, name);
|
|
}
|
|
|
|
/* Queries -------------------------------------------- */
|
|
|
|
PreviewImage *BKE_asset_metadata_preview_get_from_id(const AssetMetaData * /*asset_data*/,
|
|
const ID *id)
|
|
{
|
|
return BKE_previewimg_id_get(id);
|
|
}
|
|
|
|
/* .blend file API -------------------------------------------- */
|
|
|
|
void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data)
|
|
{
|
|
BLO_write_struct(writer, AssetMetaData, asset_data);
|
|
|
|
if (asset_data->properties) {
|
|
IDP_BlendWrite(writer, asset_data->properties);
|
|
}
|
|
if (asset_data->author) {
|
|
BLO_write_string(writer, asset_data->author);
|
|
}
|
|
if (asset_data->description) {
|
|
BLO_write_string(writer, asset_data->description);
|
|
}
|
|
if (asset_data->copyright) {
|
|
BLO_write_string(writer, asset_data->copyright);
|
|
}
|
|
if (asset_data->license) {
|
|
BLO_write_string(writer, asset_data->license);
|
|
}
|
|
|
|
LISTBASE_FOREACH (AssetTag *, tag, &asset_data->tags) {
|
|
BLO_write_struct(writer, AssetTag, tag);
|
|
}
|
|
}
|
|
|
|
void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data)
|
|
{
|
|
/* asset_data itself has been read already. */
|
|
asset_data->local_type_info = nullptr;
|
|
|
|
if (asset_data->properties) {
|
|
BLO_read_data_address(reader, &asset_data->properties);
|
|
IDP_BlendDataRead(reader, &asset_data->properties);
|
|
}
|
|
|
|
BLO_read_data_address(reader, &asset_data->author);
|
|
BLO_read_data_address(reader, &asset_data->description);
|
|
BLO_read_data_address(reader, &asset_data->copyright);
|
|
BLO_read_data_address(reader, &asset_data->license);
|
|
BLO_read_list(reader, &asset_data->tags);
|
|
BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
|
|
}
|