How to draw (as in GLPaint) on the background image and with temporary drawings?

I am writing a GLPaint-esque paint application for iPad, however I hit a stumbling block. In particular, I am trying to implement two things at the moment:

1) Background image that can be drawn.

2) The ability to draw temporary figures, for example. you could draw a line, but the final shape would only be fixed after the finger lifted.

For a background image, I understand that the idea is to draw an image in VBO and draw it right before each drawing. This is great, but now I need to add the ability to draw temporary shapes ... with kEAGLDrawablePropertyRetainedBacking set to YES (like in GLPaint), temporary ones are obviously not temporary! Turning a saved support property into NO works fine for temporary objects, but now my previous freehand lines are not saved.

What is the best approach here? Should I search for more than one EAGLLayer? All the documentation and tutorials I found show that most things should be possible with a single layer. They also say that maintained support should always be set to NO. Is there any way to work with my application in this configuration? I tried to save every point of the drawing in an ever-expanding array of vertices that will be redrawn by each frame, but due to the large number of processed sprites this does not work.

I would really appreciate any help with this, as I missed online and found nothing!

+4
source share
1 answer

Since then I have found a solution to this problem. It is best to use custom framebuffer objects and render for texture. I have not heard about this before asking a question, but it looks like an incredibly useful tool for OpenGLer tools!

For those who might want to do something similar, the idea is that you create an FBO and attach a texture to it (instead of rendering). Then you can link this FBO and draw it, like any other, with the only difference that the drawings are displayed behind the scenes. Then all you have to do to display the texture is bind the main FBO and draw the texture (using the square).

So, for my implementation, I used two different FBOs with a texture attached to each - one for the "saved" image (for hand-drawing), and the other for the "scratching" image (for temporary drawings). Each time a frame is rendered, I first draw a background texture (in my case, I just used the Texture2D class), then draw a saved texture and finally a scratch texture, if necessary. When drawing a temporary shape, everything is processed with a texture of zero, and this is cleared at the beginning of each frame. After its completion, a scratch texture is applied to the saved texture.

Here are some snippets of code that might be helpful to someone:

1) Create framebuffers (I just showed a couple here to save space!):

// ---------- DEFAULT FRAMEBUFFER ---------- // // Create framebuffer. glGenFramebuffersOES(1, &viewFramebuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); // Create renderbuffer. glGenRenderbuffersOES(1, &viewRenderbuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); // Get renderbuffer storage and attach to framebuffer. [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer]; glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); // Check for completeness. status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); if (status != GL_FRAMEBUFFER_COMPLETE_OES) { NSLog(@"Failed to make complete framebuffer object %x", status); return NO; } // Unbind framebuffer. glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); // ---------- RETAINED FRAMEBUFFER ---------- // // Create framebuffer. glGenFramebuffersOES(1, &retainedFramebuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, retainedFramebuffer); // Create the texture. glColor4f(0.0f, 0.0f, 0.0f, 0.0f); glGenTextures(1, &retainedTexture); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, retainedTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); // Attach the texture as a renderbuffer. glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, retainedTexture, 0); // Check for completeness. status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); if (status != GL_FRAMEBUFFER_COMPLETE_OES) { NSLog(@"Failed to make complete framebuffer object %x", status); return NO; } // Unbind framebuffer. glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); 

2) Draw an FBO to render:

 // Ensure that we are drawing to the current context. [EAGLContext setCurrentContext:context]; glBindFramebufferOES(GL_FRAMEBUFFER_OES, retainedFramebuffer); glViewport(0, 0, 1024, 1024); // DRAWING CODE HERE 

3) Render different textures to the main FBO and imagine:

 glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); glViewport(0, 0, backingWidth, backingHeight); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Clear to white. glClear(GL_COLOR_BUFFER_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); [self drawBackgroundTexture]; [self drawRetainedTexture]; [self drawScratchTexture]; glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES]; 

For example, drawing a drawing with a saved texture using [self drawRetainedTexture] will use the following code:

 // Bind the texture. glBindTexture(GL_TEXTURE_2D, retainedTexture); // Destination coords. GLfloat retainedVertices[] = { 0.0, backingHeight, 0.0, backingWidth, backingHeight, 0.0, 0.0, 0.0, 0.0, backingWidth, 0.0, 0.0 }; // Source coords. GLfloat retainedTexCoords[] = { 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0 }; // Draw the texture. glVertexPointer(3, GL_FLOAT, 0, retainedVertices); glTexCoordPointer(2, GL_FLOAT, 0, retainedTexCoords); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Unbind the texture. glBindTexture(GL_TEXTURE_2D, 0); 

Lots of code, but I hope this helps someone. This, of course, stalled me for a while!

+11
source

All Articles