title: FreeType add border to text
body: <p>I've made an OpenGL c++ program that can display some text into the screen. Is there a freetype function that allows me to create bordered text?</p>
  <p>Here is what I have so far:</p>
  <pre class="lang-cpp prettyprint-override"><code>
  #include &quot;text_render.h&quot;
  
  namespace OpenGL {
  
  void Text::render_text(std::string text, float x, float y, float z, float scale, std::string hex_color, float angle_rad, bool bg)
  {   
      shader.use();
      glUniform3f(glGetUniformLocation(shader.ID, &quot;textColor&quot;), 0.1, 0.1, 0.1);
      glActiveTexture(GL_TEXTURE0);
      glBindVertexArray(VAO);
  
      GLfloat vertices[6][4] = {
          { 0.0,  1.0,   0.0, 0.0 },
          { 0.0,  0.0,   0.0, 1.0 },
          { 1.0,  0.0,   1.0, 1.0 },
  
          { 0.0,  1.0,   0.0, 0.0 },
          { 1.0,  0.0,   1.0, 1.0 },
          { 1.0,  1.0,   1.0, 0.0 }
      };
  
      glBindBuffer(GL_ARRAY_BUFFER, VBO);
      glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData
      glBindBuffer(GL_ARRAY_BUFFER, 0);
  
  
      glm::mat4 rotateM = glm::rotate(glm::mat4(1.0f), glm::radians(angle_rad), glm::vec3(0.0f, 0.0f, 1.0f));
      glm::mat4 transOriginM = glm::translate(glm::mat4(1.0f), glm::vec3(x, y, z));
  
      std::string::const_iterator c;
      GLfloat char_x = 0.0f;
      for (c = text.begin(); c != text.end(); c++)
      {
          Character ch = Characters[*c];
  
          GLfloat w = ch.Size.x * scale;
          GLfloat h = ch.Size.y * scale;
          GLfloat xrel = char_x + ch.Bearing.x * scale;
          GLfloat yrel = y - (ch.Size.y - ch.Bearing.y) * scale;
  
          char_x += (ch.Advance &gt;&gt; 6) * scale; // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
  
          glm::mat4 scaleM = glm::scale(glm::mat4(1.0f), glm::vec3(w, h, 1.0f));
          glm::mat4 transRelM = glm::translate(glm::mat4(1.0f), glm::vec3(xrel, yrel, z));
  
          glm::mat4 modelM = transOriginM * rotateM * transRelM * scaleM;
  
          GLint model_loc = glGetUniformLocation(shader.ID, &quot;model&quot;);
          glUniformMatrix4fv(model_loc, 1, GL_FALSE, glm::value_ptr(modelM));
  
          glBindTexture(GL_TEXTURE_2D, ch.TextureID);
  
          glDrawArrays(GL_TRIANGLES, 0, 6);
      }
      glBindVertexArray(0);
      glBindTexture(GL_TEXTURE_2D, 0);
  }
  
  Text::Text(){}
  
  Text::Text(std::string* __font_name, int gl_width, int gl_height) 
      :SCR_WIDTH(gl_width), SCR_HEIGHT(gl_height)
  {
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      
  
      shader = Shader(&quot;./src/opengl/shaders/text.vs&quot;, &quot;./src/opengl/shaders/text.fs&quot;);
  
      glm::mat4 projection = glm::ortho(0.0f, static_cast&lt;float&gt;(SCR_WIDTH), 0.0f, static_cast&lt;float&gt;(SCR_HEIGHT));
      shader.use();
      glUniformMatrix4fv(glGetUniformLocation(shader.ID, &quot;projection&quot;), 1, GL_FALSE, glm::value_ptr(projection));
  
      if (FT_Init_FreeType(&amp;ft))
      {
          VI_ERROR(&quot;ERROR::FREETYPE: Could not init FreeType Library&quot;);
          exit(0);
      }
  
      std::string font_name = &quot;./src/opengl/fonts/&quot; + *__font_name +  &quot;.ttf&quot;;
      
      FT_Face face;
      if (FT_New_Face(ft, font_name.c_str(), 0, &amp;face)) {
          VI_ERROR(&quot;ERROR::FREETYPE: Failed to load font&quot;);
          exit(0) ;
      }
      else {
          FT_Set_Pixel_Sizes(face, 0, 48);
  
          glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  
          for (unsigned char c = 0; c &lt; 128; c++)
          {
              if (FT_Load_Char(face, c, FT_LOAD_RENDER))
              {
                  VI_ERROR(&quot;ERROR::FREETYTPE: Failed to load Glyph&quot;);
                  continue;
              }
              GLuint texture;
              glGenTextures(1, &amp;texture);
              glBindTexture(GL_TEXTURE_2D, texture);
              glTexImage2D(
                  GL_TEXTURE_2D,
                  0,
                  GL_RED,
                  face-&gt;glyph-&gt;bitmap.width,
                  face-&gt;glyph-&gt;bitmap.rows,
                  0,
                  GL_RED,
                  GL_UNSIGNED_BYTE,
                  face-&gt;glyph-&gt;bitmap.buffer
              );
              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);
              Character character = {
                  texture,
                  glm::ivec2(face-&gt;glyph-&gt;bitmap.width, face-&gt;glyph-&gt;bitmap.rows),
                  glm::ivec2(face-&gt;glyph-&gt;bitmap_left, face-&gt;glyph-&gt;bitmap_top),
                  static_cast&lt;unsigned int&gt;(face-&gt;glyph-&gt;advance.x)
              };
              Characters.insert(std::pair&lt;char, Character&gt;(c, character));
          }
          glBindTexture(GL_TEXTURE_2D, 0);
      }
      FT_Done_Face(face);
      FT_Done_FreeType(ft);
      
      glGenVertexArrays(1, &amp;VAO);
      glGenBuffers(1, &amp;VBO);
      glBindVertexArray(VAO);
      glBindBuffer(GL_ARRAY_BUFFER, VBO);
      glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
      glEnableVertexAttribArray(0);
      glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
      glBindBuffer(GL_ARRAY_BUFFER, 0);
      glBindVertexArray(0);
  }
  }
  </code></pre>
  <p>vertex shader:</p>
  <pre><code>#version 300 es
  precision mediump float;
  layout (location = 0) in vec4 in_attr;
  out vec2 vUV;
  uniform mat4 projection;
  uniform mat4 model;
  
  void main()
  {
      vUV         = in_attr.zw;
          gl_Position = projection * model * vec4(in_attr.xy, 1.0f, 1.0f);
  }
  
  </code></pre>
  <p>fragment shader:</p>
  <pre><code>#version 300 es
  precision mediump float;
  
  in vec2 vUV;
  uniform sampler2D u_texture;
  uniform vec3 textColor;
  out vec4 fragColor;
  void main()
  {
      vec2 uv = vUV.xy;
      float text = texture(u_texture, uv).r;
      fragColor = vec4(textColor.rgb*text, text);
  }
  </code></pre>