WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 370 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
4 changed files with 75 additions and 72 deletions
Showing only changes of commit a800bdc473 - Show all commits

View File

@ -26,6 +26,8 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include "BLI_string_ref.hh"
#include "AS_asset_catalog.hh" #include "AS_asset_catalog.hh"
#include "DNA_ID_enums.h" #include "DNA_ID_enums.h"
@ -44,24 +46,24 @@ ID *asset_edit_id_from_weak_reference(Main &global_main,
const AssetWeakReference &weak_ref); const AssetWeakReference &weak_ref);
/** Get main database that a given asset datablock corresponds to. */ /** Get main database that a given asset datablock corresponds to. */
Main *asset_edit_main(const ID *id); Main *asset_edit_main(const ID &id);
/** Asset editing operations. */ /** Asset editing operations. */
bool asset_edit_id_is_editable(const ID *id); bool asset_edit_id_is_editable(const ID &id);
std::optional<std::string> asset_edit_id_save_as( std::optional<std::string> asset_edit_id_save_as(
Main &global_main, Main &global_main,
const ID *id, const ID &id,
const char *name, StringRef name,
std::optional<blender::asset_system::CatalogID> catalog_id, std::optional<blender::asset_system::CatalogID> catalog_id,
std::optional<std::string> catalog_simple_name, std::optional<std::string> catalog_simple_name,
const bUserAssetLibrary *user_library, const bUserAssetLibrary &user_library,
ReportList *reports); ReportList &reports);
bool asset_edit_id_save(Main &global_main, const ID *id, ReportList *reports); bool asset_edit_id_save(Main &global_main, const ID &id, ReportList &reports);
bool asset_edit_id_revert(Main &global_main, const ID *id, ReportList *reports); bool asset_edit_id_revert(Main &global_main, const ID &id, ReportList &reports);
bool asset_edit_id_delete(Main &global_main, const ID *id, ReportList *reports); bool asset_edit_id_delete(Main &global_main, const ID &id, ReportList &reports);
/** Clean up on exit. */ /** Clean up on exit. */
void asset_edit_main_free_all(); void asset_edit_main_free_all();

View File

@ -155,21 +155,23 @@ static std::string asset_root_path_for_save(const bUserAssetLibrary &user_librar
return std::string(libpath) + SEP + "Saved" + SEP + name; return std::string(libpath) + SEP + "Saved" + SEP + name;
} }
static std::string asset_blendfile_path_for_save(ReportList *reports, static std::string asset_blendfile_path_for_save(const bUserAssetLibrary &user_library,
const bUserAssetLibrary &user_library, const StringRef base_name,
const StringRefNull base_name, const ID_Type id_type,
const ID_Type id_type) ReportList &reports)
{ {
std::string root_path = asset_root_path_for_save(user_library, id_type); std::string root_path = asset_root_path_for_save(user_library, id_type);
BLI_assert(!root_path.empty()); BLI_assert(!root_path.empty());
if (!BLI_dir_create_recursive(root_path.c_str())) { if (!BLI_dir_create_recursive(root_path.c_str())) {
BKE_report(reports, RPT_ERROR, "Failed to create asset library directory to save brush"); BKE_report(&reports, RPT_ERROR, "Failed to create asset library directory to save brush");
return ""; return "";
} }
char base_name_filesafe[FILE_MAXFILE]; char base_name_filesafe[FILE_MAXFILE];
BLI_strncpy(base_name_filesafe, base_name.c_str(), sizeof(base_name_filesafe)); BLI_strncpy(base_name_filesafe,
base_name.data(),
std::min(sizeof(base_name_filesafe), size_t(base_name.size())));
BLI_path_make_safe_filename(base_name_filesafe); BLI_path_make_safe_filename(base_name_filesafe);
const std::string filepath = root_path + SEP + base_name_filesafe + BLENDER_ASSET_FILE_SUFFIX; const std::string filepath = root_path + SEP + base_name_filesafe + BLENDER_ASSET_FILE_SUFFIX;
@ -189,13 +191,13 @@ static std::string asset_blendfile_path_for_save(ReportList *reports,
} }
static bool asset_write_in_library(Main *bmain, static bool asset_write_in_library(Main *bmain,
const ID *id_const, const ID &id_const,
const char *name, const StringRef name,
const StringRefNull filepath, const StringRefNull filepath,
const std::optional<asset_system::CatalogID> catalog, const std::optional<asset_system::CatalogID> catalog,
const std::optional<StringRefNull> catalog_simple_name, const std::optional<StringRefNull> catalog_simple_name,
std::string &final_full_file_path, std::string &final_full_file_path,
ReportList *reports) ReportList &reports)
{ {
/* XXX /* XXX
* FIXME * FIXME
@ -216,41 +218,41 @@ static bool asset_write_in_library(Main *bmain,
* - `BKE_blendfile_write_partial_end` frees the temp Main. * - `BKE_blendfile_write_partial_end` frees the temp Main.
*/ */
ID *id = const_cast<ID *>(id_const); ID &id = const_cast<ID &>(id_const);
const short prev_flag = id->flag; const short prev_flag = id.flag;
const int prev_tag = id->tag; const int prev_tag = id.tag;
const int prev_us = id->us; const int prev_us = id.us;
const std::string prev_name = id->name + 2; const std::string prev_name = id.name + 2;
IDOverrideLibrary *prev_liboverride = id->override_library; IDOverrideLibrary *prev_liboverride = id.override_library;
AssetMetaData *asset_data = id->asset_data; AssetMetaData *asset_data = id.asset_data;
const int write_flags = 0; /* Could use #G_FILE_COMPRESS ? */ const int write_flags = 0; /* Could use #G_FILE_COMPRESS ? */
const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE; const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE;
BKE_blendfile_write_partial_begin(bmain); BKE_blendfile_write_partial_begin(bmain);
id->flag |= LIB_FAKEUSER; id.flag |= LIB_FAKEUSER;
id->tag &= ~LIB_TAG_RUNTIME; id.tag &= ~LIB_TAG_RUNTIME;
id->us = 1; id.us = 1;
BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2); BLI_strncpy(id.name + 2, name.data(), std::min(sizeof(id.name) - 2, size_t(name.size())));
if (!ID_IS_ASSET(id)) { if (!ID_IS_ASSET(&id)) {
id->asset_data = id->override_library->reference->asset_data; id.asset_data = id.override_library->reference->asset_data;
} }
id->override_library = nullptr; id.override_library = nullptr;
if (catalog) { if (catalog) {
id->asset_data->catalog_id = *catalog; id.asset_data->catalog_id = *catalog;
} }
if (catalog_simple_name) { if (catalog_simple_name) {
STRNCPY(id->asset_data->catalog_simple_name, catalog_simple_name->c_str()); STRNCPY(id.asset_data->catalog_simple_name, catalog_simple_name->c_str());
} }
BKE_blendfile_write_partial_tag_ID(id, true); BKE_blendfile_write_partial_tag_ID(&id, true);
/* TODO: check overwriting existing file. */ /* TODO: check overwriting existing file. */
/* TODO: ensure filepath contains only valid characters for file system. */ /* TODO: ensure filepath contains only valid characters for file system. */
const bool sucess = BKE_blendfile_write_partial( const bool sucess = BKE_blendfile_write_partial(
bmain, filepath.c_str(), write_flags, remap_mode, reports); bmain, filepath.c_str(), write_flags, remap_mode, &reports);
if (sucess) { if (sucess) {
final_full_file_path = std::string(filepath) + SEP + "Brush" + SEP + name; final_full_file_path = std::string(filepath) + SEP + "Brush" + SEP + name;
@ -258,13 +260,13 @@ static bool asset_write_in_library(Main *bmain,
BKE_blendfile_write_partial_end(bmain); BKE_blendfile_write_partial_end(bmain);
BKE_blendfile_write_partial_tag_ID(id, false); BKE_blendfile_write_partial_tag_ID(&id, false);
id->flag = prev_flag; id.flag = prev_flag;
id->tag = prev_tag; id.tag = prev_tag;
id->us = prev_us; id.us = prev_us;
BLI_strncpy(id->name + 2, prev_name.c_str(), sizeof(id->name) - 2); BLI_strncpy(id.name + 2, prev_name.c_str(), sizeof(id.name) - 2);
id->override_library = prev_liboverride; id.override_library = prev_liboverride;
id->asset_data = asset_data; id.asset_data = asset_data;
return sucess; return sucess;
} }
@ -338,15 +340,15 @@ static Vector<AssetEditBlend> &asset_edit_blend_get_all()
return mains; return mains;
} }
static AssetEditBlend *asset_edit_blend_from_id(const ID *id) static AssetEditBlend *asset_edit_blend_from_id(const ID &id)
{ {
BLI_assert(id->tag & LIB_TAG_ASSET_MAIN); BLI_assert(id.tag & LIB_TAG_ASSET_MAIN);
for (AssetEditBlend &asset_blend : asset_edit_blend_get_all()) { for (AssetEditBlend &asset_blend : asset_edit_blend_get_all()) {
/* TODO: Look into make this whole thing more efficient. */ /* TODO: Look into make this whole thing more efficient. */
ListBase *lb = which_libbase(asset_blend.main, GS(id->name)); ListBase *lb = which_libbase(asset_blend.main, GS(id.name));
LISTBASE_FOREACH (ID *, other_id, lb) { LISTBASE_FOREACH (ID *, other_id, lb) {
if (id == other_id) { if (&id == other_id) {
return &asset_blend; return &asset_blend;
} }
} }
@ -356,7 +358,7 @@ static AssetEditBlend *asset_edit_blend_from_id(const ID *id)
return nullptr; return nullptr;
} }
Main *asset_edit_main(const ID *id) Main *asset_edit_main(const ID &id)
{ {
const AssetEditBlend *asset_blend = asset_edit_blend_from_id(id); const AssetEditBlend *asset_blend = asset_edit_blend_from_id(id);
return (asset_blend) ? asset_blend->main : nullptr; return (asset_blend) ? asset_blend->main : nullptr;
@ -375,18 +377,18 @@ static AssetEditBlend &asset_edit_blend_file_ensure(const StringRef filepath)
} }
std::optional<std::string> asset_edit_id_save_as(Main &global_main, std::optional<std::string> asset_edit_id_save_as(Main &global_main,
const ID *id, const ID &id,
const char *name, const StringRef name,
std::optional<asset_system::CatalogID> catalog_id, std::optional<asset_system::CatalogID> catalog_id,
std::optional<std::string> catalog_simple_name, std::optional<std::string> catalog_simple_name,
const bUserAssetLibrary *user_library, const bUserAssetLibrary &user_library,
ReportList *reports) ReportList &reports)
{ {
const std::string filepath = asset_blendfile_path_for_save( const std::string filepath = asset_blendfile_path_for_save(
reports, *user_library, name, GS(id->name)); user_library, name, GS(id.name), reports);
/* Save to asset library. */ /* Save to asset library. */
Main *asset_main = BKE_main_from_id(&global_main, id); Main *asset_main = BKE_main_from_id(&global_main, &id);
std::string final_full_asset_filepath; std::string final_full_asset_filepath;
const bool success = asset_write_in_library(asset_main, const bool success = asset_write_in_library(asset_main,
@ -397,18 +399,17 @@ std::optional<std::string> asset_edit_id_save_as(Main &global_main,
catalog_simple_name, catalog_simple_name,
final_full_asset_filepath, final_full_asset_filepath,
reports); reports);
if (!success) { if (!success) {
BKE_report(reports, RPT_ERROR, "Failed to write to asset library"); BKE_report(&reports, RPT_ERROR, "Failed to write to asset library");
return std::nullopt; return std::nullopt;
} }
BKE_reportf(reports, RPT_INFO, "Saved \"%s\"", filepath.c_str()); BKE_reportf(&reports, RPT_INFO, "Saved \"%s\"", filepath.c_str());
return final_full_asset_filepath; return final_full_asset_filepath;
} }
bool asset_edit_id_save(Main & /*global_main*/, const ID *id, ReportList *reports) bool asset_edit_id_save(Main & /*global_main*/, const ID &id, ReportList &reports)
{ {
AssetEditBlend *asset_blend = asset_edit_blend_from_id(id); AssetEditBlend *asset_blend = asset_edit_blend_from_id(id);
if (asset_blend == nullptr) { if (asset_blend == nullptr) {
@ -418,7 +419,7 @@ bool asset_edit_id_save(Main & /*global_main*/, const ID *id, ReportList *report
std::string final_full_asset_filepath; std::string final_full_asset_filepath;
const bool success = asset_write_in_library(asset_blend->main, const bool success = asset_write_in_library(asset_blend->main,
id, id,
id->name + 2, id.name + 2,
asset_blend->filepath.c_str(), asset_blend->filepath.c_str(),
std::nullopt, std::nullopt,
std::nullopt, std::nullopt,
@ -426,14 +427,14 @@ bool asset_edit_id_save(Main & /*global_main*/, const ID *id, ReportList *report
reports); reports);
if (!success) { if (!success) {
BKE_report(reports, RPT_ERROR, "Failed to write to asset library"); BKE_report(&reports, RPT_ERROR, "Failed to write to asset library");
return false; return false;
} }
return true; return true;
} }
bool asset_edit_id_revert(Main &global_main, const ID *id, ReportList * /*reports*/) bool asset_edit_id_revert(Main &global_main, const ID &id, ReportList & /*reports*/)
{ {
AssetEditBlend *asset_blend = asset_edit_blend_from_id(id); AssetEditBlend *asset_blend = asset_edit_blend_from_id(id);
if (asset_blend == nullptr) { if (asset_blend == nullptr) {
@ -447,7 +448,7 @@ bool asset_edit_id_revert(Main &global_main, const ID *id, ReportList * /*report
return true; return true;
} }
bool asset_edit_id_delete(Main &global_main, const ID *id, ReportList *reports) bool asset_edit_id_delete(Main &global_main, const ID &id, ReportList &reports)
{ {
AssetEditBlend *asset_blend = asset_edit_blend_from_id(id); AssetEditBlend *asset_blend = asset_edit_blend_from_id(id);
if (asset_blend == nullptr) { if (asset_blend == nullptr) {
@ -455,7 +456,7 @@ bool asset_edit_id_delete(Main &global_main, const ID *id, ReportList *reports)
} }
if (BLI_delete(asset_blend->filepath.c_str(), false, false) != 0) { if (BLI_delete(asset_blend->filepath.c_str(), false, false) != 0) {
BKE_report(reports, RPT_ERROR, "Failed to delete asset library file"); BKE_report(&reports, RPT_ERROR, "Failed to delete asset library file");
return false; return false;
} }
@ -500,9 +501,9 @@ ID *asset_edit_id_from_weak_reference(Main &global_main,
return asset_blend.ensure_id(id_type, asset_name); return asset_blend.ensure_id(id_type, asset_name);
} }
bool asset_edit_id_is_editable(const ID *id) bool asset_edit_id_is_editable(const ID &id)
{ {
if (!(id->tag & LIB_TAG_ASSET_MAIN)) { if (!(id.tag & LIB_TAG_ASSET_MAIN)) {
return false; return false;
} }

View File

@ -972,7 +972,7 @@ Main *BKE_main_from_id(Main *global_main, const ID *id, const bool verify)
return nullptr; return nullptr;
} }
if (id->tag & LIB_TAG_ASSET_MAIN) { if (id->tag & LIB_TAG_ASSET_MAIN) {
return blender::bke::asset_edit_main(id); return blender::bke::asset_edit_main(*id);
} }
if (verify) { if (verify) {

View File

@ -916,7 +916,7 @@ static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
} }
const std::optional<std::string> final_full_asset_filepath = bke::asset_edit_id_save_as( const std::optional<std::string> final_full_asset_filepath = bke::asset_edit_id_save_as(
*bmain, &brush->id, name, catalog_id, catalog_simple_name, user_library, op->reports); *bmain, brush->id, name, catalog_id, catalog_simple_name, *user_library, *op->reports);
if (!final_full_asset_filepath) { if (!final_full_asset_filepath) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
@ -1100,7 +1100,7 @@ static bool brush_asset_delete_poll(bContext *C)
/* Asset brush, check if belongs to an editable blend file. */ /* Asset brush, check if belongs to an editable blend file. */
if (ID_IS_ASSET(brush)) { if (ID_IS_ASSET(brush)) {
if (!bke::asset_edit_id_is_editable(&brush->id)) { if (!bke::asset_edit_id_is_editable(brush->id)) {
CTX_wm_operator_poll_msg_set(C, "Asset blend file is not editable"); CTX_wm_operator_poll_msg_set(C, "Asset blend file is not editable");
return false; return false;
} }
@ -1121,7 +1121,7 @@ static int brush_asset_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
bke::asset_edit_id_delete(*bmain, &brush->id, op->reports); bke::asset_edit_id_delete(*bmain, brush->id, *op->reports);
refresh_asset_library(C, *library); refresh_asset_library(C, *library);
@ -1172,7 +1172,7 @@ static bool brush_asset_update_poll(bContext *C)
return false; return false;
} }
if (!bke::asset_edit_id_is_editable(&brush->id)) { if (!bke::asset_edit_id_is_editable(brush->id)) {
CTX_wm_operator_poll_msg_set(C, "Asset blend file is not editable"); CTX_wm_operator_poll_msg_set(C, "Asset blend file is not editable");
return false; return false;
} }
@ -1195,7 +1195,7 @@ static int brush_asset_update_exec(bContext *C, wmOperator *op)
BLI_assert(ID_IS_ASSET(brush)); BLI_assert(ID_IS_ASSET(brush));
bke::asset_edit_id_save(*bmain, &brush->id, op->reports); bke::asset_edit_id_save(*bmain, brush->id, *op->reports);
refresh_asset_library(C, *user_library); refresh_asset_library(C, *user_library);
WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_EDITED, nullptr); WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_EDITED, nullptr);
@ -1231,7 +1231,7 @@ static int brush_asset_revert_exec(bContext *C, wmOperator *op)
Paint *paint = BKE_paint_get_active_from_context(C); Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint); Brush *brush = BKE_paint_brush(paint);
bke::asset_edit_id_revert(*bmain, &brush->id, op->reports); bke::asset_edit_id_revert(*bmain, brush->id, *op->reports);
WM_main_add_notifier(NC_BRUSH | NA_EDITED, nullptr); WM_main_add_notifier(NC_BRUSH | NA_EDITED, nullptr);
WM_main_add_notifier(NC_TEXTURE | ND_NODES, nullptr); WM_main_add_notifier(NC_TEXTURE | ND_NODES, nullptr);