| Benoît Jacob ( @ 2007-05-08 19:29:00 |
| Entry tags: | opengl shadowed text qt avogadro libavog |
Drawing shadowed text inside an OpenGL scene
I've been quiet lately, partly because I've had to spend most of my time on my thesis, and partly because I've done all my coding in Avogadro (no real website yet), which is not yet in KDE's SVN. If you read this story showing the new Kalzium3D features, maybe you'll be interested to know about libavogadro. This library initially took the kalzium3D rendering code but set much more ambitious goals, with currently 4-8 hackers including a promising SoC. There are immediate plans to port Kalzium to libavogadro; however libavogadro won't reach API stability in time for KDE 4.0 so we'll probably import a snapshot inside the Kalzium tree in the next days.
A new thing that libavogadro does is to draw labels on atoms. Rendering text inside an OpenGL scene is not straightforward. The problem is that in an opengl scene, you typically can't control the color of background. And if the text color is too close to the background color, then it's not readable. A bad workaround is to paint a semi-transparent dark rectangle behind the text. But in many occurences that feels ugly.
So a better solution is to draw a black shadow around the text. Just like the text below the icons on your KDE 3.5 desktop background. AFAIK, Qt does not yet provide that functionality, which is why KDesktop has its own code for that.
I initially tried to do it with QGLWidget::renderText, achieving the shadow by painting the text multiple times. Alas, renderText is not very fast, and multiple renderText calls are even slower. I got something working, but the framerate was divided by a factor of 5 (with Qt 4.2.3 and 4.3-b1). Too slow!
So I took my old TextRenderer class that I had written for Kalzium, and improved it to do shadowed text. This was achieved as follows: use a 16bpp GL_LUMINANCE_ALPHA texture, paint with Qt the character and read the luminance channel directly from the resulting bitmap; while the alpha channel is obtained by applying a trivial convolution filter (much like what KDesktop does, see above link). Characters are rendered on the fly whenever they are first needed, and are then cached and managed in a QHash.
The code is in avogadro's SVN tree at sourceforge but it's still very unclean and comments/docs are missing.
Obligatory screenshot (see how the shadow is necessary for readability on the white Hydrogen atoms):
This 35 frames-per-second is on my laptop with software-only rendering (mesa-swx11) and the highest level of detail. Disabling the labels on the atoms only increases the framerate by +10%, which is not too much if you consider how slow texture-mapping is on software-only systems.