Sources/View/GLSLBasicsView.m
//--------------------------------------------------------------------------------- |
// |
// File: GLSLBasicsView.m |
// |
// Abstract: Main rendering class |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by |
// 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 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. |
// |
// Copyright (c) 2007-2008 Apple Inc., All rights reserved. |
// |
//--------------------------------------------------------------------------------- |
//--------------------------------------------------------------------------------- |
#import "GLSLHardwareSupport.h" |
#import "GLSLBasicsView.h" |
//--------------------------------------------------------------------------------- |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Constatnts |
//--------------------------------------------------------------------------------- |
static const GLfloat kPi = 3.1415927f; // IEEE-754 single precision |
static const GLint kFloatSize = sizeof(GLfloat); |
static const GLfloat kOffsetDelta = 1.0f/256.0f; |
static const GLdouble kViewRotationDegreesPerSecond = 20.0; |
static const NSTimeInterval kScheduledTimerInSeconds = 1.0f/120.0f; |
//--------------------------------------------------------------------------------- |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Private Enumerated Types |
//--------------------------------------------------------------------------------- |
enum UniformLocations |
{ |
kUniformLightPosition = 0, |
kUniformOffset, |
kUniformPattern, |
kUniformPalette |
}; |
typedef enum UniformLocations UniformLocations; |
//--------------------------------------------------------------------------------- |
//--------------------------------------------------------------------------------- |
#pragma mark - |
//--------------------------------------------------------------------------------- |
@implementation GLSLBasicsView |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Initialize 1D & 2D Textures |
//--------------------------------------------------------------------------------- |
- (GLuint) initTexture1D:(const GLvoid *)thePixels |
count:(const GLsizei)theCount |
{ |
GLuint textureID = 0; |
glActiveTexture(GL_TEXTURE1); |
glGenTextures(1, &textureID); |
glBindTexture(GL_TEXTURE_1D, textureID); |
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
glTexImage1D(GL_TEXTURE_1D, |
0, |
GL_RGBA, |
theCount, |
0, |
GL_RGB, |
GL_FLOAT, |
thePixels); |
return textureID; |
} // initTexture1D |
//--------------------------------------------------------------------------------- |
- (GLuint) initTexture2D:(const GLvoid *)thePixels |
width:(const GLsizei)theWidth |
height:(const GLsizei)theHeight |
{ |
GLuint textureID = 0; |
glActiveTexture(GL_TEXTURE0); |
glGenTextures(1, &textureID); |
glBindTexture(GL_TEXTURE_2D, textureID); |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
glTexImage2D(GL_TEXTURE_2D, |
0, |
GL_RGBA, |
theWidth, |
theHeight, |
0, |
GL_LUMINANCE, |
GL_FLOAT, |
thePixels); |
return textureID; |
} // initTexture2D |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Initialize palette |
//--------------------------------------------------------------------------------- |
- (void) initPalettePixels:(GLfloat *)thePixels |
count:(const GLsizei)theCount |
{ |
GLfloat a = (GLfloat)theCount; |
GLfloat b = 0.5f * a; |
GLfloat c = 1.5f * a; |
GLfloat d = 2.0f / a; |
GLfloat x[2]; |
GLfloat n; |
GLint i; |
GLint j; |
a = 1.0f / a; |
c = 1.0f / c; |
for( i = 0; i < theCount; i++ ) |
{ |
n = (GLfloat)i; |
x[0] = kPi * n; |
x[1] = sinf( a * x[0] ); |
j = 3 * i; |
thePixels[j] = 1.0f - x[1]; |
thePixels[j+1] = b * c * ( 1.0f + sinf( d * x[0] ) ); |
thePixels[j+2] = x[1]; |
} // for |
} // initPalettePixels |
//--------------------------------------------------------------------------------- |
- (void) initPalette |
{ |
GLsizei count = 256; |
GLfloat *palettePixels = (GLfloat *)malloc( 3 * count * kFloatSize ); |
if( palettePixels != NULL ) |
{ |
[self initPalettePixels:palettePixels |
count:count]; |
paletteID = [self initTexture1D:palettePixels |
count:count]; |
free( palettePixels ); |
palettePixels = NULL; |
} // if |
} // initPalette |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Initialize pattern |
//--------------------------------------------------------------------------------- |
- (void) initPatternPixels:(GLfloat *)thePixels |
width:(const GLsizei)theWidth |
height:(const GLsizei)theHeight |
{ |
GLfloat a = (GLfloat)theWidth; |
GLfloat b = 0.25f * a; |
GLfloat c = 0.125f * a; |
GLfloat f; |
GLfloat x; |
GLfloat y; |
GLint i; |
GLint iMax = theWidth >> 1; |
GLint j; |
GLint jMax = theHeight >> 1; |
GLint k = theWidth - 1; |
GLint l; |
GLint m; |
GLint n; |
b = 1.0f / b; |
c = 1.0f / c; |
for( i = 0; i < iMax; i++ ) |
{ |
y = (GLfloat)i; |
for( j = 0; j < jMax; j++ ) |
{ |
x = (GLfloat) j; |
f = 0.25f*(sinf(b*x) + sinf(b*y) + sinf(b*(x+y)) + sinf(c*sqrtf(x*x+y*y))); |
l = i * theWidth; |
m = k * theWidth - l; |
n = k - j; |
thePixels[l+j] = f; |
thePixels[l+n] = f; |
thePixels[m+j] = f; |
thePixels[m+n] = f; |
} // for |
} // for |
} // initPatternPixels |
//--------------------------------------------------------------------------------- |
- (void) initPattern |
{ |
GLsizei width = 128; |
GLsizei height = 128; |
GLfloat *patternPixels = (GLfloat *)malloc(3 * width * height * kFloatSize); |
if( patternPixels != NULL ) |
{ |
[self initPatternPixels:patternPixels |
width:width |
height:height]; |
patternID = [self initTexture2D:patternPixels |
width:width |
height:height]; |
free( patternPixels ); |
patternPixels = NULL; |
} // if |
} // initPattern |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Setup OpenGL & shader uniforms |
//--------------------------------------------------------------------------------- |
- (void) initShaderUniforms |
{ |
// Enable the program object |
glUseProgramObjectARB(programObject); |
// Store the values of the uniforms from the vertex |
// and the fragment shaders |
locations[kUniformLightPosition] = [plasma getUniformLocation:"LightPosition"]; |
locations[kUniformOffset] = [plasma getUniformLocation:"offset"]; |
locations[kUniformPattern] = [plasma getUniformLocation:"pattern"]; |
locations[kUniformPalette] = [plasma getUniformLocation:"palette"]; |
// Set the (x,y,z) coordinates of the light position |
glUniform3fARB(locations[kUniformLightPosition], 0.0, 0.0, 20.0); |
// Set the samplers |
glUniform1iARB(locations[kUniformPattern], 0); |
glUniform1iARB(locations[kUniformPalette], 1); |
// Disable the program object |
glUseProgramObjectARB(NULL); |
} // initShaderUniforms |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Setup OpenGL |
//--------------------------------------------------------------------------------- |
- (void) initOpenGLStates |
{ |
[[self openGLContext] makeCurrentContext]; |
//----------------------------------------------------------------- |
// |
// For some OpenGL implementations, texture coordinates generated |
// during rasterization aren't perspective correct. However, you |
// can usually make them perspective correct by calling the API |
// glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST). Colors |
// generated at the rasterization stage aren't perspective correct |
// in almost every OpenGL implementation, / and can't be made so. |
// For this reason, you're more likely to encounter this problem |
// with colors than texture coordinates. |
// |
//----------------------------------------------------------------- |
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); |
// Set up the projection |
glMatrixMode(GL_PROJECTION); |
glLoadIdentity(); |
glFrustum(-0.3, 0.3, 0.0, 0.6, 1.0, 8.0); |
glMatrixMode(GL_MODELVIEW); |
glLoadIdentity(); |
glTranslatef(0.0, 0.0, -2.0); |
// Turn on depth test |
glEnable(GL_DEPTH_TEST); |
// front - or back - facing facets can be culled |
glEnable(GL_CULL_FACE); |
} // initOpenGL |
//--------------------------------------------------------------------------------- |
- (void) initTexturesForShader |
{ |
// Create the palette |
[self initPalette]; |
// Create the plasma pattern |
[self initPattern]; |
} // initTexturesForShader |
//--------------------------------------------------------------------------------- |
- (void) initGLSLShader |
{ |
// Initialize the plasma shader from the application bundle |
plasma = [[Shader alloc] initWithShadersInAppBundle:@"Plasma"]; |
if( plasma ) |
{ |
// Get the program object for the plasma shader |
programObject = [plasma programObject]; |
// Setup the uniforms for the plasma shader |
[self initShaderUniforms]; |
} // if |
} // initGLSLShader |
//--------------------------------------------------------------------------------- |
- (void) initOpenGLDisplayList |
{ |
tranguloidTrefoil = [[TranguloidTrefoil alloc] initTranguloidTrefoilWithAttribbutes:128 |
ratio:16]; |
if( tranguloidTrefoil ) |
{ |
tranguloidTrefoilDL = [tranguloidTrefoil displayList]; |
} // if |
} // initOpenGLDisplayList |
//--------------------------------------------------------------------------------- |
- (void) initGLUTString:(const NSRect *)theFrame |
{ |
NSSize size = theFrame->size; |
GLsizei width = (GLsizei)size.width; |
GLsizei height = (GLsizei)size.height; |
NSPoint coordinates = NSMakePoint(10.0, 10.0); |
info = [[GLUTString alloc] initWithViewSizeAndDrawCoordinates:&size |
coordinates:&coordinates]; |
infoString = [[NSString alloc] initWithFormat:@"Bounds: %ld x %ld",width,height]; |
} // initGLUTString |
//--------------------------------------------------------------------------------- |
- (void) initOpenGL:(const NSRect *)theFrame |
{ |
[self initOpenGLStates]; |
[self initTexturesForShader]; |
[self initGLSLShader]; |
[self initOpenGLDisplayList]; |
[self initGLUTString:theFrame]; |
} // initOpenGL |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Animation Timer |
//--------------------------------------------------------------------------------- |
- (void) heartbeat |
{ |
[self drawRect:[self bounds]]; |
} // heartbeat |
//--------------------------------------------------------------------------------- |
- (void) initUpdateTimer |
{ |
timer = [NSTimer timerWithTimeInterval:kScheduledTimerInSeconds |
target:self |
selector:@selector(heartbeat) |
userInfo:nil |
repeats:YES]; |
[[NSRunLoop currentRunLoop] addTimer:timer |
forMode:NSDefaultRunLoopMode]; |
[[NSRunLoop currentRunLoop] addTimer:timer |
forMode:NSEventTrackingRunLoopMode]; |
} // initUpdateTimer |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Initializations |
//--------------------------------------------------------------------------------- |
- (void) initViewAttributes |
{ |
lastFrameReferenceTime = [NSDate timeIntervalSinceReferenceDate]; |
leftMouseIsDown = NO; |
rightMouseIsDown = NO; |
angle = 0.0f; |
pitch = 25.0f; |
zoom = 1.0f; |
bounds.origin.x = 0.0f; |
bounds.origin.y = 0.0f; |
bounds.size.width = 0.0f; |
bounds.size.height = 0.0f; |
} // initViewAttributes |
//--------------------------------------------------------------------------------- |
// |
// Sync to VBL to avoid tearing. |
// |
//--------------------------------------------------------------------------------- |
- (void) initSyncToVBL |
{ |
GLint swapInterval = 1; |
[[self openGLContext] setValues:&swapInterval |
forParameter:NSOpenGLCPSwapInterval]; |
} // initSyncToVBL |
//--------------------------------------------------------------------------------- |
- (void) initOpenGLView:(const NSRect *)theFrame |
{ |
// Setting the view's frame size |
[self setFrameSize:theFrame->size]; |
// View attributes initilizations |
[self initViewAttributes]; |
// New timer for updating OpenGL view |
[self initUpdateTimer]; |
// Sync to VBL to avoid tearing |
[self initSyncToVBL]; |
// OpenGL initializations |
[self initOpenGL:theFrame]; |
// Did the frame change? |
[self setPostsFrameChangedNotifications:YES]; |
} // initOpenGLView |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Designated initializer |
//--------------------------------------------------------------------------------- |
- (NSOpenGLPixelFormat *) initPixelFormat |
{ |
NSOpenGLPixelFormatAttribute pixelAttributes[] |
= { |
NSOpenGLPFADoubleBuffer, |
NSOpenGLPFADepthSize, 24, |
NSOpenGLPFAStencilSize, 8, |
0 |
}; |
CheckForGLSLHardwareSupport( pixelAttributes ); |
NSOpenGLPixelFormat *pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttributes] |
autorelease]; |
return pixelFormat; |
} // initPixelFormat |
//--------------------------------------------------------------------------------- |
- (id) initWithFrame:(NSRect)theFrame |
pixelFormat:(NSOpenGLPixelFormat *)thePixelFormat |
{ |
// Create a GL Context to use - i.e. init the superclass |
if( thePixelFormat == nil ) |
{ |
thePixelFormat = [self initPixelFormat]; |
} // if |
self = [super initWithFrame:theFrame |
pixelFormat:thePixelFormat]; |
if( self ) |
{ |
[self initOpenGLView:&theFrame]; |
} // if |
return self; |
} // initWithFrame |
//--------------------------------------------------------------------------------- |
- (id) initWithFrame:(NSRect)theFrame |
{ |
return [self initWithFrame:theFrame |
pixelFormat:nil]; |
} // initWithFrame |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Deallocating Resources |
//--------------------------------------------------------------------------------- |
- (void) deallocTimer |
{ |
if( timer ) |
{ |
[timer invalidate]; |
[timer release]; |
timer = nil; |
} // if |
} // deallocTimer |
//--------------------------------------------------------------------------------- |
- (void) deallocOpenGLResources |
{ |
if( tranguloidTrefoil ) |
{ |
[tranguloidTrefoil release]; |
tranguloidTrefoil = nil; |
} // if |
if( patternID ) |
{ |
glDeleteTextures(1, &patternID); |
} // if |
if( paletteID ) |
{ |
glDeleteTextures(1, &paletteID); |
} // if |
if( plasma ) |
{ |
[plasma release]; |
plasma = nil; |
} // if |
if( info ) |
{ |
[info release]; |
info = nil; |
} // if |
if( infoString ) |
{ |
[infoString release]; |
infoString = nil; |
} // if |
} //deallocOpenGLResources |
//--------------------------------------------------------------------------------- |
- (void) dealloc |
{ |
// Release the update timer |
[self deallocTimer]; |
// Delete OpenGL resources |
[self deallocOpenGLResources]; |
//Dealloc the superclass |
[super dealloc]; |
} // dealloc |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Binding palette & pattern |
//--------------------------------------------------------------------------------- |
- (void) bindPalette |
{ |
glActiveTexture(GL_TEXTURE1); |
glBindTexture(GL_TEXTURE_1D, paletteID); |
} // bindPalette |
//--------------------------------------------------------------------------------- |
- (void) bindPattern |
{ |
glActiveTexture(GL_TEXTURE0); |
glBindTexture(GL_TEXTURE_2D, patternID); |
} // bindPattern |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Updating Drawing Parameters |
//--------------------------------------------------------------------------------- |
- (void) updateOffset |
{ |
offset += kOffsetDelta; |
if( offset > 1.0f ) |
{ |
offset = 0.0f; |
} // if |
} // updateOffset |
//--------------------------------------------------------------------------------- |
- (NSTimeInterval) updateTimeDelta |
{ |
NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate]; |
NSTimeInterval timeDelta = timeNow - lastFrameReferenceTime; |
return timeDelta; |
} // updateTimeDelta |
//--------------------------------------------------------------------------------- |
- (void) updatePitch |
{ |
if( pitch < -45.0f ) |
{ |
pitch = -45.0f; |
} // if |
else if( pitch > 90.0f ) |
{ |
pitch = 90.0f; |
} // else if |
glRotatef(pitch, 1.0f, 0.0f, 0.0f); |
} // updatePitch |
//--------------------------------------------------------------------------------- |
- (void) updateAngle |
{ |
if( !leftMouseIsDown && !rightMouseIsDown ) |
{ |
NSTimeInterval updateTimeDelta = [self updateTimeDelta]; |
angle += kViewRotationDegreesPerSecond * updateTimeDelta; |
if( angle >= 360.0f ) |
{ |
angle -= 360.0f; |
} // if |
} // if |
// update object rotation |
glRotatef( angle, 0.0f, 1.0f, 0.0f ); |
// reset time in all cases |
lastFrameReferenceTime = [NSDate timeIntervalSinceReferenceDate]; |
} // updateAngle |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Updating & Resizing |
//--------------------------------------------------------------------------------- |
- (void) updatePrespectiveMatrix |
{ |
GLdouble width = (GLdouble)NSWidth(bounds); |
GLdouble height = (GLdouble)NSHeight(bounds); |
GLdouble aspect = width / height; |
GLdouble right = 0.15 * aspect * zoom; |
GLdouble left = -right; |
GLdouble top = 0.15 * zoom; |
GLdouble bottom = -top; |
GLdouble zNear = 1.0; |
GLdouble zFar = 8.0; |
glMatrixMode(GL_PROJECTION); |
glLoadIdentity(); |
glFrustum(left, right, bottom, top, zNear, zFar); |
glMatrixMode(GL_MODELVIEW); |
} // updatePrespectiveMatrix |
//--------------------------------------------------------------------------------- |
// |
// Handles resizing/updating of OpenGL needs context update and if the window |
// dimensions change, window dimensions update, reseting of viewport and an update |
// of the projection matrix. |
// |
//--------------------------------------------------------------------------------- |
- (void) resizeView |
{ |
NSRect viewBounds = [self bounds]; |
if( !NSEqualRects( viewBounds, bounds ) ) |
{ |
GLsizei width = (GLsizei)NSWidth(viewBounds); |
GLsizei height = (GLsizei)NSHeight(viewBounds); |
// GLUT string object needs to know the view bounds have changed as well |
if( infoString ) |
{ |
[infoString release]; |
infoString = nil; |
} // if |
infoString = [[NSString alloc] initWithFormat:@"Bounds: %ld x %ld",width,height]; |
[info setViewSize:&viewBounds.size]; |
// Update the view bounds |
bounds = viewBounds; |
// Prespective matrix & the OpenGL view needs an update as well |
[self updatePrespectiveMatrix]; |
// View port has changed as well |
glViewport(0, 0, width, height); |
} // if |
} // resizeView |
//--------------------------------------------------------------------------------- |
// |
// Window resizes, moves and display changes. |
// |
//--------------------------------------------------------------------------------- |
- (void) update |
{ |
[super update]; |
} // update |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Draw Utilities |
//--------------------------------------------------------------------------------- |
- (void) drawBegin |
{ |
[[self openGLContext] makeCurrentContext]; |
[self resizeView]; |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); |
glClearColor(0.075f, 0.075f, 0.075f, 1.0f); |
glPushMatrix(); |
} // drawBegin |
//--------------------------------------------------------------------------------- |
- (void) drawEnd |
{ |
glPopMatrix(); |
[info drawString:infoString]; |
[[self openGLContext] flushBuffer]; |
} // drawEnd |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Drawing Utilities |
//--------------------------------------------------------------------------------- |
- (void) scaleModel |
{ |
glScalef(0.055f, 0.055f, 0.055f); |
// Use our display list |
glCallList(tranguloidTrefoilDL); |
} // scaleModel |
//--------------------------------------------------------------------------------- |
- (void) applyShader |
{ |
// Bind the shader |
glUseProgramObjectARB(programObject); |
// Modify offset uniform |
glUniform1fvARB(locations[kUniformOffset], 1, &offset); |
// Use our display list |
[self scaleModel]; |
// Unbind the shader |
glUseProgramObjectARB(NULL); |
} // applyShader |
//--------------------------------------------------------------------------------- |
- (void) drawModel |
{ |
[self bindPalette]; |
[self bindPattern]; |
[self applyShader]; |
[self updateOffset]; |
} // drawModel |
//--------------------------------------------------------------------------------- |
-(void) updateModel |
{ |
// Constant rotation of the subject |
[self updatePitch]; |
[self updateAngle]; |
// Draw the model |
[self drawModel]; |
} // updateModel |
//--------------------------------------------------------------------------------- |
- (void) drawRect:(NSRect)theRect |
{ |
[self drawBegin]; |
[self updateModel]; |
[self drawEnd]; |
} // drawRect |
//--------------------------------------------------------------------------------- |
#pragma mark - |
#pragma mark Handling mouse events |
//--------------------------------------------------------------------------------- |
- (void)mouseDown:(NSEvent *)theEvent |
{ |
lastMousePoint = [self convertPoint:[theEvent locationInWindow] |
fromView:nil]; |
leftMouseIsDown = YES; |
} // mouseDown |
//--------------------------------------------------------------------------------- |
- (void)rightMouseDown:(NSEvent *)theEvent |
{ |
lastMousePoint = [self convertPoint:[theEvent locationInWindow] |
fromView:nil]; |
rightMouseIsDown = YES; |
} // rightMouseDown |
//--------------------------------------------------------------------------------- |
- (void)mouseUp:(NSEvent *)theEvent |
{ |
leftMouseIsDown = NO; |
} // mouseUp |
//--------------------------------------------------------------------------------- |
- (void)rightMouseUp:(NSEvent *)theEvent |
{ |
rightMouseIsDown = NO; |
} // rightMouseUp |
//--------------------------------------------------------------------------------- |
- (void)mouseDragged:(NSEvent *)theEvent |
{ |
if( [theEvent modifierFlags] & NSRightMouseDown ) |
{ |
[self rightMouseDragged:theEvent]; |
} // if |
else |
{ |
NSPoint mouse = [self convertPoint:[theEvent locationInWindow] |
fromView:nil]; |
pitch += lastMousePoint.y - mouse.y; |
angle -= lastMousePoint.x - mouse.x; |
lastMousePoint = mouse; |
[self setNeedsDisplay:YES]; |
} // else |
} // mouseDragged |
//--------------------------------------------------------------------------------- |
- (void)rightMouseDragged:(NSEvent *)theEvent |
{ |
NSPoint mouse = [self convertPoint:[theEvent locationInWindow] |
fromView:nil]; |
zoom += 0.01f * (lastMousePoint.y - mouse.y); |
if( zoom < 0.05f ) |
{ |
zoom = 0.05f; |
} // if |
else if( zoom > 2.0f ) |
{ |
zoom = 2.0f; |
} // else if |
lastMousePoint = mouse; |
[self updatePrespectiveMatrix]; |
[self setNeedsDisplay:YES]; |
} // rightMouseDragged |
//--------------------------------------------------------------------------------- |
@end |
//--------------------------------------------------------------------------------- |
//--------------------------------------------------------------------------------- |
Copyright © 2008 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2008-07-30