0

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:

  1. 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)

  1. 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.

  1. Redo

Create an Undo object to store the current state. Upload the Redo buffer to both textures. Dispose the Redo object.

  1. 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?

Dahl
  • 149
  • 1
  • 10

1 Answers1

0

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.

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Thanks. I made an edit to the question, regarding your answer. – Dahl May 07 '22 at 12:14
  • @Dahl in case your editation is just vector gfx (no pixel arts or effects) you can ignore the temp texture and instead of rendering into texture render overlay over it ... and render to texture only after edit ends (that is how I do it in my vector editors like [this](https://stackoverflow.com/a/30750626/2521214) ) Rendering to texture is usually done using FBO ... you can have 2 FBO one for each texture ... then you can use one texture as normal texture and render textured QUAD into the other texture using its FBO ... However note on old Intel gfx cards this usually does not work. – Spektre May 08 '22 at 07:26
  • Also if your image is pure vector gfx why not store it as vector ... then you woul dnot need the texture rectangles in your undo redo ... but simple commands that will add/remove/change vector entities supported by editor – Spektre May 08 '22 at 07:28
  • "you can ignore the temp texture and instead of rendering into texture render overlay over it" I think i'll try that. Thanks! I am using the editor to "draw terrain". Each color channel represent a type. Then i am using this texture as a blendmap in the shader for mixing textures. My brush only has 4 colors to choose from (+ clear). First draw to a bool[][] array. Then when i flush, use the array to query adjacent pixels. More adjacent = stronger color. Since i need to know the terrain type for a pixel on the CPU side, i also have to store the color values in an array on the CPU... – Dahl May 08 '22 at 18:43
  • If I paint over pixels with other colors, I actually add those colors. I don't just overwrite the previous value. So the process is actually: chose terrain type, brush radius, sample delta etc. and start edit -> write to bool[][] -> update the color[][] on CPU (add or clear) -> upload to texture. But I think rendering unto an overlay texture makes sense! I get rendering the overlay as textured Quad onto a fbo texture. But unsure of how to "render" onto the overlay.. use glTexSubImage2D? (Sorry about the text dump) i am not familiar with using vectors. It might be overkill for my purposes. – Dahl May 08 '22 at 18:43
  • Saving the movement of brush + brush variables as UNDO/REDO objects was my first thought. But since i am not simply overwriting color values (but adding/subtracting) it gets more complicated. But i have a low cap for undo objects anyways, it should not be an issue. A pixel is an unsigned short. – Dahl May 08 '22 at 18:57
  • Yeah, i don't think the overlay works in my case. Since i am not showing it on screen, but using it as a blendmap in a shader. I am at my openGL skill limit with this, so it's possible i don't understand you. :) If you could show some pseudo-code for the rendering process that would be great. – Dahl May 08 '22 at 23:43
  • Then use [FBO](https://stackoverflow.com/a/43930271/2521214) ... FBO bound texture behaves as screen and also as a texture so you can render to it using standard GL primitives (no need for `glTexSubImage2D` you can directly use old `glBegin/glEnd` or new VBO/VAO `glDraw...` calls or use it as source texture for different FBO or screen rendering. – Spektre May 09 '22 at 07:08