137 lines
4.7 KiB
Python
137 lines
4.7 KiB
Python
# 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
|