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:
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:
Lots of code, but I hope this helps someone. This, of course, stalled me for a while!