diff --git a/assets/error.svg b/assets/error.svg
new file mode 100644
index 0000000..af2f066
--- /dev/null
+++ b/assets/error.svg
@@ -0,0 +1,80 @@
+
+
+
+
diff --git a/assets/error.svg.import b/assets/error.svg.import
new file mode 100644
index 0000000..07666be
--- /dev/null
+++ b/assets/error.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://04iv1gogpuhu"
+path="res://.godot/imported/error.svg-75fe5f417585e01e99de8885f1f45c3b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/error.svg"
+dest_files=["res://.godot/imported/error.svg-75fe5f417585e01e99de8885f1f45c3b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=2.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/icon.png b/assets/icon.png
similarity index 100%
rename from icon.png
rename to assets/icon.png
diff --git a/icon.png.import b/assets/icon.png.import
similarity index 73%
rename from icon.png.import
rename to assets/icon.png.import
index a0840e4..ce38ae5 100644
--- a/icon.png.import
+++ b/assets/icon.png.import
@@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://kqwc4avs2xdp"
-path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
+path="res://.godot/imported/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.ctex"
metadata={
"vram_texture": false
}
[deps]
-source_file="res://icon.png"
-dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"]
+source_file="res://assets/icon.png"
+dest_files=["res://.godot/imported/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.ctex"]
[params]
diff --git a/assets/okay.svg b/assets/okay.svg
new file mode 100644
index 0000000..5668fe8
--- /dev/null
+++ b/assets/okay.svg
@@ -0,0 +1,81 @@
+
+
+
+
diff --git a/assets/okay.svg.import b/assets/okay.svg.import
new file mode 100644
index 0000000..6b6c11f
--- /dev/null
+++ b/assets/okay.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://m1omb6g45vst"
+path="res://.godot/imported/okay.svg-7f6df15523471a86f27b6817e9528a4e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/okay.svg"
+dest_files=["res://.godot/imported/okay.svg-7f6df15523471a86f27b6817e9528a4e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=2.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/project.godot b/project.godot
index b65f388..f6f242c 100644
--- a/project.godot
+++ b/project.godot
@@ -15,7 +15,7 @@ config/version="v5.0"
run/main_scene="res://scenes/main.tscn"
config/features=PackedStringArray("4.3", "Mobile")
run/low_processor_mode=true
-config/icon="res://icon.png"
+config/icon="res://assets/icon.png"
[autoload]
diff --git a/scenes/ui_container.tscn b/scenes/ui_container.tscn
index b804125..1c008b4 100644
--- a/scenes/ui_container.tscn
+++ b/scenes/ui_container.tscn
@@ -165,6 +165,29 @@ offset_bottom = 31.0
grow_horizontal = 0
text = "Apply (F5)"
+[node name="StatusIndicator" type="TextureButton" parent="Editor"]
+unique_name_in_owner = true
+layout_mode = 1
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -80.0
+offset_top = 56.0
+offset_right = -56.0
+offset_bottom = 80.0
+grow_horizontal = 0
+disabled = true
+ignore_texture_size = true
+stretch_mode = 0
+
+[node name="ErrorMessageDialog" type="AcceptDialog" parent="Editor"]
+unique_name_in_owner = true
+title = "Status"
+initial_position = 2
+size = Vector2i(256, 128)
+popup_window = true
+ok_button_text = "Close"
+
[connection signal="file_selected" from="Editor/OpenShaderDialog" to="Editor" method="_on_open_shader_dialog_file_selected"]
[connection signal="file_selected" from="Editor/SaveShaderDialog" to="Editor" method="_on_save_shader_dialog_file_selected"]
[connection signal="file_selected" from="Editor/SaveImageDialog" to="Editor" method="_on_save_image_dialog_file_selected"]
@@ -176,3 +199,4 @@ text = "Apply (F5)"
[connection signal="pressed" from="Editor/SaveImageButton" to="Editor" method="_on_save_image_button_pressed"]
[connection signal="pressed" from="Editor/FitImageButton" to="Editor" method="_on_fit_image_button_pressed"]
[connection signal="pressed" from="Editor/ApplyShaderButton" to="Editor" method="_on_apply_shader_button_pressed"]
+[connection signal="pressed" from="Editor/StatusIndicator" to="Editor" method="_on_status_indicator_pressed"]
diff --git a/src/Editor.gd b/src/Editor.gd
index cad4f38..e191d47 100644
--- a/src/Editor.gd
+++ b/src/Editor.gd
@@ -6,9 +6,17 @@ extends Control
@onready var save_shader_dialog = %SaveShaderDialog
@onready var ui_control_filesave = %SaveImageDialog
+@onready var status_indicator = %StatusIndicator
+@onready var error_msg_dialog = %ErrorMessageDialog
+
@onready var image_viewport = get_tree().root.get_node("Main/%ImageViewport")
@onready var camera = get_tree().root.get_node("Main/%Camera")
+#
+
+var status_okay_texture: CompressedTexture2D = preload("uid://m1omb6g45vst")
+var status_error_texture: CompressedTexture2D = preload("uid://04iv1gogpuhu")
+
# # # # # # # # # # #
# GDShader keywords #
# https://github.com/godotengine/godot/blob/e96ad5af98547df71b50c4c4695ac348638113e0/servers/rendering/shader_language.cpp
@@ -173,7 +181,7 @@ func _on_code_edit_code_completion_requested():
func _ready():
code_editor.code_completion_enabled = true
code_editor.syntax_highlighter = ShaderSyntaxHighlighter.new()
- self.update()
+ self.update_code_edit()
func _input(event):
if event.is_action_pressed("apply_shader"):
@@ -182,15 +190,32 @@ func _input(event):
accept_event() # Event is now handled.
_on_save_shader_button_pressed()
-func update():
+func update_code_edit():
code_editor.text = Filesystem.shader.code
+enum Status {OKAY, ERROR, UNKNOWN = -1}
+
+func update_status(status: Status, msg: String = ""):
+ error_msg_dialog.dialog_text = msg
+ error_msg_dialog.reset_size()
+ if status == Status.OKAY:
+ status_indicator.texture_normal = status_okay_texture
+ elif status == Status.ERROR:
+ status_indicator.texture_normal = status_error_texture
+ else:
+ status_indicator.texture_normal = null
+ if msg == "":
+ status_indicator.disabled = true
+ else:
+ status_indicator.disabled = false
+
#
func _on_new_shader_button_pressed():
Filesystem.reset()
- self.update()
+ self.update_code_edit()
image_viewport.update()
+ update_status(Status.UNKNOWN)
func _on_open_shader_button_pressed():
open_shader_dialog.show()
@@ -215,7 +240,11 @@ func _on_fit_image_button_pressed():
func _on_apply_shader_button_pressed():
Filesystem.shader.code = code_editor.text
- image_viewport.update()
+ var errors = await image_viewport.update()
+ if len(errors) > 0:
+ update_status(Status.ERROR, "\n".join(errors))
+ else:
+ update_status(Status.OKAY)
func _on_save_image_button_pressed():
if Filesystem.result != null:
@@ -226,11 +255,16 @@ func _on_save_image_button_pressed():
func _on_open_shader_dialog_file_selected(path: String):
Filesystem.load_shader(path)
- image_viewport.update()
- self.update()
+ self.update_code_edit()
+ self._on_apply_shader_button_pressed()
func _on_save_shader_dialog_file_selected(path):
Filesystem.save_shader(path)
func _on_save_image_dialog_file_selected(path):
Filesystem.save_result(path)
+
+#
+
+func _on_status_indicator_pressed() -> void:
+ error_msg_dialog.show()
diff --git a/src/Filesystem.gd b/src/Filesystem.gd
index 18fd3d4..9f92261 100644
--- a/src/Filesystem.gd
+++ b/src/Filesystem.gd
@@ -2,7 +2,9 @@ extends Node
@onready var template_shader: Shader = load("res://src/shader/template.gdshader")
@onready var shader: Shader = template_shader.duplicate()
+
var original_image: ImageTexture
+var additional_images: Dictionary
var result: Image
var cwd = "."
@@ -24,8 +26,7 @@ func get_absolute_path(p: String) -> String:
return self.cwd + "/" + p.lstrip("./")
return p
-func load_original_image(path: String):
- print("Load ", path)
+func load_original_image(path: String) -> String: # returns an error message
var img = Image.new()
var err = img.load(path)
if err == OK:
@@ -34,12 +35,20 @@ func load_original_image(path: String):
self.last_original_image_path = path
if self.last_image_savepath == "":
self.last_image_savepath = path
- else:
- print("An error occured!")
+ return ""
+ return error_string(err) + " " + path
-func load_image(path: String) -> ImageTexture:
- print("Load ", path)
- return ImageTexture.create_from_image(Image.load_from_file(path))
+func clear_additional_images():
+ additional_images.clear()
+
+func load_additional_image(key: String, path: String) -> String: # returns Error Message String
+ var img = Image.new()
+ var err = img.load(path)
+ if err == OK:
+ additional_images[key] = ImageTexture.create_from_image(img)
+ return ""
+ else:
+ return error_string(err) + " " + path
func save_result(path: String):
print("Export ", path)
diff --git a/src/ImageViewport.gd b/src/ImageViewport.gd
index d327ce8..288929f 100644
--- a/src/ImageViewport.gd
+++ b/src/ImageViewport.gd
@@ -4,31 +4,42 @@ extends SubViewport
@onready var image_sprite = %ImageSprite
@onready var image_viewport_display = %ImageViewportDisplay
-func update():
+func update() -> Array: # returns error messages (strings)
+ var errors = []
var fit_image = false
- # load image from //!load directive -> TEXTURE
+ # load texture(s)
+ Filesystem.clear_additional_images()
+ # ... from //!load directive -> TEXTURE
var m = ShaderDirectiveParser.parse_load_directive(Filesystem.shader)
if len(m) < 1:
- return # AAAAAAAa
+ errors.append("Didn't find a load directive!")
+ return errors
var original_image_path = Filesystem.get_absolute_path(m[1])
if original_image_path != Filesystem.last_original_image_path:
fit_image = true
- Filesystem.load_original_image(original_image_path)
- if Filesystem.original_image == null:
+ var err = Filesystem.load_original_image(original_image_path)
+ if err != "":
+ errors.append(err)
image_viewport_display.hide()
- return
+ return errors
+ # ... from //!load+ directives
+ for n in ShaderDirectiveParser.parse_load_additional_directive(Filesystem.shader):
+ err = Filesystem.load_additional_image(n[1], Filesystem.get_absolute_path(n[2]))
+ if err != "":
+ errors.append(err)
+ if len(errors) > 0:
+ return errors
+ # apply textures
image_sprite.texture = Filesystem.original_image
image_sprite.offset = Filesystem.original_image.get_size() / 2
self.size = Filesystem.original_image.get_size()
var mat = ShaderMaterial.new()
mat.shader = Filesystem.shader
- # load images from //!load+ directives and apply them to
- # the material as shader parameters
- for n in ShaderDirectiveParser.parse_load_additional_directive(Filesystem.shader):
+ # ... as shader parameters
+ for key in Filesystem.additional_images:
mat.set_shader_parameter(
- n[1], # uniform param name
- Filesystem.load_image(Filesystem.get_absolute_path(n[2]))
- )
+ key, # uniform param name
+ Filesystem.additional_images[key])
# assign material
image_sprite.material = mat
# Get viewport texture
@@ -39,3 +50,5 @@ func update():
if fit_image:
camera.fit_image()
image_viewport_display.show()
+ # done
+ return errors
diff --git a/src/ShaderDirectiveParser.gd b/src/ShaderDirectiveParser.gd
index 936eaa7..6dd031b 100644
--- a/src/ShaderDirectiveParser.gd
+++ b/src/ShaderDirectiveParser.gd
@@ -11,8 +11,7 @@ func _ready():
func parse_load_directive(shader: Shader) -> PackedStringArray:
var regex_match = self._load_regex.search(Filesystem.shader.code)
- if regex_match == null: # Error!
- printerr("Didn't find any load directives!")
+ if regex_match == null:
return []
return regex_match.strings