Geometry Nodes: Update node tool menus dynamically
See #101778 Remove the requirement of restarting Blender to refresh the extended 3D view menus for node group changes. Also avoid rebuilding the tree of relevant assets and catalogs on every redraw, since parsing asset libraries, etc. could become more expensive than we want. Those two goals combined mean we have to be more rigorous in how we invalidate the cached catalog tree. The first main change required is to clear the tree as asset libraries are being read, similar to other dynamic asset menus. This is done with a 3D view header listener rather than a menu listener in this case. However, that isn't enough, because there is an issue with the asset system where the "all" library isn't updated when the current file library changes. The solution is to explicitly rebuild the "all" library's catalogs when other asset libraries are changed. The other necessity for dynamic updates is clearing the catalog tree to be rebuilt when the node group "asset traits" are changed. This is done with a new notifier type (with the goal of being a bit selective about when we re-read assets). This _also_ requires running the "presave" callback that builds asset metadata when updating the property. Otherwise saving the file and sending the notifier is necessary, which is too confusing. Pull Request: https://projects.blender.org/blender/blender/pulls/112166
This commit is contained in:
@@ -22,6 +22,8 @@
|
||||
# include "BLI_winstuff.h"
|
||||
#endif
|
||||
|
||||
#include "asset_library_service.hh"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
static CLG_LogRef LOG = {"asset_system.asset_catalog_service"};
|
||||
@@ -236,6 +238,7 @@ void AssetCatalogService::prune_catalogs_by_path(const AssetCatalogPath &path)
|
||||
}
|
||||
|
||||
this->rebuild_tree();
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
}
|
||||
|
||||
void AssetCatalogService::prune_catalogs_by_id(const CatalogID catalog_id)
|
||||
@@ -270,6 +273,7 @@ void AssetCatalogService::update_catalog_path(const CatalogID catalog_id,
|
||||
}
|
||||
|
||||
this->rebuild_tree();
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
}
|
||||
|
||||
AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalog_path)
|
||||
@@ -296,6 +300,8 @@ AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalo
|
||||
BLI_assert_msg(catalog_tree_, "An Asset Catalog tree should always exist.");
|
||||
catalog_tree_->insert_item(*catalog_ptr);
|
||||
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
|
||||
return catalog_ptr;
|
||||
}
|
||||
|
||||
@@ -644,6 +650,7 @@ void AssetCatalogService::undo()
|
||||
redo_snapshots_.append(std::move(catalog_collection_));
|
||||
catalog_collection_ = undo_snapshots_.pop_last();
|
||||
rebuild_tree();
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
}
|
||||
|
||||
void AssetCatalogService::redo()
|
||||
@@ -654,6 +661,7 @@ void AssetCatalogService::redo()
|
||||
undo_snapshots_.append(std::move(catalog_collection_));
|
||||
catalog_collection_ = redo_snapshots_.pop_last();
|
||||
rebuild_tree();
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
}
|
||||
|
||||
void AssetCatalogService::undo_push()
|
||||
|
||||
@@ -178,7 +178,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_current_file()
|
||||
return lib;
|
||||
}
|
||||
|
||||
static void rebuild_all_library(AssetLibrary &all_library, const bool reload_catalogs)
|
||||
static void rebuild_all_library_ex(AssetLibrary &all_library, const bool reload_catalogs)
|
||||
{
|
||||
/* Start with empty catalog storage. */
|
||||
all_library.catalog_service = std::make_unique<AssetCatalogService>(
|
||||
@@ -195,6 +195,13 @@ static void rebuild_all_library(AssetLibrary &all_library, const bool reload_cat
|
||||
all_library.catalog_service->rebuild_tree();
|
||||
}
|
||||
|
||||
void AssetLibraryService::rebuild_all_library()
|
||||
{
|
||||
if (all_library_) {
|
||||
rebuild_all_library_ex(*all_library_, false);
|
||||
}
|
||||
}
|
||||
|
||||
AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
|
||||
{
|
||||
/* (Re-)load all other asset libraries. */
|
||||
@@ -218,10 +225,10 @@ AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
|
||||
all_library_ = std::make_unique<AssetLibrary>(ASSET_LIBRARY_ALL);
|
||||
|
||||
/* Don't reload catalogs on this initial read, they've just been loaded above. */
|
||||
rebuild_all_library(*all_library_, /*reload_catlogs=*/false);
|
||||
rebuild_all_library_ex(*all_library_, /*reload_catlogs=*/false);
|
||||
|
||||
all_library_->on_refresh_ = [](AssetLibrary &all_library) {
|
||||
rebuild_all_library(all_library, /*reload_catalogs=*/true);
|
||||
rebuild_all_library_ex(all_library, /*reload_catalogs=*/true);
|
||||
};
|
||||
|
||||
return all_library_.get();
|
||||
|
||||
@@ -80,6 +80,7 @@ class AssetLibraryService {
|
||||
AssetLibrary *get_asset_library_current_file();
|
||||
/** Get the "All" asset library, which loads all others and merges them into one. */
|
||||
AssetLibrary *get_asset_library_all(const Main *bmain);
|
||||
void rebuild_all_library();
|
||||
|
||||
/**
|
||||
* Return the start position of the last blend-file extension in given path,
|
||||
|
||||
@@ -44,6 +44,9 @@ void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node);
|
||||
|
||||
void ntreeUpdateAllNew(Main *main);
|
||||
|
||||
/** Update asset meta-data cache of data-block properties. */
|
||||
void node_update_asset_metadata(bNodeTree &node_tree);
|
||||
|
||||
void ntreeNodeFlagSet(const bNodeTree *ntree, int flag, bool enable);
|
||||
|
||||
/**
|
||||
|
||||
@@ -1094,9 +1094,12 @@ static void ntree_blend_read_after_liblink(BlendLibReader *reader, ID *id)
|
||||
}
|
||||
}
|
||||
|
||||
static void node_tree_asset_pre_save(void *asset_ptr, AssetMetaData *asset_data)
|
||||
void node_update_asset_metadata(bNodeTree &node_tree)
|
||||
{
|
||||
bNodeTree &node_tree = *static_cast<bNodeTree *>(asset_ptr);
|
||||
AssetMetaData *asset_data = node_tree.id.asset_data;
|
||||
if (!asset_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_asset_metadata_idprop_ensure(asset_data, idprop::create("type", node_tree.type).release());
|
||||
auto inputs = idprop::create_group("inputs");
|
||||
@@ -1119,6 +1122,11 @@ static void node_tree_asset_pre_save(void *asset_ptr, AssetMetaData *asset_data)
|
||||
}
|
||||
}
|
||||
|
||||
static void node_tree_asset_pre_save(void *asset_ptr, AssetMetaData * /*asset_data*/)
|
||||
{
|
||||
node_update_asset_metadata(*static_cast<bNodeTree *>(asset_ptr));
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
static AssetTypeInfo AssetType_NT = {
|
||||
|
||||
@@ -511,9 +511,9 @@ static GeometryNodeAssetTraitFlag asset_flag_for_context(const eContextObjectMod
|
||||
}
|
||||
}
|
||||
|
||||
static asset::AssetItemTree *get_static_item_tree(const bContext &C)
|
||||
static asset::AssetItemTree *get_static_item_tree(const eContextObjectMode mode)
|
||||
{
|
||||
switch (eContextObjectMode(CTX_data_mode_enum(&C))) {
|
||||
switch (mode) {
|
||||
case CTX_MODE_EDIT_MESH: {
|
||||
static asset::AssetItemTree tree;
|
||||
return &tree;
|
||||
@@ -539,6 +539,19 @@ static asset::AssetItemTree *get_static_item_tree(const bContext &C)
|
||||
}
|
||||
}
|
||||
|
||||
static asset::AssetItemTree *get_static_item_tree(const bContext &C)
|
||||
{
|
||||
return get_static_item_tree(eContextObjectMode(CTX_data_mode_enum(&C)));
|
||||
}
|
||||
|
||||
void clear_operator_asset_trees()
|
||||
{
|
||||
for (const int mode : IndexRange(CTX_MODE_NUM)) {
|
||||
if (asset::AssetItemTree *tree = get_static_item_tree(eContextObjectMode(mode)))
|
||||
*tree = {};
|
||||
}
|
||||
}
|
||||
|
||||
static asset::AssetItemTree build_catalog_tree(const bContext &C)
|
||||
{
|
||||
const eContextObjectMode ctx_mode = eContextObjectMode(CTX_data_mode_enum(&C));
|
||||
@@ -611,7 +624,7 @@ static Set<std::string> get_builtin_menus(const ObjectType object_type, const eO
|
||||
return menus;
|
||||
}
|
||||
|
||||
static void node_add_catalog_assets_draw(const bContext *C, Menu *menu)
|
||||
static void catalog_assets_draw(const bContext *C, Menu *menu)
|
||||
{
|
||||
bScreen &screen = *CTX_wm_screen(C);
|
||||
asset::AssetItemTree *tree = get_static_item_tree(*C);
|
||||
@@ -666,7 +679,7 @@ MenuType node_group_operator_assets_menu()
|
||||
MenuType type{};
|
||||
STRNCPY(type.idname, "GEO_MT_node_operator_catalog_assets");
|
||||
type.poll = asset_menu_poll;
|
||||
type.draw = node_add_catalog_assets_draw;
|
||||
type.draw = catalog_assets_draw;
|
||||
type.listener = asset::asset_reading_region_listen_fn;
|
||||
type.flag = MenuTypeFlag::ContextDependent;
|
||||
return type;
|
||||
@@ -746,7 +759,9 @@ void ui_template_node_operator_asset_root_items(uiLayout &layout, bContext &C)
|
||||
if (!tree) {
|
||||
return;
|
||||
}
|
||||
*tree = build_catalog_tree(C);
|
||||
if (tree->assets_per_path.size() == 0) {
|
||||
*tree = build_catalog_tree(C);
|
||||
}
|
||||
|
||||
asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available(
|
||||
asset_system::all_library_reference());
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace blender::ed::geometry {
|
||||
MenuType node_group_operator_assets_menu();
|
||||
MenuType node_group_operator_assets_menu_unassigned();
|
||||
|
||||
void clear_operator_asset_trees();
|
||||
|
||||
void ui_template_node_operator_asset_menu_items(uiLayout &layout,
|
||||
bContext &C,
|
||||
StringRef catalog_path);
|
||||
|
||||
@@ -1610,8 +1610,30 @@ static void view3d_header_region_listener(const wmRegionListenerParams *params)
|
||||
}
|
||||
break;
|
||||
case NC_SPACE:
|
||||
if (wmn->data == ND_SPACE_VIEW3D) {
|
||||
ED_region_tag_redraw(region);
|
||||
switch (wmn->data) {
|
||||
case ND_SPACE_VIEW3D:
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
case ND_SPACE_ASSET_PARAMS:
|
||||
blender::ed::geometry::clear_operator_asset_trees();
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NC_ASSET:
|
||||
switch (wmn->data) {
|
||||
case ND_ASSET_LIST_READING:
|
||||
blender::ed::geometry::clear_operator_asset_trees();
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NC_NODE:
|
||||
switch (wmn->data) {
|
||||
case ND_NODE_ASSET_DATA:
|
||||
blender::ed::geometry::clear_operator_asset_trees();
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NC_GPENCIL:
|
||||
|
||||
@@ -1045,6 +1045,13 @@ static void rna_NodeTree_update(Main *bmain, Scene * /*scene*/, PointerRNA *ptr)
|
||||
ED_node_tree_propagate_change(nullptr, bmain, ntree);
|
||||
}
|
||||
|
||||
static void rna_NodeTree_update_asset(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
rna_NodeTree_update(bmain, scene, ptr);
|
||||
WM_main_add_notifier(NC_NODE | ND_NODE_ASSET_DATA, nullptr);
|
||||
blender::bke::node_update_asset_metadata(*reinterpret_cast<bNodeTree *>(ptr->owner_id));
|
||||
}
|
||||
|
||||
static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
|
||||
bContext *C,
|
||||
ReportList *reports,
|
||||
@@ -10297,7 +10304,7 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Tool", "The node group is used as a tool");
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_GeometryNodeTree_is_tool_get", "rna_GeometryNodeTree_is_tool_set");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset");
|
||||
|
||||
prop = RNA_def_property(srna, "is_modifier", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_MODIFIER);
|
||||
@@ -10305,7 +10312,7 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Modifier", "The node group is used as a geometry modifier");
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_GeometryNodeTree_is_modifier_get", "rna_GeometryNodeTree_is_modifier_set");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset");
|
||||
|
||||
prop = RNA_def_property(srna, "is_mode_edit", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_EDIT);
|
||||
@@ -10313,7 +10320,7 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Edit", "The node group is used in edit mode");
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_GeometryNodeTree_is_mode_edit_get", "rna_GeometryNodeTree_is_mode_edit_set");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset");
|
||||
|
||||
prop = RNA_def_property(srna, "is_mode_sculpt", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_SCULPT);
|
||||
@@ -10321,7 +10328,7 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Sculpt", "The node group is used in sculpt mode");
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_GeometryNodeTree_is_mode_sculpt_get", "rna_GeometryNodeTree_is_mode_sculpt_set");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset");
|
||||
|
||||
prop = RNA_def_property(srna, "is_type_mesh", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_MESH);
|
||||
@@ -10329,7 +10336,7 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Mesh", "The node group is used for meshes");
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_GeometryNodeTree_is_type_mesh_get", "rna_GeometryNodeTree_is_type_mesh_set");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset");
|
||||
|
||||
prop = RNA_def_property(srna, "is_type_curve", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_CURVE);
|
||||
@@ -10337,7 +10344,7 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Curves", "The node group is used for curves");
|
||||
RNA_def_property_boolean_funcs(
|
||||
prop, "rna_GeometryNodeTree_is_type_curve_get", "rna_GeometryNodeTree_is_type_curve_set");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset");
|
||||
|
||||
prop = RNA_def_property(srna, "is_type_point_cloud", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_POINT_CLOUD);
|
||||
@@ -10346,7 +10353,7 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna)
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_GeometryNodeTree_is_type_point_cloud_get",
|
||||
"rna_GeometryNodeTree_is_type_point_cloud_set");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update_asset");
|
||||
}
|
||||
|
||||
static StructRNA *define_specific_node(BlenderRNA *brna,
|
||||
|
||||
@@ -468,6 +468,9 @@ struct wmNotifier {
|
||||
|
||||
/* NC_NODE Nodes */
|
||||
|
||||
/* Influences which menus node assets are included in. */
|
||||
#define ND_NODE_ASSET_DATA (1 << 16)
|
||||
|
||||
/* NC_SPACE */
|
||||
#define ND_SPACE_CONSOLE (1 << 16) /* general redraw */
|
||||
#define ND_SPACE_INFO_REPORT (2 << 16) /* update for reports, could specify type */
|
||||
|
||||
Reference in New Issue
Block a user