I develop in OpenGL using C# as programming language.
I want to draw some text on the screen. For this i created a texture that contains all the characters.

Now i am not sure how to continue. I can draw now every character like this:

    Gl.glTexCoord2f(posX, posY);
    Gl.glVertex2f(-1, -1);

    Gl.glTexCoord2f(posX + size, posY);
    Gl.glVertex3f(1, -1);

    Gl.glTexCoord2f(posX + size, posY + size);
    Gl.glVertex3f(1, 1);

    Gl.glTexCoord2f(posX, posY + size);
    Gl.glVertex3f(-1, 1);

posX and posY contain the start position of the character in the character-texture. size is the size of the character in the texture.

This method needs a lot of draw calls. I mean i draw lots of quads but i only need one where i can put all the text on it. How can i improve my code?


1 Answer 1


In my engine, I use a dynamic vertex buffer for batching up text data (each character == 1 vertex) and do point-to-quad expansion in geometry shader.

As far as I know, glVertex*, glNormal*, glTexCoord* are considered obsolete (like display lists) and are not recommended to use.

This gives a comprehensive overview of various OpenGL-based text rendering techniques:

The details of the technique I'm using:

Offline: 0) prepare a font texture atlas (with tightly packed glyphs, block-compressed) and remember glyph data (position, size, unicode => glyph index mapping); for these purposes I use MakeSpriteFont from DirectX Tool Kit.

At launch time:

  1. load the font texture and glyph data (submit data of each mipmap level to glCompressedTexSubImage2D);
  2. create a dynamic vertex buffer (GL_DYNAMIC_DRAW) for holding MAX_TEXT_LENGTH vertices;

At draw time: 4) parse the submitted text string and update the VBO using the glyph data; 5) draw the points from VBO

glBindBuffer( GL_ARRAY_BUFFER, dynamicVBO_id );
glDrawArrays( GL_POINTS, 0/*first vertex*/, vertexCount/*==character count*/ );

My vertex shader code:

#version 420 core

in vec4 a_texCoord0;    // .xy - center position, .zw - width and height
in vec4 a_texCoord1;    // st coords for top left and bottom right corners

out VSO {
    vec4 xy_wh;
    vec4 tl_br;
} outputs;

void main()
    // gl_Position will be written by geometry shader
    outputs.xy_wh = a_texCoord0;
    outputs.tl_br = a_texCoord1;

Geometry shader code:

#version 420 core

layout(points) in;
layout(triangle_strip, max_vertices=4) out;

in VSO {
    vec4 xy_wh;
    vec4 tl_br; // UVs for top left and bottom right corners
} inputs[];

out GSO {
    vec2 texCoord;
} outputs;

void main()
    vec2    pos = inputs[0].xy_wh.xy;
    float   width = inputs[0].xy_wh.z;
    float   height = inputs[0].xy_wh.w;

    vec2    tl = inputs[0].tl_br.xy;
    vec2    br = inputs[0].tl_br.zw;

    gl_Position = vec4( pos.x, pos.y, 0.0f, 1.0f );
    outputs.texCoord = vec2( tl.x, tl.y );

    gl_Position = vec4( pos.x + width, pos.y, 0.0f, 1.0f );
    outputs.texCoord = vec2( br.x, tl.y );

    gl_Position = vec4( pos.x, pos.y - height, 0.0f, 1.0f );
    outputs.texCoord = vec2( tl.x, br.y );

    gl_Position = vec4( pos.x + width, pos.y - height, 0.0f, 1.0f );
    outputs.texCoord = vec2( br.x, br.y );


Fragment shader code:

#version 420 core

in GSO {
    vec2 texCoord;
} inputs;

out vec4 o_pixelColor;

uniform sampler2D s_font;

void main()
    vec4 textureColor = texture( s_font, inputs.texCoord ).rgba;
    if( textureColor.w < 1.0/255.0 ) {
    o_pixelColor = textureColor;

I'm not in any way proficient in OpenGL.

  • \$\begingroup\$ This will be a better answer if you showed how you are doing the geometry shader point to quad expansion. \$\endgroup\$
    – concept3d
    Dec 29, 2013 at 14:05
  • \$\begingroup\$ Can you explain your technique more detailed please? I am a beginner in OpenGL. Do you create a vertex buffer object? \$\endgroup\$
    – fedab
    Dec 29, 2013 at 14:10
  • \$\begingroup\$ From where do you have the information about the obsolete functions? I searched and only found out that quads are obsolete (use triangles instead) and display lists (vbo instead). \$\endgroup\$
    – fedab
    Dec 30, 2013 at 18:19
  • \$\begingroup\$ He is using triangles in a trianglestrip to create quads in the geometry shader. You can also do it by creating these on the cpu and uploading them to the vertex buffer if you don't want to learn geometry shaders yet. \$\endgroup\$ Dec 31, 2013 at 14:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .