<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Progress on typeface rendering continues.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Glyphs and text string rendering now uses 3D basis vectors for orientation, which gives it the ability not only to render precisely positioned text, but also allows general scaling, rotation and 3D orientation. In general, affine transformations with perspective are now supported. Font24.png demonstrates this.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Basis vectors are pretty cool. To render text standing up on the ground plane at one meter per texel, you simply use the X and Z unit vectors as the rendering basis.  To render at a more reasonable size, scale down the basis vectors to roughly the dimensions of one screen pixel.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Rendering text in 3D orientation is mainly a curiosity. The primary use case coming up is screen-aligned, constant size text that tracks some 3D position. To do the screen-aligned part, the text is rendered using an orthogonal projection mapping the screen pixel per pixel, with the X and Y unit vectors as the basis. By telling Freetype to use "dots per inch" of 72, the mapping  becomes: one point equals one texel equals one pixel. This nice relation helps a great deal with both accuracy and sanity, otherwise life in a sea of strange typographical units can get frustrating indeed.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Rendering screen-aligned text according to a 3D position is easy. The object is to make the text rendered in the orthogonal projection appear as if it were rendered as a billboard in the perspective projection. All we need to do is transform the 3D world position of the text into screen coordinates using the current view and projection matrices, giving the pixel coordinates for the lower left text origin.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">But we also need to take care of one nasty problem: 3D text must work correctly with the depth buffer so that the text properly hides objects behind it and is hidden by objects in front of it. Unfortunately, he depth buffer mapping for an orthogonal projection and for a perspective rendering are not at all the same. We need to render the text in the orthogonal projection at a distance that produces exactly the same values in the depth buffer as if we had rendered it in the perspective projection. Wow, how on earth do we know what that distance should be? At least, the entire text is rendered at the same distance from the eye, otherwise I doubt it would even be possible to match the depth mapping between the two projections.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Calculating the correct render depth turned out to be awfully hard.I am not a great mathematician - far from it - but I try to make up for it in other ways. After initially failing to deduce the formula from the OpenGL specification, I discovered it by experiment. I created a test bed to display the text at some randomly chosen depth, then move my viewpoint forward and back until the text ends up hidden by one object and hiding the other. At that point I knew the distance from my eye to the object, and that my randomly chosen number was the correct value to put into the depth buffer at just that distance. In this way I found some specific points on the curve, including the general range that the the number should be in. Should it be positive or negative? (Negative) Should it be big or small? (Usually small.) Close to zero or one? (Close to one.) Varying linearly with the world distance? (No, varying linearly with the inverse of the world distance.) Putting those clues together I eventually concocted a formula that always translates the perspective depth exactly to the correct orthogonal depth. Once I had the formula, it was straightforward to go back to the specification and verify that it is in fact the correct formula. So that is how I did that, and why I did not get a lot of sleep last night.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">While I was in there, I added Unicode support for text strings, see "font26.png". This phrase means "happiness" in Japanese, using one Kanji and two Hirigana characters. Notice how the text nestles itself between the two spheres, just as it should. Now you know a little about the kind of effort that needs to go into making such a seemingly simple thing work properly.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">There are still a few more steps before the new text renderer goes into service. I need to implement a platform independent interface to the font loader so that nobody needs to specify actual file names for font files. Alternatively I could embed a basic font file in the distribution, which is allowed legally because these fonts are all covered by Free licenses. But the files are not tiny, for example, about 140K for Liberation Sans Regular, which will be the basic World Welder system font. And we want to have lots of fonts. I might end up embedding one font file in the tarball anyway, but for now I will implement the Freetype Cache library interface, so fonts can be specified in terms of descriptive terms instead of exact names. This library also optimizes repeated access to many fonts from many programs, so startup time should be improved by not needing to read the font file from disk as often.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Then I need to ruggedize the code and protect the OpenGL state that the font render uses. Finally, the whole good sized piece of code, needs to be "promoted" from its testbed into the World Welder runtime library. Phew, a lot of work already and still more to do. All in the name of text display that doesn't hurt your eyes. That is more than enough reason in my opinion.</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Regards,</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;">Daniel</p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; "> </p></body></html>