I'm dealing with the undo feature of a basic iOS painting app. There's no problem with normal undoing when I only paint the strokes in one colour, but when I use different colours always render all the strokes with the last stroke color.
To accomplish this, I'm storing in the undo array my custom objects that containts the point array and the stroke colour, and at last painting it again after remove the last object and clear the screen.
Here is the code
- (void)undo {
static GLfloat* vertexBuffer = NULL;
static NSUInteger vertexMax = 64;
NSUInteger vertexCount = 0, count, i;
CGFloat oldRed = self.red;
CGFloat oldGreen = self.green;
CGFloat oldBlue = self.blue;
if (self.undoBuffer.count > 0)
{
TEUndoStroke *undoStroke = [self.undoBuffer lastObject];
if (!self.redoBuffer)
self.redoBuffer = [NSMutableArray array];
[self.redoBuffer addObject:undoStroke];
[self.undoBuffer removeLastObject];
[EAGLContext setCurrentContext:context];
glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
glClearColor(1.0, 1.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
for (TEUndoStroke *_stroke in self.undoBuffer)
{
//Aplicamos el color que tenia
NSLog(@"R: %f G: %f B: %f", _stroke.red, _stroke.green, _stroke.blue);
[self setBrushColorWithRed:_stroke.red green:_stroke.green blue:_stroke.blue];
for (int k = 1; k < _stroke.arrayStrokes.count; k++)
{
CGPoint start = [[_stroke.arrayStrokes objectAtIndex:k-1] CGPointValue];
CGPoint end = [[_stroke.arrayStrokes objectAtIndex:k] CGPointValue];
glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer);
// Convert locations from Points to Pixels
CGFloat scale = self.contentScaleFactor;
start.x *= scale;
start.y *= scale;
end.x *= scale;
end.y *= scale;
// Allocate vertex array buffer
if(vertexBuffer == NULL)
vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));
// Add points to the buffer so there are drawing points every X pixels
count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / kBrushPixelStep), 1);
for(i = 0; i < count; ++i) {
if(vertexCount == vertexMax) {
vertexMax = 2 * vertexMax;
vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));
}
vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count);
vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count);
vertexCount += 1;
}
}
}
//Render everithing at last to avoid blinking.
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Draw
glUseProgram(program[PROGRAM_POINT].id);
glDrawArrays(GL_POINTS, 0, vertexCount);
// Load data to the Vertex Buffer Object
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, vertexCount*2*sizeof(GLfloat), vertexBuffer, GL_DYNAMIC_DRAW);
// Display the buffer
glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];
}
[self setBrushColorWithRed:oldRed green:oldGreen blue:oldBlue];
}
This is the setBrushColorMethod
- (void)setBrushColorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue
{
self.red = red;
self.green = green;
self.blue = blue;
// Update the brush color
brushColor[0] = red * kBrushOpacity;
brushColor[1] = green * kBrushOpacity;
brushColor[2] = blue * kBrushOpacity;
brushColor[3] = kBrushOpacity;
if (initialized) {
glUseProgram(program[PROGRAM_POINT].id);
glUniform4fv(program[PROGRAM_POINT].uniform[UNIFORM_VERTEX_COLOR], 1, brushColor);
}
}
For example, if I draw three letters:
R in red color G in green color B in blue color
I press the undo button, letter "B" dissapears but R and G are both colored in green.