1

I have the same requirement as this question

I am right now at situation where i set UIImage on my opengl view. Below is the complete code i used to set uiimage. Also it includes the drawing code. Using below code I am able to set image and drawing on it.

when i do not set image in background it allows me to draw blur and smooth drawing

but if i set background image it draws solid drawing

I want smooth drawing on background image.

I have used some of GLPaint code of apple for drawing.

 - (id)initWithCoder:(NSCoder*)coder
{
    CGImageRef      brushImage;
    CGContextRef    brushContext;
    GLubyte         *brushData;
    size_t          width, height;

    if ((self = [super initWithCoder:coder]))
    {
        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
        eaglLayer.opaque = NO;
        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                        [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
                                        kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
                                        nil];

        _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
        if (!_context || ![EAGLContext setCurrentContext:_context])
        {
            return nil;
        }

        {
            brushImage = [UIImage imageNamed:@"Brush.png"].CGImage;

            width = CGImageGetWidth(brushImage);
            height = CGImageGetHeight(brushImage);

            if(brushImage) {
                brushData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
                brushContext = CGBitmapContextCreate(brushData, width, width, 8, width * 4, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast);
                CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
                CGContextDrawImage(brushContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), brushImage);
                CGContextRelease(brushContext);
                glGenTextures(1, &brushTexture);
                glBindTexture(GL_TEXTURE_2D, brushTexture);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData);
                free(brushData);
            }
        }

        // Setup OpenGL states
        glMatrixMode(GL_PROJECTION);
        CGRect frame = self.bounds;
        glOrthof(0, frame.size.width, 0, frame.size.height, -1, 1);
        glViewport(0, 0, frame.size.width , frame.size.height);
        glMatrixMode(GL_MODELVIEW);

        glDisable(GL_DITHER);
        glEnable(GL_TEXTURE_2D);
        glEnableClientState(GL_VERTEX_ARRAY);

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

        glEnable(GL_POINT_SPRITE_OES);
        glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
        glPointSize(10);

    }
    return self;
}



  - (void)layoutSubviews
    {
        [EAGLContext setCurrentContext:_context];
        [self destroyFramebuffer];
        [self createFramebuffer];

        if (texture)    {
            [self _updateContent];
            glDeleteTextures(1, &texture);
            texture = 0;
        }
    }


    - (void)_updateContent {
        NSUInteger width = self.frame.size.width;
        NSUInteger height = self.frame.size.height;

        CGFloat texWidth = (1.0 * width)/TEX_SIZE;
        CGFloat texHeight = (1.0 * height)/TEX_SIZE;

        GLfloat verts[12] = {
            0, height,
            width, height,
            width, 0,
            0, height,
            0, 0,
            width, 0
        };

        GLfloat txcoord[12] = {
            0, texHeight,
            texWidth, texHeight,
            texWidth, 0,
            0, texHeight,
            0, 0,
            texWidth, 0
        };

        [EAGLContext setCurrentContext:_context];
        glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer);
        glVertexPointer(2, GL_FLOAT, 0, verts);
        glTexCoordPointer(2, GL_FLOAT, 0, txcoord);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        glDisableClientState(GL_TEXTURE_COORD_ARRAY);

        glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer);
        [_context presentRenderbuffer:GL_RENDERBUFFER_OES];

        glDisable(GL_TEXTURE_2D);
        glDisable(GL_BLEND);

    }


   - (void)setContent:(UIImage*)image
{

    if (image) {
        //        self.isNotEmpty = YES;
        CGImageRef contentImage = image.CGImage;

        [EAGLContext setCurrentContext:_context];

        CGFloat w = CGImageGetWidth(contentImage);
        CGFloat h = CGImageGetHeight(contentImage);

        GLubyte *data = (GLubyte *)calloc(TEX_SIZE * TEX_SIZE * 4, sizeof(GLubyte));

        CGContextRef ctx = CGBitmapContextCreate(data, TEX_SIZE, TEX_SIZE, 8, TEX_SIZE * 4, CGImageGetColorSpace(contentImage), kCGImageAlphaPremultipliedLast);
        CGContextScaleCTM(ctx, 1, -1);
        CGContextTranslateCTM(ctx, 0, -TEX_SIZE);
        CGContextDrawImage(ctx, CGRectMake(0, 0, w, h), contentImage);
        CGContextRelease(ctx);

        if (!texture) {
            glGenTextures(1, &texture);
        }
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        free(data);
    } 
    [self setNeedsLayout];        
    glDisable(GL_VERTEX_ARRAY);
}

//Called on touchedMoved

- (void) renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end
{
    glEnable(GL_BLEND);
    if(1){
        sharedDelegate = [AppDelegate appDelegate];

        static GLfloat*     vertexBuffer = NULL;
        static NSUInteger   vertexMax = 64;
        NSUInteger          vertexCount = 0,
        count,
        i;
        GLenum err;

        glColor4f(1.0, 0.0, 1.0, 1.0);

        // 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;
        }

        if(sharedDelegate.boolIsEraser)
        {
            glColor4f(1.0, 1.0, 1.0, 0.5);
            glBlendFunc( GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
        }
        // Render the vertex array
        glVertexPointer(2, GL_FLOAT, 0, vertexBuffer);
        glDrawArrays(GL_POINTS, 0, vertexCount);

        if(sharedDelegate.boolIsEraser){
            // at last restore the  mixed-mode
            glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
        }

        glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer);
        [_context presentRenderbuffer:GL_RENDERBUFFER_OES];

        err = glGetError();
        if (err != GL_NO_ERROR)
            NSLog(@"Error in frame. glError: 0x%04X", err);

    }
}

Any workaround to accomplish this? I am almost there to my goal but badly stuck here.Any help will be appreciated.

Community
  • 1
  • 1
Heena
  • 2,348
  • 3
  • 32
  • 58

4 Answers4

1

You might try setting the shadow color to the same as the stroke color, and the stroke blur radius to however many points out from the edge of the stroke you want the blur to extend. You'll probably want to set the shadow offset to CGSizeZero.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
  • CGContextSetShadowWithColor(ctx, CGSizeZero, 15, outerColor); i have tried this and I am almost there but it shows shadow at the starting of my Cap(CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);) and not at the sides of it. Is the any way to give shadow to sides(left,right) ? – Heena Feb 28 '13 at 10:58
1

You can try openGL code from This Link

or try this

CGSize offset;
float blur;//set this variable as per your requirement
offset.width = 10;
offset.height = -10;

CGContextSetShadow(context, offset, blur);
Nirav Gadhiya
  • 6,342
  • 2
  • 37
  • 76
1

I got the solution...

The thing remaining was I need to set my opengl states after i draw UIImage in opengl view. The same thing i did when i initialized brush texture...

I just added below code in LayoutSubviews method after _updateContent method

        // Setup OpenGL states
        glMatrixMode(GL_PROJECTION);
        CGRect frame = self.bounds;
        glOrthof(0, frame.size.width, 0, frame.size.height, -1, 1);
        glViewport(0, 0, frame.size.width , frame.size.height);
        glMatrixMode(GL_MODELVIEW);

        glDisable(GL_DITHER);
        glEnable(GL_TEXTURE_2D);
        glEnableClientState(GL_VERTEX_ARRAY);

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

        glEnable(GL_POINT_SPRITE_OES);
        glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE)

and now this code is working perfectly..

Heena
  • 2,348
  • 3
  • 32
  • 58
0

You can use CGContextSetBlendMode(context, kCGBlendModeClear) ike real eraser effect

Undertaker
  • 39
  • 1
  • 7
  • I have mentioned in my code that I am using CGContextSetBlendMode code but this is not giving my blur effect – Heena Mar 04 '13 at 04:33
  • Can you send snapshot of required drawing effect or part of code that not gives you particular effect . – Undertaker Mar 04 '13 at 06:25