Sign in to follow this  

OpenGL Text in openGL

Recommended Posts

mpledge52    138
At the minute I'm using bitmap fonts and print_bitmap_string() to display text on screen. The problem I have is that it only allows me to use 7 different fonts. These fonts are all too 'skinny' which is quite hard to see on screen, I need bold text really. The trouble is that this print_bitmap_string() function is absolutely perfect for what I need -apart from the limited fonts- it is easy to place on screen, it stays the same size and always rotates to face the camera etc. However I think I need to use another method to display my text. Is there any other method which is similar but has a wider range of fonts? Ideally what I need to do is draw the character in white and have a black outline round each letter. However, if that is quite hard then I should be able to cope with a simple "chunky" font. Any ideas? Thanks.

Share this post

Link to post
Share on other sites
mpledge52    138
Well I've just looked for the function and I cant find it anywhere, I must of got it from some sample code or a tutorial somewhere. But anyhow, with the print_bitmap_string() function I can only use the following fonts:


The code I've got to print something is:

char string[0][256];
string[0][0] = 'H'; string[0][1] = 'e'; string[0][2] = 'l'; string[0][3] = 'p';

glRasterPos3f(42000, 75000, -3000);
print_bitmap_string( GLUT_BITMAP_9_BY_15 , string[0]);

That's all I do, I've not included any fancy libraries or anything.
I'll have to look through some tutorials, maybe I'm using the wrong type of function to use bitmap fonts.

***edit*** Sorry, just realised that the print_bitmap_string function actually makes a call to glutBitmapCharacter() function. No wonder I couldn't find it anywhere... :-S

[Edited by - mpledge52 on February 22, 2008 2:18:56 PM]

Share this post

Link to post
Share on other sites
snoutmate    362
Yeah, the GLUT has only few fonts hardcoded as (small) bitmaps. You can use font libraries like freetype or SDL_TTF to load and render any truetype font you want to image(s), then use it as texture. There is also a Nehe tutorial on bitmap fonts although it uses some os-specific functions.

Share this post

Link to post
Share on other sites
mpledge52    138
Thanks snoutmate, do you know if the bitmap fonts used in the Nehe tutorial (or any other fonts for that matter) behave in the same way as the bitmap fonts I have used so far? i.e. the stay the same size no matter where the camera is positioned, and (more importantly) the text rotates to face the camera at all times.

Thanks again.

Share this post

Link to post
Share on other sites
snoutmate    362
That is different thing alltogether - if you want something drawn this way (text, HUD in games, etc.), you simply draw your scene, then set orthogonal projection matrix (glOrtho) and render the text (you'd also want to disable things like depth buffer and lighting usually for this pass).

Share this post

Link to post
Share on other sites
soconne    105
You could always use freetype. Here's my simple wrapper I use for loading and drawing text.

#ifndef _FT_WRAPPER_H
#define _FT_WRAPPER_H

#include <string>
#include <vector>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

namespace freetype
// Glyph entry structure
// stores data for a single ascii character
struct GlyphEntry
unsigned char ascii, width, height;
unsigned short x, y;

// Font data structure
// stores all infomration pertaining to a loaded font
struct FontData
std::string fontFile;
float fontSize;
int pixelSize;
bool antiAlias;
unsigned char* imagePixels;
size_t imageWidth;
size_t imageHeight;

std::vector<GlyphEntry> glyphEntries;
unsigned char glyphBase;

// Frees any memory associated with FontData object
void FreeFont(FontData* font)
delete[] font->imagePixels;
delete font;

// Creates a truetype font from specified fontfile
FontData* LoadFont(const std::string& fontfile, float font_size, bool antialias)
// Create new FontData object
FontData* fontData = new FontData;
fontData->fontFile = fontfile;
fontData->fontSize = font_size;
fontData->antiAlias = antialias;

// Compute pixel size
size_t y_resolution = 96;
size_t pixel_size = font_size * y_resolution / 72;

// Margins around characters to prevent them from 'bleeding' into each other
const size_t margin = 3;
size_t image_height = 0;
size_t image_width = 256;

// Initialize FreeType
FT_Library library;
if (FT_Init_FreeType(&library) != 0)
throw "Could not initialize FreeType2 library.";

// Load the font
FT_Face face;
if (FT_New_Face(library, fontfile.c_str(), 0, &face) != 0)
throw "Could not load font file.";

// Abort if this is not a 'true type', scalable font
if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) || !(face->face_flags && FT_FACE_FLAG_HORIZONTAL))
throw "Error setting font size.";

// Set the font size
FT_Set_Pixel_Sizes(face, pixel_size, 0);

// First we go over all the characters to find the max descent
// and ascent (space required above and below the base of a
// line of text) and needed image size. There are simpler methods
// to obtain these with FreeType but they are unreliable.
int max_descent = 0, max_ascent = 0;
size_t space_on_line = image_width - margin, lines = 1;

unsigned int startChar = 32;
unsigned int endChar = 126;
for (unsigned int i = startChar; i <= endChar; i++) {

// Look up the character in the font file
size_t char_index = FT_Get_Char_Index(face, i);

// Render the current glyph
FT_Load_Glyph(face, char_index, FT_LOAD_DEFAULT);
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);

size_t advance = (face->glyph->metrics.horiAdvance >> 6) + margin;

// If the line is full, go to the next line
if (advance > space_on_line) {
space_on_line = image_width - margin;

space_on_line -= advance;

max_ascent = max(face->glyph->bitmap_top, max_ascent);
max_descent = max(face->glyph->bitmap.rows - face->glyph->bitmap_top, max_descent);

// Compute how high the texture has to be
size_t needed_image_height = (max_ascent + max_descent + margin) * lines + margin;

// Get the first power of two in which it fits
image_height = 16;
while (image_height < needed_image_height)
image_height *= 2;

// Allocate memory for the texture
unsigned char* image = new unsigned char[image_width * image_height];
for (unsigned int i = 0; i < image_width * image_height; i++)
image[i] = 0;

// Allocate space for the glyph entries
fontData->glyphEntries.resize(endChar - startChar + 1);
fontData->glyphBase = startChar;

// These are the positions at which to draw the next glyph
unsigned int x = margin, y = margin + max_ascent;

// Drawing loop
for (unsigned int i = startChar; i <= endChar; i++) {

unsigned int char_index = FT_Get_Char_Index(face, i);

// Handle antialias text
if (antialias == true) {

// Render the glyph
FT_Load_Glyph(face, char_index, FT_LOAD_DEFAULT);
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);

// See whether the character fits on the current line
unsigned int advance = (face->glyph->metrics.horiAdvance >> 6) + margin;
if (advance > image_width - x) {
x = margin;
y += (max_ascent + max_descent + margin);

// Fill in the glyph entries
fontData->glyphEntries[i - startChar].ascii = (unsigned char)i;
fontData->glyphEntries[i - startChar].width = advance - margin;
fontData->glyphEntries[i - startChar].height = pixel_size;
fontData->glyphEntries[i - startChar].x = x;
fontData->glyphEntries[i - startChar].y = y - max_ascent;

// Copy the image gotten from FreeType onto the texture at the correct position
for (unsigned int row = 0; row < face->glyph->bitmap.rows; row++) {
for (unsigned int pixel = 0; pixel < face->glyph->bitmap.width; pixel++) {

image[(x + face->glyph->bitmap_left + pixel) + (y - face->glyph->bitmap_top + row) * image_width] =
face->glyph->bitmap.buffer[pixel + row * face->glyph->bitmap.pitch];

x += advance;
// Handle monochrome text
else {

// Render the glyph
FT_Bitmap* ft_bmp;
FT_Glyph glyph;
FT_BitmapGlyph bmp_glyph;

FT_Load_Glyph(face, char_index, FT_LOAD_DEFAULT);
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
FT_Get_Glyph(face->glyph, &glyph);

FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_MONO, 0, 1);

bmp_glyph = (FT_BitmapGlyph)glyph;
ft_bmp = &bmp_glyph->bitmap;

// See whether the character fits on the current line
unsigned int advance = (face->glyph->metrics.horiAdvance >> 6) + margin;
if (advance > image_width - x) {
x = margin;
y += (max_ascent + max_descent + margin);

// Fill in the glyph entries
fontData->glyphEntries[i - startChar].ascii = (unsigned char)i;
fontData->glyphEntries[i - startChar].width = advance - margin;
fontData->glyphEntries[i - startChar].height = pixel_size;
fontData->glyphEntries[i - startChar].x = x;
fontData->glyphEntries[i - startChar].y = y - max_ascent;

// Copy the image onto the texture at the correct position
unsigned char* monochromeData = ft_bmp->buffer;
int bit;

for (size_t row = 0; row < ft_bmp->rows; row++) {

unsigned char* nextPtr = monochromeData + ft_bmp->pitch;
bit = 7;

for (size_t pixel = 0; pixel < ft_bmp->width; pixel++) {

unsigned char value = (*monochromeData & (1 << bit)) >> bit;

image[(x + bmp_glyph->left + pixel) + (y - bmp_glyph->top + row) * image_width] = value;

if (bit == -1) {
bit = 7;

bit = 7;
monochromeData = nextPtr;

x += advance;


// Return FT_FontData object
fontData->pixelSize = pixel_size;
fontData->imagePixels = image;
fontData->imageWidth = image_width;
fontData->imageHeight = image_height;
return fontData;


freetype::FontData* font;
GLuint texID;

void init()
font = freetype::LoadFont("c:\\windows\\fonts\\arial.ttf", 9.0f, false);
CreateTextureFromFont(&fontTexID, *font);

void CreateTextureFromFont(GLuint* texID, const freetype::FontData& font)
glGenTextures(1, texID);
glBindTexture(GL_TEXTURE_2D, *texID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, font.imageWidth, font.imageHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, font.imagePixels);

void drawString(freetype::FontData* f, GLuint texID, std::string str)
if (f->antiAlias) {
else {
glAlphaFunc(GL_GREATER, 0);

glBindTexture(GL_TEXTURE_2D, texID);

glColor4f(0, 0, 1, 1);

float x = 0, y = 0;

for (int i = 0; i < str.size(); i++) {

freetype::GlyphEntry g = f->glyphEntries[str[i] - f->glyphBase];

float tx1 = g.x / (float)f->imageWidth;
float ty1 = g.y / (float)f->imageHeight;
float tx2 = (g.x + g.width) / (float)f->imageWidth;
float ty2 = (g.y + g.height) / (float)f->imageHeight;

glTexCoord2f(tx1, ty1); glVertex2i(x, y);
glTexCoord2f(tx2, ty1); glVertex2i(x + g.width, y);
glTexCoord2f(tx2, ty2); glVertex2i(x + g.width, y + g.height);
glTexCoord2f(tx1, ty2); glVertex2i(x, y + g.height);

x += g.width;


if (f->antiAlias) {
else {

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Similar Content

    • By pseudomarvin
      I assumed that if a shader is computationally expensive then the execution is just slower. But running the following GLSL FS instead just crashes
      void main() { float x = 0; float y = 0; int sum = 0; for (float x = 0; x < 10; x += 0.00005) { for (float y = 0; y < 10; y += 0.00005) { sum++; } } fragColor = vec4(1, 1, 1 , 1.0); } with unhandled exception in nvoglv32.dll. Are there any hard limits on the number of steps/time that a shader can take before it is shut down? I was thinking about implementing some time intensive computation in shaders where it would take on the order of seconds to compute a frame, is that possible? Thanks.
    • By Arulbabu Donbosco
      There are studios selling applications which is just copying any 3Dgraphic content and regenerating into another new window. especially for CAVE Virtual reality experience. so that the user opens REvite or CAD or any other 3D applications and opens a model. then when the user selects the rendered window the VR application copies the 3D model information from the OpenGL window. 
      I got the clue that the VR application replaces the windows opengl32.dll file. how this is possible ... how can we copy the 3d content from the current OpenGL window.
      anyone, please help me .. how to go further... to create an application like VR CAVE. 
    • By cebugdev
      hi all,

      i am trying to build an OpenGL 2D GUI system, (yeah yeah, i know i should not be re inventing the wheel, but this is for educational and some other purpose only),
      i have built GUI system before using 2D systems such as that of HTML/JS canvas, but in 2D system, i can directly match a mouse coordinates to the actual graphic coordinates with additional computation for screen size/ratio/scale ofcourse.
      now i want to port it to OpenGL, i know that to render a 2D object in OpenGL we specify coordiantes in Clip space or use the orthographic projection, now heres what i need help about.
      1. what is the right way of rendering the GUI? is it thru drawing in clip space or switching to ortho projection?
      2. from screen coordinates (top left is 0,0 nd bottom right is width height), how can i map the mouse coordinates to OpenGL 2D so that mouse events such as button click works? In consideration ofcourse to the current screen/size dimension.
      3. when let say if the screen size/dimension is different, how to handle this? in my previous javascript 2D engine using canvas, i just have my working coordinates and then just perform the bitblk or copying my working canvas to screen canvas and scale the mouse coordinates from there, in OpenGL how to work on a multiple screen sizes (more like an OpenGL ES question).
      lastly, if you guys know any books, resources, links or tutorials that handle or discuss this, i found one with marekknows opengl game engine website but its not free,
      Just let me know. Did not have any luck finding resource in google for writing our own OpenGL GUI framework.
      IF there are no any available online, just let me know, what things do i need to look into for OpenGL and i will study them one by one to make it work.
      thank you, and looking forward to positive replies.
    • By fllwr0491
      I have a few beginner questions about tesselation that I really have no clue.
      The opengl wiki doesn't seem to talk anything about the details.
      What is the relationship between TCS layout out and TES layout in?
      How does the tesselator know how control points are organized?
          e.g. If TES input requests triangles, but TCS can output N vertices.
             What happens in this case?
      In this article,
      the isoline example TCS out=4, but TES in=isoline.
      And gl_TessCoord is only a single one.
      So which ones are the control points?
      How are tesselator building primitives?
    • By Orella
      I've been developing a 2D Engine using SFML + ImGui.
      Here you can see an image
      The editor is rendered using ImGui and the scene window is a sf::RenderTexture where I draw the GameObjects and then is converted to ImGui::Image to render it in the editor.
      Now I need to create a 3D Engine during this year in my Bachelor Degree but using SDL2 + ImGui and I want to recreate what I did with the 2D Engine. 
      I've managed to render the editor like I did in the 2D Engine using this example that comes with ImGui. 
      3D Editor preview
      But I don't know how to create an equivalent of sf::RenderTexture in SDL2, so I can draw the 3D scene there and convert it to ImGui::Image to show it in the editor.
      If you can provide code will be better. And if you want me to provide any specific code tell me.
  • Popular Now