From c8414f47dfb6465142084e25d9f9a8955ab6312f Mon Sep 17 00:00:00 2001 From: Rodolphe Suescun Date: Sun, 20 Oct 2019 00:59:51 +0200 Subject: [PATCH] Updated switch node and refactored generator edit feature. --- addons/material_maker/engine/gen_base.gd | 6 + addons/material_maker/engine/gen_graph.gd | 14 + addons/material_maker/engine/gen_shader.gd | 11 + addons/material_maker/engine/gen_switch.gd | 24 +- addons/material_maker/main_window.gd | 6 +- addons/material_maker/main_window.tscn | 2 +- addons/material_maker/nodes/custom.gd | 53 ---- addons/material_maker/nodes/custom.tscn | 65 ----- addons/material_maker/nodes/generic.gd | 57 ++-- addons/material_maker/nodes/image.gd | 2 +- addons/material_maker/nodes/node_generic.gd | 281 -------------------- addons/material_maker/nodes/switch.gd | 87 ++++++ addons/material_maker/nodes/switch.tscn | 129 +++++++++ project.godot | 1 - 14 files changed, 308 insertions(+), 430 deletions(-) delete mode 100644 addons/material_maker/nodes/custom.gd delete mode 100644 addons/material_maker/nodes/custom.tscn delete mode 100644 addons/material_maker/nodes/node_generic.gd create mode 100644 addons/material_maker/nodes/switch.gd create mode 100644 addons/material_maker/nodes/switch.tscn diff --git a/addons/material_maker/engine/gen_base.gd b/addons/material_maker/engine/gen_base.gd index c295ce2..821111b 100644 --- a/addons/material_maker/engine/gen_base.gd +++ b/addons/material_maker/engine/gen_base.gd @@ -40,6 +40,12 @@ func _ready(): func can_be_deleted() -> bool: return true +func toggle_editable(): + return false + +func is_editable(): + return false + func init_parameters(): for p in get_parameter_defs(): if !parameters.has(p.name): diff --git a/addons/material_maker/engine/gen_graph.gd b/addons/material_maker/engine/gen_graph.gd index 0fe89e8..e20d5b3 100644 --- a/addons/material_maker/engine/gen_graph.gd +++ b/addons/material_maker/engine/gen_graph.gd @@ -5,12 +5,26 @@ class_name MMGenGraph var label : String = "Graph" var connections = [] +var editable = false + + func get_type(): return "graph" func get_type_name(): return label + +func toggle_editable(): + editable = !editable + if editable: + model = null + return true + +func is_editable(): + return editable + + func get_parameter_defs(): if has_node("gen_parameters"): return get_node("gen_parameters").get_parameter_defs() diff --git a/addons/material_maker/engine/gen_shader.gd b/addons/material_maker/engine/gen_shader.gd index eada566..c81ef03 100644 --- a/addons/material_maker/engine/gen_shader.gd +++ b/addons/material_maker/engine/gen_shader.gd @@ -5,6 +5,17 @@ class_name MMGenShader var shader_model : Dictionary = {} var uses_seed = false +var editable = false + +func toggle_editable(): + editable = !editable + if editable: + model = null + return true + +func is_editable(): + return editable + func get_type(): return "shader" diff --git a/addons/material_maker/engine/gen_switch.gd b/addons/material_maker/engine/gen_switch.gd index 4101340..b1e16f7 100644 --- a/addons/material_maker/engine/gen_switch.gd +++ b/addons/material_maker/engine/gen_switch.gd @@ -6,32 +6,48 @@ class_name MMGenSwitch Texture generator switch """ +var editable = false + func get_type(): return "switch" func get_type_name(): return "Switch" +func toggle_editable(): + editable = !editable + return true + +func is_editable(): + return editable + func get_parameter_defs(): + var choices = parameters.choices if parameters.has("choices") else 2 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=0, max=1, step=1, default=0 }, + { name="source", label="Source", type="float", min=0, max=choices-1, step=1, default=0 }, ] 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" }) + var n = PoolByteArray([65+o]).get_string_from_ascii()+str(c) + rv.push_back({ name=n, label=n, 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" }) + var n = PoolByteArray([65+o]).get_string_from_ascii() + rv.push_back({ name=n, type="rgba" }) return rv +func set_parameter(p, v): + .set_parameter(p, v) + emit_signal("parameter_changed", "__update_all__", null) + func source_changed(input_index : int): notify_output_change(input_index % int(parameters.outputs)) @@ -42,7 +58,7 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext): while rv is GDScriptFunctionState: rv = yield(rv, "completed") return rv - return { defs="", code="", textures={} } + return { globals=[], defs="", code="", textures={} } func _serialize(data): return data diff --git a/addons/material_maker/main_window.gd b/addons/material_maker/main_window.gd index c84b2e8..125cfdf 100644 --- a/addons/material_maker/main_window.gd +++ b/addons/material_maker/main_window.gd @@ -30,7 +30,7 @@ const MENU = [ { menu="View", command="view_reset_zoom", shortcut="Control+0", description="Reset zoom" }, { menu="Tools", submenu="create", description="Create" }, { menu="Tools", command="create_subgraph", shortcut="Control+G", description="Create group" }, - { menu="Tools", command="make_selected_nodes_editable", shortcut="Control+F", description="Make selected nodes editable" }, + { menu="Tools", command="make_selected_nodes_editable", shortcut="Control+E", description="Make selected nodes editable" }, { menu="Tools" }, { menu="Tools", command="add_to_user_library", description="Add selected node to user library" }, { menu="Tools", command="save_user_library", description="Save user library" }, @@ -308,8 +308,8 @@ func make_selected_nodes_editable(): var selected_nodes = get_selected_nodes() if !selected_nodes.empty(): for n in selected_nodes: - n.generator.model = null - n.update_node() + if n.generator.toggle_editable(): + n.update_node() func add_to_user_library(): var selected_nodes = get_selected_nodes() diff --git a/addons/material_maker/main_window.tscn b/addons/material_maker/main_window.tscn index 84d6414..5541263 100644 --- a/addons/material_maker/main_window.tscn +++ b/addons/material_maker/main_window.tscn @@ -62,7 +62,7 @@ margin_left = 125.0 margin_right = 171.0 margin_bottom = 20.0 text = "Tools" -items = [ "Create", null, 0, false, false, -1, 0, null, "PopupMenu", false, "Create group", null, 0, false, false, 18, 268435527, null, "", false, "Make selected nodes editable", null, 0, false, false, 19, 268435526, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Add selected node to user library", null, 0, false, false, 21, 0, null, "", false, "Save user library", null, 0, false, false, 22, 0, null, "", false ] +items = [ "Create", null, 0, false, false, -1, 0, null, "PopupMenu", false, "Create group", null, 0, false, false, 18, 268435527, null, "", false, "Make selected nodes editable", null, 0, false, false, 19, 268435525, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Add selected node to user library", null, 0, false, false, 21, 0, null, "", false, "Save user library", null, 0, false, false, 22, 0, null, "", false ] [node name="Help" type="MenuButton" parent="VBoxContainer/Menu"] margin_left = 175.0 diff --git a/addons/material_maker/nodes/custom.gd b/addons/material_maker/nodes/custom.gd deleted file mode 100644 index 8879d2b..0000000 --- a/addons/material_maker/nodes/custom.gd +++ /dev/null @@ -1,53 +0,0 @@ -tool -extends "res://addons/material_maker/nodes/node_generic.gd" - -func _on_Edit_pressed(): - var edit_window = load("res://addons/material_maker/widgets/node_editor/node_editor.tscn").instance() - get_parent().add_child(edit_window) - if model_data != null: - edit_window.set_model_data(model_data) - edit_window.connect("node_changed", self, "update_node") - edit_window.popup_centered() - -func _on_Load_pressed(): - var dialog = FileDialog.new() - add_child(dialog) - dialog.rect_min_size = Vector2(500, 500) - dialog.access = FileDialog.ACCESS_FILESYSTEM - dialog.mode = FileDialog.MODE_OPEN_FILE - dialog.add_filter("*.mmn;Material Maker Node") - dialog.connect("file_selected", self, "do_load_node") - dialog.popup_centered() - -func do_load_node(file_name): - set_model(file_name) - -func _on_Save_pressed(): - var dialog = FileDialog.new() - add_child(dialog) - dialog.rect_min_size = Vector2(500, 500) - dialog.access = FileDialog.ACCESS_FILESYSTEM - dialog.mode = FileDialog.MODE_SAVE_FILE - dialog.add_filter("*.mmn;Material Maker Node") - dialog.connect("file_selected", self, "do_save_node") - dialog.popup_centered() - -func do_save_node(file_name): - var file = File.new() - if file.open(file_name, File.WRITE) == OK: - file.store_string(to_json(model_data)) - file.close() - model = file_name - -func deserialize(data): - if data.has("model_data"): - update_node(data.model_data) - .deserialize(data) - -func serialize(): - var file = model - model = "custom" - var return_value = .serialize() - model = file - return_value.model_data = model_data - return return_value diff --git a/addons/material_maker/nodes/custom.tscn b/addons/material_maker/nodes/custom.tscn deleted file mode 100644 index bc8e85d..0000000 --- a/addons/material_maker/nodes/custom.tscn +++ /dev/null @@ -1,65 +0,0 @@ -[gd_scene load_steps=6 format=2] - -[ext_resource path="res://addons/material_maker/nodes/custom.gd" type="Script" id=1] -[ext_resource path="res://addons/material_maker/icons/icons.svg" type="Texture" id=2] - -[sub_resource type="AtlasTexture" id=1] -flags = 4 -atlas = ExtResource( 2 ) -region = Rect2( 16, 16, 15, 17 ) - -[sub_resource type="AtlasTexture" id=2] -flags = 4 -atlas = ExtResource( 2 ) -region = Rect2( 48, 16, 16, 16 ) - -[sub_resource type="AtlasTexture" id=3] -flags = 4 -atlas = ExtResource( 2 ) -region = Rect2( 32, 16, 16, 16 ) - -[node name="Custom" type="GraphNode"] -margin_left = 1.0 -margin_top = 2.0 -margin_right = 95.0 -margin_bottom = 53.0 -mouse_filter = 1 -title = "Custom" -show_close = true -slot/0/left_enabled = false -slot/0/left_type = 0 -slot/0/left_color = Color( 1, 1, 1, 1 ) -slot/0/right_enabled = false -slot/0/right_type = 0 -slot/0/right_color = Color( 1, 1, 1, 1 ) -script = ExtResource( 1 ) -model = null - -[node name="CustomNodeButtons" type="HBoxContainer" parent="."] -margin_left = 16.0 -margin_top = 24.0 -margin_right = 92.0 -margin_bottom = 47.0 - -[node name="Edit" type="Button" parent="CustomNodeButtons"] -margin_right = 27.0 -margin_bottom = 23.0 -icon = SubResource( 1 ) -flat = true - -[node name="Load" type="Button" parent="CustomNodeButtons"] -margin_left = 31.0 -margin_right = 59.0 -margin_bottom = 23.0 -icon = SubResource( 2 ) -flat = true - -[node name="Save" type="Button" parent="CustomNodeButtons"] -margin_left = 63.0 -margin_right = 76.0 -margin_bottom = 23.0 -icon = SubResource( 3 ) -flat = true -[connection signal="pressed" from="CustomNodeButtons/Edit" to="." method="_on_Edit_pressed"] -[connection signal="pressed" from="CustomNodeButtons/Load" to="." method="_on_Load_pressed"] -[connection signal="pressed" from="CustomNodeButtons/Save" to="." method="_on_Save_pressed"] diff --git a/addons/material_maker/nodes/generic.gd b/addons/material_maker/nodes/generic.gd index 01321c1..c633c25 100644 --- a/addons/material_maker/nodes/generic.gd +++ b/addons/material_maker/nodes/generic.gd @@ -28,7 +28,9 @@ func on_offset_changed(): func on_parameter_changed(p, v): if ignore_parameter_change == p: return - if controls.has(p): + if p == "__update_all__": + call_deferred("update_node") + elif controls.has(p): var o = controls[p] if o is LineEdit: o.text = str(v) @@ -140,14 +142,33 @@ func create_parameter_control(p : Dictionary): control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance() return control -func update_node(): - # Clean node - var custom_node_buttons = null +func save_preview_widget(): if preview != null: remove_child(preview) if preview_timer != null: preview_timer.stop() remove_child(preview_timer) + +func restore_preview_widget(): + if preview == null: + preview = TextureRect.new() + preview.visible = false + preview_position = get_child_count() + if preview.visible: + add_child(preview) + update_preview() + set_slot(preview_position, false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0)) + # Preview timer + if preview_timer == null: + preview_timer = Timer.new() + preview_timer.one_shot = true + preview_timer.connect("timeout", self, "do_update_preview") + add_child(preview_timer) + +func update_node(): + # Clean node + var custom_node_buttons = null + save_preview_widget() for c in get_children(): remove_child(c) c.free() @@ -275,23 +296,14 @@ func update_node(): var empty_control : Control = Control.new() empty_control.rect_min_size.x = button_width hsizer.add_child(empty_control) - # Preview - if preview == null: - preview = TextureRect.new() - preview.visible = false - preview_position = get_child_count() # Edit buttons - if generator.model == null: + if generator.is_editable(): var edit_buttons = preload("res://addons/material_maker/nodes/edit_buttons.tscn").instance() add_child(edit_buttons) edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator") - # Preview timer - if preview_timer == null: - preview_timer = Timer.new() - preview_timer.one_shot = true - preview_timer.connect("timeout", self, "do_update_preview") - add_child(preview_timer) - + set_slot(edit_buttons.get_index(), false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0)) + # Preview + restore_preview_widget() func edit_generator(): if generator.has_method("edit"): @@ -350,15 +362,18 @@ func do_save_generator(file_name : String): file.store_string(to_json(data)) file.close() +func update_preview_buttons(index : int): + for i in range(output_count): + if i != index: + var line = get_child(i) + line.get_child(line.get_child_count()-1).pressed = false + func on_preview_button(pressed : bool, index : int): if pressed: preview_index = index var width if preview.visible: - for i in range(output_count): - if i != index: - var line = get_child(i) - line.get_child(line.get_child_count()-1).pressed = false + update_preview_buttons(index) update_preview() else: var status = update_preview(get_child(0).rect_size.x) diff --git a/addons/material_maker/nodes/image.gd b/addons/material_maker/nodes/image.gd index 45d1313..202f04e 100644 --- a/addons/material_maker/nodes/image.gd +++ b/addons/material_maker/nodes/image.gd @@ -1,5 +1,5 @@ tool -extends "res://addons/material_maker/node_base.gd" +extends GraphNode var generator = null diff --git a/addons/material_maker/nodes/node_generic.gd b/addons/material_maker/nodes/node_generic.gd deleted file mode 100644 index 4af631b..0000000 --- a/addons/material_maker/nodes/node_generic.gd +++ /dev/null @@ -1,281 +0,0 @@ -tool -extends "res://addons/material_maker/node_base.gd" - -export(String) var model = null setget set_model -var model_data = null -var uses_seed = false - -func _ready(): - show_close = true - connect("offset_changed", self, "_on_offset_changed") - -func set_model(m): - if m != null and typeof(m) == TYPE_STRING: - var file = File.new() - var file_name = m - if !file.file_exists(file_name): - file_name = "res://addons/material_maker/nodes/%s.mmn" % [ m ] - if file.file_exists(file_name): - if file.open(file_name, File.READ) != OK: - return - var data = file.get_as_text() - var status = validate_json(data) - file.close() - if status != "": - print("Incorrect node description (%s)" % status) - return - data = parse_json(data) - model = m - update_node(data) - else: - print("set_model error "+str(m)) - -func update_node(data): - print("node_generic.update_node") - if typeof(data) != TYPE_DICTIONARY: - return - if !data.has("name"): - return - # Clean node - parameters = {} - var custom_node_buttons = null - for c in get_children(): - if c.name != "CustomNodeButtons": - remove_child(c) - c.queue_free() - else: - custom_node_buttons = c - # Rebuild node - title = data.name - model_data = data - uses_seed = false - if model_data.has("instance") and model_data.instance.find("$(seed)"): - uses_seed = true - if model_data.has("parameters") and typeof(model_data.parameters) == TYPE_ARRAY: - var control_list = [] - var sizer = null - for p in model_data.parameters: - if !p.has("name") or !p.has("type"): - continue - var control = null - if p.type == "float": - if p.has("widget") and p.widget == "spinbox": - control = SpinBox.new() - else: - control = HSlider.new() - control.min_value = p.min - control.max_value = p.max - control.step = 0 if !p.has("step") else p.step - if p.has("default"): - control.value = p.default - control.rect_min_size.x = 80 - parameters[p.name] = 0.5*(p.min+p.max) - elif p.type == "size": - control = OptionButton.new() - for i in range(p.first, p.last+1): - var s = pow(2, i) - control.add_item("%dx%d" % [ s, s ]) - control.selected = 0 if !p.has("default") else p.default-p.first - elif p.type == "enum": - control = OptionButton.new() - for i in range(p.values.size()): - var value = p.values[i] - control.add_item(value.name) - control.selected = 0 if !p.has("default") else p.default - elif p.type == "boolean": - control = CheckBox.new() - elif p.type == "color": - control = ColorPickerButton.new() - elif p.type == "gradient": - control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance() - if control != null: - var label = p.name - control.name = label - control_list.append(control) - if p.has("label"): - label = p.label - if sizer == null or label != "nonewline": - sizer = HBoxContainer.new() - sizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL - add_child(sizer) - if label != "" && label != "nonewline": - var label_widget = Label.new() - label_widget.text = label - label_widget.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL - sizer.add_child(label_widget) - control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL - sizer.add_child(control) - initialize_properties(control_list) - else: - model_data.parameters = [] - if model_data.has("inputs") and typeof(model_data.inputs) == TYPE_ARRAY: - for i in range(model_data.inputs.size()): - var input = model_data.inputs[i] - var enable_left = false - var color_left = Color(0.5, 0.5, 0.5) - if typeof(input) == TYPE_DICTIONARY: - if input.type == "rgb": - enable_left = true - color_left = Color(0.5, 0.5, 1.0) - elif input.type == "rgba": - enable_left = true - color_left = Color(0.0, 0.5, 0.0, 0.5) - else: - enable_left = true - set_slot(i, enable_left, 0, color_left, false, 0, Color()) - else: - model_data.inputs = [] - if model_data.has("outputs") and typeof(model_data.outputs) == TYPE_ARRAY: - for i in range(model_data.outputs.size()): - var output = model_data.outputs[i] - var enable_right = false - var color_right = Color(0.5, 0.5, 0.5) - if typeof(output) == TYPE_DICTIONARY: - if output.has("rgb"): - enable_right = true - color_right = Color(0.5, 0.5, 1.0) - elif output.has("rgba"): - enable_right = true - color_right = Color(0.0, 0.5, 0.0, 0.5) - elif output.has("f"): - enable_right = true - set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right) - else: - model_data.outputs = [] - if custom_node_buttons != null: - move_child(custom_node_buttons, get_child_count()-1) - -func find_keyword_call(string, keyword): - var search_string = "$%s(" % keyword - var position = string.find(search_string) - if position == -1: - return null - var parenthesis_level = 0 - var parameter_begin = position+search_string.length() - var parameter_end = -1 - for i in range(parameter_begin, string.length()): - if string[i] == '(': - parenthesis_level += 1 - elif string[i] == ')': - if parenthesis_level == 0: - return string.substr(parameter_begin, i-parameter_begin) - parenthesis_level -= 1 - return "" - -func replace_input(string, input, type, src, default): - var required_defs = "" - var required_code = "" - while true: - var uv = find_keyword_call(string, input) - if uv == null: - break - elif uv == "": - print("syntax error") - break - var src_code - if src == null: - src_code = subst(default, "(%s)" % uv) - else: - src_code = src.get_shader_code(uv) - src_code.string = src_code[type] - required_defs += src_code.defs - required_code += src_code.code - string = string.replace("$%s(%s)" % [ input, uv ], src_code.string) - return { string=string, defs=required_defs, code=required_code } - -func is_word_letter(l): - return "azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN1234567890_".find(l) != -1 - -func replace_variable(string, variable, value): - string = string.replace("$(%s)" % variable, value) - var keyword_size = variable.length()+1 - var new_string = "" - while !string.empty(): - var pos = string.find("$"+variable) - if pos == -1: - new_string += string - break - new_string += string.left(pos) - string = string.right(pos) - if string.empty() or !is_word_letter(string[0]): - new_string += value - else: - new_string += "$"+variable - string = string.right(keyword_size) - return new_string - -func subst(string, uv = ""): - var required_defs = "" - var required_code = "" - string = replace_variable(string, "name", name) - string = replace_variable(string, "seed", str(get_seed())) - if uv != "": - string = replace_variable(string, "uv", "("+uv+")") - if model_data.has("parameters") and typeof(model_data.parameters) == TYPE_ARRAY: - for p in model_data.parameters: - if !p.has("name") or !p.has("type"): - continue - var value = parameters[p.name] - var value_string = null - if p.type == "float": - value_string = "%.9f" % value - elif p.type == "size": - value_string = "%.9f" % pow(2, value+p.first) - elif p.type == "enum": - value_string = p.values[value].value - elif p.type == "color": - value_string = "vec4(%.9f, %.9f, %.9f, %.9f)" % [ value.r, value.g, value.b, value.a ] - elif p.type == "gradient": - value_string = p.name+"_gradient_fct" - if value_string != null: - string = replace_variable(string, p.name, value_string) - if model_data.has("inputs") and typeof(model_data.inputs) == TYPE_ARRAY: - for i in range(model_data.inputs.size()): - var input = model_data.inputs[i] - var source = get_source(i) - var result = replace_input(string, input.name, input.type, source, input.default) - string = result.string - required_defs += result.defs - required_code += result.code - return { string=string, defs=required_defs, code=required_code } - -func _get_shader_code(uv, slot = 0): - var output_info = [ { field="rgba", type="vec4" }, { field="rgb", type="vec3" }, { field="f", type="float" } ] - var rv = { defs="", code="" } - var variant_string = uv+","+str(slot) - if model_data != null and model_data.has("outputs") and model_data.outputs.size() > slot: - var output = model_data.outputs[slot] - rv.defs = "" - if model_data.has("instance") && generated_variants.empty(): - rv.defs += subst(model_data.instance).string - for p in model_data.parameters: - if p.type == "gradient": - rv.defs += parameters[p.name].get_shader(p.name+"_gradient_fct") - var variant_index = generated_variants.find(variant_string) - if variant_index == -1: - variant_index = generated_variants.size() - generated_variants.append(variant_string) - for t in output_info: - if output.has(t.field): - var subst_output = subst(output[t.field], uv) - rv.defs += subst_output.defs - rv.code += subst_output.code - rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, name, slot, variant_index, t.field, subst_output.string ] - for t in output_info: - if output.has(t.field): - rv[t.field] = "%s_%d_%d_%s" % [ name, slot, variant_index, t.field ] - return rv - -func get_globals(): - var list = .get_globals() - if typeof(model_data) == TYPE_DICTIONARY and model_data.has("global") and list.find(model_data.global) == -1: - list.append(model_data.global) - return list - -func _on_offset_changed(): - update_shaders() - -func serialize(): - var return_value = .serialize() - return_value.type = model - return return_value diff --git a/addons/material_maker/nodes/switch.gd b/addons/material_maker/nodes/switch.gd new file mode 100644 index 0000000..03638f5 --- /dev/null +++ b/addons/material_maker/nodes/switch.gd @@ -0,0 +1,87 @@ +tool +extends MMGraphNodeGeneric + +var fixed_lines : int = 0 + +func _ready(): + update_node() + +func update_preview_buttons(index : int): + for i in range(generator.parameters.outputs): + if i != index: + var line = get_child(i) + line.get_child(2).pressed = false + +func update_node(): + print("update_node") + if generator == null or !generator.parameters.has("outputs") or !generator.parameters.has("choices"): + return + save_preview_widget() + var new_fixed_lines = 3 if generator.editable else 1 + if new_fixed_lines != fixed_lines: + fixed_lines = new_fixed_lines + # Remove all lines + while get_child_count() > 0: + var remove = get_child(0) + remove_child(remove) + remove.free() + var lines_list = [] + if generator.editable: + lines_list.push_back( { name="outputs", min=1, max=5 } ) + lines_list.push_back( { name="choices", min=2, max=5 } ) + lines_list.push_back( { name="source", min=0, max=generator.parameters.choices-1 } ) + for l in lines_list: + var sizer = HBoxContainer.new() + var input_label = Label.new() + sizer.add_child(input_label) + var control : HSlider = HSlider.new() + control.name = l.name + control.value = generator.parameters[l.name] + control.min_value = l.min + control.max_value = l.max + control.step = 1 + control.rect_min_size.x = 75 + sizer.add_child(control) + control.connect("value_changed", self, "_on_value_changed", [ l.name ]) + controls[l.name] = control + sizer.add_child(preload("res://addons/material_maker/widgets/preview_button.tscn").instance()) + add_child(sizer) + else: + # Keep lines with controls + while get_child_count() > output_count and get_child_count() > fixed_lines: + var remove = get_child(get_child_count()-1) + remove_child(remove) + remove.free() + # Populate the GraphNode + var output_count : int = generator.parameters.outputs + var input_count : int = output_count * generator.parameters.choices + controls["source"].max_value = generator.parameters.choices-1 + while get_child_count() < input_count: + var sizer = HBoxContainer.new() + var input_label = Label.new() + sizer.add_child(input_label) + if get_child_count() < 5: + var space = Control.new() + space.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL + sizer.add_child(space) + sizer.add_child(preload("res://addons/material_maker/widgets/preview_button.tscn").instance()) + add_child(sizer) + rect_size = Vector2(0, 0) + for i in range(get_child_count()): + var sizer = get_child(i) + var has_input = true + var has_output = false + if i < 5: + has_output = i < output_count + sizer.get_child(2).visible = has_output + sizer.get_child(2).connect("toggled", self, "on_preview_button", [ i ]) + if i >= input_count: + sizer.get_child(0).text = "" + has_input = false + else: + sizer.get_child(0).text = PoolByteArray([65+i%int(output_count)]).get_string_from_ascii()+str(1+i/int(output_count)) + sizer.get_child(0).add_color_override("font_color", Color(1.0, 1.0, 1.0) if i/int(output_count) == generator.parameters.source else Color(0.5, 0.5, 0.5)) + set_slot(i, has_input, 0, Color(0.0, 0.5, 0.0, 0.5), has_output, 0, Color(0.0, 0.5, 0.0, 0.5)) + # Preview + restore_preview_widget() + print("update_node end") diff --git a/addons/material_maker/nodes/switch.tscn b/addons/material_maker/nodes/switch.tscn new file mode 100644 index 0000000..4be55b8 --- /dev/null +++ b/addons/material_maker/nodes/switch.tscn @@ -0,0 +1,129 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://addons/material_maker/nodes/switch.gd" type="Script" id=1] +[ext_resource path="res://addons/material_maker/widgets/preview_button.tscn" type="PackedScene" id=2] + +[sub_resource type="Theme" id=1] + +[node name="Switch" type="GraphNode"] +margin_left = -1.0 +margin_top = -1.0 +margin_right = 150.0 +margin_bottom = 78.0 +mouse_filter = 1 +size_flags_stretch_ratio = 0.13 +theme = SubResource( 1 ) +title = "Switch" +show_close = true +slot/0/left_enabled = false +slot/0/left_type = 0 +slot/0/left_color = Color( 0.5, 0.5, 1, 1 ) +slot/0/right_enabled = true +slot/0/right_type = 0 +slot/0/right_color = Color( 0.5, 0.5, 1, 1 ) +slot/1/left_enabled = false +slot/1/left_type = 0 +slot/1/left_color = Color( 1, 1, 1, 1 ) +slot/1/right_enabled = false +slot/1/right_type = 0 +slot/1/right_color = Color( 1, 1, 1, 1 ) +slot/2/left_enabled = false +slot/2/left_type = 0 +slot/2/left_color = Color( 1, 1, 1, 1 ) +slot/2/right_enabled = false +slot/2/right_type = 0 +slot/2/right_color = Color( 1, 1, 1, 1 ) +script = ExtResource( 1 ) + +[node name="HBox1" type="HBoxContainer" parent="."] +margin_left = 16.0 +margin_top = 24.0 +margin_right = 135.0 +margin_bottom = 40.0 + +[node name="Label" type="Label" parent="HBox1"] +margin_top = 1.0 +margin_right = 20.0 +margin_bottom = 15.0 +rect_min_size = Vector2( 20, 0 ) +text = "A0" + +[node name="outputs" type="HSlider" parent="HBox1"] +margin_left = 24.0 +margin_right = 99.0 +margin_bottom = 16.0 +rect_min_size = Vector2( 75, 0 ) +hint_tooltip = "Output count" +min_value = 1.0 +max_value = 5.0 +value = 2.0 + +[node name="PreviewButton" parent="HBox1" instance=ExtResource( 2 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 103.0 +margin_right = 119.0 +margin_bottom = 16.0 + +[node name="HBox2" type="HBoxContainer" parent="."] +margin_left = 16.0 +margin_top = 40.0 +margin_right = 135.0 +margin_bottom = 56.0 + +[node name="Label" type="Label" parent="HBox2"] +margin_top = 1.0 +margin_right = 20.0 +margin_bottom = 15.0 +rect_min_size = Vector2( 20, 0 ) +text = "A0" + +[node name="choices" type="HSlider" parent="HBox2"] +margin_left = 24.0 +margin_right = 99.0 +margin_bottom = 16.0 +rect_min_size = Vector2( 75, 0 ) +hint_tooltip = "Choice count" +min_value = 2.0 +max_value = 5.0 +value = 2.0 + +[node name="PreviewButton" parent="HBox2" instance=ExtResource( 2 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 103.0 +margin_right = 119.0 +margin_bottom = 16.0 + +[node name="HBox3" type="HBoxContainer" parent="."] +margin_left = 16.0 +margin_top = 57.0 +margin_right = 135.0 +margin_bottom = 73.0 + +[node name="Label" type="Label" parent="HBox3"] +margin_top = 1.0 +margin_right = 20.0 +margin_bottom = 15.0 +rect_min_size = Vector2( 20, 0 ) +text = "A0" + +[node name="source" type="HSlider" parent="HBox3"] +margin_left = 24.0 +margin_right = 99.0 +margin_bottom = 16.0 +rect_min_size = Vector2( 75, 0 ) +hint_tooltip = "Choice" +max_value = 4.0 +value = 1.0 +ticks_on_borders = true + +[node name="PreviewButton" parent="HBox3" instance=ExtResource( 2 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 103.0 +margin_right = 119.0 +margin_bottom = 16.0 +[connection signal="value_changed" from="HBox1/outputs" to="." method="_on_value_changed" binds= [ "outputs" ]] +[connection signal="value_changed" from="HBox2/choices" to="." method="_on_value_changed" binds= [ "choices" ]] +[connection signal="value_changed" from="HBox3/source" to="." method="_on_value_changed" binds= [ "source" ]] diff --git a/project.godot b/project.godot index 01c3f93..b328d67 100644 --- a/project.godot +++ b/project.godot @@ -179,5 +179,4 @@ file_logging/enable_file_logging=true [rendering] -quality/filters/anisotropic_filter_level=16 environment/default_environment="res://default_env.tres"