Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MainOpenGLView.m
/* |
* |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleĆs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* |
*/ |
#import "MainOpenGLView.h" |
#include <sys/time.h> |
#include <unistd.h> |
#include <QuickTime/ImageCompression.h> // for image loading and decompression |
#include <QuickTime/QuickTimeComponents.h> // for file type support |
#include <OpenGL/CGLCurrent.h> |
#include <OpenGL/CGLContext.h> |
@implementation MainOpenGLView |
- (void) loadBufferFromImageFile: (NSString*) path: (GLubyte *) imagePtr: (GLuint) imageWidth: (GLuint) imageHeight: (GLuint) imageDepth |
{ |
CFURLRef url; |
FSRef fsRef; |
BOOL ok; |
GWorldPtr pGWorld = NULL; |
OSType pixelFormat; |
FSSpec fsspecImage; |
long rowStride; // length, in bytes, of a pixel row in the image |
GraphicsImportComponent giComp; // componenet for importing image |
Rect rectImage; // rectangle of source image |
ImageDescriptionHandle hImageDesc; // handle to image description used to get image depth |
MatrixRecord matrix; |
GDHandle origDevice; // save field for current graphics device |
CGrafPtr origPort; // save field for current graphics port |
OSStatus err = noErr; // err return value |
long origImageWidth, origImageHeight; |
url = CFURLCreateWithFileSystemPath(NULL, (CFStringRef) path, kCFURLPOSIXPathStyle, false); |
if(!url) return; |
ok = CFURLGetFSRef(url, &fsRef); |
CFRelease(url); |
if(!ok) return; |
err = FSGetCatalogInfo(&fsRef, kFSCatInfoNone, NULL, NULL, &fsspecImage, NULL); |
if(err) return; |
// get imorter for the image tyoe in file |
GetGraphicsImporterForFile (&fsspecImage, &giComp); |
if (err != noErr) return; |
// Create GWorld |
err = GraphicsImportGetNaturalBounds (giComp, &rectImage); //get the image bounds |
if (err != noErr) return; |
hImageDesc = (ImageDescriptionHandle) NewHandle (sizeof (ImageDescriptionHandle)); // create a handle for the image description |
HLock ((Handle) hImageDesc); // lock said handle |
err = GraphicsImportGetImageDescription (giComp, &hImageDesc); // retrieve the image description |
if (err != noErr) return; |
origImageWidth = (long) (rectImage.right - rectImage.left); // find width from right side - left side bounds |
origImageHeight = (long) (rectImage.bottom - rectImage.top); // same for height |
if (imageDepth <= 16) // we are using a 16 bit texture for all images 16 bits or less |
{ |
imageDepth = 16; |
pixelFormat = k16BE555PixelFormat; |
} |
else // otherwise |
{ |
imageDepth = 32; |
pixelFormat = k32ARGBPixelFormat; |
} |
SetRect (&rectImage, 0, 0, (short) imageWidth, (short) imageHeight); // l, t, r. b set image rectangle for creation of GWorld |
rowStride = imageWidth * (imageDepth >> 3); // set stride in bytes width of image * pixel depth in bytes |
// create a new gworld using our unpadded buffer, ensure we set the pixel type correctly for the expected image bpp |
QTNewGWorldFromPtr (&pGWorld, pixelFormat, &rectImage, NULL, NULL, 0, imagePtr, rowStride); |
if (NULL == pGWorld) |
{ |
CloseComponent(giComp); |
return; |
} |
GetGWorld (&origPort, &origDevice); // save onscreen graphics port |
// decompress (draw) to gworld and thus fill buffer |
SetIdentityMatrix (&matrix); // set transform matrix to identity (basically pass thorugh) |
// this scale really only does something the case of non-tiled textures to inset them one pixel |
// thus maintaining the power of 2 (or desired) dimension of the overall texture |
ScaleMatrix (&matrix, X2Fix ((GLfloat) (imageWidth) / (GLfloat) origImageWidth), |
X2Fix ((GLfloat) (imageHeight) / (GLfloat) origImageHeight), |
X2Fix (0.0), X2Fix (0.0)); |
// inset texture size to image size and offset by 1 pixel into the image so the |
// decompression puts the image into to center of the pixmap inset by one on each side |
TranslateMatrix (&matrix, X2Fix (0.0), X2Fix (0.0)); // step in for border |
err = GraphicsImportSetMatrix(giComp, &matrix); // set our matrix as the importer matrix |
if (err == noErr) |
err = GraphicsImportSetGWorld (giComp, pGWorld, NULL); // set the destination of the importer component |
if (err == noErr) |
err = GraphicsImportSetQuality (giComp, codecLosslessQuality); // we want lossless decompression |
if ((err == noErr) && GetGWorldPixMap (pGWorld) && LockPixels (GetGWorldPixMap (pGWorld))) |
GraphicsImportDraw (giComp); // if everything looks good draw image to locked pixmap |
else |
{ |
DisposeGWorld (pGWorld); // dump gworld |
pGWorld = NULL; |
CloseComponent(giComp); // dump component |
return; |
} |
UnlockPixels (GetGWorldPixMap (pGWorld)); // unlock pixels |
CloseComponent(giComp); // dump component |
SetGWorld(origPort, origDevice); // set current graphics port to offscreen |
// done with gworld and image since they are loaded to a texture |
DisposeGWorld (pGWorld); // do not need gworld |
pGWorld = NULL; |
} |
- (id)initWithFrame:(NSRect)frameRect |
{ |
NSBundle *mainBndl; |
NSString *bndlPath; |
// Init pixel format attribs |
NSOpenGLPixelFormatAttribute attrs[] = |
{ |
NSOpenGLPFAAccelerated, |
NSOpenGLPFANoRecovery, |
NSOpenGLPFADoubleBuffer, |
0 |
}; |
// Get pixel format from OpenGL |
NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; |
if (!pixFmt) |
{ |
NSLog(@"No pixel format -- exiting"); |
exit(1); |
} |
// Set default path to resource directory |
mainBndl = [NSBundle mainBundle]; |
bndlPath = [mainBndl resourcePath]; |
chdir([bndlPath cString]); |
self = [super initWithFrame:frameRect pixelFormat:pixFmt]; |
[[self openGLContext] makeCurrentContext]; |
// Init object members |
frame_rate = 30; |
image_size = 1024; |
infinite_fps = GL_FALSE; |
timer = [[NSTimer scheduledTimerWithTimeInterval: (1.0f / 30.0f) target: self selector:@selector(drawRect:) userInfo:self repeats:true] retain]; |
// Setup some basic OpenGL stuff |
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
glClearColor(1.0, 1.0, 1.0, 1.0); |
glColor4f(1.0, 1.0, 1.0, 1.0); |
glEnable(GL_RASTER_POSITION_UNCLIPPED_IBM); |
glDisable(GL_DITHER); |
// Load all images into memory |
image = malloc(image_size * image_size * 4); |
[self loadBufferFromImageFile :[NSString stringWithFormat:@"../Resources/0.jpg"]:image:image_size:image_size:32]; |
// Init fps timer |
gettimeofday(&cycle_time, NULL); |
rasterPosX = 0; |
rasterPosY = 0; |
// Call for a redisplay |
[self setNeedsDisplay:true]; |
return self; |
} |
- (void)displayMPixels |
{ |
static long loop_count = 0; |
struct timeval t2; |
unsigned long t; |
GLfloat avg_fps; |
loop_count++; |
gettimeofday(&t2, NULL); |
t = 1000000.0f * (t2.tv_sec - cycle_time.tv_sec) + (t2.tv_usec - cycle_time.tv_usec); |
// Display the average data rate |
if(t > 1000000.0f * STAT_UPDATE) |
{ |
gettimeofday(&t2, NULL); |
t = 1000000.0f * (t2.tv_sec - cycle_time.tv_sec) + (t2.tv_usec - cycle_time.tv_usec); |
gettimeofday(&cycle_time, NULL); |
avg_fps = (1000000.0f * (GLfloat) loop_count) / (GLfloat) t; |
[setFPS setFloatValue:avg_fps]; |
[setMPixels setFloatValue:(avg_fps * image_size * image_size * 4) / 1000000.0f]; |
loop_count = 0; |
gettimeofday(&cycle_time, NULL); |
} |
} |
- (void)mouseDown:(NSEvent *)theEvent |
{ |
BOOL keepOn = YES; |
BOOL isInside = YES; |
NSPoint mouseLoc; |
while (keepOn) { |
theEvent = [[self window] nextEventMatchingMask: NSLeftMouseUpMask | |
NSLeftMouseDraggedMask]; |
mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; |
isInside = [self mouse:mouseLoc inRect:[self bounds]]; |
switch ([theEvent type]) |
{ |
case NSLeftMouseUp: |
keepOn = NO; |
case NSLeftMouseDragged: |
//if (mouseLoc.x < 0) mouseLoc.x = 0; |
//if (mouseLoc.y < 0) mouseLoc.y = 0; |
// if (mouseLoc.x > [self bounds].size.width) [self bounds].size.width - 1; |
//if (mouseLoc.y > [self bounds].size.height) [self bounds].size.height - 1; |
rasterPosX = mouseLoc.x - ([self bounds].size.width/2); |
rasterPosY = mouseLoc.y - ([self bounds].size.height/2); |
[self display]; |
break; |
default: |
/* Ignore any other kind of event. */ |
break; } |
} |
return; |
} |
- (void)keyDown:(NSEvent *)theEvent |
{ |
unichar unicodeKey = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];; |
if (unicodeKey==NSUpArrowFunctionKey) |
{ |
[zoomSlider setFloatValue:[zoomSlider floatValue]+0.01f]; |
[zoomText setFloatValue:[zoomSlider floatValue]]; |
[self zoom:zoomSlider]; |
} |
else if (unicodeKey == NSDownArrowFunctionKey) |
{ |
[zoomSlider setFloatValue:[zoomSlider floatValue]-0.01f]; |
[zoomText setFloatValue:[zoomSlider floatValue]]; |
[self zoom:zoomSlider]; |
} |
} |
- (BOOL) acceptsFirstResponder{ return YES;} |
- (void)drawRect:(NSRect)aRect |
{ |
// Make this context current |
[[self openGLContext] makeCurrentContext]; |
glClear(GL_COLOR_BUFFER_BIT); |
glRasterPos2f(rasterPosX, rasterPosY); |
if(infinite_fps) |
{ |
struct timeval t1, t2; |
GLfloat t=0; |
GLuint reps = 0, i; |
gettimeofday(&t1, NULL); |
do |
{ |
for(i = 0; i < 50; i++) |
glDrawPixels(image_size, image_size, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image); |
gettimeofday(&t2, NULL); |
t = 1000000.0f *(t2.tv_sec - t1.tv_sec) +(t2.tv_usec - t1.tv_usec); |
reps += 50; |
} |
while(t < 100000.0f); //.1 seconds for infinite_fps |
glFinish(); |
gettimeofday(&t2, NULL); |
t = (t2.tv_sec - t1.tv_sec) + (t2.tv_usec - t1.tv_usec) / 1000000.0f; |
[setFPS setFloatValue: (GLfloat) reps / t]; |
[setMPixels setFloatValue:(reps * image_size * image_size * 4) / (1000000.0f * t)]; |
} |
else |
{ |
glDrawPixels(image_size, image_size, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, image); |
// Display the average data rate |
[self displayMPixels]; |
} |
// Swap buffer to screen |
[[self openGLContext] flushBuffer]; |
} |
- (void)update // moved or resized |
{ |
NSRect rect; |
[super update]; |
[[self openGLContext] makeCurrentContext]; |
[[self openGLContext] update]; |
rect = [self bounds]; |
glViewport(0, 0, (GLint) rect.size.width, (GLint) rect.size.height); |
glMatrixMode(GL_PROJECTION); |
glLoadIdentity(); |
gluOrtho2D(-(rect.size.width/2), rect.size.width/2, -(rect.size.height/2), rect.size.height/2); |
glMatrixMode(GL_MODELVIEW); |
glLoadIdentity(); |
[self setNeedsDisplay:true]; |
} |
- (void)reshape // scrolled, moved or resized |
{ |
NSRect rect; |
[super reshape]; |
[[self openGLContext] makeCurrentContext]; |
[[self openGLContext] update]; |
rect = [self bounds]; |
glViewport(0, 0, (GLint) rect.size.width, (GLint) rect.size.height); |
glMatrixMode(GL_PROJECTION); |
glLoadIdentity(); |
gluOrtho2D(-(rect.size.width/2), rect.size.width/2, -(rect.size.height/2), rect.size.height/2); |
glMatrixMode(GL_MODELVIEW); |
glLoadIdentity(); |
[self setNeedsDisplay:true]; |
} |
- (IBAction) zoom: (id) sender |
{ |
GLfloat z = [sender floatValue]; |
if(z > 0.995f && z < 1.005f) z = 1.0f; |
glPixelZoom(z, z); |
[zoomText setFloatValue:z]; |
[self setNeedsDisplay:true]; |
} |
- (IBAction) frameRate: (id) sender |
{ |
GLfloat t; |
frame_rate = [sender intValue]; |
if(!infinite_fps) |
{ |
t = 1.0f / (GLfloat) frame_rate; |
[timer invalidate]; |
[timer release]; |
timer = [[NSTimer scheduledTimerWithTimeInterval: t target: self selector:@selector(drawRect:) userInfo:self repeats:true] retain]; |
} |
} |
- (IBAction) imageSize: (id) sender |
{ |
NSString *str; |
image_size = [sender intValue]; |
if(image) free(image); |
image = malloc(image_size * image_size * 4); |
[self loadBufferFromImageFile :[NSString stringWithFormat:@"../Resources/0.jpg"]:image:image_size:image_size:32]; |
str = [NSString stringWithFormat:@"%dx%dx4", image_size, image_size]; |
[setImageSize setIntValue:image_size]; |
[setImageSizeTitle setStringValue:str]; |
} |
- (IBAction) infiniteFPS: (id) sender |
{ |
GLfloat t; |
infinite_fps = [sender intValue]; |
if(infinite_fps) |
{ |
t = 0.5f; |
[timer invalidate]; |
[timer release]; |
timer = [[NSTimer scheduledTimerWithTimeInterval: t target: self selector:@selector(drawRect:) userInfo:self repeats:true] retain]; |
[self setNeedsDisplay:true]; |
} |
else |
{ |
t = 1.0f / (GLfloat) frame_rate; |
[timer invalidate]; |
[timer release]; |
timer = [[NSTimer scheduledTimerWithTimeInterval: t target: self selector:@selector(drawRect:) userInfo:self repeats:true] retain]; |
} |
} |
- (void)mouseDragged:(NSEvent *)theEvent |
{ |
[self setNeedsDisplay:true]; |
} |
@end |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-16