Drawing text in OpenGL 3+

Started by Andrew_3ds, May 01, 2015, 18:09:33

Previous topic - Next topic

Andrew_3ds

I can't find any well explained ways to load the font as separate textures for each glyph (from a TTF), then draw them using the most efficient way(Draw each character in a different call? Instancing? Geometry shader?). If someone could show some code that would be amazing, I have been stuck on this for a long time.

Kai

There is no way to do this with OpenGL or LWJGL alone.

You need to use a font rendering library, such as the one provided by Java AWT, which makes use of platform-dependent system libraries, such as Win32 and X11, in its peer implementations.
So you can use Java AWT to draw glyphs (or whole strings) into an AWT image and then grab that image data to upload it into an OpenGL texture (for example).

But lifting AWT into your application makes it really heavyweight, so there is the trend to avoid AWT wherever possible.

And one possible route for this would be a binding of the FreeType library. But that is not there yet, so feel free to contribute! ;)

Cornix

Of course you could pre-create the Font-Textures using AWT in a separate program and then not use AWT in your application.

spasi

I'm currently considering stb as a lightweight solution to font and image loading. Many other useful stuff in there too (e.g. vorbis decoding).

Daslee

You could take Slick's TrueTypeFont class and modify it a little bit. And for drawing text you just make shaders (including geometry shader) to draw point sprites. Then modify Slick's TrueTypeFont class, so it would generate you sprites and their texture coordinates instead of drawing characters in immediate mode. And then, in every render cycle put all characters positions and their texture coordinates to the VBO, and send them to the shaders.

kappa

Quote from: Daslee on May 05, 2015, 12:51:07
You could take Slick's TrueTypeFont class and modify it a little bit. And for drawing text you just make shaders (including geometry shader) to draw point sprites. Then modify Slick's TrueTypeFont class, so it would generate you sprites and their texture coordinates instead of drawing characters in immediate mode. And then, in every render cycle put all characters positions and their texture coordinates to the VBO, and send them to the shaders.
I'm actually using a modified version of Slick's TrueTypeFont with LWJGL3 atm, but its not really a proper solution for LWJGL3 since its based on AWT (also runs into the main loop problems on OS X when not in headless mode). We need a solution that can load ttf files and doesn't have a dependency on AWT such as stb(mentioned above), FreeType or maybe even a pure java ttf loader.

abcdef

I'd be interested in a pure java solution too, I have a java awt version atm but would love to remove the awt dependency. I am kind of inspired to write one as I have written quote a few java loaders.

Cornix

I dont think a pure java solution is possible. As far as I understand font rendering is done by the OS, the best we could do is reinvent the wheel in java just because we dont want to use a native library.
Of course I'd love to be proven wrong.

kappa

Quote from: Cornix on May 05, 2015, 20:57:02
I dont think a pure java solution is possible. As far as I understand font rendering is done by the OS, the best we could do is reinvent the wheel in java just because we dont want to use a native library.
Of course I'd love to be proven wrong.
Font rendering inside OpenGL applications is mostly done manually (or using pre-baked textures) and rarely uses the native OS font renderer.

Primarily we need a library which can decode the ttf format (and possibly other font formats) and provide basic glyph data, having just this capability should solve a major hurdle.

Secondly would be a library (or libraries) that has the capability to render the glyph data with OpenGL, here there are many different techniques each with their own pro's and cons and there might not be a single solution for everyone e.g. pre-baking fonts to textures, drawing the actual glyphs using triangles, using distance fields to draw them, using the gpu to draw curves, etc. Further such a library would be expected to handle more advance features such as using font hints, basic AA, sub-pixel AA, rendering tiny fonts, scaleable fonts, etc.

Its a pretty tricky problem and why most people don't roll their own solution. Libraries like FreeType have had years of development to try solve some of these issues and is now widely used by most to handle their font needs (even AWT uses FreeType these days).

Andrew_3ds

If I were to use textures, how could I achieve drawing a whole sentence in a single call, without having to use a draw call for each glyph? That wouldn't be efficient, but I don't think you can instance with different textures.

Kai

Well you "could" do instancing with a single 2D texture while still being able to draw a whole sentence.
That is, if you have all glyphs in a single 2D texture (using bin packing or something) and submitting the texel coordinates for each glypth in a buffer (like a uniform buffer object), which you access in your shader to sample the glyph from the 2D texture.
If you do not want to use a packing algorithm to have all glyphs in a single 2D texture, you can then use a 2D array texture, where each layer is a single glypth. Then your UBO would only contain the layer id of the glypth, which could be the ASCII code of the character.
That's just what's coming to my mind right now.

abcdef

Most fonts are on a single texture (http://thingy.com/haj/images/font-to-texture-sample.png for an example), you then just have a 2D quad for each character and then use texture coordinates to find the correct character to map in the font texture.

The AWT part of most font renders is to create the font texture, the actual opengl part is AWT free after this step

SilverTiger

Some month ago I made a tutorial how to render text with LWJGL3, you may want to take a look at it here.
In that tutorial the font rendering is done by creating a texture atlas with all glyphs on a single 2D texture like the others described it already.