Blender V4.3
add_modifier_assets.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "AS_asset_catalog.hh"
7#include "AS_asset_library.hh"
9
11#include "BLI_string.h"
12
13#include "DNA_modifier_types.h"
14#include "DNA_screen_types.h"
15#include "DNA_space_types.h"
16
17#include "BKE_asset.hh"
18#include "BKE_context.hh"
19#include "BKE_idprop.hh"
20#include "BKE_lib_id.hh"
21#include "BKE_main.hh"
22#include "BKE_modifier.hh"
23#include "BKE_report.hh"
24#include "BKE_screen.hh"
25
26#include "BLT_translation.hh"
27
28#include "RNA_access.hh"
29#include "RNA_define.hh"
30
31#include "ED_asset.hh"
33#include "ED_object.hh"
34#include "ED_screen.hh"
35
36#include "MOD_nodes.hh"
37
38#include "UI_interface.hh"
39
40#include "WM_api.hh"
41
42#include "object_intern.hh"
43
44namespace blender::ed::object {
45
47{
49 return asset::list::is_loaded(&all_library_ref);
50}
51
53{
54 asset::AssetFilterSettings type_filter{};
55 type_filter.id_types = FILTER_ID_NT;
56 auto meta_data_filter = [&](const AssetMetaData &meta_data) {
57 const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type");
58 if (tree_type == nullptr || IDP_Int(tree_type) != NTREE_GEOMETRY) {
59 return false;
60 }
61 const IDProperty *traits_flag = BKE_asset_metadata_idprop_find(
62 &meta_data, "geometry_node_asset_traits_flag");
63 if (traits_flag == nullptr || !(IDP_Int(traits_flag) & GEO_NODE_ASSET_MODIFIER)) {
64 return false;
65 }
66 return true;
67 };
70 return asset::build_filtered_all_catalog_tree(library, C, type_filter, meta_data_filter);
71}
72
78
79static void catalog_assets_draw(const bContext *C, Menu *menu)
80{
82
83 const std::optional<StringRefNull> menu_path = CTX_data_string_get(C, "asset_catalog_path");
84 if (!menu_path) {
85 return;
86 }
87 const Span<asset_system::AssetRepresentation *> assets = tree.assets_per_path.lookup(
88 menu_path->data());
89 const asset_system::AssetCatalogTreeItem *catalog_item = tree.catalogs.find_item(
90 menu_path->data());
91 BLI_assert(catalog_item != nullptr);
92
93 if (assets.is_empty() && !catalog_item->has_children()) {
94 return;
95 }
96
97 uiLayout *layout = menu->layout;
98 uiItemS(layout);
99
100 wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_node_group", true);
101 for (const asset_system::AssetRepresentation *asset : assets) {
102 PointerRNA props_ptr;
103 uiItemFullO_ptr(layout,
104 ot,
105 IFACE_(asset->get_name().c_str()),
106 ICON_NONE,
107 nullptr,
110 &props_ptr);
112 }
113
114 catalog_item->foreach_child([&](const asset_system::AssetCatalogTreeItem &item) {
115 asset::draw_menu_for_catalog(item, "OBJECT_MT_add_modifier_catalog_assets", *layout);
116 });
117}
118
119static bool unassigned_local_poll(const Main &bmain)
120{
121 LISTBASE_FOREACH (const bNodeTree *, group, &bmain.nodetrees) {
122 /* Assets are displayed in other menus, and non-local data-blocks aren't added to this menu. */
123 if (group->id.library_weak_reference || group->id.asset_data) {
124 continue;
125 }
126 if (!group->geometry_node_asset_traits ||
127 !(group->geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER))
128 {
129 continue;
130 }
131 return true;
132 }
133 return false;
134}
135
136static void unassigned_assets_draw(const bContext *C, Menu *menu)
137{
138 Main &bmain = *CTX_data_main(C);
140 uiLayout *layout = menu->layout;
141 wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_node_group", true);
142 for (const asset_system::AssetRepresentation *asset : tree.unassigned_assets) {
143 PointerRNA props_ptr;
144 uiItemFullO_ptr(layout,
145 ot,
146 IFACE_(asset->get_name().c_str()),
147 ICON_NONE,
148 nullptr,
151 &props_ptr);
153 }
154
155 bool first = true;
156 bool add_separator = !tree.unassigned_assets.is_empty();
157 LISTBASE_FOREACH (const bNodeTree *, group, &bmain.nodetrees) {
158 /* Assets are displayed in other menus, and non-local data-blocks aren't added to this menu. */
159 if (group->id.library_weak_reference || group->id.asset_data) {
160 continue;
161 }
162 if (!group->geometry_node_asset_traits ||
163 !(group->geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER))
164 {
165 continue;
166 }
167
168 if (add_separator) {
169 uiItemS(layout);
170 add_separator = false;
171 }
172 if (first) {
173 uiItemL(layout, IFACE_("Non-Assets"), ICON_NONE);
174 first = false;
175 }
176
177 PointerRNA props_ptr;
178 uiItemFullO_ptr(layout,
179 ot,
180 group->id.name + 2,
181 ICON_NONE,
182 nullptr,
185 &props_ptr);
186 WM_operator_properties_id_lookup_set_from_id(&props_ptr, &group->id);
187 }
188}
189
190static void root_catalogs_draw(const bContext *C, Menu *menu)
191{
192 const Object *object = context_active_object(C);
193 if (!object) {
194 return;
195 }
196 uiLayout *layout = menu->layout;
197
198 const bool loading_finished = all_loading_finished();
199
202 if (tree.catalogs.is_empty() && loading_finished) {
203 return;
204 }
205
206 uiItemS(layout);
207
208 if (!loading_finished) {
209 uiItemL(layout, IFACE_("Loading Asset Libraries"), ICON_INFO);
210 }
211
212 Set<std::string> all_builtin_menus = [&]() {
213 Set<std::string> menus;
214 if (ELEM(object->type, OB_MESH, OB_CURVES_LEGACY, OB_FONT, OB_SURF, OB_LATTICE)) {
215 menus.add_new("Edit");
216 }
217 if (ELEM(object->type, OB_MESH, OB_CURVES_LEGACY, OB_FONT, OB_SURF, OB_VOLUME)) {
218 menus.add_new("Generate");
219 }
221 menus.add_new("Deform");
222 }
223 if (ELEM(object->type, OB_MESH)) {
224 menus.add_new("Normals");
225 }
226 if (ELEM(object->type, OB_MESH, OB_CURVES_LEGACY, OB_FONT, OB_SURF, OB_LATTICE)) {
227 menus.add_new("Physics");
228 }
229 return menus;
230 }();
231
232 tree.catalogs.foreach_root_item([&](const asset_system::AssetCatalogTreeItem &item) {
233 if (!all_builtin_menus.contains(item.get_name())) {
234 asset::draw_menu_for_catalog(item, "OBJECT_MT_add_modifier_catalog_assets", *layout);
235 }
236 });
237
238 if (!tree.unassigned_assets.is_empty() || unassigned_local_poll(*CTX_data_main(C))) {
239 uiItemS(layout);
240 uiItemM(layout,
241 "OBJECT_MT_add_modifier_unassigned_assets",
242 IFACE_("Unassigned"),
243 ICON_FILE_HIDDEN);
244 }
245}
246
249 ReportList *reports)
250{
251 Main &bmain = *CTX_data_main(&C);
252 if (bNodeTree *group = reinterpret_cast<bNodeTree *>(
254 {
255 return group;
256 }
257
260 if (!asset) {
261 return nullptr;
262 }
263 return reinterpret_cast<bNodeTree *>(asset::asset_local_id_ensure_imported(bmain, *asset));
264}
265
267{
268 bNodeTree *node_group = get_asset_or_local_node_group(C, ptr, reports);
269 if (!node_group) {
270 return nullptr;
271 }
272 if (node_group->type != NTREE_GEOMETRY) {
273 if (reports) {
274 BKE_report(reports, RPT_ERROR, "Asset is not a geometry node group");
275 }
276 return nullptr;
277 }
278 return node_group;
279}
280
282{
283 Main *bmain = CTX_data_main(C);
284 Scene *scene = CTX_data_scene(C);
285
287 if (objects.is_empty()) {
288 return OPERATOR_CANCELLED;
289 }
290
291 bNodeTree *node_group = get_node_group(*C, *op->ptr, op->reports);
292 if (!node_group) {
293 return OPERATOR_CANCELLED;
294 }
295
296 bool changed = false;
297 for (const PointerRNA &ptr : objects) {
298 Object *object = static_cast<Object *>(ptr.data);
299 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(
300 modifier_add(op->reports, bmain, scene, object, nullptr, eModifierType_Nodes));
301 if (!nmd) {
302 continue;
303 }
304 changed = true;
305 nmd->node_group = node_group;
306 id_us_plus(&node_group->id);
307 MOD_nodes_update_interface(object, nmd);
308
309 /* Don't show the data-block selector since it's not usually necessary for assets. */
311
312 STRNCPY(nmd->modifier.name, DATA_(node_group->id.name + 2));
313 BKE_modifier_unique_name(&object->modifiers, &nmd->modifier);
314
316 }
317
318 if (!changed) {
319 return OPERATOR_CANCELLED;
320 }
321
322 return OPERATOR_FINISHED;
323}
324
325static int modifier_add_asset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
326{
327 if (event->modifier & KM_ALT || CTX_wm_view3d(C)) {
328 RNA_boolean_set(op->ptr, "use_selected_objects", true);
329 }
330 return modifier_add_asset_exec(C, op);
331}
332
334 wmOperatorType * /*ot*/,
336{
339 if (!asset) {
340 return "";
341 }
342 if (!asset->get_metadata().description) {
343 return "";
344 }
345 return TIP_(asset->get_metadata().description);
346}
347
349{
350 ot->name = "Add Modifier";
351 ot->description = "Add a procedural operation/effect to the active object";
352 ot->idname = "OBJECT_OT_modifier_add_node_group";
353
358
360
364}
365
367{
368 MenuType type{};
369 STRNCPY(type.idname, "OBJECT_MT_add_modifier_unassigned_assets");
370 type.draw = unassigned_assets_draw;
372 type.description = N_(
373 "Modifier node group assets not assigned to a catalog.\n"
374 "Catalogs can be assigned in the Asset Browser");
375 return type;
376}
377
379{
380 MenuType type{};
381 STRNCPY(type.idname, "OBJECT_MT_add_modifier_catalog_assets");
382 type.draw = catalog_assets_draw;
385 return type;
386}
387
389{
390 MenuType type{};
391 STRNCPY(type.idname, "OBJECT_MT_modifier_add_root_catalogs");
392 type.draw = root_catalogs_draw;
395 return type;
396}
397
405
407{
409 const asset_system::AssetCatalogTreeItem *item = tree.catalogs.find_root_item(catalog_path);
410 if (!item) {
411 return;
412 }
415 if (!all_library) {
416 return;
417 }
418 uiItemS(&layout);
419 uiLayout *col = uiLayoutColumn(&layout, false);
420 uiLayoutSetContextString(col, "asset_catalog_path", item->catalog_path().str());
421 uiItemMContents(col, "OBJECT_MT_add_modifier_catalog_assets");
422}
423
424} // namespace blender::ed::object
Main runtime representation of an asset.
IDProperty * BKE_asset_metadata_idprop_find(const AssetMetaData *asset_data, const char *name) ATTR_WARN_UNUSED_RESULT
Definition asset.cc:186
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
std::optional< blender::StringRefNull > CTX_data_string_get(const bContext *C, const char *member)
View3D * CTX_wm_view3d(const bContext *C)
#define IDP_Int(prop)
void id_us_plus(ID *id)
Definition lib_id.cc:351
void BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define ELEM(...)
#define TIP_(msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
#define FILTER_ID_NT
Definition DNA_ID.h:1180
@ ID_NT
@ NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR
@ eModifierType_Nodes
@ NTREE_GEOMETRY
@ GEO_NODE_ASSET_MODIFIER
@ OB_LATTICE
@ OB_SURF
@ OB_FONT
@ OB_MESH
@ OB_VOLUME
@ OB_CURVES_LEGACY
bool ED_operator_object_active_editable(bContext *C)
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
Definition MOD_nodes.cc:453
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemS(uiLayout *layout)
void uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
#define UI_ITEM_NONE
void uiItemMContents(uiLayout *layout, const char *menuname)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetContextString(uiLayout *layout, const char *name, blender::StringRef value)
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon)
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_MODIFIER
Definition WM_types.hh:429
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ KM_ALT
Definition WM_types.hh:257
#define NC_OBJECT
Definition WM_types.hh:346
bool contains(const Key &key) const
Definition BLI_set.hh:291
void add_new(const Key &key)
Definition BLI_set.hh:233
constexpr bool is_empty() const
Definition BLI_span.hh:261
void foreach_child(ItemIterFn callback) const
KDTree_3d * tree
uint col
AssetLibraryReference all_library_reference()
void all_library_reload_catalogs_if_dirty()
asset_system::AssetLibrary * library_get_once_available(const AssetLibraryReference &library_reference)
bool is_loaded(const AssetLibraryReference *library_reference)
void asset_reading_region_listen_fn(const wmRegionListenerParams *params)
AssetItemTree build_filtered_all_catalog_tree(const AssetLibraryReference &library_ref, const bContext &C, const AssetFilterSettings &filter_settings, FunctionRef< bool(const AssetMetaData &)> meta_data_filter={})
ID * asset_local_id_ensure_imported(Main &bmain, const asset_system::AssetRepresentation &asset)
void operator_asset_reference_props_register(StructRNA &srna)
void draw_menu_for_catalog(const asset_system::AssetCatalogTreeItem &item, const StringRefNull menu_name, uiLayout &layout)
const asset_system::AssetRepresentation * operator_asset_reference_props_get_asset_from_all_library(const bContext &C, PointerRNA &ptr, ReportList *reports)
void operator_asset_reference_props_set(const asset_system::AssetRepresentation &asset, PointerRNA &ptr)
static void root_catalogs_draw(const bContext *C, Menu *menu)
void modifier_register_use_selected_objects_prop(wmOperatorType *ot)
ModifierData * modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
static void catalog_assets_draw(const bContext *C, Menu *menu)
static bNodeTree * get_asset_or_local_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports)
static void OBJECT_OT_modifier_add_node_group(wmOperatorType *ot)
static void unassigned_assets_draw(const bContext *C, Menu *menu)
static int modifier_add_asset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static asset::AssetItemTree * get_static_item_tree()
static MenuType modifier_add_root_catalogs_menu_type()
void ui_template_modifier_asset_menu_items(uiLayout &layout, StringRef catalog_path)
static bNodeTree * get_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports)
static bool unassigned_local_poll(const Main &bmain)
static MenuType modifier_add_unassigned_assets_menu_type()
static MenuType modifier_add_catalog_assets_menu_type()
static bool all_loading_finished()
static std::string modifier_add_asset_get_description(bContext *C, wmOperatorType *, PointerRNA *ptr)
static asset::AssetItemTree build_catalog_tree(const bContext &C)
Object * context_active_object(const bContext *C)
static int modifier_add_asset_exec(bContext *C, wmOperator *op)
Vector< PointerRNA > modifier_get_edit_objects(const bContext &C, const wmOperator &op)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
char name[66]
Definition DNA_ID.h:425
ListBase nodetrees
Definition BKE_main.hh:234
uiLayout * layout
struct bNodeTree * node_group
void * data
Definition RNA_types.hh:42
uint8_t modifier
Definition WM_types.hh:739
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
std::string(* get_description)(bContext *C, wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1074
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
#define N_(msgid)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
bool WM_menutype_add(MenuType *mt)
ID * WM_operator_properties_id_lookup_from_name_or_session_uid(Main *bmain, PointerRNA *ptr, const ID_Type type)
void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
void WM_operator_properties_id_lookup_set_from_id(PointerRNA *ptr, const ID *id)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)