I'm trying to create a simple drawing program where I allocate an off screen image and then draw a trail of small circles on it as the user clicks and drags a mouse across it. I'm having trouble finding a good way to do this in Godot.

Viewports looked promising, but they are cleared and redrawn each frame and only draw the child nodes placed on top of them. I need an image buffer that retains state each frame and only changes when I explicitly draw to it in response to a UI event.

The other method I can see would be to create an ImageTexture and then grab the Image from get_data() and update it one pixel at a time using Image.set_pixel(). This strikes me like it would b every slow and it doesn't allow me to use advanced features like shaders.

I checked out the GDPaint demo, but it doesn't use an offscreen buffer. It just creates a queue of drawing events and redraws everything each frame. This solution won't work for me as I need to store everything in a texture. (It will also take longer and longer to render as the user continues to draw).

Is there a good way to do this?

The fastest thing would be to create a viewport and draw with a shader. This is a little harder to setup, but will run extremely fast. Viewports are cleared by default, but you can control this behavior. However, it would be much easier to use an ImageTexture and just draw pixels. Usually what you want to do (since drawing more than a few pixels each frame can be slow) is to draw directly onto a CanvasItem node, using the draw function. This will be fast enough for single strokes. Then when you release the mouse (or pickup your finger from mobile) you then blit the image from the CanvasItem onto the TextureImage.

I think figuring out how to use a Viewport would work best for what I'm trying to do. I'm thinking I could set the Viewport's Clear Mode to Never and then add a custom component that draws just the operations I want for the next frame. Would that work?

@cybereality Just reread your post - how do you blit onto an ImageTexture? I can't find a method for that.

On the Image class the function blit_rect(). The only problem it is only woks on pixel values so I don't think anti-aliasing works.

a year later