Guest User

Untitled

a guest
May 21st, 2018
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. //  EAGLView.m
  3. //  OpenGL ES Tutorial - Part 3 by javacom
  4. //
  5. #import <QuartzCore/QuartzCore.h>
  6. #import <OpenGLES/EAGLDrawable.h>
  7.  
  8. #import "EAGLView.h"
  9.  
  10. #include <math.h>
  11.  
  12. // Macros
  13. #define degreesToRadians(__ANGLE__) (M_PI * (__ANGLE__) / 180.0)
  14. #define radiansToDegrees(__ANGLE__) (180.0 * (__ANGLE__) / M_PI)
  15.  
  16. CGFloat distanceBetweenPoints (CGPoint first, CGPoint second) {
  17.  CGFloat deltaX = second.x - first.x;
  18.  CGFloat deltaY = second.y - first.y;
  19.  return sqrt(deltaX*deltaX + deltaY*deltaY );
  20. };
  21.  
  22. CGFloat angleBetweenPoints(CGPoint first, CGPoint second) {
  23.  // atan((top - bottom)/(right - left))
  24.  CGFloat rads = atan((second.y - first.y) / (first.x - second.x));
  25.  return radiansToDegrees(rads);
  26. }
  27.  
  28. CGFloat angleBetweenLines(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End) {
  29.  
  30.  CGFloat a = line1End.x - line1Start.x;
  31.  CGFloat b = line1End.y - line1Start.y;
  32.  CGFloat c = line2End.x - line2Start.x;
  33.  CGFloat d = line2End.y - line2Start.y;
  34.  
  35.  CGFloat rads = acos(((a*c) + (b*d)) / ((sqrt(a*a + b*b)) * (sqrt(c*c + d*d))));
  36.  
  37.  return radiansToDegrees(rads);
  38. }
  39.  
  40. #define USE_DEPTH_BUFFER 0
  41.  
  42. // CONSTANTS
  43. #define kMinimumTouchLength 30
  44. #define kMaximumScale 7.0f
  45. #define kMinimumPinchDelta 15
  46. #define kAccelerometerFrequency  100.0 // Hz
  47. #define kFilteringFactor   0.1
  48.  
  49.  
  50. // A class extension to declare private methods
  51. @interface EAGLView ()
  52.  
  53. @property (nonatomic, retain) EAGLContext *context;
  54. @property (nonatomic, assign) NSTimer *animationTimer;
  55.  
  56. - (BOOL) createFramebuffer;
  57. - (void) destroyFramebuffer;
  58.  
  59. @end
  60.  
  61.  
  62. @implementation EAGLView
  63.  
  64. @synthesize context;
  65. @synthesize animationTimer;
  66. @synthesize animationInterval;
  67. @synthesize squareData;
  68. @synthesize ellipseData;
  69. @synthesize initialDistance;
  70. #ifdef DEBUGSCREEN
  71. @synthesize textView;
  72. #endif
  73.  
  74. // You must implement this method
  75. + (Class)layerClass {
  76.     return [CAEAGLLayer class];
  77. }
  78.  
  79.  
  80. //The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
  81. - (id)initWithCoder:(NSCoder*)coder {
  82.    
  83.     if ((self = [super initWithCoder:coder])) {
  84.  
  85.         // Get the layer
  86.         CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
  87.        
  88.         eaglLayer.opaque = YES;
  89.         eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
  90.                                         [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
  91.        
  92.         context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
  93.        
  94.         if (!context || ![EAGLContext setCurrentContext:context]) {
  95.             [self release];
  96.             return nil;
  97.         }
  98.        
  99.         animationInterval = 1.0 / 60.0;
  100.   [self setupView];
  101.     }
  102.     return self;
  103. }
  104.  
  105. // These are four methods touchesBegan, touchesMoved, touchesEnded, touchesCancelled and use to notify about touches and gestures
  106.  
  107. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
  108.  /*
  109.   NSUInteger numTaps = [[touches anyObject] tapCount];  // number of taps
  110.   NSUInteger numTouches = [touches count];              // number of touches
  111.   */
  112.  UITouch *touch = [[touches allObjects] objectAtIndex:0];
  113.  
  114.  DEBUGLOG(@"TouchBegan event counts = %d ",[[event touchesForView:self] count]);
  115.  DEBUGLOG(@"TouchBegan tounches counts = %d ",[touches count]);
  116.  if ([touches count]== 2) {
  117.   NSArray *twoTouches = [touches allObjects];
  118.   UITouch *first = [twoTouches objectAtIndex:0];
  119.   UITouch *second = [twoTouches objectAtIndex:1];
  120.   initialDistance = distanceBetweenPoints([first locationInView:self], [second locationInView:self]);  
  121.   squareData.rotstop = YES;
  122.   squareData.touchInside = NO;
  123.  }
  124.  else if ([touches count]==[[event touchesForView:self] count] & [[event touchesForView:self] count] == 1) {
  125.   squareData.startTouchPosition = [touch locationInView:self];
  126.   if (distanceBetweenPoints([touch locationInView:self], squareData.pos) <= kMinimumTouchLength * squareData.scale) {
  127.    DEBUGLOG(@"Square Touch at %.2f, %.2f ",squareData.pos.x,squareData.pos.y);
  128.    squareData.rotstop = YES;
  129.    squareData.touchInside = YES;
  130.   }
  131.  }
  132.  
  133. }
  134.  
  135. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  136.  UITouch *touch = [[touches allObjects] objectAtIndex:0];
  137.  squareData.currentTouchPosition = [touch locationInView:self];
  138.  if ([touches count]== 2) {
  139.   NSArray *twoTouches = [touches allObjects];
  140.   UITouch *first = [twoTouches objectAtIndex:0];
  141.   UITouch *second = [twoTouches objectAtIndex:1];
  142.  
  143.   // Calculate the distance bewtween the two fingers(touches) to determine the pinch distance
  144.   CGFloat currentDistance = distanceBetweenPoints([first locationInView:self], [second locationInView:self]);
  145.  
  146.   squareData.rotstop = YES;
  147.   squareData.touchInside = NO;
  148.  
  149.   if (initialDistance == 0.0f)
  150.    initialDistance = currentDistance;
  151.   if (currentDistance - initialDistance > kMinimumPinchDelta) {
  152.    squareData.pinchDistance = currentDistance - initialDistance;
  153.    squareData.scalestart = YES;
  154.    DEBUGLOG(@"Outward Pinch %.2f", squareData.pinchDistance);
  155.   }
  156.   else if (initialDistance - currentDistance > kMinimumPinchDelta) {
  157.    squareData.pinchDistance = currentDistance - initialDistance;
  158.    squareData.scalestart = YES;
  159.    DEBUGLOG(@"Inward Pinch %.2f", squareData.pinchDistance);
  160.   }
  161.  }
  162.  else if ([touches count]==[[event touchesForView:self] count] & [[event touchesForView:self] count] == 1) {
  163.   if (squareData.touchInside) {
  164.    // Only move the square to new position when touchBegan is inside the square
  165.    squareData.pos.x = [touch locationInView:self].x;
  166.    squareData.pos.y = [touch locationInView:self].y;
  167.    DEBUGLOG(@"Square Move to %.2f, %.2f ",squareData.pos.x,squareData.pos.y);
  168.    squareData.rotstop = YES;
  169.   }
  170.  }
  171. }
  172.  
  173.  
  174. - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  175.  if ([touches count] == [[event touchesForView:self] count]) {
  176.   initialDistance = squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
  177.   squareData.rotstop = squareData.touchInside = squareData.scalestart = NO;
  178.   DEBUGLOG(@"touchesEnded, all fingers up");
  179.  }
  180.  else {
  181.   initialDistance = squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
  182.   squareData.scalestart = NO;
  183.   DEBUGLOG(@"touchesEnded");
  184.  }
  185. }
  186.  
  187.  
  188. - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
  189.  initialDistance = squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
  190.  squareData.rotstop = squareData.touchInside = squareData.scalestart = NO;
  191.  DEBUGLOG(@"touchesCancelled");
  192. }
  193.  
  194. - (void)setupView {  // new method for intialisation of variables and states
  195.  
  196.  // Enable Multi Touch of the view
  197.  self.multipleTouchEnabled = YES;
  198.  
  199.  //Configure and start accelerometer
  200.  [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kAccelerometerFrequency)];
  201.  [[UIAccelerometer sharedAccelerometer] setDelegate:self];
  202. #if TARGET_IPHONE_SIMULATOR
  203.  moveX = 2.0f;
  204.  moveY = 3.0f;
  205. #else
  206.  moveX = 0.0f;
  207.  moveY = 0.0f;
  208. #endif
  209.  
  210. #ifdef DEBUGSCREEN
  211.  UIColor *bgColor = [[UIColor alloc] initWithWhite:1.0f alpha:0.0f];
  212.  textView = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 350.0f, 300.0f, 96.0f)];
  213.  textView.text = [NSString stringWithFormat:@"-Accelerometer Data-"];
  214.  textView.textAlignment = UITextAlignmentLeft;
  215.  [textView setNumberOfLines:4];
  216.  textView.backgroundColor = bgColor;
  217.  textView.font = [UIFont fontWithName:@"Arial" size:18];
  218.  [self addSubview:textView];
  219.  [self bringSubviewToFront:textView];
  220. #endif
  221.  
  222.  
  223.  // Initialise square data
  224.  squareData.rotation = squareData.pinchDistance = squareData.pinchDistanceShown = 0.0f;
  225.  ellipseData.rotation = 0.0f;
  226.  squareData.scale = 1.0f;
  227.  squareData.rotstop = squareData.touchInside = squareData.scalestart = NO;
  228.  squareData.pos.x = 160.0f;
  229.  squareData.pos.y = 240.0f;
  230.  squareData.pinchDistance = 0.0f;
  231.  squareData.rotspeed = 1.0f;
  232.  
  233.  // Initialise ellipse data
  234.  ellipseData.rotation = 0.0f;
  235.  ellipseData.rotstop = ellipseData.touchInside = ellipseData.scalestart = NO;
  236.  ellipseData.pos.x = 160.0f;
  237.  ellipseData.pos.y = 100.0f;
  238.  ellipseData.rotspeed = -4.0f;
  239.  
  240.  // calculate the vertices of ellipse
  241.  const GLfloat xradius = 35.0f;
  242.  const GLfloat yradius = 25.0f;
  243.  for (int i = 0; i < 720; i+=2) {
  244.   ellipseVertices[i] = (cos(degreesToRadians(i)) * xradius) + 0.0f;
  245.   ellipseVertices[i+1] = (sin(degreesToRadians(i)) * yradius) + 0.0f;
  246. //  DEBUGLOG(@"ellipseVertices[v%d] %.1f, %.1f",i, ellipseVertices[i], ellipseVertices[i+1]);
  247.  }
  248.  
  249.  // setup the projection matrix
  250.  glMatrixMode(GL_PROJECTION);
  251.  glLoadIdentity();
  252.  
  253.  // Setup Orthographic Projection for the 320 x 480 of the iPhone screen
  254.  glOrthof(0.0f, 320.0f, 480.0f, 0.0f, -1.0f, 1.0f);
  255.  glMatrixMode(GL_MODELVIEW);
  256.  
  257. }
  258.  
  259. - (void)drawView {
  260.    
  261.     // Define the square vertices
  262.  const GLfloat squareVertices[] = {
  263.         -20.0f, -20.0f,
  264.         20.0f,  -20.0f,
  265.         -20.0f,  20.0f,
  266.         20.0f,   20.0f,
  267.     };
  268.  
  269.     // Define the colors of the square vertices
  270.  const GLubyte squareColors[] = {
  271.         255, 255,   0, 255,
  272.         0,   255, 255, 255,
  273.         0,     0,   0,   0,
  274.         255,   0, 255, 255,
  275.     };
  276.  
  277.  
  278.  // Define the colors of the ellipse vertices
  279.  const GLubyte ellipseColors[] = {
  280.         233,  85,   85, 255,
  281.         233,  85,   85, 255,
  282.         233,  85,   85, 255,
  283.         233,  85,   85, 255,
  284.         233,  85,   85, 255,
  285.     };
  286.  
  287.  
  288.     [EAGLContext setCurrentContext:context];
  289.     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  290.     glViewport(0, 0, backingWidth, backingHeight);
  291.    
  292.  // Clear background color
  293.     glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
  294.     glClear(GL_COLOR_BUFFER_BIT);
  295.  
  296.  // draw the square
  297.  glLoadIdentity();
  298.  glTranslatef(squareData.pos.x, squareData.pos.y, 0.0f);
  299.  glRotatef(squareData.rotation, 0.0f, 0.0f, 1.0f);
  300.  glScalef(squareData.scale, squareData.scale, 1.0f);
  301.  glVertexPointer(2, GL_FLOAT, 0, squareVertices);
  302.  glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
  303.  glEnableClientState(GL_VERTEX_ARRAY);
  304.  glEnableClientState(GL_COLOR_ARRAY);
  305.  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  306.  
  307.  // draw the ellipse
  308.  glLoadIdentity();
  309.  glTranslatef(ellipseData.pos.x, ellipseData.pos.y, 0.0f);
  310.  glRotatef(ellipseData.rotation, 0.0f, 0.0f, 1.0f);
  311.  glVertexPointer(2, GL_FLOAT, 0, ellipseVertices);
  312.  glColorPointer(4, GL_UNSIGNED_BYTE, 0, ellipseColors);
  313.  glEnableClientState(GL_VERTEX_ARRAY);
  314.  glEnableClientState(GL_COLOR_ARRAY);
  315.  glDrawArrays(GL_TRIANGLE_FAN, 0, 360);  // the ellipse has 360 vertices
  316.  
  317.  // control the square rotation
  318.  if (!squareData.rotstop) {
  319.   squareData.rotation += squareData.rotspeed;
  320.   if(squareData.rotation > 360.0f)
  321.    squareData.rotation -= 360.0f;
  322.   else if(squareData.rotation < -360.0f)
  323.    squareData.rotation += 360.0f;
  324.     }
  325.  
  326.  // control the ellipse rotation
  327.  if (!ellipseData.rotstop) {
  328.   ellipseData.rotation += ellipseData.rotspeed;
  329.   if(ellipseData.rotation > 360.0f)
  330.    ellipseData.rotation -= 360.0f;
  331.   else if(ellipseData.rotation < -360.0f)
  332.    ellipseData.rotation += 360.0f;
  333.  }
  334.  
  335.  // control the square scaling
  336.  if (squareData.scalestart && squareData.scale <= kMaximumScale) {
  337.   GLfloat pinchDelta = squareData.pinchDistance - squareData.pinchDistanceShown;
  338.   if (squareData.pinchDistance != 0.0f) {
  339.    squareData.scale += pinchDelta/30;
  340.    squareData.pinchDistanceShown = squareData.pinchDistance;
  341.    if (squareData.scale >= kMaximumScale) {
  342.     squareData.scale = kMaximumScale;
  343.     squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
  344.     squareData.scalestart = NO;
  345.    } else if (squareData.scale <= 1.0f) {
  346.     squareData.scale = 1.0f;
  347.     squareData.pinchDistanceShown = squareData.pinchDistance = 0.0f;
  348.     squareData.scalestart = NO;
  349.    }
  350.    DEBUGLOG(@"scale is %.2f",squareData.scale);
  351.   }
  352.  }
  353.  
  354.  // control the ellipse movement
  355. #if TARGET_IPHONE_SIMULATOR
  356.  ellipseData.pos.x += moveX;
  357.  if (ellipseData.pos.x >= 290.f) {
  358.   moveX = -2.0f;
  359.  }
  360.  else if (ellipseData.pos.x <= 30.f) {
  361.   moveX = 2.0f;
  362.  }
  363.  
  364.  ellipseData.pos.y += moveY;
  365.  if (ellipseData.pos.y >= 450.f) {
  366.   moveY = -1.5f;
  367.  }
  368.  else if (ellipseData.pos.y <= 55.f) {
  369.   moveY = 3.5f;
  370.  }
  371. #else
  372.  ellipseData.pos.x += moveX;
  373.  if (accel[0] > -0.1 & accel[0] < 0.1 ) {
  374.    moveX = 0.0f;
  375.  }
  376.  else {
  377.   moveX = 10.0f * accel[0];
  378.  }
  379.  
  380.  ellipseData.pos.y += moveY;
  381.  if (accel[1] > -0.1 & accel[1] < 0.1 ) {
  382.    moveY = 0.0f;
  383.  }
  384.  else {
  385.   moveY = -10.0f * accel[1];
  386.  }
  387. #endif
  388.  if (ellipseData.pos.x >= 290.f) {
  389.   ellipseData.pos.x = 290.0f;
  390.  }
  391.  else if (ellipseData.pos.x <= 30.f) {
  392.   ellipseData.pos.x = 30.0f;
  393.  }
  394.  if (ellipseData.pos.y >= 450.f) {
  395.   ellipseData.pos.y = 450.0f;
  396.  }
  397.  else if (ellipseData.pos.y <= 55.f) {
  398.   ellipseData.pos.y = 55.0f;
  399.  }
  400.  
  401.  
  402.     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  403.     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  404. }
  405.  
  406. - (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
  407. {
  408.  /*
  409.   The meaning of acceleration values for firmware 2.x
  410.   acceleration.x = Roll.  It corresponds to roll, or rotation around the axis that runs from your home button to your earpiece.
  411.   Values vary from 1.0 (rolled all the way to the right) to -1.0 (rolled all the way to the left).
  412.  
  413.   acceleration.y = Pitch. Place your iPhone on the table and mentally draw a horizontal line about half-way down the screen.
  414.   That's the axis around which the Y value rotates.
  415.   Values go from 1.0 (the headphone jack straight down) to -1.0 (the headphone jack straight up).
  416.  
  417.   acceleration.z = Face up/face down.
  418.   It refers to whether your iPhone is face up (-1.0) or face down (1.0).
  419.   When placed on it side, either the side with the volume controls and ringer switch, or the side directly opposite
  420.   , the Z value equates to 0.0.
  421.   */
  422.  
  423.  //Use a basic low-pass filter in the accelerometer values
  424.  accel[0] = acceleration.x * kFilteringFactor + accel[0] * (1.0 - kFilteringFactor);
  425.  accel[1] = acceleration.y * kFilteringFactor + accel[1] * (1.0 - kFilteringFactor);
  426.  accel[2] = acceleration.z * kFilteringFactor + accel[2] * (1.0 - kFilteringFactor);
  427.  
  428. #ifdef DEBUGSCREEN
  429.  textView.text = [NSString stringWithFormat:
  430.        @"X (roll, %4.1f%%): %f\nY (pitch %4.1f%%): %f\nZ (%4.1f%%) : %f",
  431.        100.0 - (accel[0] + 1.0) * 50.0, accel[0],
  432.        100.0 - (accel[1] + 1.0) * 50.0, accel[1],
  433.        100.0 - (accel[2] + 1.0) * 50.0, accel[2]
  434.        ];
  435. #endif
  436. }
  437.  
  438. - (void)layoutSubviews {
  439.     [EAGLContext setCurrentContext:context];
  440.     [self destroyFramebuffer];
  441.     [self createFramebuffer];
  442.     [self drawView];
  443. }
  444.  
  445.  
  446. - (BOOL)createFramebuffer {
  447.    
  448.     glGenFramebuffersOES(1, &viewFramebuffer);
  449.     glGenRenderbuffersOES(1, &viewRenderbuffer);
  450.    
  451.     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  452.     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  453.     [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
  454.     glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
  455.    
  456.     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
  457.     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
  458.    
  459.     if (USE_DEPTH_BUFFER) {
  460.         glGenRenderbuffersOES(1, &depthRenderbuffer);
  461.         glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
  462.         glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
  463.         glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
  464.     }
  465.    
  466.     if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
  467.         DEBUGLOG(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
  468.         return NO;
  469.     }
  470.    
  471.     return YES;
  472. }
  473.  
  474.  
  475. - (void)destroyFramebuffer {
  476.    
  477.     glDeleteFramebuffersOES(1, &viewFramebuffer);
  478.     viewFramebuffer = 0;
  479.     glDeleteRenderbuffersOES(1, &viewRenderbuffer);
  480.     viewRenderbuffer = 0;
  481.    
  482.     if(depthRenderbuffer) {
  483.         glDeleteRenderbuffersOES(1, &depthRenderbuffer);
  484.         depthRenderbuffer = 0;
  485.     }
  486. }
  487.  
  488.  
  489. - (void)startAnimation {
  490.     self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
  491. }
  492.  
  493.  
  494. - (void)stopAnimation {
  495.     self.animationTimer = nil;
  496. }
  497.  
  498.  
  499. - (void)setAnimationTimer:(NSTimer *)newTimer {
  500.     [animationTimer invalidate];
  501.     animationTimer = newTimer;
  502. }
  503.  
  504.  
  505. - (void)setAnimationInterval:(NSTimeInterval)interval {
  506.    
  507.     animationInterval = interval;
  508.     if (animationTimer) {
  509.         [self stopAnimation];
  510.         [self startAnimation];
  511.     }
  512. }
  513.  
  514.  
  515. - (void)dealloc {
  516.    
  517.     [self stopAnimation];
  518.    
  519.     if ([EAGLContext currentContext] == context) {
  520.         [EAGLContext setCurrentContext:nil];
  521.     }
  522.    
  523.     [context release];  
  524.     [super dealloc];
  525. }
  526.  
  527. @end
Add Comment
Please, Sign In to add comment