4

I'm trying to work with the FTGL font library, to create a texture-mapped font and render it to the screen. The library creates a texture in the GL_ALPHA format to hold the font glyphs, and then when you tell it to render a string, it goes through and glBegin(GL_QUADS) and renders each glyph, exactly how you'd expect.

Only problem is, I'm not getting any text. In one scenario, I get solid black boxes instead of text, in another I get nothing. I've run the code under gDEBugger to ensure that the texture is getting uploaded and set up properly, and everything looks right, but I'm still not seeing any output.

I've tried the obvious stuff. Calling glColor beforehand to try to set a text color does nothing. Neither does attempting to ensure that alpha-blending will work properly, like so:

glEnable(GL_ALPHA_TEST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Does anyone have any idea what I'm missing, in order to make rendering from a GL_ALPHA texture to the screen show up properly?

BЈовић
  • 62,405
  • 41
  • 173
  • 273
Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • "The library creates a texture in the GL_ALPHA format to hold the font glyphs" Really? Does it not allow you to choose what format to use? That's unfortunate if it doesn't, since GL 3.1 core and above don't have GL_ALPHA textures anymore. – Nicol Bolas Dec 16 '11 at 00:06
  • @Nicol: Yes, really, and so what? I'm not aware of any video cards whose drivers only implement core and ignore backwards compatibility. That would be a really dumb move, and the manufacturers know it. – Mason Wheeler Dec 16 '11 at 00:09
  • MacOSX 10.7 doesn't implement compatibility. Your choices there are either 2.1 or 3.2 *core*. Even ignoring the fact that it's relying on removed stuff, it should still give you some options about what format you want. Because they use GL_ALPHA, you have to go through a great deal of effort to make it work with texture environments and colors (see below). If they just used GL_INTENSITY like most people would expect, you could just use GL_MODULATE and a blend mode of `GL_ONE`, `GL_ONE_MINUS_SRC_ALPHA`. – Nicol Bolas Dec 16 '11 at 00:42

1 Answers1

3

It's clear after an examination of FTGL's code that the API is designed to do the text rendering itself. You're expected to call its rendering functions, which will make the OpenGL calls internally.

To put it another way, FTGL is not designed to load a font into a texture, then give you that texture object and have you draw the glyphs yourself. That doesn't mean you can't, only that the API is not going to help you do it.

The reason you get black is because GL_ALPHA textures return zeros for the RGB component when accessed. Since you use GL_MODULATE in your texture environment, that's going to multiply zero by the RGB part of the color.

To do what you intend, you need to set the GL_TEXTURE_ENV_MODE to GL_COMBINE instead of GL_MODULATE. Which means you need to use the combine environment mode, which isn't simple. Having abandoned fixed-function for shaders pretty much as soon as they existed, I haven't touched combiners in a long time. So take what follows with a grain of salt. Here's a guess at what the environment code should look like:

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);

What you want to do is generate a color where the RGB part comes from glColor and the Alpha part comes from the texture. This is how you do that.

In English, the first line says that the texture environment mode is "combine", which activates a more complicated operation mode. The next three lines specify how the RGB part of the color is generated. The GL_COMBINE_RGB set to GL_REPLACE means that the source RGB value 0 will be what the output RGB is. Setting GL_SRC0_RGB to GL_PRIMARY_COLOR means that source RGB value 0 is the primary color, which is the color generated by vertex processing (ie: unless you're using lighting, this is just what you passed with glColor). Setting GL_OPERAND0_RGB to GL_SRC_COLOR means to take the color as it is (there are special operations you can do, like take 1 - the color or whatever).

The next 3 lines set up where the alpha part of the output color comes from. The GL_COMBINE_ALPHA set to GL_REPLACE means that the source alpha value 0 (different from the source RGB value 0) will be what the output alpha is. Setting GL_SRC0_ALPHA to GL_TEXTURE means that the source alpha value 0 comes from the texture of the current texture unit. Setting GL_OPERAND0_ALPHA to GL_SRC_ALPHA means to take the alpha as it is (as before, you could apply some transform to the alpha here).

Alternatively, if your OpenGL implementation has ARB_texture_swizzle available, you can set up a swizzle mask to effectively transform the GL_ALPHA format into GL_INTENSITY. Then you can use GL_MODULATE as your GL_TEXTURE_ENV_MODE. However, you have to make sure that your blend mode is glBlendMode(GL_ONE, GL_ONE_MINUS_SRC_ALPHA). This is necessary because GL_MODULATE will multiply the color by the alpha. If you used GL_SRC_ALPHA instead of GL_ONE, you would be doing the multiply by alpha twice (once in the texture env stage, once in the blend stage).

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • I *am* calling its rendering functions and having it make the OpenGL calls internally. It's just not quite rendering things properly. I spent several hours last night and this morning poking around in its code (a bad experience, as I am by no means a C++ guy!) just trying to make the textures set up right, since I've got an edge case it doesn't handle correctly. I do plan to move the rendering to shader-based code, but first I want to ensure that it works properly in fixed-function, since the library was *designed* for fixed-function and that gives me a sanity check. – Mason Wheeler Dec 16 '11 at 00:44