'Painting to a texture with undo/redo functionality
I am currently painting to a texture using:
glTexSubImage2D();
You can choose brush radius, color, shape etc.
Then use any of the functions:
public void drawPoint(int px, int py);
public void drawPoints(IntQueue points);
public void drawLine(int x1, int y1, int x2, int y2);
followed by:
private void flush();
This will create an Object with two buffers for pixel data. One with data of the texture before the "brush stroke" and one containing the changes. Only the affected region is saved. (a sub rectangle of the texture)
flush() also uploads the changes to the texture using glTexSubImage2D()
I also have a working undo/redo functionality.
So that's all fine and dandy. The problem is that when drawing, you'd want to see the changes apply WHILE you are drawing. The way this is set up (using the mouse to draw) is that you only see what you have drawn after you release the mouse button. If I draw and "flush" every frame, you end up with an UNDO/REDO instance of every "point".
How does a simple "paint program" do this? Or how could one do this in a smarter way?
I am using the texture as a blend map for terrain. (Red channel = Grass etc.)
Edit:
(Trying to understand @Spektre 's answer)
What did you mean with rendering to texture? i'm currently using glTexSubImage2D, glCopyImageSubData. Do you mean rendering quads to a fbo bound texture? one Quad per pixel. Cause i'm not sure about other ways of doing this.
If i understand you correctly:
- Editing
Let's say I draw a line. So I start a new edit. I have two textures. The two textures contain the same data atp. The line starts at the mouse position at edit start. Every frame (or when the mouse moves) I figure out all the pixels needed to create a line from the start point to the current mouse position. Then upload those pixels to the "front texture" using glTexSubImage2D. Then render using that texture. After the render I clear the area of pixels left by the line: copying contents of the unedited "back texture" to the "front texture". Then repeat this process until the mouse is released (edit end). When the edit ends, i save the stroke area of the unedited texture as an UNDO object. Then update both textures with the edit (line area). (Also, any currently stored Redo objects are disposed)
- Undo
(The Undo object stores the "before" pixel data and the area of the stroke) On undo, you create a Redo object to store the current "snapshot" (equal in area to the Undo). Then you upload the pixels of the Undo object into both textures. Dispose the Undo object.
- Redo
Create an Undo object to store the current state. Upload the Redo buffer to both textures. Dispose the Redo object.
- Questions
How would you copy an area of one texture unto another? glCopyImageSubData?
Should i use framebuffer objects for this, or is it "ok" to just "use textures directly" as i am doing? Curious about how paint programs does this. There are so many of them, there has to be some common way of doing this kind of editing. Am i on the right track?
Solution 1:[1]
there are more approaches to have Undo/redo. You did go for the easier but more memory heavy one. In this case you have to render actually edited part on top of your texture. As this is probably not directly a screen buffer and you most likely do some other processing on top of it you can simplify things with having 2 textures.
So when you start editing something you copy the original contents to the temp texture (use it as a clear state of backbufer).
While editing you render into your texture directly (or copy from temp texture and re-render).
On editing end you simply store the changed area from the temp texture.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Spektre |