diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index c38da14be96..efd30ba8509 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -23,6 +23,7 @@ set(SRC_DNA_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_action_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_anim_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_asset_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_enums.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h new file mode 100644 index 00000000000..edd49dd9851 --- /dev/null +++ b/source/blender/blenkernel/BKE_asset.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __BKE_ASSET_H__ +#define __BKE_ASSET_H__ + +/** \file + * \ingroup bke + */ + +#include "BLI_utildefines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct BlendWriter; +struct BlendDataReader; +struct ID; +struct PreviewImage; + +struct AssetMetaData *BKE_asset_metadata_create(void); +void BKE_asset_metadata_free(struct AssetMetaData **asset_data); + +struct AssetTagEnsureResult { + struct AssetTag *tag; + /* Set to false if a tag of this name was already present. */ + bool is_new; +}; + +struct AssetTag *BKE_asset_metadata_tag_add(struct AssetMetaData *asset_data, const char *name); +struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(struct AssetMetaData *asset_data, + const char *name); +void BKE_asset_metadata_tag_remove(struct AssetMetaData *asset_data, struct AssetTag *tag); + +void BKE_asset_metadata_write(struct BlendWriter *writer, struct AssetMetaData *asset_data); +void BKE_asset_metadata_read(struct BlendDataReader *reader, struct AssetMetaData *asset_data); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_ASSET_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index d440d3e4d64..156d731d4a7 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -77,6 +77,7 @@ set(SRC intern/armature.c intern/armature_deform.c intern/armature_update.c + intern/asset.c intern/attribute.c intern/attribute_access.cc intern/autoexec.c @@ -271,6 +272,7 @@ set(SRC BKE_attribute.h BKE_attribute_access.hh BKE_autoexec.h + BKE_asset.h BKE_blender.h BKE_blender_copybuffer.h BKE_blender_undo.h diff --git a/source/blender/blenkernel/intern/asset.c b/source/blender/blenkernel/intern/asset.c new file mode 100644 index 00000000000..92400d10fe5 --- /dev/null +++ b/source/blender/blenkernel/intern/asset.c @@ -0,0 +1,143 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bke + */ + +#include + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" +#include "BLI_utildefines.h" + +#include "BKE_asset.h" +#include "BKE_icons.h" +#include "BKE_idprop.h" + +#include "DNA_ID.h" +#include "DNA_asset_types.h" +#include "DNA_defaults.h" + +#include "BLO_read_write.h" + +#include "MEM_guardedalloc.h" + +AssetMetaData *BKE_asset_metadata_create(void) +{ + AssetMetaData *asset_data = MEM_callocN(sizeof(*asset_data), __func__); + memcpy(asset_data, DNA_struct_default_get(AssetMetaData), sizeof(*asset_data)); + return asset_data; +} + +void BKE_asset_metadata_free(AssetMetaData **asset_data) +{ + if ((*asset_data)->properties) { + IDP_FreeProperty((*asset_data)->properties); + } + MEM_SAFE_FREE((*asset_data)->description); + BLI_freelistN(&(*asset_data)->tags); + + MEM_SAFE_FREE(*asset_data); +} + +static AssetTag *asset_metadata_tag_add(AssetMetaData *asset_data, const char *const name) +{ + AssetTag *tag = MEM_callocN(sizeof(*tag), __func__); + BLI_strncpy(tag->name, name, sizeof(tag->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; +} + +/** + * Make sure there is a tag with name \a name, create one if needed. + */ +struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(AssetMetaData *asset_data, + const char *name) +{ + struct AssetTagEnsureResult result = {.tag = NULL}; + if (!name[0]) { + return result; + } + + AssetTag *tag = 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); +} + +/* .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->description) { + BLO_write_string(writer, asset_data->description); + } + 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. */ + + 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->description); + BLO_read_list(reader, &asset_data->tags); + BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags); +} diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 8113417b55f..61b5e6f85bb 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -56,6 +56,7 @@ #include "BKE_anim_data.h" #include "BKE_armature.h" +#include "BKE_asset.h" #include "BKE_bpath.h" #include "BKE_context.h" #include "BKE_global.h" @@ -2362,6 +2363,10 @@ void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after) void BKE_id_blend_write(BlendWriter *writer, ID *id) { + if (id->asset_data) { + BKE_asset_metadata_write(writer, id->asset_data); + } + /* ID_WM's id->properties are considered runtime only, and never written in .blend file. */ if (id->properties && !ELEM(GS(id->name), ID_WM)) { IDP_BlendWrite(writer, id->properties); diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index 1e45a3c1163..7199bd0f13c 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -31,6 +31,7 @@ #include "BLI_listbase.h" #include "BKE_anim_data.h" +#include "BKE_asset.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_key.h" @@ -64,6 +65,10 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user) id->override_library = NULL; } + if (id->asset_data) { + BKE_asset_metadata_free(&id->asset_data); + } + BKE_animdata_free(id, do_id_user); } diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 0ab9a5e9e14..1d7c5d8a1d3 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -119,12 +119,20 @@ void BLO_blendfiledata_free(BlendFileData *bfd); /** \name BLO Blend File Handle API * \{ */ +struct BLODataBlockInfo { + char name[64]; /* MAX_NAME */ + struct AssetMetaData *asset_data; +}; + BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct ReportList *reports); BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize); struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names); +struct LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh, + int ofblocktype, + int *tot_info_items); struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev); struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh); diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 1aecba5ba90..3a1ccbeda01 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -159,6 +159,51 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, return names; } +/** + * Gets the names and asset-data (if ID is an asset) of all the data-blocks in a file of a certain + * type (e.g. all the scene names in a file). + * + * \param bh: The blendhandle to access. + * \param ofblocktype: The type of names to get. + * \param tot_info_items: The length of the returned list. + * \return A BLI_linklist of BLODataBlockInfo *. The links and #BLODataBlockInfo.asset_data should + * be freed with MEM_freeN. + */ +LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh, int ofblocktype, int *tot_info_items) +{ + FileData *fd = (FileData *)bh; + LinkNode *infos = NULL; + BHead *bhead; + int tot = 0; + + for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { + if (bhead->code == ofblocktype) { + struct BLODataBlockInfo *info = MEM_mallocN(sizeof(*info), __func__); + const char *name = blo_bhead_id_name(fd, bhead) + 2; + + STRNCPY(info->name, name); + + /* Lastly, read asset data from the following blocks. */ + info->asset_data = blo_bhead_id_asset_data_address(fd, bhead); + if (info->asset_data) { + bhead = blo_read_asset_data_block(fd, bhead, &info->asset_data); + /* blo_read_asset_data_block() reads all DATA heads and already advances bhead to the next + * non-DATA one. Go back, so the loop doesn't skip the non-DATA head. */ + bhead = blo_bhead_prev(fd, bhead); + } + + BLI_linklist_prepend(&infos, info); + tot++; + } + else if (bhead->code == ENDB) { + break; + } + } + + *tot_info_items = tot; + return infos; +} + /** * Gets the previews of all the data-blocks in a file of a certain type * (e.g. all the scene previews in a file). diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index fd10eac4302..8dff1aa1ed0 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -44,6 +44,7 @@ #define DNA_DEPRECATED_ALLOW #include "DNA_anim_types.h" +#include "DNA_asset_types.h" #include "DNA_cachefile_types.h" #include "DNA_collection_types.h" #include "DNA_fileglobal_types.h" @@ -73,6 +74,7 @@ #include "BKE_anim_data.h" #include "BKE_animsys.h" +#include "BKE_asset.h" #include "BKE_collection.h" #include "BKE_global.h" /* for G */ #include "BKE_idprop.h" @@ -957,12 +959,21 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock) } #endif /* USE_BHEAD_READ_ON_DEMAND */ -/* Warning! Caller's responsibility to ensure given bhead **is** and ID one! */ +/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead) { return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs); } +/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ +AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead) +{ + BLI_assert(BKE_idtype_idcode_is_valid(bhead->code)); + return (fd->id_asset_data_offs >= 0) ? + *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offs) : + NULL; +} + static void decode_blender_header(FileData *fd) { char header[SIZEOFBLENDERHEADER], num[4]; @@ -1040,6 +1051,8 @@ static bool read_file_dna(FileData *fd, const char **r_error_message) /* used to retrieve ID names from (bhead+1) */ fd->id_name_offs = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]"); BLI_assert(fd->id_name_offs != -1); + fd->id_asset_data_offs = DNA_elem_offset( + fd->filesdna, "ID", "AssetMetaData", "*asset_data"); return true; } @@ -2360,6 +2373,11 @@ static void direct_link_id_common( return; } + if (id->asset_data) { + BLO_read_data_address(reader, &id->asset_data); + BKE_asset_metadata_read(reader, id->asset_data); + } + /*link direct data of ID properties*/ if (id->properties) { BLO_read_data_address(reader, &id->properties); @@ -3607,6 +3625,27 @@ static BHead *read_libblock(FileData *fd, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Read Asset Data + * \{ */ + +BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data) +{ + BLI_assert(BKE_idtype_idcode_is_valid(bhead->code)); + + bhead = read_data_into_datamap(fd, bhead, "asset-data read"); + + BlendDataReader reader = {fd}; + BLO_read_data_address(&reader, r_asset_data); + BKE_asset_metadata_read(&reader, *r_asset_data); + + oldnewmap_clear(fd->datamap); + + return bhead; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Read Global Data * \{ */ diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index fb950e37da8..3e7cdb30e1f 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -112,6 +112,9 @@ typedef struct FileData { int fileversion; /** Used to retrieve ID names from (bhead+1). */ int id_name_offs; + /** Used to retrieve asset data from (bhead+1). NOTE: This may not be available in old files, + * will be -1 then! */ + int id_asset_data_offs; /** For do_versions patching. */ int globalf, fileflags; @@ -159,6 +162,8 @@ void blo_end_packed_pointer_map(FileData *fd, struct Main *oldmain); void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd); void blo_make_old_idmap_from_main(FileData *fd, struct Main *bmain); +BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, struct AssetMetaData **r_asset_data); + void blo_cache_storage_init(FileData *fd, struct Main *bmain); void blo_cache_storage_old_bmain_clear(FileData *fd, struct Main *bmain_old); void blo_cache_storage_end(FileData *fd); @@ -170,6 +175,7 @@ BHead *blo_bhead_next(FileData *fd, BHead *thisblock); BHead *blo_bhead_prev(FileData *fd, BHead *thisblock); const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead); +struct AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead); /* do versions stuff */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index f2d860a2851..84757e313ed 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -264,7 +264,12 @@ typedef struct IDOverrideLibrary { typedef struct ID { void *next, *prev; struct ID *newid; + struct Library *lib; + + /** If the ID is an asset, this pointer is set. Owning pointer. */ + struct AssetMetaData *asset_data; + /** MAX_ID_NAME. */ char name[66]; /** @@ -310,6 +315,7 @@ typedef struct ID { struct ID *orig_id; void *py_instance; + void *_pad1; } ID; /** diff --git a/source/blender/makesdna/DNA_asset_defaults.h b/source/blender/makesdna/DNA_asset_defaults.h new file mode 100644 index 00000000000..ff00ba79cf0 --- /dev/null +++ b/source/blender/makesdna/DNA_asset_defaults.h @@ -0,0 +1,37 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup DNA + */ + +#pragma once + +/* Struct members on own line. */ +/* clang-format off */ + +/* -------------------------------------------------------------------- */ +/** \name Asset Struct + * \{ */ + +#define _DNA_DEFAULT_AssetMetaData \ + { \ + 0 \ + } + +/** \} */ + +/* clang-format on */ diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h new file mode 100644 index 00000000000..671012e54ef --- /dev/null +++ b/source/blender/makesdna/DNA_asset_types.h @@ -0,0 +1,62 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup DNA + */ + +#ifndef __DNA_ASSET_TYPES_H__ +#define __DNA_ASSET_TYPES_H__ + +#include "DNA_listBase.h" + +/** + * \brief User defined tag. + * Currently only used by assets, could be used more often at some point. + * Maybe add a custom icon and color to these in future? + */ +typedef struct AssetTag { + struct AssetTag *next, *prev; + char name[64]; /* MAX_NAME */ +} AssetTag; + +/** + * \brief The meta-data of an asset. + * By creating and giving this for a data-block (#ID.asset_data), the data-block becomes an asset. + * + * \note This struct must be readable without having to read anything but blocks from the ID it is + * attached to! That way, asset information of a file can be read, without reading anything + * more than that from the file. So pointers to other IDs or ID data are strictly forbidden. + */ +typedef struct AssetMetaData { + /** Custom asset meta-data. Cannot store pointers to IDs (#STRUCT_NO_DATABLOCK_IDPROPERTIES)! */ + struct IDProperty *properties; + + /** Optional description of this asset for display in the UI. Dynamic length. */ + char *description; + /** User defined tags for this asset. The asset manager uses these for filtering, but how they + * function exactly (e.g. how they are registered to provide a list of searchable available tags) + * is up to the asset-engine. */ + ListBase tags; /* AssetTag */ + short active_tag; + /** Store the number of tags to avoid continuous counting. Could be turned into runtime data, we + * can always reliably reconstruct it from the list. */ + short tot_tags; + + char _pad[4]; +} AssetMetaData; + +#endif /* __DNA_ASSET_TYPES_H__ */ diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 2051335dd7e..a7adaa7e258 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -138,6 +138,7 @@ set(SRC ../../blenlib/intern/hash_mm2a.c ../../blenlib/intern/listbase.c + ../DNA_asset_defaults.h ../DNA_brush_defaults.h ../DNA_cachefile_defaults.h ../DNA_camera_defaults.h diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c index 1a8bd25215f..3e4d5d87fb0 100644 --- a/source/blender/makesdna/intern/dna_defaults.c +++ b/source/blender/makesdna/intern/dna_defaults.c @@ -85,6 +85,7 @@ #include "DNA_defaults.h" #include "DNA_armature_types.h" +#include "DNA_asset_types.h" #include "DNA_brush_types.h" #include "DNA_cachefile_types.h" #include "DNA_camera_types.h" @@ -117,6 +118,7 @@ #include "DNA_world_types.h" #include "DNA_armature_defaults.h" +#include "DNA_asset_defaults.h" #include "DNA_brush_defaults.h" #include "DNA_cachefile_defaults.h" #include "DNA_camera_defaults.h" @@ -148,6 +150,9 @@ #define SDNA_DEFAULT_DECL_STRUCT(struct_name) \ static const struct_name DNA_DEFAULT_##struct_name = _DNA_DEFAULT_##struct_name +/* DNA_asset_defaults.h */ +SDNA_DEFAULT_DECL_STRUCT(AssetMetaData); + /* DNA_armature_defaults.h */ SDNA_DEFAULT_DECL_STRUCT(bArmature); @@ -338,7 +343,10 @@ extern const bTheme U_theme_default; /** Keep headers sorted. */ const void *DNA_default_table[SDNA_TYPE_MAX] = { - /* DNA_arnature_defaults.h */ + /* DNA_asset_defaults.h */ + SDNA_DEFAULT_DECL(AssetMetaData), + + /* DNA_armature_defaults.h */ SDNA_DEFAULT_DECL(bArmature), /* DNA_brush_defaults.h */ diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 81a7da7b4d8..54d2bc88d16 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -139,6 +139,7 @@ static const char *includefiles[] = { "DNA_volume_types.h", "DNA_simulation_types.h", "DNA_pointcache_types.h", + "DNA_asset_types.h", /* see comment above before editing! */ @@ -1533,6 +1534,7 @@ int main(int argc, char **argv) #include "DNA_action_types.h" #include "DNA_anim_types.h" #include "DNA_armature_types.h" +#include "DNA_asset_types.h" #include "DNA_boid_types.h" #include "DNA_brush_types.h" #include "DNA_cachefile_types.h" diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 4aeb9b9e5f7..da15489370a 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -70,6 +70,8 @@ extern StructRNA RNA_ArrayGpencilModifier; extern StructRNA RNA_ArrayModifier; extern StructRNA RNA_Attribute; extern StructRNA RNA_AttributeGroup; +extern StructRNA RNA_AssetMetaData; +extern StructRNA RNA_AssetTag; extern StructRNA RNA_BackgroundImage; extern StructRNA RNA_BevelModifier; extern StructRNA RNA_BezierSplinePoint; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 3ebbb98934e..2ce1acb0074 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -31,6 +31,7 @@ set(DEFSRC rna_animviz.c rna_armature.c rna_attribute.c + rna_asset.c rna_boid.c rna_brush.c rna_cachefile.c diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 8b861d20e4e..c2c95c59002 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4270,6 +4270,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_animviz.c", NULL, RNA_def_animviz}, {"rna_armature.c", "rna_armature_api.c", RNA_def_armature}, {"rna_attribute.c", NULL, RNA_def_attribute}, + {"rna_asset.c", NULL, RNA_def_asset}, {"rna_boid.c", NULL, RNA_def_boid}, {"rna_brush.c", NULL, RNA_def_brush}, {"rna_cachefile.c", NULL, RNA_def_cachefile}, diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index f63cf0271b8..7c67bfc360b 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -1528,6 +1528,11 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "Library", "Library file the data-block is linked from"); + prop = RNA_def_property(srna, "asset_data", PROP_POINTER, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_ui_text(prop, "Asset Data", "Additional data for an asset data-block"); + prop = RNA_def_pointer( srna, "override_library", "IDOverrideLibrary", "Library Override", "Library override data"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c new file mode 100644 index 00000000000..1af53e95cc9 --- /dev/null +++ b/source/blender/makesrna/intern/rna_asset.c @@ -0,0 +1,228 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup RNA + */ + +#include + +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "DNA_asset_types.h" +#include "DNA_defs.h" + +#include "rna_internal.h" + +#ifdef RNA_RUNTIME + +# include "BKE_asset.h" +# include "BKE_idprop.h" + +# include "BLI_listbase.h" + +# include "RNA_access.h" + +static AssetTag *rna_AssetMetaData_tag_new(AssetMetaData *asset_data, + ReportList *reports, + const char *name, + bool skip_if_exists) +{ + AssetTag *tag = NULL; + + if (skip_if_exists) { + struct AssetTagEnsureResult result = BKE_asset_metadata_tag_ensure(asset_data, name); + + if (!result.is_new) { + BKE_reportf( + reports, RPT_WARNING, "Tag '%s' already present for given asset", result.tag->name); + /* Report, but still return valid item. */ + } + tag = result.tag; + } + else { + tag = BKE_asset_metadata_tag_add(asset_data, name); + } + + return tag; +} + +static void rna_AssetMetaData_tag_remove(AssetMetaData *asset_data, + ReportList *reports, + PointerRNA *tag_ptr) +{ + AssetTag *tag = tag_ptr->data; + if (BLI_findindex(&asset_data->tags, tag) == -1) { + BKE_reportf(reports, RPT_ERROR, "Tag '%s' not found in given asset", tag->name); + return; + } + + BKE_asset_metadata_tag_remove(asset_data, tag); + RNA_POINTER_INVALIDATE(tag_ptr); +} + +static IDProperty *rna_AssetMetaData_idprops(PointerRNA *ptr, bool create) +{ + AssetMetaData *asset_data = ptr->data; + + if (create && !asset_data->properties) { + IDPropertyTemplate val = {0}; + asset_data->properties = IDP_New(IDP_GROUP, &val, "RNA_AssetMetaData group"); + } + + return asset_data->properties; +} + +static void rna_AssetMetaData_description_get(PointerRNA *ptr, char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->description) { + strcpy(value, asset_data->description); + } + else { + value[0] = '\0'; + } +} + +static int rna_AssetMetaData_description_length(PointerRNA *ptr) +{ + AssetMetaData *asset_data = ptr->data; + return asset_data->description ? strlen(asset_data->description) : 0; +} + +static void rna_AssetMetaData_description_set(PointerRNA *ptr, const char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->description) { + MEM_freeN(asset_data->description); + } + + if (value[0]) { + asset_data->description = BLI_strdup(value); + } + else { + asset_data->description = NULL; + } +} + +static void rna_AssetMetaData_active_tag_range( + PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +{ + const AssetMetaData *asset_data = ptr->data; + *min = *softmin = 0; + *max = *softmax = MAX2(asset_data->tot_tags - 1, 0); +} + +#else + +static void rna_def_asset_tag(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "AssetTag", NULL); + RNA_def_struct_ui_text(srna, "Asset Tag", "User defined tag (name token)"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_maxlength(prop, MAX_NAME); + RNA_def_property_ui_text(prop, "Name", "The identifier that makes up this tag"); + RNA_def_struct_name_property(srna, prop); +} + +static void rna_def_asset_tags_api(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "AssetTags"); + srna = RNA_def_struct(brna, "AssetTags", NULL); + RNA_def_struct_sdna(srna, "AssetMetaData"); + RNA_def_struct_ui_text(srna, "Asset Tags", "Collection of custom asset tags"); + + /* Tag collection */ + func = RNA_def_function(srna, "new", "rna_AssetMetaData_tag_new"); + RNA_def_function_ui_description(func, "Add a new tag to this asset"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_boolean(func, + "skip_if_exists", + false, + "Skip if Exists", + "Do not add a new tag if one of the same type already exists"); + /* return type */ + parm = RNA_def_pointer(func, "tag", "AssetTag", "", "New tag"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_AssetMetaData_tag_remove"); + RNA_def_function_ui_description(func, "Remove an existing tag from this asset"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + /* tag to remove */ + parm = RNA_def_pointer(func, "tag", "AssetTag", "", "Removed tag"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); +} + +static void rna_def_asset_data(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "AssetMetaData", NULL); + RNA_def_struct_ui_text(srna, "Asset Data", "Additional data stored for an asset data-block"); + // RNA_def_struct_ui_icon(srna, ICON_ASSET); /* TODO: Icon doesn't exist!. */ + /* The struct has custom properties, but no pointer properties to other IDs! */ + RNA_def_struct_idprops_func(srna, "rna_AssetMetaData_idprops"); + RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); /* Mandatory! */ + + prop = RNA_def_property(srna, "description", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, + "rna_AssetMetaData_description_get", + "rna_AssetMetaData_description_length", + "rna_AssetMetaData_description_set"); + RNA_def_property_ui_text( + prop, "Description", "A description of the asset to be displayed for the user"); + + prop = RNA_def_property(srna, "tags", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "AssetTag"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Tags", + "Custom tags (name tokens) for the asset, used for filtering and " + "general asset management"); + rna_def_asset_tags_api(brna, prop); + + prop = RNA_def_property(srna, "active_tag", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs(prop, NULL, NULL, "rna_AssetMetaData_active_tag_range"); + RNA_def_property_ui_text(prop, "Active Tag", "Index of the tag set for editing"); +} + +void RNA_def_asset(BlenderRNA *brna) +{ + RNA_define_animate_sdna(false); + + rna_def_asset_tag(brna); + rna_def_asset_data(brna); + + RNA_define_animate_sdna(true); +} + +#endif diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index d4fdac390b2..76c3e17e128 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -152,6 +152,7 @@ void RNA_def_animation(struct BlenderRNA *brna); void RNA_def_animviz(struct BlenderRNA *brna); void RNA_def_armature(struct BlenderRNA *brna); void RNA_def_attribute(struct BlenderRNA *brna); +void RNA_def_asset(struct BlenderRNA *brna); void RNA_def_boid(struct BlenderRNA *brna); void RNA_def_brush(struct BlenderRNA *brna); void RNA_def_cachefile(struct BlenderRNA *brna);