forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
107
leenkx/blender/lnx/logicnode/__init__.py
Normal file
107
leenkx/blender/lnx/logicnode/__init__.py
Normal file
@ -0,0 +1,107 @@
|
||||
import importlib
|
||||
import inspect
|
||||
import pkgutil
|
||||
import sys
|
||||
|
||||
import lnx
|
||||
import lnx.logicnode.lnx_nodes as lnx_nodes
|
||||
from lnx.logicnode.lnx_props import *
|
||||
import lnx.logicnode.lnx_sockets as lnx_sockets
|
||||
from lnx.logicnode.replacement import NodeReplacement
|
||||
from lnx.logicnode.lnx_advanced_draw import *
|
||||
|
||||
if lnx.is_reload(__name__):
|
||||
lnx_nodes = lnx.reload_module(lnx_nodes)
|
||||
lnx.logicnode.lnx_props = lnx.reload_module(lnx.logicnode.lnx_props)
|
||||
from lnx.logicnode.lnx_props import *
|
||||
lnx_sockets = lnx.reload_module(lnx_sockets)
|
||||
lnx.logicnode.replacement = lnx.reload_module(lnx.logicnode.replacement)
|
||||
from lnx.logicnode.replacement import NodeReplacement
|
||||
|
||||
HAS_RELOADED = True
|
||||
else:
|
||||
lnx.enable_reload(__name__)
|
||||
|
||||
|
||||
def init_categories():
|
||||
"""Register default node menu categories."""
|
||||
lnx_nodes.add_category('Logic', icon='OUTLINER', section="basic",
|
||||
description="Logic nodes are used to control execution flow using branching, loops, gates etc.")
|
||||
lnx_nodes.add_category('Event', icon='INFO', section="basic")
|
||||
lnx_nodes.add_category('Input', icon='GREASEPENCIL', section="basic")
|
||||
lnx_nodes.add_category('Native', icon='MEMORY', section="basic",
|
||||
description="The Native category contains nodes which interact with the system (Input/Output functionality, etc.) or Haxe.")
|
||||
|
||||
lnx_nodes.add_category('Browser', icon='URL', section="basic")
|
||||
lnx_nodes.add_category('Camera', icon='OUTLINER_OB_CAMERA', section="data")
|
||||
lnx_nodes.add_category('Material', icon='MATERIAL', section="data")
|
||||
lnx_nodes.add_category('Light', icon='LIGHT', section="data")
|
||||
lnx_nodes.add_category('World', icon='WORLD', section="data")
|
||||
lnx_nodes.add_category('Object', icon='OBJECT_DATA', section="data")
|
||||
lnx_nodes.add_category('Scene', icon='SCENE_DATA', section="data")
|
||||
lnx_nodes.add_category('Trait', icon='NODETREE', section="data")
|
||||
lnx_nodes.add_category('Network', icon='WORLD', section="data")
|
||||
lnx_nodes.add_category('Leenkx', icon='ORIENTATION_CURSOR', section="data")
|
||||
|
||||
lnx_nodes.add_category('Animation', icon='SEQUENCE', section="motion")
|
||||
lnx_nodes.add_category('Navmesh', icon='UV_VERTEXSEL', section="motion")
|
||||
lnx_nodes.add_category('Transform', icon='TRANSFORM_ORIGINS', section="motion")
|
||||
lnx_nodes.add_category('Physics', icon='PHYSICS', section="motion")
|
||||
|
||||
lnx_nodes.add_category('Array', icon='MOD_ARRAY', section="values")
|
||||
lnx_nodes.add_category('Map', icon='SHORTDISPLAY', section="values")
|
||||
lnx_nodes.add_category('Database', icon='MESH_CYLINDER', section="values")
|
||||
lnx_nodes.add_category('Math', icon='FORCE_HARMONIC', section="values")
|
||||
lnx_nodes.add_category('Random', icon='SEQ_HISTOGRAM', section="values")
|
||||
lnx_nodes.add_category('String', icon='SORTALPHA', section="values")
|
||||
lnx_nodes.add_category('Variable', icon='OPTIONS', section="values")
|
||||
|
||||
lnx_nodes.add_category('HTML', icon='SEQ_STRIP_META', section="graphics")
|
||||
lnx_nodes.add_category('Draw', icon='GREASEPENCIL', section="graphics")
|
||||
lnx_nodes.add_category('Canvas', icon='RENDERLAYERS', section="graphics",
|
||||
description="Note: To get the canvas, be sure that the node(s) and the canvas (UI) is attached to the same object.")
|
||||
lnx_nodes.add_category('Postprocess', icon='FREEZE', section="graphics")
|
||||
lnx_nodes.add_category('Renderpath', icon='STICKY_UVS_LOC', section="graphics")
|
||||
|
||||
lnx_nodes.add_category('Sound', icon='OUTLINER_OB_SPEAKER', section="sound")
|
||||
lnx_nodes.add_category('3D_Audio', icon='SPEAKER', section="sound")
|
||||
|
||||
lnx_nodes.add_category('Miscellaneous', icon='RESTRICT_COLOR_ON', section="misc")
|
||||
lnx_nodes.add_category('Custom', icon='PLUGIN', section="misc")
|
||||
lnx_nodes.add_category('Layout', icon='SEQ_STRIP_DUPLICATE', section="misc")
|
||||
|
||||
# Make sure that logic node extension packs are displayed at the end
|
||||
# of the menu by default unless they declare it otherwise
|
||||
lnx_nodes.add_category_section('default')
|
||||
|
||||
|
||||
def init_nodes(base_path=__path__, base_package=__package__, subpackages_only=False):
|
||||
"""Calls the `on_register()` method on all logic nodes in a given
|
||||
`base_package` and all its sub-packages relative to the given
|
||||
`base_path`, in order to initialize them and to register them to Leenkx.
|
||||
|
||||
Be aware that calling this function will import all modules in the
|
||||
given package, so module-level code will be executed.
|
||||
|
||||
If `subpackages_only` is true, modules directly inside the root of
|
||||
the base package are not searched and imported.
|
||||
"""
|
||||
for loader, module_name, is_pkg in pkgutil.walk_packages(base_path, base_package + '.'):
|
||||
if is_pkg:
|
||||
# The package must be loaded as well so that the modules from that package can be accessed (see the
|
||||
# pkgutil.walk_packages documentation for more information on this)
|
||||
loader.find_module(module_name).load_module(module_name)
|
||||
|
||||
# Only look at modules in sub packages if specified
|
||||
elif not subpackages_only or module_name.rsplit('.', 1)[0] != base_package:
|
||||
if 'HAS_RELOADED' not in globals() or module_name not in sys.modules:
|
||||
_module = importlib.import_module(module_name)
|
||||
else:
|
||||
# Reload the module if the SDK was reloaded at least once
|
||||
_module = importlib.reload(sys.modules[module_name])
|
||||
|
||||
for name, obj in inspect.getmembers(_module, inspect.isclass):
|
||||
if name in ("LnxLogicTreeNode", "LnxLogicVariableNodeMixin"):
|
||||
continue
|
||||
if issubclass(obj, lnx_nodes.LnxLogicTreeNode):
|
||||
obj.on_register()
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
32
leenkx/blender/lnx/logicnode/animation/LN_action.py
Normal file
32
leenkx/blender/lnx/logicnode/animation/LN_action.py
Normal file
@ -0,0 +1,32 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AnimActionNode(LnxLogicTreeNode):
|
||||
"""Samples a given action."""
|
||||
bl_idname = 'LNAnimActionNode'
|
||||
bl_label = 'Action'
|
||||
lnx_version = 2
|
||||
|
||||
property0: HaxeStringProperty('property0', name = '', default = '')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimAction', 'Action')
|
||||
self.add_input('LnxBoolSocket', 'Is Looped')
|
||||
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Action')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.label(text='Action ID:')
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def draw_label(self) -> str:
|
||||
return f'{self.bl_label}: {self.property0}'
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNAnimActionNode', self.lnx_version, 'LNAnimActionNode', 2,
|
||||
in_socket_mapping={}, out_socket_mapping={}
|
||||
)
|
12
leenkx/blender/lnx/logicnode/animation/LN_action_name.py
Normal file
12
leenkx/blender/lnx/logicnode/animation/LN_action_name.py
Normal file
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ActionNameNode(LnxLogicTreeNode):
|
||||
"""Stores the given action name."""
|
||||
bl_idname = 'LNActionNameNode'
|
||||
bl_label = 'Action Name'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAnimAction', 'Action')
|
||||
|
||||
self.add_output('LnxNodeSocketAnimAction', 'Action')
|
25
leenkx/blender/lnx/logicnode/animation/LN_blend_action.py
Normal file
25
leenkx/blender/lnx/logicnode/animation/LN_blend_action.py
Normal file
@ -0,0 +1,25 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class BlendActionNode(LnxLogicTreeNode):
|
||||
"""Interpolates between the two given actions."""
|
||||
bl_idname = 'LNBlendActionNode'
|
||||
bl_label = 'Blend Action'
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action 1')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action 2')
|
||||
self.add_input('ArmFactorSocket', 'Factor', default_value = 0.5)
|
||||
self.add_input('LnxIntSocket', 'Bone Group', default_value = -1)
|
||||
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Result')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNBlendActionNode', self.lnx_version, 'LNBlendActionNode', 2,
|
||||
in_socket_mapping={}, out_socket_mapping={}
|
||||
)
|
198
leenkx/blender/lnx/logicnode/animation/LN_blend_space_gpu.py
Normal file
198
leenkx/blender/lnx/logicnode/animation/LN_blend_space_gpu.py
Normal file
@ -0,0 +1,198 @@
|
||||
from lnx.logicnode.lnx_advanced_draw import *
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
from bpy.props import *
|
||||
from bpy.types import Node
|
||||
|
||||
class BlendSpaceNode(LnxLogicTreeNode):
|
||||
"""Activates the output when the given event is received.
|
||||
|
||||
@seeNode Send Event to Object
|
||||
@seeNode Send Event"""
|
||||
bl_idname = 'LNBlendSpaceNode'
|
||||
bl_label = 'Blend Space'
|
||||
lnx_version = 1
|
||||
lnx_section = 'custom'
|
||||
|
||||
property2: HaxeBoolProperty(
|
||||
'property2',
|
||||
name="Enable or Disable",
|
||||
description="A bool property",
|
||||
default = False
|
||||
)
|
||||
|
||||
advanced_draw_run: BoolProperty(
|
||||
name = "Advance draw enabled",
|
||||
description="",
|
||||
default = False
|
||||
)
|
||||
|
||||
def stop_modal(self):
|
||||
self.property2 = False
|
||||
|
||||
def my_float_update(self, context):
|
||||
if self.property2:
|
||||
self.set_x_y_socket()
|
||||
|
||||
property0: HaxeFloatVectorProperty(
|
||||
'property0',
|
||||
name = "Point Coordionates",
|
||||
description="",
|
||||
default = (0.0, 0.0,
|
||||
0.0, 1.0,
|
||||
1.0, 1.0,
|
||||
1.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.0, 0.0,
|
||||
0.5, 0.5),
|
||||
size = 22,
|
||||
update = my_float_update
|
||||
)
|
||||
|
||||
active_point_index: IntProperty(
|
||||
default = -1
|
||||
)
|
||||
|
||||
show_numbers: BoolProperty(
|
||||
name = "Show Point Numbers",
|
||||
description="",
|
||||
default = False
|
||||
)
|
||||
|
||||
active_point_index_ref: IntProperty(
|
||||
default = 0
|
||||
)
|
||||
|
||||
gui_bounds: FloatVectorProperty(
|
||||
name = "GUI bounds",
|
||||
description = "",
|
||||
default = (0.0, 0.0, 0.0),
|
||||
size = 3
|
||||
)
|
||||
|
||||
point_size: FloatProperty(
|
||||
name = "Point Size",
|
||||
description = "",
|
||||
default = 0.015
|
||||
)
|
||||
|
||||
property1: HaxeBoolVectorProperty(
|
||||
'property1',
|
||||
name = "Point enabled for view",
|
||||
description = "",
|
||||
default = (True,True,True,True, False, False, False, False, False, False, True),
|
||||
size = 11
|
||||
)
|
||||
|
||||
draw_handler_dict = {}
|
||||
modal_handler_dict = {}
|
||||
|
||||
def __init__(self):
|
||||
array_nodes[str(id(self))] = self
|
||||
if self.advanced_draw_run:
|
||||
self.add_advanced_draw()
|
||||
|
||||
def create_blend_space(self):
|
||||
self.blend_space = BlendSpaceGUI(self)
|
||||
|
||||
def free(self):
|
||||
self.remove_advanced_draw()
|
||||
|
||||
def get_blend_space_points(self):
|
||||
if bpy.context.space_data.edit_tree == self.get_tree():
|
||||
return self.blend_space.points
|
||||
|
||||
def draw_advanced(self):
|
||||
if bpy.context.space_data.edit_tree == self.get_tree():
|
||||
self.blend_space.draw()
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketArray', 'Actions')
|
||||
self.add_input('ArmBlendSpaceSocket', 'Cursor X')
|
||||
self.add_input('ArmBlendSpaceSocket', 'Cursor Y')
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Out')
|
||||
|
||||
def add_advanced_draw(self):
|
||||
self.advanced_draw_run = True
|
||||
handler = self.draw_handler_dict.get(str(self.as_pointer()))
|
||||
if handler is None:
|
||||
self.create_blend_space()
|
||||
editor = getattr(bpy.types, 'SpaceNodeEditor')
|
||||
handler = editor.draw_handler_add(self.draw_advanced, (), 'WINDOW', 'POST_VIEW')
|
||||
self.draw_handler_dict[str(self.as_pointer())] = handler
|
||||
self.property2 = False
|
||||
|
||||
|
||||
def remove_advanced_draw(self):
|
||||
self.advanced_draw_run = False
|
||||
handler = self.draw_handler_dict.get(str(self.as_pointer()))
|
||||
if handler is not None:
|
||||
editor = getattr(bpy.types, 'SpaceNodeEditor')
|
||||
editor.draw_handler_remove(handler, 'WINDOW')
|
||||
self.draw_handler_dict.pop(str(self.as_pointer()))
|
||||
|
||||
def set_x_y_cursor(self):
|
||||
self.property0[20] = self.inputs[2].get_default_value()
|
||||
self.property0[21] = self.inputs[3].get_default_value()
|
||||
|
||||
def set_x_y_socket(self):
|
||||
self.inputs[2].set_default_value(self.property0[20])
|
||||
self.inputs[3].set_default_value(self.property0[21])
|
||||
|
||||
|
||||
def add_point(self):
|
||||
for i in range(len(self.property1)):
|
||||
if not self.property1[i]:
|
||||
self.property1[i] = True
|
||||
self.property0[i * 2] = 0.5
|
||||
self.property0[i * 2 + 1] = 0.5
|
||||
break
|
||||
|
||||
def remove_point(self):
|
||||
for i in range(len(self.property1) - 2, 2, -1):
|
||||
if self.property1[i]:
|
||||
self.property1[i] = False
|
||||
self.active_point_index_ref = i - 1
|
||||
break
|
||||
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
row.alignment = 'EXPAND'
|
||||
op = row.operator('lnx.node_call_func', text='Show', icon='FULLSCREEN_ENTER', emboss=True, depress = self.advanced_draw_run)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'add_advanced_draw'
|
||||
op = row.operator('lnx.node_call_func', text='Hide', icon='FULLSCREEN_EXIT', emboss=True, depress = not self.advanced_draw_run)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'remove_advanced_draw'
|
||||
if self.advanced_draw_run:
|
||||
col = layout.column()
|
||||
row = col.row(align=True)
|
||||
op = row.operator('lnx.blend_space_operator', text = 'Edit', icon = 'EDITMODE_HLT', emboss = True, depress = self.property2)
|
||||
op.node_index = str(id(self))
|
||||
op = row.operator('lnx.node_call_func', text = 'Exit Edit', icon = 'OBJECT_DATAMODE', emboss = True, depress = not self.property2)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'stop_modal'
|
||||
layout.prop(self, 'show_numbers')
|
||||
if self.property2:
|
||||
col = layout.column()
|
||||
row = col.row(align=True)
|
||||
op = row.operator('lnx.node_call_func', text = 'Add Point', icon = 'PLUS', emboss = True)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'add_point'
|
||||
op = row.operator('lnx.node_call_func', text = 'Remove Point', icon = 'X', emboss = True)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'remove_point'
|
||||
cl =layout.column()
|
||||
actie_point = self.active_point_index_ref
|
||||
pos = ", Pos = " + str(round(self.property0[actie_point * 2], 2)) + ", " + str(round(self.property0[actie_point * 2 + 1], 2))
|
||||
if actie_point > 9:
|
||||
cl.label(text = "Selected: Cursor" + pos)
|
||||
else:
|
||||
cl.label(text = "Selected: " + str(self.active_point_index_ref + 1) + pos)
|
||||
else:
|
||||
self.set_x_y_cursor()
|
24
leenkx/blender/lnx/logicnode/animation/LN_bone_fk.py
Normal file
24
leenkx/blender/lnx/logicnode/animation/LN_bone_fk.py
Normal file
@ -0,0 +1,24 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class BoneFKNode(LnxLogicTreeNode):
|
||||
"""Applies forward kinematics in the given object bone."""
|
||||
bl_idname = 'LNBoneFKNode'
|
||||
bl_label = 'Bone FK'
|
||||
lnx_version = 2
|
||||
lnx_section = 'armature'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action Tree')
|
||||
self.add_input('LnxStringSocket', 'Bone')
|
||||
self.add_input('LnxDynamicSocket', 'Transform')
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Action Tree')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNBoneFKNode', self.lnx_version, 'LNBoneFKNode', 2,
|
||||
in_socket_mapping={}, out_socket_mapping={}
|
||||
)
|
77
leenkx/blender/lnx/logicnode/animation/LN_bone_ik.py
Normal file
77
leenkx/blender/lnx/logicnode/animation/LN_bone_ik.py
Normal file
@ -0,0 +1,77 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class BoneIKNode(LnxLogicTreeNode):
|
||||
"""Performs inverse kinematics on the selected armature with specified bone.
|
||||
|
||||
@input Object: Armature on which IK should be performed.
|
||||
|
||||
@input Bone: Effector or tip bone for the inverse kinematics
|
||||
|
||||
@input Goal Position: Position in world coordinates the effector bone will track to
|
||||
|
||||
@input Enable Pole: Bend IK solution towards pole location
|
||||
|
||||
@input Pole Position: Location of the pole in world coordinates
|
||||
|
||||
@input Chain Length: Number of bones to include in the IK solver including the effector. If set to 0, all bones from effector to the root bone of the armature will be considered.
|
||||
|
||||
@input Max Iterations: Maximum allowed FABRIK iterations to solve for IK. For longer chains, more iterations are needed.
|
||||
|
||||
@input Precision: Presition of IK to stop at. It is described as a tolerence in length. Typically 0.01 is a good value.
|
||||
|
||||
@input Roll Angle: Roll the bones along their local axis with specified radians. set 0 for no extra roll.
|
||||
"""
|
||||
bl_idname = 'LNBoneIKNode'
|
||||
bl_label = 'Bone IK'
|
||||
lnx_version = 3
|
||||
lnx_section = 'armature'
|
||||
|
||||
NUM_STATIC_INS = 9
|
||||
|
||||
def update_advanced(self, context):
|
||||
self.update_sockets(context)
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('2 Bone', '2 Bone', '2 Bone'),
|
||||
('FABRIK', 'FABRIK', 'FABRIK')],
|
||||
name='', default='2 Bone', update=update_advanced)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action')
|
||||
self.add_input('LnxStringSocket', 'Bone')
|
||||
self.add_input('LnxVectorSocket', 'Goal Position')
|
||||
self.add_input('LnxBoolSocket', 'Enable Pole')
|
||||
self.add_input('LnxVectorSocket', 'Pole Position')
|
||||
self.add_input('LnxFloatSocket', 'Roll Angle')
|
||||
self.add_input('ArmFactorSocket', 'Influence', default_value = 1.0)
|
||||
self.add_input('LnxIntSocket', 'Bone Group', default_value = 0)
|
||||
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Result')
|
||||
|
||||
self.update_sockets(context)
|
||||
|
||||
def update_sockets(self, context):
|
||||
remove_list = []
|
||||
for i in range(BoneIKNode.NUM_STATIC_INS, len(self.inputs)):
|
||||
remove_list.append(self.inputs[i])
|
||||
for i in remove_list:
|
||||
self.inputs.remove(i)
|
||||
|
||||
if self.property0 == 'FABRIK':
|
||||
self.add_input('LnxIntSocket', 'Chain Length')
|
||||
self.add_input('LnxIntSocket', 'Max Iterations', 10)
|
||||
self.add_input('LnxFloatSocket', 'Precision', 0.01)
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1, 2):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNBoneIKNode', self.lnx_version, 'LNBoneIKNode', 3,
|
||||
in_socket_mapping={}, out_socket_mapping={}
|
||||
)
|
@ -0,0 +1,27 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class EvaluateRootMotionNode(LnxLogicTreeNode):
|
||||
"""Calculates the root motion bone in an armature object."""
|
||||
bl_idname = 'LNEvaluateRootMotionNode'
|
||||
bl_label = 'Evaluate Root Motion'
|
||||
lnx_version = 1
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('X', 'X', 'X'),
|
||||
('Y', 'Y', 'Y'),
|
||||
('Z', 'Z', 'Z')],
|
||||
name='', default='Y')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Reset')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action')
|
||||
|
||||
self.add_input('LnxStringSocket', 'Bone')
|
||||
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Result')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.label(text='Root Motion Lock axis:')
|
||||
layout.prop(self, 'property0')
|
@ -0,0 +1,33 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AnimationStateNode(LnxLogicTreeNode):
|
||||
"""Returns the information about the current action of the given object."""
|
||||
bl_idname = 'LNAnimationStateNode'
|
||||
bl_label = 'Get Action State'
|
||||
lnx_version = 2
|
||||
|
||||
property0: HaxeStringProperty('property0', name='', default='')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'On Complete')
|
||||
self.add_output('LnxBoolSocket', 'Initialized')
|
||||
self.add_output('LnxStringSocket', 'Action Name')
|
||||
self.add_output('LnxIntSocket', 'Current Frame')
|
||||
self.add_output('LnxBoolSocket', 'Is Paused')
|
||||
self.add_output('LnxFloatSocket', 'Speed')
|
||||
self.add_output('LnxIntSocket', 'Total Frames')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.label(text='Action ID:')
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNAnimationStateNode', self.lnx_version, 'LNAnimationStateNode', 2,
|
||||
in_socket_mapping={}, out_socket_mapping={}
|
||||
)
|
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetBoneFkIkOnlyNode(LnxLogicTreeNode):
|
||||
"""Get if a particular bone is animated by Forward kinematics or Inverse kinematics only."""
|
||||
bl_idname = 'LNGetBoneFkIkOnlyNode'
|
||||
bl_label = 'Get Bone FK IK Only'
|
||||
lnx_version = 1
|
||||
lnx_section = 'armature'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Bone')
|
||||
self.add_output('LnxBoolSocket', 'FK or IK only')
|
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetBoneTransformNode(LnxLogicTreeNode):
|
||||
"""Returns bone transform in world space."""
|
||||
bl_idname = 'LNGetBoneTransformNode'
|
||||
bl_label = 'Get Bone Transform'
|
||||
lnx_version = 1
|
||||
lnx_section = 'armature'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Bone')
|
||||
self.add_output('LnxDynamicSocket', 'Transform')
|
13
leenkx/blender/lnx/logicnode/animation/LN_get_root_motion.py
Normal file
13
leenkx/blender/lnx/logicnode/animation/LN_get_root_motion.py
Normal file
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetRootMotionNode(LnxLogicTreeNode):
|
||||
"""Gets root motion of an armature object"""
|
||||
bl_idname = 'LNGetRootMotionNode'
|
||||
bl_label = 'Get Root Motion'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_output('LnxStringSocket', 'Bone')
|
||||
self.add_output('LnxVectorSocket', 'Velocity')
|
||||
self.add_output('LnxRotationSocket', 'Rotation')
|
@ -0,0 +1,37 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetTilesheetStateNode(LnxLogicTreeNode):
|
||||
"""Returns the information about the current tilesheet of the given object.
|
||||
|
||||
@output Active Tilesheet: Current active tilesheet.
|
||||
|
||||
@output Active Action: Current action in the tilesheet.
|
||||
|
||||
@output Frame: Frame offset with 0 as the first frame of the active action.
|
||||
|
||||
@output Absolute Frame: Absolute frame index in this tilesheet.
|
||||
|
||||
@output Is Paused: Tilesheet action paused.
|
||||
"""
|
||||
bl_idname = 'LNGetTilesheetStateNode'
|
||||
bl_label = 'Get Tilesheet State'
|
||||
lnx_version = 2
|
||||
lnx_section = 'tilesheet'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.add_output('LnxStringSocket', 'Active Tilesheet')
|
||||
self.add_output('LnxStringSocket', 'Active Action')
|
||||
self.add_output('LnxIntSocket', 'Frame')
|
||||
self.add_output('LnxIntSocket', 'Absolute Frame')
|
||||
self.add_output('LnxBoolSocket', 'Is Paused')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNGetTilesheetStateNode', self.lnx_version, 'LNGetTilesheetStateNode', 2,
|
||||
in_socket_mapping={}, out_socket_mapping={0:1, 1:3, 2:4}
|
||||
)
|
@ -0,0 +1,29 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class OnActionMarkerNode(LnxLogicTreeNode):
|
||||
"""Activates the output when the object action reaches the action marker."""
|
||||
bl_idname = 'LNOnActionMarkerNode'
|
||||
bl_label = 'On Action Marker'
|
||||
bl_width_default = 250
|
||||
lnx_version = 2
|
||||
|
||||
property0: HaxeStringProperty('property0', name='Action ID', default='')
|
||||
property1: HaxeStringProperty('property1', name='Marker', default='')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
layout.prop(self, 'property1')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNOnActionMarkerNode', self.lnx_version, 'LNOnActionMarkerNode', 2,
|
||||
in_socket_mapping={}, out_socket_mapping={}
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class OnAnimationTreeUpdateNode(LnxLogicTreeNode):
|
||||
"""Execute output when animation tree is updated"""
|
||||
bl_idname = 'LNOnAnimationTreeUpdateNode'
|
||||
bl_label = 'On Animation Tree Update'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action Tree')
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Action Tree')
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
28
leenkx/blender/lnx/logicnode/animation/LN_one_shot_action.py
Normal file
28
leenkx/blender/lnx/logicnode/animation/LN_one_shot_action.py
Normal file
@ -0,0 +1,28 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class OneShotActionNode(LnxLogicTreeNode):
|
||||
"""Introduce one loop of animation in the current tree."""
|
||||
bl_idname = 'LNOneShotActionNode'
|
||||
bl_label = 'One Shot Action'
|
||||
bl_width_default = 250
|
||||
lnx_version = 1
|
||||
|
||||
property0: HaxeStringProperty('property0', name = 'Action ID', default = '')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Start')
|
||||
self.add_input('LnxNodeSocketAction', 'Stop')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Main Action')
|
||||
self.add_input('LnxNodeSocketAnimAction', 'One Shot')
|
||||
self.add_input('LnxBoolSocket', 'Restart', default_value = True)
|
||||
self.add_input('LnxFloatSocket', 'Blend In Time', default_value = 1.0)
|
||||
self.add_input('LnxFloatSocket', 'Blend Out Time', default_value = 1.0)
|
||||
self.add_input('LnxIntSocket', 'Bone Group', default_value = -1)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketAction', 'Done')
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Result')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
@ -0,0 +1,45 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class OneShotActionMultiNode(LnxLogicTreeNode):
|
||||
"""Introduce one loop of animation in the current tree using the selected action."""
|
||||
bl_idname = 'LNOneShotActionMultiNode'
|
||||
bl_label = 'One Shot Action Multi'
|
||||
bl_width_default = 250
|
||||
lnx_version = 1
|
||||
min_inputs = 10
|
||||
|
||||
def __init__(self):
|
||||
super(OneShotActionMultiNode, self).__init__()
|
||||
array_nodes[self.get_id_str()] = self
|
||||
|
||||
property0: HaxeStringProperty('property0', name = 'Action ID', default = '')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Start')
|
||||
self.add_input('LnxIntSocket', 'Index', default_value = 0)
|
||||
self.add_input('LnxNodeSocketAction', 'Stop')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxBoolSocket', 'Restart', default_value = True)
|
||||
self.add_input('LnxFloatSocket', 'Blend In Time', default_value = 1.0)
|
||||
self.add_input('LnxFloatSocket', 'Blend Out Time', default_value = 1.0)
|
||||
self.add_input('LnxIntSocket', 'Bone Group', default_value = -1)
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Main Action')
|
||||
self.add_input('LnxNodeSocketAnimAction', 'Action 0')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketAction', 'Done')
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Result')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
row = layout.row(align=True)
|
||||
op = row.operator('lnx.node_add_input', text='New', icon='PLUS', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
op.socket_type = 'LnxNodeSocketAnimAction'
|
||||
op.name_format = 'Action {0}'
|
||||
op.index_name_offset = -9
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_remove_input', text='', icon='X', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
@ -0,0 +1,51 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class PlayActionFromNode(LnxLogicTreeNode):
|
||||
"""
|
||||
Plays animation action, that starts from given frame (0 is the first), and ends at given frame (-1 for last frame).
|
||||
|
||||
@input In: Activates the node logic.
|
||||
@input Object: States object/armature to run the animation action on.
|
||||
@input Action: States animation action to be played.
|
||||
@input Start Frame: Sets frame the animation should start at from 0.
|
||||
@input End Frame: Sets frame the animation should end at. HINT: Set to "-1" if you want the total frames length of the animation.
|
||||
@input Blend: Sets rate to blend multiple animations together.
|
||||
@input Speed: Sets rate the animation plays at.
|
||||
@input Loop: Sets whether the animation should rewind itself after finishing.
|
||||
|
||||
@output Out: Executes whenever the node is run.
|
||||
@output Done: Executes whenever the played animation is finished. (Only triggers if looping is false.)
|
||||
"""
|
||||
bl_idname = 'LNPlayActionFromNode'
|
||||
bl_label = 'Play Action From'
|
||||
lnx_version = 3
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimAction', 'Action')
|
||||
self.add_input('LnxIntSocket', 'Start Frame')
|
||||
self.add_input('LnxIntSocket', 'End Frame')
|
||||
self.add_input('LnxFloatSocket', 'Blend', default_value = 0.25)
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value = 1.0)
|
||||
self.add_input('LnxBoolSocket', 'Loop', default_value = False)
|
||||
self.add_input('LnxBoolSocket', 'Reverse', default_value = False)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketAction', 'Done')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version in (0, 1):
|
||||
return NodeReplacement(
|
||||
'LNPlayActionFromNode', self.lnx_version, 'LNPlayActionFromNode', 2,
|
||||
in_socket_mapping={0:0, 1:1, 2:2, 3:3, 4:4}, out_socket_mapping={0:0, 1:1}
|
||||
)
|
||||
|
||||
if self.lnx_version == 2:
|
||||
return NodeReplacement(
|
||||
'LNPlayActionFromNode', self.lnx_version, 'LNPlayActionFromNode', 3,
|
||||
in_socket_mapping={0:0, 1:1, 2:2, 3:3, 4:5, 5:6, 6:7}, out_socket_mapping={0:0, 1:1}
|
||||
)
|
||||
|
||||
raise LookupError()
|
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class PlayAnimationTreeNode(LnxLogicTreeNode):
|
||||
"""Plays a given animation tree."""
|
||||
bl_idname = 'LNPlayAnimationTreeNode'
|
||||
bl_label = 'Play Animation Tree'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action Tree')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
16
leenkx/blender/lnx/logicnode/animation/LN_play_tilesheet.py
Normal file
16
leenkx/blender/lnx/logicnode/animation/LN_play_tilesheet.py
Normal file
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class PlayTilesheetNode(LnxLogicTreeNode):
|
||||
"""Plays the given tilesheet action."""
|
||||
bl_idname = 'LNPlayTilesheetNode'
|
||||
bl_label = 'Play Tilesheet'
|
||||
lnx_version = 1
|
||||
lnx_section = 'tilesheet'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Name')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketAction', 'Done')
|
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class RemoveParentBoneNode(LnxLogicTreeNode):
|
||||
"""Removes the given object parent to the given bone."""
|
||||
bl_idname = 'LNRemoveParentBoneNode'
|
||||
bl_label = 'Remove Parent Bone'
|
||||
lnx_version = 1
|
||||
lnx_section = 'armature'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketObject', 'Parent')
|
||||
self.add_input('LnxStringSocket', 'Bone', default_value='Bone')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
24
leenkx/blender/lnx/logicnode/animation/LN_restart_action.py
Normal file
24
leenkx/blender/lnx/logicnode/animation/LN_restart_action.py
Normal file
@ -0,0 +1,24 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class RestartActionNode(LnxLogicTreeNode):
|
||||
"""Restarts the action"""
|
||||
bl_idname = 'LNRestartActionNode'
|
||||
bl_label = 'Restart Action'
|
||||
bl_width_default = 200
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Action ID')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNRestartActionNode', self.lnx_version, 'LNRestartActionNode', 2,
|
||||
in_socket_mapping={}, out_socket_mapping={}
|
||||
)
|
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetActionFrameNode(LnxLogicTreeNode):
|
||||
"""Sets the current action frame for the given object."""
|
||||
bl_idname = 'LNSetActionFrameNode'
|
||||
bl_label = 'Set Action Frame'
|
||||
bl_width_default = 200
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Action ID')
|
||||
self.add_input('LnxIntSocket', 'Frame')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,25 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetActionPausedNode(LnxLogicTreeNode):
|
||||
"""Sets the action paused state of the given object."""
|
||||
bl_idname = 'LNSetActionPausedNode'
|
||||
bl_label = 'Set Action Paused'
|
||||
bl_width_default = 200
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Action ID')
|
||||
self.add_input('LnxBoolSocket', 'Paused')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNSetActionPausedNode', self.lnx_version, 'LNSetActionPausedNode', 2,
|
||||
in_socket_mapping={}, out_socket_mapping={}
|
||||
)
|
@ -0,0 +1,25 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetActionSpeedNode(LnxLogicTreeNode):
|
||||
"""Sets the current action playback speed of the given object."""
|
||||
bl_idname = 'LNSetActionSpeedNode'
|
||||
bl_label = 'Set Action Speed'
|
||||
bl_width_default = 200
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Action ID')
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value=1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement(
|
||||
'LNSetActionSpeedNode', self.lnx_version, 'LNSetActionSpeedNode', 2,
|
||||
in_socket_mapping={}, out_socket_mapping={}
|
||||
)
|
16
leenkx/blender/lnx/logicnode/animation/LN_set_action_time.py
Normal file
16
leenkx/blender/lnx/logicnode/animation/LN_set_action_time.py
Normal file
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetActionTimeNode(LnxLogicTreeNode):
|
||||
"""Sets the current action time for the given object."""
|
||||
bl_idname = 'LNSetActionTimeNode'
|
||||
bl_label = 'Set Action Time'
|
||||
bl_width_default = 200
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Action ID')
|
||||
self.add_input('LnxFloatSocket', 'Time')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetActiveTilesheetNode(LnxLogicTreeNode):
|
||||
"""Set the active tilesheet."""
|
||||
bl_idname = 'LNSetActiveTilesheetNode'
|
||||
bl_label = 'Set Active Tilesheet'
|
||||
lnx_version = 1
|
||||
lnx_section = 'tilesheet'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Tilesheet')
|
||||
self.add_input('LnxStringSocket', 'Action')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetBoneFkIkOnlyNode(LnxLogicTreeNode):
|
||||
"""Set particular bone to be animated by Forward kinematics or Inverse kinematics only. All other animations will be ignored"""
|
||||
bl_idname = 'LNSetBoneFkIkOnlyNode'
|
||||
bl_label = 'Set Bone FK IK Only'
|
||||
lnx_version = 1
|
||||
lnx_section = 'armature'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Bone')
|
||||
self.add_input('LnxBoolSocket', 'FK or IK only')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
16
leenkx/blender/lnx/logicnode/animation/LN_set_parent_bone.py
Normal file
16
leenkx/blender/lnx/logicnode/animation/LN_set_parent_bone.py
Normal file
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetParentBoneNode(LnxLogicTreeNode):
|
||||
"""Sets the given object parent to the given bone."""
|
||||
bl_idname = 'LNSetParentBoneNode'
|
||||
bl_label = 'Set Parent Bone'
|
||||
lnx_version = 1
|
||||
lnx_section = 'armature'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketObject', 'Parent')
|
||||
self.add_input('LnxStringSocket', 'Bone', default_value='Bone')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetParticleSpeedNode(LnxLogicTreeNode):
|
||||
"""Sets the speed of the given particle source."""
|
||||
bl_idname = 'LNSetParticleSpeedNode'
|
||||
bl_label = 'Set Particle Speed'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value=1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,17 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetTilesheetFrame(LnxLogicTreeNode):
|
||||
"""Set the frame of the current tilesheet action.
|
||||
@input Frame: Frame offset to set with 0 as the first frame of the active action.
|
||||
"""
|
||||
bl_idname = 'LNSetTilesheetFrameNode'
|
||||
bl_label = 'Set Tilesheet Frame'
|
||||
lnx_version = 1
|
||||
lnx_section = 'tilesheet'
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxIntSocket', 'Frame')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetTilesheetPausedNode(LnxLogicTreeNode):
|
||||
"""Sets the tilesheet paused state of the given object."""
|
||||
bl_idname = 'LNSetTilesheetPausedNode'
|
||||
bl_label = 'Set Tilesheet Paused'
|
||||
lnx_section = 'tilesheet'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxBoolSocket', 'Paused')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
54
leenkx/blender/lnx/logicnode/animation/LN_simple_foot_ik.py
Normal file
54
leenkx/blender/lnx/logicnode/animation/LN_simple_foot_ik.py
Normal file
@ -0,0 +1,54 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SimpleFootIKNode(LnxLogicTreeNode):
|
||||
"""Performs inverse kinematics on the selected armature with specified bone.
|
||||
|
||||
@input Object: Armature on which IK should be performed.
|
||||
|
||||
@input Bone: Effector or tip bone for the inverse kinematics
|
||||
|
||||
@input Goal Position: Position in world coordinates the effector bone will track to
|
||||
|
||||
@input Enable Pole: Bend IK solution towards pole location
|
||||
|
||||
@input Pole Position: Location of the pole in world coordinates
|
||||
|
||||
@input Chain Length: Number of bones to include in the IK solver including the effector. If set to 0, all bones from effector to the root bone of the armature will be considered.
|
||||
|
||||
@input Max Iterations: Maximum allowed FABRIK iterations to solve for IK. For longer chains, more iterations are needed.
|
||||
|
||||
@input Precision: Presition of IK to stop at. It is described as a tolerence in length. Typically 0.01 is a good value.
|
||||
|
||||
@input Roll Angle: Roll the bones along their local axis with specified radians. set 0 for no extra roll.
|
||||
"""
|
||||
bl_idname = 'LNSimpleFootIKNode'
|
||||
bl_label = 'Foot IK Node'
|
||||
lnx_version = 1
|
||||
lnx_section = 'armature'
|
||||
|
||||
property0: HaxeStringProperty('property0', name = '', default = '')
|
||||
property1: HaxeStringProperty('property1', name = '', default = '')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.label(text='Left Foot Name:')
|
||||
layout.prop(self, 'property0')
|
||||
layout.label(text='Right Foot Name:')
|
||||
layout.prop(self, 'property1')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action')
|
||||
self.add_input('LnxFloatSocket', 'Scan Height', default_value = 1.0)
|
||||
self.add_input('LnxFloatSocket', 'Scan Depth', default_value = 1.0)
|
||||
self.add_input('LnxIntSocket', 'Collision Mask', default_value = 1)
|
||||
self.add_input('LnxFloatSocket', 'Height Offset', default_value = 0.0)
|
||||
self.add_input('LnxFloatSocket', 'Foot Offset', default_value = 0.0)
|
||||
self.add_input('LnxFloatSocket', 'Offset Threshold', default_value = 1.0)
|
||||
self.add_input('LnxFloatSocket', 'Interp Speed', default_value = 0.1)
|
||||
self.add_input('LnxIntSocket', 'Bone Group', default_value = -1)
|
||||
self.add_input('LnxFloatSocket', 'Influence', default_value = 1.0)
|
||||
self.add_input('LnxBoolSocket', 'Use Pole Targets', default_value = False)
|
||||
self.add_input('LnxBoolSocket', 'Rotate Foot', default_value = False)
|
||||
self.add_input('LnxNodeSocketArray', 'Pole And Direction Array')
|
||||
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Result')
|
20
leenkx/blender/lnx/logicnode/animation/LN_switch_action.py
Normal file
20
leenkx/blender/lnx/logicnode/animation/LN_switch_action.py
Normal file
@ -0,0 +1,20 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SwitchActionNode(LnxLogicTreeNode):
|
||||
"""Switch between the two given actions with interpolation."""
|
||||
bl_idname = 'LNSwitchActionNode'
|
||||
bl_label = 'Switch Action'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Action 1')
|
||||
self.add_input('LnxNodeSocketAction', 'Action 2')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action 1')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action 2')
|
||||
self.add_input('LnxBoolSocket', 'Restart', default_value = True)
|
||||
self.add_input('LnxFloatSocket', 'Time', default_value = 1.0)
|
||||
self.add_input('LnxIntSocket', 'Bone Group', default_value = -1)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Done')
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Result')
|
@ -0,0 +1,38 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SwitchActionMultiNode(LnxLogicTreeNode):
|
||||
"""Switch between the given actions with interpolation."""
|
||||
bl_idname = 'LNSwitchActionMultiNode'
|
||||
bl_label = 'Switch Action Multi'
|
||||
lnx_version = 1
|
||||
min_inputs = 8
|
||||
|
||||
def __init__(self):
|
||||
super(SwitchActionMultiNode, self).__init__()
|
||||
array_nodes[self.get_id_str()] = self
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Switch')
|
||||
self.add_input('LnxIntSocket', 'Switch To', default_value = 1)
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxBoolSocket', 'Restart', default_value = True)
|
||||
self.add_input('LnxFloatSocket', 'Time', default_value = 1.0)
|
||||
self.add_input('LnxIntSocket', 'Bone Group', default_value = -1)
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action 0')
|
||||
self.add_input('LnxNodeSocketAnimTree', 'Action 1')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Done')
|
||||
self.add_output('LnxNodeSocketAnimTree', 'Result')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
op = row.operator('lnx.node_add_input', text='New', icon='PLUS', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
op.socket_type = 'LnxNodeSocketAnimTree'
|
||||
op.name_format = 'Action {0}'
|
||||
op.index_name_offset = -6
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_remove_input', text='', icon='X', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
21
leenkx/blender/lnx/logicnode/animation/LN_sync_actions.py
Normal file
21
leenkx/blender/lnx/logicnode/animation/LN_sync_actions.py
Normal file
@ -0,0 +1,21 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SyncActionsNode(LnxLogicTreeNode):
|
||||
"""Sync two actions when blending from one to the other such that Frame A and B in both actions align."""
|
||||
|
||||
bl_idname = 'LNSyncActionNode'
|
||||
bl_label = 'Sync Action'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'From ID')
|
||||
self.add_input('LnxIntSocket', 'Frame A', default_value=0)
|
||||
self.add_input('LnxIntSocket', 'Frame B', default_value=-1)
|
||||
self.add_input('LnxBoolSocket', 'Reset Speed', default_value=True)
|
||||
self.add_input('LnxStringSocket', 'To ID')
|
||||
self.add_input('LnxIntSocket', 'Frame A', default_value=0)
|
||||
self.add_input('LnxIntSocket', 'Frame B', default_value=-1)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
5
leenkx/blender/lnx/logicnode/animation/__init__.py
Normal file
5
leenkx/blender/lnx/logicnode/animation/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
from lnx.logicnode.lnx_nodes import add_node_section
|
||||
|
||||
add_node_section(name='default', category='Animation')
|
||||
add_node_section(name='tilesheet', category='Animation')
|
||||
add_node_section(name='armature', category='Animation')
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
50
leenkx/blender/lnx/logicnode/array/LN_array.py
Normal file
50
leenkx/blender/lnx/logicnode/array/LN_array.py
Normal file
@ -0,0 +1,50 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class ArrayNode(LnxLogicVariableNodeMixin, LnxLogicTreeNode):
|
||||
"""Stores the given array as a variable."""
|
||||
bl_idname = 'LNArrayNode'
|
||||
bl_label = 'Array Dynamic'
|
||||
lnx_version = 3
|
||||
lnx_section = 'variable'
|
||||
min_inputs = 0
|
||||
|
||||
def __init__(self):
|
||||
self.register_id()
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxNodeSocketArray', 'Array', is_var=True)
|
||||
self.add_output('LnxIntSocket', 'Length')
|
||||
|
||||
def draw_content(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
|
||||
op = row.operator('lnx.node_add_input', text='New', icon='PLUS', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
op.socket_type = 'LnxDynamicSocket'
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_remove_input', text='', icon='X', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
||||
|
||||
def draw_label(self) -> str:
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
return super().draw_label()
|
||||
|
||||
return f'{super().draw_label()} [{len(self.inputs)}]'
|
||||
|
||||
def synchronize_from_master(self, master_node: LnxLogicVariableNodeMixin):
|
||||
self.inputs.clear()
|
||||
for i in range(len(master_node.inputs)):
|
||||
inp = self.add_input('LnxDynamicSocket', master_node.inputs[i].name)
|
||||
inp.hide = self.lnx_logic_id != ''
|
||||
inp.enabled = self.lnx_logic_id == ''
|
||||
inp.default_value_raw = master_node.inputs[i].get_default_value()
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 2):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
||||
|
46
leenkx/blender/lnx/logicnode/array/LN_array_add.py
Normal file
46
leenkx/blender/lnx/logicnode/array/LN_array_add.py
Normal file
@ -0,0 +1,46 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayAddNode(LnxLogicTreeNode):
|
||||
"""Adds the given value to the given array.
|
||||
|
||||
@input Array: the array to manipulate.
|
||||
@input Modify Original: if `false`, the input array is copied before adding the value.
|
||||
@input Unique Values: if `true`, values may occur only once in that array (only primitive data types are supported).
|
||||
"""
|
||||
bl_idname = 'LNArrayAddNode'
|
||||
bl_label = 'Array Add'
|
||||
lnx_version = 5
|
||||
min_inputs = 6
|
||||
|
||||
def __init__(self):
|
||||
super(ArrayAddNode, self).__init__()
|
||||
array_nodes[self.get_id_str()] = self
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxBoolSocket', 'Modify Original', default_value=True)
|
||||
self.add_input('LnxBoolSocket', 'Unique Values')
|
||||
self.add_input('LnxBoolSocket', 'Add First')
|
||||
self.add_input('LnxDynamicSocket', 'Value')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketArray', 'Array')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
|
||||
op = row.operator('lnx.node_add_input_value', text='Add Input', icon='PLUS', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
op.socket_type = 'LnxDynamicSocket'
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_remove_input', text='', icon='X', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 4):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
50
leenkx/blender/lnx/logicnode/array/LN_array_boolean.py
Normal file
50
leenkx/blender/lnx/logicnode/array/LN_array_boolean.py
Normal file
@ -0,0 +1,50 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class BooleanArrayNode(LnxLogicVariableNodeMixin, LnxLogicTreeNode):
|
||||
"""Stores an array of boolean elements as a variable."""
|
||||
bl_idname = 'LNArrayBooleanNode'
|
||||
bl_label = 'Array Boolean'
|
||||
lnx_version = 3
|
||||
lnx_section = 'variable'
|
||||
min_inputs = 0
|
||||
|
||||
def __init__(self):
|
||||
super(BooleanArrayNode, self).__init__()
|
||||
self.register_id()
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxNodeSocketArray', 'Array', is_var=True)
|
||||
self.add_output('LnxIntSocket', 'Length')
|
||||
|
||||
def draw_content(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
|
||||
op = row.operator('lnx.node_add_input', text='New', icon='PLUS', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
op.socket_type = 'LnxBoolSocket'
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_remove_input', text='', icon='X', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
||||
|
||||
def draw_label(self) -> str:
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
return super().draw_label()
|
||||
|
||||
return f'{super().draw_label()} [{len(self.inputs)}]'
|
||||
|
||||
def synchronize_from_master(self, master_node: LnxLogicVariableNodeMixin):
|
||||
self.inputs.clear()
|
||||
for i in range(len(master_node.inputs)):
|
||||
inp = self.add_input('LnxBoolSocket', master_node.inputs[i].name)
|
||||
inp.hide = self.lnx_logic_id != ''
|
||||
inp.enabled = self.lnx_logic_id == ''
|
||||
inp.default_value_raw = master_node.inputs[i].get_default_value()
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 2):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
50
leenkx/blender/lnx/logicnode/array/LN_array_color.py
Normal file
50
leenkx/blender/lnx/logicnode/array/LN_array_color.py
Normal file
@ -0,0 +1,50 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class ColorArrayNode(LnxLogicVariableNodeMixin, LnxLogicTreeNode):
|
||||
"""Stores an array of color elements as a variable."""
|
||||
bl_idname = 'LNArrayColorNode'
|
||||
bl_label = 'Array Color'
|
||||
lnx_version = 3
|
||||
lnx_section = 'variable'
|
||||
min_inputs = 0
|
||||
|
||||
def __init__(self):
|
||||
super(ColorArrayNode, self).__init__()
|
||||
self.register_id()
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxNodeSocketArray', 'Array', is_var=True)
|
||||
self.add_output('LnxIntSocket', 'Length')
|
||||
|
||||
def draw_content(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
|
||||
op = row.operator('lnx.node_add_input', text='New', icon='PLUS', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
op.socket_type = 'LnxColorSocket'
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_remove_input', text='', icon='X', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
||||
|
||||
def draw_label(self) -> str:
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
return super().draw_label()
|
||||
|
||||
return f'{super().draw_label()} [{len(self.inputs)}]'
|
||||
|
||||
def synchronize_from_master(self, master_node: LnxLogicVariableNodeMixin):
|
||||
self.inputs.clear()
|
||||
for i in range(len(master_node.inputs)):
|
||||
inp = self.add_input('LnxColorSocket', master_node.inputs[i].name)
|
||||
inp.hide = self.lnx_logic_id != ''
|
||||
inp.enabled = self.lnx_logic_id == ''
|
||||
inp.default_value_raw = master_node.inputs[i].get_default_value()
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 2):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
15
leenkx/blender/lnx/logicnode/array/LN_array_compare.py
Normal file
15
leenkx/blender/lnx/logicnode/array/LN_array_compare.py
Normal file
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayCompareNode(LnxLogicTreeNode):
|
||||
"""Compare arrays."""
|
||||
|
||||
bl_idname = 'LNArrayCompareNode'
|
||||
bl_label = 'Array Compare'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
|
||||
self.add_output('LnxBoolSocket', 'Compare')
|
||||
|
15
leenkx/blender/lnx/logicnode/array/LN_array_concat.py
Normal file
15
leenkx/blender/lnx/logicnode/array/LN_array_concat.py
Normal file
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayConcatNode(LnxLogicTreeNode):
|
||||
"""Join arrays."""
|
||||
|
||||
bl_idname = 'LNArrayConcatNode'
|
||||
bl_label = 'Array Concat'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
|
||||
self.add_output('LnxNodeSocketArray', 'Array')
|
||||
self.add_output('LnxIntSocket', 'Length')
|
13
leenkx/blender/lnx/logicnode/array/LN_array_contains.py
Normal file
13
leenkx/blender/lnx/logicnode/array/LN_array_contains.py
Normal file
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayContainsNode(LnxLogicTreeNode):
|
||||
"""Returns whether the given array contains the given value."""
|
||||
bl_idname = 'LNArrayInArrayNode'
|
||||
bl_label = 'Array Contains'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxDynamicSocket', 'Value')
|
||||
|
||||
self.add_output('LnxBoolSocket', 'Contains')
|
12
leenkx/blender/lnx/logicnode/array/LN_array_count.py
Normal file
12
leenkx/blender/lnx/logicnode/array/LN_array_count.py
Normal file
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayCountNode(LnxLogicTreeNode):
|
||||
"""Returns an array with the item counts of the given array."""
|
||||
bl_idname = 'LNArrayCountNode'
|
||||
bl_label = 'Array Count'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
|
||||
self.add_output('LnxNodeSocketArray', 'Count')
|
31
leenkx/blender/lnx/logicnode/array/LN_array_display.py
Normal file
31
leenkx/blender/lnx/logicnode/array/LN_array_display.py
Normal file
@ -0,0 +1,31 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayDisplayNode(LnxLogicTreeNode):
|
||||
"""Returns the display of the given array."""
|
||||
bl_idname = 'LNArrayDisplayNode'
|
||||
bl_label = 'Array Display'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 2:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Item Field':
|
||||
self.add_input('LnxStringSocket', 'Item Field')
|
||||
if self.property0 == 'Item Property':
|
||||
self.add_input('LnxStringSocket', 'Item Property')
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Item', 'Item', 'Array Item'),
|
||||
('Item Field', 'Item Field', 'Object Item Field, ie: name, uid, visible, parent, length, etc.'),
|
||||
('Item Property', 'Item Property', 'Object Item Property')],
|
||||
name='', default='Item', update=remove_extra_inputs)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxStringSocket', 'Separator')
|
||||
|
||||
self.add_output('LnxStringSocket', 'Items')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
13
leenkx/blender/lnx/logicnode/array/LN_array_distinct.py
Normal file
13
leenkx/blender/lnx/logicnode/array/LN_array_distinct.py
Normal file
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayDistinctNode(LnxLogicTreeNode):
|
||||
"""Returns the Distinct and Duplicated items of the given array."""
|
||||
bl_idname = 'LNArrayDistinctNode'
|
||||
bl_label = 'Array Distinct'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
|
||||
self.add_output('LnxNodeSocketArray', 'Distinct')
|
||||
self.add_output('LnxNodeSocketArray', 'Duplicated')
|
49
leenkx/blender/lnx/logicnode/array/LN_array_filter.py
Normal file
49
leenkx/blender/lnx/logicnode/array/LN_array_filter.py
Normal file
@ -0,0 +1,49 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayFilterNode(LnxLogicTreeNode):
|
||||
"""Returns an array with the filtered items of the given array."""
|
||||
bl_idname = 'LNArrayFilterNode'
|
||||
bl_label = 'Array Filter'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 1:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Item Field':
|
||||
self.add_input('LnxStringSocket', 'Item Field')
|
||||
if self.property0 == 'Item Property':
|
||||
self.add_input('LnxStringSocket', 'Item Property')
|
||||
self.add_input('LnxDynamicSocket', 'Value')
|
||||
if self.property1 == 'Between':
|
||||
self.add_input('LnxDynamicSocket', 'Value')
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Item', 'Item', 'Array Item'),
|
||||
('Item Field', 'Item Field', 'Object Item Field, ie: Name, Uid, Visible, Parent, Length, etc.'),
|
||||
('Item Property', 'Item Property', 'Object Item Property')],
|
||||
name='', default='Item', update=remove_extra_inputs)
|
||||
|
||||
property1: HaxeEnumProperty(
|
||||
'property1',
|
||||
items = [('Equal', 'Equal', 'Equal'),
|
||||
('Not Equal', 'Not Equal', 'Not Equal'),
|
||||
('Greater', 'Greater', 'Greater'),
|
||||
('Greater Equal', 'Greater Equal', 'Greater Equal'),
|
||||
('Less', 'Less', 'Less'),
|
||||
('Less Equal', 'Less Equal', 'Less Equal'),
|
||||
('Between', 'Between', 'Input 1 Between Input 2 and Input 3 inclusive'),
|
||||
('Contains', 'Contains', 'Contains'),
|
||||
('Starts With', 'Starts With', 'Starts With'),
|
||||
('Ends With', 'Ends With', 'Ends With')],
|
||||
name='', default='Equal', update=remove_extra_inputs)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxDynamicSocket', 'Value')
|
||||
|
||||
self.add_output('LnxNodeSocketArray', 'Array')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
layout.prop(self, 'property1')
|
61
leenkx/blender/lnx/logicnode/array/LN_array_float.py
Normal file
61
leenkx/blender/lnx/logicnode/array/LN_array_float.py
Normal file
@ -0,0 +1,61 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class FloatArrayNode(LnxLogicVariableNodeMixin, LnxLogicTreeNode):
|
||||
"""Stores an array of float elements as a variable."""
|
||||
bl_idname = 'LNArrayFloatNode'
|
||||
bl_label = 'Array Float'
|
||||
lnx_version = 3
|
||||
lnx_section = 'variable'
|
||||
min_inputs = 0
|
||||
|
||||
def __init__(self):
|
||||
super(FloatArrayNode, self).__init__()
|
||||
self.register_id()
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxNodeSocketArray', 'Array', is_var=True)
|
||||
self.add_output('LnxIntSocket', 'Length')
|
||||
|
||||
def draw_content(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
|
||||
op = row.operator('lnx.node_add_input', text='New', icon='PLUS', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
op.socket_type = 'LnxFloatSocket'
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_remove_input', text='', icon='X', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
||||
|
||||
def draw_label(self) -> str:
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
return super().draw_label()
|
||||
|
||||
return f'{super().draw_label()} [{len(self.inputs)}]'
|
||||
|
||||
def synchronize_from_master(self, master_node: LnxLogicVariableNodeMixin):
|
||||
self.inputs.clear()
|
||||
for i in range(len(master_node.inputs)):
|
||||
inp = self.add_input('LnxFloatSocket', master_node.inputs[i].name)
|
||||
inp.hide = self.lnx_logic_id != ''
|
||||
inp.enabled = self.lnx_logic_id == ''
|
||||
inp.default_value_raw = master_node.inputs[i].get_default_value()
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version < 0 or self.lnx_version > 2:
|
||||
raise LookupError()
|
||||
|
||||
newnode = node_tree.nodes.new(FloatArrayNode.bl_idname)
|
||||
for inp_old in self.inputs:
|
||||
inp_new = newnode.add_input('LnxFloatSocket', inp_old.name)
|
||||
inp_new.hide = self.lnx_logic_id != ''
|
||||
inp_new.enabled = self.lnx_logic_id != ''
|
||||
inp_new.default_value_raw = inp_old.get_default_value()
|
||||
NodeReplacement.replace_input_socket(node_tree, inp_old, inp_new)
|
||||
|
||||
NodeReplacement.replace_output_socket(node_tree, self.outputs[0], newnode.outputs[0])
|
||||
NodeReplacement.replace_output_socket(node_tree, self.outputs[1], newnode.outputs[1])
|
||||
|
||||
return newnode
|
13
leenkx/blender/lnx/logicnode/array/LN_array_get.py
Normal file
13
leenkx/blender/lnx/logicnode/array/LN_array_get.py
Normal file
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayGetNode(LnxLogicTreeNode):
|
||||
"""Returns the value of the given array at the given index."""
|
||||
bl_idname = 'LNArrayGetNode'
|
||||
bl_label = 'Array Get'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxIntSocket', 'Index')
|
||||
|
||||
self.add_output('LnxDynamicSocket', 'Value')
|
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayGetPreviousNextNode(LnxLogicTreeNode):
|
||||
"""Returns the previous or next value to be retrieve by looping the array according to the boolean condition."""
|
||||
bl_idname = 'LNArrayGetPreviousNextNode'
|
||||
bl_label = 'Array Get Previous/Next'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxBoolSocket', 'Previous: 0 / Next: 1')
|
||||
|
||||
self.add_output('LnxDynamicSocket', 'Value')
|
12
leenkx/blender/lnx/logicnode/array/LN_array_get_next.py
Normal file
12
leenkx/blender/lnx/logicnode/array/LN_array_get_next.py
Normal file
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayGetNextNode(LnxLogicTreeNode):
|
||||
"""Returns the next value to be retrieve by looping the array."""
|
||||
bl_idname = 'LNArrayGetNextNode'
|
||||
bl_label = 'Array Get Next'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
|
||||
self.add_output('LnxDynamicSocket', 'Value')
|
20
leenkx/blender/lnx/logicnode/array/LN_array_index.py
Normal file
20
leenkx/blender/lnx/logicnode/array/LN_array_index.py
Normal file
@ -0,0 +1,20 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayIndexNode(LnxLogicTreeNode):
|
||||
"""Returns the array index of the given value."""
|
||||
bl_idname = 'LNArrayIndexNode'
|
||||
bl_label = 'Array Index'
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxDynamicSocket', 'Value')
|
||||
self.add_input('LnxIntSocket', 'From')
|
||||
|
||||
self.add_output('LnxIntSocket', 'Index')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
16
leenkx/blender/lnx/logicnode/array/LN_array_insert.py
Normal file
16
leenkx/blender/lnx/logicnode/array/LN_array_insert.py
Normal file
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayInsertNode(LnxLogicTreeNode):
|
||||
"""Inserts the value of the given array at the given index and increases the length of the array."""
|
||||
bl_idname = 'LNArrayInsertNode'
|
||||
bl_label = 'Array Insert'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxIntSocket', 'Index')
|
||||
self.add_input('LnxDynamicSocket', 'Value')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketArray', 'Array')
|
50
leenkx/blender/lnx/logicnode/array/LN_array_integer.py
Normal file
50
leenkx/blender/lnx/logicnode/array/LN_array_integer.py
Normal file
@ -0,0 +1,50 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class IntegerArrayNode(LnxLogicVariableNodeMixin, LnxLogicTreeNode):
|
||||
"""Stores an array of integer elements as a variable."""
|
||||
bl_idname = 'LNArrayIntegerNode'
|
||||
bl_label = 'Array Integer'
|
||||
lnx_version = 4
|
||||
lnx_section = 'variable'
|
||||
min_inputs = 0
|
||||
|
||||
def __init__(self):
|
||||
super(IntegerArrayNode, self).__init__()
|
||||
self.register_id()
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxNodeSocketArray', 'Array', is_var=True)
|
||||
self.add_output('LnxIntSocket', 'Length')
|
||||
|
||||
def draw_content(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
|
||||
op = row.operator('lnx.node_add_input', text='New', icon='PLUS', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
op.socket_type = 'LnxIntSocket'
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_remove_input', text='', icon='X', emboss=True)
|
||||
op.node_index = self.get_id_str()
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
||||
|
||||
def draw_label(self) -> str:
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
return super().draw_label()
|
||||
|
||||
return f'{super().draw_label()} [{len(self.inputs)}]'
|
||||
|
||||
def synchronize_from_master(self, master_node: LnxLogicVariableNodeMixin):
|
||||
self.inputs.clear()
|
||||
for i in range(len(master_node.inputs)):
|
||||
inp = self.add_input('LnxIntSocket', master_node.inputs[i].name)
|
||||
inp.hide = self.lnx_logic_id != ''
|
||||
inp.enabled = self.lnx_logic_id == ''
|
||||
inp.default_value_raw = master_node.inputs[i].get_default_value()
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 3):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
12
leenkx/blender/lnx/logicnode/array/LN_array_length.py
Normal file
12
leenkx/blender/lnx/logicnode/array/LN_array_length.py
Normal file
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ArrayLengthNode(LnxLogicTreeNode):
|
||||
"""Returns the length of the given array."""
|
||||
bl_idname = 'LNArrayLengthNode'
|
||||
bl_label = 'Array Length'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
|
||||
self.add_output('LnxIntSocket', 'Length')
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user