diff --git a/src/Autoload/HTML5FileExchange.gd b/src/Autoload/HTML5FileExchange.gd index 19d4fad9c..96b380271 100644 --- a/src/Autoload/HTML5FileExchange.gd +++ b/src/Autoload/HTML5FileExchange.gd @@ -69,6 +69,27 @@ func _define_js() -> void: } }); } + function upload_shader() { + canceled = true; + var input = document.createElement('INPUT'); + input.setAttribute("type", "file"); + input.setAttribute("accept", ".shader"); + input.click(); + input.addEventListener('change', event => { + if (event.target.files.length > 0){ + canceled = false;} + var file = event.target.files[0]; + var reader = new FileReader(); + fileType = file.type; + fileName = file.name; + reader.readAsText(file); + reader.onloadend = function (evt) { + if (evt.target.readyState == FileReader.DONE) { + fileData = evt.target.result; + } + } + }); + } function download(fileName, byte, type) { var buffer = Uint8Array.from(byte); var blob = new Blob([buffer], { type: type}); @@ -174,3 +195,37 @@ func save_image(image : Image, file_name : String = "export") -> void: var png_data = Array(image.save_png_to_buffer()) JavaScript.eval("download('%s', %s, 'image/png');" % [file_name, str(png_data)], true) + + +func load_shader() -> void: + if OS.get_name() != "HTML5" or !OS.has_feature('JavaScript'): + return + + # Execute JS function + JavaScript.eval("upload_shader();", true) # Opens prompt for choosing file + + yield(self, "InFocus") # Wait until JS prompt is closed + + yield(get_tree().create_timer(0.5), "timeout") # Give some time for async JS data load + + if JavaScript.eval("canceled;", true): # If File Dialog closed w/o file + return + + # Use data from png data + var file_data + while true: + file_data = JavaScript.eval("fileData;", true) + if file_data != null: + break + yield(get_tree().create_timer(1.0), "timeout") # Need more time to load data + +# var file_type = JavaScript.eval("fileType;", true) + var file_name = JavaScript.eval("fileName;", true) + + var shader = Shader.new() + shader.code = file_data + + var shader_effect_dialog = Global.control.get_node("Dialogs/ImageEffects/ShaderEffect") + shader_effect_dialog.preview.material.shader = shader + shader_effect_dialog.shader_loaded_label.text = tr("Shader loaded:") + " " + file_name.get_basename() + diff --git a/src/Main.tscn b/src/Main.tscn index 3f386476c..eaee70651 100644 --- a/src/Main.tscn +++ b/src/Main.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=21 format=2] +[gd_scene load_steps=22 format=2] [ext_resource path="res://assets/themes/dark/theme.tres" type="Theme" id=1] [ext_resource path="res://src/Main.gd" type="Script" id=2] @@ -9,6 +9,7 @@ [ext_resource path="res://src/UI/Dialogs/ResizeCanvas.tscn" type="PackedScene" id=7] [ext_resource path="res://src/UI/Dialogs/SaveSpriteHTML5.tscn" type="PackedScene" id=8] [ext_resource path="res://src/UI/Dialogs/GradientDialog.tscn" type="PackedScene" id=9] +[ext_resource path="res://src/UI/Dialogs/ShaderEffect.tscn" type="PackedScene" id=10] [ext_resource path="res://src/UI/Dialogs/SaveSprite.tscn" type="PackedScene" id=11] [ext_resource path="res://src/UI/Dialogs/OpenSprite.tscn" type="PackedScene" id=12] [ext_resource path="res://src/UI/Dialogs/SplashDialog.tscn" type="PackedScene" id=27] @@ -45,17 +46,16 @@ __meta__ = { [node name="UI" parent="MenuAndUI" instance=ExtResource( 4 )] [node name="Dialogs" type="Control" parent="."] -margin_right = 40.0 -margin_bottom = 40.0 mouse_filter = 2 __meta__ = { "_edit_use_anchors_": false } [node name="ImageEffects" type="Control" parent="Dialogs"] -margin_right = 40.0 -margin_bottom = 40.0 mouse_filter = 2 +__meta__ = { +"_edit_use_anchors_": false +} [node name="ScaleImage" parent="Dialogs/ImageEffects" instance=ExtResource( 31 )] margin_bottom = 127.0 @@ -75,6 +75,8 @@ margin_bottom = 106.0 [node name="GradientDialog" parent="Dialogs/ImageEffects" instance=ExtResource( 9 )] margin_bottom = 214.0 +[node name="ShaderEffect" parent="Dialogs/ImageEffects" instance=ExtResource( 10 )] + [node name="BrushesPopup" parent="Dialogs" instance=ExtResource( 6 )] [node name="PatternsPopup" parent="Dialogs" instance=ExtResource( 5 )] diff --git a/src/UI/Dialogs/ShaderEffect.gd b/src/UI/Dialogs/ShaderEffect.gd new file mode 100644 index 000000000..b9a161dd5 --- /dev/null +++ b/src/UI/Dialogs/ShaderEffect.gd @@ -0,0 +1,56 @@ +extends ConfirmationDialog + + +var current_cel : Image + +onready var viewport : Viewport = $VBoxContainer/ViewportContainer/Viewport +onready var preview : TextureRect = viewport.get_node("Preview") +onready var shader_loaded_label : Label = $VBoxContainer/ShaderLoadedLabel + + +func _on_ShaderEffect_about_to_show() -> void: + current_cel = Global.current_project.frames[Global.current_project.current_frame].cels[Global.current_project.current_layer].image + current_cel.unlock() + viewport.size = current_cel.get_size() + var viewport_texture = viewport.get_texture().get_data() + viewport_texture.convert(Image.FORMAT_RGBA8) + + var preview_image := Image.new() + preview_image.copy_from(current_cel) + var preview_texture = ImageTexture.new() + preview_texture.create_from_image(preview_image, 0) + preview.texture = preview_texture + + +func _on_ShaderEffect_confirmed() -> void: + var viewport_texture = viewport.get_texture().get_data() + viewport_texture.flip_y() + viewport_texture.convert(Image.FORMAT_RGBA8) + print(viewport_texture.get_size()) + Global.canvas.handle_undo("Draw") + current_cel.copy_from(viewport_texture) + Global.canvas.handle_redo("Draw") + + +func _on_ShaderEffect_popup_hide() -> void: + current_cel.lock() + Global.dialog_open(false) + yield(get_tree().create_timer(0.2), "timeout") + preview.texture = null + viewport.size = Vector2.ONE + rect_size = Vector2.ONE + + +func _on_ChooseShader_pressed() -> void: + if OS.get_name() == "HTML5": + Html5FileExchange.load_shader() + else: + $FileDialog.popup_centered(Vector2(200, 340)) + + +func _on_FileDialog_file_selected(path : String) -> void: + var shader = load(path) + if !shader is Shader: + return + preview.material.shader = shader + shader_loaded_label.text = tr("Shader loaded:") + " " + path.get_file().get_basename() diff --git a/src/UI/Dialogs/ShaderEffect.tscn b/src/UI/Dialogs/ShaderEffect.tscn new file mode 100644 index 000000000..f34128008 --- /dev/null +++ b/src/UI/Dialogs/ShaderEffect.tscn @@ -0,0 +1,86 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://src/UI/Dialogs/ShaderEffect.gd" type="Script" id=2] + +[sub_resource type="ShaderMaterial" id=1] + +[node name="ShaderEffect" type="ConfirmationDialog"] +margin_right = 200.0 +margin_bottom = 228.0 +rect_min_size = Vector2( 0, 0 ) +resizable = true +script = ExtResource( 2 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 8.0 +margin_top = 8.0 +margin_right = -8.0 +margin_bottom = -36.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="VBoxContainer"] +margin_right = 255.0 +margin_bottom = 48.0 +text = "This is an experimental feature and may not be included in the stable version" +autowrap = true + +[node name="ViewportContainer" type="ViewportContainer" parent="VBoxContainer"] +margin_top = 52.0 +margin_right = 255.0 +margin_bottom = 53.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Viewport" type="Viewport" parent="VBoxContainer/ViewportContainer"] +size = Vector2( 1, 1 ) +transparent_bg = true +handle_input_locally = false +disable_3d = true +usage = 0 +render_target_update_mode = 0 +gui_disable_input = true + +[node name="Preview" type="TextureRect" parent="VBoxContainer/ViewportContainer/Viewport"] +material = SubResource( 1 ) +anchor_right = 1.0 +anchor_bottom = 1.0 + +[node name="ChooseShader" type="Button" parent="VBoxContainer"] +margin_top = 57.0 +margin_right = 255.0 +margin_bottom = 77.0 +mouse_default_cursor_shape = 2 +text = "Choose Shader" + +[node name="ShaderLoadedLabel" type="Label" parent="VBoxContainer"] +margin_top = 81.0 +margin_right = 255.0 +margin_bottom = 95.0 +text = "No shader loaded!" +autowrap = true + +[node name="FileDialog" type="FileDialog" parent="."] +margin_left = 8.0 +margin_top = 8.0 +margin_right = 263.0 +margin_bottom = 192.0 +window_title = "Open a File" +resizable = true +mode = 0 +access = 2 +filters = PoolStringArray( "*shader" ) +current_dir = "/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama" +current_path = "/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama/" +[connection signal="about_to_show" from="." to="." method="_on_ShaderEffect_about_to_show"] +[connection signal="confirmed" from="." to="." method="_on_ShaderEffect_confirmed"] +[connection signal="popup_hide" from="." to="." method="_on_ShaderEffect_popup_hide"] +[connection signal="pressed" from="VBoxContainer/ChooseShader" to="." method="_on_ChooseShader_pressed"] +[connection signal="file_selected" from="FileDialog" to="." method="_on_FileDialog_file_selected"] diff --git a/src/UI/TopMenuContainer.gd b/src/UI/TopMenuContainer.gd index 3bdaf5c79..534eab882 100644 --- a/src/UI/TopMenuContainer.gd +++ b/src/UI/TopMenuContainer.gd @@ -94,7 +94,8 @@ func setup_image_menu() -> void: "Desaturation" : 0, "Outline" : 0, "Adjust Hue/Saturation/Value" : 0, - "Gradient" : 0 + "Gradient" : 0, + "Shader" : 0 } var image_menu : PopupMenu = Global.image_menu.get_popup() @@ -333,6 +334,9 @@ func image_menu_id_pressed(id : int) -> void: 10: # Gradient Global.control.get_node("Dialogs/ImageEffects/GradientDialog").popup_centered() Global.dialog_open(true) + 11: # Shader + Global.control.get_node("Dialogs/ImageEffects/ShaderEffect").popup_centered() + Global.dialog_open(true) func show_scale_image_popup() -> void: