Advertisement
Guest User

Untitled

a guest
Jul 22nd, 2017
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.      File: PaintingView.m
  3.  Abstract: The class responsible for the finger painting. The class wraps the
  4.  CAEAGLLayer from CoreAnimation into a convenient UIView subclass. The view
  5.  content is basically an EAGL surface you render your OpenGL scene into.
  6.   Version: 1.11
  7.  
  8.  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
  9.  Inc. ("Apple") in consideration of your agreement to the following
  10.  terms, and your use, installation, modification or redistribution of
  11.  this Apple software constitutes acceptance of these terms.  If you do
  12.  not agree with these terms, please do not use, install, modify or
  13.  redistribute this Apple software.
  14.  
  15.  In consideration of your agreement to abide by the following terms, and
  16.  subject to these terms, Apple grants you a personal, non-exclusive
  17.  license, under Apple's copyrights in this original Apple software (the
  18.  "Apple Software"), to use, reproduce, modify and redistribute the Apple
  19.  Software, with or without modifications, in source and/or binary forms;
  20.  provided that if you redistribute the Apple Software in its entirety and
  21.  without modifications, you must retain this notice and the following
  22.  text and disclaimers in all such redistributions of the Apple Software.
  23.  Neither the name, trademarks, service marks or logos of Apple Inc. may
  24.  be used to endorse or promote products derived from the Apple Software
  25.  without specific prior written permission from Apple.  Except as
  26.  expressly stated in this notice, no other rights or licenses, express or
  27.  implied, are granted by Apple herein, including but not limited to any
  28.  patent rights that may be infringed by your derivative works or by other
  29.  works in which the Apple Software may be incorporated.
  30.  
  31.  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
  32.  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
  33.  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
  34.  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
  35.  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
  36.  
  37.  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
  38.  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  39.  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  40.  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
  41.  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
  42.  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
  43.  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
  44.  POSSIBILITY OF SUCH DAMAGE.
  45.  
  46.  Copyright (C) 2010 Apple Inc. All Rights Reserved.
  47.  
  48. */
  49.  
  50. #import <QuartzCore/QuartzCore.h>
  51. #import <OpenGLES/EAGLDrawable.h>
  52.  
  53. #import "PaintingView.h"
  54.  
  55. //CLASS IMPLEMENTATIONS:
  56.  
  57. // A class extension to declare private methods
  58. @interface PaintingView (private)
  59.  
  60. - (BOOL)createFramebuffer;
  61. - (void)destroyFramebuffer;
  62.  
  63. @end
  64.  
  65. @implementation PaintingView
  66.  
  67. @synthesize  location;
  68. @synthesize  previousLocation;
  69.  
  70. // Implement this to override the default layer class (which is [CALayer class]).
  71. // We do this so that our view will be backed by a layer that is capable of OpenGL ES rendering.
  72. + (Class) layerClass
  73. {
  74.     return [CAEAGLLayer class];
  75. }
  76.  
  77. // The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
  78. - (id)initWithCoder:(NSCoder*)coder {
  79.    
  80.     NSMutableArray* recordedPaths;
  81.     CGImageRef      brushImage;
  82.     CGContextRef    brushContext;
  83.     GLubyte         *brushData;
  84.    
  85.     if ((self = [super initWithCoder:coder])) {
  86.        
  87.         brushScale = kBrushScale;
  88.        
  89.         CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
  90.        
  91.         eaglLayer.opaque = NO;
  92.         // In this application, we want to retain the EAGLDrawable contents after a call to presentRenderbuffer.
  93.         eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
  94.                                         [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
  95.        
  96.         context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
  97.        
  98.         if (!context || ![EAGLContext setCurrentContext:context]) {
  99.             [self release];
  100.             return nil;
  101.         }
  102.        
  103.         // Create a texture from an image
  104.         // First create a UIImage object from the data in a image file, and then extract the Core Graphics image
  105.         brushImage = [UIImage imageNamed:@"Particle.png"].CGImage;
  106.        
  107.         // Get the width and height of the image
  108.         width = CGImageGetWidth(brushImage);
  109.         height = CGImageGetHeight(brushImage);
  110.        
  111.         // Texture dimensions must be a power of 2. If you write an application that allows users to supply an image,
  112.         // you'll want to add code that checks the dimensions and takes appropriate action if they are not a power of 2.
  113.        
  114.         // Make sure the image exists
  115.         if(brushImage) {
  116.             // Allocate  memory needed for the bitmap context
  117.             brushData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
  118.             // Use  the bitmatp creation function provided by the Core Graphics framework.
  119.             brushContext = CGBitmapContextCreate(brushData, width, height, 8, width * 4, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast);
  120.             // After you create the context, you can draw the  image to the context.
  121.             CGContextDrawImage(brushContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), brushImage);
  122.             // You don't need the context at this point, so you need to release it to avoid memory leaks.
  123.             CGContextRelease(brushContext);
  124.             // Use OpenGL ES to generate a name for the texture.
  125.             glGenTextures(1, &brushTexture);
  126.             // Bind the texture name.
  127.             glBindTexture(GL_TEXTURE_2D, brushTexture);
  128.             // Set the texture parameters to use a minifying filter and a linear filer (weighted average)
  129.             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  130.             // Specify a 2D texture image, providing the a pointer to the image data in memory
  131.             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData);
  132.             // Release  the image data; it's no longer needed
  133.             free(brushData);
  134.         }
  135.        
  136.         // Set the view's scale factor
  137.         self.contentScaleFactor = 1.0;
  138.    
  139.         // Setup OpenGL states
  140.         glMatrixMode(GL_PROJECTION);
  141.         CGRect frame = self.bounds;
  142.         CGFloat scale = self.contentScaleFactor;
  143.         // Setup the view port in Pixels
  144.         glOrthof(0, frame.size.width * scale, 0, frame.size.height * scale, -1, 1);
  145.         glViewport(0, 0, frame.size.width * scale, frame.size.height * scale);
  146.         glMatrixMode(GL_MODELVIEW);
  147.        
  148.         glDisable(GL_DITHER);
  149.         glEnable(GL_TEXTURE_2D);
  150.         glEnableClientState(GL_VERTEX_ARRAY);
  151.        
  152.         glEnable(GL_BLEND);
  153.         // Set a blending function appropriate for premultiplied alpha pixel data
  154.         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  155.        
  156.         glEnable(GL_POINT_SPRITE_OES);
  157.         glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
  158.         glPointSize(width / brushScale);
  159.        
  160.         // Make sure to start with a cleared buffer
  161.         needsErase = YES;
  162.        
  163.         // Playback recorded path, which is "Shake Me"
  164.         //recordedPaths = [NSMutableArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Recording" ofType:@"data"]];
  165.         //if([recordedPaths count])
  166.         //  [self performSelector:@selector(playback:) withObject:recordedPaths afterDelay:0.2];
  167.        
  168.     }
  169.    
  170.     return self;
  171. }
  172.  
  173. // If our view is resized, we'll be asked to layout subviews.
  174. // This is the perfect opportunity to also update the framebuffer so that it is
  175. // the same size as our display area.
  176. -(void)layoutSubviews
  177. {
  178.     [EAGLContext setCurrentContext:context];
  179.     [self destroyFramebuffer];
  180.     [self createFramebuffer];
  181.    
  182.     // Clear the framebuffer the first time it is allocated
  183.     if (needsErase) {
  184.         [self erase];
  185.         needsErase = NO;
  186.         [self renderRect];
  187.     }
  188. }
  189.  
  190. - (BOOL)createFramebuffer
  191. {
  192.     // Generate IDs for a framebuffer object and a color renderbuffer
  193.     glGenFramebuffersOES(1, &viewFramebuffer);
  194.     glGenRenderbuffersOES(1, &viewRenderbuffer);
  195.    
  196.     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  197.     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  198.     // This call associates the storage for the current render buffer with the EAGLDrawable (our CAEAGLLayer)
  199.     // allowing us to draw into a buffer that will later be rendered to screen wherever the layer is (which corresponds with our view).
  200.     [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
  201.     glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
  202.    
  203.     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
  204.     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
  205.    
  206.     // For this sample, we also need a depth buffer, so we'll create and attach one via another renderbuffer.
  207.     glGenRenderbuffersOES(1, &depthRenderbuffer);
  208.     glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
  209.     glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
  210.     glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
  211.    
  212.     if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
  213.     {
  214.         NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
  215.         return NO;
  216.     }
  217.    
  218.     return YES;
  219. }
  220.  
  221. // Clean up any buffers we have allocated.
  222. - (void)destroyFramebuffer
  223. {
  224.     glDeleteFramebuffersOES(1, &viewFramebuffer);
  225.     viewFramebuffer = 0;
  226.     glDeleteRenderbuffersOES(1, &viewRenderbuffer);
  227.     viewRenderbuffer = 0;
  228.    
  229.     if(depthRenderbuffer)
  230.     {
  231.         glDeleteRenderbuffersOES(1, &depthRenderbuffer);
  232.         depthRenderbuffer = 0;
  233.     }
  234. }
  235.  
  236. // Releases resources when they are not longer needed.
  237. - (void) dealloc
  238. {
  239.     if (brushTexture)
  240.     {
  241.         glDeleteTextures(1, &brushTexture);
  242.         brushTexture = 0;
  243.     }
  244.    
  245.     if([EAGLContext currentContext] == context)
  246.     {
  247.         [EAGLContext setCurrentContext:nil];
  248.     }
  249.    
  250.     [context release];
  251.     [super dealloc];
  252. }
  253.  
  254. // Erases the screen
  255. - (void) erase
  256. {
  257.     [EAGLContext setCurrentContext:context];
  258.    
  259.     // Clear the buffer
  260.     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  261.     glClearColor(0.0, 0.0, 0.0, 0.0);
  262.     glClear(GL_COLOR_BUFFER_BIT);
  263.    
  264.     // Display the buffer
  265.     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  266.     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  267. }
  268.  
  269. // Drawings a line onscreen based on where the user touches
  270. - (void)renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end
  271. {
  272.     static GLfloat*     vertexBuffer = NULL;
  273.     static NSUInteger   vertexMax = 64;
  274.     NSUInteger          vertexCount = 0,
  275.                         count,
  276.                         i;
  277.    
  278.     [EAGLContext setCurrentContext:context];
  279.     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  280.    
  281.     // Convert locations from Points to Pixels
  282.     CGFloat scale = self.contentScaleFactor;
  283.     start.x *= scale;
  284.     start.y *= scale;
  285.     end.x *= scale;
  286.     end.y *= scale;
  287.    
  288.     // Allocate vertex array buffer
  289.     if(vertexBuffer == NULL)
  290.         vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));
  291.    
  292.     // Add points to the buffer so there are drawing points every X pixels
  293.     count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / kBrushPixelStep), 1);
  294.     for(i = 0; i < count; ++i) {
  295.         if(vertexCount == vertexMax) {
  296.             vertexMax = 2 * vertexMax;
  297.             vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));
  298.         }
  299.        
  300.         vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count);
  301.         vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count);
  302.         vertexCount += 1;
  303.     }
  304.    
  305.     if (isEraserBrushType) {
  306.         brushScale = 5;
  307.         glPointSize(width / brushScale);
  308.         glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
  309.         glColor4f(0, 0, 0, 0.9);
  310.     } else {
  311.         brushScale = kBrushScale;
  312.         glPointSize(width / brushScale);
  313.         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  314.         [self setBrushColorWithRed:brushColorRed green:brushColorGreen blue:brushColorBlue];
  315.     }
  316.    
  317.     // Render the vertex array
  318.     glVertexPointer(2, GL_FLOAT, 0, vertexBuffer);
  319.     glDrawArrays(GL_POINTS, 0, vertexCount);
  320.    
  321.     // Display the buffer
  322.     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  323.     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  324. }
  325.  
  326. - (void)renderRect {
  327.    
  328.     [EAGLContext setCurrentContext:context];
  329.     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
  330.    
  331.     glLoadIdentity();
  332.        
  333.     // Replace the implementation of this method to do your own custom drawing.
  334.     static const GLfloat squareVertices[] = {
  335.         -15.0f, -13.0f,//-0.5f, -0.33f,
  336.         15.0f, -13.0f,//0.5f, -0.33f,
  337.         -15.0f, 13.0f,//-0.5f,  0.33f,
  338.         15.0f, 13.0f,//0.5f,  0.33f,
  339.     };
  340.    
  341.     /*static const GLubyte squareColors[] = {
  342.         0, 0, 0, 0,
  343.         0, 0, 0, 0,
  344.         0, 0, 0, 0,
  345.         0, 0, 0, 0,
  346.     };*/
  347.    
  348.     static float transY = 0.0f;
  349.    
  350.     glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f);
  351.    
  352.    
  353.     // Render the color array
  354.     //glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
  355.     //glEnableClientState(GL_COLOR_ARRAY);
  356.    
  357.     // Render the vertex array
  358.     glVertexPointer(2, GL_FLOAT, 0, squareVertices);
  359.     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  360.  
  361.  
  362.     // Display the buffer
  363.     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
  364.     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
  365. }
  366.  
  367. /**
  368.  Draw a portion of a Texture2D at a point
  369.  @param rect a CGRect bounding the portion of the texture to draw
  370.  @param point the point to draw the texture at
  371.  
  372. -(void) drawFromRect:(CGRect)rect atPoint:(CGPoint) point {
  373.    
  374.     GLfloat  coordinates[] = {
  375.         rect.origin.x/_width,             (rect.origin.y + rect.size.height)/_width,
  376.         (rect.size.width+rect.origin.x)/_width,
  377.         (rect.origin.y + rect.size.height)/_width,
  378.         rect.origin.x/_width,       rect.origin.y/_width,
  379.         (rect.size.width+rect.origin.x)/_width,
  380.         rect.origin.y/_width  };
  381.    
  382.    
  383.     GLfloat vertices[] = { 
  384.         -rect.size.width / 2 + point.x, -rect.size.height / 2 + point.y, 0.0,
  385.         rect.size.width / 2 + point.x, -rect.size.height / 2 + point.y, 0.0,            
  386.         -rect.size.width / 2 + point.x, rect.size.height / 2 + point.y, 0.0,  
  387.         rect.size.width / 2 + point.x, rect.size.height / 2 + point.y, 0.0
  388.     };
  389.    
  390.    
  391.     glBindTexture(GL_TEXTURE_2D, _name);
  392.     glVertexPointer(3, GL_FLOAT, 0, vertices);
  393.     glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
  394.     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  395.    
  396. }*/
  397.  
  398. // Handles the start of a touch
  399. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  400. {
  401.     CGRect              bounds = [self bounds];
  402.     UITouch*    touch = [[event touchesForView:self] anyObject];
  403.     firstTouch = YES;
  404.     // Convert touch point from UIView referential to OpenGL one (upside-down flip)
  405.     location = [touch locationInView:self];
  406.     location.y = bounds.size.height - location.y;
  407. }
  408.  
  409. // Handles the continuation of a touch.
  410. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
  411. {  
  412.      
  413.     CGRect              bounds = [self bounds];
  414.     UITouch*            touch = [[event touchesForView:self] anyObject];
  415.        
  416.     // Convert touch point from UIView referential to OpenGL one (upside-down flip)
  417.     if (firstTouch) {
  418.         firstTouch = NO;
  419.         previousLocation = [touch previousLocationInView:self];
  420.         previousLocation.y = bounds.size.height - previousLocation.y;
  421.     } else {
  422.         location = [touch locationInView:self];
  423.         location.y = bounds.size.height - location.y;
  424.         previousLocation = [touch previousLocationInView:self];
  425.         previousLocation.y = bounds.size.height - previousLocation.y;
  426.     }
  427.        
  428.     // Render the stroke
  429.     [self renderLineFromPoint:previousLocation toPoint:location];
  430. }
  431.  
  432. // Handles the end of a touch event when the touch is a tap.
  433. - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
  434. {
  435.     CGRect              bounds = [self bounds];
  436.     UITouch*    touch = [[event touchesForView:self] anyObject];
  437.     if (firstTouch) {
  438.         firstTouch = NO;
  439.         previousLocation = [touch previousLocationInView:self];
  440.         previousLocation.y = bounds.size.height - previousLocation.y;
  441.         [self renderLineFromPoint:previousLocation toPoint:location];
  442.     }
  443. }
  444.  
  445. // Handles the end of a touch event.
  446. - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
  447. {
  448.     // If appropriate, add code necessary to save the state of the application.
  449.     // This application is not saving state.
  450. }
  451.  
  452. - (void)setBrushToEraser:(Boolean)value {
  453.     isEraserBrushType = value;
  454. }
  455.  
  456. - (void)setBrushColorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue
  457. {
  458.     // Set the brush color using premultiplied alpha values
  459.     brushColorRed = red;
  460.     brushColorGreen = green;
  461.     brushColorBlue = blue;
  462.    
  463.     glColor4f(red   * kBrushOpacity,
  464.               green * kBrushOpacity,
  465.               blue  * kBrushOpacity,
  466.               kBrushOpacity);
  467. }
  468.  
  469. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement