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.
BasicOpenGLView.m
/* |
* BasicOpenGLView.m |
* Created November 3 2004. |
* Copyright (c) 2004 Apple Computer Inc. All rights reserved. |
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 "BasicOpenGLView.h" |
#import "trackball.h" |
// ================================== |
recVec gOrigin = {0.0, 0.0, 0.0}; |
// single set of interaction flags and states |
GLint gDollyPanStartPoint[2] = {0, 0}; |
GLfloat gTrackBallRotation [4] = {0.0f, 0.0f, 0.0f, 0.0f}; |
GLboolean gDolly = GL_FALSE; |
GLboolean gPan = GL_FALSE; |
GLboolean gTrackball = GL_FALSE; |
BasicOpenGLView * gTrackingViewInfo = NULL; |
CGDisplayCount gNumDisplays = 0; |
// time and message info |
CFAbsoluteTime gMsgPresistance = 10.0f; |
static CFAbsoluteTime gStartTime = 0.0f; |
// error output |
GLString * gErrStringTex; |
float gErrorTime; |
// set app start time |
static void setStartTime (void) { gStartTime = CFAbsoluteTimeGetCurrent (); } |
// return float elpased time in seconds since app start |
static CFAbsoluteTime getElapsedTime (void) { return CFAbsoluteTimeGetCurrent () - gStartTime; } |
// error reporting as both window message and debugger string |
void reportError (char * strError) |
{ |
NSMutableDictionary *attribs = [NSMutableDictionary dictionary]; |
[attribs setObject: [NSFont fontWithName: @"Monaco" size: 9.0f] forKey: NSFontAttributeName]; |
[attribs setObject: [NSColor whiteColor] forKey: NSForegroundColorAttributeName]; |
gErrorTime = getElapsedTime (); |
NSMutableString * errString = [NSMutableString stringWithFormat:@"Error: %s (at time: %0.1f secs).", strError, gErrorTime]; |
NSLog (@"%@\n", errString); |
if (gErrStringTex) |
[gErrStringTex setString:errString];// withAttributes:attribs]; |
else |
gErrStringTex = [[(GLString*)[GLString alloc] initWithString:errString] retain]; |
} |
// if error dump gl errors to debugger string, return error |
GLenum glReportError (void) |
{ |
GLenum err = glGetError(); |
if (GL_NO_ERROR != err) |
reportError ((char *) gluErrorString (err)); |
return err; |
} |
@implementation BasicOpenGLView |
// pixel format definition |
+ (NSOpenGLPixelFormat*) basicPixelFormat |
{ |
NSOpenGLPixelFormatAttribute attributes [] = { |
NSOpenGLPFAWindow, |
NSOpenGLPFADoubleBuffer, // double buffered |
NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer |
(NSOpenGLPixelFormatAttribute)nil |
}; |
return [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease]; |
} |
// update the projection matrix based on camera and view info |
- (void) updateProjection |
{ |
GLdouble ratio, radians, wd2; |
GLdouble left, right, top, bottom, near, far; |
[[self openGLContext] makeCurrentContext]; |
// set projection |
glMatrixMode (GL_PROJECTION); |
glLoadIdentity (); |
near = -camera.viewPos.z - shapeSize * 0.5; |
if (near < 0.00001) |
near = 0.00001; |
far = -camera.viewPos.z + shapeSize * 0.5; |
//if (near < 1.0) |
// near = 1.0; |
radians = 0.0174532925 * camera.aperture / 2; // half aperture degrees to radians |
wd2 = near * tan(radians); |
ratio = camera.viewWidth / (float) camera.viewHeight; |
if (ratio >= 1.0) { |
left = -ratio * wd2; |
right = ratio * wd2; |
top = wd2; |
bottom = -wd2; |
} else { |
left = -wd2; |
right = wd2; |
top = wd2 / ratio; |
bottom = -wd2 / ratio; |
} |
glFrustum (left, right, bottom, top, near, far); |
[self updateCameraString]; |
} |
// updates the contexts model view matrix for object and camera moves |
- (void) updateModelView |
{ |
[[self openGLContext] makeCurrentContext]; |
// move view |
glMatrixMode (GL_MODELVIEW); |
glLoadIdentity (); |
gluLookAt (camera.viewPos.x, camera.viewPos.y, camera.viewPos.z, |
camera.viewPos.x + camera.viewDir.x, |
camera.viewPos.y + camera.viewDir.y, |
camera.viewPos.z + camera.viewDir.z, |
camera.viewUp.x, camera.viewUp.y ,camera.viewUp.z); |
// if we have trackball rotation to map (this IS the test I want as it can be explicitly 0.0f) |
if ((gTrackingViewInfo == self) && gTrackBallRotation[0] != 0.0f) |
glRotatef (gTrackBallRotation[0], gTrackBallRotation[1], gTrackBallRotation[2], gTrackBallRotation[3]); |
else { |
} |
// accumlated world rotation via trackball |
glRotatef (worldRotation[0], worldRotation[1], worldRotation[2], worldRotation[3]); |
// object itself rotating applied after camera rotation |
rRot[0] = 0.0f; // reset animation rotations (do in all cases to prevent rotating while moving with trackball) |
rRot[1] = 0.0f; |
rRot[2] = 0.0f; |
[self updateCameraString]; |
} |
// handles resizing of GL need context update and if the window dimensions change, a |
// a window dimension update, reseting of viewport and an update of the projection matrix |
- (void) resizeGL |
{ |
NSRect rectView = [self bounds]; |
// ensure camera knows size changed |
if ((camera.viewHeight != rectView.size.height) || |
(camera.viewWidth != rectView.size.width)) { |
camera.viewHeight = rectView.size.height; |
camera.viewWidth = rectView.size.width; |
glViewport (0, 0, camera.viewWidth, camera.viewHeight); |
[self updateProjection]; // update projection matrix |
[self updateInfoString]; |
} |
} |
// move camera in z axis |
-(void)mouseDolly: (NSPoint) location |
{ |
GLfloat dolly = (gDollyPanStartPoint[1] -location.y) * -camera.viewPos.z / 300.0f; |
camera.viewPos.z += dolly; |
if (camera.viewPos.z == 0.0) // do not let z = 0.0 |
camera.viewPos.z = 0.0001; |
gDollyPanStartPoint[0] = location.x; |
gDollyPanStartPoint[1] = location.y; |
} |
// move camera in x/y plane |
- (void)mousePan: (NSPoint) location |
{ |
GLfloat panX = (gDollyPanStartPoint[0] - location.x) / (900.0f / -camera.viewPos.z); |
GLfloat panY = (gDollyPanStartPoint[1] - location.y) / (900.0f / -camera.viewPos.z); |
camera.viewPos.x -= panX; |
camera.viewPos.y -= panY; |
gDollyPanStartPoint[0] = location.x; |
gDollyPanStartPoint[1] = location.y; |
} |
// sets the camera data to initial conditions |
- (void) resetCamera |
{ |
camera.aperture = 40; |
camera.rotPoint = gOrigin; |
camera.viewPos.x = 0.0; |
camera.viewPos.y = 0.0; |
camera.viewPos.z = -10.0; |
camera.viewDir.x = -camera.viewPos.x; |
camera.viewDir.y = -camera.viewPos.y; |
camera.viewDir.z = -camera.viewPos.z; |
camera.viewUp.x = 0; |
camera.viewUp.y = 1; |
camera.viewUp.z = 0; |
} |
// given a delta time in seconds and current rotation accel, velocity and position, update overall object rotation |
- (void) updateObjectRotationForTimeDelta:(CFAbsoluteTime)deltaTime |
{ |
// update rotation based on vel and accel |
float rotation[4] = {0.0f, 0.0f, 0.0f, 0.0f}; |
GLfloat fVMax = 2.0; |
short i; |
// do velocities |
for (i = 0; i < 3; i++) { |
rVel[i] += rAccel[i] * deltaTime * 30.0; |
if (rVel[i] > fVMax) { |
rAccel[i] *= -1.0; |
rVel[i] = fVMax; |
} else if (rVel[i] < -fVMax) { |
rAccel[i] *= -1.0; |
rVel[i] = -fVMax; |
} |
rRot[i] += rVel[i] * deltaTime * 30.0; |
while (rRot[i] > 360.0) |
rRot[i] -= 360.0; |
while (rRot[i] < -360.0) |
rRot[i] += 360.0; |
} |
rotation[0] = rRot[0]; |
rotation[1] = 1.0f; |
addToRotationTrackball (rotation, objectRotation); |
rotation[0] = rRot[1]; |
rotation[1] = 0.0f; rotation[2] = 1.0f; |
addToRotationTrackball (rotation, objectRotation); |
rotation[0] = rRot[2]; |
rotation[2] = 0.0f; rotation[3] = 1.0f; |
addToRotationTrackball (rotation, objectRotation); |
} |
// per-window timer function, basic time based animation preformed here |
- (void)animationTimer:(NSTimer *)timer |
{ |
BOOL shouldDraw = NO; |
if (fAnimate) { |
CFTimeInterval deltaTime = CFAbsoluteTimeGetCurrent () - time; |
if (deltaTime > 10.0) // skip pauses |
return; |
else { |
// if we are not rotating with trackball in this window |
if (!gTrackball || (gTrackingViewInfo != self)) { |
[self updateObjectRotationForTimeDelta: deltaTime]; // update object rotation |
} |
shouldDraw = YES; // force redraw |
} |
} |
time = CFAbsoluteTimeGetCurrent (); //reset time in all cases |
// if we have current messages |
if (((getElapsedTime () - msgTime) < gMsgPresistance) || ((getElapsedTime () - gErrorTime) < gMsgPresistance)) |
shouldDraw = YES; // force redraw |
if (YES == shouldDraw) |
[self drawRect:[self bounds]]; // redraw now instead dirty to enable updates during live resize |
} |
// these functions create or update StringTextures one should expect to have to regenerate the image, bitmap and texture when the string changes thus these functions are not particularly light weight |
- (void) updateInfoString |
{ // update info string texture |
NSMutableString * string = [NSMutableString stringWithFormat:@"(%0.0f x %0.0f) \n%s \n%s", [self bounds].size.width, [self bounds].size.height, glGetString (GL_RENDERER), glGetString (GL_VERSION)]; |
if (infoStringTex) |
[infoStringTex setString:string];// withAttributes:stanStringAttrib]; |
else |
infoStringTex = [[(GLString*)[GLString alloc] initWithString:string] retain]; |
} |
- (void) createHelpString |
{ |
NSMutableString * string = [NSMutableString stringWithFormat:@" Cmd-O: Opens a file for display\n Cmd-Click, Click: Zoom In / Out\n Alt/Opt-Click: Rotate Object\n Ctrl-Click: Pan Around\n ===========================\n 'H': Toggle Help\n 'R': Reset Rotation\n"]; |
helpStringTex = [[(GLString*)[GLString alloc] initWithString:string] retain]; |
} |
- (void) createMessageString |
{ |
NSMutableString * string = [NSMutableString stringWithFormat:@"No messages..."]; |
msgStringTex = [[(GLString*)[GLString alloc] initWithString:string] retain]; |
} |
- (void) updateCameraString |
{ // update info string texture |
NSMutableString *string = [NSMutableString stringWithFormat:@"Camera at (%0.1f, %0.1f, %0.1f) looking at (%0.1f, %0.1f, %0.1f) with %0.1f aperture", camera.viewPos.x, camera.viewPos.y, camera.viewPos.z, camera.viewDir.x, camera.viewDir.y, camera.viewDir.z, camera.aperture]; |
if (camStringTex) |
[camStringTex setString:string];// withAttributes:stanStringAttrib]; |
else |
camStringTex = [[(GLString*)[GLString alloc] initWithString:string] retain]; |
} |
// draw text info using our StringTexture class for much more optimized text drawing |
- (void) drawInfo |
{ |
GLint matrixMode; |
GLboolean depthTest = glIsEnabled (GL_DEPTH_TEST); |
GLfloat height, width, messageTop = 10.0f; |
height = camera.viewHeight; |
width = camera.viewWidth; |
glDisable (GL_DEPTH_TEST); // ensure text is not remove by deoth buffer test. |
glEnable (GL_BLEND); // for text fading |
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // ditto |
glEnable (GL_TEXTURE_RECTANGLE_EXT); |
// set orthograhic 1:1 pixel transform in local view coords |
glGetIntegerv (GL_MATRIX_MODE, &matrixMode); |
glMatrixMode (GL_PROJECTION); |
glPushMatrix(); |
glLoadIdentity (); |
glMatrixMode (GL_MODELVIEW); |
glPushMatrix(); |
glLoadIdentity (); |
glScalef (2.0f / width, -2.0f / height, 1.0f); |
glTranslatef (-width / 2.0f, -height / 2.0f, 0.0f); |
glColor4f (1.0f, 1.0f, 1.0f, 1.0f); |
[infoStringTex drawAtPoint:NSMakePoint (10.0f, height - [infoStringTex frameSize].height - 10.0f)]; |
[camStringTex drawAtPoint:NSMakePoint (10.0f, messageTop)]; |
// GLImage: Info string display |
if([theImage imageInfo]) |
{ |
GLString *gstr = [theImage imageInfo]; |
[gstr drawAtPoint:NSMakePoint((width - ([gstr frameSize].width + 10.0f)), messageTop)]; |
} |
messageTop += [camStringTex frameSize].height + 3.0f; |
if (fDrawHelp) |
[helpStringTex drawAtPoint:NSMakePoint (floor ((width - [helpStringTex frameSize].width) / 2.0f), floor ((height - [helpStringTex frameSize].height) / 3.0f))]; |
// message string |
float currTime = getElapsedTime (); |
if ((currTime - msgTime) < gMsgPresistance) { |
GLfloat comp = (gMsgPresistance - getElapsedTime () + msgTime) * 0.1; // premultiplied fade |
glColor4f (comp, comp, comp, comp); |
[msgStringTex drawAtPoint:NSMakePoint (10.0f, messageTop)]; |
messageTop += [msgStringTex frameSize].height + 3.0f; |
} |
// global error message |
if ((currTime - gErrorTime) < gMsgPresistance) { |
GLfloat comp = (gMsgPresistance - getElapsedTime () + gErrorTime) * 0.1; // premultiplied fade |
glColor4f (comp, comp, comp, comp); |
[(GLString*)gErrStringTex drawAtPoint:NSMakePoint (10.0f, messageTop)]; |
} |
// reset orginal martices |
glPopMatrix(); // GL_MODELVIEW |
glMatrixMode (GL_PROJECTION); |
glPopMatrix(); |
glMatrixMode (matrixMode); |
glDisable (GL_TEXTURE_RECTANGLE_EXT); |
glDisable (GL_BLEND); |
if (depthTest) |
glEnable (GL_DEPTH_TEST); |
glReportError (); |
} |
-(IBAction) animate: (id) sender |
{ |
fAnimate = 1 - fAnimate; |
if (fAnimate) |
[animateMenuItem setState: NSOnState]; |
else |
[animateMenuItem setState: NSOffState]; |
} |
-(IBAction) info: (id) sender |
{ |
fInfo = 1 - fInfo; |
if (fInfo) |
[infoMenuItem setState: NSOnState]; |
else |
[infoMenuItem setState: NSOffState]; |
[self setNeedsDisplay: YES]; |
} |
-(void)keyDown:(NSEvent *)theEvent |
{ |
NSString *characters = [theEvent characters]; |
if ([characters length]) { |
unichar character = [characters characterAtIndex:0]; |
switch (character) { |
case 'h': |
// toggle help |
fDrawHelp = 1 - fDrawHelp; |
[self setNeedsDisplay: YES]; |
break; |
case 'r': |
// Reset rotation |
[self resetObjectRotation]; |
[self setNeedsDisplay:YES]; |
break; |
} |
} |
} |
- (void)mouseDown:(NSEvent *)theEvent // trackball |
{ |
if ([theEvent modifierFlags] & NSControlKeyMask) // send to pan |
[self rightMouseDown:theEvent]; |
else if ([theEvent modifierFlags] & NSAlternateKeyMask) |
{ |
NSPoint location = [self convertPoint:[theEvent locationInWindow] fromView:nil]; |
location.y = camera.viewHeight - location.y; |
gDolly = GL_FALSE; // no dolly |
gPan = GL_FALSE; // no pan |
gTrackball = GL_TRUE; |
//[self otherMouseDown:theEvent]; |
gTrackingViewInfo = self; |
startTrackball (location.x, location.y, 0, 0, camera.viewWidth, camera.viewHeight); |
//[self otherMouseDown:theEvent]; |
} |
else { |
// send to dolly |
[self otherMouseDown:theEvent]; |
} |
} |
- (void)rightMouseDown:(NSEvent *)theEvent // pan |
{ |
NSPoint location = [self convertPoint:[theEvent locationInWindow] fromView:nil]; |
location.y = camera.viewHeight - location.y; |
if (gTrackball) { // if we are currently tracking, end trackball |
if (gTrackBallRotation[0] != 0.0) |
addToRotationTrackball (gTrackBallRotation, worldRotation); |
gTrackBallRotation [0] = gTrackBallRotation [1] = gTrackBallRotation [2] = gTrackBallRotation [3] = 0.0f; |
} |
gDolly = GL_FALSE; // no dolly |
gPan = GL_TRUE; |
gTrackball = GL_FALSE; // no trackball |
gDollyPanStartPoint[0] = location.x; |
gDollyPanStartPoint[1] = location.y; |
gTrackingViewInfo = self; |
} |
- (void)otherMouseDown:(NSEvent *)theEvent //dolly |
{ |
NSPoint location = [self convertPoint:[theEvent locationInWindow] fromView:nil]; |
location.y = camera.viewHeight - location.y; |
if (gTrackball) { // if we are currently tracking, end trackball |
if (gTrackBallRotation[0] != 0.0) |
addToRotationTrackball (gTrackBallRotation, worldRotation); |
gTrackBallRotation [0] = gTrackBallRotation [1] = gTrackBallRotation [2] = gTrackBallRotation [3] = 0.0f; |
} |
gDolly = GL_TRUE; |
gPan = GL_FALSE; // no pan |
gTrackball = GL_FALSE; // no trackball |
gDollyPanStartPoint[0] = location.x; |
gDollyPanStartPoint[1] = location.y; |
gTrackingViewInfo = self; |
} |
- (void)mouseUp:(NSEvent *)theEvent |
{ |
if (gDolly) { // end dolly |
gDolly = GL_FALSE; |
} else if (gPan) { // end pan |
gPan = GL_FALSE; |
} else if (gTrackball) { // end trackball |
gTrackball = GL_FALSE; |
if (gTrackBallRotation[0] != 0.0) |
addToRotationTrackball (gTrackBallRotation, worldRotation); |
gTrackBallRotation [0] = gTrackBallRotation [1] = gTrackBallRotation [2] = gTrackBallRotation [3] = 0.0f; |
} |
gTrackingViewInfo = NULL; |
} |
- (void)rightMouseUp:(NSEvent *)theEvent |
{ |
[self mouseUp:theEvent]; |
} |
- (void)otherMouseUp:(NSEvent *)theEvent |
{ |
[self mouseUp:theEvent]; |
} |
- (void)mouseDragged:(NSEvent *)theEvent |
{ |
NSPoint location = [self convertPoint:[theEvent locationInWindow] fromView:nil]; |
location.y = camera.viewHeight - location.y; |
if (gTrackball) { |
rollToTrackball (location.x, location.y, gTrackBallRotation); |
[self setNeedsDisplay: YES]; |
} else if (gDolly) { |
[self mouseDolly: location]; |
[self updateProjection]; // update projection matrix (not normally done on draw) |
[self setNeedsDisplay: YES]; |
} else if (gPan) { |
[self mousePan: location]; |
[self setNeedsDisplay: YES]; |
} |
} |
- (void)scrollWheel:(NSEvent *)theEvent |
{ |
float wheelDelta = [theEvent deltaX] +[theEvent deltaY] + [theEvent deltaZ]; |
if (wheelDelta) |
{ |
GLfloat deltaAperture = wheelDelta * -camera.aperture / 200.0f; |
camera.aperture += deltaAperture; |
if (camera.aperture < 0.1) // do not let aperture <= 0.1 |
camera.aperture = 0.1; |
if (camera.aperture > 179.9) // do not let aperture >= 180 |
camera.aperture = 179.9; |
[self updateProjection]; // update projection matrix |
[self setNeedsDisplay: YES]; |
} |
} |
- (void)rightMouseDragged:(NSEvent *)theEvent |
{ |
[self mouseDragged: theEvent]; |
} |
- (void)otherMouseDragged:(NSEvent *)theEvent |
{ |
[self mouseDragged: theEvent]; |
} |
- (void) drawRect:(NSRect)rect |
{ |
if (NO == fGLInit) |
[self prepareOpenGL]; |
fGLInit = YES; |
// setup viewport and prespective |
[self resizeGL]; // forces projection matrix update (does test for size changes) |
[self updateModelView]; // update model view matrix for object |
// clear our drawable |
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
// GLImage: here's where we draw the textured polygon |
[theImage drawTexture]; |
if (fInfo) |
[self drawInfo]; |
if ([self inLiveResize] && !fAnimate) |
glFlush (); |
else |
[[self openGLContext] flushBuffer]; |
glReportError (); |
} |
// set initial OpenGL state (current context is set) |
// called after context is created |
- (void) prepareOpenGL |
{ |
long swapInt = 1; |
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; // set to vbl sync |
// init GL stuff here |
glEnable(GL_DEPTH_TEST); |
glShadeModel(GL_SMOOTH); |
glEnable(GL_CULL_FACE); |
glFrontFace(GL_CCW); |
glPolygonOffset (1.0f, 1.0f); |
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
[self resetCamera]; |
shapeSize = 7.0f; // max radius of of objects |
// init fonts for use with strings |
NSFont * font =[NSFont fontWithName:@"Helvetica" size:12.0]; |
stanStringAttrib = [[NSMutableDictionary dictionary] retain]; |
[stanStringAttrib setObject:font forKey:NSFontAttributeName]; |
[stanStringAttrib setObject:[NSColor whiteColor] forKey:NSForegroundColorAttributeName]; |
[font release]; |
GLString *helpStringTex = [[[GLString alloc] init] retain]; |
GLString *infoStringTex = [[[GLString alloc] init] retain];; |
GLString *camStringTex = [[[GLString alloc] init] retain];; |
GLString *capStringTex = [[[GLString alloc] init] retain];; |
GLString *msgStringTex = [[[GLString alloc] init] retain];; |
// ensure strings are created |
[self createHelpString]; |
[self createMessageString]; |
} |
// this can be a troublesome call to do anything heavyweight, as it is called on window moves, resizes, and display config changes. So be |
// careful of doing too much here. |
- (void) update // window resizes, moves and display changes (resize, depth and display config change) |
{ |
msgTime = getElapsedTime (); |
[msgStringTex setString:[NSString stringWithFormat:@"update at %0.1f secs", msgTime]]; |
// withAttributes:stanStringAttrib]; |
[super update]; |
if (![self inLiveResize]) {// if not doing live resize |
[self updateInfoString]; // to get change in renderers will rebuld string every time (could test for early out) |
//getCurrentCaps (); // this call checks to see if the current config changed in a reasonably lightweight way to prevent expensive re-allocations |
} |
} |
-(id) initWithFrame: (NSRect) frameRect |
{ |
NSOpenGLPixelFormat * pf = [BasicOpenGLView basicPixelFormat]; |
self = [super initWithFrame: frameRect pixelFormat: pf]; |
return self; |
} |
- (BOOL)acceptsFirstResponder |
{ |
return YES; |
} |
- (BOOL)becomeFirstResponder |
{ |
return YES; |
} |
- (BOOL)resignFirstResponder |
{ |
return YES; |
} |
- (void) awakeFromNib |
{ |
setStartTime (); // get app start time |
//getCurrentCaps (); // get current GL capabilites for all displays |
// set start values... |
rVel[0] = 0.3; rVel[1] = 0.1; rVel[2] = 0.2; |
rAccel[0] = 0.003; rAccel[1] = -0.005; rAccel[2] = 0.004; |
fInfo = 1; |
fAnimate = 1; |
time = CFAbsoluteTimeGetCurrent (); // set animation time start time |
fDrawHelp = 1; |
// start animation timer |
timer = [NSTimer timerWithTimeInterval:(1.0f/60.0f) target:self selector:@selector(animationTimer:) userInfo:nil repeats:YES]; |
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; |
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode]; // ensure timer fires during resize |
// GLImage: initialize our object |
theImage = [[[GLImage alloc] init] retain]; |
} |
//******************************************** |
// Additions for NSGLImage sample // |
//******************************************** |
-(void)resetObjectRotation |
{ |
int i = 0; |
for(i = 0; i < 4; i++) |
{ |
gTrackBallRotation[i] = 0.0; |
worldRotation[i] = 0.0; |
} |
} |
- (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo |
{ |
//NSLog(@"Filename: %@ \n Directory: %@ \n", [panel filename], [panel directory]); |
// So we've got an image selected. Check to see if NSImage will open it. |
// Make sure we've got a valid NSImage object |
if(!theImage) |
theImage = [[[GLImage alloc] init] retain]; |
[theImage loadTextureFromFile:[panel filename]]; |
} |
-(IBAction)openPanelAction:(id)sender |
{ |
NSOpenPanel *op = [NSOpenPanel openPanel]; |
NSMutableArray *fTypes = [NSMutableArray arrayWithObject:@"jpg"]; |
[op setCanChooseFiles:YES]; |
[op setAllowsMultipleSelection:NO]; |
[op setCanChooseDirectories:NO]; |
[op beginSheetForDirectory:[[NSBundle mainBundle] bundlePath] |
file:nil |
types:fTypes |
modalForWindow:[self window] |
modalDelegate:self |
didEndSelector:@selector(openPanelDidEnd: returnCode: contextInfo:) |
contextInfo:nil]; |
} |
@end |
Copyright © 2004 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2004-12-01