Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // EAGLView.m
- // OpenGL ES Tutorial - Part 3 by javacom
- //
- #import <QuartzCore/QuartzCore.h>
- #import <OpenGLES/EAGLDrawable.h>
- #import "EAGLView.h"
- #include <math.h>
- // Macros
- #define degreesToRadians(__ANGLE__) (M_PI * (__ANGLE__) / 180.0)
- #define radiansToDegrees(__ANGLE__) (180.0 * (__ANGLE__) / M_PI)
- CGFloat distanceBetweenPoints (CGPoint first, CGPoint second) {
- CGFloat deltaX = second.x - first.x;
- CGFloat deltaY = second.y - first.y;
- return sqrt(deltaX*deltaX + deltaY*deltaY );
- };
- CGFloat angleBetweenPoints(CGPoint first, CGPoint second) {
- // atan((top - bottom)/(right - left))
- CGFloat rads = atan((second.y - first.y) / (first.x - second.x));
- return radiansToDegrees(rads);
- }
- CGFloat angleBetweenLines(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End) {
- CGFloat a = line1End.x - line1Start.x;
- CGFloat b = line1End.y - line1Start.y;
- CGFloat c = line2End.x - line2Start.x;
- CGFloat d = line2End.y - line2Start.y;
- CGFloat rads = acos(((a*c) + (b*d)) / ((sqrt(a*a + b*b)) * (sqrt(c*c + d*d))));
- return radiansToDegrees(rads);
- }
- #define USE_DEPTH_BUFFER 0
- // CONSTANTS
- #define kMinimumTouchLength 30
- #define kMaximumScale 7.0f
- #define kMinimumPinchDelta 15
- #define kAccelerometerFrequency 100.0 // Hz
- #define kFilteringFactor 0.1
- // A class extension to declare private methods
- @interface EAGLView ()
- @property (nonatomic, retain) EAGLContext *context;
- @property (nonatomic, assign) NSTimer *animationTimer;
- - (BOOL) createFramebuffer;
- - (void) destroyFramebuffer;
- @end
- @implementation EAGLView
- @synthesize context;
- @synthesize animationTimer;
- @synthesize animationInterval;
- @synthesize squareData;
- @synthesize ellipseData;
- @synthesize initialDistance;
- #ifdef DEBUGSCREEN
- @synthesize textView;
- #endif
- // You must implement this method
- + (Class)layerClass {
- return [CAEAGLLayer class];
- }
- //The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
- - (id)initWithCoder:(NSCoder*)coder {
- if ((self = [super initWithCoder:coder])) {
- // Get the layer
- CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
- eaglLayer.opaque = YES;
- eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
- context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
- if (!context || ![EAGLContext setCurrentContext:context]) {
- [self release];
- return nil;
- }
- animationInterval = 1.0 / 60.0;
- [self setupView];
- }
- return self;
- }
- // These are four methods touchesBegan, touchesMoved, touchesEnded, touchesCancelled and use to notify about touches and gestures
- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
- /*
- NSUInteger numTaps = [[touches anyObject] tapCount]; // number of taps
- NSUInteger numTouches = [touches count]; // number of touches
- */
- UITouch *touch = [[touches allObjects] objectAtIndex:0];
- DEBUGLOG(@"TouchBegan event counts = %d ",[[event touchesForView:self] count]);
- DEBUGLOG(@"TouchBegan tounches counts = %d ",[touches count]);
- if ([touches count]== 2) {
- NSArray *twoTouches = [touches allObjects];
- UITouch *first = [twoTouches objectAtIndex:0];
- UITouch *second = [twoTouches objectAtIndex:1];
- initialDistance = distanceBetweenPoints([first locationInView:self], [second locationInView:self]);
- squareData.rotstop = YES;
- squareData.touchInside = NO;
- }
- else if ([touches count]==[[event touchesForView:self] count] & [[event touchesForView:self] count] == 1) {
- squareData.startTouchPosition = [touch locationInView:self];
- if (distanceBetweenPoints([touch locationInView:self], squareData.pos) <= kMinimumTouchLength * squareData.scale) {
- DEBUGLOG(@"Square Touch at %.2f, %.2f ",squareData.pos.x,squareData.pos.y);
- squareData.rotstop = YES;
- squareData.touchInside = YES;
- }
- }
- }
- - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
- UITouch *touch = [[touches allObjects] objectAtIndex:0];
- squareData.currentTouchPosition = [touch locationInView:self];
- if ([touches count]== 2) {
- NSArray *twoTouches = [touches allObjects];
- UITouch *first = [twoTouches objectAtIndex:0];
- UITouch *second = [twoTouches objectAtIndex:1];
- // Calculate the distance bewtween the two fingers(touches) to determine the pinch distance
- CGFloat currentDistance = distanceBetweenPoints([first locationInView:self], [second locationInView:self]);
- squareData.rotstop = YES;
- squareData.touchInside = NO;
- if (initialDistance == 0.0f)
- initialDistance = currentDistance;
- if (currentDistance - initialDistance > kMinimumPinchDelta) {
- squareData.pinchDistance = currentDistance - initialDistance;
- squareData.scalestart = YES;
- DEBUGLOG(@"Outward Pinch %.2f", squareData.pinchDistance);
- }
- else if (initialDistance - currentDistance > kMinimumPinchDelta) {
- squareData.pinchDistance = currentDistance - initialDistance;
- squareData.scalestart = YES;
- DEBUGLOG(@"Inward Pinch %.2f", squareData.pinchDistance);
- }
- }
- else if ([touches count]==[[event touchesForView:self] count] & [[event touchesForView:self] count] == 1) {
- if (squareData.touchInside) {
- // Only move the square to new position when touchBegan is inside the square
- squareData.pos.x = [touch locationInView:self].x;
- squareData.pos.y = [touch locationInView:self].y;
- DEBUGLOG(@"Square Move to %.2f, %.2f ",squareData.pos.x,squareData.pos.y);
- squareData.rotstop = YES;
- }
- }
- }
- - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
- if ([touches count] == [[event touchesForView:self] count]) {
- initialDistance = squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
- squareData.rotstop = squareData.touchInside = squareData.scalestart = NO;
- DEBUGLOG(@"touchesEnded, all fingers up");
- }
- else {
- initialDistance = squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
- squareData.scalestart = NO;
- DEBUGLOG(@"touchesEnded");
- }
- }
- - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
- initialDistance = squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
- squareData.rotstop = squareData.touchInside = squareData.scalestart = NO;
- DEBUGLOG(@"touchesCancelled");
- }
- - (void)setupView { // new method for intialisation of variables and states
- // Enable Multi Touch of the view
- self.multipleTouchEnabled = YES;
- //Configure and start accelerometer
- [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kAccelerometerFrequency)];
- [[UIAccelerometer sharedAccelerometer] setDelegate:self];
- #if TARGET_IPHONE_SIMULATOR
- moveX = 2.0f;
- moveY = 3.0f;
- #else
- moveX = 0.0f;
- moveY = 0.0f;
- #endif
- #ifdef DEBUGSCREEN
- UIColor *bgColor = [[UIColor alloc] initWithWhite:1.0f alpha:0.0f];
- textView = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 350.0f, 300.0f, 96.0f)];
- textView.text = [NSString stringWithFormat:@"-Accelerometer Data-"];
- textView.textAlignment = UITextAlignmentLeft;
- [textView setNumberOfLines:4];
- textView.backgroundColor = bgColor;
- textView.font = [UIFont fontWithName:@"Arial" size:18];
- [self addSubview:textView];
- [self bringSubviewToFront:textView];
- #endif
- // Initialise square data
- squareData.rotation = squareData.pinchDistance = squareData.pinchDistanceShown = 0.0f;
- ellipseData.rotation = 0.0f;
- squareData.scale = 1.0f;
- squareData.rotstop = squareData.touchInside = squareData.scalestart = NO;
- squareData.pos.x = 160.0f;
- squareData.pos.y = 240.0f;
- squareData.pinchDistance = 0.0f;
- squareData.rotspeed = 1.0f;
- // Initialise ellipse data
- ellipseData.rotation = 0.0f;
- ellipseData.rotstop = ellipseData.touchInside = ellipseData.scalestart = NO;
- ellipseData.pos.x = 160.0f;
- ellipseData.pos.y = 100.0f;
- ellipseData.rotspeed = -4.0f;
- // calculate the vertices of ellipse
- const GLfloat xradius = 35.0f;
- const GLfloat yradius = 25.0f;
- for (int i = 0; i < 720; i+=2) {
- ellipseVertices[i] = (cos(degreesToRadians(i)) * xradius) + 0.0f;
- ellipseVertices[i+1] = (sin(degreesToRadians(i)) * yradius) + 0.0f;
- // DEBUGLOG(@"ellipseVertices[v%d] %.1f, %.1f",i, ellipseVertices[i], ellipseVertices[i+1]);
- }
- // setup the projection matrix
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- // Setup Orthographic Projection for the 320 x 480 of the iPhone screen
- glOrthof(0.0f, 320.0f, 480.0f, 0.0f, -1.0f, 1.0f);
- glMatrixMode(GL_MODELVIEW);
- }
- - (void)drawView {
- // Define the square vertices
- const GLfloat squareVertices[] = {
- -20.0f, -20.0f,
- 20.0f, -20.0f,
- -20.0f, 20.0f,
- 20.0f, 20.0f,
- };
- // Define the colors of the square vertices
- const GLubyte squareColors[] = {
- 255, 255, 0, 255,
- 0, 255, 255, 255,
- 0, 0, 0, 0,
- 255, 0, 255, 255,
- };
- // Define the colors of the ellipse vertices
- const GLubyte ellipseColors[] = {
- 233, 85, 85, 255,
- 233, 85, 85, 255,
- 233, 85, 85, 255,
- 233, 85, 85, 255,
- 233, 85, 85, 255,
- };
- [EAGLContext setCurrentContext:context];
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
- glViewport(0, 0, backingWidth, backingHeight);
- // Clear background color
- glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- // draw the square
- glLoadIdentity();
- glTranslatef(squareData.pos.x, squareData.pos.y, 0.0f);
- glRotatef(squareData.rotation, 0.0f, 0.0f, 1.0f);
- glScalef(squareData.scale, squareData.scale, 1.0f);
- glVertexPointer(2, GL_FLOAT, 0, squareVertices);
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- // draw the ellipse
- glLoadIdentity();
- glTranslatef(ellipseData.pos.x, ellipseData.pos.y, 0.0f);
- glRotatef(ellipseData.rotation, 0.0f, 0.0f, 1.0f);
- glVertexPointer(2, GL_FLOAT, 0, ellipseVertices);
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, ellipseColors);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 360); // the ellipse has 360 vertices
- // control the square rotation
- if (!squareData.rotstop) {
- squareData.rotation += squareData.rotspeed;
- if(squareData.rotation > 360.0f)
- squareData.rotation -= 360.0f;
- else if(squareData.rotation < -360.0f)
- squareData.rotation += 360.0f;
- }
- // control the ellipse rotation
- if (!ellipseData.rotstop) {
- ellipseData.rotation += ellipseData.rotspeed;
- if(ellipseData.rotation > 360.0f)
- ellipseData.rotation -= 360.0f;
- else if(ellipseData.rotation < -360.0f)
- ellipseData.rotation += 360.0f;
- }
- // control the square scaling
- if (squareData.scalestart && squareData.scale <= kMaximumScale) {
- GLfloat pinchDelta = squareData.pinchDistance - squareData.pinchDistanceShown;
- if (squareData.pinchDistance != 0.0f) {
- squareData.scale += pinchDelta/30;
- squareData.pinchDistanceShown = squareData.pinchDistance;
- if (squareData.scale >= kMaximumScale) {
- squareData.scale = kMaximumScale;
- squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
- squareData.scalestart = NO;
- } else if (squareData.scale <= 1.0f) {
- squareData.scale = 1.0f;
- squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
- squareData.scalestart = NO;
- }
- DEBUGLOG(@"scale is %.2f",squareData.scale);
- }
- }
- // control the ellipse movement
- #if TARGET_IPHONE_SIMULATOR
- ellipseData.pos.x += moveX;
- if (ellipseData.pos.x >= 290.f) {
- moveX = -2.0f;
- }
- else if (ellipseData.pos.x <= 30.f) {
- moveX = 2.0f;
- }
- ellipseData.pos.y += moveY;
- if (ellipseData.pos.y >= 450.f) {
- moveY = -1.5f;
- }
- else if (ellipseData.pos.y <= 55.f) {
- moveY = 3.5f;
- }
- #else
- ellipseData.pos.x += moveX;
- if (accel[0] > -0.1 & accel[0] < 0.1 ) {
- moveX = 0.0f;
- }
- else {
- moveX = 10.0f * accel[0];
- }
- ellipseData.pos.y += moveY;
- if (accel[1] > -0.1 & accel[1] < 0.1 ) {
- moveY = 0.0f;
- }
- else {
- moveY = -10.0f * accel[1];
- }
- #endif
- if (ellipseData.pos.x >= 290.f) {
- ellipseData.pos.x = 290.0f;
- }
- else if (ellipseData.pos.x <= 30.f) {
- ellipseData.pos.x = 30.0f;
- }
- if (ellipseData.pos.y >= 450.f) {
- ellipseData.pos.y = 450.0f;
- }
- else if (ellipseData.pos.y <= 55.f) {
- ellipseData.pos.y = 55.0f;
- }
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
- [context presentRenderbuffer:GL_RENDERBUFFER_OES];
- }
- - (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
- {
- /*
- The meaning of acceleration values for firmware 2.x
- acceleration.x = Roll. It corresponds to roll, or rotation around the axis that runs from your home button to your earpiece.
- Values vary from 1.0 (rolled all the way to the right) to -1.0 (rolled all the way to the left).
- acceleration.y = Pitch. Place your iPhone on the table and mentally draw a horizontal line about half-way down the screen.
- That's the axis around which the Y value rotates.
- Values go from 1.0 (the headphone jack straight down) to -1.0 (the headphone jack straight up).
- acceleration.z = Face up/face down.
- It refers to whether your iPhone is face up (-1.0) or face down (1.0).
- When placed on it side, either the side with the volume controls and ringer switch, or the side directly opposite
- , the Z value equates to 0.0.
- */
- //Use a basic low-pass filter in the accelerometer values
- accel[0] = acceleration.x * kFilteringFactor + accel[0] * (1.0 - kFilteringFactor);
- accel[1] = acceleration.y * kFilteringFactor + accel[1] * (1.0 - kFilteringFactor);
- accel[2] = acceleration.z * kFilteringFactor + accel[2] * (1.0 - kFilteringFactor);
- #ifdef DEBUGSCREEN
- textView.text = [NSString stringWithFormat:
- @"X (roll, %4.1f%%): %f\nY (pitch %4.1f%%): %f\nZ (%4.1f%%) : %f",
- 100.0 - (accel[0] + 1.0) * 50.0, accel[0],
- 100.0 - (accel[1] + 1.0) * 50.0, accel[1],
- 100.0 - (accel[2] + 1.0) * 50.0, accel[2]
- ];
- #endif
- }
- - (void)layoutSubviews {
- [EAGLContext setCurrentContext:context];
- [self destroyFramebuffer];
- [self createFramebuffer];
- [self drawView];
- }
- - (BOOL)createFramebuffer {
- glGenFramebuffersOES(1, &viewFramebuffer);
- glGenRenderbuffersOES(1, &viewRenderbuffer);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
- [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
- if (USE_DEPTH_BUFFER) {
- glGenRenderbuffersOES(1, &depthRenderbuffer);
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
- glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
- }
- if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
- DEBUGLOG(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
- return NO;
- }
- return YES;
- }
- - (void)destroyFramebuffer {
- glDeleteFramebuffersOES(1, &viewFramebuffer);
- viewFramebuffer = 0;
- glDeleteRenderbuffersOES(1, &viewRenderbuffer);
- viewRenderbuffer = 0;
- if(depthRenderbuffer) {
- glDeleteRenderbuffersOES(1, &depthRenderbuffer);
- depthRenderbuffer = 0;
- }
- }
- - (void)startAnimation {
- self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
- }
- - (void)stopAnimation {
- self.animationTimer = nil;
- }
- - (void)setAnimationTimer:(NSTimer *)newTimer {
- [animationTimer invalidate];
- animationTimer = newTimer;
- }
- - (void)setAnimationInterval:(NSTimeInterval)interval {
- animationInterval = interval;
- if (animationTimer) {
- [self stopAnimation];
- [self startAnimation];
- }
- }
- - (void)dealloc {
- [self stopAnimation];
- if ([EAGLContext currentContext] == context) {
- [EAGLContext setCurrentContext:nil];
- }
- [context release];
- [super dealloc];
- }
- @end
Add Comment
Please, Sign In to add comment