diff --git a/addons/material_maker/engine/gen_base.gd b/addons/material_maker/engine/gen_base.gd index 80fc16a..0433730 100644 --- a/addons/material_maker/engine/gen_base.gd +++ b/addons/material_maker/engine/gen_base.gd @@ -34,6 +34,9 @@ var position : Vector2 = Vector2(0, 0) var model = null var parameters = {} +var seed_locked : bool = false +var seed_value : int = 0 + func _ready() -> void: init_parameters() @@ -49,9 +52,28 @@ func toggle_editable() -> bool: func is_editable() -> bool: return false + func has_randomness(): return false +func get_seed() -> int: + if !seed_locked: + var s : int = ((int(position.x) * 0x1f1f1f1f) ^ int(position.y)) % 65536 + if get_parent().get("transmits_seed") != null and get_parent().transmits_seed: + s += get_parent().get_seed() + return s + else: + return seed_value + +func toggle_lock_seed(): + if !seed_locked: + seed_value = get_seed() + seed_locked = !seed_locked + return seed_locked + +func is_seed_locked(): + return seed_locked + func init_parameters() -> void: for p in get_parameter_defs(): if !parameters.has(p.name): @@ -64,6 +86,9 @@ func init_parameters() -> void: func set_position(p) -> void: position = p + if has_randomness() and !is_seed_locked(): + for i in range(get_output_defs().size()): + notify_output_change(i) func get_type() -> String: return "generic" @@ -163,6 +188,7 @@ func get_shader_code(uv : String, output_index : int, context : MMGenContext) -> func _get_shader_code(__, __, __) -> Dictionary: return {} + func _serialize(data: Dictionary) -> Dictionary: print("cannot save "+name) return data @@ -171,8 +197,35 @@ func serialize(): var rv = { name=name, type=get_type(), parameters={}, node_position={ x=position.x, y=position.y } } for p in parameters.keys(): rv.parameters[p] = MMType.serialize_value(parameters[p]) + if seed_locked: + rv.seed_value = seed_value if model != null: rv.type = model else: rv = _serialize(rv) return rv + +func _deserialize(data : Dictionary) -> void: + pass + +func deserialize(data : Dictionary) -> void: + _deserialize(data) + if data.has("name"): + name = data.name + if data.has("node_position"): + position.x = data.node_position.x + position.y = data.node_position.y + if data.has("parameters"): + for p in data.parameters.keys(): + set_parameter(p, MMType.deserialize_value(data.parameters[p])) + else: + for p in get_parameter_defs(): + if data.has(p.name) and p.name != "type": + set_parameter(p.name, MMType.deserialize_value(data[p.name])) + if data.has("seed_value"): + seed_locked = true + seed_value = data.seed_value + else: + seed_locked = false + _post_load() + diff --git a/addons/material_maker/engine/gen_comment.gd b/addons/material_maker/engine/gen_comment.gd index 9c1798c..f87390f 100644 --- a/addons/material_maker/engine/gen_comment.gd +++ b/addons/material_maker/engine/gen_comment.gd @@ -33,3 +33,9 @@ func _serialize(data: Dictionary) -> Dictionary: data.text = text data.size = { x=size.x, y=size.y } return data + +func _deserialize(data : Dictionary) -> void: + if data.has("text"): + text = data.text + if data.has("size"): + size = Vector2(data.size.x, data.size.y) diff --git a/addons/material_maker/engine/gen_convolution.gd b/addons/material_maker/engine/gen_convolution.gd index 30484c1..da12ec0 100644 --- a/addons/material_maker/engine/gen_convolution.gd +++ b/addons/material_maker/engine/gen_convolution.gd @@ -175,6 +175,10 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) - rv[convolution_params.output_type] = "%s_%d" % [ genname, variant_index ] return rv + func _serialize(data: Dictionary) -> Dictionary: data.convolution_params = convolution_params return data + +func _deserialize(data : Dictionary) -> void: + set_convolution_params(data.convolution_params) diff --git a/addons/material_maker/engine/gen_graph.gd b/addons/material_maker/engine/gen_graph.gd index 76209b7..f78e570 100644 --- a/addons/material_maker/engine/gen_graph.gd +++ b/addons/material_maker/engine/gen_graph.gd @@ -5,10 +5,13 @@ class_name MMGenGraph var label : String = "Graph" var connections = [] -var editable = false +var editable : bool = false + +var transmits_seed : bool = true signal connections_changed(removed_connections, added_connections) + func fix_remotes() -> void: for c in get_children(): if c is MMGenRemote: @@ -17,6 +20,11 @@ func fix_remotes() -> void: func _post_load() -> void: fix_remotes() + +func has_randomness(): + return transmits_seed + + func get_type() -> String: return "graph" @@ -203,13 +211,6 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) - return rv return { globals=[], defs="", code="", textures={} } -func _serialize(data: Dictionary) -> Dictionary: - data.label = label - data.nodes = [] - for c in get_children(): - data.nodes.append(c.serialize()) - data.connections = connections - return data func edit(node) -> void: node.get_parent().call_deferred("update_view", self) @@ -300,3 +301,19 @@ func create_subgraph(gens : Array) -> void: new_graph.add_child(gen_parameters) fix_remotes() new_graph.fix_remotes() + + +func _serialize(data: Dictionary) -> Dictionary: + data.label = label + data.nodes = [] + for c in get_children(): + data.nodes.append(c.serialize()) + data.connections = connections + return data + +func _deserialize(data : Dictionary) -> void: + if data.has("label"): + label = data.label + var nodes = data.nodes if data.has("nodes") else [] + var connections = data.connections if data.has("connections") else [] + load("res://addons/material_maker/engine/loader.gd").add_to_gen_graph(self, nodes, connections) diff --git a/addons/material_maker/engine/gen_ios.gd b/addons/material_maker/engine/gen_ios.gd index 2aa8d10..4f9f1e6 100644 --- a/addons/material_maker/engine/gen_ios.gd +++ b/addons/material_maker/engine/gen_ios.gd @@ -97,3 +97,6 @@ func _serialize(data: Dictionary) -> Dictionary: data.type = "ios" data.ports = ports return data + +func _deserialize(data : Dictionary) -> void: + ports = data.ports diff --git a/addons/material_maker/engine/gen_remote.gd b/addons/material_maker/engine/gen_remote.gd index c04a788..7388b0e 100644 --- a/addons/material_maker/engine/gen_remote.gd +++ b/addons/material_maker/engine/gen_remote.gd @@ -134,11 +134,6 @@ func set_parameter(p : String, v) -> void: if name == "gen_parameters": get_parent().parameters[p] = v -func _serialize(data: Dictionary) -> Dictionary: - data.type = "remote" - data.widgets = widgets - return data - func create_linked_control(label : String) -> String: var n = get_next_widget_name() widgets.push_back({ name=n, label=label, type="linked_control", linked_widgets=[] }) @@ -219,3 +214,12 @@ func remove_configuration(widget_name : String, config_name : String) -> void: if widget.type == "config_control": widget.configurations.erase(config_name) emit_signal("parameter_changed", "__update_all__", null) + + +func _serialize(data: Dictionary) -> Dictionary: + data.type = "remote" + data.widgets = widgets + return data + +func _deserialize(data : Dictionary) -> void: + set_widgets(data.widgets.duplicate(true)) diff --git a/addons/material_maker/engine/gen_shader.gd b/addons/material_maker/engine/gen_shader.gd index 7c0a77b..e041717 100644 --- a/addons/material_maker/engine/gen_shader.gd +++ b/addons/material_maker/engine/gen_shader.gd @@ -16,6 +16,9 @@ func toggle_editable() -> bool: func is_editable() -> bool: return editable +func has_randomness(): + return uses_seed + func get_type() -> String: return "shader" @@ -45,24 +48,30 @@ func get_output_defs(): func set_shader_model(data: Dictionary): shader_model = data init_parameters() + uses_seed = false if shader_model.has("outputs"): for i in range(shader_model.outputs.size()): var output = shader_model.outputs[i] + var output_code = "" if output.has("rgba"): shader_model.outputs[i].type = "rgba" + output_code = output.rgba elif output.has("rgb"): shader_model.outputs[i].type = "rgb" - else: + output_code = output.rgb + elif output.has("f"): shader_model.outputs[i].type = "f" - -func set_position(p) -> void: - .set_position(p) - if uses_seed: - source_changed(0) - -func get_seed() -> int: - var s = ((int(position.x) * 0x1f1f1f1f) ^ int(position.y)) % 65536 - return s + output_code = output.f + else: + print("Unsupported output type") + if output_code.find("$seed") != -1 or output_code.find("$(seed)") != -1: + uses_seed = true + if shader_model.has("code"): + if shader_model.code.find("$seed") != -1 or shader_model.code.find("$(seed)") != -1: + uses_seed = true + if shader_model.has("instance"): + if shader_model.instance.find("$seed") != -1 or shader_model.instance.find("$(seed)") != -1: + uses_seed = true func find_keyword_call(string, keyword): var search_string = "$%s(" % keyword @@ -156,7 +165,6 @@ func subst(string, context, uv = "") -> Dictionary: var tmp_string = replace_variable(string, "seed", str(get_seed())) if tmp_string != string: string = tmp_string - uses_seed = true if uv != "": string = replace_variable(string, "uv", "("+uv+")") if shader_model.has("parameters") and typeof(shader_model.parameters) == TYPE_ARRAY: @@ -213,7 +221,6 @@ func subst(string, context, uv = "") -> Dictionary: return { string=string, globals=required_globals, defs=required_defs, code=required_code, textures=required_textures } func _get_shader_code(uv : String, output_index : int, context : MMGenContext) -> Dictionary: - uses_seed = false var genname = "o"+str(get_instance_id()) var output_info = [ { field="rgba", type="vec4" }, { field="rgb", type="vec3" }, { field="f", type="float" } ] var rv = { globals=[], defs="", code="", textures={} } @@ -278,10 +285,18 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext) - rv.globals.push_back(shader_model.global) return rv + func _serialize(data: Dictionary) -> Dictionary: data.shader_model = shader_model return data +func _deserialize(data : Dictionary) -> void: + if data.has("shader_model"): + set_shader_model(data.shader_model) + elif data.has("model_data"): + set_shader_model(data.model_data) + + func edit(node) -> void: if shader_model != null: var edit_window = load("res://addons/material_maker/widgets/node_editor/node_editor.tscn").instance() diff --git a/addons/material_maker/engine/loader.gd b/addons/material_maker/engine/loader.gd index 1b6beeb..fdc6637 100644 --- a/addons/material_maker/engine/loader.gd +++ b/addons/material_maker/engine/loader.gd @@ -40,6 +40,7 @@ static func create_gen(data) -> MMGenBase: { keyword="connections", type=MMGenGraph }, { keyword="nodes", type=MMGenGraph }, { keyword="shader_model", type=MMGenShader }, + { keyword="convolution_params", type=MMGenConvolution }, { keyword="model_data", type=MMGenShader }, { keyword="convolution_params", type=MMGenConvolution }, { keyword="widgets", type=MMGenRemote } @@ -48,40 +49,20 @@ static func create_gen(data) -> MMGenBase: material = MMGenMaterial, buffer = MMGenBuffer, image = MMGenImage, + ios = MMGenIOs, switch = MMGenSwitch, export = MMGenExport, + comment = MMGenComment, debug = MMGenDebug } 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() - generator.set_shader_model(data.shader_model) - elif data.has("convolution_params"): - generator = MMGenConvolution.new() - generator.set_convolution_params(data.convolution_params) - elif data.has("model_data"): - generator = MMGenShader.new() - generator.set_shader_model(data.model_data) - elif data.has("widgets"): - generator = MMGenRemote.new() - generator.set_widgets(data.widgets.duplicate(true)) - elif data.has("type"): + for g in guess: + if data.has(g.keyword): + generator = g.type.new() + break + if generator == null and data.has("type"): if types.has(data.type): generator = types[data.type].new() - elif data.type == "comment": - generator = MMGenComment.new() - if data.has("text"): - generator.text = data.text - if data.has("size"): - generator.size = Vector2(data.size.x, data.size.y) - elif data.type == "ios": - generator = MMGenIOs.new() - generator.ports = data.ports else: var file = File.new() var gen_paths = [ STD_GENDEF_PATH, OS.get_executable_path().get_base_dir()+"/generators" ] @@ -101,22 +82,10 @@ static func create_gen(data) -> MMGenBase: print("Cannot find description for "+data.type) if generator != null: generator.name = data.type - else: + if generator == null: print("LOADER: data not supported:"+str(data)) if generator != null: - if data.has("name"): - generator.name = data.name - if data.has("node_position"): - generator.position.x = data.node_position.x - generator.position.y = data.node_position.y - if data.has("parameters"): - for p in data.parameters.keys(): - generator.set_parameter(p, MMType.deserialize_value(data.parameters[p])) - else: - for p in generator.get_parameter_defs(): - if data.has(p.name) and p.name != "type": - generator.set_parameter(p.name, MMType.deserialize_value(data[p.name])) - generator._post_load() + generator.deserialize(data) return generator static func get_generator_list() -> Array: diff --git a/addons/material_maker/graph_edit.gd b/addons/material_maker/graph_edit.gd index d9fcb24..94b293e 100644 --- a/addons/material_maker/graph_edit.gd +++ b/addons/material_maker/graph_edit.gd @@ -15,6 +15,7 @@ var generator = null onready var timer : Timer = $Timer onready var subgraph_ui : HBoxContainer = $GraphUI/SubGraphUI +onready var button_transmits_seed : Button = $GraphUI/SubGraphUI/ButtonTransmitsSeed signal save_path_changed signal graph_changed @@ -127,6 +128,12 @@ func update_view(g) -> void: subgraph_ui.visible = generator != top_generator subgraph_ui.get_node("Label").text = generator.label center_view() + if generator.get_parent() is MMGenGraph: + button_transmits_seed.visible = true + button_transmits_seed.pressed = generator.transmits_seed + else: + button_transmits_seed.visible = false + func clear_material() -> void: if top_generator != null: @@ -325,3 +332,8 @@ func edit_subgraph(g : MMGenGraph) -> void: if !g.is_editable(): g.toggle_editable() update_view(g) + + +func _on_ButtonTransmitsSeed_toggled(button_pressed): + if button_pressed != generator.transmits_seed: + generator.transmits_seed = button_pressed diff --git a/addons/material_maker/graph_edit.tscn b/addons/material_maker/graph_edit.tscn index 78d9dc2..60d22a5 100644 --- a/addons/material_maker/graph_edit.tscn +++ b/addons/material_maker/graph_edit.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=6 format=2] +[gd_scene load_steps=7 format=2] [ext_resource path="res://addons/material_maker/graph_edit.gd" type="Script" id=1] [ext_resource path="res://addons/material_maker/icons/icons.svg" type="Texture" id=2] @@ -9,11 +9,16 @@ bg_color = Color( 0.6, 0.6, 0.6, 0 ) [sub_resource type="AtlasTexture" id=2] flags = 4 atlas = ExtResource( 2 ) -region = Rect2( 15.4016, 47.1451, 16.7512, 17.8319 ) +region = Rect2( 64, 32, 16, 16 ) [sub_resource type="AtlasTexture" id=3] flags = 4 atlas = ExtResource( 2 ) +region = Rect2( 15.4016, 47.1451, 16.7512, 17.8319 ) + +[sub_resource type="AtlasTexture" id=4] +flags = 4 +atlas = ExtResource( 2 ) region = Rect2( 0, 48, 16, 16 ) [node name="GraphEdit" type="GraphEdit"] @@ -37,7 +42,7 @@ margin_bottom = 24.0 alignment = 2 [node name="SubGraphUI" type="HBoxContainer" parent="GraphUI"] -margin_left = 362.0 +margin_left = 330.0 margin_right = 544.0 margin_bottom = 24.0 size_flags_horizontal = 9 @@ -48,23 +53,33 @@ margin_bottom = 24.0 rect_min_size = Vector2( 150, 0 ) size_flags_horizontal = 9 -[node name="ButtonUp" type="Button" parent="GraphUI/SubGraphUI"] +[node name="ButtonTransmitsSeed" type="Button" parent="GraphUI/SubGraphUI"] margin_left = 154.0 margin_right = 182.0 margin_bottom = 24.0 +hint_tooltip = "Affect children seeds" +size_flags_horizontal = 9 +toggle_mode = true +icon = SubResource( 2 ) + +[node name="ButtonUp" type="Button" parent="GraphUI/SubGraphUI"] +margin_left = 186.0 +margin_right = 214.0 +margin_bottom = 24.0 hint_tooltip = "Back to parent" size_flags_horizontal = 9 -icon = SubResource( 2 ) +icon = SubResource( 3 ) [node name="ButtonShowTree" type="Button" parent="GraphUI"] margin_left = 548.0 margin_right = 576.0 margin_bottom = 24.0 hint_tooltip = "Show hierarchy" -icon = SubResource( 3 ) +icon = SubResource( 4 ) [connection signal="connection_request" from="." to="." method="connect_node"] [connection signal="disconnection_request" from="." to="." method="disconnect_node"] [connection signal="timeout" from="Timer" to="." method="do_send_changed_signal"] [connection signal="text_changed" from="GraphUI/SubGraphUI/Label" to="." method="_on_Label_text_changed"] +[connection signal="toggled" from="GraphUI/SubGraphUI/ButtonTransmitsSeed" to="." method="_on_ButtonTransmitsSeed_toggled"] [connection signal="pressed" from="GraphUI/SubGraphUI/ButtonUp" to="." method="on_ButtonUp_pressed"] [connection signal="pressed" from="GraphUI/ButtonShowTree" to="." method="_on_ButtonShowTree_pressed"] diff --git a/addons/material_maker/nodes/base.gd b/addons/material_maker/nodes/base.gd index f7603bc..96d33ab 100644 --- a/addons/material_maker/nodes/base.gd +++ b/addons/material_maker/nodes/base.gd @@ -3,15 +3,19 @@ extends GraphNode class_name MMGraphNodeBase var generator : MMGenBase = null setget set_generator -var fixed_seed = false func _ready() -> void: connect("offset_changed", self, "_on_offset_changed") func _draw(): - if generator.has_randomness(): - var icon = preload("res://addons/material_maker/icons/randomness_unlocked.tres") if fixed_seed else preload("res://addons/material_maker/icons/randomness_locked.tres") + if generator != null and generator.has_randomness(): + var icon = preload("res://addons/material_maker/icons/randomness_locked.tres") if generator.is_seed_locked() else preload("res://addons/material_maker/icons/randomness_unlocked.tres") draw_texture_rect(icon, Rect2(rect_size.x-48, 4, 16, 16), false) + if !is_connected("gui_input", self, "_on_gui_input"): + connect("gui_input", self, "_on_gui_input") + else: + if is_connected("gui_input", self, "_on_gui_input"): + disconnect("gui_input", self, "_on_gui_input") func set_generator(g) -> void: generator = g @@ -21,5 +25,5 @@ func _on_offset_changed() -> void: func _on_gui_input(event): if event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT and Rect2(rect_size.x-48, 4, 16, 16).has_point(event.position): - fixed_seed = !fixed_seed + generator.toggle_lock_seed() update()