diff --git a/addons/material_maker/nodes/adjust_hsv.mmn b/addons/material_maker/nodes/adjust_hsv.mmn new file mode 100644 index 0000000..a980898 --- /dev/null +++ b/addons/material_maker/nodes/adjust_hsv.mmn @@ -0,0 +1 @@ +{"global":"vec3 rgb_to_hsv(vec3 c) {\n\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n\tvec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy);\n\tvec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx);\n\n\tfloat d = q.x - min(q.w, q.y);\n\tfloat e = 1.0e-10;\n\treturn vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nvec3 hsv_to_rgb(vec3 c) {\n\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n\treturn c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\n","inputs":[{"default":"vec3(1.0)","label":"","name":"in","type":"rgb"}],"instance":"vec3 $(name)_f(vec3 c) {\n\tvec3 hsv = rgb_to_hsv(c);\n\treturn hsv_to_rgb(vec3(fract(hsv.x+$(hue)), clamp(hsv.y*$(saturation), 0.0, 1.0), clamp(hsv.z*$(value), 0.0, 1.0)));\n}","name":"AdjustHSV","outputs":[{"rgb":"$(name)_f($in($(uv)))"}],"parameters":[{"default":0,"label":"Hue","max":0.5,"min":-0.5,"name":"hue","step":0,"type":"float"},{"default":1,"label":"Saturation","max":2,"min":0,"name":"saturation","step":0,"type":"float"},{"default":1,"label":"Value","max":2,"min":0,"name":"value","step":0,"type":"float"}]} \ No newline at end of file diff --git a/addons/material_maker/nodes/node_generic.gd b/addons/material_maker/nodes/node_generic.gd index 925bead..b87cdd9 100644 --- a/addons/material_maker/nodes/node_generic.gd +++ b/addons/material_maker/nodes/node_generic.gd @@ -77,7 +77,7 @@ func update_node(data): control.selected = 0 if !p.has("default") else p.default-p.first elif p.type == "enum": control = OptionButton.new() - for i in p.values.size(): + 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 @@ -105,8 +105,25 @@ func update_node(data): 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 model_data.outputs.size(): + 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) @@ -119,16 +136,54 @@ func update_node(data): color_right = Color(0.0, 0.5, 0.0, 0.5) elif output.has("f"): enable_right = true - set_slot(i, false, 0, color_right, enable_right, 0, color_right) + 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 subst(string, uv = ""): - string = string.replace("$(name)", name) - string = string.replace("$(seed)", str(get_seed())) - string = string.replace("$(uv)", uv) +func replace_input(string, input, type, src, context = null): + var required_defs = "" + var required_code = "" + var keyword = "$%s(" % input + while true: + var position = string.find(keyword) + if position == -1: + break + var parenthesis_level = 0 + var parameter_begin = position+keyword.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: + parameter_end = i + break + else: + parenthesis_level -= 1 + if parameter_end != -1: + var uv = string.substr(parameter_begin, parameter_end-parameter_begin) + var src_code = src.get_shader_code(uv) + required_defs += src_code.defs + required_code += src_code.code + string = string.replace(string.substr(position, parameter_end-position+1), src_code[type]) + else: + print("syntax error") + break + return { string=string, defs=required_defs, code=required_code } + +func replace_variable(string, variable, value): + string = string.replace("$(%s)" % variable, value) + return string + +func subst(string, uv = "", context = null): + 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"): @@ -144,32 +199,41 @@ func subst(string, uv = ""): elif p.type == "color": value_string = "vec4(%.9f, %.9f, %.9f, %.9f)" % [ value.r, value.g, value.b, value.a ] if value_string != null: - string = string.replace("$(%s)" % p.name, value_string) - return string + 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) + if source == null: + string = replace_variable(string, input.name, input.default) + else: + var result = replace_input(string, input.name, input.type, source, context) + 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] if model_data.has("instance") && generated_variants.empty(): - rv.defs = subst(model_data.instance) + rv.defs = subst(model_data.instance).string var variant_index = generated_variants.find(variant_string) if variant_index == -1: variant_index = generated_variants.size() generated_variants.append(variant_string) - if output.has("rgba"): - rv.code += "vec4 %s_%d_%d_rgba = %s;\n" % [ name, slot, variant_index, subst(output.rgba, uv) ] - if output.has("rgb"): - rv.code += "vec3 %s_%d_%d_rgb = %s;\n" % [ name, slot, variant_index, subst(output.rgb, uv) ] - if output.has("f"): - rv.code += "float %s_%d_%d_f = %s;\n" % [ name, slot, variant_index, subst(output.f, uv) ] - if output.has("rgba"): - rv.rgba = "%s_%d_%d_rgba" % [ name, slot, variant_index ] - if output.has("rgb"): - rv.rgb = "%s_%d_%d_rgb" % [ name, slot, variant_index ] - if output.has("f"): - rv.f = "%s_%d_%d_f" % [ name, slot, variant_index ] + for t in output_info: + if output.has(t.field): + var subst_output = subst(output[t.field], uv, rv) + 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(): diff --git a/addons/material_maker/widgets/node_editor/input.gd b/addons/material_maker/widgets/node_editor/input.gd index 110290e..2f0cf6c 100644 --- a/addons/material_maker/widgets/node_editor/input.gd +++ b/addons/material_maker/widgets/node_editor/input.gd @@ -4,5 +4,26 @@ extends HBoxContainer func _ready(): pass +func set_model_data(data): + $Name.text = data.name + $Label.text = data.label + if data.type == "rgb": + $Type.selected = 1 + elif data.type == "rgba": + $Type.selected = 2 + else: + $Type.selected = 0 + $Default.text = data.default + +func get_model_data(): + var data = { name=$Name.text, label=$Label.text, default=$Default.text } + if $Type.selected == 1: + data.type = "rgb" + elif $Type.selected == 2: + data.type = "rgba" + else: + data.type = "f" + return data + func _on_Delete_pressed(): queue_free() diff --git a/addons/material_maker/widgets/node_editor/input.tscn b/addons/material_maker/widgets/node_editor/input.tscn index 595861a..dce2a0a 100644 --- a/addons/material_maker/widgets/node_editor/input.tscn +++ b/addons/material_maker/widgets/node_editor/input.tscn @@ -3,7 +3,7 @@ [ext_resource path="res://addons/material_maker/widgets/node_editor/input.gd" type="Script" id=1] [ext_resource path="res://addons/material_maker/icons/minus.png" type="Texture" id=2] -[node name="Parameter" type="HBoxContainer"] +[node name="Parameter" type="HBoxContainer" index="0"] anchor_left = 0.0 anchor_top = 0.0 @@ -123,7 +123,7 @@ group = null text = "GreyScale" flat = false align = 0 -items = [ "GreyScale", null, false, 0, null, "Color", null, false, 1, null ] +items = [ "GreyScale", null, false, 0, null, "Color", null, false, 1, null, "RGBA", null, false, -1, null ] selected = 0 _sections_unfolded = [ "Focus", "Hint", "Rect" ] diff --git a/addons/material_maker/widgets/node_editor/node_editor.gd b/addons/material_maker/widgets/node_editor/node_editor.gd index f47cb34..d5ea398 100644 --- a/addons/material_maker/widgets/node_editor/node_editor.gd +++ b/addons/material_maker/widgets/node_editor/node_editor.gd @@ -21,9 +21,12 @@ func set_model_data(data): if data.has("parameters"): for p in data.parameters: add_item($Sizer/Tabs/General/Parameters/Sizer, ParameterEditor).set_model_data(p) + if data.has("inputs"): + for i in data.inputs: + add_item($Sizer/Tabs/General/Inputs/Sizer, InputEditor).set_model_data(i) if data.has("outputs"): for o in data.outputs: - add_item($Sizer/Tabs/General/Outputs/Sizer, OutputEditor).set_model_data(o) + add_item($Sizer/Tabs/Outputs/Outputs/Sizer, OutputEditor).set_model_data(o) if data.has("global"): $Sizer/Tabs/Global.text = data.global if data.has("instance"): @@ -39,8 +42,12 @@ func get_model_data(): for p in $Sizer/Tabs/General/Parameters/Sizer.get_children(): if p.has_method("get_model_data"): data.parameters.append(p.get_model_data()) + data.inputs = [] + for i in $Sizer/Tabs/General/Inputs/Sizer.get_children(): + if i.has_method("get_model_data"): + data.inputs.append(i.get_model_data()) data.outputs = [] - for o in $Sizer/Tabs/General/Outputs/Sizer.get_children(): + for o in $Sizer/Tabs/Outputs/Outputs/Sizer.get_children(): if o.has_method("get_model_data"): data.outputs.append(o.get_model_data()) return data @@ -52,7 +59,7 @@ func _on_AddInput_pressed(): add_item($Sizer/Tabs/General/Inputs/Sizer, InputEditor) func _on_AddOutput_pressed(): - add_item($Sizer/Tabs/General/Outputs/Sizer, OutputEditor) + add_item($Sizer/Tabs/Outputs/Outputs/Sizer, OutputEditor) func _on_OK_pressed(): emit_signal("node_changed", get_model_data()) diff --git a/addons/material_maker/widgets/node_editor/node_editor.tscn b/addons/material_maker/widgets/node_editor/node_editor.tscn index d1bd303..59ddf75 100644 --- a/addons/material_maker/widgets/node_editor/node_editor.tscn +++ b/addons/material_maker/widgets/node_editor/node_editor.tscn @@ -222,14 +222,13 @@ _sections_unfolded = [ "Size Flags" ] [node name="LabelInputs" type="Label" parent="Sizer/Tabs/General" index="3"] -visible = false anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_top = 176.0 -margin_right = 718.0 -margin_bottom = 190.0 +margin_top = 185.0 +margin_right = 825.0 +margin_bottom = 199.0 rect_pivot_offset = Vector2( 0, 0 ) rect_clip_content = false mouse_filter = 2 @@ -244,14 +243,13 @@ _sections_unfolded = [ "Size Flags" ] [node name="Inputs" type="ScrollContainer" parent="Sizer/Tabs/General" index="4"] -visible = false anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_top = 139.0 -margin_right = 718.0 -margin_bottom = 228.0 +margin_top = 203.0 +margin_right = 825.0 +margin_bottom = 338.0 rect_pivot_offset = Vector2( 0, 0 ) rect_clip_content = true mouse_filter = 0 @@ -271,7 +269,7 @@ anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_right = 718.0 +margin_right = 825.0 margin_bottom = 22.0 rect_pivot_offset = Vector2( 0, 0 ) rect_clip_content = false @@ -306,15 +304,33 @@ flat = true align = 1 _sections_unfolded = [ "Size Flags" ] -[node name="LabelOutputs" type="Label" parent="Sizer/Tabs/General" index="5"] +[node name="Outputs" type="VBoxContainer" parent="Sizer/Tabs" index="1"] + +visible = false +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 4.0 +margin_top = 32.0 +margin_right = -4.0 +margin_bottom = -4.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 1 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +alignment = 0 + +[node name="LabelOutputs" type="Label" parent="Sizer/Tabs/Outputs" index="0"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_top = 185.0 margin_right = 825.0 -margin_bottom = 199.0 +margin_bottom = 14.0 rect_pivot_offset = Vector2( 0, 0 ) rect_clip_content = false mouse_filter = 2 @@ -327,13 +343,13 @@ lines_skipped = 0 max_lines_visible = -1 _sections_unfolded = [ "Size Flags" ] -[node name="Outputs" type="ScrollContainer" parent="Sizer/Tabs/General" index="6"] +[node name="Outputs" type="ScrollContainer" parent="Sizer/Tabs/Outputs" index="1"] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 anchor_bottom = 0.0 -margin_top = 203.0 +margin_top = 18.0 margin_right = 825.0 margin_bottom = 338.0 rect_pivot_offset = Vector2( 0, 0 ) @@ -349,7 +365,7 @@ scroll_vertical = 0 scroll_deadzone = 0 _sections_unfolded = [ "Size Flags" ] -[node name="Sizer" type="VBoxContainer" parent="Sizer/Tabs/General/Outputs" index="0"] +[node name="Sizer" type="VBoxContainer" parent="Sizer/Tabs/Outputs/Outputs" index="0"] anchor_left = 0.0 anchor_top = 0.0 @@ -366,7 +382,7 @@ size_flags_vertical = 1 alignment = 0 _sections_unfolded = [ "Size Flags" ] -[node name="AddOutput" type="Button" parent="Sizer/Tabs/General/Outputs/Sizer" index="0"] +[node name="AddOutput" type="Button" parent="Sizer/Tabs/Outputs/Outputs/Sizer" index="0"] anchor_left = 0.0 anchor_top = 0.0 @@ -390,7 +406,7 @@ flat = true align = 1 _sections_unfolded = [ "Size Flags" ] -[node name="Global" type="TextEdit" parent="Sizer/Tabs" index="1"] +[node name="Global" type="TextEdit" parent="Sizer/Tabs" index="2"] visible = false anchor_left = 0.0 @@ -425,7 +441,7 @@ caret_blink = false caret_blink_speed = 0.65 caret_moving_by_right_click = true -[node name="Instance" type="TextEdit" parent="Sizer/Tabs" index="2"] +[node name="Instance" type="TextEdit" parent="Sizer/Tabs" index="3"] visible = false anchor_left = 0.0 @@ -532,7 +548,7 @@ align = 1 [connection signal="pressed" from="Sizer/Tabs/General/Inputs/Sizer/AddInput" to="." method="_on_AddInput_pressed"] -[connection signal="pressed" from="Sizer/Tabs/General/Outputs/Sizer/AddOutput" to="." method="_on_AddOutput_pressed"] +[connection signal="pressed" from="Sizer/Tabs/Outputs/Outputs/Sizer/AddOutput" to="." method="_on_AddOutput_pressed"] [connection signal="pressed" from="Sizer/HBoxContainer/OK" to="." method="_on_OK_pressed"]