Browse Source

Partial Implementation: Arrays for Arm. Constraint

This commmit does most or all of the UI code, but doesn't implement it
on the Mantis side -  and more importantly, it isn't tested thoroughly.

Perhaps I should make some of these bigger changes optional... hmmm
Joseph Brandenburg 1 month ago
parent
commit
295ead344f
7 changed files with 66 additions and 52 deletions
  1. 0 5
      __init__.py
  2. 0 1
      base_definitions.py
  3. 4 0
      link_nodes.py
  4. 0 8
      link_nodes_ui.py
  5. 2 0
      link_socket_templates.py
  6. 25 11
      utilities.py
  7. 35 27
      versioning.py

+ 0 - 5
__init__.py

@@ -275,7 +275,6 @@ def execute_handler(scene):
 
 from .versioning import versioning_tasks
 def node_version_update(node, do_once):
-    print("AAAAA")
     from .xForm_nodes_ui import xFormNode
     for bl_idname, task, required_kwargs in versioning_tasks:
         arg_map = {}
@@ -294,7 +293,6 @@ def node_version_update(node, do_once):
 
 def do_version_update(node_tree):
     # set updating status for dynamic nodes to prevent bugs in socket remapping
-    print("BBBBB")
     do_once = True
     for node in node_tree.nodes:
         if hasattr(node, 'is_updating'):
@@ -322,14 +320,11 @@ def do_version_update(node_tree):
 
 @persistent
 def version_update_handler(filename):
-    print ("CCCCC")
     for node_tree in bpy.data.node_groups: # ensure it can update again after file load.
         if node_tree.bl_idname in ["MantisTree", "SchemaTree"]:
                 node_tree.is_exporting=False; node_tree.is_executing=False
     for node_tree in bpy.data.node_groups:
         if node_tree.bl_idname in ["MantisTree", "SchemaTree"]:
-            print (node_tree.mantis_version[0], node_tree.mantis_version[1], node_tree.mantis_version[2])
-            print ("DDDDD")
             if (node_tree.mantis_version[0] < MANTIS_VERSION_MAJOR) or \
                (node_tree.mantis_version[1] < MANTIS_VERSION_MINOR) or \
                (node_tree.mantis_version[2] < MANTIS_VERSION_SUB):

+ 0 - 1
base_definitions.py

@@ -313,7 +313,6 @@ class LinkNode(MantisUINode):
 class xFormNode(MantisUINode):
     @classmethod
     def register(cls):
-        print (cls.__name__, cls.mantis_node_class_name)
         cls.mantis_class = mantis_class_from_library('.xForm_nodes', cls.mantis_node_class_name)
     def init(self, context):
         super().init(context)

+ 4 - 0
link_nodes.py

@@ -810,6 +810,10 @@ class LinkArmature(MantisLinkNode):
             num_targets = len( list(self.inputs.values())[6:] )//2
 
             props_sockets = self.gen_property_socket_map()
+            # TODO: currently this will only work if the constraint bones
+            #       are all in the same armature
+            # Mantis should intelligently provide a working armature constraint
+            # even if the user supplies targets that would not work in vanilla Blender
             targets_weights = {}
             for i in range(num_targets):
                 target = c.targets.new()

+ 0 - 8
link_nodes_ui.py

@@ -254,14 +254,6 @@ class LinkArmatureNode(Node, LinkNode):
     category_color=inheritColor
     socket_templates = LinkArmatureSockets
 
-    def draw_buttons(self, context, layout):
-        # return
-        layout.operator( 'mantis.link_armature_node_add_target' )
-        if (len(self.inputs) > 6):
-            layout.operator( 'mantis.link_armature_node_remove_target' )
-        else:
-            layout.label(text="")
-
 class LinkSplineIKNode(Node, LinkNode):
     """"A node representing Spline IK"""
     bl_idname = "LinkSplineIK"

+ 2 - 0
link_socket_templates.py

@@ -380,6 +380,8 @@ LinkArmatureSockets=[
                  default_value=False, blender_property='use_bone_envelopes'),
     SockTemplate(name="Use Current Location", bl_idname='BooleanSocket', is_input=True,
                  default_value=False, blender_property='use_current_location'),
+    TargetsArray := replace(TargetTemplate, name='Targets', use_multi_input=True),
+    WeightsArray := replace(InfluenceTemplate, name='Weights', use_multi_input=True),
     InfluenceTemplate,
     EnableTemplate,
     OutputRelationshipTemplate,

+ 25 - 11
utilities.py

@@ -167,6 +167,20 @@ def get_socket_maps(node, force=False):
                     raise RuntimeError(f"ERROR: Could not get socket data for socket of type: {sock.bl_idname}")
     return maps
 
+
+def generate_intervening_reroute(socket, other_socket,):
+    from bpy.app import version as bpy_version
+    print ("i have to make a reroute node here lol")
+    node = socket.node
+    reroute = node.id_data.nodes.new('NodeReroute')
+    # NOTE that this doesn't really do a good job of placing it. Whatever.
+    l = node.id_data.links.new(input=other_socket, output=reroute.inputs[0])
+    l = node.id_data.links.new(input=reroute.outputs[0], output=socket)
+    reroute.location = node.location.lerp(other_socket.node.location, 0.25)
+    if (bpy_version >= (4,4,0)): # correct the reroute color if possible
+        reroute.socket_idname = other_socket.bl_idname
+    return l
+
 # this function is completely overloaded with different purposes and code paths
 # TODO refactor everything that funnels into this function
 # make this stuff simpler.
@@ -177,7 +191,6 @@ def do_relink(node, socket, map, in_out='INPUT', parent_name = ''):
         tree = node.node_tree
         interface_in_out=in_out
     from bpy.types import NodeSocket, Node
-    from bpy.app import version as bpy_version
     get_string = '__extend__'
     if socket: get_string = socket.identifier
     from .base_definitions import SchemaUINode
@@ -214,32 +227,33 @@ def do_relink(node, socket, map, in_out='INPUT', parent_name = ''):
                 # then move it up and delete the other link.
                 # this also needs to modify the interface of the node tree.
             if isinstance(sub_val, NodeSocket):
+                counter_id=sub_val.node.name+"::"+sub_val.identifier
                 l = None
                 if in_out =='INPUT':
-                    counter_id=sub_val.node.name+"::"+sub_val.identifier
                     if socket_counters.get(counter_id) is None:
                         socket_counters[counter_id] = 0
                     if socket_counters[counter_id] == 0:
                         l = node.id_data.links.new(input=sub_val, output=socket)
                     else:
-                        print ("i have to make a reroute node here lol")
-                        reroute = node.id_data.nodes.new('NodeReroute')
-                        # NOTE that this doesn't really do a good job of placing it. Whatever.
-                        reroute.location = node.location.lerp(sub_val.node.location, 0.25)
-                        l = node.id_data.links.new(input=sub_val, output=reroute.inputs[0])
-                        l = node.id_data.links.new(input=reroute.outputs[0], output=socket)
-                        if (bpy_version >= (4,4,0)): # correct the reroute color if possible
-                            reroute.socket_idname = socket.bl_idname
+                        l = generate_intervening_reroute(socket, sub_val)
                     socket_counters[counter_id] += 1
                 else:
                     l = node.id_data.links.new(input=socket, output=sub_val)
                 if l is None:
                     raise RuntimeError("Could not create link")
             elif isinstance(sub_val, Node):
+                counter_id=sub_val.name+"::Output"
                 l = None
                 # this happens when it is a NodeReroute
                 if not socket.is_output:
-                    l = node.id_data.links.new(input=sub_val.outputs[0], output=socket)
+                    if socket_counters.get(counter_id) is None:
+                        socket_counters[counter_id] = 0
+                    if socket_counters[counter_id] == 0:
+                        l = node.id_data.links.new(input=sub_val.outputs[0], output=socket)
+                    else:
+                        # NOTE maybe this should make another reroute from the source to here instead
+                        l = generate_intervening_reroute(socket, sub_val.outputs[0])
+                    socket_counters[counter_id] += 1
                 else:
                     l = node.id_data.links.new(input=socket, output=sub_val.inputs[0])
                 if l is None:

+ 35 - 27
versioning.py

@@ -351,41 +351,48 @@ def schema_enable_custom_interface_types(*args, **kwargs):
             if hasattr(n, "is_updating"):
                 n.is_updating = False
         tree.do_live_update = True
-            
-def update_fcurve_node_to_multi_socket(*args, **kwargs):
-    # return
+
+
+
+# since this is basically the same operation, just do it all together
+def update_fcurve_and_armature_node_to_multi_socket(*args, **kwargs):
     node = kwargs['node']
-    prRed("BEANIS")
-    print (node)
+    prRed("BEPIS")
     live_updates = node.id_data.do_live_update
     node.id_data.do_live_update = False
+    # First we have to get the socket maps and re-init the sockets
+    from .utilities import get_socket_maps, do_relink
+    sockets_in, _sockets_out = get_socket_maps(node,)
+    node.inputs.clear(); node.outputs.clear()
+    node.init_sockets(node.socket_templates)
+    convert_keys = {'UtilityFCurve' : [ 'Keyframe', ],
+                    'LinkArmature'  : [ 'Target', 'Weight', ], }
     try:
-        from .utilities import get_socket_maps, do_relink
-        sockets_in, sockets_out = get_socket_maps(node,)
         new_sockets_in = {}
-        for socket_name, links in sockets_in.items():
-            if links is None: continue
-            if 'Keyframe.' in socket_name:
-                print (socket_name, links)
-                if new_sockets_in.get('Keyframes'):
-                                                  # has to be in this order to come back alright.
-                                                  # assuming, that is, that the keys are sorted. they should be.
-                    new_sockets_in["Keyframes"] = sockets_in[socket_name] + new_sockets_in['Keyframes']
-                else:
-                    new_sockets_in["Keyframes"] = sockets_in[socket_name]
-                prWhite (new_sockets_in['Keyframes'])
-        do_relink(node, node.inputs['Keyframes'], new_sockets_in, in_out="INPUT",)
-        delete_me = []
-        for socket in node.inputs:
-            if 'Keyframe.' in socket.name:
-                delete_me.append(socket)
-        for socket in delete_me:
-            node.inputs.remove(socket)
+        print (convert_keys[node.bl_idname])
+        for convert_key in convert_keys[node.bl_idname]:
+            for socket_name, links in sockets_in.items():
+                if links is None: continue
+                if convert_key+'.' in socket_name:
+                    print (socket_name, links)
+                    if new_sockets_in.get(convert_key+'s'):
+                                                    # has to be in this order to come back alright.
+                                                    # assuming, that is, that the keys are sorted. they should be.
+                        new_sockets_in[convert_key+'s'] = sockets_in[socket_name] + new_sockets_in[convert_key+'s']
+                    else:
+                        new_sockets_in[convert_key+'s'] = sockets_in[socket_name]
+                    prWhite (new_sockets_in[convert_key+'s'])
+            do_relink(node, node.inputs[convert_key+'s'], new_sockets_in, in_out="INPUT",)
+            delete_me = []
+            for socket in node.inputs:
+                if convert_key+'.' in socket.name:
+                    delete_me.append(socket)
+            for socket in delete_me:
+                node.inputs.remove(socket)
     finally:
         node.id_data.do_live_update = live_updates
 
 
-
 versioning_tasks = [
     # node bl_idname    task                required keyword arguments
     (['ALL'], version_upgrade_very_old, ['node_tree', 'node'],),
@@ -396,7 +403,8 @@ versioning_tasks = [
     (['LinkFloor'], up_0_12_25_replace_floor_offset_type, ['node']),
     (['XFORM'], up_0_13_0_new_custom_prop_node, ['node', 'node_tree']),
     (['SchemaTree'], schema_enable_custom_interface_types, ['tree']),
-    (['UtilityFCurve'], update_fcurve_node_to_multi_socket, ['node']),
+    (['UtilityFCurve', 'LinkArmature'],
+           update_fcurve_and_armature_node_to_multi_socket, ['node']),
 ]