Geometry Nodes: Extend add modifier menu with node group assets #111717
@ -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'}
|
||||
|
@ -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'}
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
186
source/blender/editors/asset/intern/asset_menu_utils.cc
Normal file
186
source/blender/editors/asset/intern/asset_menu_utils.cc
Normal 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
|
@ -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"
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
60
source/blender/editors/include/ED_asset_menu_utils.hh
Normal file
60
source/blender/editors/include/ED_asset_menu_utils.hh
Normal 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
Julian Eisel
commented
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
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
314
source/blender/editors/object/add_modifier_assets.cc
Normal file
314
source/blender/editors/object/add_modifier_assets.cc
Normal 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
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user
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.