mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 17:19:50 +00:00
[EXPERIMENTAL] Added ability to load a shader as an image effect
This new feature allows users to load a .shader file (must be a GLES2 Godot shader) that will modify the image itself. This feature is experimental and possibly buggy, not all shaders are working properly and I'm not sure yet why. As such, this feature may not be included in v0.8 stable.
This commit is contained in:
parent
59122f6a13
commit
186e2259ac
|
@ -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()
|
||||
|
||||
|
|
|
@ -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 )]
|
||||
|
|
56
src/UI/Dialogs/ShaderEffect.gd
Normal file
56
src/UI/Dialogs/ShaderEffect.gd
Normal file
|
@ -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()
|
86
src/UI/Dialogs/ShaderEffect.tscn
Normal file
86
src/UI/Dialogs/ShaderEffect.tscn
Normal file
|
@ -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"]
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue