Geometry Nodes: Require modifier tag for add menu, show non-assets
Any geometry node group with the "Is Modifier" tag is exposed in the add modifier menu. Local node groups that aren't assets are displayed in a subsection of the "Unassigned" menu, as they are "asset wannabees" that function similarly but aren't shared to other files. Only modifier node groups can be assigned to the geometry nodes modifier. Because of this, existing node groups are versioned to have the tag if they have a geometry output. Internally, this means the operator that used to only handle node group assets has to also add local geometry node groups. That change isn't so large though. The other changes are just UI, or changes to the node group property poll functions. Note: For assets, saving the file to generate asset meta-data may be necessary for the versioning to affect the add modifier menu. Pull Request: https://projects.blender.org/blender/blender/pulls/112918
This commit is contained in:
@@ -161,8 +161,6 @@ class NODE_HT_header(Header):
|
||||
row.template_ID(active_modifier, "node_group", new="node.new_geometry_node_group_assign")
|
||||
else:
|
||||
row.template_ID(snode, "node_tree", new="node.new_geometry_nodes_modifier")
|
||||
if snode.node_tree and snode.node_tree.asset_data:
|
||||
layout.popover(panel="NODE_PT_geometry_node_modifier")
|
||||
else:
|
||||
layout.template_ID(snode, "node_tree", new="node.new_geometry_node_group_tool")
|
||||
if snode.node_tree and snode.node_tree.asset_data:
|
||||
@@ -484,22 +482,6 @@ class NODE_PT_geometry_node_tool_mode(Panel):
|
||||
row_label.label(text=name, icon=icon)
|
||||
|
||||
|
||||
class NODE_PT_geometry_node_modifier(Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Modifier"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
snode = context.space_data
|
||||
group = snode.node_tree
|
||||
|
||||
layout.prop(group, "is_modifier")
|
||||
|
||||
|
||||
class NODE_PT_node_color_presets(PresetPanel, Panel):
|
||||
"""Predefined node color"""
|
||||
bl_label = "Color Presets"
|
||||
@@ -976,6 +958,38 @@ class NODE_PT_node_tree_interface(Panel):
|
||||
layout.use_property_split = False
|
||||
|
||||
|
||||
class NODE_PT_node_tree_properties(Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "Group"
|
||||
bl_label = "Properties"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
snode = context.space_data
|
||||
if snode is None:
|
||||
return False
|
||||
group = snode.edit_tree
|
||||
if group is None:
|
||||
return False
|
||||
if group.is_embedded_data:
|
||||
return False
|
||||
if group.bl_idname != "GeometryNodeTree":
|
||||
return False
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
snode = context.space_data
|
||||
group = snode.edit_tree
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
col = layout.column()
|
||||
col.prop(group, "is_modifier")
|
||||
col.prop(group, "is_tool")
|
||||
|
||||
|
||||
class NODE_UL_simulation_zone_items(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
@@ -1180,12 +1194,12 @@ classes = (
|
||||
NODE_MT_context_menu,
|
||||
NODE_MT_view_pie,
|
||||
NODE_PT_material_slots,
|
||||
NODE_PT_geometry_node_modifier,
|
||||
NODE_PT_geometry_node_tool_object_types,
|
||||
NODE_PT_geometry_node_tool_mode,
|
||||
NODE_PT_node_color_presets,
|
||||
NODE_MT_node_tree_interface_context_menu,
|
||||
NODE_PT_node_tree_interface,
|
||||
NODE_PT_node_tree_properties,
|
||||
NODE_PT_active_node_generic,
|
||||
NODE_PT_active_node_color,
|
||||
NODE_PT_texture_mapping,
|
||||
|
||||
@@ -977,6 +977,34 @@ static void version_node_group_split_socket(bNodeTreeInterface &tree_interface,
|
||||
csocket->flag &= ~NODE_INTERFACE_SOCKET_OUTPUT;
|
||||
}
|
||||
|
||||
static void enable_geometry_nodes_is_modifier(Main &bmain)
|
||||
{
|
||||
/* Any node group with a first socket geometry output can potentially be a modifier. Previously
|
||||
* this wasn't an explicit option, so better to enable too many groups rather than too few. */
|
||||
LISTBASE_FOREACH (bNodeTree *, group, &bmain.nodetrees) {
|
||||
if (group->type != NTREE_GEOMETRY) {
|
||||
continue;
|
||||
}
|
||||
group->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
|
||||
if (item.item_type != NODE_INTERFACE_SOCKET) {
|
||||
return true;
|
||||
}
|
||||
const auto &socket = reinterpret_cast<const bNodeTreeInterfaceSocket &>(item);
|
||||
if ((socket.flag & NODE_INTERFACE_SOCKET_OUTPUT) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (!STREQ(socket.socket_type, "NodeSocketGeometry")) {
|
||||
return true;
|
||||
}
|
||||
if (!group->geometry_node_asset_traits) {
|
||||
group->geometry_node_asset_traits = MEM_new<GeometryNodeAssetTraits>(__func__);
|
||||
}
|
||||
group->geometry_node_asset_traits->flag |= GEO_NODE_ASSET_MODIFIER;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
{
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 1)) {
|
||||
@@ -1443,6 +1471,15 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 26)) {
|
||||
enable_geometry_nodes_is_modifier(*bmain);
|
||||
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
scene->simulation_frame_start = scene->r.sfra;
|
||||
scene->simulation_frame_end = scene->r.efra;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
@@ -1455,10 +1492,5 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
scene->simulation_frame_start = scene->r.sfra;
|
||||
scene->simulation_frame_end = scene->r.efra;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
@@ -95,7 +96,7 @@ static void catalog_assets_draw(const bContext *C, Menu *menu)
|
||||
uiLayout *layout = menu->layout;
|
||||
uiItemS(layout);
|
||||
|
||||
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_asset", true);
|
||||
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_node_group", true);
|
||||
for (const asset_system::AssetRepresentation *asset : assets) {
|
||||
PointerRNA props_ptr;
|
||||
uiItemFullO_ptr(layout,
|
||||
@@ -121,11 +122,29 @@ static void catalog_assets_draw(const bContext *C, Menu *menu)
|
||||
});
|
||||
}
|
||||
|
||||
static void unassigned_assets_draw(const bContext * /*C*/, Menu *menu)
|
||||
static bool unassigned_local_poll(const Main &bmain)
|
||||
{
|
||||
LISTBASE_FOREACH (const bNodeTree *, group, &bmain.nodetrees) {
|
||||
/* Assets are displayed in other menus, and non-local data-blocks aren't added to this menu. */
|
||||
if (group->id.library_weak_reference || group->id.asset_data) {
|
||||
continue;
|
||||
}
|
||||
if (!group->geometry_node_asset_traits ||
|
||||
!(group->geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void unassigned_assets_draw(const bContext *C, Menu *menu)
|
||||
{
|
||||
Main &bmain = *CTX_data_main(C);
|
||||
asset::AssetItemTree &tree = *get_static_item_tree();
|
||||
uiLayout *layout = menu->layout;
|
||||
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_asset", true);
|
||||
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_node_group", true);
|
||||
for (const asset_system::AssetRepresentation *asset : tree.unassigned_assets) {
|
||||
PointerRNA props_ptr;
|
||||
uiItemFullO_ptr(layout,
|
||||
@@ -138,6 +157,37 @@ static void unassigned_assets_draw(const bContext * /*C*/, Menu *menu)
|
||||
&props_ptr);
|
||||
asset::operator_asset_reference_props_set(*asset, props_ptr);
|
||||
}
|
||||
|
||||
bool add_separator = !tree.unassigned_assets.is_empty();
|
||||
|
||||
LISTBASE_FOREACH (const bNodeTree *, group, &bmain.nodetrees) {
|
||||
/* Assets are displayed in other menus, and non-local data-blocks aren't added to this menu. */
|
||||
if (group->id.library_weak_reference || group->id.asset_data) {
|
||||
continue;
|
||||
}
|
||||
if (!group->geometry_node_asset_traits ||
|
||||
!(group->geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (add_separator) {
|
||||
uiItemS(layout);
|
||||
uiItemL(layout, IFACE_("Non-Assets"), ICON_NONE);
|
||||
add_separator = false;
|
||||
}
|
||||
|
||||
PointerRNA props_ptr;
|
||||
uiItemFullO_ptr(layout,
|
||||
ot,
|
||||
group->id.name + 2,
|
||||
ICON_NONE,
|
||||
nullptr,
|
||||
WM_OP_INVOKE_DEFAULT,
|
||||
UI_ITEM_NONE,
|
||||
&props_ptr);
|
||||
WM_operator_properties_id_lookup_set_from_id(&props_ptr, &group->id);
|
||||
}
|
||||
}
|
||||
|
||||
static void root_catalogs_draw(const bContext *C, Menu *menu)
|
||||
@@ -193,7 +243,7 @@ static void root_catalogs_draw(const bContext *C, Menu *menu)
|
||||
}
|
||||
});
|
||||
|
||||
if (!tree.unassigned_assets.is_empty()) {
|
||||
if (!tree.unassigned_assets.is_empty() || unassigned_local_poll(*CTX_data_main(C))) {
|
||||
uiItemS(layout);
|
||||
uiItemM(layout,
|
||||
"OBJECT_MT_add_modifier_unassigned_assets",
|
||||
@@ -202,16 +252,28 @@ static void root_catalogs_draw(const bContext *C, Menu *menu)
|
||||
}
|
||||
}
|
||||
|
||||
static bNodeTree *get_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports)
|
||||
static bNodeTree *get_asset_or_local_node_group(const bContext &C,
|
||||
PointerRNA &ptr,
|
||||
ReportList *reports)
|
||||
{
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
if (bNodeTree *group = reinterpret_cast<bNodeTree *>(
|
||||
WM_operator_properties_id_lookup_from_name_or_session_uuid(&bmain, &ptr, ID_NT)))
|
||||
{
|
||||
return group;
|
||||
}
|
||||
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
asset::operator_asset_reference_props_get_asset_from_all_library(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));
|
||||
return reinterpret_cast<bNodeTree *>(asset::asset_local_id_ensure_imported(bmain, *asset));
|
||||
}
|
||||
|
||||
static bNodeTree *get_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports)
|
||||
{
|
||||
bNodeTree *node_group = get_asset_or_local_node_group(C, ptr, reports);
|
||||
if (!node_group) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -270,11 +332,11 @@ static std::string modifier_add_asset_get_description(bContext *C,
|
||||
return TIP_(asset->get_metadata().description);
|
||||
}
|
||||
|
||||
static void OBJECT_OT_modifier_add_asset(wmOperatorType *ot)
|
||||
static void OBJECT_OT_modifier_add_node_group(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->idname = "OBJECT_OT_modifier_add_node_group";
|
||||
|
||||
ot->exec = modifier_add_asset_exec;
|
||||
ot->poll = ED_operator_object_active_editable;
|
||||
@@ -283,6 +345,7 @@ static void OBJECT_OT_modifier_add_asset(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
asset::operator_asset_reference_props_register(*ot->srna);
|
||||
WM_operator_properties_id_lookup(ot, false);
|
||||
}
|
||||
|
||||
static MenuType modifier_add_unassigned_assets_menu_type()
|
||||
@@ -291,7 +354,6 @@ static MenuType modifier_add_unassigned_assets_menu_type()
|
||||
STRNCPY(type.idname, "OBJECT_MT_add_modifier_unassigned_assets");
|
||||
type.draw = unassigned_assets_draw;
|
||||
type.listener = asset::asset_reading_region_listen_fn;
|
||||
type.flag = MenuTypeFlag::ContextDependent;
|
||||
type.description = N_(
|
||||
"Modifier node group assets not assigned to a catalog.\n"
|
||||
"Catalogs can be assigned in the Asset Browser");
|
||||
@@ -323,7 +385,7 @@ 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_unassigned_assets_menu_type()));
|
||||
WM_menutype_add(MEM_new<MenuType>(__func__, modifier_add_root_catalogs_menu_type()));
|
||||
WM_operatortype_append(OBJECT_OT_modifier_add_asset);
|
||||
WM_operatortype_append(OBJECT_OT_modifier_add_node_group);
|
||||
}
|
||||
|
||||
void ui_template_modifier_asset_menu_items(uiLayout &layout,
|
||||
|
||||
@@ -1679,18 +1679,10 @@ static bool rna_NodesModifier_node_group_poll(PointerRNA * /*ptr*/, PointerRNA v
|
||||
if (ntree->type != NTREE_GEOMETRY) {
|
||||
return false;
|
||||
}
|
||||
if (ntree->id.asset_data) {
|
||||
if (!ntree->geometry_node_asset_traits ||
|
||||
(ntree->geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER) == 0)
|
||||
{
|
||||
/* Only node group assets specially marked as modifiers can be modifiers. */
|
||||
return false;
|
||||
}
|
||||
if (!ntree->geometry_node_asset_traits) {
|
||||
return false;
|
||||
}
|
||||
if (ntree->geometry_node_asset_traits &&
|
||||
ntree->geometry_node_asset_traits->flag & GEO_NODE_ASSET_TOOL)
|
||||
{
|
||||
/* Tool node groups cannot be modifiers. */
|
||||
if ((ntree->geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER) == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -2507,30 +2507,27 @@ static void rna_SpaceNodeEditor_node_tree_set(PointerRNA *ptr,
|
||||
ED_node_tree_start(snode, (bNodeTree *)value.data, nullptr, nullptr);
|
||||
}
|
||||
|
||||
static bool space_node_node_geometry_nodes_tool_poll(const SpaceNode &snode,
|
||||
const bNodeTree &ntree)
|
||||
static bool space_node_node_geometry_nodes_poll(const SpaceNode &snode, const bNodeTree &ntree)
|
||||
{
|
||||
if (snode.geometry_nodes_type == SNODE_GEOMETRY_TOOL) {
|
||||
if (!ntree.id.asset_data) {
|
||||
/* Only assets can be tools. */
|
||||
return false;
|
||||
}
|
||||
if (!ntree.geometry_node_asset_traits ||
|
||||
(ntree.geometry_node_asset_traits->flag & GEO_NODE_ASSET_TOOL) == 0)
|
||||
{
|
||||
/* Only node groups specifically marked as tools can be tools. */
|
||||
return false;
|
||||
}
|
||||
switch (SpaceNodeGeometryNodesType(snode.geometry_nodes_type)) {
|
||||
case SNODE_GEOMETRY_MODIFIER:
|
||||
if (!ntree.geometry_node_asset_traits) {
|
||||
return false;
|
||||
}
|
||||
if ((ntree.geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER) == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case SNODE_GEOMETRY_TOOL:
|
||||
if (!ntree.geometry_node_asset_traits) {
|
||||
return false;
|
||||
}
|
||||
if ((ntree.geometry_node_asset_traits->flag & GEO_NODE_ASSET_TOOL) == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (ntree.geometry_node_asset_traits &&
|
||||
ntree.geometry_node_asset_traits->flag & GEO_NODE_ASSET_TOOL)
|
||||
{
|
||||
/* Tool node groups cannot be modifiers. */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rna_SpaceNodeEditor_node_tree_poll(PointerRNA *ptr, const PointerRNA value)
|
||||
@@ -2543,10 +2540,8 @@ static bool rna_SpaceNodeEditor_node_tree_poll(PointerRNA *ptr, const PointerRNA
|
||||
return false;
|
||||
}
|
||||
if (ntree->type == NTREE_GEOMETRY) {
|
||||
if (snode->geometry_nodes_type == SNODE_GEOMETRY_TOOL) {
|
||||
if (!space_node_node_geometry_nodes_tool_poll(*snode, *ntree)) {
|
||||
return false;
|
||||
}
|
||||
if (!space_node_node_geometry_nodes_poll(*snode, *ntree)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -2559,7 +2554,7 @@ static void rna_SpaceNodeEditor_geometry_nodes_type_update(Main * /*bmain*/,
|
||||
SpaceNode &snode = *static_cast<SpaceNode *>(ptr->data);
|
||||
if (snode.nodetree) {
|
||||
if (snode.nodetree->type == NTREE_GEOMETRY) {
|
||||
if (!space_node_node_geometry_nodes_tool_poll(snode, *snode.nodetree)) {
|
||||
if (!space_node_node_geometry_nodes_poll(snode, *snode.nodetree)) {
|
||||
snode.nodetree = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user