Pixel Bitmap font for OGL

Hello

Could someone offer their opinion (or statements of fact :)) on which method is the best way to render a bitmap font in OpenGL? Most tutorials I have found do something like: load up a TTF and convert it to a pixel image. This is not what I want, as I already have my own texture atlas'd bitmap font on a single 128x128 image.

Furthermore, I don't need or want any texture filtering, scaling, rotating, etc -- I just want to plaster the pixels of the letter directly onto the screen at a pixel-perfect 1:1 ratio.

Not necessarily looking for anyone to write code for me, concepts and/or links are great, unless code would be useful to help explain.

I'm not fully comfortable yet with OpenGL but I've come across several different possibilities as methods:

- 1) The TTF-to-pixel way, which I don't want
- 2) Render each letter to a quad? This seems iffy to me as I do not require any transforms from projection space, screen space, filtering, etc. I just want to paste the pixels directly to the screen.
- 3) Create a FramebufferObject and attached Texture object, and somehow write to the Texture object (probably only one time), not sure which function I need to do the actual draws. Render-to-texture tutorials I've found often use the function glViewport(), but this is only for rendering the entire window to a texture, I think.
- 4) Use glBlitFramebuffer directly onto the backbuffer? This function has pixel-perfect parameters but I get the impression that calling this function once per letter would be... not smart? =)
- 5) I've also seen some people, on certain sites, reference using a GLSL shader to render bitmap fonts to the screen? Right now I only have basic experience thus far with a basic vertex shader and a fragment shader.

What's the best way to implement this? Thank you =)
Last edited on
First create a texture the same size as the screen (you may want to want to check the NPOT extension is available, which thankfully it pretty much always is nowadays) and a normal buffer (that is, a regular array in main memory) in the same format as the texture. To update the contents of the screen you write to the buffer at the appropriate locations, and then when it's time to render the frame you upload it to the GPU. Now, this texture-buffer pair only describes the entire screen. You can choose to store your font glyphs prior to rendering however you like
Now to render the texture on the screen you can use glBlitFramebuffer().
Thank you for the reply!

To update the contents of the screen you write to the buffer at the appropriate locations


Yes, sorry, that is the specific part I intended to ask about. I have my image successfully loaded with fileIO, and the texture created in OpenGL and all seems to be well there, no issues =)

So my question is, what exactly is the best method/functions to do the "copying the letters over to the buffer" part? Or "stamping" the individual letters onto the buffer if you will. Bear in mind I'm not looking for any filtering/sampling/rotation/scaling, I just want a direct pixel copy to the buffer (or to the screen directly!), which is why rendering each letter onto a quad didn't seem like the best way, in my head.

So, if I had a function to write text with my bitmap font, like:
1
2
3
4
void BitmapFontWrite(const char* text, GLuint x_pos, GLuint y_pos)
{
 // which OpenGL functions/techniques should I be using in here?
}


I have made a BitmapFontWrite() function in the past, but I made it in SDL, which only dealt with 2D images, so it wasn't complicated. But now that I'm using OpenGL, I'd like to know which OpenGL functions/techniques I should be using to copy/stamp these letters over to a buffer, or directly to the backbuffer...whatever is best. =)
Last edited on
So my question is, what exactly is the best method/functions to do the "copying the letters over to the buffer" part?
Well, in the specific phrase you quoted I'm talking about a plain-ol' buffer. That is, an array in memory. I assume you know how to write bytes to memory.
Once you've put the array in the state you want, you upload it to the device using (IINM) glTexImage2D().

So, to recap:
1
2
3
4
5
6
7
8
during render{
    for every character on the screen{
        copy the character's glyph onto buffer at the character's location; (again, this is a RAM-to-RAM operation)
    }
    upload buffer to texture on device; (glTexImage2D)
    clear framebuffer; (glClear)
    copy texture to framebuffer; (glBlitFramebuffer)
}
Well, in the specific phrase you quoted I'm talking about a plain-ol' buffer. That is, an array in memory. I assume you know how to write bytes to memory.


Yes =) thank you, however I need clarification for something else that you said as I'm not super experienced in graphics programming -- when you say "again, this is a RAM-to-RAM operation" -- that means it's happening on the CPU, not the GPU, right?

If so... is that okay for something that happens extremely often? It's my (limited) understanding that CPU operations are slower than GPU ones, and since I already uploaded the image data for the bitmap font (128x128 image) to OpenGL with glTexImage2D, I was hoping there was a function to transfer from GPU-to-GPU data. Sorry if I'm misunderstanding here.

I suppose I could store each letter individually as plain pixel data on CPU (which I believe you suggested on the first post), but I was hoping there was a dedicated OpenGL technique for copying an exact rect of one OpenGL texture, and pasting it directly onto a rect of another OpenGL texture. (Maybe SDL spoiled me by having methods that allowed you to specify a unique rect for both source and dest.)

Thank you again =)
If so... is that okay for something that happens extremely often? It's my (limited) understanding that CPU operations are slower than GPU ones, and since I already uploaded the image data for the bitmap font (128x128 image) to OpenGL with glTexImage2D, I was hoping there was a function to transfer from GPU-to-GPU data. Sorry if I'm misunderstanding here.
Oh! Well, in that case you can use (IINM) glBlitNamedFramebuffer() to transfer from the font texture to the screen texture, and then again from the screen texture to the framebuffer. You can of course transfer directly from the font to the framebuffer, but if you use an intermediate texture you only need to copy from the font when the text on the screen changes. If you transfer directly from the font to the framebuffer you need to redraw every frame because the framebuffer is either in a cleared or indeterminate state.
would it be of any benefit to draw the text on a different surface as an overlay, rather than manually handle it per frame?
Last edited on
Unless by "overlay" you're referring to some specific concept (I know that word used to refer to some kind of video rendering that was used in the past), I addressed that, didn't I? I proposed using an intermediate texture in between the font texture and the framebuffer to only have to redraw the text when it changes.
Ah, I did not follow your terminology 100%, thought you were putting it on a texture then on the main surface, not an intermediate surface. Same idea, then.
Hi, thanks guys, I was still struggling a bit with the OpenGL calls (like which exact funcs were needed) but it's working!

https://i.imgur.com/Mm8TY0C.png

For now, I'm drawing straight to the backbuffer. The steps I've done, (unless I've done something wrong or missed something), are this:

1. glGenFramebuffers (make a single test fbo)

2. glBindFramebuffer (binds the new fbo to the GL_READ_FRAMEBUFFER)

3. glFramebufferTexture2D (attaches a texture object (which I already had uploaded outside of the function) to the new fbo)

4. iterate through the string, using glBlitFramebuffer... the Src being the READ fbo, and the Dst being the backbuffer (which I guess it is, by default?)

5. glBindFramebuffer 0 to unbind it

6. glDeleteFramebuffers on my fbo in cleanup

Here it is, keep in mind I'm doing EVERYTHING (init and cleanup) inside this function, which I know is dumb, I'll fix that =)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
void GameEngine::_Write(const char* text, GLuint x, GLuint y)
{
	// Do this only once, in Init
	/////////////////////////////////////////////////////////
	// Create framebuffer
	GLuint tempFbo = 0;
	glGenFramebuffers(1, &tempFbo);
	/////////////////////////////////////////////////////////


	// Do this only before the first _Write() call
	/////////////////////////////////////////////////////////
	// Bind framebuffer
	glBindFramebuffer(GL_READ_FRAMEBUFFER, tempFbo);
	/////////////////////////////////////////////////////////


	// Attach the font texture to the framebuffer
	// TODO: Hard-coded font texture (_textures[1])
	glFramebufferTexture2D(GL_READ_FRAMEBUFFER,
		GL_COLOR_ATTACHMENT0,
		GL_TEXTURE_2D,
		_textures[1], 0);

	// Draw every letter in the passed-in string
	for(int i = 0; text[i] != 0; ++i)
	{
		// Get character
		unsigned char char_value = text[i] - 33;

		// Get proper position to draw at
		// TODO: Screen size (480) hard-coded
		SDL_Point pos;
		pos.x = x;
		pos.y = 480 - y;
		// Note: Flip vertically for OpenGL

		// Draw character
		_DrawTextCharacter(1, char_value, pos, i);
	}


	// Do this only after the last _Write() call
	/////////////////////////////////////////////////////////
	// Unbind framebuffer
	glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
	/////////////////////////////////////////////////////////


	// Do this only once, in Cleanup
	/////////////////////////////////////////////////////////
	// Delete framebuffer
	glDeleteFramebuffers(1, &tempFbo);
	/////////////////////////////////////////////////////////
}


And here is my _DrawTextCharacter function... this one's not too important but maybe someone who finds this thread might want to use it for reference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
void GameEngine::_DrawTextCharacter(GLuint tex, GLuint sprite, SDL_Point& pos, GLuint i)
{
	// TODO: Hard-coded values for dimensions of character
	GLint sprite_w = 8;
	GLint sprite_h = 16;

	// TODO: Retrieve texture dimensions from OpenGL
	// Store my own values instead?
	GLint texture_w;
	GLint texture_h;

	// Retrieve the dimensions of the texture
	glBindTexture(GL_TEXTURE_2D, _textures[tex]);
	glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texture_w);
	glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texture_h);
	glBindTexture(GL_TEXTURE_2D, 0);

	// Get rows, cols, and total indices in sprite sheet
	GLint num_rows = texture_h / sprite_h;
	GLint num_cols = texture_w / sprite_w;
	GLint total_rects = num_rows * num_cols;

	// Safety clamp for passed-in character value
	sprite %= total_rects;

	// Assign rect data
	SDL_Rect src, dst;
	src.x = ((sprite % num_cols) * sprite_w);
	src.w = ((sprite % num_cols) * sprite_w) + sprite_w;
	src.y = texture_h - ((sprite / num_cols) * sprite_h) - sprite_h;
	src.h = texture_h - ((sprite / num_cols) * sprite_h);
	dst.x = (i * sprite_w) + pos.x;
	dst.w = (i * sprite_w) + pos.x + sprite_w;
	dst.y = pos.y - sprite_h;
	dst.h = pos.y;
	// Note: "w" and "h" are used as "x1" and "y1" values
	// Note: Intentional vertical flip on Y-axis

	// Draw character
	glBlitFramebuffer(
		src.x, src.y,
		src.w, src.h,
		dst.x, dst.y,
		dst.w, dst.h,
		GL_COLOR_BUFFER_BIT, GL_NEAREST);
}


So I have a couple more questions:

1. First, aside from not yet splitting up the Gen/Bind/Unbind/Delete parts into external functions, have I done anything glaringly wrong, dangerous, wasteful, etc? For example, in DrawTextCharacter, is retrieving the already-uploaded texture dimensions with glGetTexLevelParameteriv a stupid idea, and I should manually save that kind of thing, or is retrieving it from OpenGL just dandy?

2. Do I need to un-attach the texture object from my FBO before unbinding and deleting the FBO, or does that not really matter? (I assume if I were to attach another texture on the same channel, the old one gets overwritten anyway yeah?)

Thanks again
Last edited on
have I done anything glaringly wrong, dangerous, wasteful, etc?
As I recall, the point of FBOs is that you can avoid re-uploading to the GPU static vertex data over and over each frame. I don't see any reason to create and destroy that FBO every frame.

For example, in DrawTextCharacter, is retrieving the already-uploaded texture dimensions with glGetTexLevelParameteriv a stupid idea, and I should manually save that kind of thing, or is retrieving it from OpenGL just dandy?
As a general rule, the fewer OpenGL calls, the better.

Do I need to un-attach the texture object from my FBO before unbinding and deleting the FBO, or does that not really matter?
I don't think it matters.

I assume if I were to attach another texture on the same channel
"Channel"?
What a quick reply! Good morning.

I don't see any reason to create and destroy that FBO every frame.

Yes, I agree, thank you! I'm going to change that; I intended to signify my intent to separate those parts out, in the comments of the code, but I should've explained this, thank you.

"Channel"?

By channel I meant like attaching the texture to the FBO on:
GL_COLOR_ATTACHMENT0

Not sure if channel is the right term. But anyway, I assume that attaching a 2nd textureattachment automatically severs the first, like re-assigning a pointer. (I assume)

Thank you =)
Last edited on
Yes, that's how state transformations work in OpenGL. It's analogous to setting a variable.
Topic archived. No new replies allowed.