Objective-C OpenGL how to rotate, scale - ios

I have the following source code where i can draw some objects to the screen but i want to rotate and scale the drawed object and nothing happens when i am touching the screen. (In the log i can see if i am doing a pan gesture or a pinch gesture so the detection is ok)
What am i doing wrong?
UPDATE
Now it moves (instead of rotation) maybe i rotate it not around the center of the pointcloud. I tried to move it to center but now nothing is on the screen. Here is the updated Code:
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>
#import "EAGLView.h"
#import "VertexPoint.h"
#import "CamOnMap-Swift.h"
#import <Math.h>
#define USE_DEPTH_BUFFER 1
#define DEGREES_TO_RADIANS(__ANGLE) ((__ANGLE) / 180.0 * M_PI)
// 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;
// You must implement this method
+ (Class)layerClass {
return [CAEAGLLayer class];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
NSLog(#"Ide eljutottam ez az initWithCoder");
TOUCH_ROT_FACTOR = (180.0 / 320.0);
if ((self = [super initWithCoder:aDecoder])) {
// 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;
}
- (void)setupView {
const GLfloat zNear = 0.1, zFar = 1000.0, fieldOfView = 60.0;
GLfloat size;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
//Grab the size of the screen
CGRect rect = self.frame;
glFrustumf(-size, size,
-size / (rect.size.width / rect.size.height),
size / (rect.size.width / rect.size.height),
zNear, zFar);
glViewport(0, 0, rect.size.width, rect.size.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
//Initialize touchLocation to 0, 0
// touchLocation = CGPointMake(rect.size.width/2, rect.size.height/2);
// touchLocation = CGPointMake(0, 0);
// GLfloat x = (touchLocation.x);
// GLfloat y = (touchLocation.y);
//translate the triangle
// glTranslatef(x, y, -10.0);
multitouch_distance_start = 0;
viewDistance = -100;
[self setupGestures];
[self getPly];
}
- (void)setupGestures{
[self setUserInteractionEnabled:true];
[self setMultipleTouchEnabled:true];
pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchHandler:)];
panGesture =[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panHandler:)];
[self addGestureRecognizer:pinchGesture];
[self addGestureRecognizer:panGesture];
};
-(VertexPoint*)center:(NSMutableArray *)vertices2{
float sum_x =0.0f;
float sum_y =0.0f;
float sum_z =0.0f;
for (int i=0; i<vertices2.count; i++) {
VertexPoint *point =vertices2[i];
sum_x +=point.x;
sum_y +=point.y;
sum_z +=point.z;
}
center_ = [[VertexPoint alloc] init];
GLfloat point[] = {(sum_x / vertices2.count),(sum_y / vertices2.count), (sum_z / vertices2.count)};
[center_ setPosition:point];
return center_;
}
-(float)multiTouchDistance:(UIPinchGestureRecognizer *) recognizer{
float x1 = [recognizer locationOfTouch:0 inView:self].x;
float y1 = [recognizer locationOfTouch:0 inView:self].y;
float x2 = [recognizer locationOfTouch:1 inView:self].x;
float y2 = [recognizer locationOfTouch:1 inView:self].y;
float dx = x2 - x1;
float dy = y2 - y1;
return sqrt(dx*dx + dy*dy);
}
- (void)pinchHandler:(UIPinchGestureRecognizer *)recognizer {
glPopMatrix();
float d = [self multiTouchDistance:recognizer];
NSLog(#"d: %f",d);
if(d > 0.0f)multitouch_distance_start = d;
viewDistance *= multitouch_distance_start / d;
multitouch_distance_start = d;
//glScalef(recognizer.scale, recognizer.scale, recognizer.scale);
//recognizer.scale = 1;
NSLog(#"viewDistance: %f",viewDistance);
glPushMatrix();
[self render];
}
- (void)panHandler:(UIPanGestureRecognizer *)recognizer {
if(recognizer.state == UIGestureRecognizerStateBegan){
CGPoint translation = [recognizer translationInView:self];
xPrev = translation.x;
yPrev = translation.y;
}
if(recognizer.state == UIGestureRecognizerStateChanged){
glPopMatrix();
CGPoint translation = [recognizer translationInView:self];
GLfloat dx = translation.x - xPrev;
GLfloat dy = translation.y - yPrev;
xAngle += ((dx) * (TOUCH_ROT_FACTOR));
yAngle += ((dy) * (TOUCH_ROT_FACTOR));
// glRotatef(xAngle,1,0,0);
// glRotatef(yAngle,0,1,0);
xPrev = translation.x;
yPrev = translation.y;
glPushMatrix();
NSLog(#"pan");
[self render];
}
};
-(void)completionHandler:(NSString *) data{
// NSLog(#"%#",data);
NSArray *dataArray = [data componentsSeparatedByString:#"\n"];
vertices = [[NSMutableArray alloc] init];
for(NSInteger i = 14; i < dataArray.count; i++ ){
NSArray *row = [dataArray[i] componentsSeparatedByString:#" "];
if(![dataArray[i] isEqual: #""]){
VertexPoint *point = [[VertexPoint alloc] init];
GLfloat a[] = { [[row objectAtIndex:0] floatValue], [[row objectAtIndex:1] floatValue], [[row objectAtIndex:2] floatValue]};
[point setPosition:a];
GLfloat b[] = { [[row objectAtIndex:6] floatValue],[[row objectAtIndex:7] floatValue], [[row objectAtIndex:8] floatValue], [[row objectAtIndex:9] floatValue]};
[point setColor:b];
[vertices addObject:point];
}
}
long vcount = [vertices count] * 3; // * 2 for the two coordinates of a loc object
glVertices = (GLfloat *)malloc(vcount * sizeof(GLfloat));
int currIndex = 0;
for (VertexPoint *loc in vertices) {
glVertices[currIndex++] = (loc.x);
glVertices[currIndex++] =(loc.y);
glVertices[currIndex++] =(loc.z);
}
long ccount = [vertices count] * 4;
glColors = (GLfloat *)malloc(ccount * sizeof(GLfloat));
int currColorIndex = 0;
for(VertexPoint *color in vertices){
glColors[currColorIndex++] = (color.r);
glColors[currColorIndex++] = (color.g);
glColors[currColorIndex++] = (color.b);
glColors[currColorIndex++] = (color.a);
}
center_ = [self center: vertices];
glTranslatef(0, 0, -100);
// glTranslatef(-1 * center_.x, -1 * center_.y, -1 * center_.z);
NSLog(#"x: %f, y: %f, z:%f",-1 * center_.x,-1 * center_.y,-1 * center_.z);
[self drawView];
};
-(void)getPly{
GlobalDataFunctions *globalDataFunctions = [[GlobalDataFunctions alloc] init];
NSString *ply = [globalDataFunctions selectedPly];
NSLog(#"%#",ply);
RestClient *restClient = [[RestClient alloc] init];
NSString *username = [[NSUserDefaults standardUserDefaults] objectForKey:#"username"];
NSString *password = [[NSUserDefaults standardUserDefaults] objectForKey:#"password"];
[restClient getPly: username password:password ply:ply myComletionHandler: ^(NSString *data){
[self completionHandler:data];
}];
};
- (void)drawView {
NSLog(#"drawView");
//setting up the draw content
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
//Draw stuff
//reset matrix to identity
glLoadIdentity();
//rough approximation of screen to current 3D space
GLfloat x = (touchLocation.x - 160.0) / 38.0;
GLfloat y = (240.0 - touchLocation.y) / 38.0;
//translate the triangle
glTranslatef(x, y, -1.0);
[self render];
}
-(void)render{
NSLog(#"render");
center_ = [self center: vertices];
// glTranslatef(-1 * center_.x, -1 * center_.y, -1 * center_.z);
//clear the back color back to our original color and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//rough approximation of screen to current 3D space
//set the format and location for verticies
glVertexPointer(3, GL_FLOAT, 0, glVertices);
//set the opengl state
glEnableClientState(GL_VERTEX_ARRAY);
//set the format and location for colors
glColorPointer(4, GL_FLOAT, 0, glColors);
//set the opengl state
glEnableClientState(GL_COLOR_ARRAY);
glPointSize(3);
//draw the triangles
// glTranslatef(0,0,viewDistance);
// glTranslatef(-1 * center_.x, -1 * center_.y, -1 * center_.z);
glDrawArrays(GL_POINTS, 0, vertices.count);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
//show the render buffer
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
touchLocation = [touch locationInView:self];
NSLog(#"touch");
[self drawView];
}
- (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) {
NSLog(#"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;
}
}
And here can you find a sample input data: http://pastebin.com/rcrfZdyt

Related

iOS CALayer convertPoint:fromLayer: message sent to deallocated instance

I have a class with a square made of bezierPaths, you can change the size of the square by pressing near a side and drag it.
Right now i can drag and release one time, the next time i get the following error:
2015-01-20 14:20:36.356 BezierPaths[196:3437] *** -[CALayer convertPoint:fromLayer:]: message sent to deallocated instance 0x1742251c0
Why doesnt it work the 2nd time?
This is the class:
#implementation EditBezierView
{
UIBezierPath *path;
UIImage *incrementalImage;
CGPoint pts[9];
NSMutableArray *pathPoints;
NSMutableArray *controlPoints;
BOOL pressedPoint;
int index;
float xStart;
float yStart;
int closestIndex;
CGPoint closestComparePoint;
bool moveControl;
int counter;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
[self setMultipleTouchEnabled:NO];
[self setBackgroundColor:[UIColor clearColor]];
path = [UIBezierPath bezierPath];
[path setLineWidth:1.0];
pathPoints = [NSMutableArray array];
controlPoints = [NSMutableArray array];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setMultipleTouchEnabled:NO];
path = [UIBezierPath bezierPath];
[path setLineWidth:2.0];
counter = 0;
}
return self;
}
- (void)initValues
{
[pathPoints addObject:[NSValue valueWithCGPoint:CGPointMake(47.0, 130.0)]];
[pathPoints addObject:[NSValue valueWithCGPoint:CGPointMake(14.0, 230.0)]];
[controlPoints addObject:[NSValue valueWithCGPoint:CGPointMake(26.0, 150.0)]];
[pathPoints addObject:[NSValue valueWithCGPoint:CGPointMake(22.0, 320.0)]];
[controlPoints addObject:[NSValue valueWithCGPoint:CGPointMake(9.0, 270.0)]];
[pathPoints addObject:[NSValue valueWithCGPoint:CGPointMake(90.0, 420.0)]];
[controlPoints addObject:[NSValue valueWithCGPoint:CGPointMake(24.0, 380.0)]];
[pathPoints addObject:[NSValue valueWithCGPoint:CGPointMake(230.0, 420.0)]];
[controlPoints addObject:[NSValue valueWithCGPoint:CGPointMake(170.0, 460.0)]];
[pathPoints addObject:[NSValue valueWithCGPoint:CGPointMake(300.0, 320.0)]];
[controlPoints addObject:[NSValue valueWithCGPoint:CGPointMake(280.0, 390)]];
[pathPoints addObject:[NSValue valueWithCGPoint:CGPointMake(307.0, 220.0)]];
[controlPoints addObject:[NSValue valueWithCGPoint:CGPointMake(315.0, 260.0)]];
[pathPoints addObject:[NSValue valueWithCGPoint:CGPointMake(270.0, 130.0)]];
[controlPoints addObject:[NSValue valueWithCGPoint:CGPointMake(300.0, 160.0)]];
[self drawPaths];
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
[[UIColor blueColor] setStroke];
[path stroke];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
counter++;
NSLog(#"%d", counter);
[self.layer.sublayers makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
UITouch *currentTouch = [touches anyObject];
CGPoint startPt = [currentTouch locationInView:self];
if(moveControl)
{
float xOs = [(NSValue*)[controlPoints objectAtIndex:closestIndex] CGPointValue].x;
float yOs = [(NSValue*)[controlPoints objectAtIndex:closestIndex] CGPointValue].y;
[controlPoints replaceObjectAtIndex:closestIndex withObject:[NSValue valueWithCGPoint:CGPointMake(xOs - (xStart-startPt.x), yOs - (yStart - startPt.y))]];
}
else
{
float xOs = [(NSValue*)[pathPoints objectAtIndex:closestIndex] CGPointValue].x;
float yOs = [(NSValue*)[pathPoints objectAtIndex:closestIndex] CGPointValue].y;
[pathPoints replaceObjectAtIndex:closestIndex withObject:[NSValue valueWithCGPoint:CGPointMake(xOs - (xStart-startPt.x), yOs - (yStart - startPt.y))]];
}
[self drawPaths];
xStart = startPt.x;
yStart = startPt.y;
}
- (void)drawPaths
{
path = [UIBezierPath bezierPath];
for(int i = 1; i < [pathPoints count]; i++)
{
//Draw path
[path moveToPoint:((NSValue*)[pathPoints objectAtIndex:i-1]).CGPointValue];
[path addQuadCurveToPoint:((NSValue*)[pathPoints objectAtIndex:i]).CGPointValue controlPoint:((NSValue*)[controlPoints objectAtIndex:i-1]).CGPointValue];
//Draw points
if(i == 1)
{
[self addrectangle:((NSValue*)[pathPoints objectAtIndex:i-1]).CGPointValue];
[self addrectangle:((NSValue*)[pathPoints objectAtIndex:i]).CGPointValue];
[self addQuadrectangle:((NSValue*)[controlPoints objectAtIndex:i-1]).CGPointValue];
}
else
{
[self addrectangle:((NSValue*)[pathPoints objectAtIndex:i]).CGPointValue];
[self addQuadrectangle:((NSValue*)[controlPoints objectAtIndex:i-1]).CGPointValue];
}
}
[self setNeedsDisplay];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *currentTouch = [touches anyObject];
CGPoint startPt = [currentTouch locationInView:self];
closestComparePoint = startPt;
xStart = startPt.x;
yStart = startPt.y;
[self findNearestPoint];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//[self drawPath];
}
-(void)findNearestPoint
{
int pathClosestIndex = 0;
CGFloat xDist;
CGFloat yDist;
CGFloat Controldistance = 12401240;
CGFloat Pathdistance = 12401240;
for(int i = 0; i < [controlPoints count]; i++)
{
xDist = ABS([(NSValue*)[controlPoints objectAtIndex:i] CGPointValue].x - closestComparePoint.x);
yDist = ABS([(NSValue*)[controlPoints objectAtIndex:i] CGPointValue].y - closestComparePoint.y);
if(sqrt((xDist * xDist) + (yDist * yDist)) < Controldistance)
{
Controldistance = sqrt((xDist * xDist) + (yDist * yDist));
closestIndex = i;
}
}
for(int i = 0; i < [pathPoints count]; i++)
{
xDist = ABS([(NSValue*)[pathPoints objectAtIndex:i] CGPointValue].x - closestComparePoint.x);
yDist = ABS([(NSValue*)[pathPoints objectAtIndex:i] CGPointValue].y - closestComparePoint.y);
if(sqrt((xDist * xDist) + (yDist * yDist)) < Pathdistance)
{
Pathdistance = sqrt((xDist * xDist) + (yDist * yDist));
pathClosestIndex = i;
}
}
if(Pathdistance < Controldistance)
{
moveControl = NO;
closestIndex = pathClosestIndex;
}
else
{
moveControl = YES;
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
pressedPoint = NO;
}
-(void)removeRectangles{
[self.layer.sublayers makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
}
-(void)addrectangle:(CGPoint) center{
int offset = 8;
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(center.x - offset, center.y - offset)];
// # Entry Point with 10px white frame
[path2 moveToPoint:CGPointMake(center.x - offset, center.y - offset)];
// # Keeping 10px frame with iPhone's 450 on y-axis
[path2 addLineToPoint:CGPointMake(center.x - offset, center.y + offset)];
// path2 Substracting 10px for frame on x-axis, and moving 450 in y-axis
[path2 addLineToPoint:CGPointMake(center.x + offset, center.y + offset)];
// # Moving up to 1st step 10px line, 310px on the x-axis
[path2 addLineToPoint:CGPointMake(center.x + offset, center.y - offset)];
// # Back to entry point
[path2 addLineToPoint:CGPointMake(center.x - offset, center.y - offset)];
// 4th Create a CAShapeLayer that uses that UIBezierPath:
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path2 CGPath];
shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
shapeLayer.lineWidth = 1.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
// 5th add shapeLayer as sublayer inside layer view
[self.layer addSublayer:shapeLayer];
}
-(void)addQuadrectangle:(CGPoint) center{
int offset = 4;
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(center.x - offset, center.y - offset)];
// # Entry Point with 10px white frame
[path2 moveToPoint:CGPointMake(center.x - offset, center.y - offset)];
// # Keeping 10px frame with iPhone's 450 on y-axis
[path2 addLineToPoint:CGPointMake(center.x - offset, center.y + offset)];
// path2 Substracting 10px for frame on x-axis, and moving 450 in y-axis
[path2 addLineToPoint:CGPointMake(center.x + offset, center.y + offset)];
// # Moving up to 1st step 10px line, 310px on the x-axis
[path2 addLineToPoint:CGPointMake(center.x + offset, center.y - offset)];
// # Back to entry point
[path2 addLineToPoint:CGPointMake(center.x - offset, center.y - offset)];
// 4th Create a CAShapeLayer that uses that UIBezierPath:
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [path2 CGPath];
shapeLayer.strokeColor = [[UIColor redColor] CGColor];
shapeLayer.lineWidth = 1.0;
shapeLayer.fillColor = [[UIColor clearColor] CGColor];
// 5th add shapeLayer as sublayer inside layer view
[self.layer addSublayer:shapeLayer];
}
-(int)findOrigoInX
{
int closestToX = [(NSValue *)[pathPoints firstObject] CGPointValue].x;
for(int i = 1; i < [pathPoints count]; i++)
{
if([(NSValue *)[pathPoints objectAtIndex:i] CGPointValue].x < closestToX)
{
closestToX = [(NSValue *)[pathPoints objectAtIndex:i] CGPointValue].x;
}
}
return closestToX;
}
-(int)findOrigoInY
{
int closestToY = [(NSValue *)[pathPoints firstObject] CGPointValue].y;
for(int i = 1; i < [pathPoints count]; i++)
{
if([(NSValue *)[pathPoints objectAtIndex:i] CGPointValue].y > closestToY)
{
closestToY = [(NSValue *)[pathPoints objectAtIndex:i] CGPointValue].y;
}
}
return closestToY;
}
-(NSMutableArray*)generateKoordinateArray
{
NSLog(#"count in pathPoints : %lu", (unsigned long)[pathPoints count]);
NSMutableArray *storeArray = [[NSMutableArray alloc] init];
BezierCsvFormat *storeBezier = [[BezierCsvFormat alloc] init];
NSString *stringValueX;
NSString *stringValueY;
int xOffset = [self findOrigoInX];
NSLog(#"x offset : %d", xOffset);
int yOffset = [self findOrigoInY];
NSLog(#"y offset : %d", yOffset);
for(int i = 1; i < [pathPoints count]; i++)
{
storeBezier = [[BezierCsvFormat alloc] init];
stringValueX = [NSString stringWithFormat:#"%d", (int)[(NSValue *)[pathPoints objectAtIndex:i-1] CGPointValue].x - xOffset];
stringValueY = [NSString stringWithFormat:#"%d", ABS((int)[(NSValue *)[pathPoints objectAtIndex:i-1] CGPointValue].y - yOffset)];
[storeBezier setp0:[NSString stringWithFormat:#"%#,%#",stringValueX, stringValueY]];
stringValueX = [NSString stringWithFormat:#"%d", (int)[(NSValue *)[controlPoints objectAtIndex:i-1] CGPointValue].x - xOffset];
int multiplicator = 1;
if((int)[(NSValue *)[controlPoints objectAtIndex:i-1] CGPointValue].y > yOffset)
{
multiplicator = multiplicator * -1;
}
stringValueY = [NSString stringWithFormat:#"%d", multiplicator * ABS((int)[(NSValue *)[controlPoints objectAtIndex:i-1] CGPointValue].y - yOffset)];
[storeBezier setp1:[NSString stringWithFormat:#"%#,%#",stringValueX, stringValueY]];
stringValueX = [NSString stringWithFormat:#"%d", (int)[(NSValue *)[pathPoints objectAtIndex:i] CGPointValue].x - xOffset];
stringValueY = [NSString stringWithFormat:#"%d", ABS((int)[(NSValue *)[pathPoints objectAtIndex:i] CGPointValue].y - yOffset)];
[storeBezier setp2:[NSString stringWithFormat:#"%#,%#",stringValueX, stringValueY]];
[storeArray addObject:storeBezier];
}
NSLog(#"count in storeArray : %lu", (unsigned long)[storeArray count]);
return storeArray;
}
- (NSMutableArray*)printCoordinateSystem
{
NSMutableArray *tempArray = [self generateKoordinateArray];
return tempArray;
NSLog(#"count in tempArray : %lu", (unsigned long)[tempArray count]);
for(int i = 0; i < [tempArray count]; i++)
{
NSLog(#"p0 : %# p1 : %# p2 : %#", [(BezierCsvFormat*)[tempArray objectAtIndex:i] getp0], [(BezierCsvFormat*)[tempArray objectAtIndex:i] getp1], [(BezierCsvFormat*)[tempArray objectAtIndex:i] getp2]);
}
}
-(void)resetView{
#try {
[path removeAllPoints];
pathPoints = [NSMutableArray array];
[self.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[self.layer.sublayers makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
[self setNeedsDisplay];
}
#catch (NSException *exception) {
[self resetView];
}
#finally {
}
}

OpenGL live record not working.

I've got a uiview that implements openGL for drawing. I'm trying to implement a basic recording feature, as shown here.
All of the setup works fine, as does the openGL drawing. But I get an error on the third or fourth frame that the AVAdaptor tries to append (the first few go ok).
I think it's a problem with the CVPixelBufferPoolCreatePixelBuffer call, but I can't track it down...
Here's the code. The recording code is near the bottom:
#import "ochrDrawingView.h"
#define POINT_FREQUENCY_CONSTANT 0.3 // 1 is a point for every pixel of distance. Note: performance drops above 0.5 on long lines.
#define ARBITRARY_BUFFER_SIZE 2048
typedef struct {
GLfloat Position[2];
GLfloat TextureCoordinates[2];
} TexturedVertex;
typedef struct {
TexturedVertex BottomLeft;
TexturedVertex BottomRight;
TexturedVertex TopLeft;
TexturedVertex TopRight;
} TexturedSquare;
#pragma mark - Implementation
#implementation ochrDrawingView {
// OpenGL
EAGLContext *context;
CAEAGLLayer *eaglLayer;
GLuint renderBuffer;
GLuint frameBuffer;
GLKBaseEffect *effect;
GLint backingWidth;
GLint backingHeight;
// Drawing
CGSize brushSize;
float brushScale;
BOOL isFirstTouch;
CGPoint origin;
CGPoint midpoint;
CGPoint destination;
// Concurrency
dispatch_queue_t recordingQueue;
// Video Recording
AVAssetWriter *videoWriter;
AVAssetWriterInput *videoWriterInput;
AVAssetWriterInputPixelBufferAdaptor *avAdaptor;
BOOL isRecording;
BOOL hasFinishedRecording;
NSDate *recordingBeganAt;
void* bitmapData;
}
#pragma mark - Setup
- (id)initWithCoder:(NSCoder *)aDecoder {
NSLog(#"About to initWithCoder...");
self = [super initWithCoder:aDecoder];
if (self) {
isRecording = NO;
[self setupLayer];
[self setupContext];
[self setupRenderBuffer];
[self setupFrameBuffer];
[self setViewportParameters];
[self setupBaseEffect];
[self eraseScreen];
recordingQueue = dispatch_queue_create("recordingQueue", NULL);
}
return self;
}
+ (Class) layerClass {
return [CAEAGLLayer class];
}
- (void) setupContext {
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:context];
}
- (void) setupLayer {
eaglLayer = (CAEAGLLayer *) self.layer;
[eaglLayer setOpaque:YES];
[eaglLayer setDrawableProperties: [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]];
}
- (void)setupRenderBuffer {
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer];
}
- (void) setViewportParameters {
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
NSLog(#"Width: %d, Height: %d", backingWidth, backingHeight);
glViewport(0, 0, backingWidth, backingHeight);
}
- (void) setupFrameBuffer {
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
}
- (void) setupBaseEffect {
effect = [[GLKBaseEffect alloc] init];
// Load the texture into the effect
NSError *error;
NSDictionary *options = #{ GLKTextureLoaderOriginBottomLeft: #YES };
NSString *path = [[NSBundle mainBundle] pathForResource:#"brush.png" ofType:nil];
GLKTextureInfo *texture = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
if (texture == nil) NSLog(#"Texture failed to load. Error: %#", error.localizedDescription);
effect.texture2d0.name = texture.name;
effect.texture2d0.enabled = GL_TRUE;
// Set the brushSize (used later, in drawing method)
brushSize = CGSizeMake(texture.width, texture.height);
brushScale = 0.6;
// Set up a project and modelview matrix. maybe:
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, backingWidth, 0, backingHeight, 0, 1.0f);
effect.transform.projectionMatrix = projectionMatrix;
[effect prepareToDraw];
}
- (void) eraseScreen {
[EAGLContext setCurrentContext:context];
// Clear the buffer
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// Display the buffer
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];
}
#pragma mark - Touch Response
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
isFirstTouch = YES;
origin = [[touches anyObject] locationInView:self];
origin.y = backingHeight - origin.y;
[self drawPointAtPoint:origin];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (isFirstTouch) {
isFirstTouch = NO;
midpoint = [[touches anyObject] locationInView:self];
midpoint.y = backingHeight - midpoint.y;
} else {
destination = [[touches anyObject] locationInView:self];
destination.y = backingHeight - destination.y;
[self drawCubicLineFromPoint:origin HalfwayToPoint:destination WithControl:midpoint];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchesMoved:touches withEvent:event];
}
#pragma mark - Drawing Algorithms
- (void)drawCubicLineFromPoint:(CGPoint)start HalfwayToPoint:(CGPoint)end WithControl:(CGPoint)control {
static GLfloat tempVertexBuffer[ARBITRARY_BUFFER_SIZE];
static GLubyte tempIndexBuffer[ARBITRARY_BUFFER_SIZE];
int vertexCount = 0;
int indexCount = 0;
float pointCount;
// [EAGLContext setCurrentContext:context];
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// Get the number of points to be drawn between the two points
float distance = sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y));
pointCount = MAX(ceilf(distance * POINT_FREQUENCY_CONSTANT), 1);
// Adjust the size of the brush based on the (rough) speed of the stroke
if (distance > 20) {
brushScale = 0.5;
} else {
brushScale = 0.6;
}
// Get the adjustment value used to center each texture (the brush image is a square, so here I use only width)
float positionAdjustmentToCenterTexture = brushScale * brushSize.width / 2.0;
// Iterate through the points to be drawn, drawing a TexturedSquare (more or less) for each.
float t = 0.0, x, y;
for (float i = 0; i < pointCount; i++) {
x = powf(1 - t, 2) * start.x + 2 * (1 - t) * t * control.x + t * t * end.x;
y = powf(1 - t, 2) * start.y + 2 * (1 - t) * t * control.y + t * t * end.y;
t += 0.5 / pointCount;
// Bottom-left vertex
tempVertexBuffer[4 * vertexCount + 0] = x - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 0;
tempVertexBuffer[4 * vertexCount + 3] = 0;
vertexCount++;
// Bottom-right vertex
tempVertexBuffer[4 * vertexCount + 0] = x + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 1;
tempVertexBuffer[4 * vertexCount + 3] = 0;
vertexCount++;
// Top-left vertex
tempVertexBuffer[4 * vertexCount + 0] = x - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 0;
tempVertexBuffer[4 * vertexCount + 3] = 1;
vertexCount++;
// Top-right vertex
tempVertexBuffer[4 * vertexCount + 0] = x + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 1;
tempVertexBuffer[4 * vertexCount + 3] = 1;
vertexCount++;
// Add the indices for the triangles
tempIndexBuffer[indexCount++] = vertexCount - 4;
tempIndexBuffer[indexCount++] = vertexCount - 3;
tempIndexBuffer[indexCount++] = vertexCount - 2;
tempIndexBuffer[indexCount++] = vertexCount - 3;
tempIndexBuffer[indexCount++] = vertexCount - 2;
tempIndexBuffer[indexCount++] = vertexCount - 1;
}
origin = CGPointMake(x, y); // sets the origin to the last point drawn
midpoint = end; // sets the midpoint to the previous destination.
long pointer = (long)&tempVertexBuffer;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)pointer + offsetof(TexturedVertex, Position));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)pointer + offsetof(TexturedVertex, TextureCoordinates));
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_BYTE, tempIndexBuffer);
// Display the buffer
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];
// If recording, record this frame
if (isRecording) {
dispatch_async(recordingQueue, ^{
[self writeCurrentFrame];
});
}
}
- (void)drawStraightLineFromPoint:(CGPoint)start ToPoint:(CGPoint)end {
GLfloat tempVertexBuffer[128];
GLubyte tempIndexBuffer[128];
int vertexCount = 0;
int indexCount = 0;
float pointCount;
// Dumb setup stuff.
[EAGLContext setCurrentContext:context];
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// Get the number of points to be drawn between the two points
pointCount = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y)) * POINT_FREQUENCY_CONSTANT), 1);
// Get the adjustment value used to center each texture (the brush image is a square, so here I use only width)
float positionAdjustmentToCenterTexture = brushScale * brushSize.width / 2.0;
// Iterate through the points to be drawn, drawing a TexturedSquare (more or less) for each.
float x;
float y;
for (float i = 0; i < pointCount; i++) {
// Set the x and y coordinates for each points, interpolating based on the distance
x = start.x + ((end.x - start.x) * (i / pointCount));
y = start.y + (end.y - start.y) * (i / pointCount);
// Bottom-left vertex
tempVertexBuffer[4 * vertexCount + 0] = x - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 0;
tempVertexBuffer[4 * vertexCount + 3] = 0;
vertexCount++;
// Bottom-right vertex
tempVertexBuffer[4 * vertexCount + 0] = x + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 1;
tempVertexBuffer[4 * vertexCount + 3] = 0;
vertexCount++;
// Top-left vertex
tempVertexBuffer[4 * vertexCount + 0] = x - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 0;
tempVertexBuffer[4 * vertexCount + 3] = 1;
vertexCount++;
// Top-right vertex
tempVertexBuffer[4 * vertexCount + 0] = x + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 1;
tempVertexBuffer[4 * vertexCount + 3] = 1;
vertexCount++;
// Add the indices for the triangles
tempIndexBuffer[indexCount++] = vertexCount - 4;
tempIndexBuffer[indexCount++] = vertexCount - 3;
tempIndexBuffer[indexCount++] = vertexCount - 2;
tempIndexBuffer[indexCount++] = vertexCount - 3;
tempIndexBuffer[indexCount++] = vertexCount - 2;
tempIndexBuffer[indexCount++] = vertexCount - 1;
}
long pointer = (long)&tempVertexBuffer;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)pointer + offsetof(TexturedVertex, Position));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)pointer + offsetof(TexturedVertex, TextureCoordinates));
// Last parameter may be wrong...
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_BYTE, tempIndexBuffer);
// Display the buffer
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];
}
- (void)drawPointAtPoint:(CGPoint)start {
GLfloat tempVertexBuffer[16];
GLubyte tempIndexBuffer[6];
int vertexCount = 0;
int indexCount = 0;
// Dumb setup stuff.
// [EAGLContext setCurrentContext:context];
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// Get the adjustment value used to center each texture (the brush image is a square, so here I use only width)
float positionAdjustmentToCenterTexture = brushScale * brushSize.width / 2.0;
// Iterate through the points to be drawn, drawing a TexturedSquare (more or less) for each.
float x = start.x;
float y = start.y;
// Bottom-left vertex
tempVertexBuffer[4 * vertexCount + 0] = x - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 0;
tempVertexBuffer[4 * vertexCount + 3] = 0;
vertexCount++;
// Bottom-right vertex
tempVertexBuffer[4 * vertexCount + 0] = x + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 1;
tempVertexBuffer[4 * vertexCount + 3] = 0;
vertexCount++;
// Top-left vertex
tempVertexBuffer[4 * vertexCount + 0] = x - positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 0;
tempVertexBuffer[4 * vertexCount + 3] = 1;
vertexCount++;
// Top-right vertex
tempVertexBuffer[4 * vertexCount + 0] = x + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 1] = y + positionAdjustmentToCenterTexture;
tempVertexBuffer[4 * vertexCount + 2] = 1;
tempVertexBuffer[4 * vertexCount + 3] = 1;
vertexCount++;
// Add the indices for the triangles
tempIndexBuffer[indexCount++] = vertexCount - 4;
tempIndexBuffer[indexCount++] = vertexCount - 3;
tempIndexBuffer[indexCount++] = vertexCount - 2;
tempIndexBuffer[indexCount++] = vertexCount - 3;
tempIndexBuffer[indexCount++] = vertexCount - 2;
tempIndexBuffer[indexCount++] = vertexCount - 1;
long pointer = (long)&tempVertexBuffer;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)pointer + offsetof(TexturedVertex, Position));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)pointer + offsetof(TexturedVertex, TextureCoordinates));
// Last parameter may be wrong...
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_BYTE, tempIndexBuffer);
// Display the buffer
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];
}
#pragma mark - Video Recorder Functions
- (BOOL) setupVideoWriter {
NSError* error = nil;
videoWriter = [[AVAssetWriter alloc] initWithURL:[self temporaryFileURL] fileType:AVFileTypeQuickTimeMovie error:&error];
NSParameterAssert(videoWriter);
//Configure video
NSDictionary* videoCompressionProps = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:1024.0*1024.0], AVVideoAverageBitRateKey,
nil ];
NSDictionary* videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:self.frame.size.width], AVVideoWidthKey,
[NSNumber numberWithInt:self.frame.size.height], AVVideoHeightKey,
videoCompressionProps, AVVideoCompressionPropertiesKey,
nil];
videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
NSParameterAssert(videoWriterInput);
videoWriterInput.expectsMediaDataInRealTime = YES;
NSDictionary* bufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil];
avAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput
sourcePixelBufferAttributes:bufferAttributes];
//add input
[videoWriter addInput:videoWriterInput];
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:CMTimeMake(0, 1000)];
return YES;
}
- (CGContextRef) getContextOfSize:(CGSize)size {
CGContextRef tempContext = NULL;
CGColorSpaceRef colorSpace;
int bitmapByteCount;
int bitmapBytesPerRow;
bitmapBytesPerRow = size.width * 4;
bitmapByteCount = bitmapBytesPerRow * size.height;
colorSpace = CGColorSpaceCreateDeviceRGB();
if (bitmapData != NULL) {
free(bitmapData);
}
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL) {
fprintf (stderr, "Memory not allocated!");
return NULL;
}
tempContext = CGBitmapContextCreate (bitmapData,
size.width,
size.height,
8,
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaNoneSkipFirst);
CGContextSetAllowsAntialiasing(tempContext, NO);
if (tempContext == NULL) {
free (bitmapData);
fprintf (stderr, "Context not created!");
return NULL;
}
CGColorSpaceRelease(colorSpace);
return tempContext;
}
- (void) writeCurrentFrame {
NSLog(#"writeCurrentFrame called");
// Get a context
CGContextRef videoContext = [self getContextOfSize:self.frame.size];
// Render the current screen into that context
[self.layer renderInContext:videoContext];
// Get a CGImage from the context
CGImageRef cgImage = CGBitmapContextCreateImage(videoContext);
// Check if the AVAssetWriterInput is ready for more data
if (![videoWriterInput isReadyForMoreMediaData]) {
NSLog(#"Not ready for video data");
} else {
// If it is, convert the CGImage into a CVPixelBufferReference
CVPixelBufferRef pixelBuffer = NULL;
CFDataRef cfImage = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
int status = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, avAdaptor.pixelBufferPool, &pixelBuffer);
if (status != 0) {
NSLog(#"Error creating pixel buffer. Status: %d", status);
} else {
NSLog(#"No error creating the pixel buffer...");
}
// Set image data into pixel buffer
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
uint8_t* destPixels = CVPixelBufferGetBaseAddress(pixelBuffer);
CFDataGetBytes(cfImage, CFRangeMake(0, CFDataGetLength(cfImage)), destPixels);
// If all's well so far, append the pixelbuffer to the adaptor
if (status == 0) {
float millisecondsSinceStart = [[NSDate date] timeIntervalSinceDate:recordingBeganAt];
BOOL success = [avAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:CMTimeMake((int) millisecondsSinceStart, 1000)];
if (!success) {
NSLog(#"Warning: Unable to write buffer to video.");
} else {
NSLog(#"Success! Was able to write buffer to video.");
}
}
// Clean up
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
// CVPixelBufferRelease(pixelBuffer);
CFRelease(cfImage);
CGImageRelease(cgImage);
CGContextRelease(videoContext);
}
}
- (BOOL) completeRecordingSession {
return YES;
}
- (NSURL *) temporaryFileURL {
NSString* outputPath = [[NSString alloc] initWithFormat:#"%#/%#", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0], #"output.mp4"];
NSURL* outputURL = [[NSURL alloc] initFileURLWithPath:outputPath];
NSLog(#"Will try to store the file at %#", outputURL);
NSFileManager* fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:outputPath]) {
NSLog(#"There is already a file there - trying to delete it...");
NSError* error;
if ([fileManager removeItemAtPath:outputPath error:&error] == NO) {
NSLog(#"Could not delete old recording file at path: %#", outputPath);
} else {
NSLog(#"Sucessfully deleted file. The new file can be stored at %#", outputURL);
}
} else {
NSLog(#"File can be stored at %#", outputURL);
}
return outputURL;
}
- (BOOL) startRecording {
isRecording = YES;
return [self setupVideoWriter];;
}
- (BOOL) stopRecording {
return YES;
}
#pragma mark - Helper Functions
- (void) logLocationOfPoint:(CGPoint)point {
NSLog(#"point at { %d, %d }", (int) point.x, (int) point.y);
}
#end
For anyone curious:
The above method takes a flawed approach. In general, it's much better to render into a texture, and then from the texture into a renderbuffer. The performance hit you take on the extra step is minimal, and this approach is much more expandable in terms of streaming, recording, processing, etc.
Best. S

With what coordinates do i use to manually draw a custom path with an MKMapView?

There are CLLocation2D points, MKMapPoints, MKCoordinates, and convertCoordinate:toPointInView: which all give you points in one form or another. I am drawing a custom route in:
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
Whats the proper point to use for drawing?
routeView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, mapView.frame.size.width, mapView.frame.size.height)];
routeView.userInteractionEnabled = NO;
[mapView addSubview:routeView];
And
-(void) updateRouteView {
CGContextRef context = CGBitmapContextCreate(nil,
routeView.frame.size.width,
routeView.frame.size.height,
8,
4 * routeView.frame.size.width,
CGColorSpaceCreateDeviceRGB(),
kCGImageAlphaPremultipliedLast);
CGContextSetStrokeColorWithColor(context, lineColor.CGColor);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
CGContextSetLineWidth(context, 4.0);
for(int i = 0; i < self.routes.count; i++) {
CLLocation* location = [self.routes objectAtIndex:i];
CGPoint point = [mapView convertCoordinate:location.coordinate toPointToView:routeView];
if(i == 0) {
CGContextMoveToPoint(context, point.x, routeView.frame.size.height - point.y);
} else {
CGContextAddLineToPoint(context, point.x, routeView.frame.size.height - point.y);
}
}
CGContextStrokePath(context);
CGImageRef image = CGBitmapContextCreateImage(context);
UIImage* img = [UIImage imageWithCGImage:image];
routeView.image = img;
CGContextRelease(context);
}
You can use google api like-
Define approirate variable in .h-
NSArray *arrRoutePoints;
MKPolygon *objpolygon;
MKPolyline *objpolyline;
Call function like where you want -
self.arrRoutePoints=[self getRoutePointFrom:newSource to:newDestination];
[self drawRoute];
Function Code :
- (NSArray*)getRoutePointFrom:(MKPointAnnotation *)origin to:(MKPointAnnotation *)destination
{
NSString *saddress=[NSString stringWithFormat:#"%f,%f",origin.coordinate.latitude,origin.coordinate.longitude];
NSString *daddress=[NSString stringWithFormat:#"%f,%f",destination.coordinate.latitude,destination.coordinate.longitude];
NSString *apiUrlString=[NSString stringWithFormat:#"http://maps.google.com/maps?output=dragdir&saddr=%#&daddr=%#", saddress, daddress];
NSURL *apiUrl=[NSURL URLWithString:apiUrlString];
NSError *error;
NSString *apiResponse=[NSString stringWithContentsOfURL:apiUrl encoding:NSUTF8StringEncoding error:&error];
NSRange range;
range=[apiResponse rangeOfString:#"points:\\\"([^\\\"]*)\\\"" options:NSRegularExpressionSearch];
NSString *encodedPoint=[apiResponse substringWithRange:range];
NSLog(#"Encode lentgh %d",[encodedPoint length]);
encodedPoint=[encodedPoint stringByReplacingOccurrencesOfString:#"points:\"" withString:#""];
encodedPoint=[encodedPoint stringByReplacingOccurrencesOfString:#"\"" withString:#""];
return [self decodePolyLine:[encodedPoint mutableCopy]];
}
- (NSMutableArray *)decodePolyLine:(NSMutableString *)encodedString
{
[encodedString replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encodedString length])];
NSInteger len = [encodedString length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encodedString characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
if(index<len)
{
b = [encodedString characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
}
else
{
break;
}
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
printf("\n[%f,", [latitude doubleValue]);
printf("%f]", [longitude doubleValue]);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:loc];
}
return array;
}
- (void)drawRoute
{
int numPoints=[arrRoutePoints count];
if(numPoints >1)
{
CLLocationCoordinate2D *coord=malloc(numPoints *sizeof(CLLocationCoordinate2D));
for(int i=0;i<numPoints;i++)
{
CLLocation *current=[arrRoutePoints objectAtIndex:i];
NSLog(#"%#",[arrRoutePoints objectAtIndex:i]);
NSLog(#"Current \n[%g",current.coordinate.latitude);
NSLog(#"%g]",current.coordinate.longitude);
coord[i]=current.coordinate;
NSLog(#"\n[%g",coord[i].latitude);
NSLog(#"%g]",coord[i].longitude);
}
self.objpolyline=[MKPolyline polylineWithCoordinates:coord count:numPoints];
free(coord);
[mapView addOverlay:objpolyline];
[mapView setNeedsDisplay];
}
}

iOS OpenGL 2D rotating images (not screen)

I have for example following code (just as example, I'm building not game, I'm trying to build KNOB control by OpenGL ES, Quartz2D not does not fit, do not ask why):
Original code from here:
http://www.raywenderlich.com/9743/how-to-create-a-simple-2d-iphone-game-with-opengl-es-2-0-and-glkit-part-1
Code drawing following images on the screen, in future I'll replace this images by my KNOB:
Basically I interested to rotate only Player (the man in the left area).
I want him to rotate continuously from 0 to 360 degrees. I tried following code, but...
self.effect.transform.modelviewMatrix = GLKMatrix4Rotate(self.effect.transform.modelviewMatrix, radians(10), 0, 0, -1);
I give full screen rotating (with monsters also), but I want to rotate only one object (in this example only player in left area). Also want to note that the monsters are moving.
The code for function [sprite render]; see below.
Here is main code:
//
// SGGViewController.m
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "SGGViewController.h"
#import "SGGSprite.h"
#interface SGGViewController ()
#property (strong, nonatomic) EAGLContext *context;
#property (strong) GLKBaseEffect * effect;
#property (strong) SGGSprite * player;
#property (strong) NSMutableArray * children;
#property (assign) float timeSinceLastSpawn;
#end
#implementation SGGViewController
#synthesize effect = _effect;
#synthesize context = _context;
#synthesize player = _player;
#synthesize children = _children;
#synthesize timeSinceLastSpawn = _timeSinceLastSpawn;
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(#"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
[EAGLContext setCurrentContext:self.context];
self.effect = [[GLKBaseEffect alloc] init];
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, 1024, 0, 768, -1, 1);
self.effect.transform.projectionMatrix = projectionMatrix;
self.player = [[SGGSprite alloc] initWithFile:#"2.png" effect:self.effect];
self.player.position = GLKVector2Make(self.player.contentSize.width/2, 160);
self.children = [NSMutableArray array];
[self.children addObject:self.player];
}
- (void)addTarget {
SGGSprite * target = [[SGGSprite alloc] initWithFile:#"Target.png" effect:self.effect];
[self.children addObject:target];
int minY = target.contentSize.height/2;
int maxY = 320 - target.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
target.position = GLKVector2Make(480 + (target.contentSize.width/2), actualY);
int minVelocity = 480.0/4.0;
int maxVelocity = 480.0/2.0;
int rangeVelocity = maxVelocity - minVelocity;
int actualVelocity = (arc4random() % rangeVelocity) + minVelocity;
target.moveVelocity = GLKVector2Make(-actualVelocity, 0);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
#pragma mark - GLKViewDelegate
static inline double radians (double degrees) {return degrees * M_PI/180;}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
for (SGGSprite * sprite in self.children) {
[sprite render];
}
}
- (void)update {
self.timeSinceLastSpawn += self.timeSinceLastUpdate;
if (self.timeSinceLastSpawn > 1.0) {
self.timeSinceLastSpawn = 0;
[self addTarget];
}
for (SGGSprite * sprite in self.children) {
[sprite update:self.timeSinceLastUpdate];
}
}
#end
This is code for function [sprite render];
//
// SGGSprite.m
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "SGGSprite.h"
typedef struct {
CGPoint geometryVertex;
CGPoint textureVertex;
} TexturedVertex;
typedef struct {
TexturedVertex bl;
TexturedVertex br;
TexturedVertex tl;
TexturedVertex tr;
} TexturedQuad;
#interface SGGSprite()
#property (strong) GLKBaseEffect * effect;
#property (assign) TexturedQuad quad;
#property (strong) GLKTextureInfo * textureInfo;
#end
#implementation SGGSprite
#synthesize position = _position;
#synthesize contentSize = _contentSize;
#synthesize effect = _effect;
#synthesize quad = _quad;
#synthesize textureInfo = _textureInfo;
#synthesize moveVelocity = _moveVelocity;
- (id)initWithFile:(NSString *)fileName effect:(GLKBaseEffect *)effect {
if ((self = [super init])) {
self.effect = effect;
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
GLKTextureLoaderOriginBottomLeft,
nil];
NSError * error;
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
self.textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
if (self.textureInfo == nil) {
NSLog(#"Error loading file: %#", [error localizedDescription]);
return nil;
}
self.contentSize = CGSizeMake(self.textureInfo.width, self.textureInfo.height);
TexturedQuad newQuad;
newQuad.bl.geometryVertex = CGPointMake(0, 0);
newQuad.br.geometryVertex = CGPointMake(self.textureInfo.width, 0);
newQuad.tl.geometryVertex = CGPointMake(0, self.textureInfo.height);
newQuad.tr.geometryVertex = CGPointMake(self.textureInfo.width, self.textureInfo.height);
newQuad.bl.textureVertex = CGPointMake(0, 0);
newQuad.br.textureVertex = CGPointMake(1, 0);
newQuad.tl.textureVertex = CGPointMake(0, 1);
newQuad.tr.textureVertex = CGPointMake(1, 1);
self.quad = newQuad;
}
return self;
}
- (GLKMatrix4) modelMatrix {
GLKMatrix4 modelMatrix = GLKMatrix4Identity;
modelMatrix = GLKMatrix4Translate(modelMatrix, self.position.x, self.position.y, 0);
modelMatrix = GLKMatrix4Translate(modelMatrix, -self.contentSize.width/2, -self.contentSize.height/2, 0);
return modelMatrix;
}
static inline double radians (double degrees) {return degrees * M_PI/180;}
- (void)render {
self.effect.texture2d0.name = self.textureInfo.name;
self.effect.texture2d0.enabled = YES;
self.effect.transform.modelviewMatrix = self.modelMatrix;
[self.effect prepareToDraw];
long offset = (long)&_quad;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, geometryVertex)));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, textureVertex)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
- (void)update:(float)dt {
GLKVector2 curMove = GLKVector2MultiplyScalar(self.moveVelocity, dt);
self.position = GLKVector2Add(self.position, curMove);
}
#end
In this example you share the same functions to draw the player, the target, and the background.
You have to define a new effect and matrix independently for the player to apply a separate effect like rotation.
For example, here it is for SGGViewController.m:
//
// SGGViewController.m
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "SGGViewController.h"
#import "SGGSprite.h"
float _rotation;
#interface SGGViewController ()
#property (strong, nonatomic) EAGLContext *context;
#property (strong) GLKBaseEffect * effect;
#property (strong) GLKBaseEffect * effectPlayer; //Added For The Player
#property (strong) SGGSprite * player;
#property (strong) NSMutableArray * children;
#property (strong) NSMutableArray * childrenPlayer; //Added For The Player
#property (assign) float timeSinceLastSpawn;
#end
#implementation SGGViewController
#synthesize effect = _effect;
#synthesize effectPlayer = _effectPlayer;
#synthesize context = _context;
#synthesize player = _player;
#synthesize children = _children;
#synthesize childrenPlayer = _childrenPlayer;
#synthesize timeSinceLastSpawn = _timeSinceLastSpawn;
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(#"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
[EAGLContext setCurrentContext:self.context];
//--------------------This Is To Define Effect For The background-------------------
self.effect = [[GLKBaseEffect alloc] init];
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, 480, 0, 320, -1024, 1024);
self.effect.transform.projectionMatrix = projectionMatrix;
//----------------------------------------------------------------------------------
//--------This One For The Player ---------
self.effectPlayer = [[GLKBaseEffect alloc] init];
GLKMatrix4 projectionMatrixPlay = GLKMatrix4MakeOrtho(0, 480, 0, 320, -1024, 1024);
self.effectPlayer.transform.projectionMatrix = projectionMatrixPlay;
//----------------------------------------------------------------------------------
//----Note Here I Have Uses Another Separate Function To Init The Texture File----
self.player = [[SGGSprite alloc] initWithFilePlayer:#"2.png" effectPlayer:self.effectPlayer];
self.player.positionPlayer = GLKVector2Make(self.player.contentSizePlayer.width/2, 160);
//--The Array Setting For Target And Anything Else (Background, Splash, Etc.)---
self.children = [NSMutableArray array];
//---And This Is The Array Setting For The Player---
self.childrenPlayer = [NSMutableArray array];
[self.childrenPlayer addObject:self.player];
}
//-----While The Target As Usual--------
- (void)addTarget
{
SGGSprite * target = [[SGGSprite alloc] initWithFile:#"Target.png" effect:self.effect];
[self.children addObject:target];
int minY = target.contentSize.height/2;
int maxY = 320 - target.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
target.position = GLKVector2Make(480 + (target.contentSize.width/2), actualY);
int minVelocity = 480.0/4.0;
int maxVelocity = 480.0/2.0;
int rangeVelocity = maxVelocity - minVelocity;
int actualVelocity = (arc4random() % rangeVelocity) + minVelocity;
target.moveVelocity = GLKVector2Make(-actualVelocity, 0);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
#pragma mark - GLKViewDelegate
static inline double radians (double degrees) {return degrees * M_PI/180;}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
for (SGGSprite * sprite in self.children) {
[sprite render];
}
//--------Separate Rendering For The Player In A New Function RenderPlayer-----------
for (SGGSprite * sprite in self.childrenPlayer) {
[sprite renderPlayer];
}
}
- (void)update
{
self.timeSinceLastSpawn += self.timeSinceLastUpdate;
_rotation += self.timeSinceLastUpdate * 20; //Speed And Angle Of Rotation
if (self.timeSinceLastSpawn > 1.0) {
self.timeSinceLastSpawn = 0;
[self addTarget];
}
for (SGGSprite * sprite in self.children)
{
[sprite update:self.timeSinceLastUpdate];
}
//---Another One For The Player Note Theres A New Function Called updatePlayer---
for (SGGSprite * sprite in self.childrenPlayer)
{
[sprite updatePlayer:self.timeSinceLastUpdate rotationPlayer:_rotation];
}
}
#end
And Now For SGGSprite.m
//
// SGGSprite.m
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "SGGSprite.h"
typedef struct {
CGPoint geometryVertex;
CGPoint textureVertex;
} TexturedVertex;
typedef struct {
TexturedVertex bl;
TexturedVertex br;
TexturedVertex tl;
TexturedVertex tr;
} TexturedQuad;
typedef struct {
CGPoint geometryVertexPlayer;
CGPoint textureVertexPlayer;
} TexturedVertexPlayer;
typedef struct {
TexturedVertexPlayer bl;
TexturedVertexPlayer br;
TexturedVertexPlayer tl;
TexturedVertexPlayer tr;
} TexturedQuadPlayer;
#interface SGGSprite()
#property (strong) GLKBaseEffect * effect;
#property (strong) GLKBaseEffect * effectPlayer; //Added
#property (assign) TexturedQuad quad;
#property (strong) GLKTextureInfo * textureInfo;
#property (assign) TexturedQuadPlayer quadPlayer; //Added
#property (strong) GLKTextureInfo * textureInfoPlayer; //Added
#end
#implementation SGGSprite
#synthesize position = _position;
#synthesize positionPlayer = _positionPlayer; //Added
#synthesize contentSize = _contentSize;
#synthesize contentSizePlayer = _contentSizePlayer; //Added
#synthesize effect = _effect;
#synthesize effectPlayer = _effectPlayer; //Added
#synthesize quad = _quad;
#synthesize quadPlayer = _quadPlayer; //Added
#synthesize textureInfo = _textureInfo;
#synthesize moveVelocity = _moveVelocity;
#synthesize textureInfoPlayer = _textureInfoPlayer; //Added
#synthesize moveVelocityPlayer = _moveVelocityPlayer; //Added
int moved = 0; // to make sure the game just started
- (id)initWithFile:(NSString *)fileName effect:(GLKBaseEffect *)effect
{
if ((self = [super init]))
{
self.effect = effect;
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
GLKTextureLoaderOriginBottomLeft,
nil];
NSError * error;
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
self.textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
if (self.textureInfo == nil)
{
NSLog(#"Error loading file: %#", [error localizedDescription]);
return nil;
}
self.contentSize = CGSizeMake(self.textureInfo.width, self.textureInfo.height);
TexturedQuad newQuad;
newQuad.bl.geometryVertex = CGPointMake(0, 0);
newQuad.br.geometryVertex = CGPointMake(self.textureInfo.width, 0);
newQuad.tl.geometryVertex = CGPointMake(0, self.textureInfo.height);
newQuad.tr.geometryVertex = CGPointMake(self.textureInfo.width, self.textureInfo.height);
newQuad.bl.textureVertex = CGPointMake(0, 0);
newQuad.br.textureVertex = CGPointMake(1, 0);
newQuad.tl.textureVertex = CGPointMake(0, 1);
newQuad.tr.textureVertex = CGPointMake(1, 1);
self.quad = newQuad;
}
return self;
}
//----------The Init Function For The Player Only-------------
- (id)initWithFilePlayer:(NSString *)fileName effectPlayer:(GLKBaseEffect *)effectPlayer
{
if ((self = [super init]))
{
self.effectPlayer = effectPlayer;
NSDictionary * options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],
GLKTextureLoaderOriginBottomLeft,
nil];
NSError * error;
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
self.textureInfoPlayer = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
if (self.textureInfoPlayer == nil)
{
NSLog(#"Error loading file: %#", [error localizedDescription]);
return nil;
}
self.contentSizePlayer = CGSizeMake(self.textureInfoPlayer.width, self.textureInfoPlayer.height);
TexturedQuadPlayer newQuad;
newQuad.bl.geometryVertexPlayer = CGPointMake(0, 0);
newQuad.br.geometryVertexPlayer = CGPointMake(self.textureInfoPlayer.width, 0);
newQuad.tl.geometryVertexPlayer = CGPointMake(0, self.textureInfoPlayer.height);
newQuad.tr.geometryVertexPlayer = CGPointMake(self.textureInfoPlayer.width, self.textureInfoPlayer.height);
newQuad.bl.textureVertexPlayer = CGPointMake(0, 0);
newQuad.br.textureVertexPlayer = CGPointMake(1, 0);
newQuad.tl.textureVertexPlayer = CGPointMake(0, 1);
newQuad.tr.textureVertexPlayer = CGPointMake(1, 1);
self.quadPlayer = newQuad;
}
return self;
}
- (GLKMatrix4) modelMatrix
{
GLKMatrix4 modelMatrix = GLKMatrix4Identity;
modelMatrix = GLKMatrix4Translate(modelMatrix, self.position.x, self.position.y, 0);
modelMatrix = GLKMatrix4Translate(modelMatrix, -self.contentSize.width/2, -self.contentSize.height/2, 0);
return modelMatrix;
}
//-------------Added For The Player-----------------
- (GLKMatrix4) modelMatrixPlayer
{
GLKMatrix4 modelMatrixPlayer = GLKMatrix4Identity;
modelMatrixPlayer = GLKMatrix4Translate(modelMatrixPlayer, self.positionPlayer.x, self.positionPlayer.y, 0);
modelMatrixPlayer = GLKMatrix4Translate(modelMatrixPlayer, -self.contentSizePlayer.width/2, -self.contentSizePlayer.height/2, 0);
return modelMatrixPlayer;
}
static inline double radians (double degrees) {return degrees * M_PI/180;}
- (void)render
{
self.effect.texture2d0.name = self.textureInfo.name;
self.effect.texture2d0.enabled = YES;
self.effect.transform.modelviewMatrix = self.modelMatrix;
[self.effect prepareToDraw];
long offset = (long)&_quad;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, geometryVertex)));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, textureVertex)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
- (void)renderPlayer
{
self.effectPlayer.texture2d0.name = self.textureInfoPlayer.name;
self.effectPlayer.texture2d0.enabled = YES;
if (moved == 0) // Only Applied When You Restart Game To Position The Player In The Center
{
self.effectPlayer.transform.modelviewMatrix = self.modelMatrixPlayer;
}
[self.effectPlayer prepareToDraw];
long offset = (long)&_quadPlayer;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertexPlayer), (void *) (offset + offsetof(TexturedVertexPlayer, geometryVertexPlayer)));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertexPlayer), (void *) (offset + offsetof(TexturedVertexPlayer, textureVertexPlayer)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
- (void)update:(float)dt
{
GLKVector2 curMove = GLKVector2MultiplyScalar(self.moveVelocity, dt);
self.position = GLKVector2Add(self.position, curMove);
}
// ------------- Rotate The Object --------------------------------------------
- (void)updatePlayer:(float)rt rotationPlayer:(float)rotate
{
moved = 1;
self.effectPlayer.transform.modelviewMatrix = self.modelMatrixPlayer; //Adjust the player Location And Ready To Move
//Moving The Object
GLKVector2 curRotate = GLKVector2MultiplyScalar(self.moveVelocityPlayer, rt);
self.positionPlayer = GLKVector2Add(self.positionPlayer, curRotate);
//Rotation Section
self.effectPlayer.transform.modelviewMatrix = GLKMatrix4Rotate(self.effectPlayer.transform.modelviewMatrix, rotate, 0, 0, -1);
}
#end
Well Thats Not Everything Here Is The SGGSprite.h
//
// SGGSprite.h
// SimpleGLKitGame
//
// Created by Ray Wenderlich on 1/30/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import <GLKit/GLKit.h>
#import <Foundation/Foundation.h>
#interface SGGSprite : NSObject
#property (assign) GLKVector2 position;
#property (assign) GLKVector2 positionPlayer; //Position For The Player
#property (assign) CGSize contentSize;
#property (assign) CGSize contentSizePlayer; //Size Of The Player
#property (assign) GLKVector2 moveVelocity;
#property (assign) GLKVector2 moveVelocityPlayer; //Speed Of The Player If Moved
- (id)initWithFile:(NSString *)fileName effect:(GLKBaseEffect *)effect;
- (id)initWithFilePlayer:(NSString *)fileName effectPlayer:(GLKBaseEffect *)effectPlayer;
- (void)render;
- (void)renderPlayer;
- (void)update:(float)dt; //Move Object
- (void)updatePlayer:(float)rt rotationPlayer:(float)rotate; //Rotate Object
#end

Issue with Drawing on UIImage

I am using the following code to Draw over an image. All the touch delegates are working, but the drawing is not rendered over the UIImage. Here is the code. I am not able to identify the issue. Thanks in advance.
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self setupVariables];
}
return self;
}
- (void)drawPic:(UIImage *)thisPic {
myPic = thisPic;
[myPic retain];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
float newHeight;
float newWidth;
float xPos;
float yPos;
float ratio;
if (myPic != NULL) {
ratio = myPic.size.height/460;
if (myPic.size.width/320 > ratio) {
ratio = myPic.size.width/320;
}
newHeight = myPic.size.height/ratio;
newWidth = myPic.size.width/ratio;
xPos = (320 - newWidth) / 2;
yPos = (460 - newHeight) / 2;
[myPic drawInRect:CGRectMake(xPos, yPos, newWidth, newHeight)];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *allTouches = [[event allTouches] allObjects];
if ([allTouches count] > 1) {
return;
}
else {
[self drawPoint:[allTouches objectAtIndex:0]];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *allTouches = [[event allTouches] allObjects];
if ([allTouches count] > 1) {
return;
}
else {
[self drawPoint:[allTouches objectAtIndex:0]];
self.previousPoint = nil;
self.point = nil;
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *allTouches = [[event allTouches] allObjects];
if ([allTouches count] > 1) {
return;
}
else {
[self drawPoint:[allTouches objectAtIndex:0]];
self.previousPoint = nil;
self.point = nil;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *allTouches = [[event allTouches] allObjects];
if ([allTouches count] > 1) {
return;
}
else {
[self drawPoint:[allTouches objectAtIndex:0]];
}
}
- (void)dealloc {
CGContextRelease(offScreenBuffer);
[point release];
[previousPoint release];
[super dealloc];
}
- (void)setupVariables {
self.point = nil;
self.previousPoint = nil;
offScreenBuffer = [self setupBuffer];
}
- (CGContextRef)setupBuffer {
CGSize size = self.bounds.size;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL,size.width,size.height,8,size.width*4, colorSpace,kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
CGContextTranslateCTM(context, 0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);
return context;
}
- (void)drawToBuffer {
// Red Gr Blu Alpha
CGFloat color[4] = {0.0, 1.0, 0.0, 1.0};
if (self.previousPoint != nil) {
CGContextSetRGBStrokeColor(offScreenBuffer, color[0], color[1], color[2], color[3]);
CGContextBeginPath(offScreenBuffer);
CGContextSetLineWidth(offScreenBuffer, 10.0);
CGContextSetLineCap(offScreenBuffer, kCGLineCapRound);
CGContextMoveToPoint(offScreenBuffer, previousPoint.location.x, previousPoint.location.y);
CGContextAddLineToPoint(offScreenBuffer, point.location.x, point.location.y);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeColor);
CGContextDrawPath(offScreenBuffer, kCGPathStroke);
}
}
- (void)drawPoint:(UITouch *)touch {
PointLocation *currentLoc = [[PointLocation alloc] init];
currentLoc.location = [touch locationInView:self];
self.previousPoint = self.point;
self.point = currentLoc;
[self drawToBuffer];
[self setNeedsDisplay];
[currentLoc release];
}
It's very simple. You need to do all your drawing in drawRect: and you're only drawing the image in drawRect:, so that's why you only see the image.
-(void)drawPic:(UIImage *)thisPic {
//code for UIViewContentModeScaleAspectFit if needed
self.backgroundColor = [UIColor colorWithPatternImage:thisPic];
[self setNeedsDisplay];
}
Do Not use this in drawRect Method:
[myPic drawInRect:CGRectMake(xPos, yPos, newWidth, newHeight)];
Edit
- (void)drawRect:(CGRect)rect {
if (!myDrawing) {
// CGFloat scale = 0.5;
// CATransform3D transform = CATransform3DMakeScale(scale, scale, scale);
// [self layer].transform = transform;
myDrawing = [[NSMutableArray alloc] initWithCapacity:0];
self.lineOnOffArray = [[NSMutableArray alloc] initWithCapacity:0];
//arrPenThickness = [[NSMutableArray alloc] initWithCapacity:0];
}
CGContextRef ctx = UIGraphicsGetCurrentContext();
if ([myDrawing count] > 0) {
for (int i = 0 ; i < [myDrawing count] ; i++) {
NSArray *thisArray = [myDrawing objectAtIndex:i];
NSString *onOffFlag = [self.lineOnOffArray objectAtIndex:i];
if (([thisArray count] > 2) && (onOffFlag == #"1")){
float penT = [[arrPenThickness objectAtIndex:i] floatValue];
NSString* penC = [arrPenColors objectAtIndex:i];
NSArray *arr = [penC componentsSeparatedByString:#","];
float r = [[arr objectAtIndex:0]floatValue];
float g = [[arr objectAtIndex:1]floatValue];
float b = [[arr objectAtIndex:2]floatValue];
float a = [[arr objectAtIndex:3]floatValue];
CGContextSetRGBStrokeColor(ctx,
r/255.0,
g/255.0,
b/255.0,
a);
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, penT);
float thisX = [[thisArray objectAtIndex:0] floatValue];
float thisY = [[thisArray objectAtIndex:1] floatValue];
CGContextBeginPath(ctx);
for (int j = 2; j < [thisArray count] ; j+=2) {
CGContextMoveToPoint(ctx, thisX, thisY);
thisX = [[thisArray objectAtIndex:j] floatValue];
thisY = [[thisArray objectAtIndex:j+1] floatValue];
CGContextAddLineToPoint(ctx, thisX,thisY);
}
CGContextStrokePath(ctx);
}
}
}
}

Resources