Refactor using better Godot and JavaScript API and add an example
This commit is contained in:
parent
a5ca12fd6d
commit
4af1125541
@ -1 +1,8 @@
|
||||
# HTML5 File Exchange for Godot 3.2
|
||||
|
||||
## Usage
|
||||
|
||||
* Copy addons to your project.
|
||||
* Enable the plugin. (A `HTML5File` singleton should be added into autoload list).
|
||||
* Add a HTML5 export item to enable HTML5 debugging option.
|
||||
* Check sample.tscn for usage.
|
@ -1,24 +1,21 @@
|
||||
extends Node
|
||||
|
||||
signal InFocus
|
||||
signal read_completed
|
||||
signal load_completed(image)
|
||||
|
||||
var js_callback = JavaScript.create_callback(self, "load_handler");
|
||||
var js_interface;
|
||||
|
||||
func _ready():
|
||||
if OS.get_name() == "HTML5" and OS.has_feature('JavaScript'):
|
||||
_define_js()
|
||||
|
||||
|
||||
func _notification(notification:int) -> void:
|
||||
if notification == MainLoop.NOTIFICATION_WM_FOCUS_IN:
|
||||
emit_signal("InFocus")
|
||||
js_interface = JavaScript.get_interface("_HTML5FileExchange");
|
||||
|
||||
func _define_js()->void:
|
||||
#Define JS script
|
||||
JavaScript.eval("""
|
||||
var fileData;
|
||||
var fileType;
|
||||
var fileName;
|
||||
var canceled;
|
||||
function upload() {
|
||||
var _HTML5FileExchange = {};
|
||||
_HTML5FileExchange.upload = function(gd_callback) {
|
||||
canceled = true;
|
||||
var input = document.createElement('INPUT');
|
||||
input.setAttribute("type", "file");
|
||||
@ -29,56 +26,32 @@ func _define_js()->void:
|
||||
canceled = false;}
|
||||
var file = event.target.files[0];
|
||||
var reader = new FileReader();
|
||||
fileType = file.type;
|
||||
fileName = file.name;
|
||||
this.fileType = file.type;
|
||||
// var fileName = file.name;
|
||||
reader.readAsArrayBuffer(file);
|
||||
reader.onloadend = function (evt) {
|
||||
reader.onloadend = (evt) => { // Since here's it's arrow function, "this" still refers to _HTML5FileExchange
|
||||
if (evt.target.readyState == FileReader.DONE) {
|
||||
fileData = evt.target.result;
|
||||
this.result = evt.target.result;
|
||||
gd_callback(); // It's hard to retrieve value from callback argument, so it's just for notification
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function download(fileName, byte) {
|
||||
var buffer = Uint8Array.from(byte);
|
||||
var blob = new Blob([buffer], { type: 'image/png'});
|
||||
var link = document.createElement('a');
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = fileName;
|
||||
link.click();
|
||||
};
|
||||
""", true)
|
||||
|
||||
func load_handler(_args):
|
||||
emit_signal("read_completed")
|
||||
|
||||
func load_image()->Image:
|
||||
func load_image():
|
||||
if OS.get_name() != "HTML5" or !OS.has_feature('JavaScript'):
|
||||
return
|
||||
|
||||
#Execute js function
|
||||
JavaScript.eval("upload();", true) #opens promt for choosing file
|
||||
js_interface.upload(js_callback);
|
||||
|
||||
#label.text = "Wait for focus"
|
||||
yield(self, "InFocus") #wait until js promt is closed
|
||||
yield(self, "read_completed")
|
||||
|
||||
#label.text = "Timer on for loading"
|
||||
yield(get_tree().create_timer(0.1), "timeout") #give some time for async js data load
|
||||
|
||||
if JavaScript.eval("canceled;", true): # if File Dialog closed w/o file
|
||||
#label.text = "Canceled prompt"
|
||||
return
|
||||
|
||||
# use data from png data
|
||||
#label.text = "Load image"
|
||||
var imageData
|
||||
while true:
|
||||
imageData = JavaScript.eval("fileData;", true)
|
||||
if imageData != null:
|
||||
break
|
||||
#label.text = "No image yet"
|
||||
yield(get_tree().create_timer(1.0), "timeout") #need more time to load data
|
||||
|
||||
var imageType = JavaScript.eval("fileType;", true)
|
||||
var imageName = JavaScript.eval("fileName;", true)
|
||||
var imageType = js_interface.fileType;
|
||||
var imageData = JavaScript.eval("_HTML5FileExchange.result", true) # interface doesn't work as expected for some reason
|
||||
|
||||
var image = Image.new()
|
||||
var image_error
|
||||
@ -90,39 +63,18 @@ func load_image()->Image:
|
||||
"image/webp":
|
||||
image_error = image.load_webp_from_buffer(imageData)
|
||||
var invalidType:
|
||||
#label.text = "Unsupported file format - %s." % invalidType
|
||||
print("Unsupported file format - %s." % invalidType)
|
||||
return
|
||||
|
||||
if image_error:
|
||||
#label.text = "An error occurred while trying to display the image."
|
||||
return
|
||||
else:
|
||||
return image
|
||||
# Display texture
|
||||
var tex = ImageTexture.new()
|
||||
tex.create_from_image(image, 0) # Flag = 0 or else export is fucked!
|
||||
Sprite.texture = tex
|
||||
#loadedImage = image # Keep Image for later, just in case...
|
||||
#loadedImageName = imageName
|
||||
#label.text = "Image %s loaded as %s." % [imageName, imageType]
|
||||
return
|
||||
#label.text = "Something went wrong"
|
||||
print("An error occurred while trying to display the image.")
|
||||
|
||||
emit_signal("load_completed", image)
|
||||
|
||||
func save_image(image:Image, fileName:String = "export")->void:
|
||||
func save_image(image:Image, fileName:String = "export.png")->void:
|
||||
if OS.get_name() != "HTML5" or !OS.has_feature('JavaScript'):
|
||||
return
|
||||
|
||||
image.clear_mipmaps()
|
||||
if image.save_png("user://export_temp.png"):
|
||||
#label.text = "Error saving temp file"
|
||||
return
|
||||
var file:File = File.new()
|
||||
if file.open("user://export_temp.png", File.READ):
|
||||
#label.text = "Error opening file"
|
||||
return
|
||||
var pngData = Array(file.get_buffer(file.get_len())) #read data as PoolByteArray and convert it to Array for JS
|
||||
file.close()
|
||||
var dir = Directory.new()
|
||||
dir.remove("user://export_temp.png")
|
||||
JavaScript.eval("download('%s', %s);" % [fileName, str(pngData)], true)
|
||||
#label.text = "Saving DONE"
|
||||
var buffer = image.save_png_to_buffer()
|
||||
JavaScript.download_buffer(buffer, fileName)
|
||||
|
19
addons/HTML5FileExchange/Sample.gd
Normal file
19
addons/HTML5FileExchange/Sample.gd
Normal file
@ -0,0 +1,19 @@
|
||||
extends TextureRect
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
func _on_UploadButton_pressed():
|
||||
HTML5File.load_image()
|
||||
|
||||
var image = yield(HTML5File, "load_completed")
|
||||
|
||||
var tex = ImageTexture.new()
|
||||
tex.create_from_image(image, 0)
|
||||
|
||||
texture = tex;
|
||||
|
||||
func _on_DownloadButton_pressed():
|
||||
var image = texture.get_data()
|
||||
HTML5File.save_image(image, "image.png")
|
35
addons/HTML5FileExchange/sample.tscn
Normal file
35
addons/HTML5FileExchange/sample.tscn
Normal file
@ -0,0 +1,35 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/HTML5FileExchange/Sample.gd" type="Script" id=1]
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||
margin_right = 136.0
|
||||
margin_bottom = 20.0
|
||||
|
||||
[node name="UploadButton" type="Button" parent="VBoxContainer/HBoxContainer"]
|
||||
margin_right = 57.0
|
||||
margin_bottom = 20.0
|
||||
text = "Upload"
|
||||
|
||||
[node name="DownloadButton" type="Button" parent="VBoxContainer/HBoxContainer"]
|
||||
margin_left = 61.0
|
||||
margin_right = 136.0
|
||||
margin_bottom = 20.0
|
||||
text = "Download"
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="VBoxContainer"]
|
||||
margin_top = 24.0
|
||||
margin_right = 136.0
|
||||
margin_bottom = 24.0
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/UploadButton" to="VBoxContainer/TextureRect" method="_on_UploadButton_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/DownloadButton" to="VBoxContainer/TextureRect" method="_on_DownloadButton_pressed"]
|
7
default_env.tres
Normal file
7
default_env.tres
Normal file
@ -0,0 +1,7 @@
|
||||
[gd_resource type="Environment" load_steps=2 format=2]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
|
||||
[resource]
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
35
icon.png.import
Normal file
35
icon.png.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
31
project.godot
Normal file
31
project.godot
Normal file
@ -0,0 +1,31 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=4
|
||||
|
||||
[application]
|
||||
|
||||
config/name="HTML5-File-Exchange-for-Godot"
|
||||
run/main_scene="res://addons/HTML5FileExchange/sample.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[autoload]
|
||||
|
||||
HTML5File="*res://addons/HTML5FileExchange/HTML5FileExchange.gd"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PoolStringArray( "res://addons/HTML5FileExchange/plugin.cfg" )
|
||||
|
||||
[physics]
|
||||
|
||||
common/enable_pause_aware_picking=true
|
||||
|
||||
[rendering]
|
||||
|
||||
environment/default_environment="res://default_env.tres"
|
Loading…
Reference in New Issue
Block a user