diff --git a/addons/material_maker/engine/gen_graph.gd b/addons/material_maker/engine/gen_graph.gd index 6ed6299..8fb9859 100644 --- a/addons/material_maker/engine/gen_graph.gd +++ b/addons/material_maker/engine/gen_graph.gd @@ -2,22 +2,48 @@ tool extends MMGenBase class_name MMGenGraph +var label : String = "Graph" var connections = [] func get_type(): return "graph" +func get_type_name(): + return label + +func get_parameter_defs(): + return [] + +func get_input_defs(): + var inputs = get_node("gen_inputs") + if inputs != null: + return inputs.get_input_defs() + return [] + +func get_output_defs(): + var outputs = get_node("gen_outputs") + if outputs != null: + return outputs.get_output_defs() + return [] + func get_port_source(gen_name: String, input_index: int) -> OutputPort: - for c in connections: - if c.to == gen_name and c.to_port == input_index: - var src_gen = get_node(c.from) - if src_gen != null: - return OutputPort.new(src_gen, c.from_port) + if gen_name == "gen_inputs": + var parent = get_parent() + if parent != null and parent.get_type() == "graph": + return parent.get_port_source(name, input_index) + else: + for c in connections: + if c.to == gen_name and c.to_port == input_index: + var src_gen = get_node(c.from) + if src_gen != null: + if src_gen.get_type() == "graph": + return src_gen.get_port_source("gen_outputs", c.from_port) + return OutputPort.new(src_gen, c.from_port) return null -func get_port_target(gen_name: String, input_index: int) -> InputPort: +func get_port_target(gen_name: String, output_index: int) -> InputPort: for c in connections: - if c.from == gen_name and c.from_port == input_index: + if c.from == gen_name and c.from_port == output_index: var tgt_gen = get_node(c.to) if tgt_gen != null: return InputPort.new(tgt_gen, c.to_port) @@ -65,7 +91,15 @@ func disconnect_children(from, from_port : int, to, to_port : int): connections.remove(remove) return true +func _get_shader_code(uv : String, output_index : int, context : MMGenContext): + print("Getting shader code from graph") + var outputs = get_node("gen_outputs") + if outputs != null: + outputs._get_shader_code(uv, output_index, context) + return { defs="", code="", textures={} } + func _serialize(data): + data.label = label data.nodes = [] for c in get_children(): data.nodes.append(c.serialize()) diff --git a/addons/material_maker/engine/gen_ios.gd b/addons/material_maker/engine/gen_ios.gd new file mode 100644 index 0000000..38ee958 --- /dev/null +++ b/addons/material_maker/engine/gen_ios.gd @@ -0,0 +1,50 @@ +tool +extends MMGenBase +class_name MMGenIOs + +""" +IOs just forward their inputs to their outputs and are used to specify graph interfaces +""" + +var mask : int = 3 +var ports : Array = [] + +func _ready(): + if !parameters.has("size"): + parameters.size = 4 + +func get_type(): + return "buffer" + +func get_type_name(): + match mask: + 1: return "Inputs" + 2: return "Output" + _: return "IOs" + return "Buffer" + +func get_input_defs(): + var rv : Array = [] + if mask != 2: + for p in ports: + rv.push_back({ name=p.name, type="rgba" }) + return rv + +func get_output_defs(): + var rv : Array = [] + if mask != 2: + for p in ports: + rv.push_back({ name=p.name, type="rgba" }) + return rv + +func _get_shader_code(uv : String, output_index : int, context : MMGenContext): + print("Getting shader code from ios") + if mask != 2: + var source = get_source(output_index) + if source != null: + return source.generator._get_shader_code(uv, source.output_index, context) + return { defs="", code="", textures={} } + +func _serialize(data): + data.type = "buffer" + return data diff --git a/addons/material_maker/engine/loader.gd b/addons/material_maker/engine/loader.gd index efcf467..e4b41fe 100644 --- a/addons/material_maker/engine/loader.gd +++ b/addons/material_maker/engine/loader.gd @@ -11,9 +11,11 @@ static func load_gen(filename: String) -> MMGenBase: static func add_to_gen_graph(gen_graph, generators, connections): var rv = { generators=[], connections=[] } + var gennames = {} for n in generators: var g = create_gen(n) if g != null: + var orig_name = g.name var name = g.name var index = 1 while gen_graph.has_node(name): @@ -22,15 +24,21 @@ static func add_to_gen_graph(gen_graph, generators, connections): g.name = name gen_graph.add_child(g) rv.generators.append(g) + gennames[orig_name] = name for c in connections: - gen_graph.connections.append(c) - rv.connections.append(c) + if gennames.has(c.from) and gennames.has(c.to): + c.from = gennames[c.from] + c.to = gennames[c.to] + gen_graph.connections.append(c) + rv.connections.append(c) return rv static func create_gen(data) -> MMGenBase: var generator = null if data.has("connections") and data.has("nodes"): generator = MMGenGraph.new() + if data.has("label"): + generator.label = data.label add_to_gen_graph(generator, data.nodes, data.connections) elif data.has("shader_model"): generator = MMGenShader.new() @@ -48,6 +56,9 @@ static func create_gen(data) -> MMGenBase: generator = MMGenBuffer.new() elif data.type == "image": generator = MMGenImage.new() + elif data.type == "ios": + generator = MMGenIOs.new() + generator.ports = data.ports else: var file = File.new() if file.open("res://addons/material_maker/nodes/"+data.type+".mmg", File.READ) == OK: diff --git a/addons/material_maker/graph_edit.gd b/addons/material_maker/graph_edit.gd index e8efb4a..89b2cc8 100644 --- a/addons/material_maker/graph_edit.gd +++ b/addons/material_maker/graph_edit.gd @@ -99,6 +99,7 @@ func clear_material(): send_changed_signal() func update_graph(generators, connections): + var rv = [] for g in generators: var node = node_factory.create_node(g.get_type()) if node != null: @@ -106,8 +107,10 @@ func update_graph(generators, connections): add_node(node) node.generator = g node.offset = g.position + rv.push_back(node) for c in connections: .connect_node("node_"+c.from, c.from_port, "node_"+c.to, c.to_port) + return rv func new_material(): clear_material() @@ -137,7 +140,8 @@ func create_nodes(data, position : Vector2 = Vector2(0, 0)): var new_stuff = MMGenLoader.add_to_gen_graph(generator, data.nodes, data.connections) for g in new_stuff.generators: g.position += position - update_graph(new_stuff.generators, new_stuff.connections) + return update_graph(new_stuff.generators, new_stuff.connections) + return [] func load_file(filename): clear_material() @@ -172,6 +176,7 @@ func remove_selection(): if c is GraphNode and c.selected and c.name != "Material": remove_node(c) +# Maybe move this to gen_graph... func serialize_selection(): var data = { nodes = [], connections = [] } var nodes = [] @@ -193,7 +198,10 @@ func serialize_selection(): var from = get_node(c.from) var to = get_node(c.to) if from != null and from.selected and to != null and to.selected: - data.connections.append(c) + var connection = c.duplicate(true) + connection.from = from.generator.name + connection.to = to.generator.name + data.connections.append(connection) return data func can_copy(): @@ -214,7 +222,8 @@ func paste(pos = Vector2(0, 0)): if c is GraphNode: c.selected = false var data = parse_json(OS.clipboard) - create_nodes(data, scroll_offset+0.5*rect_size) + for c in create_nodes(data, scroll_offset+0.5*rect_size): + c.selected = true # Center view diff --git a/addons/material_maker/nodes/normal_map.mmg b/addons/material_maker/nodes/normal_map.mmg new file mode 100644 index 0000000..9ddeea0 --- /dev/null +++ b/addons/material_maker/nodes/normal_map.mmg @@ -0,0 +1 @@ +{"label":"Normal Map","connections":[{"from":"nm_convolution","from_port":0,"to":"nm_postprocess","to_port":0},{"from":"nm_postprocess","from_port":0,"to":"gen_outputs","to_port":0},{"from":"gen_inputs","from_port":0,"to":"nm_convolution","to_port":0}],"nodes":[{"name":"gen_inputs","type":"ios","ports":[{"name":""}],"node_position":{"x":-89.25,"y":-73.75}},{"name":"gen_outputs","type":"ios","ports":[{"name":""}],"node_position":{"x":-89.25,"y":-73.75}},{"convolution_params":{"input_type":"f","matrix":[[[-1,-1,0],[0,-2,0],[1,-1,0]],[[-2,0,0],0,[2,0,0]],[[-1,1,0],[0,2,0],[1,1,0]]],"output_type":"rgb","x":1,"y":1},"name":"nm_convolution","node_position":{"x":-89.25,"y":-73.75},"parameters":{"size":7},"type":"shader"},{"name":"nm_postprocess","node_position":{"x":-98.25,"y":-6.75},"parameters":{"amount":0.995,"size":7},"shader_model":{"global":"","inputs":[{"default":"vec3(0.0)","label":"","name":"in","type":"rgb"}],"instance":"","name":"NormalMapPostProcess","outputs":[{"rgb":"0.5*normalize($in($uv)*$amount*$size/128.0-vec3(0.0, 0.0, 1.0))+vec3(0.5)","type":"rgb"}],"parameters":[{"default":8,"first":4,"label":"","last":11,"name":"size","type":"size"},{"default":1,"label":"","max":2,"min":0,"name":"amount","step":0.005,"type":"float"}]},"type":"shader"}]} \ No newline at end of file diff --git a/addons/material_maker/nodes/transform.mmg b/addons/material_maker/nodes/transform.mmg index 2897272..620c91d 100644 --- a/addons/material_maker/nodes/transform.mmg +++ b/addons/material_maker/nodes/transform.mmg @@ -1 +1 @@ -{"name":"transform","node_position":{"x":0,"y":0},"parameters":{"repeat":false,"rotate":0,"scale_x":1,"scale_y":1,"translate_x":0.33,"translate_y":0.095},"shader_model":{"global":"vec2 transform(vec2 uv, vec2 translate, float rotate, vec2 scale, bool repeat) {\n \tvec2 rv;\n\tuv -= vec2(0.5);\n\trv.x = cos(rotate)*uv.x + sin(rotate)*uv.y;\n\trv.y = -sin(rotate)*uv.x + cos(rotate)*uv.y;\n\trv /= scale;\n\trv += vec2(0.5);\n\trv -= translate;\n if (repeat) {\n\t\treturn fract(rv);\n\t} else {\n\t\treturn clamp(rv, vec2(0.0), vec2(1.0));\n\t}\t\n}","inputs":[{"default":"vec4($uv, 0.0, 1.0)","label":"","name":"i","type":"rgba"},{"default":"1.0","label":"","name":"tx","type":"f"},{"default":"1.0","label":"","name":"ty","type":"f"},{"default":"1.0","label":"","name":"r","type":"f"},{"default":"1.0","label":"","name":"sx","type":"f"},{"default":"1.0","label":"","name":"sy","type":"f"}],"instance":"","name":"Transform","outputs":[{"rgba":"$i(transform($uv, vec2($translate_x*(2.0*$tx($uv)-1.0), $translate_y*(2.0*$ty($uv)-1.0)), $rotate*(2.0*$r($uv)-1.0), vec2($scale_x*(2.0*$sx($uv)-1.0), $scale_y*(2.0*$sy($uv)-1.0)), $repeat))","type":"rgba"}],"parameters":[{"default":0,"label":"2:Translate X:","max":1,"min":-1,"name":"translate_x","step":0.005,"type":"float","widget":"spinbox"},{"default":0,"label":"Translate Y:","max":1,"min":-1,"name":"translate_y","step":0.005,"type":"float","widget":"spinbox"},{"default":0,"label":"Rotate:","max":720,"min":-720,"name":"rotate","step":0.005,"type":"float","widget":"spinbox"},{"default":1,"label":"Scale X:","max":50,"min":0,"name":"scale_x","step":0.005,"type":"float","widget":"spinbox"},{"default":1,"label":"Scale Y:","max":50,"min":0,"name":"scale_y","step":0.005,"type":"float","widget":"spinbox"},{"default":false,"label":"Repeat:","name":"repeat","type":"boolean"}]}} \ No newline at end of file +{"name":"transform","node_position":{"x":0,"y":0},"parameters":{"repeat":false,"rotate":120,"scale_x":1,"scale_y":1,"translate_x":0,"translate_y":0},"shader_model":{"global":"vec2 transform(vec2 uv, vec2 translate, float rotate, vec2 scale, bool repeat) {\n \tvec2 rv;\n\tuv -= vec2(0.5);\n\trv.x = cos(rotate)*uv.x + sin(rotate)*uv.y;\n\trv.y = -sin(rotate)*uv.x + cos(rotate)*uv.y;\n\trv /= scale;\n\trv += vec2(0.5);\n\trv -= translate;\n if (repeat) {\n\t\treturn fract(rv);\n\t} else {\n\t\treturn clamp(rv, vec2(0.0), vec2(1.0));\n\t}\t\n}","inputs":[{"default":"vec4($uv, 0.0, 1.0)","label":"","name":"i","type":"rgba"},{"default":"1.0","label":"","name":"tx","type":"f"},{"default":"1.0","label":"","name":"ty","type":"f"},{"default":"1.0","label":"","name":"r","type":"f"},{"default":"1.0","label":"","name":"sx","type":"f"},{"default":"1.0","label":"","name":"sy","type":"f"}],"instance":"","name":"Transform","outputs":[{"rgba":"$i(transform($uv, vec2($translate_x*(2.0*$tx($uv)-1.0), $translate_y*(2.0*$ty($uv)-1.0)), $rotate*0.01745329251*(2.0*$r($uv)-1.0), vec2($scale_x*(2.0*$sx($uv)-1.0), $scale_y*(2.0*$sy($uv)-1.0)), $repeat))","type":"rgba"}],"parameters":[{"default":0,"label":"2:Translate X:","max":1,"min":-1,"name":"translate_x","step":0.005,"type":"float","widget":"spinbox"},{"default":0,"label":"Translate Y:","max":1,"min":-1,"name":"translate_y","step":0.005,"type":"float","widget":"spinbox"},{"default":0,"label":"Rotate:","max":720,"min":-720,"name":"rotate","step":0.005,"type":"float","widget":"spinbox"},{"default":1,"label":"Scale X:","max":50,"min":0,"name":"scale_x","step":0.005,"type":"float","widget":"spinbox"},{"default":1,"label":"Scale Y:","max":50,"min":0,"name":"scale_y","step":0.005,"type":"float","widget":"spinbox"},{"default":false,"label":"Repeat:","name":"repeat","type":"boolean"}]},"type":"shader"} \ No newline at end of file