mirror of
https://github.com/Relintai/material-maker.git
synced 2024-12-23 21:16:54 +01:00
fc3173b9b4
This results in less merge conflicts when using the Text Editor > Files > Trim Trailing Whitespace editor setting. .ptex, .mmg and .json files generated weren't modified as these are saved by Material Maker. These files could be made to end with a newline automatically on save in a future commit.
159 lines
4.6 KiB
GDScript
159 lines
4.6 KiB
GDScript
tool
|
|
extends Control
|
|
class_name MMGradientEditor
|
|
|
|
class GradientCursor:
|
|
extends Control
|
|
|
|
var color : Color
|
|
|
|
const WIDTH : int = 10
|
|
|
|
func _ready() -> void:
|
|
rect_position = Vector2(0, 15)
|
|
rect_size = Vector2(WIDTH, 15)
|
|
|
|
func _draw() -> void:
|
|
var polygon : PoolVector2Array = PoolVector2Array([Vector2(0, 5), Vector2(WIDTH/2, 0), Vector2(WIDTH, 5), Vector2(WIDTH, 15), Vector2(0, 15)])
|
|
var c = color
|
|
c.a = 1.0
|
|
draw_colored_polygon(polygon, c)
|
|
|
|
func _gui_input(ev) -> void:
|
|
if ev is InputEventMouseButton:
|
|
if ev.button_index == BUTTON_LEFT && ev.doubleclick:
|
|
get_parent().select_color(self, ev.global_position)
|
|
elif ev.button_index == BUTTON_RIGHT && get_parent().get_sorted_cursors().size() > 2:
|
|
var parent = get_parent()
|
|
parent.remove_child(self)
|
|
parent.update_value()
|
|
queue_free()
|
|
elif ev is InputEventMouseMotion && (ev.button_mask & 1) != 0:
|
|
rect_position.x += ev.relative.x
|
|
rect_position.x = min(max(0, rect_position.x), get_parent().rect_size.x-rect_size.x)
|
|
get_parent().update_value()
|
|
|
|
func get_position() -> Vector2:
|
|
return rect_position.x / (get_parent().rect_size.x - WIDTH)
|
|
|
|
func set_color(c) -> void:
|
|
color = c
|
|
get_parent().update_value()
|
|
update()
|
|
|
|
static func sort(a, b) -> bool:
|
|
return a.get_position() < b.get_position()
|
|
|
|
var value = null setget set_value
|
|
export var embedded : bool = true
|
|
|
|
signal updated(value)
|
|
|
|
func _ready() -> void:
|
|
$Gradient.material = $Gradient.material.duplicate(true)
|
|
set_value(MMGradient.new())
|
|
|
|
func get_gradient_from_data(data):
|
|
if typeof(data) == TYPE_ARRAY:
|
|
return data
|
|
elif typeof(data) == TYPE_DICTIONARY:
|
|
if data.has("parameters") and data.parameters.has("gradient"):
|
|
return data.parameters.gradient
|
|
if data.has("type") and data.type == "Gradient":
|
|
return data
|
|
return null
|
|
|
|
func get_drag_data(position : Vector2):
|
|
var data = MMType.serialize_value(value)
|
|
var preview = ColorRect.new()
|
|
preview.rect_size = Vector2(64, 24)
|
|
preview.material = $Gradient.material
|
|
set_drag_preview(preview)
|
|
return data
|
|
|
|
func can_drop_data(position : Vector2, data) -> bool:
|
|
return get_gradient_from_data(data) != null
|
|
|
|
func drop_data(position : Vector2, data) -> void:
|
|
var gradient = get_gradient_from_data(data)
|
|
if gradient != null:
|
|
set_value(MMType.deserialize_value(gradient))
|
|
|
|
func set_value(v) -> void:
|
|
value = v
|
|
for c in get_children():
|
|
if c is GradientCursor:
|
|
remove_child(c)
|
|
c.free()
|
|
for p in value.points:
|
|
add_cursor(p.v*(rect_size.x-GradientCursor.WIDTH), p.c)
|
|
$Interpolation.selected = value.interpolation
|
|
update_shader()
|
|
|
|
func update_value() -> void:
|
|
value.clear()
|
|
for c in get_children():
|
|
if c is GradientCursor:
|
|
value.add_point(c.rect_position.x/(rect_size.x-GradientCursor.WIDTH), c.color)
|
|
update_shader()
|
|
|
|
func add_cursor(x, color) -> void:
|
|
var cursor = GradientCursor.new()
|
|
add_child(cursor)
|
|
cursor.rect_position.x = x
|
|
cursor.color = color
|
|
|
|
func _gui_input(ev) -> void:
|
|
if ev is InputEventMouseButton && ev.button_index == 1 && ev.doubleclick:
|
|
if ev.position.y > 15:
|
|
var p = clamp(ev.position.x, 0, rect_size.x-GradientCursor.WIDTH)
|
|
add_cursor(p, get_gradient_color(p))
|
|
update_value()
|
|
elif embedded:
|
|
var popup = load("res://addons/material_maker/widgets/gradient_popup.tscn").instance()
|
|
add_child(popup)
|
|
var popup_size = popup.rect_size
|
|
popup.popup(Rect2(ev.global_position, Vector2(0, 0)))
|
|
popup.set_global_position(ev.global_position-Vector2(popup_size.x / 2, popup_size.y))
|
|
popup.init(value)
|
|
popup.connect("updated", self, "set_value")
|
|
|
|
# Showing a color picker popup to change a cursor's color
|
|
|
|
var active_cursor
|
|
|
|
func select_color(cursor, position) -> void:
|
|
active_cursor = cursor
|
|
$Gradient/Popup/ColorPicker.color = cursor.color
|
|
$Gradient/Popup/ColorPicker.connect("color_changed", cursor, "set_color")
|
|
$Gradient/Popup.rect_position = position
|
|
$Gradient/Popup.popup()
|
|
|
|
func _on_Popup_popup_hide() -> void:
|
|
$Gradient/Popup/ColorPicker.disconnect("color_changed", active_cursor, "set_color")
|
|
|
|
# Calculating a color from the gradient and generating the shader
|
|
|
|
func get_sorted_cursors() -> Array:
|
|
var array = []
|
|
for c in get_children():
|
|
if c is GradientCursor:
|
|
array.append(c)
|
|
array.sort_custom(GradientCursor, "sort")
|
|
return array
|
|
|
|
func get_gradient_color(x) -> Color:
|
|
return value.get_color(x / (rect_size.x - GradientCursor.WIDTH))
|
|
|
|
func update_shader() -> void:
|
|
var shader
|
|
shader = "shader_type canvas_item;\n"
|
|
shader += value.get_shader("gradient")
|
|
shader += "void fragment() { COLOR = gradient(UV.x); }"
|
|
$Gradient.material.shader.set_code(shader)
|
|
emit_signal("updated", value)
|
|
|
|
func _on_Interpolation_item_selected(ID) -> void:
|
|
value.interpolation = ID
|
|
update_shader()
|