Note that there are some explanatory texts on larger screens.

plurals
  1. PORecord the drawing as a m4v video file - OpenGL
    primarykey
    data
    text
    <p>I have downloaded the sample code GLPaint from developer.Apple website to draw pictures on a Canvas using OpenGL.</p> <p>I have done the changes in GLPaint application to meet my requirements.</p> <p>Now I need to record the drawing as a m4v video file that should integrated my spoken instructions which I spoken while drawing the image.</p> <p>Eg:</p> <ul> <li><p>After I clicked on Draw and Record button, I started drawing a circle and spoken "This is a circle".</p></li> <li><p>After I clicked the Done button, the result should be a video file that include the Drawing actions with the voice "This is a circle"</p></li> </ul> <p>I researched on this topic but I didn't find any good methods to do the functionality.</p> <h3>Code:</h3> <p><strong>PaintingView.h</strong> EAGLContext *context;</p> <pre><code>// OpenGL names for the renderbuffer and framebuffers used to render to this view GLuint viewRenderbuffer, viewFramebuffer; // OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) GLuint depthRenderbuffer; GLuint brushTexture; CGPoint location; CGPoint previousLocation; </code></pre> <p><strong>PaintingView.m</strong></p> <pre><code>// Handles the start of a touch - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { CGRect bounds = [self bounds]; UITouch* touch = [[event touchesForView:self] anyObject]; firstTouch = YES; // Convert touch point from UIView referential to OpenGL one (upside-down flip) location = [touch locationInView:self]; location.y = bounds.size.height - location.y; } // Handles the continuation of a touch. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { CGRect bounds = [self bounds]; UITouch* touch = [[event touchesForView:self] anyObject]; // Convert touch point from UIView referential to OpenGL one (upside-down flip) if (firstTouch) { firstTouch = NO; previousLocation = [touch previousLocationInView:self]; previousLocation.y = bounds.size.height - previousLocation.y; } else { location = [touch locationInView:self]; location.y = bounds.size.height - location.y; previousLocation = [touch previousLocationInView:self]; previousLocation.y = bounds.size.height - previousLocation.y; } // Render the stroke [self renderLineFromPoint:previousLocation toPoint:location]; } // Handles the end of a touch event when the touch is a tap. - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { CGRect bounds = [self bounds]; UITouch* touch = [[event touchesForView:self] anyObject]; if (firstTouch) { firstTouch = NO; previousLocation = [touch previousLocationInView:self]; previousLocation.y = bounds.size.height - previousLocation.y; [self renderLineFromPoint:previousLocation toPoint:location]; } } // Drawings a line onscreen based on where the user touches - (void) renderLineFromPoint:(CGPoint)start toPoint:(CGPoint)end { static GLfloat* vertexBuffer = NULL; static NSUInteger vertexMax = 64; NSUInteger vertexCount = 0, count, i; [EAGLContext setCurrentContext:context]; glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); // Convert locations from Points to Pixels CGFloat scale = self.contentScaleFactor; start.x *= scale; start.y *= scale; end.x *= scale; end.y *= scale; // Allocate vertex array buffer if(vertexBuffer == NULL) vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat)); // Add points to the buffer so there are drawing points every X pixels count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) / kBrushPixelStep), 1); for(i = 0; i &lt; count; ++i) { if(vertexCount == vertexMax) { vertexMax = 2 * vertexMax; vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat)); } vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count); vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count); vertexCount += 1; } // Render the vertex array glVertexPointer(2, GL_FLOAT, 0, vertexBuffer); glDrawArrays(GL_POINTS, 0, vertexCount); // Display the buffer glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES]; } // Erases the screen - (void) erase { [EAGLContext setCurrentContext:context]; // Clear the buffer glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); // Display the buffer glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES]; } // The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder: - (id)initWithCoder:(NSCoder*)coder { CGImageRef brushImage; CGContextRef brushContext; GLubyte *brushData; size_t width, height; if ((self = [super initWithCoder:coder])) { CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = YES; // In this application, we want to retain the EAGLDrawable contents after a call to presentRenderbuffer. eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; if (!context || ![EAGLContext setCurrentContext:context]) { [self release]; return nil; } // Create a texture from an image // First create a UIImage object from the data in a image file, and then extract the Core Graphics image brushImage = [UIImage imageNamed:@"Particle.png"].CGImage; // Get the width and height of the image width = CGImageGetWidth(brushImage); height = CGImageGetHeight(brushImage); // Texture dimensions must be a power of 2. If you write an application that allows users to supply an image, // you'll want to add code that checks the dimensions and takes appropriate action if they are not a power of 2. // Make sure the image exists if(brushImage) { // Allocate memory needed for the bitmap context brushData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte)); // Use the bitmatp creation function provided by the Core Graphics framework. brushContext = CGBitmapContextCreate(brushData, width, height, 8, width * 4, CGImageGetColorSpace(brushImage), kCGImageAlphaPremultipliedLast); // After you create the context, you can draw the image to the context. CGContextDrawImage(brushContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), brushImage); // You don't need the context at this point, so you need to release it to avoid memory leaks. CGContextRelease(brushContext); // Use OpenGL ES to generate a name for the texture. glGenTextures(1, &amp;brushTexture); // Bind the texture name. glBindTexture(GL_TEXTURE_2D, brushTexture); // Set the texture parameters to use a minifying filter and a linear filer (weighted average) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Specify a 2D texture image, providing the a pointer to the image data in memory glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData); // Release the image data; it's no longer needed free(brushData); } // Set the view's scale factor self.contentScaleFactor = 1.0; // Setup OpenGL states glMatrixMode(GL_PROJECTION); CGRect frame = self.bounds; CGFloat scale = self.contentScaleFactor; // Setup the view port in Pixels glOrthof(0, frame.size.width * scale, 0, frame.size.height * scale, -1, 1); glViewport(0, 0, frame.size.width * scale, frame.size.height * scale); glMatrixMode(GL_MODELVIEW); glDisable(GL_DITHER); glEnable(GL_TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnable(GL_BLEND); // Set a blending function appropriate for premultiplied alpha pixel data glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_POINT_SPRITE_OES); glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE); glPointSize(width / kBrushScale); // Make sure to start with a cleared buffer needsErase = YES; } </code></pre> <p><strong>AppDelegate.h</strong></p> <pre><code> PaintingWindow *window; //its a class inherited from window. PaintingView *drawingView; @property (nonatomic, retain) IBOutlet PaintingWindow *window; @property (nonatomic, retain) IBOutlet PaintingView *drawingView; @synthesize window; @synthesize drawingView; return self; } </code></pre> <p><strong>Appdelegate.m</strong></p> <pre><code>- (void) applicationDidFinishLaunching:(UIApplication*)application { CGRect rect = [[UIScreen mainScreen] applicationFrame]; CGFloat components[3]; // Create a segmented control so that the user can choose the brush color. UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems: [NSArray arrayWithObjects: [UIImage imageNamed:@"Red.png"], [UIImage imageNamed:@"Yellow.png"], [UIImage imageNamed:@"Green.png"], [UIImage imageNamed:@"Blue.png"], [UIImage imageNamed:@"Purple.png"], nil]]; // Compute a rectangle that is positioned correctly for the segmented control you'll use as a brush color palette //CGRect frame = CGRectMake(rect.origin.x + kLeftMargin, rect.size.height - kPaletteHeight - kTopMargin, rect.size.width - (kLeftMargin + kRightMargin), kPaletteHeight); CGRect frame = CGRectMake(50, 22, (rect.size.width - (kLeftMargin + kRightMargin)) - 20, kPaletteHeight); segmentedControl.frame = frame; // When the user chooses a color, the method changeBrushColor: is called. [segmentedControl addTarget:self action:@selector(changeBrushColor:) forControlEvents:UIControlEventValueChanged]; segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar; // Make sure the color of the color complements the black background segmentedControl.tintColor = [UIColor darkGrayColor]; // Set the third color (index values start at 0) segmentedControl.selectedSegmentIndex = 2; // Add the control to the window [window addSubview:segmentedControl]; // Now that the control is added, you can release it [segmentedControl release]; [self addBackgroundSegmentControll]; // Define a starting color HSL2RGB((CGFloat) 2.0 / (CGFloat)kPaletteSize, kSaturation, kLuminosity, &amp;components[0], &amp;components[1], &amp;components[2]); // Defer to the OpenGL view to set the brush color [drawingView setBrushColorWithRed:components[0] green:components[1] blue:components[2]]; // Look in the Info.plist file and you'll see the status bar is hidden // Set the style to black so it matches the background of the application [application setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO]; // Now show the status bar, but animate to the style. [application setStatusBarHidden:NO withAnimation:YES]; // Load the sounds NSBundle *mainBundle = [NSBundle mainBundle]; erasingSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"Erase" ofType:@"caf"]]; selectSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"Select" ofType:@"caf"]]; [window setFrame:CGRectMake(0, 0, 768, 1024)]; drawingView.frame = CGRectMake(0, 0, 768, 1024); // Erase the view when recieving a notification named "shake" from the NSNotificationCenter object // The "shake" nofification is posted by the PaintingWindow object when user shakes the device [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(eraseView) name:@"shake" object:nil]; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload