WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 358 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.
6 changed files with 72 additions and 37 deletions
Showing only changes of commit c0653b1fff - Show all commits

View File

@ -1581,7 +1581,6 @@ class USERPREF_PT_file_paths_asset_libraries(FilePathsPanel, Panel):
layout.prop(active_library, "path")
layout.prop(active_library, "import_method", text="Import Method")
layout.prop(active_library, "use_relative_path")
layout.prop(active_library, "is_default")
class USERPREF_UL_asset_libraries(UIList):

View File

@ -89,7 +89,7 @@ static const asset_system::AssetRepresentation *get_local_asset_from_relative_id
return matching_asset;
}
static const asset_system::AssetRepresentation *find_asset_from_weak_ref(
const asset_system::AssetRepresentation *find_asset_from_weak_ref(
const bContext &C, const AssetWeakReference &weak_ref, ReportList *reports)
{
if (weak_ref.asset_library_type == ASSET_LIBRARY_LOCAL) {

View File

@ -44,6 +44,9 @@ void operator_asset_reference_props_set(const asset_system::AssetRepresentation
PointerRNA &ptr);
void operator_asset_reference_props_register(StructRNA &srna);
const asset_system::AssetRepresentation *find_asset_from_weak_ref(
const bContext &C, const AssetWeakReference &weak_ref, ReportList *reports);
/**
* Load all asset libraries to find an asset from the #operator_asset_reference_props_register
* properties. The loading happens in the background, so there may be no result immediately. In

View File

@ -788,19 +788,6 @@ static AssetWeakReference brush_asset_create_weakref_hack(const bUserAssetLibrar
return asset_weak_ref;
}
static const bUserAssetLibrary *brush_asset_get_default_library()
{
if (BLI_listbase_is_empty(&U.asset_libraries)) {
return nullptr;
}
LISTBASE_FOREACH (const bUserAssetLibrary *, asset_library, &U.asset_libraries) {
if (asset_library->flag & ASSET_LIBRARY_DEFAULT) {
return asset_library;
}
}
return static_cast<const bUserAssetLibrary *>(U.asset_libraries.first);
}
static void refresh_asset_library(const bContext *C, const bUserAssetLibrary &user_library)
{
/* TODO: Should the all library reference be automatically cleared? */
@ -827,6 +814,12 @@ static bool brush_asset_save_as_poll(bContext *C)
if (paint == nullptr || brush == nullptr) {
return false;
}
if (!paint->brush_asset_reference) {
/* The brush should always be an imported asset. We use this asset reference to find
* which library and catalog the brush came from, as defaults for the popup. */
BLI_assert_unreachable();
return false;
}
if (BLI_listbase_is_empty(&U.asset_libraries)) {
CTX_wm_operator_poll_msg_set(C, "No asset library available to save to");
@ -952,17 +945,74 @@ static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static std::optional<AssetLibraryReference> library_to_library_ref(
const asset_system::AssetLibrary &library)
{
for (const AssetLibraryReference &ref : asset_system::all_valid_asset_library_refs()) {
const std::string root_path = AS_asset_library_root_path_from_library_ref(ref);
/* Use #BLI_path_cmp_normalized because `library.root_path()` ends with a slash while
* `root_path` doesn't. */
if (BLI_path_cmp_normalized(root_path.c_str(), library.root_path().c_str()) == 0) {
return ref;
}
}
return std::nullopt;
}
static bool library_is_editable(const AssetLibraryReference &library)
{
if (library.type == ASSET_LIBRARY_ESSENTIALS) {
return false;
}
return true;
}
static int brush_asset_save_as_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference;
const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref(
*C, brush_weak_ref, op->reports);
if (!asset) {
BLI_assert_unreachable();
return OPERATOR_CANCELLED;
}
const asset_system::AssetLibrary &library = asset->owner_asset_library();
const std::optional<AssetLibraryReference> library_ref = library_to_library_ref(library);
if (!library_ref) {
BLI_assert_unreachable();
return OPERATOR_CANCELLED;
}
RNA_string_set(op->ptr, "name", brush->id.name + 2);
if (const bUserAssetLibrary *library = brush_asset_get_default_library()) {
const AssetLibraryReference library_ref = user_library_to_library_ref(*library);
const int enum_value = asset::library_reference_to_enum_value(&library_ref);
RNA_enum_set(op->ptr, "asset_library_reference", enum_value);
/* If the library isn't saved from the operator's last execution, find the current library or the
* first library if the current library isn't editable. */
if (!RNA_struct_property_is_set_ex(op->ptr, "asset_library_reference", false)) {
if (library_is_editable(*library_ref)) {
RNA_enum_set(op->ptr,
"asset_library_reference",
asset::library_reference_to_enum_value(&*library_ref));
}
else {
const AssetLibraryReference first_library = user_library_to_library_ref(
*static_cast<const bUserAssetLibrary *>(U.asset_libraries.first));
RNA_enum_set(op->ptr,
"asset_library_reference",
asset::library_reference_to_enum_value(&first_library));
}
}
/* By default, put the new asset in the same catalog as the existing asset. */
if (!RNA_struct_property_is_set(op->ptr, "catalog_path")) {
const asset_system::CatalogID catalog_id = asset->get_metadata().catalog_id;
const asset_system::AssetCatalog *catalog = library.catalog_service().find_catalog(catalog_id);
if (catalog == nullptr) {
BLI_assert_unreachable();
return OPERATOR_CANCELLED;
}
RNA_string_set(op->ptr, "catalog_path", catalog->path.c_str());
}
return WM_operator_props_dialog_popup(C, op, 400, std::nullopt, IFACE_("Save"));
@ -990,6 +1040,7 @@ static void visit_asset_catalog_for_search_fn(
const char *edit_text,
FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
/* NOTE: Using the all library would also be a valid choice. */
const bUserAssetLibrary *user_library = get_asset_library_from_prop(*ptr);
if (!user_library) {
return;

View File

@ -117,7 +117,6 @@ typedef enum eAssetImportMethod {
typedef enum eAssetLibrary_Flag {
ASSET_LIBRARY_RELATIVE_PATH = (1 << 0),
ASSET_LIBRARY_DEFAULT = (1 << 1),
} eAssetLibrary_Flag;
/**

View File

@ -361,18 +361,6 @@ static void rna_userdef_asset_library_path_set(PointerRNA *ptr, const char *valu
BKE_preferences_asset_library_path_set(library, value);
}
static void rna_UserAssetLibrary_is_default_set(PointerRNA *ptr, bool value)
{
bUserAssetLibrary *library = static_cast<bUserAssetLibrary *>(ptr->data);
if (!value) {
return;
}
LISTBASE_FOREACH (bUserAssetLibrary *, library_iter, &U.asset_libraries) {
library_iter->flag &= ~ASSET_LIBRARY_DEFAULT;
}
library->flag |= ASSET_LIBRARY_DEFAULT;
}
static void rna_userdef_extension_repo_name_set(PointerRNA *ptr, const char *value)
{
bUserExtensionRepo *repo = (bUserExtensionRepo *)ptr->data;
@ -6618,11 +6606,6 @@ static void rna_def_userdef_filepaths_asset_library(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, nullptr, "flag", ASSET_LIBRARY_RELATIVE_PATH);
RNA_def_property_ui_text(
prop, "Relative Path", "Use relative path when linking assets from this asset library");
prop = RNA_def_property(srna, "is_default", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", ASSET_LIBRARY_DEFAULT);
RNA_def_property_boolean_funcs(prop, nullptr, "rna_UserAssetLibrary_is_default_set");
RNA_def_property_ui_text(prop, "Default", "Use this library for saving new assets");
}
static void rna_def_userdef_filepaths_extension_repo(BlenderRNA *brna)