Skip to content
Snippets Groups Projects
JSONOps.py 4.72 KiB
Newer Older
  • Learn to ignore specific revisions
  • # Copyright 2015 Théo Friberg under GNU GPL 3
    
    import json
    
    def readNodes(file):
        with open(file, "r") as data_file:
            return json.load(data_file)
    
    def inflateFile(mat, fileToInflate, x=0, y=0):
    
        """
    This method sets up a material saved to a JSON file. It returns a dictionary of
    nodes with their labels as keys. The nodes are added to the specified material.
    
    _Usage_: inflateFile(<reference to material the nodes are added to>,
    <path of the file to load>, [optional <translation of the final node setup on the x axis>, <translation of the final node setup on the y axis>])
    
    The syntax of the JSON file must be as follows:
    
    1. Opening declaration (this may later be extended to create operators automatically and contain operator metadata):
    
    {
    "NodeSetup":[
    
    2. Nodes as follows
    
    {
        "label": "<label for the node>", - the node's mandatory identifier
        "type": "<the type of the node>, - the node's type (mandatory)
        "location": [<x>, <y>], - the node's mandatory location
        "in": [
                  [<node>, <output>, (mandatoy) <input>],
                                  <etc.>
              ] - (optional) Links going in to the node. Parameters:
    
                * The node whose output we take
                * Which output we take (can either be the display name, or
                  the index of the output. In the former case, must be written
                  as such: "\"<name>\"". In the later case, can be written as
                  either <index> or "<index>".)
                * (optional) The input the connection goes into. The syntax is
                  as per above. If omitted, links go into inputs in numerical
                  order from top to bottom.
    },
    
    <etc.>
    
    Note: Nodes can be accessed in more depth. For accessing the blend_mode of
    a MixRGB, for example, one would write eg. (python):
    
        <node>.blend_mode = "MULTIPLY"
    
    From JSON, this can be written as:
    
        "blend_mode": "\"MULTIPLY\""
    
    For setting default values of inputs, use the following syntaxes:
    
        "inputs[0].default_value": 1
    or
    
        "inputs[\"Color\"].default_value": [0, 1, 0, 1]
    
    3. Closing declaration as follows:
    
    ]
    }
    
    The file is read using Python's built-in JSON parser, so indentation or line breaks are optional."""
    
        # Variables for the parsed JSON array, the nodes added and all the
        # nodes in the material, respectively.
    
        nodes_JSON = readNodes(fileToInflate)
        nodes_dict = {}
        nodes = mat.node_tree.nodes
    
    
        # We iterate a first time to create the nodes with their settings
    
    
        for node in nodes_JSON["NodeSetup"]:
            technical_name = node["type"]
            location = node["location"]
            nodes_dict[node["label"]] = nodes.new(technical_name)
            nodes_dict[node["label"]].location = (node["location"][0]+x,
                                                  node["location"][1]+y)
            nodes_dict[node["label"]].name = node["label"]
            nodes_dict[node["label"]].label = node["label"]
    
            # The nodes' parameters can be generic, runnable Python.
            # This requires us to actually execute part of the files.
    
            for attribute in node.keys():
                if attribute not in ("in", "label", "type", "location"):
                    exec("nodes_dict[node[\"label\"]]."+ attribute + " = " +
                         str(node[attribute]))
    
        # We create the links between the nodes
        # The syntax in the json is the following
        # "in": [
    # ["<what node is plugged in>", <which of the nodes outputs is used, can be
    # either string, as in "\"Color\"" or number, eg. 0 for the first output.>,
    # <what input is this plugged to. Can be omitted for sequentially filling all
    # inputs. If this has a value, it works like the previous value.>],
    # <next inputs etc.>
    #               ]
    
        links = mat.node_tree.links
    
        for node in nodes_JSON["NodeSetup"]:
            if "in" in node.keys(): # Does the node have links?
                i = 0
                while i < len(node["in"]): # We iterate over the links
    
                    # Is a specific input specified?
    
                    if len(node["in"][i]) == 3:
    
                        # Contruct and execute the line adding a link
    
                        exec ("links.new(nodes_dict[\"" + node["in"][i][0] +
                              "\"].outputs[" + str(node["in"][i][1]) +
                              "], nodes_dict[\"" + node["label"] + "\"].inputs["
                              + str(node["in"][i][2]) + "])")
                    else:
    
                        # We don't have a specific input to hook up to
    
                        exec ("links.new(nodes_dict[\"" + node["in"][i][0] +
                              "\"].outputs[" + str(node["in"][i][1]) +
                              "], nodes_dict[\"" + node["label"] + "\"].inputs["
                               + str(i) + "])")
                    i += 1
    
        # We return the nodes for purposes of further access to them
    
    
        return nodes_dict