title: iOS: How to Render-To-1-channel-Texture in GLES2
body: <p>I'm pretty sure now after hours of bashing that this cannot be done.</p>
  
  <p>This is my code so far (BELOW) for rendering to a texture;   it does the job, but is very wasteful. I only want a single 8-bit channel, possibly 16-bit greyscale. I don't want a useless R G and B channel.</p>
  
  <p>But if I try to switch GL_RGBA /*GL_ALPHA*/ in glTexImage2D,  glCheckFramebufferStatus catches a 'frame buffer incomplete' error: 36054  0x8CD6  GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT</p>
  
  <p>guys on IRC suggest GL_R  but Xcode doesn't offer autocompleteion for that,  so it looks like maybe it is one of those things pruned out of GL for GLES</p>
  
  <p>but that seems really bizarre!  this is a mobile device. Surely something that reduces by a factor of four the amount of bits needed to perform an operation...  surely this would be one of the last things to take out.</p>
  
  <p>?!?</p>
  
  <p>can anyone bury this one definitively?    Is it possible to render onto a single channel texture in GLES2.0?</p>
  
  <pre><code>+ (void)  blurTexture: (GLuint)     in_texId
               POTWidth: (GLuint)     in_W
              POTHeight: (GLuint)     in_H
         returningTexId: (GLuint*)    out_pTexId
  {
      // search HELP: 'Using a Framebuffer Object as a Texture'
      // http://stackoverflow.com/questions/3613889/gl-framebuffer-incomplete-attachment-when-trying-to-attach-texture
  
      // Create the destination texture, and attach it to the framebuffer’s color attachment point.
  
      // create the texture
      GLuint id_texDest;
      {
          // fragshader will use 0 
          glActiveTexture( GL_TEXTURE0 );
  
          // Ask GL to give us a texture-ID for us to use
          glGenTextures( 1, &amp; id_texDest );
          glBindTexture( GL_TEXTURE_2D, id_texDest );
  
  
          // actually allocate memory for this texture
          GLuint pixCount = in_W * in_H;
  
          typedef struct { uint8_t r, g, b, a } rgba;
  
          rgba * alphas = calloc( pixCount, sizeof( rgba ) );
  
          // XOR texture
          int pix=0;
          for ( int x = 0;  x &lt; in_W;  x++ )
          {
              for ( int y = 0;  y &lt; in_H;  y++ )
              {
                  //alphas[ pix ].r = (y &lt; 256) ? x^y : 0;
                  //alphas[ pix ].g = (y &lt; 512) ? 127 : 0;
                  //alphas[ pix ].b = (y &lt; 768) ? 127 : 0;
                  alphas[ pix ].a = (y &lt; 512) ? x^y : 0; // half mottled, half black
  
                  pix++;
              }
          }
  
          // set some params on the ACTIVE texture
          glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*_MIPMAP_LINEAR*/  );
          glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  
          glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
          glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  
          // WRITE/COPY from P into active texture  
          glTexImage2D( GL_TEXTURE_2D, 0,
                       GL_RGBA /*GL_ALPHA*/, in_W, in_H, 0, 
                       GL_RGBA /*GL_ALPHA*/, 
                       GL_UNSIGNED_BYTE, 
                       (void *) alphas );
  
          //glGenerateMipmap( GL_TEXTURE_2D );
  
          free( alphas );
  
          glLogAndFlushErrors();
  
      }
  
  
      GLuint textureFrameBuffer;
      {
          GLint oldFBO;
          glGetIntegerv( GL_FRAMEBUFFER_BINDING, &amp; oldFBO );
  
          // create framebuffer
          glGenFramebuffers( 1, &amp; textureFrameBuffer );
          glBindFramebuffer( GL_FRAMEBUFFER, textureFrameBuffer );
  
          // attach renderbuffer
          glFramebufferTexture2D( GL_FRAMEBUFFER, 
                                 GL_COLOR_ATTACHMENT0, 
                                 GL_TEXTURE_2D, 
                                 id_texDest, 
                                 0 );
  
          //glDisable( GL_DEPTH_TEST );
  
          // Test the framebuffer for completeness. This test only needs to be performed when the framebuffer’s configuration changes.
          GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER ) ;
          NSAssert1( status == GL_FRAMEBUFFER_COMPLETE, @"failed to make complete framebuffer object %x", status );
  
          // 36054  0x8CD6  GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
  
          // unbind frame buffer
          glBindFramebuffer( GL_FRAMEBUFFER, oldFBO );
      }
  
  
  
  
      glLogAndFlushErrors();
  
      // clear texture bitmap to backcolor
      {
          GLint oldFBO;
          glGetIntegerv( GL_FRAMEBUFFER_BINDING, &amp; oldFBO );
  
          glBindFramebuffer( GL_FRAMEBUFFER, textureFrameBuffer );
          glLogAndFlushErrors();
  
          {
              float j = 0.1f;
              glClearColor( j, j, j, j );
              glLogAndFlushErrors();
              glClear( GL_COLOR_BUFFER_BIT );
              glLogAndFlushErrors();
          }
  
          glBindFramebuffer( GL_FRAMEBUFFER, oldFBO );
      }
  
      glDeleteFramebuffers( 1, &amp; textureFrameBuffer );
  
      * out_pTexId = id_texDest;
  
      glLogAndFlushErrors();
  }
  </code></pre>