WIP: Closures and deferred evaluation for geometry nodes #107842

Draft
Lukas Tönne wants to merge 35 commits from LukasTonne/blender:geometry-nodes-closures into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 243 additions and 47 deletions
Showing only changes of commit 249bb47f5a - Show all commits

View File

@ -9,6 +9,7 @@ from bpy.types import (
from bpy.props import (
BoolProperty,
CollectionProperty,
EnumProperty,
StringProperty,
)
@ -198,10 +199,109 @@ class NODE_OT_tree_path_parent(Operator):
return {'FINISHED'}
class NodeFunctionSignatureOperator():
# Dictionary of node types with methods to get the signature
signature_nodes = {
'FunctionNodeEvaluate' : lambda node: node.signature,
}
param_type: EnumProperty(
name = "Parameter Type",
items = [
('INPUT', "Input", ""),
('OUTPUT', "Output", ""),
]
)
def params_get(self, signature):
return signature.inputs if self.param_type == 'INPUT' else signature.outputs
@classmethod
def poll(cls, context):
snode = context.space_data
if snode is None:
return False
node = context.active_node
if node is None or node.bl_idname not in cls.signature_nodes:
return False
return True
class NODE_OT_function_parameter_add(NodeFunctionSignatureOperator, Operator):
'''Add a parameter to the function signature'''
bl_idname = "node.function_parameter_add"
bl_label = "Add Parameter"
bl_options = {'REGISTER', 'UNDO'}
default_socket_type = 'FLOAT'
def execute(self, context):
node = context.active_node
signature = self.signature_nodes[node.bl_idname](node)
params = self.params_get(signature)
# Remember index to move the item
dst_index = min(params.active_index + 1, len(params))
# Empty name so it is based on the type only
params.new(self.default_socket_type, "")
params.move(len(params) - 1, dst_index)
params.active_index = dst_index
return {'FINISHED'}
class NODE_OT_function_parameter_remove(NodeFunctionSignatureOperator, Operator):
'''Remove a parameter from the function signature'''
bl_idname = "node.function_parameter_remove"
bl_label = "Remove Parameter"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
node = context.active_node
signature = self.signature_nodes[node.bl_idname](node)
params = self.params_get(signature)
if params.active:
params.remove(params.active)
params.active_index = min(params.active_index, len(params) - 1)
return {'FINISHED'}
class NODE_OT_function_parameter_move(NodeFunctionSignatureOperator, Operator):
'''Move a parameter item up or down in the signature'''
bl_idname = "node.function_parameter_move"
bl_label = "Move Parameter"
bl_options = {'REGISTER', 'UNDO'}
direction: EnumProperty(
name="Direction",
items=[('UP', "Up", ""), ('DOWN', "Down", "")],
default = 'UP',
)
def execute(self, context):
node = context.active_node
signature = self.signature_nodes[node.bl_idname](node)
params = self.params_get(signature)
if self.direction == 'UP' and params.active_index > 0:
params.move(params.active_index, params.active_index - 1)
params.active_index -= 1
elif self.direction == 'DOWN' and params.active_index < len(params) - 1:
params.move(params.active_index, params.active_index + 1)
params.active_index += 1
return {'FINISHED'}
classes = (
NodeSetting,
NODE_OT_add_node,
NODE_OT_collapse_hide_unused_toggle,
NODE_OT_tree_path_parent,
NODE_OT_function_parameter_add,
NODE_OT_function_parameter_remove,
NODE_OT_function_parameter_move,
)

View File

@ -955,6 +955,98 @@ class NODE_PT_node_tree_interface_outputs(NodeTreeInterfacePanel):
self.draw_socket_list(context, "OUT", "outputs", "active_output")
class NODE_UL_function_parameters(bpy.types.UIList):
def draw_item(self, context, layout, _data, item, icon, _active_data, _active_propname, _index):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
row = layout.row(align=True)
row.template_node_socket(color=item.color)
row.prop(item, "name", text="", emboss=False, icon_value=icon)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.template_node_socket(color=item.color)
class FunctionSignaturePanel():
# Must be defined by subclasses
param_type = None
params_prop = None
# Dictionary of node types with methods to get the signature
signature_nodes = {
'FunctionNodeEvaluate' : lambda node: node.signature,
}
@classmethod
def poll(cls, context):
snode = context.space_data
if snode is None:
return False
node = context.active_node
if node is None or node.bl_idname not in cls.signature_nodes:
return False
return True
def draw(self, context):
layout = self.layout
node = context.active_node
signature = self.signature_nodes[node.bl_idname](node)
params = getattr(signature, self.params_prop)
split = layout.row()
split.template_list(
"NODE_UL_function_parameters",
self.params_prop,
signature,
self.params_prop,
params,
"active_index")
ops_col = split.column()
add_remove_col = ops_col.column(align=True)
props = add_remove_col.operator("node.function_parameter_add", icon='ADD', text="")
props.param_type = self.param_type
props = add_remove_col.operator("node.function_parameter_remove", icon='REMOVE', text="")
props.param_type = self.param_type
ops_col.separator()
up_down_col = ops_col.column(align=True)
props = up_down_col.operator("node.function_parameter_move", icon='TRIA_UP', text="")
props.param_type = self.param_type
props.direction = 'UP'
props = up_down_col.operator("node.function_parameter_move", icon='TRIA_DOWN', text="")
props.param_type = self.param_type
props.direction = 'DOWN'
active_param = params.active
if active_param is not None:
layout.prop(active_param, "socket_type")
layout.prop(active_param, "name")
class NODE_PT_function_signature_inputs(FunctionSignaturePanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Node"
bl_label = "Function Signature Inputs"
param_type = 'INPUT'
params_prop = "inputs"
class NODE_PT_function_signature_outputs(FunctionSignaturePanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Node"
bl_label = "Function Signature Outputs"
param_type = 'OUTPUT'
params_prop = "outputs"
# Grease Pencil properties
class NODE_PT_annotation(AnnotationDataPanel, Panel):
bl_space_type = 'NODE_EDITOR'
@ -1019,6 +1111,9 @@ classes = (
NODE_UL_interface_sockets,
NODE_PT_node_tree_interface_inputs,
NODE_PT_node_tree_interface_outputs,
NODE_UL_function_parameters,
NODE_PT_function_signature_inputs,
NODE_PT_function_signature_outputs,
node_panel(EEVEE_MATERIAL_PT_settings),
node_panel(MATERIAL_PT_viewport),

View File

@ -258,6 +258,10 @@ bool nodeFunctionParameterSetUniqueName(bNodeFunctionSignature *sig,
unique_name,
ARRAY_SIZE(unique_name));
}
else if (unique_name[0] == '\0') {
/* Should use default if name is empty, same as BLI_uniquename_cb behavior. */
BLI_strncpy(unique_name, defname, sizeof(unique_name));
}
param->name = BLI_strdup(unique_name);
return name_changed;
}

View File

@ -5490,30 +5490,57 @@ static void rna_def_node_function_parameter(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Color", "Socket color");
}
static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out)
static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *cprop, eNodeFunctionParameterType param_type)
{
StructRNA *srna;
PropertyRNA *prop;
PropertyRNA *parm;
FunctionRNA *func;
const char *structtype = (in_out == SOCK_IN ? "NodeFunctionSignatureInputs" : "NodeFunctionSignatureOutputs");
const char *uiname = (in_out == SOCK_IN ? "Node Function Signature Inputs" : "Node Function Signature Outputs");
const char *newfunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_new" :
"rna_NodeFunctionSignature_outputs_new");
const char *structtype = (param_type == NODE_FUNC_PARAM_IN ? "NodeFunctionSignatureInputs" :
"NodeFunctionSignatureOutputs");
const char *uiname = (param_type == NODE_FUNC_PARAM_IN ? "Node Function Signature Inputs" :
"Node Function Signature Outputs");
const char *active_index_sdna = (param_type == NODE_FUNC_PARAM_IN ? "active_input" :
"active_output");
const char *active_param_get = (param_type == NODE_FUNC_PARAM_IN ?
"rna_NodeFunctionSignature_active_input_get" :
"rna_NodeFunctionSignature_active_output_get");
const char *active_param_set = (param_type == NODE_FUNC_PARAM_IN ?
"rna_NodeFunctionSignature_active_input_set" :
"rna_NodeFunctionSignature_active_output_set");
const char *newfunc = (param_type == NODE_FUNC_PARAM_IN ?
"rna_NodeFunctionSignature_inputs_new" :
"rna_NodeFunctionSignature_outputs_new");
const char *removefunc = "rna_NodeFunctionSignature_params_remove";
const char *clearfunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_clear" :
"rna_NodeFunctionSignature_outputs_clear");
const char *movefunc = (in_out == SOCK_IN ? "rna_NodeFunctionSignature_inputs_move" :
"rna_NodeFunctionSignature_outputs_move");
const char *clearfunc = (param_type == NODE_FUNC_PARAM_IN ?
"rna_NodeFunctionSignature_inputs_clear" :
"rna_NodeFunctionSignature_outputs_clear");
const char *movefunc = (param_type == NODE_FUNC_PARAM_IN ?
"rna_NodeFunctionSignature_inputs_move" :
"rna_NodeFunctionSignature_outputs_move");
RNA_def_property_srna(cprop, structtype);
srna = RNA_def_struct(brna, structtype, NULL);
RNA_def_struct_sdna(srna, "bNodeFunctionSignature");
RNA_def_struct_ui_text(srna, uiname, "Collection of node function parameters");
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, active_index_sdna);
RNA_def_property_ui_text(prop, "Active Index", "Index of the active parameter");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_NODE, NULL);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "NodeFunctionParameter");
RNA_def_property_pointer_funcs(prop, active_param_get, active_param_set, NULL, NULL);
RNA_def_property_ui_text(prop, "Active", "Active parameter");
RNA_def_property_update(prop, NC_NODE, NULL);
func = RNA_def_function(srna, "new", newfunc);
RNA_def_function_ui_description(func, "Add a parameter to this signature");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type");
parm = RNA_def_enum(
func, "socket_type", node_socket_data_type_items, SOCK_FLOAT, "Type", "Data type");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
@ -5529,11 +5556,11 @@ static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *c
func = RNA_def_function(srna, "clear", clearfunc);
RNA_def_function_ui_description(func, "Remove all parameters from this collection");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
func = RNA_def_function(srna, "move", movefunc);
RNA_def_function_ui_description(func, "Move a parameter to another position");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
parm = RNA_def_int(
func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the parameter to move", 0, 10000);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
@ -5556,46 +5583,14 @@ static void rna_def_node_function_signature(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "NodeFunctionParameter");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Inputs", "Function inputs");
rna_def_node_function_signature_api(brna, prop, SOCK_IN);
rna_def_node_function_signature_api(brna, prop, NODE_FUNC_PARAM_IN);
prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "outputs", "outputs_num");
RNA_def_property_struct_type(prop, "NodeFunctionParameter");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Outputs", "Function outputs");
rna_def_node_function_signature_api(brna, prop, SOCK_OUT);
prop = RNA_def_property(srna, "active_input_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "active_input");
RNA_def_property_ui_text(prop, "Active Input Index", "Index of the active input");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_NODE, NULL);
prop = RNA_def_property(srna, "active_output_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "active_output");
RNA_def_property_ui_text(prop, "Active Output Index", "Index of the active output");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_NODE, NULL);
prop = RNA_def_property(srna, "active_input", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "NodeFunctionParameter");
RNA_def_property_pointer_funcs(prop,
"rna_NodeFunctionSignature_active_input_get",
"rna_NodeFunctionSignature_active_input_set",
NULL,
NULL);
RNA_def_property_ui_text(prop, "Active Input Index", "Index of the active input");
RNA_def_property_update(prop, NC_NODE, NULL);
prop = RNA_def_property(srna, "active_output", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "NodeFunctionParameter");
RNA_def_property_pointer_funcs(prop,
"rna_NodeFunctionSignature_active_output_get",
"rna_NodeFunctionSignature_active_output_set",
NULL,
NULL);
RNA_def_property_ui_text(prop, "Active Output Index", "Index of the active output");
RNA_def_property_update(prop, NC_NODE, NULL);
rna_def_node_function_signature_api(brna, prop, NODE_FUNC_PARAM_OUT);
}
static void def_fn_evaluate(StructRNA *srna)

View File

@ -342,7 +342,9 @@ SocketDeclarationPtr declaration_for_signature_parameter(const bNodeFunctionPara
dst = std::make_unique<decl::Custom>();
break;
}
dst->name = param.name;
dst->name = param.name ? param.name : "";
char buf[MAX_NAME];
dst->identifier = BLI_snprintf(buf, sizeof(buf), "Item_%d", param.identifier);
dst->in_out = in_out;
dst->hide_value = true;
dst->compact = false;