mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 17:19:50 +00:00
Compare commits
1 commit
3b2a287efc
...
ac14b2316e
Author | SHA1 | Date | |
---|---|---|---|
ac14b2316e |
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -6,17 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
|
||||
## [v1.1] - Unreleased
|
||||
This update has been brought to you by the contributions of:
|
||||
Fayez Akhtar ([@Variable-ind](https://github.com/Variable-ind)), Spencer Beckwith ([@spencerjbeckwith](https://github.com/spencerjbeckwith))
|
||||
Fayez Akhtar ([@Variable-ind](https://github.com/Variable-ind))
|
||||
|
||||
Built using Godot 4.3
|
||||
|
||||
### Added
|
||||
- Tilemap layers have arrived! Tilemap layers allow artists to create tiles, and easily preview and dynamically modify them within Pixelorama. [#1146](https://github.com/Orama-Interactive/Pixelorama/pull/1146)
|
||||
- Indexed mode has finally been implemented! [#1136](https://github.com/Orama-Interactive/Pixelorama/pull/1136)
|
||||
- Audio layers have been added, allowing artists to easily synchronize their animations with audio. [#1149](https://github.com/Orama-Interactive/Pixelorama/pull/1149)
|
||||
- Added a new text tool. Destructive only for now, meaning that once the text is confirmed, it cannot be changed later. [#1134](https://github.com/Orama-Interactive/Pixelorama/pull/1134)
|
||||
- A color curves image and layer effect has been added.
|
||||
- It is now possible to load custom Godot shaders as image and layer effects.
|
||||
- Implemented support for multiple grids. [#1122](https://github.com/Orama-Interactive/Pixelorama/pull/1122)
|
||||
|
||||
### Changed
|
||||
|
@ -25,11 +21,7 @@ Built using Godot 4.3
|
|||
### Fixed
|
||||
- Fixed crash when Pixelorama starts without a palette.
|
||||
- Undo/redo now works again when the cursor is hovering over the timeline.
|
||||
- The first frame is no longer exported twice when using ping-pong loop.
|
||||
- Fixed pencil/eraser/shading previews turning white for a brief moment when changing image brushes, and when switchin between tools.
|
||||
- Dialogs that are children of other dialogs now always appear on top, to avoid issues where they could hide behind their parents and causing confusion that made Pixelorama seem unresponsive.
|
||||
- Palette swatches now get deleted when the user removes all palettes.
|
||||
- The CLI's output option now works with filepaths instead of just filenames. [#1145](https://github.com/Orama-Interactive/Pixelorama/pull/1145)
|
||||
- Palette swatches now get deleted when the user removes all palettes
|
||||
- Fixed the Palettize effect and palette exporting to images storing slightly wrong color values. [77f6bcf](https://github.com/Orama-Interactive/Pixelorama/commit/77f6bcf07bd80bc042e478bb883d05900cebe436)
|
||||
- Fixed some issues with the Palettize effect where the output would be different if the palette size changed and empty swatches were added, even if the colors themselves stayed the same. Initially fixed by [bd7d3b1](https://github.com/Orama-Interactive/Pixelorama/commit/bd7d3b19cc98804e9b99754153c4d553d2048ee3), but [1dcb696](https://github.com/Orama-Interactive/Pixelorama/commit/1dcb696c35121f8208bde699f87bb75deff99d13) is the proper fix.
|
||||
- Fixed recorder label not updating when project is changed. [#1139](https://github.com/Orama-Interactive/Pixelorama/pull/1139)
|
||||
|
@ -58,7 +50,7 @@ Built using Godot 4.3
|
|||
- Fixed layer effect slider values being rounded to the nearest integer.
|
||||
- Fixed memory leak where the project remained referenced by a drawing tool, even when its tab was closed.
|
||||
- Fixed memory leak where the first project remained forever references in memory by the Recorder panel.
|
||||
- Slightly optimize circle brushes by only calling the ellipse algorithms once while drawing.
|
||||
- Slightly optimize circle brushes by only calling the ellipse algorithms once while drawing
|
||||
|
||||
### Removed
|
||||
- The Recorder panel has been removed from the Web version. It wasn't functional anyway in a way that was useful, and it's unsure if we can find a way to make it work.
|
||||
|
|
|
@ -1157,27 +1157,6 @@ msgstr ""
|
|||
msgid "Tint effect factor:"
|
||||
msgstr ""
|
||||
|
||||
#. An image effect that adjusts the colors of the image by using curves.
|
||||
msgid "Color Curves"
|
||||
msgstr ""
|
||||
|
||||
#. Refers to a color channel, such as the red, green, blue or alpha channels.
|
||||
msgid "Channel:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Red"
|
||||
msgstr ""
|
||||
|
||||
msgid "Green"
|
||||
msgstr ""
|
||||
|
||||
#. Refers to the value (as in HSV) of the colors of an image.
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
|
||||
msgid "Presets"
|
||||
msgstr ""
|
||||
|
||||
msgid "Apply"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -685,10 +685,6 @@ adjust_brightness_contrast={
|
|||
"deadzone": 0.5,
|
||||
"events": []
|
||||
}
|
||||
color_curves={
|
||||
"deadzone": 0.5,
|
||||
"events": []
|
||||
}
|
||||
gradient={
|
||||
"deadzone": 0.5,
|
||||
"events": []
|
||||
|
|
|
@ -64,14 +64,13 @@ enum EffectsMenu {
|
|||
DESATURATION,
|
||||
HSV,
|
||||
BRIGHTNESS_SATURATION,
|
||||
COLOR_CURVES,
|
||||
PALETTIZE,
|
||||
PIXELIZE,
|
||||
POSTERIZE,
|
||||
GAUSSIAN_BLUR,
|
||||
GRADIENT,
|
||||
GRADIENT_MAP,
|
||||
LOADED_EFFECTS
|
||||
SHADER
|
||||
}
|
||||
## Enumeration of items present in the Select Menu.
|
||||
enum SelectMenu { SELECT_ALL, CLEAR_SELECTION, INVERT, TILE_MODE, MODIFY }
|
||||
|
@ -810,7 +809,6 @@ func _initialize_keychain() -> void:
|
|||
&"drop_shadow": Keychain.InputAction.new("", "Effects menu", true),
|
||||
&"adjust_hsv": Keychain.InputAction.new("", "Effects menu", true),
|
||||
&"adjust_brightness_contrast": Keychain.InputAction.new("", "Effects menu", true),
|
||||
&"color_curves": Keychain.InputAction.new("", "Effects menu", true),
|
||||
&"gaussian_blur": Keychain.InputAction.new("", "Effects menu", true),
|
||||
&"gradient": Keychain.InputAction.new("", "Effects menu", true),
|
||||
&"gradient_map": Keychain.InputAction.new("", "Effects menu", true),
|
||||
|
|
|
@ -3,9 +3,6 @@ extends Node
|
|||
|
||||
signal project_saved
|
||||
signal reference_image_imported
|
||||
signal shader_copied(file_path: String)
|
||||
|
||||
const SHADERS_DIRECTORY := "user://shaders"
|
||||
|
||||
var preview_dialog_tscn := preload("res://src/UI/Dialogs/ImportPreviewDialog.tscn")
|
||||
var preview_dialogs := [] ## Array of preview dialogs
|
||||
|
@ -42,13 +39,12 @@ func handle_loading_file(file: String) -> void:
|
|||
elif file_ext in ["pck", "zip"]: # Godot resource pack file
|
||||
Global.control.get_node("Extensions").install_extension(file)
|
||||
|
||||
elif file_ext == "gdshader": # Godot shader file
|
||||
elif file_ext == "shader" or file_ext == "gdshader": # Godot shader file
|
||||
var shader := load(file)
|
||||
if not shader is Shader:
|
||||
return
|
||||
var new_path := SHADERS_DIRECTORY.path_join(file.get_file())
|
||||
DirAccess.copy_absolute(file, new_path)
|
||||
shader_copied.emit(new_path)
|
||||
var file_name: String = file.get_file().get_basename()
|
||||
Global.control.find_child("ShaderEffect").change_shader(shader, file_name)
|
||||
elif file_ext == "mp3": # Audio file
|
||||
open_audio_file(file)
|
||||
|
||||
|
|
|
@ -25,13 +25,7 @@ func get_content() -> ImageExtended:
|
|||
|
||||
|
||||
func set_content(content, texture: ImageTexture = null) -> void:
|
||||
var proper_content: ImageExtended
|
||||
if content is not ImageExtended:
|
||||
proper_content = ImageExtended.new()
|
||||
proper_content.copy_from_custom(content, image.is_indexed)
|
||||
else:
|
||||
proper_content = content
|
||||
image = proper_content
|
||||
image = content
|
||||
if is_instance_valid(texture) and is_instance_valid(texture.get_image()):
|
||||
image_texture = texture
|
||||
if image_texture.get_image().get_size() != image.get_size():
|
||||
|
|
|
@ -144,10 +144,8 @@ func set_nodes() -> void:
|
|||
selection_checkbox = $VBoxContainer/OptionsContainer/SelectionCheckBox
|
||||
affect_option_button = $VBoxContainer/OptionsContainer/AffectOptionButton
|
||||
animate_panel = $"%AnimatePanel"
|
||||
if is_instance_valid(animate_panel):
|
||||
animate_panel.image_effect_node = self
|
||||
if is_instance_valid(live_checkbox):
|
||||
live_checkbox.button_pressed = live_preview
|
||||
animate_panel.image_effect_node = self
|
||||
live_checkbox.button_pressed = live_preview
|
||||
|
||||
|
||||
func display_animate_dialog() -> void:
|
||||
|
|
|
@ -232,7 +232,7 @@ func display_effects(cel: BaseCel, image_override: Image = null) -> Image:
|
|||
return image
|
||||
var image_size := image.get_size()
|
||||
for effect in effects:
|
||||
if not effect.enabled or not is_instance_valid(effect.shader):
|
||||
if not effect.enabled:
|
||||
continue
|
||||
var shader_image_effect := ShaderImageEffect.new()
|
||||
shader_image_effect.generate_image(image, effect.shader, effect.params, image_size)
|
||||
|
|
|
@ -252,17 +252,6 @@ static func create_ui_for_shader_uniforms(
|
|||
func(_gradient, _cc): value_changed.call(gradient_edit.texture, u_name)
|
||||
)
|
||||
hbox.add_child(gradient_edit)
|
||||
elif u_name.begins_with("curve_"):
|
||||
var curve_edit := CurveEdit.new()
|
||||
curve_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
if params.has(u_name) and params[u_name] is CurveTexture:
|
||||
curve_edit.curve = params[u_name].curve
|
||||
else:
|
||||
curve_edit.set_default_curve()
|
||||
curve_edit.value_changed.connect(
|
||||
func(curve: Curve): value_changed.call(CurveEdit.to_texture(curve), u_name)
|
||||
)
|
||||
hbox.add_child(curve_edit)
|
||||
else: ## Simple texture
|
||||
var file_dialog := FileDialog.new()
|
||||
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
|
|
|
@ -64,7 +64,6 @@ func draw_palette() -> void:
|
|||
var grid_index := i + grid_size.x * j
|
||||
var index := convert_grid_index_to_palette_index(grid_index)
|
||||
var swatch := swatches[grid_index]
|
||||
swatch.color_index = index
|
||||
swatch.show_left_highlight = Palettes.left_selected_color == index
|
||||
swatch.show_right_highlight = Palettes.right_selected_color == index
|
||||
var color = current_palette.get_color(index)
|
||||
|
|
|
@ -8,7 +8,6 @@ signal dropped(source_index: int, new_index: int)
|
|||
const DEFAULT_COLOR := Color(0.0, 0.0, 0.0, 0.0)
|
||||
|
||||
var index := -1
|
||||
var color_index := -1
|
||||
var show_left_highlight := false
|
||||
var show_right_highlight := false
|
||||
var empty := true:
|
||||
|
@ -49,23 +48,6 @@ func _draw() -> void:
|
|||
draw_rect(
|
||||
Rect2(margin - Vector2.ONE, size - margin * 2 + Vector2(2, 2)), Color.WHITE, false, 1
|
||||
)
|
||||
if Global.show_pixel_indices:
|
||||
var font := Themes.get_font()
|
||||
var str_pos := Vector2(size.x / 2, size.y - 2)
|
||||
var text_color := Global.control.theme.get_color(&"font_color", &"Label")
|
||||
draw_string_outline(
|
||||
font,
|
||||
str_pos,
|
||||
str(color_index),
|
||||
HORIZONTAL_ALIGNMENT_RIGHT,
|
||||
-1,
|
||||
size.x / 2,
|
||||
1,
|
||||
text_color.inverted()
|
||||
)
|
||||
draw_string(
|
||||
font, str_pos, str(color_index), HORIZONTAL_ALIGNMENT_RIGHT, -1, size.x / 2, text_color
|
||||
)
|
||||
|
||||
|
||||
## Enables drawing of highlights which indicate selected swatches
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
shader_type canvas_item;
|
||||
|
||||
// CurveTexture(s)
|
||||
uniform sampler2D curve_rgb;
|
||||
uniform sampler2D curve_red;
|
||||
uniform sampler2D curve_green;
|
||||
uniform sampler2D curve_blue;
|
||||
uniform sampler2D curve_alpha;
|
||||
uniform sampler2D curve_hue;
|
||||
uniform sampler2D curve_sat;
|
||||
uniform sampler2D curve_value;
|
||||
uniform sampler2D selection : filter_nearest;
|
||||
|
||||
|
||||
vec3 rgb2hsb(vec3 c) {
|
||||
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
vec4 p = mix(vec4(c.bg, K.wz),
|
||||
vec4(c.gb, K.xy),
|
||||
step(c.b, c.g));
|
||||
vec4 q = mix(vec4(p.xyw, c.r),
|
||||
vec4(c.r, p.yzx),
|
||||
step(p.x, c.r));
|
||||
float d = q.x - min(q.w, q.y);
|
||||
float e = 1.0e-10;
|
||||
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
|
||||
d / (q.x + e),
|
||||
q.x);
|
||||
}
|
||||
|
||||
vec3 hsb2rgb(vec3 c)
|
||||
{
|
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
|
||||
void fragment() {
|
||||
vec4 original_color = texture(TEXTURE, UV);
|
||||
vec4 selection_color = texture(selection, UV);
|
||||
vec4 col;
|
||||
float red_curve_color = texture(curve_red, vec2(COLOR.r, 0.0)).r;
|
||||
float green_curve_color = texture(curve_green, vec2(COLOR.g, 0.0)).r;
|
||||
float blue_curve_color = texture(curve_blue, vec2(COLOR.b, 0.0)).r;
|
||||
float alpha_curve_color = texture(curve_alpha, vec2(COLOR.a, 0.0)).r;
|
||||
col.r = red_curve_color;
|
||||
col.g = green_curve_color;
|
||||
col.b = blue_curve_color;
|
||||
col.a = alpha_curve_color;
|
||||
|
||||
vec3 hsb = rgb2hsb(col.rgb);
|
||||
float hue_curve_color = texture(curve_hue, vec2(hsb.r, 0.0)).r;
|
||||
float sat_curve_color = texture(curve_sat, vec2(hsb.g, 0.0)).r;
|
||||
float value_curve_color = texture(curve_value, vec2(hsb.b, 0.0)).r;
|
||||
hsb.r = hue_curve_color;
|
||||
hsb.g = sat_curve_color;
|
||||
hsb.b = value_curve_color;
|
||||
|
||||
col.rgb = hsb2rgb(hsb);
|
||||
|
||||
float rgb_curve_color_r = texture(curve_rgb, vec2(col.r, 0.0)).r;
|
||||
float rgb_curve_color_g = texture(curve_rgb, vec2(col.g, 0.0)).r;
|
||||
float rgb_curve_color_b = texture(curve_rgb, vec2(col.b, 0.0)).r;
|
||||
col.rgb = vec3(rgb_curve_color_r, rgb_curve_color_g, rgb_curve_color_b);
|
||||
vec4 output = mix(original_color.rgba, col, selection_color.a);
|
||||
COLOR = output;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
extends ImageEffect
|
||||
|
||||
enum Channel { RGB, RED, GREEN, BLUE, ALPHA, HUE, SATURATION, VALUE }
|
||||
const SHADER := preload("res://src/Shaders/Effects/ColorCurves.gdshader")
|
||||
|
||||
var curves: Array[Curve]
|
||||
@onready var channel_option_button := %ChannelOptionButton as OptionButton
|
||||
@onready var curve_edit := $VBoxContainer/CurveEdit as CurveEdit
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
var sm := ShaderMaterial.new()
|
||||
sm.shader = SHADER
|
||||
preview.set_material(sm)
|
||||
for i in channel_option_button.item_count:
|
||||
var curve := Curve.new()
|
||||
curve.add_point(Vector2.ZERO, 0, 1, Curve.TANGENT_LINEAR)
|
||||
curve.add_point(Vector2.ONE, 1, 0, Curve.TANGENT_LINEAR)
|
||||
curves.append(curve)
|
||||
curve_edit.curve = curves[Channel.RGB]
|
||||
|
||||
|
||||
func commit_action(cel: Image, project := Global.current_project) -> void:
|
||||
var selection_tex: ImageTexture
|
||||
if selection_checkbox.button_pressed and project.has_selection:
|
||||
var selection := project.selection_map.return_cropped_copy(project.size)
|
||||
selection_tex = ImageTexture.create_from_image(selection)
|
||||
|
||||
var params := {
|
||||
"curve_rgb": CurveEdit.to_texture(curves[Channel.RGB]),
|
||||
"curve_red": CurveEdit.to_texture(curves[Channel.RED]),
|
||||
"curve_green": CurveEdit.to_texture(curves[Channel.GREEN]),
|
||||
"curve_blue": CurveEdit.to_texture(curves[Channel.BLUE]),
|
||||
"curve_alpha": CurveEdit.to_texture(curves[Channel.ALPHA]),
|
||||
"curve_hue": CurveEdit.to_texture(curves[Channel.HUE]),
|
||||
"curve_sat": CurveEdit.to_texture(curves[Channel.SATURATION]),
|
||||
"curve_value": CurveEdit.to_texture(curves[Channel.VALUE]),
|
||||
"selection": selection_tex
|
||||
}
|
||||
if !has_been_confirmed:
|
||||
for param in params:
|
||||
preview.material.set_shader_parameter(param, params[param])
|
||||
else:
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(cel, SHADER, params, project.size)
|
||||
|
||||
|
||||
func _on_channel_option_button_item_selected(index: int) -> void:
|
||||
curve_edit.curve = curves[index]
|
|
@ -1,61 +0,0 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://cthknpr74lawl"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bybqhhayl5ay5" path="res://src/UI/Dialogs/ImageEffects/ImageEffectParent.tscn" id="1_4g7xo"]
|
||||
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/ColorCurvesDialog.gd" id="2_xkivc"]
|
||||
[ext_resource type="Script" path="res://src/UI/Nodes/CurveEditor/CurveEdit.gd" id="3_3yyhs"]
|
||||
|
||||
[sub_resource type="Curve" id="Curve_gvi51"]
|
||||
_data = [Vector2(0, 0), 0.0, 1.0, 0, 1, Vector2(1, 1), 1.0, 0.0, 1, 0]
|
||||
point_count = 2
|
||||
|
||||
[node name="ColorCurvesDialog" instance=ExtResource("1_4g7xo")]
|
||||
title = "Color Curves"
|
||||
size = Vector2i(362, 481)
|
||||
script = ExtResource("2_xkivc")
|
||||
|
||||
[node name="VBoxContainer" parent="." index="3"]
|
||||
offset_bottom = 432.0
|
||||
|
||||
[node name="ShowAnimate" parent="VBoxContainer" index="0"]
|
||||
visible = false
|
||||
|
||||
[node name="ColorOptions" type="GridContainer" parent="VBoxContainer" index="3"]
|
||||
layout_mode = 2
|
||||
columns = 2
|
||||
|
||||
[node name="ChannelLabel" type="Label" parent="VBoxContainer/ColorOptions" index="0"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Channel:"
|
||||
|
||||
[node name="ChannelOptionButton" type="OptionButton" parent="VBoxContainer/ColorOptions" index="1"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
mouse_default_cursor_shape = 2
|
||||
selected = 0
|
||||
item_count = 8
|
||||
popup/item_0/text = "RGB"
|
||||
popup/item_1/text = "Red"
|
||||
popup/item_1/id = 1
|
||||
popup/item_2/text = "Green"
|
||||
popup/item_2/id = 2
|
||||
popup/item_3/text = "Blue"
|
||||
popup/item_3/id = 3
|
||||
popup/item_4/text = "Alpha"
|
||||
popup/item_4/id = 4
|
||||
popup/item_5/text = "Hue"
|
||||
popup/item_5/id = 5
|
||||
popup/item_6/text = "Saturation"
|
||||
popup/item_6/id = 6
|
||||
popup/item_7/text = "Value"
|
||||
popup/item_7/id = 7
|
||||
|
||||
[node name="CurveEdit" type="VBoxContainer" parent="VBoxContainer" index="4"]
|
||||
custom_minimum_size = Vector2(32, 150)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
script = ExtResource("3_3yyhs")
|
||||
curve = SubResource("Curve_gvi51")
|
||||
|
||||
[connection signal="item_selected" from="VBoxContainer/ColorOptions/ChannelOptionButton" to="." method="_on_channel_option_button_item_selected"]
|
|
@ -3,7 +3,8 @@ extends ImageEffect
|
|||
var shader: Shader
|
||||
var params := {}
|
||||
|
||||
@onready var shader_params := $VBoxContainer/ShaderParams as VBoxContainer
|
||||
@onready var shader_loaded_label: Label = $VBoxContainer/ShaderLoadedLabel
|
||||
@onready var shader_params: BoxContainer = $VBoxContainer/ShaderParams
|
||||
|
||||
|
||||
func _about_to_popup() -> void:
|
||||
|
@ -16,22 +17,36 @@ func _about_to_popup() -> void:
|
|||
super._about_to_popup()
|
||||
|
||||
|
||||
func set_nodes() -> void:
|
||||
aspect_ratio_container = $VBoxContainer/AspectRatioContainer
|
||||
preview = $VBoxContainer/AspectRatioContainer/Preview
|
||||
|
||||
|
||||
func commit_action(cel: Image, project := Global.current_project) -> void:
|
||||
if not is_instance_valid(shader):
|
||||
if !shader:
|
||||
return
|
||||
|
||||
var gen := ShaderImageEffect.new()
|
||||
gen.generate_image(cel, shader, params, project.size)
|
||||
|
||||
|
||||
func _on_ChooseShader_pressed() -> void:
|
||||
if OS.get_name() == "Web":
|
||||
Html5FileExchange.load_shader()
|
||||
else:
|
||||
$FileDialog.popup_centered(Vector2(300, 340))
|
||||
|
||||
|
||||
func _on_FileDialog_file_selected(path: String) -> void:
|
||||
var shader_tmp = load(path)
|
||||
if !shader_tmp is Shader:
|
||||
return
|
||||
change_shader(shader_tmp, path.get_file().get_basename())
|
||||
|
||||
|
||||
func set_nodes() -> void:
|
||||
preview = $VBoxContainer/AspectRatioContainer/Preview
|
||||
|
||||
|
||||
func change_shader(shader_tmp: Shader, shader_name: String) -> void:
|
||||
shader = shader_tmp
|
||||
preview.material.shader = shader_tmp
|
||||
title = shader_name
|
||||
shader_loaded_label.text = tr("Shader loaded:") + " " + shader_name
|
||||
params.clear()
|
||||
for child in shader_params.get_children():
|
||||
child.queue_free()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://b1ola6loro5m7"]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://bkr47ocij684y"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/UI/Dialogs/ImageEffects/ShaderEffect.gd" id="1"]
|
||||
[ext_resource type="PackedScene" uid="uid://3pmb60gpst7b" path="res://src/UI/Nodes/TransparentChecker.tscn" id="2"]
|
||||
|
@ -6,8 +6,6 @@
|
|||
[sub_resource type="ShaderMaterial" id="1"]
|
||||
|
||||
[node name="ShaderEffect" type="ConfirmationDialog"]
|
||||
position = Vector2i(0, 36)
|
||||
size = Vector2i(612, 350)
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
|
@ -17,14 +15,17 @@ anchor_bottom = 1.0
|
|||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = -8.0
|
||||
offset_bottom = -49.0
|
||||
offset_bottom = -36.0
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "This is an experimental feature and may not be included in the stable version"
|
||||
|
||||
[node name="AspectRatioContainer" type="AspectRatioContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Preview" type="TextureRect" parent="VBoxContainer/AspectRatioContainer"]
|
||||
texture_filter = 1
|
||||
material = SubResource("1")
|
||||
custom_minimum_size = Vector2(200, 200)
|
||||
layout_mode = 2
|
||||
|
@ -38,5 +39,22 @@ anchors_preset = 0
|
|||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="ChooseShader" type="Button" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
mouse_default_cursor_shape = 2
|
||||
text = "Choose Shader"
|
||||
|
||||
[node name="ShaderLoadedLabel" type="Label" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "No shader loaded!"
|
||||
|
||||
[node name="ShaderParams" type="VBoxContainer" parent="VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="FileDialog" type="FileDialog" parent="." groups=["FileDialogs"]]
|
||||
access = 2
|
||||
filters = PackedStringArray("*gdshader; Godot Shader File")
|
||||
show_hidden_files = true
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/ChooseShader" to="." method="_on_ChooseShader_pressed"]
|
||||
[connection signal="file_selected" from="FileDialog" to="." method="_on_FileDialog_file_selected"]
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
# Code taken and modified from Material Maker, licensed under MIT
|
||||
# gdlint: ignore=max-line-length
|
||||
# https://github.com/RodZill4/material-maker/blob/master/material_maker/widgets/curve_edit/control_point.gd
|
||||
class_name CurveEditControlPoint
|
||||
extends Control
|
||||
|
||||
signal moved(index: int)
|
||||
signal removed(index: int)
|
||||
|
||||
const OFFSET := Vector2(3, 3)
|
||||
|
||||
var moving := false
|
||||
|
||||
var min_x: float
|
||||
var max_x: float
|
||||
var min_y: float
|
||||
var max_y: float
|
||||
var left_slope: CurveEditTangentPoint
|
||||
var right_slope: CurveEditTangentPoint
|
||||
|
||||
@onready var parent := get_parent() as Control
|
||||
@onready var grandparent := parent.get_parent() as CurveEdit
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
gui_input.connect(_on_gui_input)
|
||||
custom_minimum_size = Vector2(8, 8)
|
||||
left_slope = CurveEditTangentPoint.new()
|
||||
right_slope = CurveEditTangentPoint.new()
|
||||
add_child(left_slope)
|
||||
add_child(right_slope)
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var color := Color.GRAY
|
||||
var current_scene := get_tree().current_scene
|
||||
if current_scene is Control:
|
||||
var current_theme := (current_scene as Control).theme
|
||||
color = current_theme.get_color("font_color", "Label")
|
||||
for c: CurveEditTangentPoint in get_children():
|
||||
if c.visible:
|
||||
draw_line(OFFSET, c.position + OFFSET, color)
|
||||
draw_rect(Rect2(0, 0, 7, 7), color)
|
||||
|
||||
|
||||
func initialize(curve: Curve, index: int) -> void:
|
||||
if not is_instance_valid(parent):
|
||||
await ready
|
||||
position = grandparent.transform_point(curve.get_point_position(index)) - OFFSET
|
||||
var left_tangent := curve.get_point_left_tangent(index)
|
||||
var right_tangent := curve.get_point_right_tangent(index)
|
||||
if left_tangent != INF:
|
||||
left_slope.position = (
|
||||
left_slope.distance * (parent.size * Vector2(1.0, -left_tangent)).normalized()
|
||||
)
|
||||
if right_tangent != INF:
|
||||
right_slope.position = (
|
||||
right_slope.distance * (parent.size * Vector2(1.0, -right_tangent)).normalized()
|
||||
)
|
||||
|
||||
|
||||
func set_control_point_visibility(left: bool, new_visible: bool) -> void:
|
||||
if not is_instance_valid(left_slope):
|
||||
await ready
|
||||
if left:
|
||||
left_slope.visible = new_visible
|
||||
else:
|
||||
right_slope.visible = new_visible
|
||||
|
||||
|
||||
func set_constraint(new_min_x: float, new_max_x: float, new_min_y: float, new_max_y: float) -> void:
|
||||
min_x = new_min_x
|
||||
max_x = new_max_x
|
||||
min_y = new_min_y
|
||||
max_y = new_max_y
|
||||
|
||||
|
||||
func _on_gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
if event.pressed:
|
||||
moving = true
|
||||
else:
|
||||
moving = false
|
||||
grandparent.update_controls()
|
||||
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
|
||||
removed.emit(get_index())
|
||||
elif moving and event is InputEventMouseMotion:
|
||||
position += event.relative
|
||||
if position.x < min_x:
|
||||
position.x = min_x
|
||||
elif position.x > max_x:
|
||||
position.x = max_x
|
||||
if position.y < min_y:
|
||||
position.y = min_y
|
||||
elif position.y > max_y:
|
||||
position.y = max_y
|
||||
moved.emit(get_index())
|
||||
|
||||
|
||||
func update_tangents() -> void:
|
||||
queue_redraw()
|
||||
moved.emit(get_index())
|
|
@ -1,273 +0,0 @@
|
|||
# Code taken and modified from Material Maker, licensed under MIT
|
||||
# gdlint: ignore=max-line-length
|
||||
# https://github.com/RodZill4/material-maker/blob/master/material_maker/widgets/curve_edit/curve_view.gd
|
||||
# and
|
||||
# gdlint: ignore=max-line-length
|
||||
# https://github.com/RodZill4/material-maker/blob/master/material_maker/widgets/curve_edit/curve_editor.gd
|
||||
@tool
|
||||
class_name CurveEdit
|
||||
extends VBoxContainer
|
||||
|
||||
signal value_changed(value: Curve)
|
||||
|
||||
@export var show_axes := true
|
||||
@export var curve: Curve:
|
||||
set(value):
|
||||
curve = value
|
||||
queue_redraw()
|
||||
update_controls()
|
||||
|
||||
## Array of dictionaries of key [String] and value [Array] of type [CurveEdit.CurvePoint].
|
||||
var presets: Array[Dictionary] = [
|
||||
{"Linear": [CurvePoint.new(0.0, 0.0, 0.0, 1.0), CurvePoint.new(1.0, 1.0, 1.0, 0.0)]},
|
||||
{
|
||||
"Ease out":
|
||||
[
|
||||
CurvePoint.new(0.0, 0.0, 0.0, 4.0),
|
||||
CurvePoint.new(0.292893, 0.707107, 1.0, 1.0),
|
||||
CurvePoint.new(1.0, 1.0, 0.0, 0.0)
|
||||
]
|
||||
},
|
||||
{
|
||||
"Ease in out":
|
||||
[
|
||||
CurvePoint.new(0.0, 0.0, 0.0, 0.0),
|
||||
CurvePoint.new(0.5, 0.5, 3.0, 3.0),
|
||||
CurvePoint.new(1.0, 1.0, 0.0, 0.0)
|
||||
]
|
||||
},
|
||||
{
|
||||
"Ease in":
|
||||
[
|
||||
CurvePoint.new(0.0, 0.0, 0.0, 0.0),
|
||||
CurvePoint.new(0.707107, 0.292893, 1.0, 1.0),
|
||||
CurvePoint.new(1.0, 1.0, 4.0, 0.0)
|
||||
]
|
||||
},
|
||||
{
|
||||
"Sawtooth":
|
||||
[
|
||||
CurvePoint.new(0.0, 0.0, 0.0, 2.0),
|
||||
CurvePoint.new(0.5, 1.0, 2.0, -2.0),
|
||||
CurvePoint.new(1.0, 0.0, -2.0, 0.0)
|
||||
]
|
||||
},
|
||||
{
|
||||
"Bounce":
|
||||
[
|
||||
CurvePoint.new(0.0, 0.0, 0.0, 5.0),
|
||||
CurvePoint.new(0.15, 0.65, 2.45201, 2.45201),
|
||||
CurvePoint.new(0.5, 1.0, 0.0, 0.0),
|
||||
CurvePoint.new(0.85, 0.65, -2.45201, -2.45201),
|
||||
CurvePoint.new(1.0, 0.0, -5.0, 0.0)
|
||||
]
|
||||
},
|
||||
{
|
||||
"Bevel":
|
||||
[
|
||||
CurvePoint.new(0.0, 0.0, 0.0, 2.38507),
|
||||
CurvePoint.new(0.292893, 0.707107, 2.34362, 0.428147),
|
||||
CurvePoint.new(1.0, 1.0, 0.410866, 0.0)
|
||||
]
|
||||
}
|
||||
]
|
||||
var curve_editor := Control.new()
|
||||
var hbox := HBoxContainer.new()
|
||||
|
||||
|
||||
class CurvePoint:
|
||||
var pos: Vector2
|
||||
var left_tangent: float
|
||||
var right_tangent: float
|
||||
|
||||
func _init(x: float, y: float, _left_tangent := 0.0, _right_tangent := 0.0) -> void:
|
||||
pos = Vector2(x, y)
|
||||
left_tangent = _left_tangent
|
||||
right_tangent = _right_tangent
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
if not is_instance_valid(curve):
|
||||
curve = Curve.new()
|
||||
if custom_minimum_size.is_zero_approx():
|
||||
custom_minimum_size = Vector2(32, 150)
|
||||
curve_editor.gui_input.connect(_on_gui_input)
|
||||
resized.connect(_on_resize)
|
||||
curve_editor.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
add_child(curve_editor)
|
||||
add_child(hbox)
|
||||
var presets_button := MenuButton.new()
|
||||
presets_button.text = "Presets"
|
||||
presets_button.flat = false
|
||||
presets_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
presets_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
presets_button.get_popup().id_pressed.connect(_on_presets_item_selected)
|
||||
for preset in presets:
|
||||
presets_button.get_popup().add_item(preset.keys()[0])
|
||||
var invert_button := Button.new()
|
||||
invert_button.text = "Invert"
|
||||
invert_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
invert_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
invert_button.pressed.connect(_on_invert_button_pressed)
|
||||
hbox.add_child(presets_button)
|
||||
hbox.add_child(invert_button)
|
||||
_on_resize.call_deferred()
|
||||
|
||||
|
||||
func update_controls() -> void:
|
||||
for c in curve_editor.get_children():
|
||||
if c is CurveEditControlPoint:
|
||||
c.queue_free()
|
||||
for i in curve.point_count:
|
||||
var p := curve.get_point_position(i)
|
||||
var control_point := CurveEditControlPoint.new()
|
||||
curve_editor.add_child(control_point)
|
||||
control_point.initialize(curve, i)
|
||||
control_point.position = transform_point(p) - control_point.OFFSET
|
||||
if i == 0 or i == curve.point_count - 1:
|
||||
control_point.set_constraint(
|
||||
control_point.position.x,
|
||||
control_point.position.x,
|
||||
-control_point.OFFSET.y,
|
||||
available_size().y - control_point.OFFSET.y
|
||||
)
|
||||
if i == 0:
|
||||
control_point.set_control_point_visibility(true, false)
|
||||
else:
|
||||
control_point.set_control_point_visibility(false, false)
|
||||
else:
|
||||
var min_x := transform_point(curve.get_point_position(i - 1)).x + 1
|
||||
var max_x := transform_point(curve.get_point_position(i + 1)).x - 1
|
||||
control_point.set_constraint(
|
||||
min_x, max_x, -control_point.OFFSET.y, available_size().y - control_point.OFFSET.y
|
||||
)
|
||||
control_point.moved.connect(_on_control_point_moved)
|
||||
control_point.removed.connect(_on_control_point_removed)
|
||||
value_changed.emit(curve)
|
||||
|
||||
|
||||
static func to_texture(from_curve: Curve, width := 256) -> CurveTexture:
|
||||
var texture := CurveTexture.new()
|
||||
texture.texture_mode = CurveTexture.TEXTURE_MODE_RED
|
||||
texture.curve = from_curve
|
||||
texture.width = width
|
||||
return texture
|
||||
|
||||
|
||||
func set_default_curve() -> void:
|
||||
if not is_instance_valid(curve):
|
||||
curve = Curve.new()
|
||||
_on_presets_item_selected(0)
|
||||
|
||||
|
||||
func available_size() -> Vector2:
|
||||
if curve_editor.size.is_zero_approx():
|
||||
return Vector2.ONE
|
||||
return curve_editor.size
|
||||
|
||||
|
||||
func transform_point(p: Vector2) -> Vector2:
|
||||
return (Vector2(0.0, 1.0) + Vector2(1.0, -1.0) * p) * available_size()
|
||||
|
||||
|
||||
func reverse_transform_point(p: Vector2) -> Vector2:
|
||||
return Vector2(0.0, 1.0) + Vector2(1.0, -1.0) * p / available_size()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var bg := Color.DARK_GRAY
|
||||
var fg := Color.GRAY
|
||||
var current_scene := get_tree().current_scene
|
||||
if current_scene is Control:
|
||||
var current_theme := (current_scene as Control).theme
|
||||
var panel_stylebox := current_theme.get_stylebox("panel", "Panel")
|
||||
if panel_stylebox is StyleBoxFlat:
|
||||
bg = panel_stylebox.bg_color
|
||||
fg = current_theme.get_color("font_color", "Label")
|
||||
var axes_color := bg.lerp(fg, 0.25)
|
||||
var curve_color := bg.lerp(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, available_size().y - 1), axes_color)
|
||||
draw_line(Vector2(0, p.y), Vector2(available_size().x - 1, p.y), axes_color)
|
||||
var points := PackedVector2Array()
|
||||
for i in range(curve.point_count - 1):
|
||||
var p1 := curve.get_point_position(i)
|
||||
var p2 := curve.get_point_position(i + 1)
|
||||
var d := (p2.x - p1.x) / 3.0
|
||||
var yac := p1.y + d * curve.get_point_right_tangent(i)
|
||||
var ybc := p2.y - d * curve.get_point_left_tangent(i + 1)
|
||||
var p := transform_point(p1)
|
||||
if points.is_empty():
|
||||
points.push_back(p)
|
||||
var count := maxi(1, 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 y := p1.y * omt3 + yac * omt2 * t * 3.0 + ybc * omt * t2 * 3.0 + p2.y * t3
|
||||
p = transform_point(Vector2(x, y))
|
||||
points.push_back(p)
|
||||
draw_polyline(points, curve_color)
|
||||
|
||||
|
||||
func _on_control_point_moved(index: int) -> void:
|
||||
var control_point := curve_editor.get_child(index) as CurveEditControlPoint
|
||||
var new_point := reverse_transform_point(control_point.position + control_point.OFFSET)
|
||||
curve.set_point_offset(index, new_point.x)
|
||||
curve.set_point_value(index, new_point.y)
|
||||
if is_instance_valid(control_point.left_slope):
|
||||
var slope_vector := control_point.left_slope.position / available_size()
|
||||
if slope_vector.x != 0:
|
||||
curve.set_point_left_tangent(index, -slope_vector.y / slope_vector.x)
|
||||
if is_instance_valid(control_point.right_slope):
|
||||
var slope_vector := control_point.right_slope.position / available_size()
|
||||
if slope_vector.x != 0:
|
||||
curve.set_point_right_tangent(index, -slope_vector.y / slope_vector.x)
|
||||
queue_redraw()
|
||||
value_changed.emit(curve)
|
||||
|
||||
|
||||
func _on_control_point_removed(index: int) -> void:
|
||||
if index > 0 and index < curve.point_count:
|
||||
curve.remove_point(index)
|
||||
queue_redraw()
|
||||
update_controls()
|
||||
|
||||
|
||||
func _on_gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT and event.double_click:
|
||||
var new_point_position := reverse_transform_point(get_local_mouse_position())
|
||||
curve.add_point(new_point_position, 0.0, 0.0)
|
||||
update_controls()
|
||||
|
||||
|
||||
func _on_resize() -> void:
|
||||
queue_redraw()
|
||||
update_controls()
|
||||
|
||||
|
||||
func _on_presets_item_selected(index: int) -> void:
|
||||
curve.clear_points()
|
||||
var preset_points: Array = presets[index].values()[0]
|
||||
for point: CurvePoint in preset_points:
|
||||
curve.add_point(point.pos, point.left_tangent, point.right_tangent)
|
||||
curve = curve # Call setter
|
||||
|
||||
|
||||
func _on_invert_button_pressed() -> void:
|
||||
var copy_curve := curve.duplicate() as Curve
|
||||
curve.clear_points()
|
||||
for i in copy_curve.point_count:
|
||||
var point := copy_curve.get_point_position(i)
|
||||
point.y = 1.0 - point.y
|
||||
var left_tangent := -copy_curve.get_point_left_tangent(i)
|
||||
var right_tangent := -copy_curve.get_point_right_tangent(i)
|
||||
curve.add_point(point, left_tangent, right_tangent)
|
||||
curve = curve # Call setter
|
|
@ -1,62 +0,0 @@
|
|||
# Code taken and modified from Material Maker, licensed under MIT
|
||||
# gdlint: ignore=max-line-length
|
||||
# https://github.com/RodZill4/material-maker/blob/master/material_maker/widgets/curve_edit/slope_point.gd
|
||||
class_name CurveEditTangentPoint
|
||||
extends Control
|
||||
|
||||
const OFFSET := Vector2(0, 0)
|
||||
|
||||
@export var distance := 30
|
||||
|
||||
var moving = false
|
||||
@onready var parent := get_parent() as CurveEditControlPoint
|
||||
@onready var grandparent := parent.get_parent() as Control
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
gui_input.connect(_on_gui_input)
|
||||
custom_minimum_size = Vector2(8, 8)
|
||||
if get_index() == 0:
|
||||
distance = -distance
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var color := Color.GRAY
|
||||
var current_scene := get_tree().current_scene
|
||||
if current_scene is Control:
|
||||
var current_theme := (current_scene as Control).theme
|
||||
color = current_theme.get_color("font_color", "Label")
|
||||
draw_circle(Vector2(3.0, 3.0), 3.0, color)
|
||||
|
||||
|
||||
func _on_gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||
if event.pressed:
|
||||
if event.double_click:
|
||||
var vector: Vector2
|
||||
if get_index() == 0:
|
||||
vector = (
|
||||
parent.position - grandparent.get_child(parent.get_index() - 1).position
|
||||
)
|
||||
else:
|
||||
vector = (
|
||||
grandparent.get_child(parent.get_index() + 1).position - parent.position
|
||||
)
|
||||
vector = distance * vector.normalized()
|
||||
position = vector - OFFSET
|
||||
if event.is_control_or_command_pressed():
|
||||
parent.get_child(1 - get_index()).position = -vector - OFFSET
|
||||
parent.update_tangents()
|
||||
else:
|
||||
moving = true
|
||||
else:
|
||||
moving = false
|
||||
elif moving and event is InputEventMouseMotion:
|
||||
var vector := get_global_mouse_position() - parent.get_global_rect().position + OFFSET
|
||||
vector *= signf(vector.x)
|
||||
vector = distance * vector.normalized()
|
||||
position = vector - OFFSET
|
||||
if event.is_command_or_control_pressed():
|
||||
parent.get_child(1 - get_index()).position = -vector - OFFSET
|
||||
parent.update_tangents()
|
|
@ -20,7 +20,6 @@ var effects: Array[LayerEffect] = [
|
|||
"Adjust Brightness/Contrast",
|
||||
preload("res://src/Shaders/Effects/BrightnessContrast.gdshader")
|
||||
),
|
||||
LayerEffect.new("Color Curves", preload("res://src/Shaders/Effects/ColorCurves.gdshader")),
|
||||
LayerEffect.new("Palettize", preload("res://src/Shaders/Effects/Palettize.gdshader")),
|
||||
LayerEffect.new("Pixelize", preload("res://src/Shaders/Effects/Pixelize.gdshader")),
|
||||
LayerEffect.new("Posterize", preload("res://src/Shaders/Effects/Posterize.gdshader")),
|
||||
|
@ -37,11 +36,6 @@ var effects: Array[LayerEffect] = [
|
|||
func _ready() -> void:
|
||||
for effect in effects:
|
||||
effect_list.get_popup().add_item(effect.name)
|
||||
if not DirAccess.dir_exists_absolute(OpenSave.SHADERS_DIRECTORY):
|
||||
DirAccess.make_dir_recursive_absolute(OpenSave.SHADERS_DIRECTORY)
|
||||
for file_name in DirAccess.get_files_at(OpenSave.SHADERS_DIRECTORY):
|
||||
_load_shader_file(OpenSave.SHADERS_DIRECTORY.path_join(file_name))
|
||||
OpenSave.shader_copied.connect(_load_shader_file)
|
||||
effect_list.get_popup().id_pressed.connect(_on_effect_list_id_pressed)
|
||||
|
||||
|
||||
|
@ -54,8 +48,7 @@ func _on_about_to_popup() -> void:
|
|||
var layer := Global.current_project.layers[Global.current_project.current_layer]
|
||||
enabled_button.button_pressed = layer.effects_enabled
|
||||
for effect in layer.effects:
|
||||
if is_instance_valid(effect.shader):
|
||||
_create_effect_ui(layer, effect)
|
||||
_create_effect_ui(layer, effect)
|
||||
|
||||
|
||||
func _on_visibility_changed() -> void:
|
||||
|
@ -65,14 +58,6 @@ func _on_visibility_changed() -> void:
|
|||
child.queue_free()
|
||||
|
||||
|
||||
func _load_shader_file(file_path: String) -> void:
|
||||
var file := load(file_path)
|
||||
if file is Shader:
|
||||
var effect_name := file_path.get_file().get_basename()
|
||||
effects.append(LayerEffect.new(effect_name, file))
|
||||
effect_list.get_popup().add_item(effect_name)
|
||||
|
||||
|
||||
func _on_effect_list_id_pressed(index: int) -> void:
|
||||
var layer := Global.current_project.layers[Global.current_project.current_layer]
|
||||
var effect := effects[index].duplicate()
|
||||
|
|
|
@ -14,7 +14,6 @@ const HEART_ICON := preload("res://assets/graphics/misc/heart.svg")
|
|||
var recent_projects := []
|
||||
var selected_layout := 0
|
||||
var zen_mode := false
|
||||
var loaded_effects_submenu: PopupMenu
|
||||
|
||||
# Dialogs
|
||||
var new_image_dialog := Dialog.new("res://src/UI/Dialogs/CreateNewImage.tscn")
|
||||
|
@ -34,14 +33,13 @@ var hsv_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/HSVDialog.tscn")
|
|||
var adjust_brightness_saturation_dialog := Dialog.new(
|
||||
"res://src/UI/Dialogs/ImageEffects/BrightnessContrastDialog.tscn"
|
||||
)
|
||||
var color_curves_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/ColorCurvesDialog.tscn")
|
||||
var gaussian_blur_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/GaussianBlur.tscn")
|
||||
var gradient_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/GradientDialog.tscn")
|
||||
var gradient_map_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/GradientMapDialog.tscn")
|
||||
var palettize_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/PalettizeDialog.tscn")
|
||||
var pixelize_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/PixelizeDialog.tscn")
|
||||
var posterize_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/Posterize.tscn")
|
||||
var loaded_effect_dialogs: Array[Dialog] = []
|
||||
var shader_effect_dialog := Dialog.new("res://src/UI/Dialogs/ImageEffects/ShaderEffect.tscn")
|
||||
var manage_layouts_dialog := Dialog.new("res://src/UI/Dialogs/ManageLayouts.tscn")
|
||||
var window_opacity_dialog := Dialog.new("res://src/UI/Dialogs/WindowOpacityDialog.tscn")
|
||||
var about_dialog := Dialog.new("res://src/UI/Dialogs/AboutDialog.tscn")
|
||||
|
@ -80,24 +78,21 @@ class Dialog:
|
|||
|
||||
func popup(dialog_size := Vector2i.ZERO) -> void:
|
||||
if not is_instance_valid(node):
|
||||
instantiate_scene()
|
||||
var scene := load(scene_path)
|
||||
if not scene is PackedScene:
|
||||
return
|
||||
node = scene.instantiate()
|
||||
if not is_instance_valid(node):
|
||||
return
|
||||
Global.control.get_node("Dialogs").add_child(node)
|
||||
node.popup_centered(dialog_size)
|
||||
var is_file_dialog := node is FileDialog
|
||||
Global.dialog_open(true, is_file_dialog)
|
||||
|
||||
func instantiate_scene() -> void:
|
||||
var scene := load(scene_path)
|
||||
if not scene is PackedScene:
|
||||
return
|
||||
node = scene.instantiate()
|
||||
if is_instance_valid(node):
|
||||
Global.control.get_node("Dialogs").add_child(node)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Global.project_switched.connect(_project_switched)
|
||||
Global.cel_switched.connect(_update_current_frame_mark)
|
||||
OpenSave.shader_copied.connect(_load_shader_file)
|
||||
_setup_file_menu()
|
||||
_setup_edit_menu()
|
||||
_setup_view_menu()
|
||||
|
@ -454,52 +449,21 @@ func _setup_effects_menu() -> void:
|
|||
"Desaturation": "desaturation",
|
||||
"Adjust Hue/Saturation/Value": "adjust_hsv",
|
||||
"Adjust Brightness/Contrast": "adjust_brightness_contrast",
|
||||
"Color Curves": "color_curves",
|
||||
"Palettize": "palettize",
|
||||
"Pixelize": "pixelize",
|
||||
"Posterize": "posterize",
|
||||
"Gaussian Blur": "gaussian_blur",
|
||||
"Gradient": "gradient",
|
||||
"Gradient Map": "gradient_map",
|
||||
"Loaded": ""
|
||||
# "Shader": ""
|
||||
}
|
||||
var i := 0
|
||||
for item in menu_items:
|
||||
if item == "Loaded":
|
||||
_setup_loaded_effects_submenu()
|
||||
else:
|
||||
_set_menu_shortcut(menu_items[item], effects_menu, i, item)
|
||||
_set_menu_shortcut(menu_items[item], effects_menu, i, item)
|
||||
i += 1
|
||||
effects_menu.id_pressed.connect(effects_menu_id_pressed)
|
||||
|
||||
|
||||
func _setup_loaded_effects_submenu() -> void:
|
||||
if not DirAccess.dir_exists_absolute(OpenSave.SHADERS_DIRECTORY):
|
||||
DirAccess.make_dir_recursive_absolute(OpenSave.SHADERS_DIRECTORY)
|
||||
var shader_files := DirAccess.get_files_at(OpenSave.SHADERS_DIRECTORY)
|
||||
if shader_files.size() == 0:
|
||||
return
|
||||
for shader_file in shader_files:
|
||||
_load_shader_file(OpenSave.SHADERS_DIRECTORY.path_join(shader_file))
|
||||
|
||||
|
||||
func _load_shader_file(file_path: String) -> void:
|
||||
var file := load(file_path)
|
||||
if file is not Shader:
|
||||
return
|
||||
var effect_name := file_path.get_file().get_basename()
|
||||
if not is_instance_valid(loaded_effects_submenu):
|
||||
loaded_effects_submenu = PopupMenu.new()
|
||||
loaded_effects_submenu.set_name("loaded_effects_submenu")
|
||||
loaded_effects_submenu.id_pressed.connect(_loaded_effects_submenu_id_pressed)
|
||||
effects_menu.add_child(loaded_effects_submenu)
|
||||
effects_menu.add_submenu_item("Loaded", loaded_effects_submenu.get_name())
|
||||
loaded_effects_submenu.add_item(effect_name)
|
||||
var effect_index := loaded_effects_submenu.item_count - 1
|
||||
loaded_effects_submenu.set_item_metadata(effect_index, file)
|
||||
loaded_effect_dialogs.append(Dialog.new("res://src/UI/Dialogs/ImageEffects/ShaderEffect.tscn"))
|
||||
|
||||
|
||||
func _setup_select_menu() -> void:
|
||||
# Order as in Global.SelectMenu enum
|
||||
var select_menu_items := {
|
||||
|
@ -804,17 +768,6 @@ func _snap_to_submenu_id_pressed(id: int) -> void:
|
|||
snap_to_submenu.set_item_checked(id, Global.snap_to_perspective_guides)
|
||||
|
||||
|
||||
func _loaded_effects_submenu_id_pressed(id: int) -> void:
|
||||
var dialog := loaded_effect_dialogs[id]
|
||||
if is_instance_valid(dialog.node):
|
||||
dialog.popup()
|
||||
else:
|
||||
dialog.instantiate_scene()
|
||||
var shader := loaded_effects_submenu.get_item_metadata(id) as Shader
|
||||
dialog.node.change_shader(shader, loaded_effects_submenu.get_item_text(id))
|
||||
dialog.popup()
|
||||
|
||||
|
||||
func _panels_submenu_id_pressed(id: int) -> void:
|
||||
if zen_mode:
|
||||
return
|
||||
|
@ -981,8 +934,6 @@ func effects_menu_id_pressed(id: int) -> void:
|
|||
hsv_dialog.popup()
|
||||
Global.EffectsMenu.BRIGHTNESS_SATURATION:
|
||||
adjust_brightness_saturation_dialog.popup()
|
||||
Global.EffectsMenu.COLOR_CURVES:
|
||||
color_curves_dialog.popup()
|
||||
Global.EffectsMenu.GAUSSIAN_BLUR:
|
||||
gaussian_blur_dialog.popup()
|
||||
Global.EffectsMenu.GRADIENT:
|
||||
|
@ -995,6 +946,8 @@ func effects_menu_id_pressed(id: int) -> void:
|
|||
pixelize_dialog.popup()
|
||||
Global.EffectsMenu.POSTERIZE:
|
||||
posterize_dialog.popup()
|
||||
#Global.EffectsMenu.SHADER:
|
||||
#shader_effect_dialog.popup()
|
||||
_:
|
||||
_handle_metadata(id, effects_menu)
|
||||
|
||||
|
|
Loading…
Reference in a new issue