OpenGL paint program based on Apple's "glPaint" on white background - how to combine?

Attempting to write a simple iPhone paint program and I am using the Apple glPaint sample as a guide. The only problem is painting doesn't work on a white background as white + color = white. I've tried different blending functions, but couldn't press on the correct combination of settings and / or brushes to make this work. I've seen similar posts about this issue, but there are no answers. Does anyone know how this might work?

Edit:
I don't even have transparency effects at the moment, if I could draw solid lines with rounded ends I would be happy.

+2


a source to share


7 replies


I have a white background working (using the standard GLPaint code) by simply changing the transparent color in the erase method i.e.

- (void) erase
{
    [EAGLContext setCurrentContext:context];

    // Clear the buffer
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    //glClearColor(0.0, 0.0, 0.0, 0.0);
    glClearColor(1.0, 1.0, 1.0, 0.0); // Change to white
    glClear(GL_COLOR_BUFFER_BIT);

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

      



The default blend function and the brush image seem to just work.

+3


a source


Instead of adding color to the mixture, could you subtract its opposite? This is roughly how paint and light work in real life and should provide correct functionality.

Example: if the user draws in Red:255 Green:0 Blue:100 Opacity:0.5

, you have to do it with a pixel:

pixel.red -= (255-paint.red) * paint.opacity;      //Subtract 0
pixel.green -= (255-paint.green) * paint.opacity;  //Subtract 127.5
pixel.blue -= (255-paint.blue) * paint.opacity;    //Subtract 77.5

      

EDIT: As you pointed out, this is not what is expected as painting over blue with full red will turn black as they subtract each other.

A possible solution for this would be to combine the additive and subtractive approaches.



For example, if you added 0.5*paint.colour

and subtracted 0.5*paint.complementaryColour

, adding full red to blue would result in:

newPixel.red -> 0 +  127.5 -  0  = 127.5
newPixel.green -> 0 + 0 - 127.5  = 0     //Cap it off, or invent new math =D
newPixel.blue -> 255 + 0 - 127.5 = 127.5

      

As you can see, this results in a nice purple which is a combination of blue and red. You can set the additive proportion to subtractive logic to simulate how well the paint mixes.

Hope it helps! =)

+2


a source


I had the same problem. The edges of the brush were darker than they should be. It turns out that apple api pre multiplies alpha into rgb channels.

So, I objected by doing a grayscale in Photoshop with only rgb and alpha values. This should look like you want your brush to be white, which is full color pigment and black, which is not color pigmentation. I load this brush as in the apple glPaint example code. Then I copy the R channel (or G or B channels as they are all equal) to the alpha channel of the texture. After that I set the RGB values ​​to the maximum for all pixels of the brush texture.

So now your brush has an alpha channel with information about how your brush looks. and RGB are all 1.

Finally, I used the mixing function:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

      

And don't forget to set the color before painting.

glColor4f(1.0f,0.0f,0.0f,1.0f); //red color

      

Check the code below, see if it works for you:

-(GLuint) createBrushWithImage: (NSString*)brushName
{

    GLuint            brushTexture;
    CGImageRef      brushImage;
CGContextRef    brushContext;
GLubyte         *brushData,*brushData1;
size_t          width, height;

//initialize brush image
brushImage = [UIImage imageNamed:brushName].CGImage;

// Get the width and height of the image
width = CGImageGetWidth(brushImage);
height = CGImageGetHeight(brushImage);

//make the brush texture and context
if(brushImage) {
    // Allocate  memory needed for the bitmap context
    brushData = (GLubyte *) calloc(width * height *4, sizeof(GLubyte));
    // We are going to use brushData1 to make the final texture
    brushData1 = (GLubyte *) calloc(width * height *4, sizeof(GLubyte));
    // Use  the bitmatp creation function provided by the Core Graphics framework. 

    brushContext = CGBitmapContextCreate(brushData, width, height, 8, width *4 , CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast);
    // After you create the context, you can draw the  image to the context.
    CGContextDrawImage(brushContext, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), brushImage);
    // You don't need the context at this point, so you need to release it to avoid memory leaks.
    CGContextRelease(brushContext);

    for(int i=0; i< width*height;i++){
                    //set the R-G-B channel to maximum
        brushData1[i*4] = brushData1[i*4+1] =brushData1[i*4+2] =0xff;
                    //store originally loaded brush image in alpha channel
        brushData1[i*4+3] = brushData[i*4];
    }

    // Use OpenGL ES to generate a name for the texture.
    glGenTextures(1, &brushTexture);
    // Bind the texture name. 
    glBindTexture(GL_TEXTURE_2D, brushTexture);
    // Set the texture parameters to use a minifying filter and a linear filer (weighted average)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    // Specify a 2D texture image, providing the a pointer to the image data in memory
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData1);
    // Release  the image data; it no longer needed
    free(brushData1);
    free(brushData);
}

      

return brushTexture; }

+2


a source


I ran into something similar. the following mix function call solved it for me without any complicated math.

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);

      

Add this before glDraw calls and you can paint with any texture as a brush.

+1


a source


This actually works even better:

glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);

      

0


a source


GLPaint sample code is used in mode glBlendFunc(GL_SRC_ALPHA, GL_ONE)

and glBlendFunc(GL_SRC_ALPHA, GL_ONE)

function - (id)initWithCoder:(NSCoder*)coder

. Therefore, when the color is white, all other colors will not be displayed. I also want to solve it.

0


a source


glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);

      

This is the best answer. And you need to load the brush image. The picture should be alpha and backgroud while ellipse.

0


a source







All Articles