title: glTexImage2D failing in GLUT/FreeType example with OpenGL 3 and above
body: <p>I'm using the example found here: <a href="http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_01" rel="nofollow">http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_01</a> </p>
  
  <p>The issue is that when I specify an OpenGL context with a version above 3, ie:</p>
  
  <pre><code>glutInitContextVersion (3, 2); 
  </code></pre>
  
  <p>Calling glTexImage2D results in a GL_INVALID_ENUM (as reported by GLIntercept) error and the output of the example is blank. As far as I can tell from the OpenGL 3.3 reference, this should only be happening if type is not a valid type constant or target is an invalid target.</p>
  
  <p>Here is the offending line:</p>
  
  <pre><code>glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g-&gt;bitmap.width, g-&gt;bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g-&gt;bitmap.buffer);
  </code></pre>
  
  <p>Also, I have tried modifying the example to resize the bitmap so it's dimensions are the nearest power of 2, as in the NeHe tutorial ( <a href="http://nehe.gamedev.net/tutorial/freetype_fonts_in_opengl/24001/" rel="nofollow">http://nehe.gamedev.net/tutorial/freetype_fonts_in_opengl/24001/</a> ), however I still got the same error.</p>
  
  <p>I've also tried implementing the example using GLFW and have the same problem.</p>
  
  <p>I'm using different shader loading code to the example, but shaders both compile/link fine and the example still works if I'm not specifying a modern OpenGL version.</p>
  
  <p>If it helps my environment is: 
  Windows 7 64-bit, Visual Studio 2010<br>
  AMD HD6950 Graphics with Catalyst 12.3 drivers.</p>
  
  <p>Software libraries are:<br>
  FreeGLUT 2.8.0<br>
  GLEW 1.7.0<br>
  FreeType 2.4.9<br>
  glm-0.9.3.0  </p>
  
  <hr>
  
  <p>For reference, here is gliLog.txt - I've omitted the most of the end of the log since it's the same error recurring over and over again.</p>
  
  <pre><code>GL Intercept Log. Version : 0.5    Compile Date: Dec  3 2005    Run on: Fri Jun 22 15:42:05 2012
  
  ===================================================
  Diagnostic: Unknown function wglCreateContextAttribsARB being logged.
  GL ERROR - Function wglGetPixelFormat(0x200110ef) generated error GL_INVALID_ENUM
  GL ERROR - Function glGetString(GL_VERSION) generated error GL_INVALID_ENUM
  GL ERROR - Function glGetString(GL_EXTENSIONS) generated error GL_INVALID_ENUM
  ...
  InterceptShaderGLSL::CreateObjectPost - Unknown object type 0x8dd9
  InterceptShaderGLSL::DeleteObjectPost - Unable to find shader ID 2
  GL ERROR - Function glTexImage2D(GL_TEXTURE_2D,0,GL_ALPHA,27,35,0,GL_ALPHA,GL_UNSIGNED_BYTE,0x73ab670) generated error 0x0500
  ImageSaveManager::Save2DImage - invalid width/height on image
  InterceptImage::SaveTextureImage - Error saving image 1
  GL ERROR - Function glDrawArrays(GL_TRIANGLE_STRIP,0,4) generated error 0x0502
  GL ERROR - Function glTexImage2D(GL_TEXTURE_2D,0,GL_ALPHA,20,35,0,GL_ALPHA,GL_UNSIGNED_BYTE,0x73ac300) generated error 0x0500
  ImageSaveManager::Save2DImage - invalid width/height on image
  InterceptImage::SaveTextureImage - Error saving image 0
  GL ERROR - Function glDrawArrays(GL_TRIANGLE_STRIP,0,4) generated error 0x0502
  GL ERROR - Function glTexImage2D(GL_TEXTURE_2D,0,GL_ALPHA,23,28,0,GL_ALPHA,GL_UNSIGNED_BYTE,0x73ac580) generated error 0x0500
  ImageSaveManager::Save2DImage - invalid width/height on image
  InterceptImage::SaveTextureImage - Error saving image 0
  </code></pre>
  
  <p>And here is the example code</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;math.h&gt;
  #include &lt;GL/glew.h&gt;
  #include &lt;GL/freeglut.h&gt;
  /* Using GLM for our transformation matrix */
  #include &lt;glm/glm.hpp&gt;
  #include &lt;glm/gtc/matrix_transform.hpp&gt;
  #include &lt;glm/gtc/type_ptr.hpp&gt;
  /* Using FreeType 2 for rendering fonts */
  #include &lt;ft2build.h&gt;
  #include FT_FREETYPE_H
  #include "shader_utils.h"
  
  #pragma comment(lib, "opengl32.lib")
  #pragma comment(lib, "glew32.lib")
  #pragma comment(lib, "freeglut.lib")
  #pragma comment(lib, "freetypeD.lib")
  
  GLuint program;
  GLint attribute_coord;
  GLint uniform_tex;
  GLint uniform_color;
  
  struct point {
      GLfloat x;
      GLfloat y;
      GLfloat s;
      GLfloat t;
  };
  
  GLuint vbo;
  
  FT_Library ft;
  FT_Face face;
  
  const char *fontfilename;
  
  int init_resources()
  {
  
      /* Initialize the FreeType2 library */
      if(FT_Init_FreeType(&amp;ft)) {
          fprintf(stderr, "Could not init freetype library\n");
          return 0;
      }
  
      /* Load a font */
      if(FT_New_Face(ft, fontfilename, 0, &amp;face)) {
          fprintf(stderr, "Could not open font %s\n", fontfilename);
          return 0;
      }
  
      /* Compile and link the shader program */
      GLint link_ok = GL_FALSE;
  
      program = text::LoadShader("text.v.glsl", NULL, "text.f.glsl");
  
      const char* attribute_name;
      attribute_name = "coord";
      attribute_coord = glGetAttribLocation(program, attribute_name);
      if (attribute_coord == -1) {
          fprintf(stderr, "Could not bind attribute %s\n", attribute_name);
          return 0;
      }
  
      const char* uniform_name;
      uniform_name = "tex";
      uniform_tex = glGetUniformLocation(program, uniform_name);
      if (uniform_tex == -1) {
          fprintf(stderr, "Could not bind uniform %s\n", uniform_name);
          return 0;
      }
  
      uniform_name = "color";
      uniform_color = glGetUniformLocation(program, uniform_name);
      if (uniform_color == -1) {
          fprintf(stderr, "Could not bind uniform %s\n", uniform_name);
          return 0;
      }
  
      // Create the vertex buffer object
      glGenBuffers(1, &amp;vbo);
  
      return 1;
  }
  
  /**
      * Render text using the currently loaded font and currently set font size.
      * Rendering starts at coordinates (x, y), z is always 0.
      * The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy).
      */
  void render_text(const char *text, float x, float y, float sx, float sy) {
      const char *p;
      FT_GlyphSlot g = face-&gt;glyph;
  
      /* Create a texture that will be used to hold one "glyph" */
      GLuint tex;
      glActiveTexture(GL_TEXTURE0);
      glGenTextures(1, &amp;tex);
      glBindTexture(GL_TEXTURE_2D, tex);
      glUniform1i(uniform_tex, 0);
  
      /* We require 1 byte alignment when uploading texture data */
      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  
      /* Clamping to edges is important to prevent artifacts when scaling */
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  
      /* Linear filtering usually looks best for text */
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  
      /* Set up the VBO for our vertex data */
      glEnableVertexAttribArray(attribute_coord);
      glBindBuffer(GL_ARRAY_BUFFER, vbo);
      glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
  
      /* Loop through all characters */
      for(p = text; *p; p++) {
          /* Try to load and render the character */
          if(FT_Load_Char(face, *p, FT_LOAD_RENDER))
              continue;
  
          /* Upload the "bitmap", which contains an 8-bit grayscale image, as an alpha texture */
          glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g-&gt;bitmap.width, g-&gt;bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g-&gt;bitmap.buffer);
  
          /* Calculate the vertex and texture coordinates */
          float x2 = x + g-&gt;bitmap_left * sx;
          float y2 = -y - g-&gt;bitmap_top * sy;
          float w = g-&gt;bitmap.width * sx;
          float h = g-&gt;bitmap.rows * sy;
  
          point box[4] = {
              {x2,     -y2    , 0, 0},
              {x2 + w, -y2    , 1, 0},
              {x2,     -y2 - h, 0, 1},
              {x2 + w, -y2 - h, 1, 1},
          };
  
          /* Draw the character on the screen */
          glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
          glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  
          /* Advance the cursor to the start of the next character */
          x += (g-&gt;advance.x &gt;&gt; 6) * sx;
          y += (g-&gt;advance.y &gt;&gt; 6) * sy;
      }
  
      glDisableVertexAttribArray(attribute_coord);
      glDeleteTextures(1, &amp;tex);
  }
  
  void display()
  {
      float sx = 2.0 / glutGet(GLUT_WINDOW_WIDTH);
      float sy = 2.0 / glutGet(GLUT_WINDOW_HEIGHT);
  
      glUseProgram(program);
  
      /* White background */
      glClearColor(1, 1, 1, 1);
      glClear(GL_COLOR_BUFFER_BIT);
  
      /* Enable blending, necessary for our alpha texture */
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  
      GLfloat black[4] = {0, 0, 0, 1};
      GLfloat red[4] = {1, 0, 0, 1};
      GLfloat transparent_green[4] = {0, 1, 0, 0.5};
  
      /* Set font size to 48 pixels, color to black */
      FT_Set_Pixel_Sizes(face, 0, 48);
      glUniform4fv(uniform_color, 1, black);
  
      /* Effects of alignment */
      render_text("The Quick Brown Fox Jumps Over The Lazy Dog",          -1 + 8 * sx,   1 - 50 * sy,    sx, sy);
      render_text("The Misaligned Fox Jumps Over The Lazy Dog",           -1 + 8.5 * sx, 1 - 100.5 * sy, sx, sy);
  
      /* Scaling the texture versus changing the font size */
      render_text("The Small Texture Scaled Fox Jumps Over The Lazy Dog", -1 + 8 * sx,   1 - 175 * sy,   sx * 0.5, sy * 0.5);
      FT_Set_Pixel_Sizes(face, 0, 24);
      render_text("The Small Font Sized Fox Jumps Over The Lazy Dog",     -1 + 8 * sx,   1 - 200 * sy,   sx, sy);
      FT_Set_Pixel_Sizes(face, 0, 48);
      render_text("The Tiny Texture Scaled Fox Jumps Over The Lazy Dog",  -1 + 8 * sx,   1 - 235 * sy,   sx * 0.25, sy * 0.25);
      FT_Set_Pixel_Sizes(face, 0, 12);
      render_text("The Tiny Font Sized Fox Jumps Over The Lazy Dog",      -1 + 8 * sx,   1 - 250 * sy,   sx, sy);
      FT_Set_Pixel_Sizes(face, 0, 48);
  
      /* Colors and transparency */
      render_text("The Solid Black Fox Jumps Over The Lazy Dog",          -1 + 8 * sx,   1 - 430 * sy,   sx, sy);
  
      glUniform4fv(uniform_color, 1, red);
      render_text("The Solid Red Fox Jumps Over The Lazy Dog",            -1 + 8 * sx,   1 - 330 * sy,   sx, sy);
      render_text("The Solid Red Fox Jumps Over The Lazy Dog",            -1 + 28 * sx,  1 - 450 * sy,   sx, sy);
  
      glUniform4fv(uniform_color, 1, transparent_green);
      render_text("The Transparent Green Fox Jumps Over The Lazy Dog",    -1 + 8 * sx,   1 - 380 * sy,   sx, sy);
      render_text("The Transparent Green Fox Jumps Over The Lazy Dog",    -1 + 18 * sx,  1 - 440 * sy,   sx, sy);
  
      glutSwapBuffers();
  }
  
  void free_resources()
  {
      glDeleteProgram(program);
  }
  
  int main(int argc, char* argv[]) {
      glutInitContextVersion (3, 2);
      glutInitContextFlags (GLUT_FORWARD_COMPATIBLE | GLUT_DEBUG);
      glutInit(&amp;argc, argv);
      glutInitDisplayMode(GLUT_RGBA|GLUT_ALPHA|GLUT_DOUBLE);
      glutInitWindowSize(640, 480);
      glutCreateWindow("Basic Text");
  
      if(argc &gt; 1)
          fontfilename = argv[1];
      else
          fontfilename = "FreeSans.ttf";
  
      GLenum glew_status = glewInit();
      if (GLEW_OK != glew_status) {
          fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status));
          return 1;
      }
  
      if (!GLEW_VERSION_2_0) {
          fprintf(stderr, "No support for OpenGL 2.0 found\n");
          return 1;
      }
      if (init_resources()) {
          glutDisplayFunc(display);
          glutMainLoop();
      }
  
      free_resources();
      return 0;
  }
  </code></pre>