From 565219ab749251261a052a94e9b4d85822fbda76 Mon Sep 17 00:00:00 2001 From: RodZill4 Date: Sat, 21 Mar 2020 17:44:41 +0100 Subject: [PATCH 1/7] Started implementing the Tones node --- addons/material_maker/engine/gen_base.gd | 3 + addons/material_maker/nodes/levels.mmg | 122 +++++++++++++ material_maker/graph_edit.gd | 2 +- material_maker/main_window.gd | 2 +- material_maker/node_factory.gd | 13 +- material_maker/nodes/levels.gd | 153 +++++++++++++++++ material_maker/nodes/levels.tscn | 209 +++++++++++++++++++++++ 7 files changed, 497 insertions(+), 7 deletions(-) create mode 100644 addons/material_maker/nodes/levels.mmg create mode 100644 material_maker/nodes/levels.gd create mode 100644 material_maker/nodes/levels.tscn diff --git a/addons/material_maker/engine/gen_base.gd b/addons/material_maker/engine/gen_base.gd index e665262..17793a5 100644 --- a/addons/material_maker/engine/gen_base.gd +++ b/addons/material_maker/engine/gen_base.gd @@ -53,6 +53,9 @@ func toggle_editable() -> bool: func is_template() -> bool: return model != null +func get_template_name() -> bool: + return model + func is_editable() -> bool: return false diff --git a/addons/material_maker/nodes/levels.mmg b/addons/material_maker/nodes/levels.mmg new file mode 100644 index 0000000..be161f0 --- /dev/null +++ b/addons/material_maker/nodes/levels.mmg @@ -0,0 +1,122 @@ +{ + "name": "levels", + "node_position": { + "x": 0, + "y": 0 + }, + "parameters": { + "in_max": { + "a": 1, + "b": 1, + "g": 1, + "r": 1, + "type": "Color" + }, + "in_mid": { + "a": 0.5, + "b": 0.5, + "g": 0.5, + "r": 0.5, + "type": "Color" + }, + "in_min": { + "a": 0, + "b": 0, + "g": 0, + "r": 0, + "type": "Color" + }, + "out_max": { + "a": 1, + "b": 1, + "g": 1, + "r": 1, + "type": "Color" + }, + "out_min": { + "a": 0, + "b": 0, + "g": 0, + "r": 0, + "type": "Color" + } + }, + "shader_model": { + "code": "", + "global": "vec4 adjust_levels(vec4 input, vec4 in_min, vec4 in_mid, vec4 in_max, vec4 out_min, vec4 out_max) {\n\tinput = clamp((input-in_min)/(in_max-in_min), 0.0, 1.0);\n\tin_mid = (in_mid-in_min)/(in_max-in_min);\n\tvec4 dark = step(in_mid, input);\n\tinput = 0.5*mix(input/(in_mid), 1.0+(input-in_mid)/(1.0-in_mid), dark);\n\treturn out_min+input*(out_max-out_min);\n}\n", + "inputs": [ + { + "default": "vec4(1.0)", + "label": "", + "name": "input", + "type": "rgba" + } + ], + "instance": "", + "name": "Levels", + "outputs": [ + { + "rgba": "adjust_levels($input($uv), $in_min, $in_mid, $in_max, $out_min, $out_max)", + "type": "rgba" + } + ], + "parameters": [ + { + "default": { + "a": 0, + "b": 0, + "g": 0, + "r": 0 + }, + "label": "", + "name": "in_min", + "type": "color" + }, + { + "default": { + "a": 0.498039, + "b": 0.498039, + "g": 0.498039, + "r": 0.498039 + }, + "label": "", + "name": "in_mid", + "type": "color" + }, + { + "default": { + "a": 1, + "b": 1, + "g": 1, + "r": 1 + }, + "label": "", + "name": "in_max", + "type": "color" + }, + { + "default": { + "a": 1, + "b": 0, + "g": 0, + "r": 0 + }, + "label": "", + "name": "out_min", + "type": "color" + }, + { + "default": { + "a": 1, + "b": 1, + "g": 1, + "r": 1 + }, + "label": "", + "name": "out_max", + "type": "color" + } + ] + }, + "type": "shader" +} \ No newline at end of file diff --git a/material_maker/graph_edit.gd b/material_maker/graph_edit.gd index 4c2e658..ba166a1 100644 --- a/material_maker/graph_edit.gd +++ b/material_maker/graph_edit.gd @@ -166,7 +166,7 @@ func clear_material() -> void: func update_graph(generators, connections) -> Array: var rv = [] for g in generators: - var node = node_factory.create_node(g.get_type()) + var node = node_factory.create_node(g.get_template_name() if g.is_template() else "", g.get_type()) if node != null: node.name = "node_"+g.name add_node(node) diff --git a/material_maker/main_window.gd b/material_maker/main_window.gd index 0434639..be7af06 100644 --- a/material_maker/main_window.gd +++ b/material_maker/main_window.gd @@ -462,7 +462,7 @@ func make_selected_nodes_editable() -> void: var selected_nodes = get_selected_nodes() if !selected_nodes.empty(): for n in selected_nodes: - if n.generator.toggle_editable(): + if n.generator.toggle_editable() and n.has_method("update_node"): n.update_node() func add_to_user_library() -> void: diff --git a/material_maker/node_factory.gd b/material_maker/node_factory.gd index 12a908e..7548ff4 100644 --- a/material_maker/node_factory.gd +++ b/material_maker/node_factory.gd @@ -2,13 +2,16 @@ extends Node var includes -func create_node(type) -> Node: +func create_node(model : String, type : String) -> Node: + var node_type = null var node = null - var file_name = "res://material_maker/nodes/"+type+".tscn" + var file_name = "res://material_maker/nodes/"+model+".tscn" + if ! ResourceLoader.exists(file_name): + file_name = "res://material_maker/nodes/"+type+".tscn" if ResourceLoader.exists(file_name): - var node_type = load(file_name) - if node_type != null: - node = node_type.instance() + node_type = load(file_name) + if node_type != null: + node = node_type.instance() if node == null: node = preload("res://material_maker/nodes/generic.tscn").instance() return node diff --git a/material_maker/nodes/levels.gd b/material_maker/nodes/levels.gd new file mode 100644 index 0000000..afd07ef --- /dev/null +++ b/material_maker/nodes/levels.gd @@ -0,0 +1,153 @@ +extends MMGraphNodeBase + +class Cursor: + extends Control + + var color : Color + var top : bool = true + var position : float + + + const WIDTH : int = 8 + const HEIGHT : int = 8 + + func _init(c, p, t = true): + color = c + position = p + top = t + + func _ready() -> void: + rect_position = Vector2(position * get_parent().rect_size.x - 0.5*WIDTH, -2 if top else get_parent().rect_size.y+2-HEIGHT) + rect_size = Vector2(WIDTH, HEIGHT) + + func _draw() -> void: + var polygon : PoolVector2Array + if top: + polygon = PoolVector2Array([Vector2(0, 0), Vector2(WIDTH/2, HEIGHT), Vector2(WIDTH, 0), Vector2(0, 0)]) + else: + polygon = PoolVector2Array([Vector2(0, HEIGHT), Vector2(WIDTH/2, 0), Vector2(WIDTH, HEIGHT), Vector2(0, HEIGHT)]) + var c = color + c.a = 1.0 + draw_colored_polygon(polygon, c) + var outline_color = 0.0 if position > 0.5 else 1.0 + draw_polyline(polygon, Color(outline_color, outline_color, outline_color), 1.0, true) + + func _gui_input(ev) -> void: + if ev is InputEventMouseMotion && (ev.button_mask & 1) != 0: + rect_position.x += ev.relative.x + rect_position.x = min(max(-0.5*WIDTH, rect_position.x), get_parent().rect_size.x-0.5*WIDTH) + var new_position = (rect_position.x+0.5*WIDTH)/get_parent().rect_size.x + if new_position != position: + position = new_position + get_parent().get_parent().update_value(self, position) + update() + + func get_position() -> Vector2: + return rect_position.x / (get_parent().rect_size.x - WIDTH) + +var cursor_in_min : Cursor +var cursor_in_mid : Cursor +var cursor_in_max : Cursor +var cursor_out_min : Cursor +var cursor_out_max : Cursor + +func _ready() -> void: + var slot_color = mm_io_types.types["rgba"].color + var slot_type = mm_io_types.types["rgba"].slot_type + set_slot(0, true, slot_type, slot_color, true, slot_type, slot_color) + cursor_in_min = Cursor.new(Color(0.0, 0.0, 0.0), 0.0) + $Histogram.add_child(cursor_in_min) + cursor_in_mid = Cursor.new(Color(0.5, 0.5, 0.5), 0.5) + $Histogram.add_child(cursor_in_mid) + cursor_in_max = Cursor.new(Color(1.0, 1.0, 1.0), 1.0) + $Histogram.add_child(cursor_in_max) + cursor_out_min = Cursor.new(Color(0.0, 0.0, 0.0), 0.0, false) + $Histogram.add_child(cursor_out_min) + cursor_out_max = Cursor.new(Color(1.0, 1.0, 1.0), 1.0, false) + $Histogram.add_child(cursor_out_max) + +func set_generator(g) -> void: + .set_generator(g) + generator.connect("parameter_changed", self, "on_parameter_changed") + update_node() + +func update_node() -> void: + if has_node("NodeEditButtons"): + var r = $NodeEditButtons + remove_child(r) + r.free() + rect_size = Vector2(0, 0) + if generator.is_editable(): + var edit_buttons = preload("res://material_maker/nodes/edit_buttons.tscn").instance() + add_child(edit_buttons) + edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator") + set_slot(edit_buttons.get_index(), false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0)) + +func on_parameter_changed(p, v) -> void: + if p == "__input_changed__": + var source = generator.get_source(0) + var result = source.generator.render(source.output_index, 128, true) + while result is GDScriptFunctionState: + result = yield(result, "completed") + result.copy_to_texture($ViewportImage/ColorRect.material.get_shader_param("tex")) + result.release() + +func set_parameter(n : String, v : float, d : float) -> void: + var value = generator.get_parameter(n) + match $Mode.selected: + 0: + value.r = v + value.g = v + value.b = v + value.a = d + 1: + value.r = v + 2: + value.g = v + 3: + value.b = v + 4: + value.a = v + generator.set_parameter(n, value) + +func update_value(control : Cursor, value : float) -> void: + match control: + cursor_in_min: + set_parameter("in_min", value, 0) + cursor_in_mid: + set_parameter("in_mid", value, 0.5) + cursor_in_max: + set_parameter("in_max", value, 1) + cursor_out_min: + set_parameter("out_min", value, 0) + cursor_out_max: + set_parameter("out_max", value, 1) + get_parent().send_changed_signal() + +func edit_generator() -> void: + if generator.has_method("edit"): + generator.edit(self) + +func update_generator(shader_model : Dictionary) -> void: + generator.set_shader_model(shader_model) + update_node() + +func save_generator() -> void: + 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("*.mmg;Material Maker Generator") + dialog.connect("file_selected", self, "do_save_generator") + dialog.popup_centered() + +func do_save_generator(file_name : String) -> void: + var file = File.new() + if file.open(file_name, File.WRITE) == OK: + var data = generator.serialize() + data.name = file_name.get_file().get_basename() + data.node_position = { x=0, y=0 } + file.store_string(JSON.print(data, "\t", true)) + file.close() + mm_loader.update_predefined_generators() diff --git a/material_maker/nodes/levels.tscn b/material_maker/nodes/levels.tscn new file mode 100644 index 0000000..c263878 --- /dev/null +++ b/material_maker/nodes/levels.tscn @@ -0,0 +1,209 @@ +[gd_scene load_steps=14 format=2] + +[ext_resource path="res://material_maker/nodes/levels.gd" type="Script" id=1] + +[sub_resource type="Shader" id=1] +code = "shader_type canvas_item; + +uniform sampler2D tex; + +void fragment() { + COLOR = texture(tex, UV); +} +" + +[sub_resource type="ImageTexture" id=14] +resource_local_to_scene = true +flags = 0 +flags = 0 + +[sub_resource type="ShaderMaterial" id=4] +resource_local_to_scene = true +shader = SubResource( 1 ) +shader_param/tex = SubResource( 14 ) + +[sub_resource type="Shader" id=5] +code = "shader_type canvas_item; + +uniform sampler2D tex; + +void fragment() { + vec4 sum = vec4(0.0); + for (int i = 0; i < 128; ++i) { + sum += step(abs(texture(tex, vec2(UV.x, float(i)/127.0))-UV.y), vec4(0.02)); + } + COLOR = vec4(sum.xyz/255.0, 1.0); +} +" + +[sub_resource type="ViewportTexture" id=6] +viewport_path = NodePath("ViewportImage") + +[sub_resource type="ShaderMaterial" id=7] +resource_local_to_scene = true +shader = SubResource( 5 ) +shader_param/tex = SubResource( 6 ) + +[sub_resource type="Shader" id=8] +code = "shader_type canvas_item; + +uniform sampler2D tex; + +void fragment() { + vec4 sum = vec4(0.0); + for (int i = 0; i < 128; ++i) { + sum += texture(tex, vec2(float(i)/127.0, UV.x)); + } + COLOR = vec4(sum.xyz/255.0, 1.0); +}" + +[sub_resource type="ViewportTexture" id=9] +viewport_path = NodePath("ViewportHistogram1") + +[sub_resource type="ShaderMaterial" id=10] +resource_local_to_scene = true +shader = SubResource( 8 ) +shader_param/tex = SubResource( 9 ) + +[sub_resource type="Shader" id=11] +code = "shader_type canvas_item; + +uniform sampler2D tex; + +void fragment() { + if (abs(fract(UV.y+0.05)) < 0.1) { + COLOR = vec4(vec3(UV.x), 1.0); + } else { + vec4 highest = vec4(0.0); + for (int i = 0; i < 128; ++i) { + highest = max(highest, texture(tex, vec2(float(i)/128.0, 0.0))); + } + vec4 value = 0.5*(texture(tex, vec2(max(0.0, UV.x-0.025), 0.0))+texture(tex, vec2(min(1.0, UV.x+0.025), 0.0))); + COLOR = vec4(step(vec4(0.95-UV.y)*highest/0.9, value).xyz, 1.0); + } +}" + +[sub_resource type="ViewportTexture" id=12] +viewport_path = NodePath("ViewportHistogram2") + +[sub_resource type="ShaderMaterial" id=13] +resource_local_to_scene = true +shader = SubResource( 11 ) +shader_param/tex = SubResource( 12 ) + +[node name="Tones" type="GraphNode"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = -39.6668 +margin_top = 14.4243 +margin_right = -1095.67 +margin_bottom = -579.576 +title = "Tones" +show_close = true +slot/0/left_enabled = true +slot/0/left_type = 0 +slot/0/left_color = Color( 0, 0.396078, 1, 1 ) +slot/0/right_enabled = true +slot/0/right_type = 0 +slot/0/right_color = Color( 0, 0.415686, 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 ) +slot/3/left_enabled = false +slot/3/left_type = 0 +slot/3/left_color = Color( 1, 1, 1, 1 ) +slot/3/right_enabled = false +slot/3/right_type = 0 +slot/3/right_color = Color( 1, 1, 1, 1 ) +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ViewportImage" type="Viewport" parent="."] +size = Vector2( 256, 256 ) +disable_3d = true +keep_3d_linear = true +usage = 0 +render_target_v_flip = true +render_target_update_mode = 3 + +[node name="ColorRect" type="ColorRect" parent="ViewportImage"] +material = SubResource( 4 ) +margin_right = 256.0 +margin_bottom = 128.0 +rect_min_size = Vector2( 256, 256 ) + +[node name="ViewportHistogram1" type="Viewport" parent="."] +size = Vector2( 128, 128 ) +disable_3d = true +keep_3d_linear = true +usage = 0 +render_target_v_flip = true +render_target_update_mode = 3 + +[node name="ColorRect" type="ColorRect" parent="ViewportHistogram1"] +material = SubResource( 7 ) +margin_right = 128.0 +margin_bottom = 128.0 +rect_min_size = Vector2( 128, 128 ) + +[node name="ViewportHistogram2" type="Viewport" parent="."] +size = Vector2( 128, 2 ) +disable_3d = true +keep_3d_linear = true +usage = 0 +render_target_v_flip = true +render_target_update_mode = 3 + +[node name="ColorRect" type="ColorRect" parent="ViewportHistogram2"] +material = SubResource( 10 ) +margin_right = 128.0 +margin_bottom = 2.0 +rect_min_size = Vector2( 128, 2 ) + +[node name="Mode" type="OptionButton" parent="."] +margin_left = 16.0 +margin_top = 24.0 +margin_right = 208.0 +margin_bottom = 44.0 +text = "Luminance" +items = [ "Luminance", null, false, 0, null, "Red", null, false, 1, null, "Green", null, false, 2, null, "Blue", null, false, 3, null, "Alpha", null, false, 4, null ] +selected = 0 + +[node name="Spacer1" type="Control" parent="."] +margin_left = 16.0 +margin_top = 45.0 +margin_right = 208.0 +margin_bottom = 49.0 +rect_min_size = Vector2( 0, 4 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Histogram" type="ColorRect" parent="."] +material = SubResource( 13 ) +margin_left = 16.0 +margin_top = 50.0 +margin_right = 208.0 +margin_bottom = 178.0 +rect_min_size = Vector2( 192, 128 ) + +[node name="Spacer2" type="Control" parent="."] +margin_left = 16.0 +margin_top = 179.0 +margin_right = 208.0 +margin_bottom = 183.0 +rect_min_size = Vector2( 0, 4 ) +__meta__ = { +"_edit_use_anchors_": false +} From ef4fbac0a486bfe3ec54be2d564f2761ce9bf1c6 Mon Sep 17 00:00:00 2001 From: RodZill4 Date: Sat, 21 Mar 2020 21:49:05 +0100 Subject: [PATCH 2/7] Renamed Tones node and added alpha channel to histogram --- .../nodes/{levels.mmg => tones.mmg} | 0 material_maker/nodes/{levels.gd => tones.gd} | 0 .../nodes/{levels.tscn => tones.tscn} | 59 ++++++++++--------- 3 files changed, 30 insertions(+), 29 deletions(-) rename addons/material_maker/nodes/{levels.mmg => tones.mmg} (100%) rename material_maker/nodes/{levels.gd => tones.gd} (100%) rename material_maker/nodes/{levels.tscn => tones.tscn} (77%) diff --git a/addons/material_maker/nodes/levels.mmg b/addons/material_maker/nodes/tones.mmg similarity index 100% rename from addons/material_maker/nodes/levels.mmg rename to addons/material_maker/nodes/tones.mmg diff --git a/material_maker/nodes/levels.gd b/material_maker/nodes/tones.gd similarity index 100% rename from material_maker/nodes/levels.gd rename to material_maker/nodes/tones.gd diff --git a/material_maker/nodes/levels.tscn b/material_maker/nodes/tones.tscn similarity index 77% rename from material_maker/nodes/levels.tscn rename to material_maker/nodes/tones.tscn index c263878..b664487 100644 --- a/material_maker/nodes/levels.tscn +++ b/material_maker/nodes/tones.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=14 format=2] -[ext_resource path="res://material_maker/nodes/levels.gd" type="Script" id=1] +[ext_resource path="res://material_maker/nodes/tones.gd" type="Script" id=1] [sub_resource type="Shader" id=1] code = "shader_type canvas_item; @@ -12,17 +12,17 @@ void fragment() { } " -[sub_resource type="ImageTexture" id=14] +[sub_resource type="ImageTexture" id=2] resource_local_to_scene = true flags = 0 flags = 0 -[sub_resource type="ShaderMaterial" id=4] +[sub_resource type="ShaderMaterial" id=3] resource_local_to_scene = true shader = SubResource( 1 ) -shader_param/tex = SubResource( 14 ) +shader_param/tex = SubResource( 2 ) -[sub_resource type="Shader" id=5] +[sub_resource type="Shader" id=4] code = "shader_type canvas_item; uniform sampler2D tex; @@ -36,15 +36,15 @@ void fragment() { } " -[sub_resource type="ViewportTexture" id=6] +[sub_resource type="ViewportTexture" id=5] viewport_path = NodePath("ViewportImage") -[sub_resource type="ShaderMaterial" id=7] +[sub_resource type="ShaderMaterial" id=6] resource_local_to_scene = true -shader = SubResource( 5 ) -shader_param/tex = SubResource( 6 ) +shader = SubResource( 4 ) +shader_param/tex = SubResource( 5 ) -[sub_resource type="Shader" id=8] +[sub_resource type="Shader" id=7] code = "shader_type canvas_item; uniform sampler2D tex; @@ -57,15 +57,15 @@ void fragment() { COLOR = vec4(sum.xyz/255.0, 1.0); }" -[sub_resource type="ViewportTexture" id=9] +[sub_resource type="ViewportTexture" id=8] viewport_path = NodePath("ViewportHistogram1") -[sub_resource type="ShaderMaterial" id=10] +[sub_resource type="ShaderMaterial" id=9] resource_local_to_scene = true -shader = SubResource( 8 ) -shader_param/tex = SubResource( 9 ) +shader = SubResource( 7 ) +shader_param/tex = SubResource( 8 ) -[sub_resource type="Shader" id=11] +[sub_resource type="Shader" id=10] code = "shader_type canvas_item; uniform sampler2D tex; @@ -78,26 +78,27 @@ void fragment() { for (int i = 0; i < 128; ++i) { highest = max(highest, texture(tex, vec2(float(i)/128.0, 0.0))); } - vec4 value = 0.5*(texture(tex, vec2(max(0.0, UV.x-0.025), 0.0))+texture(tex, vec2(min(1.0, UV.x+0.025), 0.0))); - COLOR = vec4(step(vec4(0.95-UV.y)*highest/0.9, value).xyz, 1.0); + vec4 value = step(vec4(0.95-UV.y)*highest/0.9, 0.5*(texture(tex, vec2(max(0.0, UV.x-0.01), 0.0))+texture(tex, vec2(min(1.0, UV.x+0.01), 0.0)))); + float alpha = step(0.1, dot(value, vec4(1.0))); + COLOR = vec4(mix(value.rgb, vec3(0.5), 0.3*value.a), alpha); } }" -[sub_resource type="ViewportTexture" id=12] +[sub_resource type="ViewportTexture" id=11] viewport_path = NodePath("ViewportHistogram2") -[sub_resource type="ShaderMaterial" id=13] +[sub_resource type="ShaderMaterial" id=12] resource_local_to_scene = true -shader = SubResource( 11 ) -shader_param/tex = SubResource( 12 ) +shader = SubResource( 10 ) +shader_param/tex = SubResource( 11 ) [node name="Tones" type="GraphNode"] anchor_right = 1.0 anchor_bottom = 1.0 -margin_left = -39.6668 -margin_top = 14.4243 -margin_right = -1095.67 -margin_bottom = -579.576 +margin_left = 2.75074 +margin_top = 1.78928 +margin_right = -1053.25 +margin_bottom = -529.211 title = "Tones" show_close = true slot/0/left_enabled = true @@ -138,7 +139,7 @@ render_target_v_flip = true render_target_update_mode = 3 [node name="ColorRect" type="ColorRect" parent="ViewportImage"] -material = SubResource( 4 ) +material = SubResource( 3 ) margin_right = 256.0 margin_bottom = 128.0 rect_min_size = Vector2( 256, 256 ) @@ -152,7 +153,7 @@ render_target_v_flip = true render_target_update_mode = 3 [node name="ColorRect" type="ColorRect" parent="ViewportHistogram1"] -material = SubResource( 7 ) +material = SubResource( 6 ) margin_right = 128.0 margin_bottom = 128.0 rect_min_size = Vector2( 128, 128 ) @@ -166,7 +167,7 @@ render_target_v_flip = true render_target_update_mode = 3 [node name="ColorRect" type="ColorRect" parent="ViewportHistogram2"] -material = SubResource( 10 ) +material = SubResource( 9 ) margin_right = 128.0 margin_bottom = 2.0 rect_min_size = Vector2( 128, 2 ) @@ -191,7 +192,7 @@ __meta__ = { } [node name="Histogram" type="ColorRect" parent="."] -material = SubResource( 13 ) +material = SubResource( 12 ) margin_left = 16.0 margin_top = 50.0 margin_right = 208.0 From 08f5d007ae2783eb856e811fa5bea25020104e05 Mon Sep 17 00:00:00 2001 From: RodZill4 Date: Sun, 22 Mar 2020 05:45:29 +0100 Subject: [PATCH 3/7] Updated histogram for alpha channel --- material_maker/nodes/tones.tscn | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/material_maker/nodes/tones.tscn b/material_maker/nodes/tones.tscn index b664487..554a9ff 100644 --- a/material_maker/nodes/tones.tscn +++ b/material_maker/nodes/tones.tscn @@ -4,6 +4,7 @@ [sub_resource type="Shader" id=1] code = "shader_type canvas_item; +render_mode blend_disabled; uniform sampler2D tex; @@ -13,9 +14,6 @@ void fragment() { " [sub_resource type="ImageTexture" id=2] -resource_local_to_scene = true -flags = 0 -flags = 0 [sub_resource type="ShaderMaterial" id=3] resource_local_to_scene = true @@ -24,6 +22,7 @@ shader_param/tex = SubResource( 2 ) [sub_resource type="Shader" id=4] code = "shader_type canvas_item; +render_mode blend_disabled; uniform sampler2D tex; @@ -32,7 +31,7 @@ void fragment() { for (int i = 0; i < 128; ++i) { sum += step(abs(texture(tex, vec2(UV.x, float(i)/127.0))-UV.y), vec4(0.02)); } - COLOR = vec4(sum.xyz/255.0, 1.0); + COLOR = sum/255.0; } " @@ -46,6 +45,7 @@ shader_param/tex = SubResource( 5 ) [sub_resource type="Shader" id=7] code = "shader_type canvas_item; +render_mode blend_disabled; uniform sampler2D tex; @@ -54,7 +54,7 @@ void fragment() { for (int i = 0; i < 128; ++i) { sum += texture(tex, vec2(float(i)/127.0, UV.x)); } - COLOR = vec4(sum.xyz/255.0, 1.0); + COLOR = sum/255.0; }" [sub_resource type="ViewportTexture" id=8] @@ -69,6 +69,7 @@ shader_param/tex = SubResource( 8 ) code = "shader_type canvas_item; uniform sampler2D tex; +render_mode blend_disabled; void fragment() { if (abs(fract(UV.y+0.05)) < 0.1) { @@ -78,7 +79,7 @@ void fragment() { for (int i = 0; i < 128; ++i) { highest = max(highest, texture(tex, vec2(float(i)/128.0, 0.0))); } - vec4 value = step(vec4(0.95-UV.y)*highest/0.9, 0.5*(texture(tex, vec2(max(0.0, UV.x-0.01), 0.0))+texture(tex, vec2(min(1.0, UV.x+0.01), 0.0)))); + vec4 value = step(vec4(0.95-UV.y)*highest/0.9, 0.5*(texture(tex, vec2(max(0.0, UV.x-0.015), 0.0))+texture(tex, vec2(min(1.0, UV.x+0.015), 0.0)))); float alpha = step(0.1, dot(value, vec4(1.0))); COLOR = vec4(mix(value.rgb, vec3(0.5), 0.3*value.a), alpha); } @@ -132,8 +133,8 @@ __meta__ = { [node name="ViewportImage" type="Viewport" parent="."] size = Vector2( 256, 256 ) -disable_3d = true -keep_3d_linear = true +transparent_bg = true +hdr = false usage = 0 render_target_v_flip = true render_target_update_mode = 3 @@ -146,8 +147,9 @@ rect_min_size = Vector2( 256, 256 ) [node name="ViewportHistogram1" type="Viewport" parent="."] size = Vector2( 128, 128 ) -disable_3d = true -keep_3d_linear = true +own_world = true +transparent_bg = true +hdr = false usage = 0 render_target_v_flip = true render_target_update_mode = 3 @@ -160,6 +162,7 @@ rect_min_size = Vector2( 128, 128 ) [node name="ViewportHistogram2" type="Viewport" parent="."] size = Vector2( 128, 2 ) +transparent_bg = true disable_3d = true keep_3d_linear = true usage = 0 From d3a3fabc310c94ed04c41853470026b419dc9860 Mon Sep 17 00:00:00 2001 From: RodZill4 Date: Sun, 22 Mar 2020 09:54:32 +0100 Subject: [PATCH 4/7] Moved histogram to a separate scene (so it can become a panel later) --- material_maker/nodes/tones.gd | 3 +- material_maker/nodes/tones.tscn | 141 +--------------- material_maker/widgets/histogram/histogram.gd | 7 + .../widgets/histogram/histogram.tscn | 157 ++++++++++++++++++ 4 files changed, 168 insertions(+), 140 deletions(-) create mode 100644 material_maker/widgets/histogram/histogram.gd create mode 100644 material_maker/widgets/histogram/histogram.tscn diff --git a/material_maker/nodes/tones.gd b/material_maker/nodes/tones.gd index afd07ef..ad3c464 100644 --- a/material_maker/nodes/tones.gd +++ b/material_maker/nodes/tones.gd @@ -7,7 +7,6 @@ class Cursor: var top : bool = true var position : float - const WIDTH : int = 8 const HEIGHT : int = 8 @@ -89,7 +88,7 @@ func on_parameter_changed(p, v) -> void: var result = source.generator.render(source.output_index, 128, true) while result is GDScriptFunctionState: result = yield(result, "completed") - result.copy_to_texture($ViewportImage/ColorRect.material.get_shader_param("tex")) + result.copy_to_texture($Histogram.get_image_texture()) result.release() func set_parameter(n : String, v : float, d : float) -> void: diff --git a/material_maker/nodes/tones.tscn b/material_maker/nodes/tones.tscn index 554a9ff..12c3ae3 100644 --- a/material_maker/nodes/tones.tscn +++ b/material_maker/nodes/tones.tscn @@ -1,97 +1,7 @@ -[gd_scene load_steps=14 format=2] +[gd_scene load_steps=3 format=2] [ext_resource path="res://material_maker/nodes/tones.gd" type="Script" id=1] - -[sub_resource type="Shader" id=1] -code = "shader_type canvas_item; -render_mode blend_disabled; - -uniform sampler2D tex; - -void fragment() { - COLOR = texture(tex, UV); -} -" - -[sub_resource type="ImageTexture" id=2] - -[sub_resource type="ShaderMaterial" id=3] -resource_local_to_scene = true -shader = SubResource( 1 ) -shader_param/tex = SubResource( 2 ) - -[sub_resource type="Shader" id=4] -code = "shader_type canvas_item; -render_mode blend_disabled; - -uniform sampler2D tex; - -void fragment() { - vec4 sum = vec4(0.0); - for (int i = 0; i < 128; ++i) { - sum += step(abs(texture(tex, vec2(UV.x, float(i)/127.0))-UV.y), vec4(0.02)); - } - COLOR = sum/255.0; -} -" - -[sub_resource type="ViewportTexture" id=5] -viewport_path = NodePath("ViewportImage") - -[sub_resource type="ShaderMaterial" id=6] -resource_local_to_scene = true -shader = SubResource( 4 ) -shader_param/tex = SubResource( 5 ) - -[sub_resource type="Shader" id=7] -code = "shader_type canvas_item; -render_mode blend_disabled; - -uniform sampler2D tex; - -void fragment() { - vec4 sum = vec4(0.0); - for (int i = 0; i < 128; ++i) { - sum += texture(tex, vec2(float(i)/127.0, UV.x)); - } - COLOR = sum/255.0; -}" - -[sub_resource type="ViewportTexture" id=8] -viewport_path = NodePath("ViewportHistogram1") - -[sub_resource type="ShaderMaterial" id=9] -resource_local_to_scene = true -shader = SubResource( 7 ) -shader_param/tex = SubResource( 8 ) - -[sub_resource type="Shader" id=10] -code = "shader_type canvas_item; - -uniform sampler2D tex; -render_mode blend_disabled; - -void fragment() { - if (abs(fract(UV.y+0.05)) < 0.1) { - COLOR = vec4(vec3(UV.x), 1.0); - } else { - vec4 highest = vec4(0.0); - for (int i = 0; i < 128; ++i) { - highest = max(highest, texture(tex, vec2(float(i)/128.0, 0.0))); - } - vec4 value = step(vec4(0.95-UV.y)*highest/0.9, 0.5*(texture(tex, vec2(max(0.0, UV.x-0.015), 0.0))+texture(tex, vec2(min(1.0, UV.x+0.015), 0.0)))); - float alpha = step(0.1, dot(value, vec4(1.0))); - COLOR = vec4(mix(value.rgb, vec3(0.5), 0.3*value.a), alpha); - } -}" - -[sub_resource type="ViewportTexture" id=11] -viewport_path = NodePath("ViewportHistogram2") - -[sub_resource type="ShaderMaterial" id=12] -resource_local_to_scene = true -shader = SubResource( 10 ) -shader_param/tex = SubResource( 11 ) +[ext_resource path="res://material_maker/widgets/histogram/histogram.tscn" type="PackedScene" id=2] [node name="Tones" type="GraphNode"] anchor_right = 1.0 @@ -131,50 +41,6 @@ __meta__ = { "_edit_use_anchors_": false } -[node name="ViewportImage" type="Viewport" parent="."] -size = Vector2( 256, 256 ) -transparent_bg = true -hdr = false -usage = 0 -render_target_v_flip = true -render_target_update_mode = 3 - -[node name="ColorRect" type="ColorRect" parent="ViewportImage"] -material = SubResource( 3 ) -margin_right = 256.0 -margin_bottom = 128.0 -rect_min_size = Vector2( 256, 256 ) - -[node name="ViewportHistogram1" type="Viewport" parent="."] -size = Vector2( 128, 128 ) -own_world = true -transparent_bg = true -hdr = false -usage = 0 -render_target_v_flip = true -render_target_update_mode = 3 - -[node name="ColorRect" type="ColorRect" parent="ViewportHistogram1"] -material = SubResource( 6 ) -margin_right = 128.0 -margin_bottom = 128.0 -rect_min_size = Vector2( 128, 128 ) - -[node name="ViewportHistogram2" type="Viewport" parent="."] -size = Vector2( 128, 2 ) -transparent_bg = true -disable_3d = true -keep_3d_linear = true -usage = 0 -render_target_v_flip = true -render_target_update_mode = 3 - -[node name="ColorRect" type="ColorRect" parent="ViewportHistogram2"] -material = SubResource( 9 ) -margin_right = 128.0 -margin_bottom = 2.0 -rect_min_size = Vector2( 128, 2 ) - [node name="Mode" type="OptionButton" parent="."] margin_left = 16.0 margin_top = 24.0 @@ -194,8 +60,7 @@ __meta__ = { "_edit_use_anchors_": false } -[node name="Histogram" type="ColorRect" parent="."] -material = SubResource( 12 ) +[node name="Histogram" parent="." instance=ExtResource( 2 )] margin_left = 16.0 margin_top = 50.0 margin_right = 208.0 diff --git a/material_maker/widgets/histogram/histogram.gd b/material_maker/widgets/histogram/histogram.gd new file mode 100644 index 0000000..ce43ecc --- /dev/null +++ b/material_maker/widgets/histogram/histogram.gd @@ -0,0 +1,7 @@ +extends Control + +func update_histogram() -> void: + pass + +func get_image_texture() -> ImageTexture: + return $ViewportImage/ColorRect.material.get_shader_param("tex") diff --git a/material_maker/widgets/histogram/histogram.tscn b/material_maker/widgets/histogram/histogram.tscn new file mode 100644 index 0000000..ff72eb1 --- /dev/null +++ b/material_maker/widgets/histogram/histogram.tscn @@ -0,0 +1,157 @@ +[gd_scene load_steps=14 format=2] + +[ext_resource path="res://material_maker/widgets/histogram/histogram.gd" type="Script" id=1] + +[sub_resource type="Shader" id=1] +resource_local_to_scene = true +code = "shader_type canvas_item; +render_mode blend_disabled; + +uniform sampler2D tex; + +void fragment() { + COLOR = texture(tex, UV); +} +" + +[sub_resource type="ImageTexture" id=2] +resource_local_to_scene = true + +[sub_resource type="ShaderMaterial" id=3] +resource_local_to_scene = true +shader = SubResource( 1 ) +shader_param/tex = SubResource( 2 ) + +[sub_resource type="Shader" id=4] +code = "shader_type canvas_item; +render_mode blend_disabled; + +uniform sampler2D tex; + +void fragment() { + vec4 sum = vec4(0.0); + for (int i = 0; i < 128; ++i) { + sum += step(abs(texture(tex, vec2(UV.x, float(i)/127.0))-UV.y), vec4(0.02)); + } + COLOR = sum/255.0; +} +" + +[sub_resource type="ViewportTexture" id=5] +viewport_path = NodePath("ViewportImage") + +[sub_resource type="ShaderMaterial" id=6] +resource_local_to_scene = true +shader = SubResource( 4 ) +shader_param/tex = SubResource( 5 ) + +[sub_resource type="Shader" id=7] +code = "shader_type canvas_item; +render_mode blend_disabled; + +uniform sampler2D tex; + +void fragment() { + vec4 sum = vec4(0.0); + for (int i = 0; i < 128; ++i) { + sum += texture(tex, vec2(float(i)/127.0, UV.x)); + } + COLOR = sum/255.0; +}" + +[sub_resource type="ViewportTexture" id=8] +viewport_path = NodePath("ViewportHistogram1") + +[sub_resource type="ShaderMaterial" id=9] +resource_local_to_scene = true +shader = SubResource( 7 ) +shader_param/tex = SubResource( 8 ) + +[sub_resource type="Shader" id=10] +code = "shader_type canvas_item; + +uniform sampler2D tex; +render_mode blend_disabled; + +void fragment() { + if (abs(fract(UV.y+0.05)) < 0.1) { + COLOR = vec4(vec3(UV.x), 1.0); + } else { + vec4 highest = vec4(0.0); + for (int i = 0; i < 128; ++i) { + highest = max(highest, texture(tex, vec2(float(i)/128.0, 0.0))); + } + vec4 value = step(vec4(0.95-UV.y)*highest/0.9, 0.5*(texture(tex, vec2(max(0.0, UV.x-0.015), 0.0))+texture(tex, vec2(min(1.0, UV.x+0.015), 0.0)))); + float alpha = step(0.1, dot(value, vec4(1.0))); + COLOR = vec4(mix(value.rgb, vec3(0.5), 0.3*value.a), alpha); + } +}" + +[sub_resource type="ViewportTexture" id=11] +flags = 4 +viewport_path = NodePath("ViewportHistogram2") + +[sub_resource type="ShaderMaterial" id=12] +resource_local_to_scene = true +shader = SubResource( 10 ) +shader_param/tex = SubResource( 11 ) + +[node name="Histogram" type="Control"] +margin_right = 64.0 +margin_bottom = 64.0 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ViewportImage" type="Viewport" parent="."] +size = Vector2( 256, 256 ) +transparent_bg = true +hdr = false +usage = 0 +render_target_v_flip = true +render_target_update_mode = 3 + +[node name="ColorRect" type="ColorRect" parent="ViewportImage"] +material = SubResource( 3 ) +margin_right = 256.0 +margin_bottom = 128.0 +rect_min_size = Vector2( 256, 256 ) + +[node name="ViewportHistogram1" type="Viewport" parent="."] +size = Vector2( 128, 128 ) +own_world = true +transparent_bg = true +hdr = false +usage = 0 +render_target_v_flip = true +render_target_update_mode = 3 + +[node name="ColorRect" type="ColorRect" parent="ViewportHistogram1"] +material = SubResource( 6 ) +margin_right = 128.0 +margin_bottom = 128.0 +rect_min_size = Vector2( 128, 128 ) + +[node name="ViewportHistogram2" type="Viewport" parent="."] +size = Vector2( 128, 2 ) +transparent_bg = true +disable_3d = true +keep_3d_linear = true +usage = 0 +render_target_v_flip = true +render_target_update_mode = 3 + +[node name="ColorRect" type="ColorRect" parent="ViewportHistogram2"] +material = SubResource( 9 ) +margin_right = 128.0 +margin_bottom = 2.0 +rect_min_size = Vector2( 128, 2 ) + +[node name="Control" type="ColorRect" parent="."] +material = SubResource( 12 ) +anchor_right = 1.0 +anchor_bottom = 1.0 +__meta__ = { +"_edit_use_anchors_": false +} From 362747023998bab502800586d3a2aac74a5f3be6 Mon Sep 17 00:00:00 2001 From: RodZill4 Date: Sun, 22 Mar 2020 10:48:07 +0100 Subject: [PATCH 5/7] Added missing initialization of cursor positions in the Tones node --- material_maker/nodes/tones.gd | 61 +++++++++++++++++++++++---------- material_maker/nodes/tones.tscn | 1 + 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/material_maker/nodes/tones.gd b/material_maker/nodes/tones.gd index ad3c464..f8a496e 100644 --- a/material_maker/nodes/tones.gd +++ b/material_maker/nodes/tones.gd @@ -16,9 +16,10 @@ class Cursor: top = t func _ready() -> void: - rect_position = Vector2(position * get_parent().rect_size.x - 0.5*WIDTH, -2 if top else get_parent().rect_size.y+2-HEIGHT) + rect_position.y = -2 if top else get_parent().rect_size.y+2-HEIGHT + set_value(position) rect_size = Vector2(WIDTH, HEIGHT) - + func _draw() -> void: var polygon : PoolVector2Array if top: @@ -30,7 +31,7 @@ class Cursor: draw_colored_polygon(polygon, c) var outline_color = 0.0 if position > 0.5 else 1.0 draw_polyline(polygon, Color(outline_color, outline_color, outline_color), 1.0, true) - + func _gui_input(ev) -> void: if ev is InputEventMouseMotion && (ev.button_mask & 1) != 0: rect_position.x += ev.relative.x @@ -40,9 +41,10 @@ class Cursor: position = new_position get_parent().get_parent().update_value(self, position) update() - - func get_position() -> Vector2: - return rect_position.x / (get_parent().rect_size.x - WIDTH) + + func set_value(v : float): + position = v + rect_position.x = position * get_parent().rect_size.x - 0.5*WIDTH var cursor_in_min : Cursor var cursor_in_mid : Cursor @@ -69,18 +71,7 @@ func set_generator(g) -> void: .set_generator(g) generator.connect("parameter_changed", self, "on_parameter_changed") update_node() - -func update_node() -> void: - if has_node("NodeEditButtons"): - var r = $NodeEditButtons - remove_child(r) - r.free() - rect_size = Vector2(0, 0) - if generator.is_editable(): - var edit_buttons = preload("res://material_maker/nodes/edit_buttons.tscn").instance() - add_child(edit_buttons) - edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator") - set_slot(edit_buttons.get_index(), false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0)) + _on_Mode_item_selected(0) func on_parameter_changed(p, v) -> void: if p == "__input_changed__": @@ -91,6 +82,26 @@ func on_parameter_changed(p, v) -> void: result.copy_to_texture($Histogram.get_image_texture()) result.release() +func get_parameter(n : String) -> float: + var value = generator.get_parameter(n) + match $Mode.selected: + 1: + return value.r + 2: + return value.g + 3: + return value.b + 4: + return value.a + return (value.r+value.g+value.b)/3.0 + +func _on_Mode_item_selected(_id): + cursor_in_min.set_value(get_parameter("in_min")) + cursor_in_mid.set_value(get_parameter("in_mid")) + cursor_in_max.set_value(get_parameter("in_max")) + cursor_out_min.set_value(get_parameter("out_min")) + cursor_out_max.set_value(get_parameter("out_max")) + func set_parameter(n : String, v : float, d : float) -> void: var value = generator.get_parameter(n) match $Mode.selected: @@ -123,6 +134,20 @@ func update_value(control : Cursor, value : float) -> void: set_parameter("out_max", value, 1) get_parent().send_changed_signal() +# Everything below is only meant for editing the shader + +func update_node() -> void: + if has_node("NodeEditButtons"): + var r = $NodeEditButtons + remove_child(r) + r.free() + rect_size = Vector2(0, 0) + if generator.is_editable(): + var edit_buttons = preload("res://material_maker/nodes/edit_buttons.tscn").instance() + add_child(edit_buttons) + edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator") + set_slot(edit_buttons.get_index(), false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0)) + func edit_generator() -> void: if generator.has_method("edit"): generator.edit(self) diff --git a/material_maker/nodes/tones.tscn b/material_maker/nodes/tones.tscn index 12c3ae3..4e6ee22 100644 --- a/material_maker/nodes/tones.tscn +++ b/material_maker/nodes/tones.tscn @@ -76,3 +76,4 @@ rect_min_size = Vector2( 0, 4 ) __meta__ = { "_edit_use_anchors_": false } +[connection signal="item_selected" from="Mode" to="." method="_on_Mode_item_selected"] From 4502f2c03382d781c753c92f1ff620fe3f044d29 Mon Sep 17 00:00:00 2001 From: RodZill4 Date: Sun, 22 Mar 2020 15:08:48 +0100 Subject: [PATCH 6/7] Added button to Tones node to adjust levels automatically --- material_maker/icons/icons.svg | 43 ++++++++- material_maker/library/base.json | 44 +++++++++ material_maker/library/base/filter_tones.png | Bin 0 -> 776 bytes material_maker/nodes/tones.gd | 91 ++++++++---------- material_maker/nodes/tones.tscn | 30 +++++- material_maker/widgets/histogram/histogram.gd | 3 + .../widgets/histogram/histogram.tscn | 2 +- 7 files changed, 157 insertions(+), 56 deletions(-) create mode 100644 material_maker/library/base/filter_tones.png diff --git a/material_maker/icons/icons.svg b/material_maker/icons/icons.svg index ab74fb5..f4a511c 100644 --- a/material_maker/icons/icons.svg +++ b/material_maker/icons/icons.svg @@ -55,9 +55,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="40.459032" - inkscape:cx="12.31719" - inkscape:cy="41.781829" + inkscape:zoom="7.152214" + inkscape:cx="122.70346" + inkscape:cy="36.247815" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" @@ -605,5 +605,42 @@ sodipodi:end="0.0018129957" sodipodi:open="true" d="m 15.411452,304.10377 a 7.4148879,7.4346347 0 0 1 -7.4502054,7.39166 7.4148879,7.4346347 0 0 1 -7.37939334,-7.46273 7.4148879,7.4346347 0 0 1 7.43561054,-7.40642 7.4148879,7.4346347 0 0 1 7.3941002,7.44808" /> + + + + + diff --git a/material_maker/library/base.json b/material_maker/library/base.json index a2962cc..b792392 100644 --- a/material_maker/library/base.json +++ b/material_maker/library/base.json @@ -2289,6 +2289,50 @@ "tree_item": "Filter/AdjustHSV", "type": "adjust_hsv" }, + { + "collapsed": true, + "icon": "filter_tones", + "name": "tones", + "parameters": { + "in_max": { + "a": 1, + "b": 1, + "g": 1, + "r": 1, + "type": "Color" + }, + "in_mid": { + "a": 0.5, + "b": 0.5, + "g": 0.5, + "r": 0.5, + "type": "Color" + }, + "in_min": { + "a": 0, + "b": 0, + "g": 0, + "r": 0, + "type": "Color" + }, + "out_max": { + "a": 1, + "b": 1, + "g": 1, + "r": 1, + "type": "Color" + }, + "out_min": { + "a": 0, + "b": 0, + "g": 0, + "r": 0, + "type": "Color" + } + }, + "tree_item": "Filter/Tones", + "type": "tones" + }, { "collapsed": true, "icon": "filter_greyscale", diff --git a/material_maker/library/base/filter_tones.png b/material_maker/library/base/filter_tones.png new file mode 100644 index 0000000000000000000000000000000000000000..b2809d07d7369cb75b131bcfaf69397c86835197 GIT binary patch literal 776 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=EX7WqAsj$Z!;#Vf2?p z><3}SFw?)MfP#`Gt`Q}{`DrEPiAAXl<>lpinR(g8$%zH2dih1^v)|cBF)%Q-db&7< zRLprhYkzidphVkz{a%l)9IrH#IJjh&a4Bho2u$I7#jByF_m9;tD82n$Q?R>Z!He8E zJ_{6f?a)5x=~AF+#gVD0)imL^rNly(y$|OVPtvzP$1JJ$eb4vm_mgENP2iXpqBWI! z)hs4=Znx+ITiq6aJi5J^U-drsidW2C_iYYH3hsPueP2AE@j&AB1*_z^4DNRqJ$RkV zod0{xPL?w)^IrP|Fs}Nw?q*Kh$>_-{C(RS|p2WyIoXEK=d*@W#ncKA+v*(4kXxq;}H* z4vqthn>#ALo8M=${lhZJE?bU?dm&rjtOmceVbxQ&FNj;8U;e#bz%7w`h7fCn_=aUX zXP87EI5ftv?P0UyTXe-hlR5j3V8E332Ucz1jMrG#bTX~sjt~afixhfbg~9p@ zzPC?|KJaqR*WaJ@)ReeAC+&G-Tx|CK&aYopd2yk?{|5frxa!{t%lf46j_Vte@3w2R zH=dUJDS6)Jz)z)aZ-?8-5x3R#m7)(!%Z>}(`;7Um&<372B0Oac&kwY9tYMhVcQ|_0 yu34!!S9NTW`7}Fn+FAzbyLxk*e#$2NG`GH3efrvb%g4Y}%i!ti=d#Wzp$P!V9ZOpP literal 0 HcmV?d00001 diff --git a/material_maker/nodes/tones.gd b/material_maker/nodes/tones.gd index f8a496e..aff0e33 100644 --- a/material_maker/nodes/tones.gd +++ b/material_maker/nodes/tones.gd @@ -36,11 +36,13 @@ class Cursor: if ev is InputEventMouseMotion && (ev.button_mask & 1) != 0: rect_position.x += ev.relative.x rect_position.x = min(max(-0.5*WIDTH, rect_position.x), get_parent().rect_size.x-0.5*WIDTH) - var new_position = (rect_position.x+0.5*WIDTH)/get_parent().rect_size.x - if new_position != position: - position = new_position - get_parent().get_parent().update_value(self, position) - update() + update_value((rect_position.x+0.5*WIDTH)/get_parent().rect_size.x) + + func update_value(p : float) -> void: + if p != position: + set_value(p) + get_parent().get_parent().update_value(self, position) + update() func set_value(v : float): position = v @@ -70,7 +72,6 @@ func _ready() -> void: func set_generator(g) -> void: .set_generator(g) generator.connect("parameter_changed", self, "on_parameter_changed") - update_node() _on_Mode_item_selected(0) func on_parameter_changed(p, v) -> void: @@ -84,7 +85,7 @@ func on_parameter_changed(p, v) -> void: func get_parameter(n : String) -> float: var value = generator.get_parameter(n) - match $Mode.selected: + match $Bar/Mode.selected: 1: return value.r 2: @@ -104,7 +105,7 @@ func _on_Mode_item_selected(_id): func set_parameter(n : String, v : float, d : float) -> void: var value = generator.get_parameter(n) - match $Mode.selected: + match $Bar/Mode.selected: 0: value.r = v value.g = v @@ -134,44 +135,36 @@ func update_value(control : Cursor, value : float) -> void: set_parameter("out_max", value, 1) get_parent().send_changed_signal() -# Everything below is only meant for editing the shader - -func update_node() -> void: - if has_node("NodeEditButtons"): - var r = $NodeEditButtons - remove_child(r) - r.free() - rect_size = Vector2(0, 0) - if generator.is_editable(): - var edit_buttons = preload("res://material_maker/nodes/edit_buttons.tscn").instance() - add_child(edit_buttons) - edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator") - set_slot(edit_buttons.get_index(), false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0)) - -func edit_generator() -> void: - if generator.has_method("edit"): - generator.edit(self) - -func update_generator(shader_model : Dictionary) -> void: - generator.set_shader_model(shader_model) - update_node() - -func save_generator() -> void: - 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("*.mmg;Material Maker Generator") - dialog.connect("file_selected", self, "do_save_generator") - dialog.popup_centered() - -func do_save_generator(file_name : String) -> void: - var file = File.new() - if file.open(file_name, File.WRITE) == OK: - var data = generator.serialize() - data.name = file_name.get_file().get_basename() - data.node_position = { x=0, y=0 } - file.store_string(JSON.print(data, "\t", true)) - file.close() - mm_loader.update_predefined_generators() +func _on_Auto_pressed(): + var histogram = $Histogram.get_histogram_texture().get_data() + histogram.lock() + var in_min : int = -1 + var in_mid : int = -1 + var in_mid_value : float = 0 + var in_max : int = -1 + var histogram_size = histogram.get_size().x + for i in range(histogram_size): + var color : Color = histogram.get_pixel(i, 0) + var value : float + match $Bar/Mode.selected: + 0: + value = (color.r+color.g+color.b)/3.0 + 1: + value = color.r + 2: + value = color.g + 3: + value = color.b + 4: + value = color.a + if value > 0.0: + if in_min == -1: + in_min = i + in_max = i + if in_mid_value < value: + in_mid = i + in_mid_value = value + histogram.unlock() + cursor_in_min.update_value(in_min/(histogram_size-1)) + cursor_in_mid.update_value(in_mid/(histogram_size-1)) + cursor_in_max.update_value(in_max/(histogram_size-1)) diff --git a/material_maker/nodes/tones.tscn b/material_maker/nodes/tones.tscn index 4e6ee22..bd5f634 100644 --- a/material_maker/nodes/tones.tscn +++ b/material_maker/nodes/tones.tscn @@ -1,7 +1,13 @@ -[gd_scene load_steps=3 format=2] +[gd_scene load_steps=5 format=2] [ext_resource path="res://material_maker/nodes/tones.gd" type="Script" id=1] [ext_resource path="res://material_maker/widgets/histogram/histogram.tscn" type="PackedScene" id=2] +[ext_resource path="res://material_maker/icons/icons.svg" type="Texture" id=3] + +[sub_resource type="AtlasTexture" id=1] +flags = 4 +atlas = ExtResource( 3 ) +region = Rect2( 16, 80, 16, 16 ) [node name="Tones" type="GraphNode"] anchor_right = 1.0 @@ -41,15 +47,32 @@ __meta__ = { "_edit_use_anchors_": false } -[node name="Mode" type="OptionButton" parent="."] +[node name="Bar" type="HBoxContainer" parent="."] margin_left = 16.0 margin_top = 24.0 margin_right = 208.0 margin_bottom = 44.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Mode" type="OptionButton" parent="Bar"] +margin_right = 172.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 text = "Luminance" items = [ "Luminance", null, false, 0, null, "Red", null, false, 1, null, "Green", null, false, 2, null, "Blue", null, false, 3, null, "Alpha", null, false, 4, null ] selected = 0 +[node name="Auto" type="TextureButton" parent="Bar"] +margin_left = 176.0 +margin_top = 2.0 +margin_right = 192.0 +margin_bottom = 18.0 +hint_tooltip = "Set levels automatically" +size_flags_vertical = 4 +texture_normal = SubResource( 1 ) + [node name="Spacer1" type="Control" parent="."] margin_left = 16.0 margin_top = 45.0 @@ -76,4 +99,5 @@ rect_min_size = Vector2( 0, 4 ) __meta__ = { "_edit_use_anchors_": false } -[connection signal="item_selected" from="Mode" to="." method="_on_Mode_item_selected"] +[connection signal="item_selected" from="Bar/Mode" to="." method="_on_Mode_item_selected"] +[connection signal="pressed" from="Bar/Auto" to="." method="_on_Auto_pressed"] diff --git a/material_maker/widgets/histogram/histogram.gd b/material_maker/widgets/histogram/histogram.gd index ce43ecc..d2ae909 100644 --- a/material_maker/widgets/histogram/histogram.gd +++ b/material_maker/widgets/histogram/histogram.gd @@ -5,3 +5,6 @@ func update_histogram() -> void: func get_image_texture() -> ImageTexture: return $ViewportImage/ColorRect.material.get_shader_param("tex") + +func get_histogram_texture() -> ImageTexture: + return $Control.material.get_shader_param("tex") diff --git a/material_maker/widgets/histogram/histogram.tscn b/material_maker/widgets/histogram/histogram.tscn index ff72eb1..02670ed 100644 --- a/material_maker/widgets/histogram/histogram.tscn +++ b/material_maker/widgets/histogram/histogram.tscn @@ -81,7 +81,7 @@ void fragment() { for (int i = 0; i < 128; ++i) { highest = max(highest, texture(tex, vec2(float(i)/128.0, 0.0))); } - vec4 value = step(vec4(0.95-UV.y)*highest/0.9, 0.5*(texture(tex, vec2(max(0.0, UV.x-0.015), 0.0))+texture(tex, vec2(min(1.0, UV.x+0.015), 0.0)))); + vec4 value = step(vec4(0.95-UV.y)*highest/0.9, texture(tex, vec2(UV.x, 0.0))); float alpha = step(0.1, dot(value, vec4(1.0))); COLOR = vec4(mix(value.rgb, vec3(0.5), 0.3*value.a), alpha); } From e15b939258ab79ea135f6e2b9c717d534882cb07 Mon Sep 17 00:00:00 2001 From: RodZill4 Date: Fri, 27 Mar 2020 09:08:03 +0100 Subject: [PATCH 7/7] Added documentation for the Tones node --- .../doc/images/node_filter_tones.png | Bin 0 -> 6853 bytes material_maker/doc/node_filter_tones.rst | 38 ++++++++++++++++++ material_maker/doc/nodes_filter.rst | 1 + 3 files changed, 39 insertions(+) create mode 100644 material_maker/doc/images/node_filter_tones.png create mode 100644 material_maker/doc/node_filter_tones.rst diff --git a/material_maker/doc/images/node_filter_tones.png b/material_maker/doc/images/node_filter_tones.png new file mode 100644 index 0000000000000000000000000000000000000000..a2acbf26d7ef3b25144dde5886c10c9272b096b3 GIT binary patch literal 6853 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 literal 0 HcmV?d00001 diff --git a/material_maker/doc/node_filter_tones.rst b/material_maker/doc/node_filter_tones.rst new file mode 100644 index 0000000..e4cbb26 --- /dev/null +++ b/material_maker/doc/node_filter_tones.rst @@ -0,0 +1,38 @@ +Tones node +~~~~~~~~~~ + +The **Tones** node provides an easy interface to adjust the tones of its input. It can be applied +homogeneously to the R, G and B channels, or separately on R, G, B and A. + +The nodes shows an histogram of all channels of its input, and 3 cursors to modify the input +adjustment at the top, and 2 cursors to modify the output adjustment. + +.. image:: images/node_filter_tones.png + :align: center + +Inputs +++++++ + +The **Tones** node requires an RGBA input texture. + +Outputs ++++++++ + +The **Tones** node provides a single RGBA texture. + +Parameters +++++++++++ + +At the top of the node, a control can be used to select the active channel (Luminance, Red, +Green, Blue and Alpha). + +The button can be used to adjust automatically the Tones to the node's input to obtain better +contrast. + +The 3 cursors at the top of the histogram can be used to select the input colors that will be +remapped to black (value = 0 for single channel), mid-grey (value = 0.5) and white (value = 1). +Values between those defined by cursors are interpolated linearly, and all values are clamped +between 0 and 1. + +The 2 bottom cursors define the output color for black (value = 0 for single channel) and +white (value = 1). \ No newline at end of file diff --git a/material_maker/doc/nodes_filter.rst b/material_maker/doc/nodes_filter.rst index 06d11e9..1d04094 100644 --- a/material_maker/doc/nodes_filter.rst +++ b/material_maker/doc/nodes_filter.rst @@ -9,6 +9,7 @@ The filter nodes accept one or several inputs and generate one or several images node_filter_invert node_filter_brightness_contrast node_filter_adjust_hsv + node_filter_tones node_filter_greyscale node_filter_colorize node_filter_combine