diff options
Diffstat (limited to 'tests/OffscreenContext.mm')
-rw-r--r-- | tests/OffscreenContext.mm | 186 |
1 files changed, 53 insertions, 133 deletions
diff --git a/tests/OffscreenContext.mm b/tests/OffscreenContext.mm index 9a6a5e2..eb2f777 100644 --- a/tests/OffscreenContext.mm +++ b/tests/OffscreenContext.mm @@ -1,12 +1,11 @@ #include "OffscreenContext.h" +#include "imageutils.h" +#include "fbo.h" -#import <OpenGL/OpenGL.h> -#import <OpenGL/glu.h> // for gluCheckExtension #import <AppKit/AppKit.h> // for NSOpenGL... -// Simple error reporting macros to help keep the sample code clean -#define REPORT_ERROR_AND_EXIT(desc) { std::cout << desc << "\n"; return false; } -#define NULL_ERROR_EXIT(test, desc) { if (!test) REPORT_ERROR_AND_EXIT(desc); } + +#define REPORTGLERROR(task) { GLenum tGLErr = glGetError(); if (tGLErr != GL_NO_ERROR) { std::cout << "OpenGL error " << tGLErr << " while " << task << "\n"; } } struct OffscreenContext { @@ -14,7 +13,7 @@ struct OffscreenContext NSAutoreleasePool *pool; int width; int height; - GLuint fbo; + fbo_t *fbo; }; @@ -26,78 +25,58 @@ OffscreenContext *create_offscreen_context(int w, int h) ctx->pool = [NSAutoreleasePool new]; - /* - * Create an OpenGL context just so that OpenGL calls will work. I'm not - using it for actual rendering. - */ + // Create an OpenGL context just so that OpenGL calls will work. + // Will not be used for actual rendering. - NSOpenGLPixelFormatAttribute attributes[] = { + NSOpenGLPixelFormatAttribute attributes[] = { NSOpenGLPFAPixelBuffer, NSOpenGLPFANoRecovery, NSOpenGLPFAAccelerated, NSOpenGLPFADepthSize, 24, (NSOpenGLPixelFormatAttribute) 0 }; - NSOpenGLPixelFormat* pixFormat = [[[NSOpenGLPixelFormat - alloc] initWithAttributes:attributes] autorelease]; - // Create the OpenGL context to render with (with color and depth buffers) - ctx->openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixFormat - shareContext:nil]; - NULL_ERROR_EXIT(ctx->openGLContext, "Unable to create NSOpenGLContext"); + NSOpenGLPixelFormat *pixFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease]; + + // Create and make current the OpenGL context to render with (with color and depth buffers) + ctx->openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixFormat shareContext:nil]; + if (!ctx->openGLContext) { + std::cerr << "Unable to create NSOpenGLContext\n"; + return NULL; + } [ctx->openGLContext makeCurrentContext]; + + glewInit(); +#ifdef DEBUG + cout << "GLEW version " << glewGetString(GLEW_VERSION) << "\n"; + cout << (const char *)glGetString(GL_RENDERER) << "(" << (const char *)glGetString(GL_VENDOR) << ")\n" + << "OpenGL version " << (const char *)glGetString(GL_VERSION) << "\n"; + cout << "Extensions: " << (const char *)glGetString(GL_EXTENSIONS) << "\n"; + + + if (GLEW_ARB_framebuffer_object) { + cout << "ARB_FBO supported\n"; + } + if (GLEW_EXT_framebuffer_object) { + cout << "EXT_FBO supported\n"; + } + if (GLEW_EXT_packed_depth_stencil) { + cout << "EXT_packed_depth_stencil\n"; + } +#endif - /* - * Test if framebuffer objects are supported - */ - const GLubyte* strExt = glGetString(GL_EXTENSIONS); - GLboolean fboSupported = gluCheckExtension((const GLubyte*)"GL_EXT_framebuffer_object", strExt); - if (!fboSupported) - REPORT_ERROR_AND_EXIT("Your system does not support framebuffer extension - unable to render scene"); - /* - * Create an FBO - */ - GLuint renderBuffer = 0; - GLuint depthBuffer = 0; - // Depth buffer to use for depth testing - optional if you're not using depth testing - glGenRenderbuffersEXT(1, &depthBuffer); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, w, h); - REPORTGLERROR("creating depth render buffer"); - - // Render buffer to use for imaging - glGenRenderbuffersEXT(1, &renderBuffer); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderBuffer); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h); - REPORTGLERROR("creating color render buffer"); - ctx->fbo = 0; - glGenFramebuffersEXT(1, &ctx->fbo); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->fbo); - REPORTGLERROR("binding framebuffer"); - - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_RENDERBUFFER_EXT, renderBuffer); - REPORTGLERROR("specifying color render buffer"); - - if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != - GL_FRAMEBUFFER_COMPLETE_EXT) - REPORT_ERROR_AND_EXIT("Problem with OpenGL framebuffer after specifying color render buffer."); - - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, depthBuffer); - REPORTGLERROR("specifying depth render buffer"); - - if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != - GL_FRAMEBUFFER_COMPLETE_EXT) - REPORT_ERROR_AND_EXIT("Problem with OpenGL framebuffer after specifying depth render buffer."); + ctx->fbo = fbo_new(); + if (!fbo_init(ctx->fbo, w, h)) { + return NULL; + } return ctx; } bool teardown_offscreen_context(OffscreenContext *ctx) { - // "un"bind my FBO - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + fbo_unbind(ctx->fbo); + fbo_delete(ctx->fbo); /* * Cleanup @@ -109,99 +88,40 @@ bool teardown_offscreen_context(OffscreenContext *ctx) return true; } +/*! + Capture framebuffer from OpenGL and write it to the given filename as PNG. +*/ bool save_framebuffer(OffscreenContext *ctx, const char *filename) { - /* - * Extract the resulting rendering as an image - */ - + // Read pixels from OpenGL int samplesPerPixel = 4; // R, G, B and A int rowBytes = samplesPerPixel * ctx->width; - char* bufferData = (char*)malloc(rowBytes * ctx->height); + unsigned char *bufferData = (unsigned char *)malloc(rowBytes * ctx->height); if (!bufferData) { std::cerr << "Unable to allocate buffer for image extraction."; return 1; } - glReadPixels(0, 0, ctx->width, ctx->height, GL_BGRA, GL_UNSIGNED_BYTE, + glReadPixels(0, 0, ctx->width, ctx->height, GL_RGBA, GL_UNSIGNED_BYTE, bufferData); REPORTGLERROR("reading pixels from framebuffer"); // Flip it vertically - images read from OpenGL buffers are upside-down - char* flippedBuffer = (char*)malloc(rowBytes * ctx->height); + unsigned char *flippedBuffer = (unsigned char *)malloc(rowBytes * ctx->height); if (!flippedBuffer) { std::cout << "Unable to allocate flipped buffer for corrected image."; return 1; } - for (int i = 0 ; i < ctx->height ; i++) { - bcopy(bufferData + i * rowBytes, flippedBuffer + (ctx->height - i - 1) * - rowBytes, rowBytes); - } - - /* - * Output the image to a file - */ - CGColorSpaceRef colorSpace = - CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - CGBitmapInfo bitmapInfo = kCGImageAlphaNoneSkipFirst | - kCGBitmapByteOrder32Little; // XRGB Little Endian - int bitsPerComponent = 8; - CGContextRef contextRef = CGBitmapContextCreate(flippedBuffer, - ctx->width, ctx->height, bitsPerComponent, rowBytes, - colorSpace, bitmapInfo); - if (!contextRef) { - std::cerr << "Unable to create CGContextRef."; - return false; - } + flip_image(bufferData, flippedBuffer, samplesPerPixel, ctx->width, ctx->height); - CGImageRef imageRef = CGBitmapContextCreateImage(contextRef); - if (!imageRef) { - std::cerr << "Unable to create CGImageRef."; - return false; - } - Boolean isDirectory = false; - CFStringRef fname = CFStringCreateWithCString(kCFAllocatorDefault, filename, kCFStringEncodingUTF8); - CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, - fname, kCFURLPOSIXPathStyle, isDirectory); - if (!fileURL) { - std::cerr << "Unable to create file URL ref."; - return false; - } - CGDataConsumerRef dataconsumer = CGDataConsumerCreateWithURL(fileURL); - - CFIndex fileImageIndex = 1; - CFMutableDictionaryRef fileDict = NULL; - CFStringRef fileUTType = kUTTypePNG; - // Create an image destination opaque reference for authoring an image file - CGImageDestinationRef imageDest = CGImageDestinationCreateWithDataConsumer(dataconsumer, - fileUTType, - fileImageIndex, - fileDict); - if (!imageDest) { - std::cerr << "Unable to create CGImageDestinationRef."; - return false; - } - CFIndex capacity = 1; - CFMutableDictionaryRef imageProps = - CFDictionaryCreateMutable(kCFAllocatorDefault, - capacity, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CGImageDestinationAddImage(imageDest, imageRef, imageProps); - CGImageDestinationFinalize(imageDest); + bool writeok = write_png(filename, flippedBuffer, ctx->width, ctx->height); free(flippedBuffer); free(bufferData); - CFRelease(imageDest); - CFRelease(dataconsumer); - CFRelease(fileURL); - CFRelease(fname); - CFRelease(imageProps); - CGColorSpaceRelease(colorSpace); - CGImageRelease(imageRef); - return true; + + return writeok; } void bind_offscreen_context(OffscreenContext *ctx) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->fbo); + fbo_bind(ctx->fbo); } |