Skip to content

Instantly share code, notes, and snippets.

@nevyn
Created April 26, 2009 08:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nevyn/101958 to your computer and use it in GitHub Desktop.
Save nevyn/101958 to your computer and use it in GitHub Desktop.
//
// NSImageGLTextureAdditions.h
// SkryllePhoto
//
// Created by Joachim Bengtsson on 2007-05-14.
// Copyright 2007 Joachim Bengtsson. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <OpenGL/gl.h>
@interface GLTexture : NSObject {
GLuint texID;
NSBitmapImageRep *cache;
NSSize size;
}
/// Just takes ownership. NOTE: does not store size!
-(GLTexture*)initWithTexID:(GLuint)tid;
/// Creates a texture from src
-(GLTexture*)initWithNSImage:(NSImage*)src;
/// Does the expensive part of -[GLTexture useImage]. Can be called from any thread.
-(void)prepareCacheForImage:(NSImage*)src;
/// Converts src to an OpenGL texture.
/// @arg src may be nil if -[GLTexture prepareCacheForImage] has been called.
/// @note Calling this method invalidates the cache generated by -[GLTexture prepareCacheForImage]
/// @note Must be called from the same thread that the OpenGL context was created in.
-(GLTexture*)useImage:(NSImage*)src;
-(void)deleteTexture;
-(NSSize)size;
-(void)apply;
-(void)unapply;
// Private
-(void)makeOpenGLTextureOfInternalCache;
@end
@interface NSImage(NSImageGLTextureAdditions)
-(GLTexture*)glTexture;
-(NSSize)pixelSize;
+(NSImage*)imageWithContentsOfPath:(NSString*)path;
@end
//
// NSImageGLTextureAdditions.m
// SkryllePhoto
//
// Created by Joachim Bengtsson on 2007-05-14.
// Copyright 2007 Joachim Bengtsson. All rights reserved.
//
#import "GLTexture.h"
#import <OpenGL/glu.h>
#import "NCCommon.h"
@implementation GLTexture
-(GLTexture*)initWithTexID:(GLuint)tid;
{
if(![super init]) return nil;
cache = nil;
texID = tid;
return self;
}
-(GLTexture*)initWithNSImage:(NSImage*)src;
{
if(![super init]) return nil;
cache = nil;
[self useImage:src];
return self;
}
-(void)prepareCacheForImage:(NSImage*)src;
{
[cache release];
size = [src size];
size.width = floorf( size.width );
size.height = floorf( size.height );
cache = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes: NULL
pixelsWide: size.width
pixelsHigh: size.height
bitsPerSample: 8
samplesPerPixel: 4
hasAlpha: YES
isPlanar: NO
colorSpaceName: NSDeviceRGBColorSpace
bitmapFormat: 0
bytesPerRow: 0
bitsPerPixel: 32];
bzero( [cache bitmapData], size.height * [cache bytesPerRow] );
NSGraphicsContext *ctx = [NSGraphicsContext graphicsContextWithBitmapImageRep: cache];
NSGraphicsContext *old = [[NSGraphicsContext currentContext] retain];
[NSGraphicsContext setCurrentContext: ctx];
NSRect rect = { NSZeroPoint, size };
[src drawInRect: rect fromRect: rect operation: NSCompositeSourceOver fraction: 1.0]; // 500 ms for 3mpx
[NSGraphicsContext setCurrentContext: old]; [old release];
}
-(GLTexture*)useImage:(NSImage*)src;
{
if(!cache)
[self prepareCacheForImage:src];
[self makeOpenGLTextureOfInternalCache];
[cache release]; cache = nil;
return self;
}
-(void)deleteTexture;
{
if(texID)
glDeleteTextures(1,&texID);
texID = 0; // ensure it is zeroed for failure cases
}
-(void)dealloc;
{
[self deleteTexture];
[super dealloc];
}
-(NSSize)size;
{
return size;
}
-(void)apply;
{
glEnable(GL_TEXTURE_RECTANGLE_EXT);
glBindTexture (GL_TEXTURE_RECTANGLE_EXT, texID);
}
-(void)unapply;
{
glDisable(GL_TEXTURE_RECTANGLE_EXT);
}
-(void)makeOpenGLTextureOfInternalCache;
{
if(texID == 0)
glGenTextures(1, &texID);
glBindTexture( GL_TEXTURE_RECTANGLE_EXT, texID);
glReportError();
glTexParameteri( GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri( GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexParameteri( GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glReportError();
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glPixelStorei( GL_UNPACK_ROW_LENGTH, [cache bytesPerRow] / 4 );
glReportError();
glTexImage2D( GL_TEXTURE_RECTANGLE_EXT,
0,
GL_RGBA,
size.width,
size.height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
[cache bitmapData] );
glReportError();
}
-(NSString*)description;
{
return sf(@"<GLTexture@%p wraps texid %d of size (%.2f, %.2f)>", self, texID, size.width, size.height);
}
@end
static unsigned int truncPowerOf2(unsigned int x)
{
int i = 0;
while (x = x>>1) i++;
return (1<<i);
}
@implementation NSImage(NSImageGLTextureAdditions)
-(GLTexture*)glTexture;
{
return [[[GLTexture alloc] initWithNSImage:self] autorelease];
}
-(NSSize)pixelSize;
{
NSImageRep *r = [self bestRepresentationForDevice:nil];
return NSMakeSize([r pixelsWide],[r pixelsHigh]);
}
+(NSImage*)imageWithContentsOfPath:(NSString*)path;
{
return [[[NSImage alloc] initWithContentsOfFile:path] autorelease];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment