Condition Nodes #6
145
nodes.py
145
nodes.py
@ -4,7 +4,7 @@ import functools
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from math import degrees, radians
|
from math import degrees, radians
|
||||||
from typing import TypeVar, Callable, Optional, Iterable
|
from typing import TypeVar, Callable, Optional, Iterable, Tuple, List
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import nodeitems_utils
|
import nodeitems_utils
|
||||||
@ -13,6 +13,10 @@ from mathutils import Vector, Quaternion, Matrix, Euler
|
|||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
|
def _on_num_sockets_change(self: "SequenceNode", context: bpy.types.Context) -> None:
|
||||||
|
self.recreate(context)
|
||||||
|
|
||||||
|
|
||||||
class RigNodesNodeTree(bpy.types.NodeTree):
|
class RigNodesNodeTree(bpy.types.NodeTree):
|
||||||
"""Control EVERYTHING"""
|
"""Control EVERYTHING"""
|
||||||
|
|
||||||
@ -927,6 +931,137 @@ class Math(AbstractRigNodesNode):
|
|||||||
self.outputs["Result"].default_value = res
|
self.outputs["Result"].default_value = res
|
||||||
|
|
||||||
|
|
||||||
|
_enum_condition_data_types = [
|
||||||
|
("VECTOR", "Vector", ""),
|
||||||
|
("ROTATION", "Rotation", ""),
|
||||||
|
("FLOAT", "Float", ""),
|
||||||
|
("INT", "Int", ""),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _enum_dyn_conditional_value(
|
||||||
|
self: "ConditionalValueNode", context: bpy.types.Context
|
||||||
|
) -> List[Tuple[str, str, str]]:
|
||||||
|
if self.num_socks <= 0:
|
||||||
|
return [("NONE", "None", "")]
|
||||||
|
return [(f"{i}", f"Socket {i+1}", "") for i in range(0, self.num_socks)]
|
||||||
|
|
||||||
|
|
||||||
|
class ConditionalValueNode(AbstractRigNodesNode):
|
||||||
|
bl_idname = "ConditionalValueNode"
|
||||||
|
bl_label = "Conditional Value"
|
||||||
|
bl_icon = "EMPTY_ARROWS"
|
||||||
|
|
||||||
|
dtype: bpy.props.EnumProperty( # type: ignore
|
||||||
|
name="Type",
|
||||||
|
items=_enum_condition_data_types,
|
||||||
|
default="VECTOR",
|
||||||
|
update=_on_num_sockets_change,
|
||||||
|
)
|
||||||
|
num_socks: bpy.props.IntProperty( # type: ignore
|
||||||
|
default=2,
|
||||||
|
name="Sockets",
|
||||||
|
update=_on_num_sockets_change,
|
||||||
|
)
|
||||||
|
active_sel: bpy.props.EnumProperty( # type: ignore
|
||||||
|
name="Active",
|
||||||
|
items=_enum_dyn_conditional_value,
|
||||||
|
)
|
||||||
|
|
||||||
|
def draw_buttons(
|
||||||
|
self, context: bpy.types.Context, layout: bpy.types.UILayout
|
||||||
|
) -> None:
|
||||||
|
super().draw_buttons(context, layout)
|
||||||
|
layout.prop(self, "active_sel")
|
||||||
|
layout.prop(self, "dtype")
|
||||||
|
layout.prop(self, "num_socks")
|
||||||
|
|
||||||
|
def init(self, context):
|
||||||
|
for index in range(0, self.num_socks):
|
||||||
|
match self.dtype:
|
||||||
|
case "VECTOR":
|
||||||
|
self.inputs.new("NodeSocketVector", f"Vector {index+1}")
|
||||||
|
case "ROTATION":
|
||||||
|
self.inputs.new("NodeSocketQuaternion", f"Rotation {index+1}")
|
||||||
|
case "FLOAT":
|
||||||
|
self.inputs.new("NodeSocketFloat", f"Float {index+1}")
|
||||||
|
case "INT":
|
||||||
|
self.inputs.new("NodeSocketInt", f"Int {index+1}")
|
||||||
|
|
||||||
|
match self.dtype:
|
||||||
|
case "VECTOR":
|
||||||
|
self.outputs.new("NodeSocketVector", "Vector")
|
||||||
|
case "ROTATION":
|
||||||
|
self.outputs.new("NodeSocketQuaternion", "Rotation")
|
||||||
|
case "FLOAT":
|
||||||
|
self.outputs.new("NodeSocketFloat", "Float")
|
||||||
|
case "INT":
|
||||||
|
self.outputs.new("NodeSocketInt", "Int")
|
||||||
|
|
||||||
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
|
match self.dtype:
|
||||||
|
case "VECTOR":
|
||||||
|
out = self._get_input_value(f"Vector {int(self.active_sel)+1}", Vector)
|
||||||
|
case "ROTATION":
|
||||||
|
out = self._get_input_value(
|
||||||
|
f"Rotation {int(self.active_sel)+1}", Quaternion
|
||||||
|
)
|
||||||
|
case "FLOAT":
|
||||||
|
out = self._get_input_value(f"Float {int(self.active_sel)+1}", float)
|
||||||
|
case "INT":
|
||||||
|
out = self._get_input_value(f"Int {int(self.active_sel)+1}", int)
|
||||||
|
|
||||||
|
self.outputs[0].default_value = out
|
||||||
|
|
||||||
|
|
||||||
|
class ConditionalExecutionNode(AbstractRigNodesNode):
|
||||||
|
bl_idname = "ConditionalExecutionNode"
|
||||||
|
bl_label = "Conditional Execution"
|
||||||
|
bl_icon = "EMPTY_ARROWS"
|
||||||
|
|
||||||
|
num_socks: bpy.props.IntProperty( # type: ignore
|
||||||
|
default=2,
|
||||||
|
name="Sockets",
|
||||||
|
update=_on_num_sockets_change,
|
||||||
|
)
|
||||||
|
active_sel: bpy.props.EnumProperty( # type: ignore
|
||||||
|
name="Active",
|
||||||
|
items=_enum_dyn_conditional_value,
|
||||||
|
)
|
||||||
|
|
||||||
|
def draw_buttons(
|
||||||
|
self, context: bpy.types.Context, layout: bpy.types.UILayout
|
||||||
|
) -> None:
|
||||||
|
super().draw_buttons(context, layout)
|
||||||
|
layout.prop(self, "active_sel")
|
||||||
|
layout.prop(self, "num_socks")
|
||||||
|
|
||||||
|
def init(self, context: bpy.types.Context) -> None:
|
||||||
|
self.inputs.new(NodeSocketExecute.bl_idname, NodeSocketExecute.bl_label)
|
||||||
|
for index in range(0, self.num_socks):
|
||||||
|
self.outputs.new(
|
||||||
|
NodeSocketExecute.bl_idname, f"{NodeSocketExecute.bl_label} {index + 1}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def exec_order_successors(self) -> Iterable["AbstractRigNodesNode"]:
|
||||||
|
"""Generator, yields the nodes that should be executed after this one."""
|
||||||
|
|
||||||
|
# For output execution order, only consider actual 'Execute' sockets.
|
||||||
|
def follow_socket(socket: bpy.types.NodeSocket) -> bool:
|
||||||
|
return isinstance(socket, NodeSocketExecute) or isinstance(
|
||||||
|
socket.node, AbstractAlwaysExecuteNode
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.active_sel is not "NONE":
|
||||||
|
return self._connected_nodes(
|
||||||
|
[self.outputs[int(self.active_sel)]], "to_socket", follow_socket
|
||||||
|
)
|
||||||
|
return []
|
||||||
|
|
||||||
|
def execute(self, depsgraph: bpy.types.Depsgraph) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SetCursorNode(AbstractAlwaysExecuteNode):
|
class SetCursorNode(AbstractAlwaysExecuteNode):
|
||||||
"""Sets the location and/or rotation of the 3D cursor"""
|
"""Sets the location and/or rotation of the 3D cursor"""
|
||||||
|
|
||||||
@ -1232,10 +1367,6 @@ class ClampNode(AbstractRigNodesNode):
|
|||||||
self.outputs["Result"].default_value = clamped
|
self.outputs["Result"].default_value = clamped
|
||||||
|
|
||||||
|
|
||||||
def _on_num_sockets_change(self: "SequenceNode", context: bpy.types.Context) -> None:
|
|
||||||
self.recreate(context)
|
|
||||||
|
|
||||||
|
|
||||||
class SequenceNode(AbstractRigNodesNode):
|
class SequenceNode(AbstractRigNodesNode):
|
||||||
"""Multiple 'Execute' node sockets."""
|
"""Multiple 'Execute' node sockets."""
|
||||||
|
|
||||||
@ -1307,6 +1438,8 @@ node_categories = [
|
|||||||
"Flow",
|
"Flow",
|
||||||
items=[
|
items=[
|
||||||
nodeitems_utils.NodeItem("SequenceNode"),
|
nodeitems_utils.NodeItem("SequenceNode"),
|
||||||
|
nodeitems_utils.NodeItem("ConditionalValueNode"),
|
||||||
|
nodeitems_utils.NodeItem("ConditionalExecutionNode"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
RigNodesNodeCategory(
|
RigNodesNodeCategory(
|
||||||
@ -1371,6 +1504,8 @@ classes = (
|
|||||||
TwoBoneIKNode,
|
TwoBoneIKNode,
|
||||||
SetCursorNode,
|
SetCursorNode,
|
||||||
SequenceNode,
|
SequenceNode,
|
||||||
|
ConditionalValueNode,
|
||||||
|
ConditionalExecutionNode,
|
||||||
# Math Nodes
|
# Math Nodes
|
||||||
RotateTowards,
|
RotateTowards,
|
||||||
AngleFromVectors,
|
AngleFromVectors,
|
||||||
|
Loading…
Reference in New Issue
Block a user