initial support for calling subprograms
This commit is contained in:
@@ -16,12 +16,6 @@ class BaseTree:
|
||||
update_function_trees()
|
||||
|
||||
|
||||
class FunctionTree(bpy.types.NodeTree, BaseTree):
|
||||
bl_idname = "FunctionTree"
|
||||
bl_icon = "MOD_DATA_TRANSFER"
|
||||
bl_label = "Function Nodes"
|
||||
|
||||
|
||||
class NodeStorage:
|
||||
def __init__(self, node):
|
||||
self.node = node
|
||||
|
49
release/scripts/startup/function_nodes/function_tree.py
Normal file
49
release/scripts/startup/function_nodes/function_tree.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import bpy
|
||||
from collections import namedtuple
|
||||
|
||||
from . base import BaseTree
|
||||
|
||||
FunctionInput = namedtuple("FunctionInput",
|
||||
["data_type", "name", "identifier"])
|
||||
|
||||
FunctionOutput = namedtuple("FunctionOutput",
|
||||
["data_type", "name", "identifier"])
|
||||
|
||||
class FunctionTree(bpy.types.NodeTree, BaseTree):
|
||||
bl_idname = "FunctionTree"
|
||||
bl_icon = "MOD_DATA_TRANSFER"
|
||||
bl_label = "Function Nodes"
|
||||
|
||||
def iter_function_inputs(self):
|
||||
node = self.get_input_node()
|
||||
if node is None:
|
||||
return
|
||||
|
||||
for socket in node.outputs[:-1]:
|
||||
yield FunctionInput(
|
||||
socket.data_type,
|
||||
"hello",
|
||||
socket.identifier)
|
||||
|
||||
def iter_function_outputs(self):
|
||||
node = self.get_output_node()
|
||||
if node is None:
|
||||
return
|
||||
|
||||
for socket in node.inputs[:-1]:
|
||||
yield FunctionOutput(
|
||||
socket.data_type,
|
||||
"bye",
|
||||
socket.identifier)
|
||||
|
||||
def get_input_node(self):
|
||||
for node in self.nodes:
|
||||
if node.bl_idname == "fn_FunctionInputNode":
|
||||
return node
|
||||
return None
|
||||
|
||||
def get_output_node(self):
|
||||
for node in self.nodes:
|
||||
if node.bl_idname == "fn_FunctionOutputNode":
|
||||
return node
|
||||
return None
|
@@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
from . base import FunctionTree
|
||||
from . function_tree import FunctionTree
|
||||
|
||||
def draw_menu(self, context):
|
||||
tree = context.space_data.node_tree
|
||||
|
27
release/scripts/startup/function_nodes/nodes/call.py
Normal file
27
release/scripts/startup/function_nodes/nodes/call.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from .. base import FunctionNode
|
||||
from .. socket_decl import TreeInterfaceDecl
|
||||
|
||||
class CallNode(bpy.types.Node, FunctionNode):
|
||||
bl_idname = "fn_CallNode"
|
||||
bl_label = "Call"
|
||||
|
||||
function_tree: PointerProperty(
|
||||
name="Function Tree",
|
||||
type=bpy.types.NodeTree,
|
||||
update=FunctionNode.refresh,
|
||||
)
|
||||
|
||||
def get_sockets(self):
|
||||
if self.function_tree is None:
|
||||
return [], []
|
||||
|
||||
return [
|
||||
TreeInterfaceDecl("inputs", self.function_tree, "IN"),
|
||||
], [
|
||||
TreeInterfaceDecl("outputs", self.function_tree, "OUT"),
|
||||
]
|
||||
|
||||
def draw(self, layout):
|
||||
layout.prop(self, "function_tree", text="")
|
@@ -1,6 +1,7 @@
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from dataclasses import dataclass
|
||||
from . function_tree import FunctionTree
|
||||
from . sockets import OperatorSocket
|
||||
from . types import type_infos
|
||||
from . base import DataSocket
|
||||
@@ -38,6 +39,45 @@ class FixedSocketDecl(SocketDeclBase):
|
||||
def amount(self, node):
|
||||
return 1
|
||||
|
||||
class TreeInterfaceDecl(SocketDeclBase):
|
||||
def __init__(self, identifier: str, tree: FunctionTree, in_or_out: str):
|
||||
assert tree is not None
|
||||
self.identifier = identifier
|
||||
self.tree = tree
|
||||
self.in_or_out = in_or_out
|
||||
|
||||
def build(self, node, node_sockets):
|
||||
if self.in_or_out == "IN":
|
||||
return list(self._build_inputs(node_sockets))
|
||||
elif self.in_or_out == "OUT":
|
||||
return list(self._build_outputs(node_sockets))
|
||||
else:
|
||||
assert False
|
||||
|
||||
def _build_inputs(self, node_sockets):
|
||||
for data_type, name, identifier in self.tree.iter_function_inputs():
|
||||
yield type_infos.build(
|
||||
data_type,
|
||||
node_sockets,
|
||||
name,
|
||||
self.identifier + identifier)
|
||||
|
||||
def _build_outputs(self, node_sockets):
|
||||
for data_type, name, identifier in self.tree.iter_function_outputs():
|
||||
yield type_infos.build(
|
||||
data_type,
|
||||
node_sockets,
|
||||
name,
|
||||
self.identifier + identifier)
|
||||
|
||||
def amount(self, node):
|
||||
if self.in_or_out == "IN":
|
||||
return len(tuple(self.tree.iter_function_inputs()))
|
||||
elif self.in_or_out == "OUT":
|
||||
return len(tuple(self.tree.iter_function_outputs()))
|
||||
else:
|
||||
assert False
|
||||
|
||||
class ListSocketDecl(SocketDeclBase):
|
||||
def __init__(self, identifier: str, display_name: str, prop_name: str, list_or_base: str):
|
||||
self.identifier = identifier
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
from . base import FunctionTree
|
||||
from . function_tree import FunctionTree
|
||||
|
||||
class TreePanel(bpy.types.Panel):
|
||||
bl_idname = "fn_tree_panel"
|
||||
|
@@ -2,9 +2,10 @@ import bpy
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
|
||||
from . base import DataSocket
|
||||
from . types import type_infos
|
||||
from . sockets import OperatorSocket
|
||||
from . base import DataSocket, FunctionTree
|
||||
from . function_tree import FunctionTree
|
||||
from . utils.graph import iter_connected_components
|
||||
|
||||
from . socket_decl import (
|
||||
@@ -12,6 +13,7 @@ from . socket_decl import (
|
||||
ListSocketDecl,
|
||||
PackListDecl,
|
||||
AnyVariadicDecl,
|
||||
TreeInterfaceDecl,
|
||||
)
|
||||
|
||||
|
||||
@@ -157,7 +159,7 @@ def iter_possible_list_component_types(component, decision_users, linked_sockets
|
||||
for socket in decision_users[decision_id]["LIST"]:
|
||||
for other_node, other_socket in linked_sockets[socket]:
|
||||
other_decl = other_socket.get_decl(other_node)
|
||||
if isinstance(other_decl, (FixedSocketDecl, AnyVariadicDecl)):
|
||||
if data_sockets_are_static(other_decl):
|
||||
data_type = other_socket.data_type
|
||||
if type_infos.is_list(data_type):
|
||||
yield type_infos.to_base(data_type)
|
||||
@@ -166,7 +168,7 @@ def iter_possible_list_component_types(component, decision_users, linked_sockets
|
||||
for socket in decision_users[decision_id]["BASE"]:
|
||||
for other_node, other_socket in linked_sockets[socket]:
|
||||
other_decl = other_socket.get_decl(other_node)
|
||||
if isinstance(other_decl, (FixedSocketDecl, AnyVariadicDecl)):
|
||||
if data_sockets_are_static(other_decl):
|
||||
data_type = other_socket.data_type
|
||||
if type_infos.is_base(data_type):
|
||||
yield data_type
|
||||
@@ -186,7 +188,7 @@ def make_pack_list_decisions(tree, linked_sockets, list_decisions):
|
||||
assert len(linked_sockets[socket]) == 1
|
||||
origin_node, origin_socket = next(iter(linked_sockets[socket]))
|
||||
origin_decl = origin_socket.get_decl(origin_node)
|
||||
if isinstance(origin_decl, (FixedSocketDecl, AnyVariadicDecl)):
|
||||
if data_sockets_are_static(origin_decl):
|
||||
data_type = origin_socket.data_type
|
||||
if data_type == decl.base_type:
|
||||
decisions[decision_id] = "BASE"
|
||||
@@ -211,6 +213,9 @@ def make_pack_list_decisions(tree, linked_sockets, list_decisions):
|
||||
|
||||
return decisions
|
||||
|
||||
def data_sockets_are_static(decl):
|
||||
return isinstance(decl, (FixedSocketDecl, AnyVariadicDecl, TreeInterfaceDecl))
|
||||
|
||||
def iter_pack_list_sockets(tree):
|
||||
for node in tree.nodes:
|
||||
for decl, sockets in node.storage.sockets_per_decl.items():
|
||||
|
@@ -20,9 +20,9 @@ namespace FN { namespace DataFlowNodes {
|
||||
|
||||
auto fn = SharedFunction::New(btree->id.name, fgraph.signature());
|
||||
fgraph_add_DependenciesBody(fn, fgraph);
|
||||
//fgraph_add_TupleCallBody(fn, fgraph);
|
||||
fgraph_add_LLVMBuildIRBody(fn, fgraph);
|
||||
derive_TupleCallBody_from_LLVMBuildIRBody(fn, *(new llvm::LLVMContext()));
|
||||
fgraph_add_TupleCallBody(fn, fgraph);
|
||||
// fgraph_add_LLVMBuildIRBody(fn, fgraph);
|
||||
// derive_TupleCallBody_from_LLVMBuildIRBody(fn, *(new llvm::LLVMContext()));
|
||||
return fn;
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "FN_functions.hpp"
|
||||
#include "FN_types.hpp"
|
||||
#include "FN_data_flow_nodes.hpp"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
@@ -73,7 +74,7 @@ namespace FN { namespace DataFlowNodes {
|
||||
|
||||
static void insert_get_list_element_node(
|
||||
Builder &builder,
|
||||
const BuilderContext ctx,
|
||||
const BuilderContext &ctx,
|
||||
bNode *bnode)
|
||||
{
|
||||
SharedType &base_type = ctx.type_from_rna(bnode, "active_type");
|
||||
@@ -126,6 +127,30 @@ namespace FN { namespace DataFlowNodes {
|
||||
builder.map_output(node->output(0), bnode, 0);
|
||||
}
|
||||
|
||||
static void insert_call_node(
|
||||
Builder &builder,
|
||||
const BuilderContext &ctx,
|
||||
bNode *bnode)
|
||||
{
|
||||
PointerRNA ptr;
|
||||
ctx.get_rna(bnode, &ptr);
|
||||
|
||||
PointerRNA btree_ptr = RNA_pointer_get(&ptr, "function_tree");
|
||||
bNodeTree *btree = (bNodeTree *)btree_ptr.id.data;
|
||||
|
||||
if (btree == nullptr) {
|
||||
BLI_assert(BLI_listbase_is_empty(&bnode->inputs));
|
||||
BLI_assert(BLI_listbase_is_empty(&bnode->outputs));
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<SharedFunction> fn = generate_function(btree);
|
||||
BLI_assert(fn.has_value());
|
||||
|
||||
Node *node = builder.insert_function(fn.value());
|
||||
builder.map_sockets(node, bnode);
|
||||
}
|
||||
|
||||
void register_node_inserters(GraphInserters &inserters)
|
||||
{
|
||||
inserters.reg_node_function("fn_CombineVectorNode", Functions::combine_vector);
|
||||
@@ -139,6 +164,7 @@ namespace FN { namespace DataFlowNodes {
|
||||
inserters.reg_node_inserter("fn_ClampNode", insert_clamp_node);
|
||||
inserters.reg_node_inserter("fn_GetListElementNode", insert_get_list_element_node);
|
||||
inserters.reg_node_inserter("fn_PackListNode", insert_pack_list_node);
|
||||
inserters.reg_node_inserter("fn_CallNode", insert_call_node);
|
||||
}
|
||||
|
||||
} }
|
Reference in New Issue
Block a user