armory/blender/arm/make_logic.py

149 lines
5.3 KiB
Python
Raw Normal View History

2016-09-23 00:34:42 +02:00
import os
2017-04-02 23:26:27 +02:00
import bpy
2017-03-15 12:30:14 +01:00
import arm.utils
2017-04-08 00:34:45 +02:00
import arm.log
2016-09-23 00:34:42 +02:00
2017-04-02 23:26:27 +02:00
parsed_nodes = []
2017-04-14 20:38:50 +02:00
parsed_labels = dict()
2017-04-02 23:26:27 +02:00
2016-09-23 00:34:42 +02:00
# Generating node sources
2016-10-19 13:28:06 +02:00
def build_node_trees():
2017-04-02 23:26:27 +02:00
os.chdir(arm.utils.get_fp())
2016-09-23 00:34:42 +02:00
# Make sure package dir exists
2016-10-17 00:02:51 +02:00
nodes_path = 'Sources/' + bpy.data.worlds['Arm'].arm_project_package.replace(".", "/") + "/node"
if not os.path.exists(nodes_path):
os.makedirs(nodes_path)
# Export node scripts
for node_group in bpy.data.node_groups:
2017-04-02 23:26:27 +02:00
if node_group.bl_idname == 'ArmLogicTreeType': # Build only logic trees
node_group.use_fake_user = True # Keep fake references for now
2016-10-19 13:28:06 +02:00
build_node_tree(node_group)
2016-09-23 00:34:42 +02:00
2016-10-19 13:28:06 +02:00
def build_node_tree(node_group):
2017-04-02 23:26:27 +02:00
global parsed_nodes
2017-04-14 20:38:50 +02:00
global parsed_labels
2017-04-02 23:26:27 +02:00
parsed_nodes = []
2017-04-14 20:38:50 +02:00
parsed_labels = dict()
2017-04-02 23:26:27 +02:00
root_nodes = get_root_nodes(node_group)
2016-10-17 00:02:51 +02:00
path = 'Sources/' + bpy.data.worlds['Arm'].arm_project_package.replace('.', '/') + '/node/'
2017-04-02 23:26:27 +02:00
group_name = arm.utils.safe_source_name(node_group.name)
2016-09-23 00:34:42 +02:00
2017-04-02 23:26:27 +02:00
with open(path + group_name + '.hx', 'w') as f:
2016-10-17 00:02:51 +02:00
f.write('package ' + bpy.data.worlds['Arm'].arm_project_package + '.node;\n\n')
f.write('import armory.logicnode.*;\n\n')
2017-04-04 23:11:31 +02:00
f.write('@:keep class ' + group_name + ' extends armory.logicnode.LogicTree {\n\n')
f.write('\tpublic function new() { super(); notifyOnAdd(add); }\n\n')
f.write('\tfunction add() {\n')
2017-04-02 23:26:27 +02:00
for node in root_nodes:
2017-05-06 00:22:15 +02:00
build_node(node, f)
f.write('\t}\n')
f.write('}\n')
2016-09-23 00:34:42 +02:00
2017-05-06 00:22:15 +02:00
def build_node(node, f):
2017-04-02 23:26:27 +02:00
global parsed_nodes
2017-04-14 20:38:50 +02:00
global parsed_labels
2017-04-02 23:26:27 +02:00
2017-04-04 23:11:31 +02:00
if node.type == 'REROUTE':
2017-05-06 00:22:15 +02:00
return build_node(node.inputs[0].links[0].from_node, f)
2017-04-04 23:11:31 +02:00
# Get node name
2017-04-08 20:05:35 +02:00
name = '_' + arm.utils.safe_source_name(node.name)
2016-09-23 00:34:42 +02:00
2017-04-14 20:38:50 +02:00
# Link nodes using labels
if node.label != '':
if node.label in parsed_labels:
return parsed_labels[node.label]
parsed_labels[node.label] = name
# Check if node already exists
2017-04-02 23:26:27 +02:00
if name in parsed_nodes:
return name
2016-09-23 00:34:42 +02:00
2017-04-14 20:38:50 +02:00
parsed_nodes.append(name)
# Create node
2017-04-04 23:11:31 +02:00
node_type = node.bl_idname[2:] # Discard 'LN'TimeNode prefix
2017-04-02 23:26:27 +02:00
f.write('\t\tvar ' + name + ' = new ' + node_type + '(this);\n')
# Properties
2017-04-02 23:26:27 +02:00
for i in range(0, 5):
if hasattr(node, 'property' + str(i)):
f.write('\t\t' + name + '.property' + str(i) + ' = "' + getattr(node, 'property' + str(i)) + '";\n')
# Create inputs
for inp in node.inputs:
# Is linked - find node
if inp.is_linked:
2017-04-02 23:26:27 +02:00
n = inp.links[0].from_node
2017-04-03 22:29:46 +02:00
socket = inp.links[0].from_socket
2017-05-06 00:22:15 +02:00
inp_name = build_node(n, f)
2017-04-03 22:29:46 +02:00
for i in range(0, len(n.outputs)):
if n.outputs[i] == socket:
inp_from = i
break
# Not linked - create node with default values
else:
2017-04-02 23:26:27 +02:00
inp_name = build_default_node(inp)
2017-04-03 22:29:46 +02:00
inp_from = 0
# Add input
2017-04-03 22:29:46 +02:00
f.write('\t\t' + name + '.addInput(' + inp_name + ', ' + str(inp_from) + ');\n')
# Create outputs
for out in node.outputs:
if out.is_linked:
out_name = ''
for l in out.links:
n = l.to_node
out_name += '[' if len(out_name) == 0 else ', '
2017-05-06 00:22:15 +02:00
out_name += build_node(n, f)
2017-04-03 22:29:46 +02:00
out_name += ']'
# Not linked - create node with default values
else:
out_name = '[' + build_default_node(out) + ']'
# Add input
f.write('\t\t' + name + '.addOutputs(' + out_name + ');\n')
return name
2016-09-23 00:34:42 +02:00
def get_root_nodes(node_group):
roots = []
2017-04-02 23:26:27 +02:00
for node in node_group.nodes:
2017-04-08 00:34:45 +02:00
if node.bl_idname == 'NodeUndefined':
arm.log.warn('Undefined logic nodes in ' + node_group.name)
return []
2017-04-02 23:26:27 +02:00
if node.type == 'FRAME':
continue
2017-03-06 02:29:03 +01:00
linked = False
2017-04-02 23:26:27 +02:00
for out in node.outputs:
if out.is_linked:
2017-03-06 02:29:03 +01:00
linked = True
break
if not linked: # Assume node with no connected outputs as roots
2017-04-02 23:26:27 +02:00
roots.append(node)
return roots
2016-09-23 00:34:42 +02:00
def build_default_node(inp):
2017-04-02 23:26:27 +02:00
inp_name = 'new NullNode(this)'
2017-04-08 20:05:35 +02:00
if inp.bl_idname == 'ArmNodeSocketAction':
2017-04-08 00:34:45 +02:00
return inp_name
if inp.bl_idname == 'ArmNodeSocketObject':
inp_name = 'new ObjectNode(this, "' + str(inp.default_value) + '")'
elif inp.type == 'VECTOR':
2017-04-02 23:26:27 +02:00
inp_name = 'new VectorNode(this, ' + str(inp.default_value[0]) + ', ' + str(inp.default_value[1]) + ', ' + str(inp.default_value[2]) + ')'
2017-04-04 23:11:31 +02:00
elif inp.type == 'RGBA':
inp_name = 'new ColorNode(this, ' + str(inp.default_value[0]) + ', ' + str(inp.default_value[1]) + ', ' + str(inp.default_value[2]) + ', ' + str(inp.default_value[3]) + ')'
elif inp.type == 'RGB':
inp_name = 'new ColorNode(this, ' + str(inp.default_value[0]) + ', ' + str(inp.default_value[1]) + ', ' + str(inp.default_value[2]) + ')'
2017-04-02 23:26:27 +02:00
elif inp.type == 'VALUE':
inp_name = 'new FloatNode(this, ' + str(inp.default_value) + ')'
2017-04-03 22:29:46 +02:00
elif inp.type == 'INT':
2017-04-04 23:11:31 +02:00
inp_name = 'new IntegerNode(this, ' + str(inp.default_value) + ')'
elif inp.type == 'BOOLEAN':
2017-04-04 23:11:31 +02:00
inp_name = 'new BooleanNode(this, ' + str(inp.default_value).lower() + ')'
2017-04-03 22:29:46 +02:00
elif inp.type == 'STRING':
inp_name = 'new StringNode(this, "' + str(inp.default_value) + '")'
2017-04-02 23:26:27 +02:00
return inp_name