initial support for calling subprograms

This commit is contained in:
2019-03-22 11:57:03 +01:00
parent cf72da183d
commit e77a8b97e1
9 changed files with 157 additions and 16 deletions

View File

@@ -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

View 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

View File

@@ -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

View 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="")

View File

@@ -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

View File

@@ -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"

View File

@@ -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():

View File

@@ -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;
}

View File

@@ -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);
}
} }