Question

I'm working on a game for the iPhone that has a drawing/paint mechanic involved and I'm having problems trying to create a tool that would erase things already painted.

The main problem is that the background being painted on is not a solid color but a static image or animation. I've tried using different blending options and logical operations in drawing but nothing seemed to work. I'm new to OpenGL so I must be missing something.

Any tips?

EDIT: To give a little more information, I'm using textures for my brushes and using glVertexPointer() and glDrawArrays() to render them. For example:

glBindTexture(GL_TEXTURE_2D, circleBrush);
glVertexPointer(3, GL_FLOAT, 0, verts);
glTexCoordPointer(2, GL_FLOAT, 0, coords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

EDIT 2: Unfortunately, stencil buffers are not available on the iPhone. : (

EDIT 3: Framebuffer objects are available on the iPhone and that is the road I took. I haven't fully implemented it yet, but so far it looks like it works the way I wanted it to. Thanks everyone!

Was it helpful?

Solution

Draw a full-screen textured quad over your scene. When the user draws a brush stroke, use glTexSubImage2D to update the your texture.

glReadPixels/glDrawPixels is slow.

Using FrameBufferObjects is even better, but I doubt this extention is available on the iPhone (then again, I don't know for sure, so maybe try it). FBO's allow you to draw directly into a texture as if it were another rendering context.

OTHER TIPS

Stencil Buffer is the best way to approach this for sure...You'll save time, cpu, and potential problems..,They are available on Iphone, you just have to created an OpenGlES 2.0 surface (not gles 1.0 or 1.1).

        //Turn off writing to the Color Buffer and Depth Buffer
        //We want to draw to the Stencil Buffer only
        glColorMask(false, false, false, false);
        glDepthMask(false);

        //Enable the Stencil Buffer
        glEnable(GL_STENCIL_TEST);

        //Set 1 into the stencil buffer
        glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
        glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

        //CALL YOUR DRAWING METHOD HERE


        //Turn on Color Buffer and Depth Buffer
        glColorMask(true, true, true, true);
        glDepthMask(true);

        //Only write to the Stencil Buffer where 1 is set
        glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
        //Keep the content of the Stencil Buffer
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

        //CALL OUR DRAWING METHOD AGAIN

Lookup this example : http://www.opengl.org/resources/code/samples/glut_examples/examples/stenciltst.c

Here's the visual result : http://www.opengl.org/resources/code/samples/glut_examples/examples/stenciltst.jpg

I've implented the same kind of eraser tool with this, on both android and iPhone and it works like a charm !

Good luck !

Cheers !

You don't give much info, but I assume that your storing whatever they "paint" into a buffer and then drawing it on screen like this:

 glWindowPos2i(X, Y);
 glDrawPixels(drawing->Width, drawing->Height, drawing->Format, 
              GL_UNSIGNED_BYTE, drawing->ImageData);

With drawing->ImageData being the buffer. What you could do is have a separate background buffer and draw it first. Then the erase tool will simply white-out the the drawing buffer(turning all the values, including alpha, all the way up).

For this solution to work you'd have to turn on blending and turn off depth testing.

 glEnable(GL_BLEND);
 glDisable(GL_DEPTH_TEST);
 glWindowPos2i(X, Y);
 //background never changes
 glDrawPixels(background->Width, background->Height, background->Format, 
              GL_UNSIGNED_BYTE, background->ImageData);
 glWindowPos2i(X, Y);
 glDrawPixels(drawing->Width, drawing->Height, drawing->Format, 
              GL_UNSIGNED_BYTE, drawing->ImageData);
 glEnable(GL_DEPTH_TEST);
 glDisable(GL_BLEND);

Is that what you're looking for?

You could use the stencil buffer for this operation. The stencil buffer is a special buffer which holds information for every pixel, similiar to the depth buffer. Unlike the depth buffer, you decide how the stencil buffer is altered while drawing and how it influences the decision to draw into the color buffer or not. To do so, you can set the specific states before any drawing operation. Here is what you do:

  • At the time the users erases, draw the "erased" region into the stencil buffer (using StencilOp, see below). You can use any GL drawing function for that.

  • In every rendering pass, first draw the background (if you want, you can use a negative stencil test here to only draw the "erased" part of the background - may increase performance).

  • Then, enable the stencil test for all other drawing operations. OpenGL will then only draw to the "non-erased" regions.

The function to set how the stencil buffer should influence drawing (or not): glStencilFunc()

The function to set how the stencil buffer itself is influenced by drawing: glStencilOp()

Further explanation, also with the arguments for these: http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node117.html

Using glBlendFunc(GL_ONE, GL_ZERO) mode can earse.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top