Geometry Nodes: Extend add modifier menu with node group assets #111717

Merged
Hans Goudey merged 30 commits from HooglyBoogly/blender:geometry-nodes-is-modifier-trait into main 2023-09-05 14:47:25 +02:00
15 changed files with 519 additions and 191 deletions
Showing only changes of commit 14b8bba55d - Show all commits

View File

@ -38,9 +38,11 @@ class OBJECT_MT_modifier_add(Menu):
layout.menu("OBJECT_MT_modifier_add_deform")
layout.menu("OBJECT_MT_modifier_add_physics")
layout.menu_contents("OBJECT_MT_modifier_add_root_catalogs")
class OBJECT_MT_modifier_add_edit(Menu):
bl_label = "Generate"
bl_label = "Edit"
def draw(self, context):
layout = self.layout
@ -54,6 +56,7 @@ class OBJECT_MT_modifier_add_edit(Menu):
layout.operator("object.modifier_add", text="Vertex Weight Edit", icon='MOD_VERTEX_WEIGHT').type='VERTEX_WEIGHT_EDIT'
layout.operator("object.modifier_add", text="Vertex Weight Mix", icon='MOD_VERTEX_WEIGHT').type='VERTEX_WEIGHT_MIX'
layout.operator("object.modifier_add", text="Vertex Weight Proximity", icon='MOD_VERTEX_WEIGHT').type='VERTEX_WEIGHT_PROXIMITY'
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
class OBJECT_MT_modifier_add_generate(Menu):
@ -82,6 +85,7 @@ class OBJECT_MT_modifier_add_generate(Menu):
layout.operator("object.modifier_add", text="Volume to Mesh", icon='VOLUME_DATA').type='VOLUME_TO_MESH'
layout.operator("object.modifier_add", text="Weld", icon='AUTOMERGE_OFF').type='WELD'
layout.operator("object.modifier_add", text="Wireframe", icon='MOD_WIREFRAME').type='WIREFRAME'
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
class OBJECT_MT_modifier_add_deform(Menu):
@ -107,6 +111,7 @@ class OBJECT_MT_modifier_add_deform(Menu):
layout.operator("object.modifier_add", text="Wave", icon='MOD_WAVE').type='WAVE'
if context.object.type == 'VOLUME':
layout.operator("object.modifier_add", text="Volume Displace", icon='VOLUME_DATA').type='VOLUME_DISPLACE'
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
class OBJECT_MT_modifier_add_physics(Menu):
@ -123,6 +128,7 @@ class OBJECT_MT_modifier_add_physics(Menu):
layout.operator("object.modifier_add", text="Particle Instance", icon='MOD_PARTICLE_INSTANCE').type='PARTICLE_INSTANCE'
layout.operator("object.modifier_add", text="Particle System", icon='MOD_PARTICLES').type='PARTICLE_SYSTEM'
layout.operator("object.modifier_add", text="Soft Body", icon='MOD_SOFT').type='SOFT_BODY'
layout.template_modifier_asset_menu_items(catalog_path=self.bl_label)
class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):

View File

@ -1056,6 +1056,10 @@ void ntreeBlendReadData(BlendDataReader *reader, ID *owner_id, bNodeTree *ntree)
}
BLO_read_data_address(reader, &ntree->geometry_node_asset_traits);
std::cout << ntree->id.name << ": ";
std::cout << bool(ntree->geometry_node_asset_traits &&
(ntree->geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER))
<< '\n';
BLO_read_data_address(reader, &ntree->nested_node_refs);
/* TODO: should be dealt by new generic cache handling of IDs... */

View File

@ -25,6 +25,7 @@
struct AssetLibrary;
struct bScreen;
struct uiLayout;
namespace blender::asset_system {
class AssetCatalogTreeItem;
@ -71,4 +72,10 @@ PointerRNA persistent_catalog_path_rna_pointer(const bScreen &owner_screen,
const asset_system::AssetLibrary &library,
const asset_system::AssetCatalogTreeItem &item);
void draw_menu_for_catalog(const bScreen &owner_screen,
const asset_system::AssetLibrary &library,
const asset_system::AssetCatalogTreeItem &item,
StringRefNull menu_name,
uiLayout &layout);
} // namespace blender::ed::asset

View File

@ -33,6 +33,8 @@ extern "C" {
#endif
struct AssetHandle;
struct bContext;
struct ReportList;
AssetRepresentationHandle *ED_asset_handle_get_representation(const struct AssetHandle *asset);
ID_Type ED_asset_handle_get_id_type(const struct AssetHandle *asset);
@ -54,6 +56,13 @@ namespace blender::ed::asset {
PointerRNA create_asset_rna_ptr(const asset_system::AssetRepresentation *asset);
}
void operator_asset_reference_props_set(const asset_system::AssetRepresentation &asset,
PointerRNA &ptr);
void operator_asset_reference_props_register(StructRNA &srna);
const asset_system::AssetRepresentation *operator_asset_reference_props_get_asset(
const bContext &C, PointerRNA &ptr, ReportList *reports);
} // namespace blender::ed::asset
#endif

View File

@ -21,6 +21,10 @@
#include "ED_asset_catalog.h"
#include "ED_asset_catalog.hh"
#include "UI_interface.hh"
#include "BLT_translation.h"
#include "WM_api.hh"
using namespace blender;
@ -225,4 +229,20 @@ PointerRNA persistent_catalog_path_rna_pointer(const bScreen &owner_screen,
const_cast<asset_system::AssetCatalogPath *>(&path)};
}
void draw_menu_for_catalog(const bScreen &owner_screen,
HooglyBoogly marked this conversation as resolved Outdated

This seems placed a bit arbitrarily here. The file provides high level catalog editing functions, while this is a UI layout utility. Could be a template even.

This seems placed a bit arbitrarily here. The file provides high level catalog editing functions, while this is a UI layout utility. Could be a template even.
const asset_system::AssetLibrary &library,
const asset_system::AssetCatalogTreeItem &item,
const StringRefNull menu_name,
uiLayout &layout)
{
PointerRNA path_ptr = asset::persistent_catalog_path_rna_pointer(owner_screen, library, item);
if (path_ptr.data == nullptr) {
return;
}
uiLayout *col = uiLayoutColumn(&layout, false);
uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr);
uiItemM(col, menu_name.c_str(), IFACE_(item.get_name().c_str()), ICON_NONE);
}
} // namespace blender::ed::asset

View File

@ -10,6 +10,7 @@
#include "AS_asset_library.hh"
#include "AS_asset_representation.hh"
#include "BKE_asset.h"
#include "BKE_bpath.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
@ -33,6 +34,7 @@
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_enum_types.hh"
#include "RNA_prototypes.h"
#include "WM_api.hh"
@ -41,6 +43,120 @@
using namespace blender;
namespace blender::ed::asset {
void operator_asset_reference_props_register(StructRNA &srna)
{
PropertyRNA *prop;
prop = RNA_def_enum(&srna,
"asset_library_type",
rna_enum_aset_library_type_items,
ASSET_LIBRARY_LOCAL,
"Asset Library Type",
"");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_string(
&srna, "asset_library_identifier", nullptr, 0, "Asset Library Identifier", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_string(
&srna, "relative_asset_identifier", nullptr, 0, "Relative Asset Identifier", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void operator_asset_reference_props_set(const asset_system::AssetRepresentation &asset,
PointerRNA &ptr)
{
AssetWeakReference *weak_ref = asset.make_weak_reference();
RNA_enum_set(&ptr, "asset_library_type", weak_ref->asset_library_type);
RNA_string_set(&ptr, "asset_library_identifier", weak_ref->asset_library_identifier);
RNA_string_set(&ptr, "relative_asset_identifier", weak_ref->relative_asset_identifier);
BKE_asset_weak_reference_free(&weak_ref);
}
/**
* #AssetLibrary::resolve_asset_weak_reference_to_full_path() currently does not support local
* assets.
*/
static const asset_system::AssetRepresentation *get_local_asset_from_relative_identifier(
const bContext &C, const StringRefNull relative_identifier, ReportList *reports)
{
AssetLibraryReference library_ref{};
library_ref.type = ASSET_LIBRARY_LOCAL;
ED_assetlist_storage_fetch(&library_ref, &C);
ED_assetlist_ensure_previews_job(&library_ref, &C);
const asset_system::AssetRepresentation *matching_asset = nullptr;
ED_assetlist_iterate(library_ref, [&](asset_system::AssetRepresentation &asset) {
if (asset.get_identifier().library_relative_identifier() == relative_identifier) {
matching_asset = &asset;
return false;
}
return true;
});
if (reports && !matching_asset) {
if (ED_assetlist_is_loaded(&library_ref)) {
BKE_reportf(
reports, RPT_ERROR, "No asset found at path \"%s\"", relative_identifier.c_str());
}
else {
BKE_report(reports, RPT_WARNING, "Asset loading is unfinished");
}
}
return matching_asset;
}
static 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) {
return get_local_asset_from_relative_identifier(
C, weak_ref.relative_asset_identifier, reports);
}
const AssetLibraryReference library_ref = asset_system::all_library_reference();
ED_assetlist_storage_fetch(&library_ref, &C);
ED_assetlist_ensure_previews_job(&library_ref, &C);
asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available(
asset_system::all_library_reference());
if (!all_library) {
BKE_report(reports, RPT_WARNING, "Asset loading is unfinished");
}
const std::string full_path = all_library->resolve_asset_weak_reference_to_full_path(weak_ref);
const asset_system::AssetRepresentation *matching_asset = nullptr;
ED_assetlist_iterate(library_ref, [&](asset_system::AssetRepresentation &asset) {
if (asset.get_identifier().full_path() == full_path) {
matching_asset = &asset;
return false;
}
return true;
});
if (reports && !matching_asset) {
if (ED_assetlist_is_loaded(&library_ref)) {
BKE_reportf(reports, RPT_ERROR, "No asset found at path \"%s\"", full_path.c_str());
}
}
return matching_asset;
}
/** \note Does not check asset type or meta data. */
const asset_system::AssetRepresentation *operator_asset_reference_props_get_asset(
HooglyBoogly marked this conversation as resolved Outdated

The function names should make it more clear that they trigger loading of all asset libraries. This is a rather significant operation.
Previously these were local scope functions, if they become generalized for reuse we need to be more thoughtful with naming.

The function names should make it more clear that they trigger loading of all asset libraries. This is a rather significant operation. Previously these were local scope functions, if they become generalized for reuse we need to be more thoughtful with naming.

It also needs to be clear that this triggers loading in the background, so there may not be a result immediately.

It also needs to be clear that this triggers loading in the background, so there may not be a result immediately.
const bContext &C, PointerRNA &ptr, ReportList *reports)
{
AssetWeakReference weak_ref{};
weak_ref.asset_library_type = RNA_enum_get(&ptr, "asset_library_type");
weak_ref.asset_library_identifier = RNA_string_get_alloc(
&ptr, "asset_library_identifier", nullptr, 0, nullptr);
weak_ref.relative_asset_identifier = RNA_string_get_alloc(
&ptr, "relative_asset_identifier", nullptr, 0, nullptr);
return find_asset_from_weak_ref(C, weak_ref, reports);
HooglyBoogly marked this conversation as resolved Outdated

Isn't this leaking memory? Where are the identifier strings freed?

Isn't this leaking memory? Where are the identifier strings freed?

No, because the struct has a destructor that frees the strings: ~AssetWeakReference();

No, because the struct has a destructor that frees the strings: `~AssetWeakReference();`
}
} // namespace blender::ed::asset
/* -------------------------------------------------------------------- */
using PointerRNAVec = blender::Vector<PointerRNA>;

View File

@ -40,7 +40,6 @@
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_enum_types.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
@ -70,92 +69,10 @@ namespace blender::ed::geometry {
/** \name Operator
* \{ */
/**
* #AssetLibrary::resolve_asset_weak_reference_to_full_path() currently does not support local
* assets.
*/
static const asset_system::AssetRepresentation *get_local_asset_from_relative_identifier(
const bContext &C, const StringRefNull relative_identifier, ReportList *reports)
{
AssetLibraryReference library_ref{};
library_ref.type = ASSET_LIBRARY_LOCAL;
ED_assetlist_storage_fetch(&library_ref, &C);
ED_assetlist_ensure_previews_job(&library_ref, &C);
const asset_system::AssetRepresentation *matching_asset = nullptr;
ED_assetlist_iterate(library_ref, [&](asset_system::AssetRepresentation &asset) {
if (asset.get_identifier().library_relative_identifier() == relative_identifier) {
matching_asset = &asset;
return false;
}
return true;
});
if (reports && !matching_asset) {
if (ED_assetlist_is_loaded(&library_ref)) {
BKE_reportf(
reports, RPT_ERROR, "No asset found at path \"%s\"", relative_identifier.c_str());
}
else {
BKE_report(reports, RPT_WARNING, "Asset loading is unfinished");
}
}
return matching_asset;
}
static 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) {
return get_local_asset_from_relative_identifier(
C, weak_ref.relative_asset_identifier, reports);
}
const AssetLibraryReference library_ref = asset_system::all_library_reference();
ED_assetlist_storage_fetch(&library_ref, &C);
ED_assetlist_ensure_previews_job(&library_ref, &C);
asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available(
asset_system::all_library_reference());
if (!all_library) {
BKE_report(reports, RPT_WARNING, "Asset loading is unfinished");
}
const std::string full_path = all_library->resolve_asset_weak_reference_to_full_path(weak_ref);
const asset_system::AssetRepresentation *matching_asset = nullptr;
ED_assetlist_iterate(library_ref, [&](asset_system::AssetRepresentation &asset) {
if (asset.get_identifier().full_path() == full_path) {
matching_asset = &asset;
return false;
}
return true;
});
if (reports && !matching_asset) {
if (ED_assetlist_is_loaded(&library_ref)) {
BKE_reportf(reports, RPT_ERROR, "No asset found at path \"%s\"", full_path.c_str());
}
}
return matching_asset;
}
/** \note Does not check asset type or meta data. */
static const asset_system::AssetRepresentation *get_asset(const bContext &C,
PointerRNA &ptr,
ReportList *reports)
{
AssetWeakReference weak_ref{};
weak_ref.asset_library_type = RNA_enum_get(&ptr, "asset_library_type");
weak_ref.asset_library_identifier = RNA_string_get_alloc(
&ptr, "asset_library_identifier", nullptr, 0, nullptr);
weak_ref.relative_asset_identifier = RNA_string_get_alloc(
&ptr, "relative_asset_identifier", nullptr, 0, nullptr);
return find_asset_from_weak_ref(C, weak_ref, reports);
}
static const bNodeTree *get_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports)
{
const asset_system::AssetRepresentation *asset = get_asset(C, ptr, reports);
const asset_system::AssetRepresentation *asset = asset::operator_asset_reference_props_get_asset(
C, ptr, reports);
if (!asset) {
return nullptr;
}
@ -374,7 +291,8 @@ static std::string run_node_group_get_description(bContext *C,
wmOperatorType * /*ot*/,
PointerRNA *ptr)
{
const asset_system::AssetRepresentation *asset = get_asset(*C, *ptr, nullptr);
const asset_system::AssetRepresentation *asset = asset::operator_asset_reference_props_get_asset(
*C, *ptr, nullptr);
if (!asset) {
return "";
}
@ -532,20 +450,7 @@ void GEOMETRY_OT_execute_node_group(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
prop = RNA_def_enum(ot->srna,
"asset_library_type",
rna_enum_aset_library_type_items,
ASSET_LIBRARY_LOCAL,
"Asset Library Type",
"");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_string(
ot->srna, "asset_library_identifier", nullptr, 0, "Asset Library Identifier", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_string(
ot->srna, "relative_asset_identifier", nullptr, 0, "Relative Asset Identifier", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
asset::operator_asset_reference_props_register(*ot->srna);
}
/** \} */
@ -704,7 +609,6 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu)
for (const asset_system::AssetRepresentation *asset : assets) {
uiLayout *col = uiLayoutColumn(layout, false);
wmOperatorType *ot = WM_operatortype_find("GEOMETRY_OT_execute_node_group", true);
AssetWeakReference *weak_ref = asset->make_weak_reference();
PointerRNA props_ptr;
uiItemFullO_ptr(col,
ot,
@ -714,11 +618,7 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu)
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
&props_ptr);
RNA_enum_set(&props_ptr, "asset_library_type", weak_ref->asset_library_type);
RNA_string_set(&props_ptr, "asset_library_identifier", weak_ref->asset_library_identifier);
RNA_string_set(&props_ptr, "relative_asset_identifier", weak_ref->relative_asset_identifier);
BKE_asset_weak_reference_free(&weak_ref);
asset::operator_asset_reference_props_set(*asset, props_ptr);
}
asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available(
@ -727,18 +627,9 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu)
return;
}
catalog_item->foreach_child([&](asset_system::AssetCatalogTreeItem &child_item) {
PointerRNA path_ptr = asset::persistent_catalog_path_rna_pointer(
screen, *all_library, child_item);
if (path_ptr.data == nullptr) {
return;
}
uiLayout *col = uiLayoutColumn(layout, false);
uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr);
uiItemM(col,
"GEO_MT_node_operator_catalog_assets",
IFACE_(child_item.get_name().c_str()),
ICON_NONE);
catalog_item->foreach_child([&](asset_system::AssetCatalogTreeItem &item) {
asset::draw_menu_for_catalog(
screen, *all_library, item, "GEO_MT_node_operator_catalog_assets", *layout);
});
}
@ -806,17 +697,10 @@ void ui_template_node_operator_asset_root_items(uiLayout &layout, bContext &C)
eObjectMode(active_object->mode));
tree->catalogs.foreach_root_item([&](asset_system::AssetCatalogTreeItem &item) {
if (builtin_menus.contains(item.get_name())) {
return;
if (!builtin_menus.contains(item.get_name())) {
asset::draw_menu_for_catalog(
screen, *all_library, item, "GEO_MT_node_operator_catalog_assets", layout);
}
PointerRNA path_ptr = asset::persistent_catalog_path_rna_pointer(screen, *all_library, item);
if (path_ptr.data == nullptr) {
return;
}
uiLayout *col = uiLayoutColumn(&layout, false);
uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr);
const char *text = IFACE_(item.get_name().c_str());
uiItemM(col, "GEO_MT_node_operator_catalog_assets", text, ICON_NONE);
});
}

View File

@ -9,6 +9,8 @@
#pragma once
#include "BLI_compiler_attrs.h"
#include "BLI_string_ref.hh"
#include "DNA_object_enums.h"
#include "DNA_userdef_enums.h"
#include "DNA_windowmanager_types.h"
@ -636,3 +638,9 @@ void ED_object_data_xform_by_mat4(XFormObjectData *xod, const float mat[4][4]);
void ED_object_data_xform_restore(XFormObjectData *xod);
void ED_object_data_xform_tag_update(XFormObjectData *xod);
namespace blender::ed::object {
void ui_template_modifier_asset_menu_items(uiLayout &layout, bContext &C, StringRef catalog_path);
}

View File

@ -31,6 +31,7 @@ set(INC_SYS
)
set(SRC
add_modifier_assets.cc
object_add.cc
object_bake.cc
object_bake_api.cc

View File

@ -0,0 +1,298 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "AS_asset_catalog.hh"
#include "AS_asset_catalog_tree.hh"
#include "AS_asset_library.hh"
#include "AS_asset_representation.hh"
#include "BLI_multi_value_map.hh"
#include "DNA_modifier_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BLT_translation.h"
#include "RNA_access.hh"
#include "ED_asset.hh"
#include "ED_object.hh"
#include "ED_screen.hh"
#include "MOD_nodes.hh"
#include "UI_interface.hh"
#include "WM_api.hh"
#include "object_intern.h"
namespace blender::ed::object {
static bool all_loading_finished()
{
AssetLibraryReference all_library_ref = asset_system::all_library_reference();
return ED_assetlist_is_loaded(&all_library_ref);
}
static asset::AssetItemTree build_catalog_tree(const bContext &C)
{
AssetFilterSettings type_filter{};
type_filter.id_types = FILTER_ID_NT;
auto meta_data_filter = [&](const AssetMetaData &meta_data) {
const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type");
if (tree_type == nullptr || IDP_Int(tree_type) != NTREE_GEOMETRY) {
return false;
}
const IDProperty *traits_flag = BKE_asset_metadata_idprop_find(
&meta_data, "geometry_node_asset_traits_flag");
if (traits_flag == nullptr || !(IDP_Int(traits_flag) & GEO_NODE_ASSET_MODIFIER)) {
return false;
}
return true;
};
const AssetLibraryReference library = asset_system::all_library_reference();
return asset::build_filtered_all_catalog_tree(library, C, type_filter, meta_data_filter);
}
static asset::AssetItemTree *get_static_item_tree()
{
static asset::AssetItemTree tree;
return &tree;
}
static void catalog_assets_draw(const bContext *C, Menu *menu)
{
bScreen &screen = *CTX_wm_screen(C);
asset::AssetItemTree &tree = *get_static_item_tree();
const PointerRNA menu_path_ptr = CTX_data_pointer_get(C, "asset_catalog_path");
if (RNA_pointer_is_null(&menu_path_ptr)) {
return;
}
const asset_system::AssetCatalogPath &menu_path =
*static_cast<const asset_system::AssetCatalogPath *>(menu_path_ptr.data);
const Span<asset_system::AssetRepresentation *> assets = tree.assets_per_path.lookup(menu_path);
asset_system::AssetCatalogTreeItem *catalog_item = tree.catalogs.find_item(menu_path);
BLI_assert(catalog_item != nullptr);
if (assets.is_empty() && !catalog_item->has_children()) {
return;
}
uiLayout *layout = menu->layout;
uiItemS(layout);
for (const asset_system::AssetRepresentation *asset : assets) {
uiLayout *col = uiLayoutColumn(layout, false);
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_asset", true);
PointerRNA props_ptr;
uiItemFullO_ptr(col,
ot,
IFACE_(asset->get_name().c_str()),
ICON_NONE,
nullptr,
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
&props_ptr);
asset::operator_asset_reference_props_set(*asset, props_ptr);
}
asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available(
asset_system::all_library_reference());
if (!all_library) {
return;
}
catalog_item->foreach_child([&](asset_system::AssetCatalogTreeItem &item) {
asset::draw_menu_for_catalog(
screen, *all_library, item, "OBJECT_MT_add_modifier_catalog_assets", *layout);
});
}
static void root_catalogs_draw(const bContext *C, Menu *menu)
{
bScreen &screen = *CTX_wm_screen(C);
uiLayout *layout = menu->layout;
const bool loading_finished = all_loading_finished();
asset::AssetItemTree &tree = *get_static_item_tree();
tree = build_catalog_tree(*C);
if (tree.catalogs.is_empty() && loading_finished) {
return;
}
uiItemS(layout);
if (!loading_finished) {
uiItemL(layout, IFACE_("Loading Asset Libraries"), ICON_INFO);
}
static Set<std::string> all_builtin_menus = []() {
Set<std::string> menus;
menus.add_new("Edit");
menus.add_new("Generate");
menus.add_new("Deform");
menus.add_new("Physics");
return menus;
}();
asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available(
asset_system::all_library_reference());
if (!all_library) {
return;
}
tree.catalogs.foreach_root_item([&](asset_system::AssetCatalogTreeItem &item) {
if (!all_builtin_menus.contains(item.get_name())) {
asset::draw_menu_for_catalog(
screen, *all_library, item, "OBJECT_MT_add_modifier_catalog_assets", *layout);
}
});
}
static bNodeTree *get_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports)
{
const asset_system::AssetRepresentation *asset = asset::operator_asset_reference_props_get_asset(
C, ptr, reports);
if (!asset) {
return nullptr;
}
Main &bmain = *CTX_data_main(&C);
bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
asset::asset_local_id_ensure_imported(bmain, *asset));
if (!node_group) {
return nullptr;
}
if (node_group->type != NTREE_GEOMETRY) {
if (reports) {
BKE_report(reports, RPT_ERROR, "Asset is not a geometry node group");
}
return nullptr;
}
return node_group;
}
static int modifier_add_asset_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *object = ED_object_active_context(C);
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(
ED_object_modifier_add(op->reports, bmain, scene, object, nullptr, eModifierType_Nodes));
if (!nmd) {
return OPERATOR_CANCELLED;
}
bNodeTree *node_group = get_node_group(*C, *op->ptr, op->reports);
if (!node_group) {
return OPERATOR_CANCELLED;
}
nmd->node_group = node_group;
id_us_plus(&node_group->id);
MOD_nodes_update_interface(object, nmd);
STRNCPY(nmd->modifier.name, DATA_(node_group->id.name));
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
return OPERATOR_FINISHED;
}
static std::string modifier_add_asset_get_description(bContext *C,
wmOperatorType * /*ot*/,
PointerRNA *ptr)
{
const asset_system::AssetRepresentation *asset = asset::operator_asset_reference_props_get_asset(
*C, *ptr, nullptr);
if (!asset) {
return "";
}
if (!asset->get_metadata().description) {
return "";
}
return asset->get_metadata().description;
}
static void OBJECT_OT_modifier_add_asset(wmOperatorType *ot)
{
ot->name = "Add Modifier";
ot->description = "Add a procedural operation/effect to the active object";
ot->idname = "OBJECT_OT_modifier_add_asset";
ot->exec = modifier_add_asset_exec;
ot->poll = ED_operator_object_active_editable;
ot->get_description = modifier_add_asset_get_description;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
asset::operator_asset_reference_props_register(*ot->srna);
}
static MenuType modifier_add_catalog_assets_menu_type()
{
MenuType type{};
STRNCPY(type.idname, "OBJECT_MT_add_modifier_catalog_assets");
type.draw = catalog_assets_draw;
type.listener = asset::asset_reading_region_listen_fn;
return type;
}
static MenuType modifier_add_root_catalogs_menu_type()
{
MenuType type{};
STRNCPY(type.idname, "OBJECT_MT_modifier_add_root_catalogs");
type.draw = root_catalogs_draw;
type.listener = asset::asset_reading_region_listen_fn;
return type;
}
void object_modifier_add_asset_register()
{
WM_menutype_add(MEM_new<MenuType>(__func__, modifier_add_catalog_assets_menu_type()));
WM_menutype_add(MEM_new<MenuType>(__func__, modifier_add_root_catalogs_menu_type()));
WM_operatortype_append(OBJECT_OT_modifier_add_asset);
}
void ui_template_modifier_asset_menu_items(uiLayout &layout,
bContext &C,
const StringRef catalog_path)
{
using namespace blender;
using namespace blender::ed;
using namespace blender::ed::object;
bScreen &screen = *CTX_wm_screen(&C);
asset::AssetItemTree &tree = *get_static_item_tree();
const asset_system::AssetCatalogTreeItem *item = tree.catalogs.find_root_item(catalog_path);
if (!item) {
return;
}
asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available(
asset_system::all_library_reference());
if (!all_library) {
return;
}
PointerRNA path_ptr = asset::persistent_catalog_path_rna_pointer(screen, *all_library, *item);
if (path_ptr.data == nullptr) {
return;
}
uiItemS(&layout);
uiLayout *col = uiLayoutColumn(&layout, false);
uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr);
uiItemMContents(col, "OBJECT_MT_add_modifier_catalog_assets");
}
} // namespace blender::ed::object

View File

@ -369,3 +369,13 @@ void OBJECT_OT_datalayout_transfer(struct wmOperatorType *ot);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
namespace blender::ed::object {
void object_modifier_add_asset_register();
}
#endif

View File

@ -38,7 +38,6 @@
#include "BKE_DerivedMesh.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_curves.h"
@ -1265,7 +1264,6 @@ static const EnumPropertyItem *modifier_add_itemf(bContext *C,
PropertyRNA * /*prop*/,
bool *r_free)
{
using namespace blender;
Object *ob = ED_object_active_context(C);
if (!ob) {
@ -1303,45 +1301,6 @@ static const EnumPropertyItem *modifier_add_itemf(bContext *C,
RNA_enum_item_add(&items, &totitem, md_item);
}
const AssetLibraryReference library_ref = asset_system::all_library_reference();
AssetFilterSettings filter_settings{};
filter_settings.id_types = FILTER_ID_NT;
int i = 200;
ED_assetlist_storage_fetch(&library_ref, C);
ED_assetlist_ensure_previews_job(&library_ref, C);
ED_assetlist_iterate(library_ref, [&](asset_system::AssetRepresentation &asset) {
if (!ED_asset_filter_matches_asset(&filter_settings, asset)) {
return true;
}
const AssetMetaData &asset_data = asset.get_metadata();
const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&asset_data, "type");
if (tree_type == nullptr || IDP_Int(tree_type) != NTREE_GEOMETRY) {
return true;
}
const IDProperty *traits = BKE_asset_metadata_idprop_find(&asset_data,
"geometry_node_asset_traits_flag");
if (traits == nullptr ||
(IDP_Int(traits) & (GEO_NODE_ASSET_MODIFIER | GEO_NODE_ASSET_MESH | GEO_NODE_ASSET_MESH |
GEO_NODE_ASSET_POINT_CLOUD)) == 0)
{
return true;
}
EnumPropertyItem item{};
item.value = i;
item.identifier = asset.get_name().c_str();
item.icon = ICON_GEOMETRY_NODES;
item.name = asset.get_name().c_str();
item.description = asset_data.description;
RNA_enum_item_add(&items, &totitem, &item);
i++;
return true;
});
RNA_enum_item_end(&items, &totitem);
*r_free = true;

View File

@ -28,6 +28,7 @@
void ED_operatortypes_object()
{
using namespace blender::ed::object;
WM_operatortype_append(OBJECT_OT_location_clear);
WM_operatortype_append(OBJECT_OT_rotation_clear);
WM_operatortype_append(OBJECT_OT_scale_clear);
@ -288,6 +289,8 @@ void ED_operatortypes_object()
WM_operatortype_append(OBJECT_OT_light_linking_blockers_link);
WM_operatortype_append(OBJECT_OT_light_linking_unlink_from_collection);
object_modifier_add_asset_register();
}
void ED_operatormacros_object()

View File

@ -98,17 +98,9 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu)
return;
}
catalog_item->foreach_child([&](asset_system::AssetCatalogTreeItem &child_item) {
PointerRNA path_ptr = asset::persistent_catalog_path_rna_pointer(
screen, *all_library, child_item);
if (path_ptr.data == nullptr) {
return;
}
uiLayout *col = uiLayoutColumn(layout, false);
uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr);
uiItemM(
col, "NODE_MT_node_add_catalog_assets", IFACE_(child_item.get_name().c_str()), ICON_NONE);
catalog_item->foreach_child([&](asset_system::AssetCatalogTreeItem &item) {
asset::draw_menu_for_catalog(
screen, *all_library, item, "NODE_MT_node_add_catalog_assets", *layout);
});
}
@ -180,16 +172,10 @@ static void add_root_catalogs_draw(const bContext *C, Menu *menu)
}
tree.catalogs.foreach_root_item([&](asset_system::AssetCatalogTreeItem &item) {
if (all_builtin_menus.contains(item.get_name())) {
return;
if (!all_builtin_menus.contains(item.get_name())) {
asset::draw_menu_for_catalog(
screen, *all_library, item, "NODE_MT_node_add_catalog_assets", *layout);
}
PointerRNA path_ptr = asset::persistent_catalog_path_rna_pointer(screen, *all_library, item);
if (path_ptr.data == nullptr) {
return;
}
uiLayout *col = uiLayoutColumn(layout, false);
uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr);
uiItemM(col, "NODE_MT_node_add_catalog_assets", IFACE_(item.get_name().c_str()), ICON_NONE);
});
}

View File

@ -38,6 +38,7 @@ const EnumPropertyItem rna_enum_icon_items[] = {
# include "DNA_asset_types.h"
# include "ED_geometry.hh"
# include "ED_object.hh"
const char *rna_translate_ui_text(
const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop, bool translate)
@ -786,6 +787,16 @@ static void rna_uiLayout_template_node_operator_asset_menu_items(uiLayout *layou
}
}
static void rna_uiLayout_template_modifier_asset_menu_items(uiLayout *layout,
bContext *C,
const char *catalog_path)
{
if (U.experimental.use_node_group_operators) {
blender::ed::object::ui_template_modifier_asset_menu_items(
*layout, *C, blender::StringRef(catalog_path));
}
}
static void rna_uiLayout_template_node_operator_root_items(uiLayout *layout, bContext *C)
{
if (U.experimental.use_node_group_operators) {
@ -1893,6 +1904,12 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "catalog_path", nullptr, 0, "", "");
func = RNA_def_function(srna,
"template_modifier_asset_menu_items",
"rna_uiLayout_template_modifier_asset_menu_items");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "catalog_path", nullptr, 0, "", "");
func = RNA_def_function(srna,
"template_node_operator_asset_menu_items",
"rna_uiLayout_template_node_operator_asset_menu_items");