Added an error indicator and error message box and refactored some code in the process - implements #21, prepares #16

This commit is contained in:
ChaoticByte 2024-12-26 22:18:18 +01:00
parent ca40971e53
commit 8394ad9d3c
No known key found for this signature in database
12 changed files with 345 additions and 31 deletions

80
assets/error.svg Normal file
View file

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="30"
height="30"
viewBox="0 0 30 30"
version="1.1"
id="svg5"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="error.svg"
inkscape:export-filename="error.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:document-units="px"
showgrid="true"
inkscape:zoom="22.627417"
inkscape:cx="12.28598"
inkscape:cy="16.108776"
inkscape:window-width="1854"
inkscape:window-height="1011"
inkscape:window-x="66"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
type="xygrid"
id="grid9"
originx="0"
originy="0" />
</sodipodi:namedview>
<defs
id="defs2">
<rect
x="-19.109422"
y="15.119667"
width="23.697131"
height="28.949477"
id="rect4519" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="display:none;opacity:0.75;fill:#ff3815;fill-opacity:1;stroke:#ff3815;stroke-width:6;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 4,25 H 26 L 15,6 Z"
id="path11345"
sodipodi:nodetypes="cccc" />
<circle
style="opacity:0.75;fill:#ff3815;fill-opacity:1;stroke:none;stroke-width:6;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="path15121"
cx="15"
cy="15"
r="13" />
<g
aria-label="!"
transform="matrix(0.80238423,0,0,0.80238423,20.811527,-5.9033718)"
id="text4517"
style="font-size:24px;white-space:pre;shape-inside:url(#rect4519);display:inline;fill:#ffffff;fill-opacity:1">
<path
d="m -5.6133052,29.164717 h -3.264 L -9.5630195,16.081288 h 4.6354286 z m -4.0045715,4.580571 q 0,-1.261715 0.6857143,-1.755429 0.6857143,-0.521142 1.6731429,-0.521142 0.96,0 1.6457143,0.521142 0.6857143,0.493714 0.6857143,1.755429 0,1.206857 -0.6857143,1.755429 -0.6857143,0.521142 -1.6457143,0.521142 -0.9874286,0 -1.6731429,-0.521142 -0.6857143,-0.548572 -0.6857143,-1.755429 z"
style="font-weight:bold;-inkscape-font-specification:'sans-serif Bold';text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke-width:1.14286"
id="path4674" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

37
assets/error.svg.import Normal file
View file

@ -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

View file

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3 KiB

Before After
Before After

View file

@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://kqwc4avs2xdp" uid="uid://kqwc4avs2xdp"
path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex" path="res://.godot/imported/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://icon.png" source_file="res://assets/icon.png"
dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"] dest_files=["res://.godot/imported/icon.png-b6a7fb2db36edd3d95dc42f1dc8c1c5d.ctex"]
[params] [params]

81
assets/okay.svg Normal file
View file

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="30"
height="30"
viewBox="0 0 30 30"
version="1.1"
id="svg5"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="success.svg"
inkscape:export-filename="error.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:document-units="px"
showgrid="true"
inkscape:zoom="22.627417"
inkscape:cx="3.314563"
inkscape:cy="14.385204"
inkscape:window-width="1854"
inkscape:window-height="1011"
inkscape:window-x="66"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
type="xygrid"
id="grid9"
originx="0"
originy="0" />
</sodipodi:namedview>
<defs
id="defs2">
<rect
x="0"
y="0"
width="30"
height="30"
id="rect15390" />
<rect
x="-19.109422"
y="15.119667"
width="23.697131"
height="28.949477"
id="rect4519" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="display:none;opacity:0.75;fill:#ff3815;fill-opacity:1;stroke:#ff3815;stroke-width:6;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 4,25 H 26 L 15,6 Z"
id="path11345"
sodipodi:nodetypes="cccc" />
<circle
style="opacity:0.75;fill:#15ff1e;fill-opacity:1;stroke:none;stroke-width:6;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="path15121"
cx="15"
cy="15"
r="13" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 8.1284306,14.403599 5.2374004,4.840883 8.39167,-9.6564053"
id="path20589"
sodipodi:nodetypes="ccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

37
assets/okay.svg.import Normal file
View file

@ -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

View file

@ -15,7 +15,7 @@ config/version="v5.0"
run/main_scene="res://scenes/main.tscn" run/main_scene="res://scenes/main.tscn"
config/features=PackedStringArray("4.3", "Mobile") config/features=PackedStringArray("4.3", "Mobile")
run/low_processor_mode=true run/low_processor_mode=true
config/icon="res://icon.png" config/icon="res://assets/icon.png"
[autoload] [autoload]

View file

@ -165,6 +165,29 @@ offset_bottom = 31.0
grow_horizontal = 0 grow_horizontal = 0
text = "Apply (F5)" 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/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/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"] [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/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/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/ApplyShaderButton" to="Editor" method="_on_apply_shader_button_pressed"]
[connection signal="pressed" from="Editor/StatusIndicator" to="Editor" method="_on_status_indicator_pressed"]

View file

@ -6,9 +6,17 @@ extends Control
@onready var save_shader_dialog = %SaveShaderDialog @onready var save_shader_dialog = %SaveShaderDialog
@onready var ui_control_filesave = %SaveImageDialog @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 image_viewport = get_tree().root.get_node("Main/%ImageViewport")
@onready var camera = get_tree().root.get_node("Main/%Camera") @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 # # GDShader keywords #
# https://github.com/godotengine/godot/blob/e96ad5af98547df71b50c4c4695ac348638113e0/servers/rendering/shader_language.cpp # 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(): func _ready():
code_editor.code_completion_enabled = true code_editor.code_completion_enabled = true
code_editor.syntax_highlighter = ShaderSyntaxHighlighter.new() code_editor.syntax_highlighter = ShaderSyntaxHighlighter.new()
self.update() self.update_code_edit()
func _input(event): func _input(event):
if event.is_action_pressed("apply_shader"): if event.is_action_pressed("apply_shader"):
@ -182,15 +190,32 @@ func _input(event):
accept_event() # Event is now handled. accept_event() # Event is now handled.
_on_save_shader_button_pressed() _on_save_shader_button_pressed()
func update(): func update_code_edit():
code_editor.text = Filesystem.shader.code 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(): func _on_new_shader_button_pressed():
Filesystem.reset() Filesystem.reset()
self.update() self.update_code_edit()
image_viewport.update() image_viewport.update()
update_status(Status.UNKNOWN)
func _on_open_shader_button_pressed(): func _on_open_shader_button_pressed():
open_shader_dialog.show() open_shader_dialog.show()
@ -215,7 +240,11 @@ func _on_fit_image_button_pressed():
func _on_apply_shader_button_pressed(): func _on_apply_shader_button_pressed():
Filesystem.shader.code = code_editor.text 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(): func _on_save_image_button_pressed():
if Filesystem.result != null: if Filesystem.result != null:
@ -226,11 +255,16 @@ func _on_save_image_button_pressed():
func _on_open_shader_dialog_file_selected(path: String): func _on_open_shader_dialog_file_selected(path: String):
Filesystem.load_shader(path) Filesystem.load_shader(path)
image_viewport.update() self.update_code_edit()
self.update() self._on_apply_shader_button_pressed()
func _on_save_shader_dialog_file_selected(path): func _on_save_shader_dialog_file_selected(path):
Filesystem.save_shader(path) Filesystem.save_shader(path)
func _on_save_image_dialog_file_selected(path): func _on_save_image_dialog_file_selected(path):
Filesystem.save_result(path) Filesystem.save_result(path)
#
func _on_status_indicator_pressed() -> void:
error_msg_dialog.show()

View file

@ -2,7 +2,9 @@ extends Node
@onready var template_shader: Shader = load("res://src/shader/template.gdshader") @onready var template_shader: Shader = load("res://src/shader/template.gdshader")
@onready var shader: Shader = template_shader.duplicate() @onready var shader: Shader = template_shader.duplicate()
var original_image: ImageTexture var original_image: ImageTexture
var additional_images: Dictionary
var result: Image var result: Image
var cwd = "." var cwd = "."
@ -24,8 +26,7 @@ func get_absolute_path(p: String) -> String:
return self.cwd + "/" + p.lstrip("./") return self.cwd + "/" + p.lstrip("./")
return p return p
func load_original_image(path: String): func load_original_image(path: String) -> String: # returns an error message
print("Load ", path)
var img = Image.new() var img = Image.new()
var err = img.load(path) var err = img.load(path)
if err == OK: if err == OK:
@ -34,12 +35,20 @@ func load_original_image(path: String):
self.last_original_image_path = path self.last_original_image_path = path
if self.last_image_savepath == "": if self.last_image_savepath == "":
self.last_image_savepath = path self.last_image_savepath = path
else: return ""
print("An error occured!") return error_string(err) + " " + path
func load_image(path: String) -> ImageTexture: func clear_additional_images():
print("Load ", path) additional_images.clear()
return ImageTexture.create_from_image(Image.load_from_file(path))
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): func save_result(path: String):
print("Export ", path) print("Export ", path)

View file

@ -4,31 +4,42 @@ extends SubViewport
@onready var image_sprite = %ImageSprite @onready var image_sprite = %ImageSprite
@onready var image_viewport_display = %ImageViewportDisplay @onready var image_viewport_display = %ImageViewportDisplay
func update(): func update() -> Array: # returns error messages (strings)
var errors = []
var fit_image = false 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) var m = ShaderDirectiveParser.parse_load_directive(Filesystem.shader)
if len(m) < 1: 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]) var original_image_path = Filesystem.get_absolute_path(m[1])
if original_image_path != Filesystem.last_original_image_path: if original_image_path != Filesystem.last_original_image_path:
fit_image = true fit_image = true
Filesystem.load_original_image(original_image_path) var err = Filesystem.load_original_image(original_image_path)
if Filesystem.original_image == null: if err != "":
errors.append(err)
image_viewport_display.hide() 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.texture = Filesystem.original_image
image_sprite.offset = Filesystem.original_image.get_size() / 2 image_sprite.offset = Filesystem.original_image.get_size() / 2
self.size = Filesystem.original_image.get_size() self.size = Filesystem.original_image.get_size()
var mat = ShaderMaterial.new() var mat = ShaderMaterial.new()
mat.shader = Filesystem.shader mat.shader = Filesystem.shader
# load images from //!load+ directives and apply them to # ... as shader parameters
# the material as shader parameters for key in Filesystem.additional_images:
for n in ShaderDirectiveParser.parse_load_additional_directive(Filesystem.shader):
mat.set_shader_parameter( mat.set_shader_parameter(
n[1], # uniform param name key, # uniform param name
Filesystem.load_image(Filesystem.get_absolute_path(n[2])) Filesystem.additional_images[key])
)
# assign material # assign material
image_sprite.material = mat image_sprite.material = mat
# Get viewport texture # Get viewport texture
@ -39,3 +50,5 @@ func update():
if fit_image: if fit_image:
camera.fit_image() camera.fit_image()
image_viewport_display.show() image_viewport_display.show()
# done
return errors

View file

@ -11,8 +11,7 @@ func _ready():
func parse_load_directive(shader: Shader) -> PackedStringArray: func parse_load_directive(shader: Shader) -> PackedStringArray:
var regex_match = self._load_regex.search(Filesystem.shader.code) var regex_match = self._load_regex.search(Filesystem.shader.code)
if regex_match == null: # Error! if regex_match == null:
printerr("Didn't find any load directives!")
return [] return []
return regex_match.strings return regex_match.strings