Prechádzať zdrojové kódy

initial implementation for number overlay

Joseph Brandenburg 1 týždeň pred
rodič
commit
1b79536b5c
5 zmenil súbory, kde vykonal 74 pridanie a 15 odobranie
  1. 14 4
      base_definitions.py
  2. 24 5
      execution/readtree.py
  3. 2 1
      misc_nodes.py
  4. 19 2
      socket_definitions.py
  5. 15 3
      utilities/utilities.py

+ 14 - 4
base_definitions.py

@@ -1000,10 +1000,10 @@ class MantisNode:
             if socket.ui_only == True: continue # used in UI but not in generation
             if socket.is_input:
                 self.inputs[socket.name] = NodeSocket(is_input=True, name=socket.name,
-                                    node=self,)
+                                    node=self, socket_type=socket.bl_idname)
             else:
                 self.outputs[socket.name] = NodeSocket(is_input=False, name=socket.name,
-                                    node=self,)
+                                    node=self, socket_type=socket.bl_idname)
             self.parameters[socket.name] = None
         for traverse_owner, traverse_target in traverse_in.items():
             self.inputs[traverse_owner].traverse_target = self.outputs[traverse_target]
@@ -1208,8 +1208,14 @@ class MantisNode:
                                                     tuple(v[8:12]),
                                                     tuple(v[12:16]) ))
                 elif (value := node_socket.default_value) is not None:
+                    if hasattr(node_socket, 'use_overlay') and node_socket.use_overlay:
+                        value = "$"+node_socket.overlay_text
+                        # TODO: the overlay system should use a math parser for numerical types
+                        #       that treats strings as variable names
+                        # but for now I am just gonna hamfist it like this lol
                     if isinstance(value, str) and "$" in value:
-                        value = handle_overlay_detect(self, node_socket.identifier, value)
+                        value = handle_overlay_detect(self,
+                            node_socket.identifier, node_socket.bl_idname, value)
                     self.parameters[key] = value
                 else:
                     raise RuntimeError(wrapRed("No value found for " + self.__repr__() + " when filling out node parameters for " + ui_node.name + "::"+node_socket.name))
@@ -1412,10 +1418,12 @@ class NodeSocket:
         "is_input",
         "links",
         "is_linked",
+        "socket_type",
     )
     def __init__(self, is_input = False,
                  node = None, name = None,
-                 traverse_target = None):
+                 traverse_target = None,
+                 socket_type=""):
         self.can_traverse = False # to/from the other side of the parent node
         self.traverse_target = None
         self.node = node
@@ -1423,6 +1431,7 @@ class NodeSocket:
         self.is_input = is_input
         self.links = []
         self.is_linked = False
+        self.socket_type = socket_type
         if (traverse_target):
             self.can_traverse = True
 
@@ -1476,6 +1485,7 @@ class MantisNodeSocketCollection(dict):
             if socket.ui_only == True: continue # used in UI but not in generation
             if socket.is_input != self.is_input: continue
             self[socket.name] = NodeSocket(is_input=self.is_input, name=socket.name, node=self.node)
+    
     def __delitem__(self, key):
         """Deletes a node socket by name, and all its links."""
         socket = self[key]

+ 24 - 5
execution/readtree.py

@@ -160,6 +160,16 @@ overlay_valid_socket_types = [
 forbidden_key_names = ["",]
 forbidden_in_key_name = ['$',]
 def node_scan_overlays(node, socket_id,):
+    from ..misc_nodes import SimpleInputNode
+    overlay_data_type = str
+    if isinstance(node, SimpleInputNode):
+        overlay_data_type = type(node.parameters[list(node.outputs.values())[0].name])
+    else:
+        match node.inputs[socket_id].socket_type:
+            case "IntSocket" | "UnsignedIntSocket":
+                overlay_data_type = int
+            case "FloatSocket" | "FloatPositiveSocket" | "FloatFactorSocket" | "FloatAngleSocket":
+                overlay_data_type = float
     from ..utilities.node_common import GraphError
     interface_nodes = node.mContext.interface_nodes
     from ..utilities.utilities import get_ui_node
@@ -176,7 +186,10 @@ def node_scan_overlays(node, socket_id,):
         else:
             raise KeyError(f"Socket not found by ID {socket_id} in node {node.ui_signature}\n"
                         f"Candidates: {[socket.identifier for socket in ui_node.inputs]}")
+    
     value = socket.default_value # get the ACTUAL UI value
+    if hasattr(socket, 'overlay_text'): # TODO this is all wrong but for now
+        value = "$"+socket.overlay_text # I am not implementing the Parser feature
     if not isinstance(value, str): return
     # First step: get the interface nodes and the overlay keys
     # this should only check interfaces that are ancestors of this node
@@ -247,7 +260,10 @@ def node_scan_overlays(node, socket_id,):
     overlay_tries = []
     for quoted_substring in  quoted_substrings:
         overlay_tries.extend(quoted_substring.split("$"))
-    result = overlay_tries[0] # the 0th element is always before the split character
+    if overlay_data_type == str:
+        result = overlay_tries[0] # the 0th element is always before the split character
+    else: # TODO HACK later use the parser feature
+        result = 0
     # the reason for the difference between overlay_try and key is because
     #  we don't actually know if the $text part has a key in it
     for overlay_try in overlay_tries[1:]:
@@ -273,10 +289,13 @@ def node_scan_overlays(node, socket_id,):
                                               f"type {socket_type}" )
                             # NOTE that the above can also be caused by any BUG occuring in node group update
                             # because it causes the interface to be invalid for the UI node that spawns the interface node.
-                        if isinstance(overlay_value, (float, int)):
-                            overlay_value = str(overlay_value).zfill(STRING_PADDING)
-                        assert (isinstance(overlay_value, str)), f"Error: Variable {key} is not supported because it is type {type(overlay_value)}"
-                        overlay_resolved_value = overlay_try.replace(key, overlay_value)
+                        if overlay_data_type == str:
+                            if isinstance(overlay_value, (float, int)):
+                                overlay_value = str(overlay_value).zfill(STRING_PADDING)
+                            assert (isinstance(overlay_value, str)), f"Error: Variable {key} is not supported because it is type {type(overlay_value)}"
+                            overlay_resolved_value = overlay_try.replace(key, overlay_value)
+                        else:
+                            overlay_resolved_value = overlay_value
                         break
                 else: # we'll try the base tree
                     if base_tree_result := root_overlay_values.get(overlay_try):

+ 2 - 1
misc_nodes.py

@@ -373,9 +373,10 @@ class SimpleInputNode(MantisMiscNode):
         from .utilities.utilities import handle_overlay_detect
         ui_outputs = ui_node.outputs
         node_socket = ui_outputs[0] # this is a simple input node.
+        # TODO HACK this will not work for number types!!
         if (value := node_socket.default_value) is not None:
             if isinstance(value, str) and "$" in value:
-                value = handle_overlay_detect(self, node_socket.identifier, value)
+                value = handle_overlay_detect(self, node_socket.identifier, 'StringSocket', value)
             self.parameters[node_socket.name] = value
         
 #*#-------------------------------#++#-------------------------------#*#

+ 19 - 2
socket_definitions.py

@@ -46,6 +46,23 @@ class MantisSocket(parent_classes):
     def draw_color_simple(self):
         return self.color_simple    
 
+class MantisSocketOverlayEnabled(MantisSocket):
+    # this class just needs a couple properties
+    use_overlay: bpy.props.BoolProperty( default=False )
+    overlay_text: bpy.props.StringProperty( default="", )
+    def draw(self, context, layout, node, text):
+        if self.is_linked or self.node.bl_idname in text_only_output_types:
+            layout.label(text=getattr(self, "display_text", "") if self.is_linked else self.name)
+        elif hasattr(self, "default_value") and not self.is_output:
+            has_overlay = hasattr(self, "overlay_text") and hasattr(self, "use_overlay")
+            row = layout.row(align=True) if has_overlay else layout
+            # We'll show the property or the overlay field here
+            prop_field = "overlay_text" if (has_overlay and self.use_overlay) else "default_value"
+            row.prop(self, prop_field,text=self.name)
+            # and the button to choose whether or not to use the overlay field
+            if has_overlay: row.prop(self, "use_overlay", text="", icon='CONSOLE', toggle=True)
+        else:
+            layout.label(text=self.name)
 
 
 
@@ -932,7 +949,7 @@ class QuaternionSocketAA(MantisSocket):
         default = (1.0, 0.0, 0.0, 0.0,),
         update = update_socket,)
 
-class IntSocket(MantisSocket):
+class IntSocket(MantisSocketOverlayEnabled):
     '''Custom node socket type'''
     bl_idname = 'IntSocket'
     bl_label = "Integer"
@@ -942,7 +959,7 @@ class IntSocket(MantisSocket):
     input : bpy.props.BoolProperty(default =False,)
     is_valid_interface_type=True
 
-class UnsignedIntSocket(MantisSocket):
+class UnsignedIntSocket(MantisSocketOverlayEnabled):
     '''Unsigned Integer Socket'''
     bl_idname = 'UnsignedIntSocket'
     bl_label = "Unsigned Integer"

+ 15 - 3
utilities/utilities.py

@@ -964,19 +964,31 @@ def project_point_to_plane(point, origin, normal):
 # If a $ character is in a value, it is an overlay request
 # in the root tree, supply it immediately, otherwise tag this node
 # once we finish pulling data from the tree we handle the overlay.
-def handle_overlay_detect(node, socket_id, value) -> str:
+def handle_overlay_detect(node, socket_id, socket_idname, value) -> str:
     mContext = node.mContext
     root_tree = mContext.base_tree
     root_items_tree = root_tree.interface.items_tree
     # detect if it is in the root tree, if so, handle immediately
     out_value = value
+    socket_type = str
+    match socket_idname:
+        case "IntSocket" | "UnsignedIntSocket":
+            socket_type = int
+        case "FloatSocket" | "FloatPositiveSocket" | "FloatFactorSocket" | "FloatAngleSocket":
+            socket_type = float
+    
     if node.signature[0] is None and len(node.signature) ==2:
         for key, interface_item in root_items_tree.items():
             if interface_item.item_type != "SOCKET": continue
             if interface_item.in_out != "INPUT": continue
             # NOTE this will need to change if overlays extend to other data types
-            if not hasattr(interface_item, "default_string"): continue
-            out_value = out_value.replace("$"+key, interface_item.default_string)
+            if hasattr(interface_item, "default_string"):
+                out_value = socket_type(out_value.replace("$"+key, interface_item.default_string))
+            elif key == value: # TODO this is the wrong way to do this, replace this with parser later
+                if hasattr(interface_item, "default_int"):
+                    out_value = socket_type(interface_item.default_int)
+                elif hasattr(interface_item, "default_float"):
+                    out_value = socket_type(interface_item.default_float)
     else: # since it is not root, we have to tag it.
         mContext.tagged_for_overlay.append((node.signature, socket_id))
     return out_value