medvedNick
medvedNick

Reputation: 4510

Drawing into OpenGL ES framebuffer and getting UIImage from it on iPhone

I'm trying to do offscreen rendering of some primitives in OpenGL ES on iOS. The code is as follows:

// context and neccesary buffers
@interface RendererGL
{
   EAGLContext* myContext;
   GLuint framebuffer;
   GLuint colorRenderbuffer;
   GLuint depthRenderbuffer;
}

.m file:

- (id) init
{
    self = [super init];
    if (self)
    {
            // initializing context
        myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        [EAGLContext setCurrentContext:myContext];
        [self setupOpenGL]; // creating buffers
    }
    return self;
}

-(void) setupOpenGL
{
    int width = 256;
    int height = 256;

    // generating buffers and binding them as Apple,s tutorial says

    glGenFramebuffersOES(1, &framebuffer);
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);

    glGenRenderbuffersOES(1, &colorRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
    glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, width, height);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);

    glGenRenderbuffersOES(1, &depthRenderbuffer);
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
    glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, width, height);
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);

    GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) ;
    if(status != GL_FRAMEBUFFER_COMPLETE_OES) {
        NSLog(@"failed to make complete framebuffer object %x", status);
    }
}

- (UIImage *) renderImage
{
        int width = 256;
        int height = 256;

        [EAGLContext setCurrentContext:myContext];
        glEnable(GL_DEPTH_TEST);

// clear color - cyan       
        glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// trying to draw some primitive - red line
        float line[] = {-0.5f, -0.5f, 0.5f, 0.5f};

        glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer); //should I do this?

        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(2, GL_FLOAT, 0, line);

        glColor4f(1.0, 0.0, 0.0, 1.0);
        glLineWidth(10);

        glDrawArrays(GL_LINES, 0, 2); // draw line with two points

        [myContext presentRenderbuffer:GL_RENDERBUFFER_OES]; // and this?

// then I grab image from _frameBuffer and return it as UIImage - this part is working
        NSInteger x = 0, y = 0;
        NSInteger dataLength = width * height * 4;
        GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));

        glPixelStorei(GL_PACK_ALIGNMENT, 4);
        glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);

        CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
        CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
        CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
                                        ref, NULL, true, kCGRenderingIntentDefault);


        UIGraphicsBeginImageContext(CGSizeMake(width, height));
        CGContextRef cgcontext = UIGraphicsGetCurrentContext();
        CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
        CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, width, height), iref);
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        free(data);
        CFRelease(ref);
        CFRelease(colorspace);
        CGImageRelease(iref);

        return image;
    }

the problem is that -renderImage returning completely cyan image, without red line. What can it be? Did I missed some actions before drawing line?

Upvotes: 3

Views: 4150

Answers (1)

medvedNick
medvedNick

Reputation: 4510

the first problem is that I was creating EAGLContext for OpenGL ES 2.0, but functions which I used were for OpenGL ES 1.1. The solution is to set constant to kEAGLRenderingAPIOpenGLES1

the second - I did not set model and projection matricies (if I use 1.1)

glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);

after this all works)

Upvotes: 3

Related Questions