views:

55

answers:

3

(Also asked on the Apple Developer forums)

I am new to OpenGL, so be kind :). 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);

}
+1  A: 

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.

Calvin1602
Oh, I moved that into the draw method for error checking previous and forgot to move it out. I was worried it was a texture issue at first. The image loading takes place before the at the initial page creation.I tried throwing the glBindRenderbufferOES before the calls and it didn't seem to do anything...
Ginamin
+1  A: 

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...

Calvin1602
Ah, a good find! ...but didn't fix it
Ginamin