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.
6 changed files with 552 additions and 0 deletions
Showing only changes of commit 871d2c418c - Show all commits

View File

@ -224,6 +224,53 @@ typedef int (*NodeGPUExecFunction)(struct GPUMaterial *mat,
struct GPUNodeStack *in,
struct GPUNodeStack *out);
/* -------------------------------------------------------------------- */
/** \name Node Function Signature
* \{ */
struct bNodeSocket *nodeFunctionSignatureFindSocket(struct bNodeFunctionSignature *sig,
eNodeSocketInOut in_out,
const char *identifier);
struct bNodeSocket *nodeFunctionSignatureAddSocket(struct bNodeTree *ntree,
struct bNodeFunctionSignature *sig,
eNodeSocketInOut in_out,
const char *idname,
const char *name);
struct bNodeSocket *nodeFunctionSignatureInsertSocket(struct bNodeTree *ntree,
struct bNodeFunctionSignature *sig,
eNodeSocketInOut in_out,
const char *idname,
struct bNodeSocket *next_sock,
const char *name);
struct bNodeSocket *nodeFunctionSignatureCopySocket(struct bNodeTree *ntree,
struct bNodeFunctionSignature *sig,
const struct bNode *from_node,
const struct bNodeSocket *from_sock);
struct bNodeSocket *nodeFunctionSignatureCopySocketEx(struct bNodeTree *ntree,
struct bNodeFunctionSignature *sig,
const struct bNode *from_node,
const struct bNodeSocket *from_sock,
const char *idname,
const char *name);
struct bNodeSocket *nodeFunctionSignatureCopyInsertSocket(struct bNodeTree *ntree,
struct bNodeFunctionSignature *sig,
struct bNodeSocket *next_sock,
const struct bNode *from_node,
const struct bNodeSocket *from_sock);
void nodeFunctionSignatureRemoveSocket(struct bNodeTree *ntree,
struct bNodeFunctionSignature *sig,
struct bNodeSocket *sock);
void nodeFunctionSignatureClear(struct bNodeTree *ntree,
struct bNodeFunctionSignature *sig,
eNodeSocketInOut in_out);
void nodeFunctionSignatureMoveSocket(struct bNodeTree *ntree,
struct bNodeFunctionSignature *sig,
eNodeSocketInOut in_out,
int from_index,
int to_index);
/** \} */
/**
* \brief Defines a node type.
*

View File

@ -54,6 +54,8 @@ void BKE_ntree_update_tag_active_output_changed(struct bNodeTree *ntree);
void BKE_ntree_update_tag_missing_runtime_data(struct bNodeTree *ntree);
/** Used when the interface sockets/values have changed. */
void BKE_ntree_update_tag_interface(struct bNodeTree *ntree);
/** Used when a signature is changed. */
void BKE_ntree_update_tag_signature_changed(struct bNodeTree *ntree, struct bNodeFunctionSignature *sig);
/** Used when change parent node. */
void BKE_ntree_update_tag_parent_change(struct bNodeTree *ntree, struct bNode *node);
/** Used when an id data block changed that might be used by nodes that need to be updated. */

View File

@ -122,6 +122,209 @@ static void free_localized_node_groups(bNodeTree *ntree);
static void node_socket_interface_free(bNodeTree * /*ntree*/,
bNodeSocket *sock,
const bool do_id_user);
static void node_socket_set_typeinfo(bNodeTree *ntree,
bNodeSocket *sock,
bNodeSocketType *typeinfo);
/* ************ NODE FUNCTION SIGNATURE *************** */
static bNodeSocket *make_signature_socket(bNodeTree *ntree,
bNodeFunctionSignature *sig,
const eNodeSocketInOut in_out,
const char *idname,
const char *name)
{
bNodeSocketType *stype = nodeSocketTypeFind(idname);
if (stype == nullptr) {
return nullptr;
}
bNodeSocket *sock = MEM_cnew<bNodeSocket>("socket template");
sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname));
sock->in_out = in_out;
sock->type = SOCK_CUSTOM; /* int type undefined by default */
node_socket_set_typeinfo(ntree, sock, stype);
/* assign new unique index */
const int own_index = sig->cur_index++;
/* use the own_index as socket identifier */
if (in_out == SOCK_IN) {
BLI_snprintf(sock->identifier, MAX_NAME, "Input_%d", own_index);
}
else {
BLI_snprintf(sock->identifier, MAX_NAME, "Output_%d", own_index);
}
sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
BLI_strncpy(sock->name, name, NODE_MAXSTR);
sock->storage = nullptr;
sock->flag |= SOCK_COLLAPSED;
return sock;
}
bNodeSocket *nodeFunctionSignatureFindSocket(bNodeFunctionSignature *sig,
const eNodeSocketInOut in_out,
const char *identifier)
{
ListBase *sockets = (in_out == SOCK_IN) ? &sig->inputs : &sig->outputs;
LISTBASE_FOREACH (bNodeSocket *, iosock, sockets) {
if (STREQ(iosock->identifier, identifier)) {
return iosock;
}
}
return nullptr;
}
bNodeSocket *nodeFunctionSignatureAddSocket(bNodeTree *ntree,
bNodeFunctionSignature *sig,
const eNodeSocketInOut in_out,
const char *idname,
const char *name)
{
bNodeSocket *iosock = make_signature_socket(ntree, sig, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_addtail(&sig->inputs, iosock);
}
else if (in_out == SOCK_OUT) {
BLI_addtail(&sig->outputs, iosock);
}
BKE_ntree_update_tag_signature_changed(ntree, sig);
return iosock;
}
bNodeSocket *nodeFunctionSignatureInsertSocket(bNodeTree *ntree,
bNodeFunctionSignature *sig,
const eNodeSocketInOut in_out,
const char *idname,
bNodeSocket *next_sock,
const char *name)
{
bNodeSocket *iosock = make_signature_socket(ntree, sig, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_insertlinkbefore(&sig->inputs, next_sock, iosock);
}
else if (in_out == SOCK_OUT) {
BLI_insertlinkbefore(&sig->outputs, next_sock, iosock);
}
BKE_ntree_update_tag_signature_changed(ntree, sig);
return iosock;
}
bNodeSocket *nodeFunctionSignatureCopySocket(bNodeTree *ntree,
bNodeFunctionSignature *sig,
const bNode *from_node,
const bNodeSocket *from_sock)
{
return nodeFunctionSignatureCopySocketEx(
ntree, sig, from_node, from_sock, from_sock->idname, from_sock->name);
}
bNodeSocket *nodeFunctionSignatureCopySocketEx(bNodeTree *ntree,
bNodeFunctionSignature *sig,
const bNode *from_node,
const bNodeSocket *from_sock,
const char *idname,
const char *name)
{
bNodeSocket *iosock = nodeFunctionSignatureAddSocket(
ntree, sig, static_cast<eNodeSocketInOut>(from_sock->in_out), idname, DATA_(name));
if (iosock) {
if (iosock->typeinfo->interface_from_socket) {
iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
}
}
return iosock;
}
bNodeSocket *nodeFunctionSignatureCopyInsertSocket(bNodeTree *ntree,
bNodeFunctionSignature *sig,
bNodeSocket *next_sock,
const bNode *from_node,
const bNodeSocket *from_sock)
{
bNodeSocket *iosock = nodeFunctionSignatureInsertSocket(
ntree,
sig,
static_cast<eNodeSocketInOut>(from_sock->in_out),
from_sock->idname,
next_sock,
from_sock->name);
if (iosock) {
if (iosock->typeinfo->interface_from_socket) {
iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock);
}
}
return iosock;
}
void nodeFunctionSignatureRemoveSocket(bNodeTree *ntree,
bNodeFunctionSignature *sig,
bNodeSocket *sock)
{
/* this is fast, this way we don't need an in_out argument */
BLI_remlink(&sig->inputs, sock);
BLI_remlink(&sig->outputs, sock);
node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
BKE_ntree_update_tag_signature_changed(ntree, sig);
}
void nodeFunctionSignatureClear(bNodeTree *ntree,
bNodeFunctionSignature *sig,
eNodeSocketInOut in_out)
{
if (in_out == SOCK_IN) {
LISTBASE_FOREACH (bNodeSocket *, sock, &sig->inputs) {
node_socket_interface_free(ntree, sock, true);
}
BLI_freelistN(&sig->inputs);
}
else if (in_out == SOCK_OUT) {
LISTBASE_FOREACH (bNodeSocket *, sock, &sig->outputs) {
node_socket_interface_free(ntree, sock, true);
}
BLI_freelistN(&sig->outputs);
}
BKE_ntree_update_tag_signature_changed(ntree, sig);
}
void nodeFunctionSignatureMoveSocket(bNodeTree *ntree,
bNodeFunctionSignature *sig,
eNodeSocketInOut in_out,
int from_index,
int to_index)
{
ListBase *socket_list = (in_out == SOCK_IN) ? &sig->inputs : &sig->outputs;
if (from_index == to_index) {
return;
}
if (from_index < 0 || to_index < 0) {
return;
}
bNodeSocket *sock = (bNodeSocket *)BLI_findlink(socket_list, from_index);
if (to_index < from_index) {
bNodeSocket *nextsock = (bNodeSocket *)BLI_findlink(socket_list, to_index);
if (nextsock) {
BLI_remlink(socket_list, sock);
BLI_insertlinkbefore(socket_list, nextsock, sock);
}
}
else {
bNodeSocket *prevsock = (bNodeSocket *)BLI_findlink(socket_list, to_index);
if (prevsock) {
BLI_remlink(socket_list, sock);
BLI_insertlinkafter(socket_list, prevsock, sock);
}
}
BKE_ntree_update_tag_signature_changed(ntree, sig);
}
static void ntree_init_data(ID *id)
{

View File

@ -1181,6 +1181,15 @@ void BKE_ntree_update_tag_interface(bNodeTree *ntree)
add_tree_tag(ntree, NTREE_CHANGED_INTERFACE);
}
void BKE_ntree_update_tag_signature_changed(bNodeTree *ntree, bNodeFunctionSignature *sig)
{
/* TODO what needs to happen here for general signatures?
* Flag in bNodeFunctionSignature itself (runtime data),
* then propagate that to parent tree in BKE_ntree_update_main_tree.
*/
add_tree_tag(ntree, NTREE_CHANGED_INTERFACE);
}
void BKE_ntree_update_tag_parent_change(bNodeTree *ntree, bNode *node)
{
add_node_tag(ntree, node, NTREE_CHANGED_PARENT);

View File

@ -1626,6 +1626,14 @@ typedef struct NodeShaderMix {
char _pad[3];
} NodeShaderMix;
typedef struct bNodeFunctionSignature {
ListBase inputs;
ListBase outputs;
/* Unique ID counter */
int cur_index;
int _pad;
} bNodeFunctionSignature;
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1

View File

@ -3280,6 +3280,194 @@ static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C,
DEG_relations_tag_update(bmain);
}
/* ******** Node Function Signature ******** */
static int rna_NodeFunctionSignature_active_input_get(PointerRNA *ptr)
{
bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data;
int index = 0;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->inputs, index) {
if (socket->flag & SELECT) {
return index;
}
}
return -1;
}
static void rna_NodeFunctionSignature_active_input_set(PointerRNA *ptr, int value)
{
bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data;
int index = 0;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->inputs, index) {
SET_FLAG_FROM_TEST(socket->flag, index == value, SELECT);
}
}
static int rna_NodeFunctionSignature_active_output_get(PointerRNA *ptr)
{
bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data;
int index = 0;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->outputs, index) {
if (socket->flag & SELECT) {
return index;
}
}
return -1;
}
static void rna_NodeFunctionSignature_active_output_set(PointerRNA *ptr, int value)
{
bNodeFunctionSignature *sig = (bNodeFunctionSignature *)ptr->data;
int index = 0;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sig->outputs, index) {
SET_FLAG_FROM_TEST(socket->flag, index == value, SELECT);
}
}
static bNodeSocket *rna_NodeFunctionSignature_inputs_new(ID *id,
bNodeFunctionSignature *sig,
Main *bmain,
ReportList *reports,
const char *type,
const char *name)
{
bNodeTree *ntree = (bNodeTree *)id;
if (!rna_NodeTree_check(ntree, reports)) {
return NULL;
}
bNodeSocket *sock = nodeFunctionSignatureAddSocket(ntree, sig, SOCK_IN, type, name);
if (sock == NULL) {
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return sock;
}
static bNodeSocket *rna_NodeFunctionSignature_outputs_new(ID *id,
bNodeFunctionSignature *sig,
Main *bmain,
ReportList *reports,
const char *type,
const char *name)
{
bNodeTree *ntree = (bNodeTree *)id;
if (!rna_NodeTree_check(ntree, reports)) {
return NULL;
}
bNodeSocket *sock = nodeFunctionSignatureAddSocket(ntree, sig, SOCK_OUT, type, name);
if (sock == NULL) {
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return sock;
}
static void rna_NodeFunctionSignature_socket_remove(ID *id,
bNodeFunctionSignature *sig,
Main *bmain,
ReportList *reports,
bNodeSocket *sock)
{
bNodeTree *ntree = (bNodeTree *)id;
if (!rna_NodeTree_check(ntree, reports)) {
return;
}
if (BLI_findindex(&sig->inputs, sock) == -1 && BLI_findindex(&sig->outputs, sock) == -1) {
BKE_reportf(reports, RPT_ERROR, "Unable to locate socket '%s' in node", sock->identifier);
}
else {
nodeFunctionSignatureRemoveSocket(ntree, sig, sock);
ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
}
static void rna_NodeFunctionSignature_inputs_clear(ID *id,
bNodeFunctionSignature *sig,
Main *bmain,
ReportList *reports)
{
bNodeTree *ntree = (bNodeTree *)id;
if (!rna_NodeTree_check(ntree, reports)) {
return;
}
nodeFunctionSignatureClear(ntree, sig, SOCK_IN);
ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
static void rna_NodeFunctionSignature_outputs_clear(ID *id,
bNodeFunctionSignature *sig,
Main *bmain,
ReportList *reports)
{
bNodeTree *ntree = (bNodeTree *)id;
if (!rna_NodeTree_check(ntree, reports)) {
return;
}
nodeFunctionSignatureClear(ntree, sig, SOCK_OUT);
ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
static void rna_NodeFunctionSignature_inputs_move(ID *id,
bNodeFunctionSignature *sig,
Main *bmain,
ReportList *reports,
int from_index,
int to_index)
{
bNodeTree *ntree = (bNodeTree *)id;
if (!rna_NodeTree_check(ntree, reports)) {
return;
}
nodeFunctionSignatureMoveSocket(ntree, sig, SOCK_IN, from_index, to_index);
BKE_ntree_update_tag_interface(ntree);
ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
static void rna_NodeFunctionSignature_outputs_move(ID *id,
bNodeFunctionSignature *sig,
Main *bmain,
ReportList *reports,
int from_index,
int to_index)
{
bNodeTree *ntree = (bNodeTree *)id;
if (!rna_NodeTree_check(ntree, reports)) {
return;
}
nodeFunctionSignatureMoveSocket(ntree, sig, SOCK_OUT, from_index, to_index);
BKE_ntree_update_tag_interface(ntree);
ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
/* ******** Node Types ******** */
static void rna_NodeInternalSocketTemplate_name_get(PointerRNA *ptr, char *value)
@ -5260,6 +5448,100 @@ static void def_fn_bind(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNodeBind_update");
}
static void rna_def_node_function_signature_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out)
{
StructRNA *srna;
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 *removefunc = "rna_NodeFunctionSignature_socket_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");
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 Socket Declarations");
func = RNA_def_function(srna, "new", newfunc);
RNA_def_function_ui_description(func, "Add a socket 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");
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);
/* return value */
parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "New socket");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", removefunc);
RNA_def_function_ui_description(func, "Remove a socket from this signature");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "The socket to remove");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "clear", clearfunc);
RNA_def_function_ui_description(func, "Remove all sockets from this signature");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
func = RNA_def_function(srna, "move", movefunc);
RNA_def_function_ui_description(func, "Move a socket to another position");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS);
parm = RNA_def_int(
func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_int(
func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_node_function_signature(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "NodeFunctionSignature", NULL);
RNA_def_struct_ui_text(srna, "Node Function Signature", "Declaration of inputs and outputs of a node function");
RNA_def_struct_sdna(srna, "bNodeFunctionSignature");
prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "inputs", NULL);
RNA_def_property_struct_type(prop, "NodeSocketInterface");
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);
prop = RNA_def_property(srna, "active_input", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_NodeFunctionSignature_active_input_get",
"rna_NodeFunctionSignature_active_input_set",
NULL);
RNA_def_property_ui_text(prop, "Active Input", "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, "outputs", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "outputs", NULL);
RNA_def_property_struct_type(prop, "NodeSocketInterface");
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_output", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop,
"rna_NodeFunctionSignature_active_output_get",
"rna_NodeFunctionSignature_active_output_set",
NULL);
RNA_def_property_ui_text(prop, "Active Output", "Index of the active output");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_NODE, NULL);
}
static void def_fn_evaluate(StructRNA *srna)
{
}
@ -13170,6 +13452,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_node_socket(brna);
rna_def_node_socket_interface(brna);
rna_def_node_function_signature(brna);
rna_def_node(brna);
rna_def_node_link(brna);