Okay, this is what worked for me. I have this hierarchy of nodes:
Control > ViewportContainer > Viewport > Control
The top-level Control is where I draw the composed texture, and the bottom level is where current draw_* calls are being done. Now there was a one fiddly thing. After drawing is done at the bottom layer, I capture the viewport texture into a new ImageTexture. Then I recompose all ImageTextures by drawing them all onto that same control, and recapturing it all into a saved compose ImageTexture. But this causes the screen to flicker because the viewport is flipped in Y. So, I had to do three things.
- Set V Flip to On, on the Viewport.
- Recalculate mouse coordinates for Y to account for the flipped Y in the viewport.
- Set a transformation matrix, and also adjust where the final composed texture is drawn in the top level control.
In the end, is there a way to make use of a Viewport in this way but without it displaying to the screen? I had attempted such, but got various errors, from the embedded Viewport's Control size being 0, to the texture being Nil.
Top level control:
extends Control
class_name DrawingArea
func _ready():
connect("resized", self, "resized")
Global.drawingRegion = Rect2(Vector2(0, 0), get_size() )
resized()
update()
func _draw():
draw_rect(Global.drawingRegion, Color(0.0, 0.0, 0.0), true)
draw_set_transform_matrix(Transform2D.FLIP_Y)
draw_texture(Global.composeBuffer, Vector2(0.0, -1.0 * Global.drawingRegion.size.y) )
get_child(0).get_child(0).get_child(0).update()
func resized():
Global.drawingRegion = Rect2(Vector2(0, 0), get_size() )
get_child(0).get_child(0).get_child(0).rect_size = get_size()
update()
Bottom level Control:
extends Control
class_name FrontSurface
var entered := false
var compose := false
func _ready():
connect("mouse_entered", self, "mouse_entered")
connect("mouse_exited", self, "mouse_exited")
for eachTool in Global.tools:
eachTool.connect("drawDone", self, "drawDone")
func _draw():
if(!compose):
Global.tools[Global.currentTool].draw(self)
else:
compose = false
draw_rect(Global.drawingRegion, Color(0.0, 0.0, 0.0), true)
for buf in Global.bufferList:
draw_texture(buf, Vector2(0.0, 0.0) )
yield(VisualServer, "frame_post_draw")
Global.composeBuffer.create_from_image(get_parent().get_texture().get_data() )
get_parent().get_parent().get_parent().update()
func drawDone():
var tex := Buffer.new()
yield(VisualServer, "frame_post_draw")
tex.create_from_image(get_parent().get_texture().get_data() )
Global.bufferList.append(tex)
compose = true
update()
func _input(event):
if(entered):
var eventCopy = event.duplicate(true)
if(event is InputEventMouseMotion):
var mouseCoords = get_global_transform().affine_inverse() * \
(get_viewport_transform().affine_inverse() * event.position)
mouseCoords.x = clamp(mouseCoords.x, 0.0, get_size().x)
mouseCoords.y = Global.drawingRegion.size.y - clamp(mouseCoords.y, 0.0, get_size().y)
eventCopy.position = mouseCoords
Global.tools[Global.currentTool].handleEvent(eventCopy)
update()
func mouse_entered():
entered = true
func mouse_exited():
entered = false