title: OpenGL 2.0 Bug - Setup and shaders work, won't draw
body: <p>I've got a UIView that loads OpenGL. The setup works fine (you can test the 'erase' call with different colors) and the shaders are compiled without error. </p>
  
  <p>The shaders are VERY basic: the vertex shader takes the position, the fragment shader always renders black. </p>
  
  <p>However, it won't draw. I've picked apart the problem for hours and can't find the bug. </p>
  
  <p>Please help. </p>
  
  <pre><code>#pragma mark Imports
  #import "ochrDrawingView.h"
  
  #pragma mark - Definitions
  #define loquacious YES
  
  
  typedef struct {
      GLfloat x;
      GLfloat y;
  } vertex;
  
  typedef vertex vector;
  
  typedef struct {
      GLfloat r;
      GLfloat g;
      GLfloat b;
      GLfloat a;
  } color;
  
  
  #pragma mark - Inline Functions
  static inline GLfloat distanceBetweenVertices (vertex one, vertex two) {
      return sqrtf((two.x - one.x) * (two.x - one.x) + (two.y - one.y) * (two.y - one.y));
  }
  
  static inline GLfloat magnitudeOfVector (vector vec) {
      return sqrtf(vec.x * vec.x + vec.y * vec.y);
  }
  
  static inline GLfloat dotProductOfVectors(vector one, vector two) {
      return (one.x *two.x + one.y * two.y);
  }
  
  static inline GLfloat crossProductOfVectors (vector one, vector two) {
      return (one.x * two.y - one.y * two.x);
  }
  
  static inline vector vectorFromVertices (vertex one, vertex two) {
      return (vector) { two.x - one.x, two.y - one.y };
  }
  
  
  
  #pragma mark - Variables and Implementation
  @implementation ochrDrawingView {
      EAGLContext *context;
      CAEAGLLayer *eaglLayer;
  
      // Buffers
      GLuint renderBuffer;
      GLuint frameBuffer;
      GLuint vertexBufferID;
  
      // The attributes in for the shader program
      GLuint positionAttribute;
      GLuint colorAttribute;
  
      GLuint shaderProgram;
  
      // The pixel dimensions of the backbuffer
      GLint backingWidth;
      GLint backingHeight;
  
      // Some BOOLs
      BOOL isFirstTouch;
  
      // The points for drawing
      CGPoint origin;
      CGPoint control;
      CGPoint destination;
  }
  
  @synthesize currentColor;
  
  #pragma mark - OpenGL setup
  
  + (Class) layerClass {
      return [CAEAGLLayer class];
  }
  
  - (void) setUpLayer {
      if (loquacious) NSLog(@"setUpLayer called in ochrDrawingView");
      eaglLayer = (CAEAGLLayer *) self.layer;
      [eaglLayer setOpaque:YES];
      [eaglLayer setDrawableProperties:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],     kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]];    
  }    
  
  - (void) setUpContext {
      if (loquacious) NSLog(@"setUpContext called in ochrDrawingView");
      context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
      [EAGLContext setCurrentContext:context];
      if (!context) {
          NSLog(@"Context failed to set up properly");
      }
  }
  
  - (void) setUpRenderBuffer {
      if (loquacious) NSLog(@"setUpRenderBuffer called in ochrDrawingView");
      glGenRenderbuffers(1, &amp;renderBuffer);
      glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
      [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer];
  }
  
  - (void) setUpFrameBuffer {
      if (loquacious) NSLog(@"setUpFrameBuffer called in ochrDrawingView");
      glGenFramebuffers(1, &amp;frameBuffer);
      glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
  }
  
  - (void) setUpViewport {
      if (loquacious) NSLog(@"setUpViewport called in ochrDrawingView");
      glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &amp;backingWidth);
  glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &amp;backingHeight);
      glViewport(0, 0, backingWidth, backingHeight);
   }
  
  - (void) setUpVertexBuffer {
      glGenBuffers(1, &amp;vertexBufferID);
  }
  
  #pragma mark - Shaders
  
  - (GLuint)compileShaderOfType:(GLenum)shaderType {
  
      NSString *shaderString;
  
      NSString *vertexString =
      @" attribute vec4 Position; "
      @" void main (void) { "
      @"      gl_Position = Position; "
      @"      gl_PointSize = 16.0; "
      @" } ";
  
      NSString *fragmentString =
      @" void main (void) { "
      @"      gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); "
      @" } " ;
  
      if (shaderType == GL_VERTEX_SHADER) {
          shaderString = vertexString;
          if (loquacious) NSLog(@"About to compile a vertex shader");
      } else if (shaderType == GL_FRAGMENT_SHADER) {
          shaderString = fragmentString;
          if (loquacious) NSLog(@"About to compile a fragment shader");
      } else {
          NSLog(@"Not a valid shader type");
      }
  
      GLuint shaderHandle = glCreateShader(shaderType);
  
      const char *shaderStringUTF8 = [shaderString UTF8String];
      int shaderStringLength = [shaderString length];
      glShaderSource(shaderHandle, 1, &amp;shaderStringUTF8, &amp;shaderStringLength);
  
      glCompileShader(shaderHandle);
  
      GLint compileSuccess;
      glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &amp;compileSuccess);
      if (compileSuccess == GL_FALSE) {
          GLchar messages[256];
          glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &amp;messages[0]);
          NSString *messageString = [NSString stringWithUTF8String:messages];
          NSLog(@"%@", messageString);
          exit(1);
      }
      return shaderHandle;
  }
  
  - (void)compileShaders {
  
      if (loquacious) NSLog(@"compileShaders called in ochrDrawingView");
      GLuint vertexShader = [self compileShaderOfType:GL_VERTEX_SHADER];
      GLuint fragmentShader = [self compileShaderOfType:GL_FRAGMENT_SHADER];
  
      shaderProgram = glCreateProgram();
      glAttachShader(shaderProgram, vertexShader);
      glAttachShader(shaderProgram, fragmentShader);
      glLinkProgram(shaderProgram);
  
      GLint linkSuccess;
      glGetProgramiv(shaderProgram, GL_LINK_STATUS, &amp;linkSuccess);
      if (linkSuccess == GL_FALSE) {
          GLchar messages[256];
          glGetProgramInfoLog(shaderProgram, sizeof(messages), 0, &amp;messages[0]);
          NSString *messageString = [NSString stringWithUTF8String:messages];
          NSLog(@"%@", messageString);
          exit(1);
      }
  
      glUseProgram(shaderProgram);
  
      positionAttribute = glGetAttribLocation(shaderProgram, "Position");
      glEnableVertexAttribArray(positionAttribute);
  }
  
  #pragma mark - Init call
  
  - (id)initWithFrame:(CGRect)frame {
      self = [super initWithFrame:frame];
      if (self) {
          if (loquacious) NSLog(@"ochrDrawingView is about to initialize.");
          [self setUpLayer];
          [self setUpContext];
          [self setContentScaleFactor:[[UIScreen mainScreen] scale]];
          [self setUpRenderBuffer];
          [self setUpFrameBuffer];
          [self setUpVertexBuffer];
          [self compileShaders];
          [self erase];
      }
      return self;
  }
  
  // Erases the screen
  - (void)erase
  {
      if (loquacious) NSLog(@"Erase called in ochrDrawingView.");
      [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 {
      origin = [[touches anyObject] locationInView:self];
      origin.y = self.bounds.size.height - origin.y;
      isFirstTouch = YES;
  }
  
  - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
      if (isFirstTouch) {
          isFirstTouch = NO;
          destination = [[touches anyObject] locationInView:self];
          destination.y = self.bounds.size.height - destination.y;
      } else {
          origin = destination;
          destination = [[touches anyObject] locationInView:self];
          destination.y = self.bounds.size.height - destination.y;
      }
  
      [self renderLineFromPoint:origin toPoint:destination];
  }
  
  // Handles the end of a touch event when the touch is a tap.
  - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
      if (isFirstTouch) {
          destination = [[touches anyObject] locationInView:self];
          destination.y = self.bounds.size.height - destination.y;
          [self renderLineFromPoint:origin toPoint:destination];
      }
  }
  
  - (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
  
  }
  
  #pragma mark - Drawing Algorithm
  
  // 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;
      NSUInteger count;
      NSUInteger i;
  
      [EAGLContext setCurrentContext:context];
      glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
  
      // 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)) / 3), 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++;
      }
  
      // Load data to the Vertex Buffer Object
      glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
      glBufferData(GL_ARRAY_BUFFER, vertexCount * 2 * sizeof(GLfloat), vertexBuffer, GL_DYNAMIC_DRAW);
  
      glEnableVertexAttribArray(positionAttribute);
      glVertexAttribPointer(positionAttribute, 2, GL_FLOAT, GL_FALSE, 0, 0);
  
      // Draw
      glUseProgram(shaderProgram);
      glDrawArrays(GL_POINTS, 0, vertexCount);
  
      // Display the buffer
      glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
      [context presentRenderbuffer:GL_RENDERBUFFER];
  }
  
  
  @end
  </code></pre>