title: How to render text with PyOpenGL?
body: <p>I'm learning modern openGL, and at this moment I'm facing trouble with rendering text. I'm following this <a href="https://learnopengl.com/In-Practice/Text-Rendering" rel="nofollow noreferrer">tutorial</a> which is in C++, but I'm trying to implement in python.</p>
  <p>Here is my code:</p>
  <pre class="lang-py prettyprint-override"><code>from OpenGL.GL import *
  from OpenGL.GLU import *
  
  from OpenGL.GL import shaders
  
  import glfw
  import freetype
  import glm
  
  import numpy as np
  from PIL import Image
  import math
  import time
  
  
  class CharacterSlot:
      def __init__(self, texture, glyph):
          self.texture = texture
          self.textureSize = (glyph.bitmap.width, glyph.bitmap.rows)
  
          if isinstance(glyph, freetype.GlyphSlot):
              self.bearing = (glyph.bitmap_left, glyph.bitmap_top)
              self.advance = glyph.advance.x
          elif isinstance(glyph, freetype.BitmapGlyph):
              self.bearing = (glyph.left, glyph.top)
              self.advance = None
          else:
              raise RuntimeError('unknown glyph type')
  
  def _get_rendering_buffer(xpos, ypos, w, h, zfix=0.0):
      return np.asarray([
          xpos, ypos - h, zfix, 0.0, 1.0,
          xpos, ypos, zfix, 0.0, 0.0,
          xpos + w, ypos, zfix, 1.0, 0.0,
          xpos, ypos - h, zfix, 0.0, 1.0,
          xpos + w, ypos, zfix, 1.0, 0.0,
          xpos + w, ypos - h, zfix, 1.0, 1.0
      ], np.float32)
  
  
  VERTEX_SHADER = &quot;&quot;&quot;
          #version 330 core
          layout (location = 0) in vec4 vertex; // &lt;vec2 pos, vec2 tex&gt;
          out vec2 TexCoords;
  
          uniform mat4 projection;
  
          void main()
          {
              gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
              TexCoords = vertex.zw;
          }
  
  
         &quot;&quot;&quot;
  
  FRAGMENT_SHADER = &quot;&quot;&quot;
          #version 330 core
          in vec2 TexCoords;
          out vec4 color;
  
          uniform sampler2D text;
          uniform vec3 textColor;
  
          void main()
          {    
              vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
              color = vec4(textColor, 1.0) * sampled;
          }
  
          &quot;&quot;&quot;
  
  shaderProgram = None
  Characters = dict()
  VBO = None
  VAO = None
  
  def initliaze():
      global VERTEXT_SHADER
      global FRAGMENT_SHADER
      global shaderProgram
      global Characters
      global VBO
      global VAO
  
      #compiling shaders
      vertexshader = shaders.compileShader(VERTEX_SHADER, GL_VERTEX_SHADER)
      fragmentshader = shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)
  
      #creating shaderProgram
      shaderProgram = shaders.compileProgram(vertexshader, fragmentshader)
  
      #get projection
      #problem
      
      shader_projection = glGetUniformLocation(shaderProgram, &quot;projection&quot;)
      projection = glm.ortho(0.0,640,0.0,640)
      glUniformMatrix4fv(shader_projection, 1, GL_FALSE, glm.value_ptr(projection));
      
      #disable byte-alignment restriction
      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  
      face = freetype.Face(&quot;Vera.ttf&quot;)
      face.set_char_size( 48*64 )
  
      #load first 128 characters of ASCII set
      for i in range(0,128):
          face.load_char(chr(i))
          glyph = face.glyph
          
          #generate texture
          texture = glGenTextures(1)
          glBindTexture(GL_TEXTURE_2D, texture)
          glTexImage2D(GL_TEXTURE_2D,
                       0,
                       GL_RGB,
                       glyph.bitmap.width, glyph.bitmap.rows,
                       0,
                       GL_RGB,
                       GL_UNSIGNED_BYTE,
                       glyph.bitmap.buffer)
  
          #texture options
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  
          #now store character for later use
          Characters[chr(i)] = CharacterSlot(texture,glyph)
          
      glBindTexture(GL_TEXTURE_2D, 0);
  
      #configure VAO/VBO for texture quads
      VAO = glGenVertexArrays(1)
      glBindVertexArray(VAO)
      
      VBO = glGenBuffers(1);
      glBindBuffer(GL_ARRAY_BUFFER, VBO);
      glBufferData(GL_ARRAY_BUFFER, 6 * 4, None, GL_DYNAMIC_DRAW);
      glEnableVertexAttribArray(0);
      glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4, 0);
      glBindBuffer(GL_ARRAY_BUFFER, 0);
      glBindVertexArray(0);
      
  def render_text(window,text,x,y,scale,color):
      global shaderProgram
      global Characters
      global VBO
      global VAO
      
      face = freetype.Face(&quot;Vera.ttf&quot;)
      face.set_char_size(48*64)
      glUniform3f(glGetUniformLocation(shaderProgram, &quot;textColor&quot;),
                  color[0]/255,color[1]/255,color[2]/255)
                 
      glActiveTexture(GL_TEXTURE0);
      
  
      for c in text:
          ch = Characters[c]
          w,h = ch.textureSize
          w = w*scale
          h = w*scale
          vertices = _get_rendering_buffer(x,y,w,h)
  
          #render glyph texture over quad
          glBindTexture(GL_TEXTURE_2D, ch.texture);
          #update content of VBO memory
          glBindBuffer(GL_ARRAY_BUFFER, VBO);
          glBufferSubData(GL_ARRAY_BUFFER, 0, len(vertices), vertices)
  
          glBindBuffer(GL_ARRAY_BUFFER, 0);
          #render quad
          glDrawArrays(GL_TRIANGLES, 0, 6);
          #now advance cursors for next glyph (note that advance is number of 1/64 pixels)
          x += (ch.advance+6)*scale;
  
      glBindVertexArray(0);
      glBindTexture(GL_TEXTURE_2D, 0);
  
      glfwSwapBuffers(window);
      glfwPollEvents();
      
  def main():
      glfw.init()
      window = glfw.create_window(640, 640,&quot;EXAMPLE PROGRAM&quot;,None,None)
      
      glfw.make_context_current(window)
  
      
      initliaze()
      while not glfw.window_should_close(window):
          glfw.poll_events()
          glClearColor(0,0,0,1);
          glClear(GL_COLOR_BUFFER_BIT);
          render_text(window,'hello',1,1,1,(100,100,100))
  
          
      glfw.terminate()
  
  
  if __name__ == '__main__':
      main()
  
  </code></pre>
  <p>I'm facing trouble in two portion so far I can understand. The first problem in <em>initliaze()</em>, error raised for the following portion.</p>
  <pre class="lang-py prettyprint-override"><code>    shader_projection = glGetUniformLocation(shaderProgram, &quot;projection&quot;)
      projection = glm.ortho(0.0,640,0.0,640)
      glUniformMatrix4fv(shader_projection, 1, GL_FALSE, glm.value_ptr(projection));
  </code></pre>
  <p>I've commented out the above portion to ignore. The second problem is in <em>render_text()</em> function, error raised for the following portion.</p>
  <pre class="lang-py prettyprint-override"><code>glUniform3f(glGetUniformLocation(shaderProgram, &quot;textColor&quot;),
                  color[0]/255,color[1]/255,color[2]/255)
  </code></pre>
  <p>There could be problems in many more places. I don't understand that why text rendering will be so difficult. What am I missing here?</p>