Project Description
I'm trying to generate a texture via GDScript to use it (as an heightmap) in a shader.
The only way I found to do this was to use a Viewport containing a Sprite, being able to update my 'texture' by overwriting Sprite._draw() and to get the result via viewport.get_texture().get_data().
I do my initialization of the Sprite in its first _draw call, here just drawing a black background. Then at every subsequent call I retrieve back the drawn sprite on the viewport, redraw it, and update it by redrawing on top of it.
Problem
I use a Timer to update the Sprite every .05s, but if I start it in _ready with a wait_time of .05 the first_pass in _draw seems to be discarded, and the black background is not rendered.
My guess would be that the second _draw call is made before the first finish, retrieving a non-initialized image.
Setting the wait_time to .2s the first time seems to solve the problem, but also seems a very bad solution.
My scene tree look like that:
!SceneTree
The script inside the Sprite:
extends Sprite
onready var timer = $RedrawTimer
# Needed to avoid Godot freeing them too soon by lack of reference
var tex = null
var old_image = null
# Just used to distinguish the first _draw call,
# because I need to initialize the texture by code and
# can't find how to do it outside of _draw.
var first_pass = true
func _ready():
# There is the problem.
# Wait .2s at the first pass or the first draw may be discarded (probably a race condition)
timer.wait_time = 0.2
timer.connect("timeout", self, '_on_timer_timeout')
timer.start()
func _on_timer_timeout():
# Set back the timer cooldown to its normal value
timer.wait_time = 0.05
update()
func _draw():
if (first_pass):
# Draw black background
draw_rect(Rect2(Vector2(0, 0), Vector2(200, 200)), Color(0.0, 0.0, 0.0))
first_pass = false
else:
# Take the previous frame image to update it
old_image = Image.new()
old_image.copy_from(get_viewport().get_texture().get_data())
old_image.flip_y() # flip it back. due to the way OpenGL works, the resulting ViewportTexture is flipped vertically.
# Draw it back
tex = ImageTexture.new()
tex.create_from_image(old_image)
draw_texture(tex, Vector2(0, 0))
# Draw some modifications
draw_circle(Vector2(50, 70), 10, Color(0.0, 0.0, 1.0, 0.02))
# Draw a white outline
draw_rect(Rect2(Vector2(1, 0), Vector2(200, 200)), Color(1.0, 1.0, 1.0), false)
I would like to know if my guess of a race condition is correct, and how to solve it.
Any advice or other method I can use to generate by script a texture usable by shaders would also be welcomed.