8

As part of modifying the GLPaint, I am trying to add erase functionality where user could select an eraser button and erase the painted area just as painting.

I am trying have a conditional statement within "renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end" method so that I could check whether the stroke is for painting or erasing.

For erasing I do not know how to make use of the "start" and "end" parameters for erasing. Is there any method call in OpenGL like glClear() that accepts these two parameter and does erase?

Any pointer will be very helpful. Thank you.

dinesh
  • 125
  • 2
  • 6

4 Answers4

10

Along the same vein as Erase using brush in GLPaint, you could reuse the

- (void)renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end 

method by having the condition:

if (isEraserBrushType) {
    glBlendFunc(GL_ONE, GL_ZERO);
    glColor4f(0, 0, 0, 0.0);
} else {
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    [self setBrushColorWithRed:brushColourRed green:brushColourGreen blue:brushColourBlue];
}

above the code:

// Render the vertex array
glVertexPointer(2, GL_FLOAT, 0, eraseBuffer);
glDrawArrays(GL_POINTS, 0, vertexCount);

Note, you'll need to implement isEraserBrushType, and store brushColourRed, brushColourGreen and brushColourBlue somehow.

Community
  • 1
  • 1
zlog
  • 3,316
  • 4
  • 42
  • 82
  • 1
    it erases with a rectangle brush (i think it the brush image size - 64/64), not with the current brush image. any ideas why is that? – Yogev Shelly Jun 30 '12 at 20:23
  • I'm guessing that's why this isn't an accepted answer. @zlog I'd like to know this as well. Any idea how to erase with the brush image, not the brush bounding box? – taber Jul 06 '12 at 14:31
  • 4
    just found this post: http://stackoverflow.com/questions/4074955/blending-a-texture-to-erase-alpha-values-softly-with-opengl using `glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA)` seems to do the trick. – taber Jul 06 '12 at 16:59
4

I think I can solve this problem, although not a very good.

You can create a new function copy of "renderLineFromPoint", like this;

- (void) drawErase:(CGPoint)start toPoint:(CGPoint)end
{
    static GLfloat*     eraseBuffer = NULL;
    static NSUInteger   eraseMax = 64;

    NSUInteger          vertexCount = 0,
    count,
    i;

    [EAGLContext setCurrentContext:context];
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);

    // Convert locations from Points to Pixels
    CGFloat scale = 1.0;//self.contentScaleFactor;
    start.x *= scale;
    start.y *= scale;
    end.x *= scale;
    end.y *= scale;

    // Allocate vertex array buffer
    if(eraseBuffer == NULL)
        eraseBuffer = malloc(eraseMax * 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 == eraseMax) {
            eraseMax = 2 * eraseMax;
            eraseBuffer = realloc(eraseBuffer, eraseMax * 2 * sizeof(GLfloat));
        }

        eraseBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count);
        eraseBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count);
        vertexCount += 1;
    }
    //}
    //glEnable(GL_BLEND);   //   打开混合
        //glDisable(GL_DEPTH_TEST);   //   关闭深度测试
        //glBlendFunc(GL_SRC_ALPHA,   GL_ONE);   //   基于源象素alpha通道值的半透明混合函数 

        //You need set the mixed-mode
    glBlendFunc(GL_ONE, GL_ZERO);
        //the erase brush color  is transparent.
    glColor4f(0, 0, 0, 0.0);

    // Render the vertex array
    glVertexPointer(2, GL_FLOAT, 0, eraseBuffer);
    glDrawArrays(GL_POINTS, 0, vertexCount);

    // Display the buffer
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];

        // at last restore the  mixed-mode
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}

My English is poor. Can you understand what I said? Hope these can help you.

The_Fox
  • 6,992
  • 2
  • 43
  • 69
qqcool
  • 41
  • 2
1

I attempted to use the accepted answer, however it would erase in a square pattern, whereas I wanted to erase using my own brush. Instead I used a different blending function.

if (self.isErasing) {
    glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
    [self setBrushColorWithRed:0 green:0 blue:0];
} else {
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}

The way this works is that the incoming (source) colour is multiplied by zero to completely disappear meaning that you don't actually paint anything new. Then the destination colour is set to be (1 - Source Alpha). So wherever the brush has colour the destination has no colour.

Ben Taylor
  • 41
  • 4
-2

Another idea, if suppose your view's back ground is pure black you can simply call [self setBrushColorWithRed:0.0 green:0.0 blue:0.0] and then call renderPoint:ToPint: - This will draw in black (and the user may think that he is actually erasing.

arin
  • 61
  • 8