2024-06-04 18:31:04 +02:00
|
|
|
extends SubViewport
|
|
|
|
|
2024-12-19 18:52:47 +01:00
|
|
|
@onready var camera = %Camera
|
|
|
|
@onready var image_sprite = %ImageSprite
|
2024-12-21 15:38:07 +01:00
|
|
|
@onready var image_viewport_display = %ImageViewportDisplay
|
2024-06-04 18:31:04 +02:00
|
|
|
|
2025-01-06 22:11:53 +01:00
|
|
|
var _fragment_function_regex: RegEx = RegEx.create_from_string(r'\s*void\s+fragment\s*\(\s*\)\s*{\s*')
|
2024-12-29 19:45:57 +01:00
|
|
|
|
2025-01-06 22:11:53 +01:00
|
|
|
func validate_shader_compilation(shader: Shader) -> bool:
|
2024-12-29 19:45:57 +01:00
|
|
|
# Inject code to validate shader compilation
|
|
|
|
var shader_code = shader.code;
|
|
|
|
# -> get position of fragment shader
|
|
|
|
var fragment_function_match = _fragment_function_regex.search(shader.code)
|
|
|
|
if fragment_function_match == null:
|
|
|
|
return false
|
|
|
|
# -> inject uniform
|
|
|
|
var uniform_name = "shader_compilation_validate_" + str(randi_range(999999999, 100000000))
|
|
|
|
var uniform_code_line = "\nuniform bool " + uniform_name + ";\n"
|
|
|
|
shader_code = shader_code.insert(fragment_function_match.get_start(), uniform_code_line)
|
|
|
|
# -> inject variable access to prevent that the uniform gets optimized away
|
|
|
|
shader_code = shader_code.insert(fragment_function_match.get_end() + len(uniform_code_line), "\n" + uniform_name + ";\n")
|
|
|
|
# apply shader code
|
|
|
|
shader.code = shader_code
|
|
|
|
# test if uniform list is empty -> if it is empty, the shader compilation failed
|
|
|
|
return len(shader.get_shader_uniform_list()) > 0
|
|
|
|
|
2025-01-06 22:11:53 +01:00
|
|
|
func inject_step_uniform(shader_code: String) -> Shader:
|
|
|
|
var shader = Shader.new()
|
|
|
|
# this should run after validate_shader_compilation()
|
|
|
|
var fragment_function_match = _fragment_function_regex.search(shader_code)
|
|
|
|
shader.code = shader_code.insert(fragment_function_match.get_start(), "\nuniform int STEP;")
|
|
|
|
return shader
|
|
|
|
|
2024-12-26 22:18:18 +01:00
|
|
|
func update() -> Array: # returns error messages (strings)
|
2025-01-06 22:11:53 +01:00
|
|
|
# inject STEP uniform & get number of steps
|
|
|
|
var shader: Shader = inject_step_uniform(Filesystem.shader_code)
|
|
|
|
var step: int = ShaderDirectiveParser.parse_steps_directive(shader)
|
|
|
|
# validate shader
|
|
|
|
if not validate_shader_compilation(shader):
|
2024-12-29 19:45:57 +01:00
|
|
|
return ["Shader compilation failed!"]
|
2024-12-26 22:18:18 +01:00
|
|
|
var errors = []
|
2025-01-06 22:11:53 +01:00
|
|
|
# load texture(s) from //!load directive -> TEXTURE
|
|
|
|
var m = ShaderDirectiveParser.parse_load_directive(shader)
|
2024-12-21 18:25:11 +01:00
|
|
|
if len(m) < 1:
|
2024-12-26 22:18:18 +01:00
|
|
|
errors.append("Didn't find a load directive!")
|
|
|
|
return errors
|
2024-12-21 18:25:11 +01:00
|
|
|
var original_image_path = Filesystem.get_absolute_path(m[1])
|
2025-01-06 22:11:53 +01:00
|
|
|
var fit_image = false
|
2024-12-21 18:25:11 +01:00
|
|
|
if original_image_path != Filesystem.last_original_image_path:
|
|
|
|
fit_image = true
|
2024-12-26 22:18:18 +01:00
|
|
|
var err = Filesystem.load_original_image(original_image_path)
|
|
|
|
if err != "":
|
|
|
|
errors.append(err)
|
2024-12-25 00:07:51 +01:00
|
|
|
image_viewport_display.hide()
|
2024-12-26 22:18:18 +01:00
|
|
|
return errors
|
|
|
|
# ... from //!load+ directives
|
2025-01-06 22:11:53 +01:00
|
|
|
Filesystem.clear_additional_images()
|
|
|
|
for n in ShaderDirectiveParser.parse_load_additional_directive(shader):
|
2024-12-26 22:18:18 +01:00
|
|
|
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
|
2024-12-21 18:25:11 +01:00
|
|
|
image_sprite.texture = Filesystem.original_image
|
|
|
|
image_sprite.offset = Filesystem.original_image.get_size() / 2
|
|
|
|
self.size = Filesystem.original_image.get_size()
|
2025-01-06 22:11:53 +01:00
|
|
|
# create shader material
|
2024-12-19 18:52:47 +01:00
|
|
|
var mat = ShaderMaterial.new()
|
2025-01-06 22:11:53 +01:00
|
|
|
mat.shader = shader
|
|
|
|
# add images as shader parameters
|
2024-12-26 22:18:18 +01:00
|
|
|
for key in Filesystem.additional_images:
|
2024-12-19 18:52:47 +01:00
|
|
|
mat.set_shader_parameter(
|
2024-12-26 22:18:18 +01:00
|
|
|
key, # uniform param name
|
|
|
|
Filesystem.additional_images[key])
|
2025-01-06 22:11:53 +01:00
|
|
|
# iterate n times
|
|
|
|
for i in range(step):
|
|
|
|
# set STEP param
|
|
|
|
mat.set_shader_parameter("STEP", i)
|
|
|
|
# assign material
|
|
|
|
image_sprite.material = mat
|
|
|
|
# Get viewport texture
|
|
|
|
await RenderingServer.frame_post_draw # for good measure
|
|
|
|
Filesystem.result = get_texture().get_image()
|
|
|
|
image_sprite.material = null
|
|
|
|
image_sprite.texture = ImageTexture.create_from_image(Filesystem.result)
|
|
|
|
if fit_image:
|
|
|
|
camera.fit_image()
|
2024-12-27 23:54:38 +01:00
|
|
|
camera.update_vd_zoomlevel()
|
2024-12-21 15:38:07 +01:00
|
|
|
image_viewport_display.show()
|
2024-12-26 22:18:18 +01:00
|
|
|
# done
|
|
|
|
return errors
|