Geometry Nodes: support panels in geometry nodes modifier #116472

Merged
Jacques Lucke merged 10 commits from JacquesLucke/blender:nodes-modifier-panels into main 2023-12-23 16:33:25 +01:00
3 changed files with 149 additions and 25 deletions
Showing only changes of commit 7535272e3b - Show all commits

View File

@ -2348,7 +2348,7 @@ typedef struct NodesModifierBake {
typedef struct NodesModifierPanel {
/** ID of the corresponding panel from #bNodeTreeInterfacePanel::identifier. */
int panel_id;
int id;
/** #NodesModifierPanelFlag. */
uint32_t flag;
} NodesModifierPanel;

View File

@ -7115,6 +7115,30 @@ static void rna_def_modifier_nodes_bakes(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Bakes", "Bake data for every bake node");
}
static void rna_def_modifier_nodes_panel(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "NodesModifierPanel", nullptr);
RNA_def_struct_ui_text(srna, "Nodes Modifier Panel", "");
prop = RNA_def_property(srna, "is_open", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", NODES_MODIFIER_PANEL_OPEN);
RNA_def_property_ui_text(prop, "Is Open", "Whether the panel is expanded or closed");
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, nullptr);
}
static void rna_def_modifier_nodes_panels(BlenderRNA *brna)
{
StructRNA *srna;
srna = RNA_def_struct(brna, "NodesModifierPanels", nullptr);
RNA_def_struct_sdna(srna, "NodesModifierData");
RNA_def_struct_ui_text(srna, "Panels", "State of all panels defined by the node group");
}
static void rna_def_modifier_nodes(BlenderRNA *brna)
{
StructRNA *srna;
@ -7123,6 +7147,9 @@ static void rna_def_modifier_nodes(BlenderRNA *brna)
rna_def_modifier_nodes_bake(brna);
rna_def_modifier_nodes_bakes(brna);
rna_def_modifier_nodes_panel(brna);
rna_def_modifier_nodes_panels(brna);
srna = RNA_def_struct(brna, "NodesModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Nodes Modifier", "");
RNA_def_struct_sdna(srna, "NodesModifierData");
@ -7148,6 +7175,11 @@ static void rna_def_modifier_nodes(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, nullptr, "bakes", "bakes_num");
RNA_def_property_srna(prop, "NodesModifierBakes");
prop = RNA_def_property(srna, "panels", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "NodesModifierPanel");
RNA_def_property_collection_sdna(prop, nullptr, "panels", "panels_num");
RNA_def_property_srna(prop, "NodesModifierPanels");
prop = RNA_def_property(srna, "show_group_selector", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, nullptr, "flag", NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR);

View File

@ -427,6 +427,49 @@ static void update_bakes_from_node_group(NodesModifierData &nmd)
update_existing_bake_caches(nmd);
}
static void update_panels_from_node_group(NodesModifierData &nmd)
{
Map<int, NodesModifierPanel *> old_panel_by_id;
for (NodesModifierPanel &panel : MutableSpan(nmd.panels, nmd.panels_num)) {
old_panel_by_id.add(panel.id, &panel);
}
Vector<const bNodeTreeInterfacePanel *> interface_panels;
if (nmd.node_group) {
nmd.node_group->ensure_interface_cache();
nmd.node_group->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
if (item.item_type != NODE_INTERFACE_PANEL) {
return true;
}
interface_panels.append(reinterpret_cast<const bNodeTreeInterfacePanel *>(&item));
return true;
});
}
NodesModifierPanel *new_panels = MEM_cnew_array<NodesModifierPanel>(interface_panels.size(),
__func__);
for (const int i : interface_panels.index_range()) {
const bNodeTreeInterfacePanel &interface_panel = *interface_panels[i];
const int id = interface_panel.identifier;
NodesModifierPanel *old_panel = old_panel_by_id.lookup_default(id, nullptr);
NodesModifierPanel &new_panel = new_panels[i];
if (old_panel) {
new_panel = *old_panel;
}
else {
new_panel.id = id;
const bool default_closed = interface_panel.flag & NODE_INTERFACE_PANEL_DEFAULT_CLOSED;
SET_FLAG_FROM_TEST(new_panel.flag, default_closed, NODES_MODIFIER_PANEL_OPEN);
}
}
MEM_SAFE_FREE(nmd.panels);
nmd.panels = new_panels;
nmd.panels_num = interface_panels.size();
}
} // namespace blender
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
@ -434,6 +477,7 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
using namespace blender;
update_id_properties_from_node_group(nmd);
update_bakes_from_node_group(*nmd);
update_panels_from_node_group(*nmd);
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
}
@ -1834,10 +1878,57 @@ static void draw_property_for_output_socket(const bContext &C,
add_attribute_search_button(C, row, nmd, md_ptr, rna_path_attribute_name, socket, true);
}
static NodesModifierPanel *find_panel_by_id(const NodesModifierData &nmd, const int id)
JacquesLucke marked this conversation as resolved Outdated

Return a const pointer or make the nmd argument non-const

Return a const pointer or make the `nmd` argument non-const
{
for (const int i : IndexRange(nmd.panels_num)) {
if (nmd.panels[i].id == id) {
return &nmd.panels[i];
}
}
return nullptr;
}
static void draw_interface_panel_content(const bContext *C,
uiLayout *layout,
PointerRNA *modifier_ptr,
NodesModifierData &nmd,
const bNodeTreeInterfacePanel &interface_panel,
int &next_input_index)
{
Main *bmain = CTX_data_main(C);
PointerRNA bmain_ptr = RNA_main_pointer_create(bmain);
for (const bNodeTreeInterfaceItem *item : interface_panel.items()) {
if (item->item_type == NODE_INTERFACE_PANEL) {
const bNodeTreeInterfacePanel &sub_interface_panel =
JacquesLucke marked this conversation as resolved Outdated

Using const auto & after these reinterpret casts looks a bit nicer

Using `const auto &` after these reinterpret casts looks a bit nicer
*reinterpret_cast<const bNodeTreeInterfacePanel *>(item);
NodesModifierPanel *panel = find_panel_by_id(nmd, sub_interface_panel.identifier);
PointerRNA panel_ptr = RNA_pointer_create(
modifier_ptr->owner_id, &RNA_NodesModifierPanel, panel);
if (uiLayout *panel_layout = uiLayoutPanel(
C, layout, sub_interface_panel.name, &panel_ptr, "is_open"))
{
draw_interface_panel_content(
C, panel_layout, modifier_ptr, nmd, sub_interface_panel, next_input_index);
}
}
else {
const bNodeTreeInterfaceSocket &interface_socket =
*reinterpret_cast<const bNodeTreeInterfaceSocket *>(item);
if (interface_socket.flag & NODE_INTERFACE_SOCKET_INPUT) {
if (!(interface_socket.flag & NODE_INTERFACE_SOCKET_HIDE_IN_MODIFIER)) {
draw_property_for_socket(
*C, layout, &nmd, &bmain_ptr, modifier_ptr, interface_socket, next_input_index);
}
next_input_index++;
}
}
}
}
static void panel_draw(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
Main *bmain = CTX_data_main(C);
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
@ -1861,17 +1952,10 @@ static void panel_draw(const bContext *C, Panel *panel)
}
if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
PointerRNA bmain_ptr = RNA_main_pointer_create(bmain);
nmd->node_group->ensure_interface_cache();
for (const int socket_index : nmd->node_group->interface_inputs().index_range()) {
const bNodeTreeInterfaceSocket *socket = nmd->node_group->interface_inputs()[socket_index];
if (is_layer_selection_field(*socket) ||
!(socket->flag & NODE_INTERFACE_SOCKET_HIDE_IN_MODIFIER)) {
draw_property_for_socket(*C, layout, nmd, &bmain_ptr, ptr, *socket, socket_index);
}
}
int next_input_index = 0;
draw_interface_panel_content(
C, layout, ptr, *nmd, nmd->node_group->tree_interface.root_panel, next_input_index);
}
/* Draw node warnings. */
@ -1994,19 +2078,19 @@ static void internal_dependencies_panel_draw(const bContext * /*C*/, Panel *pane
static void panel_register(ARegionType *region_type)
{
using namespace blender;
PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
modifier_subpanel_register(region_type,
"output_attributes",
N_("Output Attributes"),
nullptr,
output_attribute_panel_draw,
panel_type);
modifier_subpanel_register(region_type,
"internal_dependencies",
N_("Internal Dependencies"),
nullptr,
internal_dependencies_panel_draw,
panel_type);
modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
// modifier_subpanel_register(region_type,
// "output_attributes",
// N_("Output Attributes"),
// nullptr,
// output_attribute_panel_draw,
// panel_type);
// modifier_subpanel_register(region_type,
// "internal_dependencies",
// N_("Internal Dependencies"),
// nullptr,
// internal_dependencies_panel_draw,
// panel_type);
}
static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
@ -2041,6 +2125,7 @@ static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const Modi
for (const NodesModifierBake &bake : Span(nmd->bakes, nmd->bakes_num)) {
BLO_write_string(writer, bake.directory);
}
BLO_write_struct_array(writer, NodesModifierPanel, nmd->panels_num, nmd->panels);
if (!BLO_write_is_undo(writer)) {
LISTBASE_FOREACH (IDProperty *, prop, &nmd->settings.properties->data.group) {
@ -2073,6 +2158,7 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
for (NodesModifierBake &bake : MutableSpan(nmd->bakes, nmd->bakes_num)) {
BLO_read_data_address(reader, &bake.directory);
}
BLO_read_data_address(reader, &nmd->panels);
nmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
nmd->runtime->cache = std::make_shared<bake::ModifierCache>();
@ -2095,6 +2181,10 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
}
}
if (nmd->panels) {
tnmd->panels = static_cast<NodesModifierPanel *>(MEM_dupallocN(nmd->panels));
}
tnmd->runtime = MEM_new<NodesModifierRuntime>(__func__);
if (flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) {
@ -2128,6 +2218,8 @@ static void free_data(ModifierData *md)
}
MEM_SAFE_FREE(nmd->bakes);
MEM_SAFE_FREE(nmd->panels);
MEM_SAFE_FREE(nmd->bake_directory);
MEM_delete(nmd->runtime);
}