diff --git a/game/addons/mat_maker_gd/nodes/bases/curve_base.gd b/game/addons/mat_maker_gd/nodes/bases/curve_base.gd new file mode 100644 index 00000000..157f0e83 --- /dev/null +++ b/game/addons/mat_maker_gd/nodes/bases/curve_base.gd @@ -0,0 +1,98 @@ +tool +extends MMNode + +class Point: + var p : Vector2 + var ls : float + var rs : float + func _init(x : float, y : float, nls : float, nrs : float) -> void: + p = Vector2(x, y) + ls = nls + rs = nrs + +var points = [ Point.new(0.0, 0.0, 0.0, 1.0), Point.new(1.0, 1.0, 1.0, 0.0) ] + +func to_string() -> String: + var rv = PoolStringArray() + for p in points: + rv.append("("+str(p.x)+","+str(p.y)+","+str(p.ls)+","+str(p.rs)+")") + return rv.join(",") + +func clear() -> void: + points.clear() + +func add_point(x : float, y : float, ls : float = INF, rs : float = INF) -> void: + for i in points.size(): + if x < points[i].p.x: + if ls == INF: + ls == 0 + if rs == INF: + rs == 0 + points.insert(i, Point.new(x, y, ls, rs)) + return + points.append(Point.new(x, y, ls, rs)) + +func remove_point(index : int) -> bool: + if index <= 0 or index >= points.size() - 1: + return false + else: + points.remove(index) + return true + +func get_point_count() -> int: + return points.size() + +func set_point(i : int, v : Point) -> void: + points[i] = v + +func get_shader_params(name) -> Dictionary: + var rv = {} + for i in range(points.size()): + rv["p_"+name+"_"+str(i)+"_x"] = points[i].p.x + rv["p_"+name+"_"+str(i)+"_y"] = points[i].p.y + rv["p_"+name+"_"+str(i)+"_ls"] = points[i].ls + rv["p_"+name+"_"+str(i)+"_rs"] = points[i].rs + return rv + +func get_shader(name) -> String: + var shader + shader = "float "+name+"_curve_fct(float x) {\n" + for i in range(points.size()-1): + if i < points.size()-2: + shader += "if (x <= p_"+name+"_"+str(i+1)+"_x) " + shader += "{\n" + shader += "float dx = x - p_"+name+"_"+str(i)+"_x;\n" + shader += "float d = p_"+name+"_"+str(i+1)+"_x - p_"+name+"_"+str(i)+"_x;\n" + shader += "float t = dx/d;\n" + shader += "float omt = (1.0 - t);\n" + shader += "float omt2 = omt * omt;\n" + shader += "float omt3 = omt2 * omt;\n" + shader += "float t2 = t * t;\n" + shader += "float t3 = t2 * t;\n" + shader += "d /= 3.0;\n" + shader += "float y1 = p_"+name+"_"+str(i)+"_y;\n" + shader += "float yac = p_"+name+"_"+str(i)+"_y + d*p_"+name+"_"+str(i)+"_rs;\n" + shader += "float ybc = p_"+name+"_"+str(i+1)+"_y - d*p_"+name+"_"+str(i+1)+"_ls;\n" + shader += "float y2 = p_"+name+"_"+str(i+1)+"_y;\n" + shader += "return y1*omt3 + yac*omt2*t*3.0 + ybc*omt*t2*3.0 + y2*t3;\n" + shader += "}\n" + shader += "}\n" + return shader + +func serialize() -> Dictionary: + var rv = [] + for p in points: + rv.append({ x=p.p.x, y=p.p.y, ls=p.ls, rs=p.rs }) + return { type="Curve", points=rv } + +func deserialize(v) -> void: + clear() + if typeof(v) == TYPE_DICTIONARY and v.has("type") and v.type == "Curve": + for p in v.points: + add_point(p.x, p.y, p.ls, p.rs) + elif typeof(v) == TYPE_OBJECT and v.get_script() == get_script(): + clear() + for p in v.points: + add_point(p.p.x, p.p.y, p.ls, p.rs) + else: + print("Cannot deserialize curve") diff --git a/game/addons/mat_maker_gd/nodes/bases/polygon_base.gd b/game/addons/mat_maker_gd/nodes/bases/polygon_base.gd new file mode 100644 index 00000000..ce922207 --- /dev/null +++ b/game/addons/mat_maker_gd/nodes/bases/polygon_base.gd @@ -0,0 +1,71 @@ +tool +extends MMNode + +var points : Array = [Vector2(0.2, 0.2), Vector2(0.7, 0.4), Vector2(0.4, 0.7)] + +func to_string() -> String: + var rv = PoolStringArray() + for p in points: + rv.append("("+str(p.x)+","+str(p.y)+")") + return rv.join(",") + +func clear() -> void: + points.clear() + +func add_point(x : float, y : float, closed : bool = true) -> void: + var p : Vector2 = Vector2(x, y) + var points_count = points.size() + if points_count < 3: + points.append(p) + return + var min_length : float = (p-Geometry.get_closest_point_to_segment_2d(p, points[0], points[points_count-1])).length() + var insert_point = 0 + for i in points_count-1: + var length = (p-Geometry.get_closest_point_to_segment_2d(p, points[i], points[i+1])).length() + if length < min_length: + min_length = length + insert_point = i+1 + if !closed and insert_point == 0 and (points[0]-p).length() > (points[points_count-1]-p).length(): + insert_point = points_count + points.insert(insert_point, p) + +func remove_point(index : int) -> bool: + var s = points.size() + if s < 4 or index < 0 or index >= s: + return false + else: + points.remove(index) + return true + +func get_point_count() -> int: + return points.size() + +func get_point(i : int) -> Vector2: + return points[i] + +func set_point(i : int, v : Vector2) -> void: + points[i] = v + +func get_shader() -> String: + var elements : PoolStringArray = PoolStringArray() + for p in points: + elements.append("vec2(%.9f, %.9f)" % [p.x, p.y]) + return "{"+elements.join(", ")+"}" + +func serialize() -> Dictionary: + var rv = [] + for p in points: + rv.append({ x=p.x, y=p.y }) + return { type="Polygon", points=rv } + +func deserialize(v) -> void: + clear() + if typeof(v) == TYPE_DICTIONARY and v.has("type") and v.type == "Polygon": + for p in v.points: + points.push_back(Vector2(p.x, p.y)) + elif typeof(v) == TYPE_OBJECT and v.get_script() == get_script(): + clear() + for p in v.points: + points.push_back(Vector2(p.x, p.y)) + else: + print("Cannot deserialize polygon") diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/control_point.gd b/game/addons/mat_maker_gd/widgets/curve_edit/control_point.gd new file mode 100644 index 00000000..9c178aa0 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/control_point.gd @@ -0,0 +1,66 @@ +extends Control + +var MMCurve = preload("res://addons/mat_maker_gd/nodes/bases/curve_base.gd") + +var moving : bool = false + +var min_x : float +var max_x : float +var min_y : float +var max_y : float + +const OFFSET : Vector2 = Vector2(3, 3) + +signal moved(index) +signal removed(index) + +func _ready(): + pass # Replace with function body. + +func _draw(): + var current_theme : Theme = get_node("/root/MainWindow").theme + var color : Color = current_theme.get_color("font_color", "Label") + for c in get_children(): + if c.visible: + draw_line(OFFSET, c.rect_position+OFFSET, color) + draw_rect(Rect2(0, 0, 7, 7), color) + +#p : MMCurve.Point +func initialize(p) -> void: + rect_position = get_parent().transform_point(p.p)-OFFSET + if p.ls != INF: + $LeftSlope.rect_position = $LeftSlope.distance*(get_parent().rect_size*Vector2(1.0, -p.ls)).normalized() + if p.rs != INF: + $RightSlope.rect_position = $RightSlope.distance*(get_parent().rect_size*Vector2(1.0, -p.rs)).normalized() + +func set_constraint(x : float, X : float, y : float, Y : float) -> void: + min_x = x + max_x = X + min_y = y + max_y = Y + +func _on_ControlPoint_gui_input(event): + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT: + if event.pressed: + moving = true + else: + moving = false + get_parent().update_controls() + elif event.button_index == BUTTON_RIGHT and event.pressed: + emit_signal("removed", get_index()) + elif moving and event is InputEventMouseMotion: + rect_position += event.relative + if rect_position.x < min_x: + rect_position.x = min_x + elif rect_position.x > max_x: + rect_position.x = max_x + if rect_position.y < min_y: + rect_position.y = min_y + elif rect_position.y > max_y: + rect_position.y = max_y + emit_signal("moved", get_index()) + +func update_tangents() -> void: + update() + emit_signal("moved", get_index()) diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/control_point.tscn b/game/addons/mat_maker_gd/widgets/curve_edit/control_point.tscn new file mode 100644 index 00000000..79a15803 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/control_point.tscn @@ -0,0 +1,39 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://material_maker/widgets/curve_edit/slope_point.gd" type="Script" id=1] +[ext_resource path="res://material_maker/widgets/curve_edit/control_point.gd" type="Script" id=2] + +[node name="ControlPoint" type="Control"] +margin_left = 56.9864 +margin_top = 33.8615 +margin_right = 63.9864 +margin_bottom = 40.8615 +rect_min_size = Vector2( 7, 7 ) +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="LeftSlope" type="Control" parent="."] +margin_left = -18.5235 +margin_right = -11.5235 +margin_bottom = 7.0 +rect_min_size = Vector2( 7, 7 ) +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} +distance = -30.0 + +[node name="RightSlope" type="Control" parent="."] +margin_left = 15.6919 +margin_right = 22.6919 +margin_bottom = 7.0 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} +distance = 30.0 +[connection signal="gui_input" from="." to="." method="_on_ControlPoint_gui_input"] +[connection signal="gui_input" from="LeftSlope" to="LeftSlope" method="_on_ControlPoint_gui_input"] +[connection signal="gui_input" from="RightSlope" to="RightSlope" method="_on_ControlPoint_gui_input"] diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/curve_dialog.gd b/game/addons/mat_maker_gd/widgets/curve_edit/curve_dialog.gd new file mode 100644 index 00000000..611f5619 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/curve_dialog.gd @@ -0,0 +1,32 @@ +extends WindowDialog + +var MMCurve = preload("res://addons/mat_maker_gd/nodes/bases/curve_base.gd") + +var previous_value + +signal curve_changed(curve) +signal return_curve(curve) + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +func _on_CurveDialog_popup_hide(): + emit_signal("return_curve", null) + +func _on_OK_pressed(): + emit_signal("return_curve", $VBoxContainer/EditorContainer/CurveEditor.curve) + +func _on_Cancel_pressed(): + emit_signal("return_curve", previous_value) + +func edit_curve(curve) -> Array: + previous_value = curve.duplicate() + $VBoxContainer/EditorContainer/CurveEditor.set_curve(curve) + popup_centered() + var result = yield(self, "return_curve") + queue_free() + return result + +func _on_CurveEditor_value_changed(value): + emit_signal("curve_changed", value) diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/curve_dialog.tscn b/game/addons/mat_maker_gd/widgets/curve_edit/curve_dialog.tscn new file mode 100644 index 00000000..e63ec876 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/curve_dialog.tscn @@ -0,0 +1,81 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://material_maker/widgets/curve_edit/curve_editor.tscn" type="PackedScene" id=1] +[ext_resource path="res://material_maker/widgets/curve_edit/curve_dialog.gd" type="Script" id=2] + +[node name="CurveDialog" type="WindowDialog"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 307.0 +margin_top = 151.0 +margin_right = -347.0 +margin_bottom = -174.0 +window_title = "Edit curve" +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 5.0 +margin_top = 5.0 +margin_right = -5.0 +margin_bottom = -5.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="EditorContainer" type="MarginContainer" parent="VBoxContainer"] +margin_right = 616.0 +margin_bottom = 353.0 +rect_clip_content = true +size_flags_horizontal = 3 +size_flags_vertical = 3 +custom_constants/margin_right = 4 +custom_constants/margin_top = 4 +custom_constants/margin_left = 4 +custom_constants/margin_bottom = 4 + +[node name="CurveEditor" parent="VBoxContainer/EditorContainer" instance=ExtResource( 1 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 4.0 +margin_top = 4.0 +margin_right = 612.0 +margin_bottom = 349.0 +size_flags_vertical = 3 + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +margin_top = 357.0 +margin_right = 616.0 +margin_bottom = 361.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 365.0 +margin_right = 616.0 +margin_bottom = 385.0 + +[node name="Control" type="Control" parent="VBoxContainer/HBoxContainer"] +margin_right = 488.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 + +[node name="OK" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 492.0 +margin_right = 552.0 +margin_bottom = 20.0 +rect_min_size = Vector2( 60, 0 ) +text = "OK" + +[node name="Cancel" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 556.0 +margin_right = 616.0 +margin_bottom = 20.0 +rect_min_size = Vector2( 60, 0 ) +text = "Cancel" +[connection signal="popup_hide" from="." to="." method="_on_CurveDialog_popup_hide"] +[connection signal="value_changed" from="VBoxContainer/EditorContainer/CurveEditor" to="." method="_on_CurveEditor_value_changed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/OK" to="." method="_on_OK_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/Cancel" to="." method="_on_Cancel_pressed"] diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/curve_edit.gd b/game/addons/mat_maker_gd/widgets/curve_edit/curve_edit.gd new file mode 100644 index 00000000..a0f241c8 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/curve_edit.gd @@ -0,0 +1,32 @@ +extends Control + +var MMCurve = preload("res://addons/mat_maker_gd/nodes/bases/curve_base.gd") + +var value = null setget set_value + + +signal updated(curve) + + +func _ready(): + set_value(MMCurve.new()) + +func set_value(v) -> void: + value = v.duplicate() + $CurveView.curve = value + $CurveView.update() + +func _on_CurveEdit_pressed(): + var dialog = preload("res://addons/mat_maker_gd/widgets/curve_edit/curve_dialog.tscn").instance() + add_child(dialog) + dialog.connect("curve_changed", self, "on_value_changed") + var new_curve = dialog.edit_curve(value) + while new_curve is GDScriptFunctionState: + new_curve = yield(new_curve, "completed") + if new_curve != null: + set_value(new_curve) + emit_signal("updated", new_curve.duplicate()) + +func on_value_changed(v) -> void: + set_value(v) + emit_signal("updated", v.duplicate()) diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/curve_edit.tscn b/game/addons/mat_maker_gd/widgets/curve_edit/curve_edit.tscn new file mode 100644 index 00000000..8355700b --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/curve_edit.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://material_maker/widgets/curve_edit/curve_edit.gd" type="Script" id=1] +[ext_resource path="res://material_maker/widgets/curve_edit/curve_view.tscn" type="PackedScene" id=2] + +[node name="CurveEdit" type="Button"] +anchor_left = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = -1280.0 +margin_right = -1220.0 +margin_bottom = -700.0 +rect_min_size = Vector2( 60, 20 ) +focus_mode = 1 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="CurveView" parent="." instance=ExtResource( 2 )] +[connection signal="pressed" from="." to="." method="_on_CurveEdit_pressed"] diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/curve_editor.gd b/game/addons/mat_maker_gd/widgets/curve_edit/curve_editor.gd new file mode 100644 index 00000000..63beaddc --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/curve_editor.gd @@ -0,0 +1,64 @@ +extends "res://addons/mat_maker_gd/widgets/curve_edit/curve_view.gd" + +signal value_changed(value) + +func _ready(): + update_controls() + +func set_curve(c) -> void: + curve = c + update() + update_controls() + +func update_controls() -> void: + for c in get_children(): + c.queue_free() + for i in curve.points.size(): + var p = curve.points[i] + var control_point = preload("res://addons/mat_maker_gd/widgets/curve_edit/control_point.tscn").instance() + add_child(control_point) + control_point.initialize(p) + control_point.rect_position = transform_point(p.p)-control_point.OFFSET + if i == 0 or i == curve.points.size()-1: + control_point.set_constraint(control_point.rect_position.x, control_point.rect_position.x, -control_point.OFFSET.y, rect_size.y-control_point.OFFSET.y) + if i == 0: + control_point.get_child(0).visible = false + else: + control_point.get_child(1).visible = false + else: + var min_x = transform_point(curve.points[i-1].p).x+1 + var max_x = transform_point(curve.points[i+1].p).x-1 + control_point.set_constraint(min_x, max_x, -control_point.OFFSET.y, rect_size.y-control_point.OFFSET.y) + control_point.connect("moved", self, "_on_ControlPoint_moved") + control_point.connect("removed", self, "_on_ControlPoint_removed") + emit_signal("value_changed", curve) + +func _on_ControlPoint_moved(index): + var control_point = get_child(index) + curve.points[index].p = reverse_transform_point(control_point.rect_position+control_point.OFFSET) + if control_point.has_node("LeftSlope"): + var slope_vector = control_point.get_node("LeftSlope").rect_position/rect_size + if slope_vector.x != 0: + curve.points[index].ls = -slope_vector.y / slope_vector.x + if control_point.has_node("RightSlope"): + var slope_vector = control_point.get_node("RightSlope").rect_position/rect_size + if slope_vector.x != 0: + curve.points[index].rs = -slope_vector.y / slope_vector.x + update() + emit_signal("value_changed", curve) + +func _on_ControlPoint_removed(index): + if curve.remove_point(index): + update() + update_controls() + +func _on_CurveEditor_gui_input(event): + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT and event.doubleclick: + var new_point_position = reverse_transform_point(get_local_mouse_position()) + curve.add_point(new_point_position.x, new_point_position.y, 0.0, 0.0) + update_controls() + +func _on_resize() -> void: + ._on_resize() + update_controls() diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/curve_editor.tscn b/game/addons/mat_maker_gd/widgets/curve_edit/curve_editor.tscn new file mode 100644 index 00000000..578dac0f --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/curve_editor.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://material_maker/widgets/curve_edit/curve_view.tscn" type="PackedScene" id=1] +[ext_resource path="res://material_maker/widgets/curve_edit/curve_editor.gd" type="Script" id=2] + +[node name="CurveEditor" instance=ExtResource( 1 )] +margin_left = 10.0 +margin_top = 10.0 +margin_right = -10.0 +margin_bottom = -10.0 +mouse_filter = 0 +script = ExtResource( 2 ) +[connection signal="gui_input" from="." to="." method="_on_CurveEditor_gui_input"] diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/curve_view.gd b/game/addons/mat_maker_gd/widgets/curve_edit/curve_view.gd new file mode 100644 index 00000000..57188ad2 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/curve_view.gd @@ -0,0 +1,53 @@ +tool +extends Control + +var MMCurve = preload("res://addons/mat_maker_gd/nodes/bases/curve_base.gd") + +export var show_axes : bool = false + +var curve #: MMCurve + +func _ready() -> void: + curve = MMCurve.new() + connect("resized", self, "_on_resize") + update() + +func transform_point(p : Vector2) -> Vector2: + return (Vector2(0.0, 1.0)+Vector2(1.0, -1.0)*p)*rect_size + +func reverse_transform_point(p : Vector2) -> Vector2: + return Vector2(0.0, 1.0)+Vector2(1.0, -1.0)*p/rect_size + +func _draw(): + var current_theme : Theme = get_node("/root/MainWindow").theme + var bg = current_theme.get_stylebox("panel", "Panel").bg_color + var fg = current_theme.get_color("font_color", "Label") + var axes_color : Color = bg.linear_interpolate(fg, 0.25) + var curve_color : Color = bg.linear_interpolate(fg, 0.75) + if show_axes: + for i in range(5): + var p = transform_point(0.25*Vector2(i, i)) + draw_line(Vector2(p.x, 0), Vector2(p.x, rect_size.y-1), axes_color) + draw_line(Vector2(0, p.y), Vector2(rect_size.x-1, p.y), axes_color) + for i in range(curve.points.size()-1): + var p1 = curve.points[i].p + var p2 = curve.points[i+1].p + var d = (p2.x-p1.x)/3.0 + var yac = p1.y+d*curve.points[i].rs + var ybc = p2.y-d*curve.points[i+1].ls + var p = transform_point(p1) + var count : int = max(1, int((transform_point(p2).x-p.x/5.0))) + for tt in range(count): + var t = (tt+1.0)/count + var omt = (1.0 - t) + var omt2 = omt * omt + var omt3 = omt2 * omt + var t2 = t * t + var t3 = t2 * t + var x = p1.x+(p2.x-p1.x)*t + var np = transform_point(Vector2(x, p1.y*omt3 + yac*omt2*t*3.0 + ybc*omt*t2*3.0 + p2.y*t3)) + draw_line(p, np, curve_color) + p = np + +func _on_resize() -> void: + update() diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/curve_view.tscn b/game/addons/mat_maker_gd/widgets/curve_edit/curve_view.tscn new file mode 100644 index 00000000..55896879 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/curve_view.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://material_maker/widgets/curve_edit/curve_view.gd" type="Script" id=1] + +[node name="CurveView" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 4.0 +margin_top = 4.0 +margin_right = -4.0 +margin_bottom = -4.0 +mouse_filter = 2 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} diff --git a/game/addons/mat_maker_gd/widgets/curve_edit/slope_point.gd b/game/addons/mat_maker_gd/widgets/curve_edit/slope_point.gd new file mode 100644 index 00000000..53d3a41f --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/curve_edit/slope_point.gd @@ -0,0 +1,44 @@ +extends Control + +export var distance : float + +var moving = false + +const OFFSET = -Vector2(0, 0) + +func _ready(): + pass # Replace with function body. + +func _draw(): + var current_theme : Theme = get_node("/root/MainWindow").theme + var color : Color = current_theme.get_color("font_color", "Label") + draw_circle(Vector2(3.0, 3.0), 3.0, color) + +func _on_ControlPoint_gui_input(event): + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT: + if event.pressed: + if event.doubleclick: + var parent = get_parent() + var vector : Vector2 + if get_index() == 0: + vector = parent.rect_position-parent.get_parent().get_child(parent.get_index()-1).rect_position + else: + vector = parent.get_parent().get_child(parent.get_index()+1).rect_position-parent.rect_position + vector = distance*vector.normalized() + rect_position = vector-OFFSET + if event.control: + get_parent().get_child(1-get_index()).rect_position = -vector-OFFSET + get_parent().update_tangents() + else: + moving = true + else: + moving = false + elif moving and event is InputEventMouseMotion: + var vector = get_global_mouse_position()-get_parent().get_global_rect().position+OFFSET + vector *= sign(vector.x) + vector = distance*vector.normalized() + rect_position = vector-OFFSET + if event.control: + get_parent().get_child(1-get_index()).rect_position = -vector-OFFSET + get_parent().update_tangents() diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/control_point.gd b/game/addons/mat_maker_gd/widgets/polygon_edit/control_point.gd new file mode 100644 index 00000000..22c19de6 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/control_point.gd @@ -0,0 +1,30 @@ +extends Control + +var moving : bool = false + +const OFFSET : Vector2 = Vector2(3, 3) + +signal moved(index) +signal removed(index) + +func _draw(): + var current_theme : Theme = get_node("/root/MainWindow").theme + var color : Color = current_theme.get_color("font_color", "Label") + draw_rect(Rect2(0, 0, 7, 7), color) + +func initialize(p : Vector2) -> void: + rect_position = get_parent().transform_point(p)-OFFSET + +func _on_ControlPoint_gui_input(event): + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT: + if event.pressed: + moving = true + else: + moving = false + get_parent().update_controls() + elif event.button_index == BUTTON_RIGHT and event.pressed: + emit_signal("removed", get_index()) + elif moving and event is InputEventMouseMotion: + rect_position += event.relative + emit_signal("moved", get_index()) diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/control_point.tscn b/game/addons/mat_maker_gd/widgets/polygon_edit/control_point.tscn new file mode 100644 index 00000000..b78ac93b --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/control_point.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://material_maker/widgets/polygon_edit/control_point.gd" type="Script" id=1] + +[node name="ControlPoint" type="Control"] +margin_left = 56.9864 +margin_top = 33.8615 +margin_right = 63.9864 +margin_bottom = 40.8615 +rect_min_size = Vector2( 7, 7 ) +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} +[connection signal="gui_input" from="." to="." method="_on_ControlPoint_gui_input"] diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_dialog.gd b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_dialog.gd new file mode 100644 index 00000000..fb9f8694 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_dialog.gd @@ -0,0 +1,32 @@ +extends WindowDialog + +export var closed : bool = true setget set_closed +var previous_value + +signal polygon_changed(polygon) +signal return_polygon(polygon) + +func set_closed(c : bool = true): + closed = c + window_title = "Edit polygon" if closed else "Edit polyline" + $VBoxContainer/EditorContainer/PolygonEditor.set_closed(closed) + +func _on_CurveDialog_popup_hide(): + emit_signal("return_polygon", null) + +func _on_OK_pressed(): + emit_signal("return_polygon", $VBoxContainer/EditorContainer/PolygonEditor.polygon) + +func _on_Cancel_pressed(): + emit_signal("return_polygon", previous_value) + +func edit_polygon(polygon) -> Array: + previous_value = polygon.duplicate() + $VBoxContainer/EditorContainer/PolygonEditor.set_polygon(polygon) + popup_centered() + var result = yield(self, "return_polygon") + queue_free() + return result + +func _on_PolygonEditor_value_changed(value): + emit_signal("polygon_changed", value) diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_dialog.tscn b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_dialog.tscn new file mode 100644 index 00000000..a3805368 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_dialog.tscn @@ -0,0 +1,81 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://material_maker/widgets/polygon_edit/polygon_editor.tscn" type="PackedScene" id=1] +[ext_resource path="res://material_maker/widgets/polygon_edit/polygon_dialog.gd" type="Script" id=2] + +[node name="PolygonDialog" type="WindowDialog"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 307.0 +margin_top = 151.0 +margin_right = -508.0 +margin_bottom = -70.0 +window_title = "Edit polygon" +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 5.0 +margin_top = 5.0 +margin_right = -5.0 +margin_bottom = -5.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="EditorContainer" type="MarginContainer" parent="VBoxContainer"] +margin_right = 455.0 +margin_bottom = 457.0 +rect_clip_content = true +size_flags_horizontal = 3 +size_flags_vertical = 3 +custom_constants/margin_right = 4 +custom_constants/margin_top = 4 +custom_constants/margin_left = 4 +custom_constants/margin_bottom = 4 + +[node name="PolygonEditor" parent="VBoxContainer/EditorContainer" instance=ExtResource( 1 )] +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 4.0 +margin_top = 4.0 +margin_right = 451.0 +margin_bottom = 453.0 + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +margin_top = 461.0 +margin_right = 455.0 +margin_bottom = 465.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 469.0 +margin_right = 455.0 +margin_bottom = 489.0 + +[node name="Control" type="Control" parent="VBoxContainer/HBoxContainer"] +margin_right = 327.0 +margin_bottom = 20.0 +size_flags_horizontal = 3 + +[node name="OK" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 331.0 +margin_right = 391.0 +margin_bottom = 20.0 +rect_min_size = Vector2( 60, 0 ) +text = "OK" + +[node name="Cancel" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 395.0 +margin_right = 455.0 +margin_bottom = 20.0 +rect_min_size = Vector2( 60, 0 ) +text = "Cancel" + +[connection signal="popup_hide" from="." to="." method="_on_CurveDialog_popup_hide"] +[connection signal="value_changed" from="VBoxContainer/EditorContainer/PolygonEditor" to="." method="_on_PolygonEditor_value_changed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/OK" to="." method="_on_OK_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/Cancel" to="." method="_on_Cancel_pressed"] diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_edit.gd b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_edit.gd new file mode 100644 index 00000000..4a773209 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_edit.gd @@ -0,0 +1,38 @@ +extends Control + +var MMPolygon = preload("res://addons/mat_maker_gd/nodes/bases/polygon_base.gd") + +export var closed : bool = true setget set_closed +var value = null setget set_value + + +signal updated(polygon) + + +func set_closed(c : bool = true): + closed = c + $PolygonView.set_closed(c) + +func _ready(): + set_value(MMPolygon.new()) + +func set_value(v) -> void: + value = v.duplicate() + $PolygonView.polygon = value + $PolygonView.update() + +func _on_PolygonEdit_pressed(): + var dialog = preload("res://addons/mat_maker_gd/widgets/polygon_edit/polygon_dialog.tscn").instance() + dialog.set_closed(closed) + add_child(dialog) + dialog.connect("polygon_changed", self, "on_value_changed") + var new_polygon = dialog.edit_polygon(value) + while new_polygon is GDScriptFunctionState: + new_polygon = yield(new_polygon, "completed") + if new_polygon != null: + set_value(new_polygon) + emit_signal("updated", new_polygon.duplicate()) + +func on_value_changed(v) -> void: + set_value(v) + emit_signal("updated", v.duplicate()) diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_edit.tscn b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_edit.tscn new file mode 100644 index 00000000..cc961643 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_edit.tscn @@ -0,0 +1,26 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://material_maker/widgets/polygon_edit/polygon_edit.gd" type="Script" id=1] +[ext_resource path="res://material_maker/widgets/polygon_edit/polygon_view.tscn" type="PackedScene" id=2] + +[node name="PolygonEdit" type="Button"] +anchor_left = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = -1280.0 +margin_right = -1248.0 +margin_bottom = -688.0 +rect_min_size = Vector2( 32, 32 ) +focus_mode = 1 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="PolygonView" parent="." instance=ExtResource( 2 )] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_right = 0.0 +margin_bottom = 0.0 + +[connection signal="pressed" from="." to="." method="_on_PolygonEdit_pressed"] diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_editor.gd b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_editor.gd new file mode 100644 index 00000000..c31dd437 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_editor.gd @@ -0,0 +1,46 @@ +extends "res://addons/mat_maker_gd/widgets/polygon_edit/polygon_view.gd" + +signal value_changed(value) + +func _ready(): + update_controls() + +func set_polygon(p) -> void: + polygon = p + update() + update_controls() + +func update_controls() -> void: + for c in get_children(): + c.queue_free() + for i in polygon.points.size(): + var p = polygon.points[i] + var control_point = preload("res://addons/mat_maker_gd/widgets/polygon_edit/control_point.tscn").instance() + add_child(control_point) + control_point.initialize(p) + control_point.rect_position = transform_point(p)-control_point.OFFSET + control_point.connect("moved", self, "_on_ControlPoint_moved") + control_point.connect("removed", self, "_on_ControlPoint_removed") + emit_signal("value_changed", polygon) + +func _on_ControlPoint_moved(index): + var control_point = get_child(index) + polygon.points[index] = reverse_transform_point(control_point.rect_position+control_point.OFFSET) + update() + emit_signal("value_changed", polygon) + +func _on_ControlPoint_removed(index): + if polygon.remove_point(index): + update() + update_controls() + +func _on_PolygonEditor_gui_input(event): + if event is InputEventMouseButton: + if event.button_index == BUTTON_LEFT and event.doubleclick: + var new_point_position = reverse_transform_point(get_local_mouse_position()) + polygon.add_point(new_point_position.x, new_point_position.y, closed) + update_controls() + +func _on_resize() -> void: + ._on_resize() + update_controls() diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_editor.tscn b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_editor.tscn new file mode 100644 index 00000000..04a84088 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_editor.tscn @@ -0,0 +1,14 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://material_maker/widgets/curve_edit/curve_view.tscn" type="PackedScene" id=1] +[ext_resource path="res://material_maker/widgets/polygon_edit/polygon_editor.gd" type="Script" id=2] + +[node name="PolygonEditor" instance=ExtResource( 1 )] +margin_left = 10.0 +margin_top = 10.0 +margin_right = -10.0 +margin_bottom = -10.0 +mouse_filter = 0 +script = ExtResource( 2 ) + +[connection signal="gui_input" from="." to="." method="_on_PolygonEditor_gui_input"] diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_view.gd b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_view.gd new file mode 100644 index 00000000..a0d76c6f --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_view.gd @@ -0,0 +1,44 @@ +tool +extends Control + +var MMPolygon = preload("res://addons/mat_maker_gd/nodes/bases/polygon_base.gd") + +var polygon #: MMPolygon + +var draw_size : Vector2 = Vector2(1, 1) +var draw_offset : Vector2 = Vector2(0, 0) +var closed : bool = true + +func set_closed(c : bool = true): + closed = c + update() + +func _ready() -> void: + polygon = MMPolygon.new() + connect("resized", self, "_on_resize") + _on_resize() + +func transform_point(p : Vector2) -> Vector2: + return draw_offset+p*draw_size + +func reverse_transform_point(p : Vector2) -> Vector2: + return (p-draw_offset)/draw_size + +func _draw(): + var current_theme : Theme = get_node("/root/MainWindow").theme + var bg = current_theme.get_stylebox("panel", "Panel").bg_color + var fg = current_theme.get_color("font_color", "Label") + var axes_color : Color = bg.linear_interpolate(fg, 0.25) + var curve_color : Color = bg.linear_interpolate(fg, 0.75) + draw_rect(Rect2(draw_offset, draw_size), axes_color, false) + var tp : Vector2 = transform_point(polygon.points[polygon.points.size()-1 if closed else 0]) + for p in polygon.points: + var tnp = transform_point(p) + draw_line(tp, tnp, curve_color) + tp = tnp + +func _on_resize() -> void: + var ds : float = min(rect_size.x, rect_size.y) + draw_size = Vector2(ds, ds) + draw_offset = 0.5*(rect_size-draw_size) + update() diff --git a/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_view.tscn b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_view.tscn new file mode 100644 index 00000000..a2faf432 --- /dev/null +++ b/game/addons/mat_maker_gd/widgets/polygon_edit/polygon_view.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://material_maker/widgets/polygon_edit/polygon_view.gd" type="Script" id=1] + +[node name="PolygonView" type="Control"] +margin_right = 64.0 +margin_bottom = 64.0 +mouse_filter = 2 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +}