diff --git a/addons/material_maker/engine/gen_base.gd b/addons/material_maker/engine/gen_base.gd index 7d0db5e..748b93f 100644 --- a/addons/material_maker/engine/gen_base.gd +++ b/addons/material_maker/engine/gen_base.gd @@ -6,6 +6,8 @@ class_name MMGenBase Base class for texture generators, that defines their API """ +signal parameter_changed + class InputPort: var generator : MMGenBase = null var input_index : int = 0 @@ -58,12 +60,16 @@ func get_parameter_defs(): func set_parameter(n : String, v): parameters[n] = v source_changed(0) + emit_signal("parameter_changed", n, v) + +func notify_output_change(output_index : int): + var targets = get_targets(output_index) + for target in targets: + target.generator.source_changed(target.input_index) func source_changed(input_index : int): for i in range(get_output_defs().size()): - var target = get_target(i) - if target != null: - target.generator.source_changed(target.input_index) + notify_output_change(i) func get_input_defs(): return [] @@ -74,8 +80,8 @@ func get_output_defs(): func get_source(input_index : int): return get_parent().get_port_source(name, input_index) -func get_target(output_index : int): - return get_parent().get_port_target(name, output_index) +func get_targets(output_index : int): + return get_parent().get_port_targets(name, output_index) func get_input_shader(input_index : int): var source = get_source(input_index) diff --git a/addons/material_maker/engine/gen_buffer.gd b/addons/material_maker/engine/gen_buffer.gd index d19e207..9b677c5 100644 --- a/addons/material_maker/engine/gen_buffer.gd +++ b/addons/material_maker/engine/gen_buffer.gd @@ -28,8 +28,9 @@ func get_input_defs(): func get_output_defs(): return [ { type="rgba" } ] -func source_changed(input_port_index): +func source_changed(input_port_index : int): updated = false + .source_changed(input_port_index) func _get_shader_code(uv : String, output_index : int, context : MMGenContext): var source = get_source(0) diff --git a/addons/material_maker/engine/gen_graph.gd b/addons/material_maker/engine/gen_graph.gd index e036c5f..ad0b7ba 100644 --- a/addons/material_maker/engine/gen_graph.gd +++ b/addons/material_maker/engine/gen_graph.gd @@ -26,6 +26,11 @@ func get_output_defs(): return outputs.get_output_defs() return [] +func source_changed(input_index : int): + var generator = get_node("gen_inputs") + if generator != null: + generator.source_changed(input_index) + func get_port_source(gen_name: String, input_index: int) -> OutputPort: if gen_name == "gen_inputs": var parent = get_parent() @@ -41,13 +46,14 @@ func get_port_source(gen_name: String, input_index: int) -> OutputPort: return OutputPort.new(src_gen, c.from_port) return null -func get_port_target(gen_name: String, output_index: int) -> InputPort: +func get_port_targets(gen_name: String, output_index: int) -> InputPort: + var rv = [] for c in connections: 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) - return null + rv.push_back(InputPort.new(tgt_gen, c.to_port)) + return rv func remove_generator(generator : MMGenBase): var new_connections = [] @@ -95,7 +101,11 @@ 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) + print("found!") + var rv = outputs._get_shader_code(uv, output_index, context) + while rv is GDScriptFunctionState: + rv = yield(rv, "completed") + return rv return { defs="", code="", textures={} } func _serialize(data): diff --git a/addons/material_maker/engine/gen_ios.gd b/addons/material_maker/engine/gen_ios.gd index 75f8c2f..99ae0b3 100644 --- a/addons/material_maker/engine/gen_ios.gd +++ b/addons/material_maker/engine/gen_ios.gd @@ -37,13 +37,24 @@ func get_output_defs(): rv.push_back({ name=p.name, type="rgba" }) return rv +func source_changed(input_index : int): + if name == "gen_outputs": + get_parent().notify_output_change(input_index) + else: + notify_output_change(input_index) + func _get_shader_code(uv : String, output_index : int, context : MMGenContext): if mask != 2: var source = get_source(output_index) if source != null: - return source.generator._get_shader_code(uv, source.output_index, context) + var rv = source.generator._get_shader_code(uv, source.output_index, context) + while rv is GDScriptFunctionState: + rv = yield(rv, "completed") + return rv return { defs="", code="", textures={} } func _serialize(data): - data.type = "buffer" + data.type = "ios" + data.mask = mask + data.ports = ports return data diff --git a/addons/material_maker/engine/gen_remote.gd b/addons/material_maker/engine/gen_remote.gd index bbb2a26..e0d5976 100644 --- a/addons/material_maker/engine/gen_remote.gd +++ b/addons/material_maker/engine/gen_remote.gd @@ -10,13 +10,60 @@ var widgets = null func set_widgets(w): widgets = w + var i = 0 + for w in widgets: + var param_name = "param"+str(i) + if !parameters.has(param_name): + parameters["param"+str(i)] = 0 + i += 1 func get_type(): - return "remote" + return "remot" func get_type_name(): return "Remote" +func get_parameter_defs(): + var rv = [] + var i = 0 + for w in widgets: + match w.type: + "config_control": + var p = { name="param"+str(i), label=w.label, type="enum", values=[] } + for c in w.configurations: + p.values.push_back({ name=c, value=c }) + rv.append(p) + i += 1 + "linked_control": + var linked = w.linked_widgets[0] + var gen = get_parent().get_node(linked.node) + if gen != null: + var gen_params = gen.get_parameter_defs() + for pd in gen_params: + if pd.name == linked.widget: + var p = pd.duplicate(true) + p.name = "param"+str(i) + p.label = w.label + rv.append(p) + break + i += 1 + _: + print(w.type) + return rv + +func set_parameter(p, v): + .set_parameter(p, v) + var parent = get_parent() + var param_index = p.trim_prefix("param").to_int() + var widget = widgets[param_index] + match widget.type: + "linked_control": + for w in widget.linked_widgets: + parent.get_node(w.node).set_parameter(w.widget, v) + "config_control": + for w in widget.configurations[widget.configurations.keys()[v]]: + parent.get_node(w.node).set_parameter(w.widget, w.value) + func _serialize(data): data.type = "remote" data.widgets = widgets diff --git a/addons/material_maker/engine/gen_switch.gd b/addons/material_maker/engine/gen_switch.gd index d67bddb..f8f72a8 100644 --- a/addons/material_maker/engine/gen_switch.gd +++ b/addons/material_maker/engine/gen_switch.gd @@ -15,8 +15,29 @@ func get_type_name(): func get_parameter_defs(): return [ { name="outputs", label="Outputs", type="float", min=1, max=5, step=1, default=2 }, { name="choices", label="Choices", type="float", min=2, max=5, step=1, default=2 }, - { name="source", label="Source", type="float", min=1, max=2, step=1 } ] + { name="source", label="Source", type="float", min=0, max=1, step=1, default=0 } ] -func set_parameter(n : String, v): - .set_parameter(n, v) - # Force redraw if outputs or choices is modified \ No newline at end of file +func get_input_defs(): + var rv : Array = [] + for c in range(parameters.choices): + for o in range(parameters.outputs): + rv.push_back({ name=PoolByteArray([64+o]).get_string_from_ascii()+str(c), type="rgba" }) + return rv + +func get_output_defs(): + var rv : Array = [] + for o in range(parameters.outputs): + rv.push_back({ name=PoolByteArray([64+o]).get_string_from_ascii(), type="rgba" }) + return rv + +func source_changed(input_index : int): + notify_output_change(input_index % parameters.outputs) + +func _get_shader_code(uv : String, output_index : int, context : MMGenContext): + var source = get_source(output_index+parameters.source*parameters.outputs) + if source != null: + var rv = source.generator._get_shader_code(uv, source.output_index, context) + while rv is GDScriptFunctionState: + rv = yield(rv, "completed") + return rv + return { defs="", code="", textures={} } diff --git a/addons/material_maker/engine/loader.gd b/addons/material_maker/engine/loader.gd index d223e02..d5aa8f2 100644 --- a/addons/material_maker/engine/loader.gd +++ b/addons/material_maker/engine/loader.gd @@ -61,7 +61,11 @@ static func create_gen(data) -> MMGenBase: generator = MMGenImage.new() elif data.type == "ios": generator = MMGenIOs.new() + if data.has("mask"): + generator.mask = data.mask generator.ports = data.ports + elif data.type == "switch": + generator = MMGenSwitch.new() 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/main_window.tscn b/addons/material_maker/main_window.tscn index ac61f02..fb86ec5 100644 --- a/addons/material_maker/main_window.tscn +++ b/addons/material_maker/main_window.tscn @@ -102,6 +102,10 @@ script = ExtResource( 6 ) [connection signal="no_more_tabs" from="VBoxContainer/HBoxContainer/Projects" to="." method="new_material"] [connection signal="resized" from="VBoxContainer/HBoxContainer/Projects" to="VBoxContainer/HBoxContainer/Projects" method="_on_Projects_resized"] [connection signal="tab_changed" from="VBoxContainer/HBoxContainer/Projects" to="." method="_on_Projects_tab_changed"] +[connection signal="connection_request" from="VBoxContainer/HBoxContainer/Projects/GraphEdit" to="VBoxContainer/HBoxContainer/Projects/GraphEdit" method="connect_node"] +[connection signal="disconnection_request" from="VBoxContainer/HBoxContainer/Projects/GraphEdit" to="VBoxContainer/HBoxContainer/Projects/GraphEdit" method="disconnect_node"] +[connection signal="close_request" from="VBoxContainer/HBoxContainer/Projects/GraphEdit/node_Material" to="VBoxContainer/HBoxContainer/Projects/GraphEdit/node_Material" method="on_close_request"] +[connection signal="offset_changed" from="VBoxContainer/HBoxContainer/Projects/GraphEdit/node_Material" to="VBoxContainer/HBoxContainer/Projects/GraphEdit/node_Material" method="on_offset_changed"] [connection signal="reposition_active_tab_request" from="VBoxContainer/HBoxContainer/Projects/Tabs" to="VBoxContainer/HBoxContainer/Projects" method="move_active_tab_to"] [connection signal="tab_changed" from="VBoxContainer/HBoxContainer/Projects/Tabs" to="VBoxContainer/HBoxContainer/Projects" method="set_current_tab"] [connection signal="tab_close" from="VBoxContainer/HBoxContainer/Projects/Tabs" to="VBoxContainer/HBoxContainer/Projects" method="close_tab"] diff --git a/addons/material_maker/nodes/generic.gd b/addons/material_maker/nodes/generic.gd index 5ce03ae..cd8883b 100644 --- a/addons/material_maker/nodes/generic.gd +++ b/addons/material_maker/nodes/generic.gd @@ -3,10 +3,11 @@ extends GraphNode var generator = null setget set_generator -var controls = [] +var controls = {} func set_generator(g): generator = g + generator.connect("parameter_changed", self, "on_parameter_changed") update_node() func on_close_request(): @@ -15,35 +16,49 @@ func on_close_request(): func on_offset_changed(): generator.position = offset +func on_parameter_changed(p, v): + var o = controls[p] + if o is LineEdit: + o.text = str(v) + elif o is SpinBox: + o.value = v + elif o is HSlider: + o.value = v + elif o is OptionButton: + o.selected = v + elif o is CheckBox: + o.pressed = v + elif o is ColorPickerButton: + o.color = MMType.deserialize_value(v) + elif o is Control and o.filename == "res://addons/material_maker/widgets/gradient_editor.tscn": + var gradient : MMGradient = MMGradient.new() + gradient.deserialize(v) + o.value = gradient + else: + print("unsupported widget "+str(o)) + func initialize_properties(): - for o in controls: - if o == null: - print("error in node "+name) - continue - if !generator.parameters.has(o.name): + var parameter_names = [] + for p in generator.get_parameter_defs(): + parameter_names.push_back(p.name) + for c in controls: + if parameter_names.find(c) == -1: continue + var o = controls[c] + on_parameter_changed(c, generator.parameters[c]) if o is LineEdit: - o.text = str(generator.parameters[o.name]) o.connect("text_changed", self, "_on_text_changed", [ o.name ]) elif o is SpinBox: - o.value = generator.parameters[o.name] o.connect("value_changed", self, "_on_value_changed", [ o.name ]) elif o is HSlider: - o.value = generator.parameters[o.name] o.connect("value_changed", self, "_on_value_changed", [ o.name ]) elif o is OptionButton: - o.selected = generator.parameters[o.name] o.connect("item_selected", self, "_on_value_changed", [ o.name ]) elif o is CheckBox: - o.pressed = generator.parameters[o.name] o.connect("toggled", self, "_on_value_changed", [ o.name ]) elif o is ColorPickerButton: - o.color = MMType.deserialize_value(generator.parameters[o.name]) o.connect("color_changed", self, "_on_color_changed", [ o.name ]) elif o is Control and o.filename == "res://addons/material_maker/widgets/gradient_editor.tscn": - var gradient : MMGradient = MMGradient.new() - gradient.deserialize(generator.parameters[o.name]) - o.value = gradient o.connect("updated", self, "_on_gradient_changed", [ o.name ]) else: print("unsupported widget "+str(o)) @@ -111,7 +126,7 @@ func update_node(): for c in get_children(): c.get_child(0).rect_min_size.x = input_names_width # Parameters - controls = [] + controls = {} var index = -1 var regex = RegEx.new() regex.compile("^(\\d+):(.*)") @@ -153,7 +168,7 @@ func update_node(): if control != null: var label = p.name control.name = label - controls.append(control) + controls[control.name] = control if p.has("label"): label = p.label var result = regex.search(label) diff --git a/addons/material_maker/nodes/normal_map.mmg b/addons/material_maker/nodes/normal_map.mmg index 9ddeea0..2d37a31 100644 --- a/addons/material_maker/nodes/normal_map.mmg +++ b/addons/material_maker/nodes/normal_map.mmg @@ -1 +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 +{"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":"buffer","to_port":0},{"from":"buffer","from_port":0,"to":"nm_convolution","to_port":0}],"label":"Normal Map","name":"normal_map","node_position":{"x":0,"y":0},"nodes":[{"name":"gen_inputs","node_position":{"x":-259.25,"y":-144.75},"type":"ios","ports":[{"name":"in","type":"rgba"}]},{"name":"gen_outputs","node_position":{"x":145.75,"y":-3.75},"type":"ios","ports":[{"name":"in","type":"rgba"}]},{"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":-76.75},"parameters":{"size":5},"type":"shader"},{"name":"nm_postprocess","node_position":{"x":-98.25,"y":-6.75},"parameters":{"amount":0.995,"size":5},"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"},{"name":"buffer","node_position":{"x":-89.663818,"y":-147.39386},"parameters":{"size":5},"type":"buffer"}],"parameters":{"amount":0.35,"size":4},"type":"graph"} \ No newline at end of file diff --git a/addons/material_maker/widgets/linked_widgets/config_control.gd b/addons/material_maker/widgets/linked_widgets/config_control.gd index a437f02..5672a38 100644 --- a/addons/material_maker/widgets/linked_widgets/config_control.gd +++ b/addons/material_maker/widgets/linked_widgets/config_control.gd @@ -52,7 +52,7 @@ func apply_configuration(c): for w in configurations[c]: var value = duplicate_value(w.value) w.widget.set(WIDGETS[get_widget_type(w.widget)].value_attr, value) - w.node.parameters[w.widget.name] = value + w.node.generator.set_parameter(w.widget.name, value) var graph_node = get_parent() while !(graph_node is GraphNode): graph_node = graph_node.get_parent()