Reputation: 1608
(Also asked on the Apple Developer forums)
I seem to have a rendering issue with OpenGL. My app is supposed to draw a line as the user traces his finger across the screen. So, touchesMoved calls the draw function below and passes a NSMutableArray currentStroke which contains point data.
The issue I am having is that the last triangle drawn for each line (each line ends with touchesEnded) flickers. I think it has to do with the render buffer... If I call the draw function twice from touchesEnded, the flickering goes away. I just think that is a very, very jimmy-rigged solution. Anyone have an idea of what could cause the flickering and a solution?
- (void)draw {
glLoadIdentity();
//Configuring OpenGL
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//Texture Loading
GLuint texture[1];
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
//Configuring Image for OpenGL Texture: Switch off mipmap; Set linear scaling
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
//Set image to texture
NSString *path = [[NSBundle mainBundle] pathForResource:@"at2" ofType:@"png"];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil)
NSLog(@"No Image");
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef context2 = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast |kCGBitmapByteOrder32Big );
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context2, CGRectMake( 0, 0, width, height ) );
CGContextTranslateCTM( context2, 0, height - height );
CGContextDrawImage( context2, CGRectMake( 0, 0, width, height ), image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(context2);
free(imageData);
[image release];
[texData release];
static const GLfloat texCoords[] = {
0.0, 1.0,
1.0, 1.0,
1.0, 0.0,
0.0, 0.0
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
GLfloat vertices[8];
GLfloat xadjust;
GLfloat yadjust;
//Iterate through points and create triangles
if ( (currentStroke != nil) && ([currentStroke count] > 1)) {
for (int i=0; i<([currentStroke count]-1); i++) {
vertices[0] = [[currentStroke objectAtIndex:i] CGPointValue].x;
vertices[1] = self.frame.size.height - [[currentStroke objectAtIndex:i] CGPointValue].y;
vertices[2] = [[currentStroke objectAtIndex:i+1] CGPointValue].x;
vertices[3] = self.frame.size.height - [[currentStroke objectAtIndex:i+1] CGPointValue].y;
//Minimum width of triangle
xadjust = -4;
//Minimum height of triangle, increase of y aspect of triangle is short
if ((vertices[3]-vertices[1])<1&&(vertices[3]-vertices[1])>=0) {
yadjust = 2;
} else if ((vertices[3]-vertices[1])>-1&&(vertices[3]-vertices[1])<=0){
yadjust = -3;
} else {
yadjust = 2;
}
vertices[4] = [[currentStroke objectAtIndex:i] CGPointValue].x+xadjust;
vertices[5] = self.frame.size.height - [[currentStroke objectAtIndex:i] CGPointValue].y+yadjust;
vertices[6] = [[currentStroke objectAtIndex:i+1] CGPointValue].x+xadjust;
vertices[7] = self.frame.size.height - [[currentStroke objectAtIndex:i+1] CGPointValue].y+yadjust;
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
glDisable(GL_BLEND);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
Upvotes: 0
Views: 404
Reputation: 1608
Should have posted this when I figured it out, but better late than never. By setting kEAGLDrawablePropertyRetainedBacking to true, it stopped flickering. The app also flickered when I just used glClear() once (had to use it twice), but setting the retained background property fixed this as well. I'm still not entirely sure why the flickering happened. It was obviously a double buffer issue since it flickered on every other frame.
Upvotes: 0
Reputation: 9547
oh, I thing I got it.
for (int i=0; i<([currentStroke count]-1); i++)
vertices[2] = [[currentStroke objectAtIndex:i+1] CGPointValue].x;
so you access [currentStroke count] -1 +1 -> out of bounds for (int i=0; i<([currentStroke count]-2); i++), and make sure count > 2...
Upvotes: 1
Reputation: 9547
Not directly related to the question, but you load the image each and every time you draw, don't you ? (or maybe not, but I'm puzzled by objective-c's syntax) If you do, it's not a good thing. Especially initWithData:texData and glTexImage2D should be done only once, outside draw().
For the flickering, it's usually a double-buffering issue, but on iPhone it's always a double-buffer.
I think you should call glBindRenderbufferOES before the actual draw calls, though.
Upvotes: 1