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
22 changed files with 809 additions and 222 deletions

View File

@ -230,6 +230,7 @@ class NewGeometryNodesModifier(Operator):
return {'CANCELLED'}
group = geometry_node_group_empty_new()
group.is_modifier = True
modifier.node_group = group
return {'FINISHED'}
@ -257,6 +258,7 @@ class NewGeometryNodeTreeAssign(Operator):
if not modifier:
return {'CANCELLED'}
group = geometry_node_group_empty_new()
group.is_modifier = True
modifier.node_group = group
return {'FINISHED'}

View File

@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
from bpy.types import Panel
from bpy.types import Panel, Menu
class ModifierButtonsPanel:
@ -22,10 +22,151 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
def draw(self, _context):
layout = self.layout
layout.operator_menu_enum("object.modifier_add", "type")
layout.operator("wm.call_menu", text="Add Modifier", icon='ADD').name="OBJECT_MT_modifier_add"
layout.template_modifiers()
class OBJECT_MT_modifier_add(Menu):
bl_label = "Add Modifier"
def draw(self, context):
layout = self.layout
ob_type = context.object.type
geometry_nodes_supported = ob_type in {'MESH', 'CURVE', 'CURVES', 'FONT', 'SURFACE', 'VOLUME', 'POINTCLOUD'}

All these if statements are pretty ugly, but since we're not going to be adding more of them in the future, I think it's better to keep things simple and not abstract it.

All these if statements are pretty ugly, but since we're not going to be adding more of them in the future, I think it's better to keep things simple and not abstract it.
if geometry_nodes_supported:
layout.operator("object.modifier_add", text="Empty Modifier").type='NODES'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.menu("OBJECT_MT_modifier_add_edit")
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'VOLUME'}:
layout.menu("OBJECT_MT_modifier_add_generate")
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE', 'VOLUME'}:
layout.menu("OBJECT_MT_modifier_add_deform")
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.menu("OBJECT_MT_modifier_add_physics")
if geometry_nodes_supported:
layout.menu_contents("OBJECT_MT_modifier_add_root_catalogs")
class OBJECT_MT_modifier_add_edit(Menu):
bl_label = "Edit"
def draw(self, context):
layout = self.layout
ob_type = context.object.type
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Data Transfer", icon='MOD_DATA_TRANSFER').type='DATA_TRANSFER'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Mesh Cache", icon='MOD_MESHDEFORM').type='MESH_CACHE'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Mesh Sequence Cache", icon='MOD_MESHDEFORM').type='MESH_SEQUENCE_CACHE'
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Normal Edit", icon='MOD_NORMALEDIT').type='NORMAL_EDIT'
layout.operator("object.modifier_add", text="Weighted Normal", icon='MOD_NORMALEDIT').type='WEIGHTED_NORMAL'
layout.operator("object.modifier_add", text="UV Project", icon='MOD_UVPROJECT').type='UV_PROJECT'
layout.operator("object.modifier_add", text="UV Warp", icon='MOD_UVPROJECT').type='UV_WARP'
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):
bl_label = "Generate"
def draw(self, context):
layout = self.layout
ob_type = context.object.type
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Array", icon='MOD_ARRAY').type='ARRAY'
layout.operator("object.modifier_add", text="Bevel", icon='MOD_BEVEL').type='BEVEL'
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Boolean", icon='MOD_BOOLEAN').type='BOOLEAN'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Build", icon='MOD_BUILD').type='BUILD'
layout.operator("object.modifier_add", text="Decimate", icon='MOD_DECIM').type='DECIMATE'
layout.operator("object.modifier_add", text="Edge Split", icon='MOD_EDGESPLIT').type='EDGE_SPLIT'
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Mask", icon='MOD_MASK').type='MASK'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Mirror", icon='MOD_MIRROR').type='MIRROR'
if ob_type == 'VOLUME':
layout.operator("object.modifier_add", text="Mesh to Volume", icon='VOLUME_DATA').type='MESH_TO_VOLUME'
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Multiresolution", icon='MOD_MULTIRES').type='MULTIRES'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Remesh", icon='MOD_REMESH').type='REMESH'
layout.operator("object.modifier_add", text="Screw", icon='MOD_SCREW').type='SCREW'
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Skin", icon='MOD_SKIN').type='SKIN'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Solidify", icon='MOD_SOLIDIFY').type='SOLIDIFY'
layout.operator("object.modifier_add", text="Subdivision Surface", icon='MOD_SUBSURF').type='SUBSURF'
layout.operator("object.modifier_add", text="Triangulate", icon='MOD_TRIANGULATE').type='TRIANGULATE'
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Volume to Mesh", icon='VOLUME_DATA').type='VOLUME_TO_MESH'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Weld", icon='AUTOMERGE_OFF').type='WELD'
if ob_type == 'MESH':
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):
bl_label = "Deform"
def draw(self, context):
layout = self.layout
ob_type = context.object.type
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Armature", icon='MOD_ARMATURE').type='ARMATURE'
layout.operator("object.modifier_add", text="Cast", icon='MOD_CAST').type='CAST'
layout.operator("object.modifier_add", text="Curve", icon='MOD_CURVE').type='CURVE'
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Displace", icon='MOD_DISPLACE').type='DISPLACE'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Hook", icon='HOOK').type='HOOK'
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Laplacian Deform", icon='MOD_MESHDEFORM').type='LAPLACIANDEFORM'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Lattice", icon='MOD_LATTICE').type='LATTICE'
layout.operator("object.modifier_add", text="Mesh Deform", icon='MOD_MESHDEFORM').type='MESH_DEFORM'
layout.operator("object.modifier_add", text="Shrinkwrap", icon='MOD_SHRINKWRAP').type='SHRINKWRAP'
layout.operator("object.modifier_add", text="Simple Deform", icon='MOD_SIMPLEDEFORM').type='SIMPLE_DEFORM'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE'}:
layout.operator("object.modifier_add", text="Smooth", icon='MOD_SMOOTH').type='SMOOTH'
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Smooth Corrective", icon='MOD_SMOOTH').type='CORRECTIVE_SMOOTH'
layout.operator("object.modifier_add", text="Smooth Laplacian", icon='MOD_SMOOTH').type='LAPLACIANSMOOTH'
layout.operator("object.modifier_add", text="Surface Deform", icon='MOD_MESHDEFORM').type='SURFACE_DEFORM'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
layout.operator("object.modifier_add", text="Warp", icon='MOD_WARP').type='WARP'
layout.operator("object.modifier_add", text="Wave", icon='MOD_WAVE').type='WAVE'
if ob_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):
bl_label = "Physics"
def draw(self, context):
layout = self.layout
ob_type = context.object.type
if ob_type == 'MESH':
layout.operator("object.modifier_add", text="Cloth", icon='MOD_CLOTH').type='CLOTH'
layout.operator("object.modifier_add", text="Collision", icon='MOD_PHYSICS').type='COLLISION'
layout.operator("object.modifier_add", text="Dynamic Paint", icon='MOD_DYNAMICPAINT').type='DYNAMIC_PAINT'
layout.operator("object.modifier_add", text="Explode", icon='MOD_EXPLODE').type='EXPLODE'
layout.operator("object.modifier_add", text="Fluid", icon='MOD_FLUIDSIM').type='FLUID'
layout.operator("object.modifier_add", text="Ocean", icon='MOD_OCEAN').type='OCEAN'
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'
if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}:
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):
bl_label = "Modifiers"
@ -42,6 +183,11 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
classes = (
DATA_PT_modifiers,
OBJECT_MT_modifier_add,
OBJECT_MT_modifier_add_edit,
OBJECT_MT_modifier_add_generate,
OBJECT_MT_modifier_add_deform,
OBJECT_MT_modifier_add_physics,
DATA_PT_gpencil_modifiers,
)

View File

@ -160,6 +160,8 @@ 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_asset_traits")
else:
layout.template_ID(snode, "node_tree", new="node.new_geometry_node_group_tool")
if snode.node_tree and snode.node_tree.asset_data:
@ -448,18 +450,21 @@ class NODE_PT_geometry_node_asset_traits(Panel):
snode = context.space_data
group = snode.node_tree
col = layout.column(heading="Type")
col.prop(group, "is_tool")
col = layout.column(heading="Mode")
col.active = group.is_tool
col.prop(group, "is_mode_edit")
col.prop(group, "is_mode_sculpt")
col = layout.column(heading="Geometry")
col.active = group.is_tool
col.prop(group, "is_type_mesh")
col.prop(group, "is_type_curve")
if context.preferences.experimental.use_new_point_cloud_type:
col.prop(group, "is_type_point_cloud")
if snode.geometry_nodes_type == 'MODIFIER':
layout.prop(group, "is_modifier")
else:
col = layout.column(heading="Type")
col.prop(group, "is_tool")
col = layout.column(heading="Mode")
col.active = group.is_tool
col.prop(group, "is_mode_edit")
col.prop(group, "is_mode_sculpt")
col = layout.column(heading="Geometry")
col.active = group.is_tool
col.prop(group, "is_type_mesh")
col.prop(group, "is_type_curve")
if context.preferences.experimental.use_new_point_cloud_type:
col.prop(group, "is_type_point_cloud")
class NODE_PT_node_color_presets(PresetPanel, Panel):

View File

@ -31,6 +31,7 @@ set(SRC
intern/asset_library_reference_enum.cc
intern/asset_list.cc
intern/asset_mark_clear.cc
intern/asset_menu_utils.cc
intern/asset_ops.cc
intern/asset_shelf.cc
intern/asset_shelf_asset_view.cc

View File

@ -26,10 +26,6 @@
struct AssetLibrary;
struct bScreen;
namespace blender::asset_system {
class AssetCatalogTreeItem;
}
/**
* Returns if the catalogs of \a library are allowed to be editable, or if the UI should forbid
* edits.
@ -59,16 +55,3 @@ void ED_asset_catalog_move(
AssetLibrary *library,
blender::asset_system::CatalogID src_catalog_id,
std::optional<blender::asset_system::CatalogID> dst_parent_catalog_id = std::nullopt);
namespace blender::ed::asset {
/**
* Some code needs to pass catalog paths to context and for this they need persistent pointers to
* the paths. Rather than keeping some local path storage, get a pointer into the asset system
* directly, which is persistent until the library is reloaded and can safely be held by context.
*/
PointerRNA persistent_catalog_path_rna_pointer(const bScreen &owner_screen,
const asset_system::AssetLibrary &library,
const asset_system::AssetCatalogTreeItem &item);
} // namespace blender::ed::asset

View File

@ -47,13 +47,3 @@ void ED_asset_handle_get_full_library_path(
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
namespace blender::ed::asset {
PointerRNA create_asset_rna_ptr(const asset_system::AssetRepresentation *asset);
}
#endif

View File

@ -206,23 +206,3 @@ bool ED_asset_catalogs_get_save_catalogs_when_file_is_saved()
{
return asset_system::AssetLibrary::save_catalogs_when_file_is_saved;
}
namespace blender::ed::asset {
PointerRNA persistent_catalog_path_rna_pointer(const bScreen &owner_screen,
const asset_system::AssetLibrary &library,
const asset_system::AssetCatalogTreeItem &item)
{
const asset_system::AssetCatalog *catalog = library.catalog_service->find_catalog_by_path(
item.catalog_path());
if (!catalog) {
return PointerRNA_NULL;
}
const asset_system::AssetCatalogPath &path = catalog->path;
return {&const_cast<ID &>(owner_screen.id),
&RNA_AssetCatalogPath,
const_cast<asset_system::AssetCatalogPath *>(&path)};
}
} // namespace blender::ed::asset

View File

@ -57,16 +57,3 @@ void ED_asset_handle_get_full_library_path(const AssetHandle *asset_handle,
BLI_strncpy(r_full_lib_path, library_path.c_str(), FILE_MAX);
}
namespace blender::ed::asset {
PointerRNA create_asset_rna_ptr(const asset_system::AssetRepresentation *asset)
{
PointerRNA ptr{};
ptr.owner_id = nullptr;
ptr.type = &RNA_AssetRepresentation;
ptr.data = const_cast<asset_system::AssetRepresentation *>(asset);
return ptr;
}
} // namespace blender::ed::asset

View File

@ -0,0 +1,186 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edasset
*/
#include "AS_asset_catalog.hh"
#include "AS_asset_catalog_tree.hh"
#include "AS_asset_library.hh"
#include "AS_asset_representation.hh"
#include "DNA_screen_types.h"
#include "BKE_asset.h"
#include "BKE_report.h"
#include "BLT_translation.h"
#include "WM_api.hh"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_enum_types.hh"
#include "RNA_prototypes.h"
#include "ED_asset_list.h"
#include "ED_asset_list.hh"
#include "ED_asset_menu_utils.hh"
#include "UI_interface.hh"
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;
}
const asset_system::AssetRepresentation *operator_asset_reference_props_get_asset_from_all_library(
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);
}
PointerRNA persistent_catalog_path_rna_pointer(const bScreen &owner_screen,
const asset_system::AssetLibrary &library,
const asset_system::AssetCatalogTreeItem &item)
{
const asset_system::AssetCatalog *catalog = library.catalog_service->find_catalog_by_path(
item.catalog_path());
if (!catalog) {
return PointerRNA_NULL;
}
const asset_system::AssetCatalogPath &path = catalog->path;
return {&const_cast<ID &>(owner_screen.id),
&RNA_AssetCatalogPath,
const_cast<asset_system::AssetCatalogPath *>(&path)};
}
PointerRNA create_asset_rna_ptr(const asset_system::AssetRepresentation *asset)
{
PointerRNA ptr{};
ptr.owner_id = nullptr;
ptr.type = &RNA_AssetRepresentation;
ptr.data = const_cast<asset_system::AssetRepresentation *>(asset);
return ptr;
}
void draw_menu_for_catalog(const bScreen &owner_screen,
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"

View File

@ -42,12 +42,12 @@
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_enum_types.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "ED_asset.hh"
#include "ED_asset_menu_utils.hh"
#include "ED_geometry.hh"
#include "ED_mesh.hh"
@ -72,92 +72,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_from_all_library(C, ptr, reports);
if (!asset) {
return nullptr;
}
@ -376,7 +294,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_from_all_library(*C, *ptr, nullptr);
if (!asset) {
return "";
}
@ -534,20 +453,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);
}
/** \} */
@ -706,7 +612,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,
@ -716,11 +621,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(
@ -729,18 +630,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);
});
}
@ -809,17 +701,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

@ -0,0 +1,60 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edasset
*
* Code for dealing with dynamic asset menus and passing assets to operators with RNA properties.
HooglyBoogly marked this conversation as resolved Outdated

This comment should not be copied over.

This comment should not be copied over.
*/
#pragma once
#include "BLI_string_ref.hh"
#include "RNA_types.hh"
struct AssetLibrary;
struct bScreen;
struct uiLayout;
namespace blender::asset_system {
class AssetCatalogTreeItem;
class AssetLibrary;
class AssetRepresentation;
} // namespace blender::asset_system
namespace blender::ed::asset {
/**
* Some code needs to pass catalog paths to context and for this they need persistent pointers to
* the paths. Rather than keeping some local path storage, get a pointer into the asset system
* directly, which is persistent until the library is reloaded and can safely be held by context.
*/
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);
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);
/**
* 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
* that case an "Asset loading is unfinished" report is added.
*
* \note Does not check asset type or meta data.
*/
const asset_system::AssetRepresentation *operator_asset_reference_props_get_asset_from_all_library(
const bContext &C, PointerRNA &ptr, ReportList *reports);
} // namespace blender::ed::asset

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

@ -4,6 +4,7 @@
set(INC
../include
../../asset_system
../../blenfont
../../blenkernel
../../blentranslation
@ -30,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,314 @@
/* 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 "BLI_string.h"
#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_asset_menu_utils.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)
{
const Object *object = ED_object_active_context(C);
if (!object) {
return;
}
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;
if (ELEM(object->type, OB_MESH, OB_CURVES_LEGACY, OB_FONT, OB_SURF, OB_LATTICE)) {
menus.add_new("Edit");
}
if (ELEM(object->type, OB_MESH, OB_CURVES_LEGACY, OB_FONT, OB_SURF, OB_VOLUME)) {
menus.add_new("Generate");
}
if (ELEM(object->type, OB_MESH, OB_CURVES_LEGACY, OB_FONT, OB_SURF, OB_LATTICE, OB_VOLUME)) {
menus.add_new("Deform");
}
if (ELEM(object->type, OB_MESH, OB_CURVES_LEGACY, OB_FONT, OB_SURF, OB_LATTICE)) {
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_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));
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 + 2));
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_from_all_library(*C, *ptr, nullptr);
if (!asset) {
return "";
}
if (!asset->get_metadata().description) {
return "";
}
return TIP_(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;
type.context_dependent = true;
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;
type.context_dependent = true;
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

@ -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

@ -22,6 +22,7 @@
#include "RNA_access.hh"
#include "ED_asset.hh"
#include "ED_asset_menu_utils.hh"
#include "ED_screen.hh"
#include "node_intern.hh"
@ -99,17 +100,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);
});
}
@ -181,16 +174,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

@ -40,6 +40,7 @@ set(SRC
../include/ED_anim_api.hh
../include/ED_armature.hh
../include/ED_asset.hh
../include/ED_asset_menu_utils.hh
../include/ED_buttons.hh
../include/ED_clip.hh
../include/ED_curve.hh

View File

@ -897,6 +897,7 @@ typedef enum GeometryNodeAssetTraitFlag {
GEO_NODE_ASSET_MESH = (1 << 3),
GEO_NODE_ASSET_CURVE = (1 << 4),
GEO_NODE_ASSET_POINT_CLOUD = (1 << 5),
GEO_NODE_ASSET_MODIFIER = (1 << 6),
} GeometryNodeAssetTraitFlag;
ENUM_OPERATORS(GeometryNodeAssetTraitFlag, GEO_NODE_ASSET_POINT_CLOUD);

View File

@ -1785,6 +1785,15 @@ static void rna_GeometryNodeTree_is_tool_set(PointerRNA *ptr, bool value)
geometry_node_asset_trait_flag_set(ptr, GEO_NODE_ASSET_TOOL, value);
}
static bool rna_GeometryNodeTree_is_modifier_get(PointerRNA *ptr)
{
return geometry_node_asset_trait_flag_get(ptr, GEO_NODE_ASSET_MODIFIER);
}
static void rna_GeometryNodeTree_is_modifier_set(PointerRNA *ptr, bool value)
{
geometry_node_asset_trait_flag_set(ptr, GEO_NODE_ASSET_MODIFIER, value);
}
static bool rna_GeometryNodeTree_is_mode_edit_get(PointerRNA *ptr)
{
return geometry_node_asset_trait_flag_get(ptr, GEO_NODE_ASSET_EDIT);
@ -10308,6 +10317,14 @@ static void rna_def_geometry_nodetree(BlenderRNA *brna)
prop, "rna_GeometryNodeTree_is_tool_get", "rna_GeometryNodeTree_is_tool_set");
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
prop = RNA_def_property(srna, "is_modifier", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_MODIFIER);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
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");
prop = RNA_def_property(srna, "is_mode_edit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", GEO_NODE_ASSET_EDIT);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);

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");