(void)setupFBO:(NSSize)size buffer:(Ptr)buffer //used to setup FBO the first time, buffer is set to NULL is size is the final size
{
CGLContextObj cgl_ctx = [offscreenContext CGLContextObj];
if(fbo.texture)
{
glDeleteTextures(1, &fbo.texture);
}
if(fbo.fbo)
{
glDeleteFramebuffersEXT(1, &fbo.fbo);
fbo.fbo = 0;
}
if(fbo.depthBuffer)
{
glDeleteRenderbuffersEXT(1, &fbo.depthBuffer);
fbo.depthBuffer = 0;
}
// texture / color attachment
glGenTextures(1, &fbo.texture);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, fbo.texture);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,
GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_SHARED_APPLE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA8, size.width, size.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
glBindTexture(GL_TEXTURE_2D, 0);
/*
// depth buffer
glGenRenderbuffersEXT(1, &fbo.depthBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo.depthBuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width, size.height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
*/
// FBO and connect attachments
glGenFramebuffersEXT(1, &fbo.fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo.fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, fbo.texture, 0);
//glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo.depthBuffer);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
//glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, size.width ,size.height);
//glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
//glPushMatrix();
glLoadIdentity();
glOrtho(0, size.width, 0, size.height, -1.0, 1.0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
NSLog(@“OpenGL error %04X”, status);
glDeleteTextures(1, &fbo.texture);
glDeleteFramebuffersEXT(1, &fbo.fbo);
//glDeleteRenderbuffersEXT(1, &fbo.depthBuffer);
fbo.texture = 0;
fbo.fbo = 0;
fbo.depthBuffer = 0;
}
}
//This function attaches new texture with update frame and render
-(void)scaleFrame:(CVImageBufferRef)frame toSize:(NSSize)size resizedFrame:(CVImageBufferRef)resizedFrame
{
GLuint texture = [self textureFromPixels:frame ofSize:size];
int texWidth = CVPixelBufferGetWidth(frame);
int texHeight = CVPixelBufferGetHeight(frame);
CGLContextObj cgl_ctx = [offscreenContext CGLContextObj];
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo.fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_EXT, texture, 0);
glBegin(GL_QUADS);
glTexCoord2f(texWidth, texHeight); glVertex3f(1.0, 1.0, 0); // upper right
glTexCoord2f(0.0, texHeight); glVertex3f(0.0, 1.0, 0); // upper left
glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0); // lower left
glTexCoord2f(texWidth, 0.0); glVertex3f(1.0, 0.0, 0); // lower right
glEnd();
//glPixelStorei(GL_PACK_ALIGNMENT, 4);
//glPixelStorei(GL_PACK_ROW_LENGTH, size.width);
CVPixelBufferLockBaseAddress(resizedFrame, 0);
glReadPixels(0, 0, size.width, size.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, CVPixelBufferGetBaseAddress(resizedFrame));
CVPixelBufferUnlockBaseAddress(resizedFrame, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
//finally this function creates texture from pixels, the size is the final size not the original
(GLuint)textureFromPixels:(CVImageBufferRef)image ofSize:(NSSize)size
{
CGLContextObj cgl_ctx = [offscreenContext CGLContextObj];
int texWidth = size.width; //CVPixelBufferGetWidth(image);
int texHeight = size.height; //CVPixelBufferGetHeight(image);
if(fbo.texture)
{
glDeleteTextures(1, &fbo.texture);
}
//GLuint texture;
glGenTextures(1, &fbo.texture);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, fbo.texture);
//glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_REPEAT);
//glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_REPEAT);
//glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,
GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_SHARED_APPLE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
CVPixelBufferLockBaseAddress(image, 0);
glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA8, texWidth, texHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, CVPixelBufferGetBaseAddress(image));
CVPixelBufferUnlockBaseAddress(image, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
return fbo.texture;
}