{"id":3593,"date":"2015-01-04T19:34:07","date_gmt":"2015-01-04T09:34:07","guid":{"rendered":"http:\/\/www.vectorstorm.org\/?p=3593"},"modified":"2015-01-04T19:35:24","modified_gmt":"2015-01-04T09:35:24","slug":"pixel-exact-text-troubles","status":"publish","type":"post","link":"https:\/\/www.vectorstorm.com.au\/2015\/01\/04\/pixel-exact-text-troubles\/","title":{"rendered":"Pixel-exact text troubles"},"content":{"rendered":"

\"Screen<\/a>I was going to post about various new features I’ve been adding to MMORPG Tycoon 2, but at the very last minute I noticed something very odd in my current build;\u00a0 in some of the small text strings in one of the new windows, I was getting blurry text.\u00a0 The sort of blurry text that used to occur, back before I worked out how to get the VectorStorm library to draw pixel-exact text.\u00a0 The string at the top of this image is one where the string appeared blurry.\u00a0 Beneath it is how it should have appeared.\u00a0 And did appear, in fact, in other places in the program.<\/p>\n

Here were the clues to the problem:<\/p>\n

    \n
  1. Not every string looked blurry.\u00a0 “Level 1 Inn”, for example, looked blurry.\u00a0 “Level 1 Grinding Zone”, in the same place, did not.\u00a0 And this was consistent — it happens the same way every single time, no matter how big or small the window is.<\/li>\n
  2. It seemed like only strings which were drawn with a centered justification ever appeared blurry.\u00a0 But not every string drawn with a centered justification appeared blurry.<\/li>\n<\/ol>\n

    <\/p>\n

    Under the hood, VectorStorm uses BMFont<\/a>-style font rendering.\u00a0 We build a model for each text string, with a rectangle for each glyph, and those rectangles are drawn using a texture which contains the glyphs of the font.\u00a0 I make the rendering pixel-exact by ensuring that the pixels of each rectangle’s texture are aligned precisely with the pixels of the screen, so that each screen pixel is sampling from just one texture pixel.\u00a0 If the pixels of the texture aren’t quite aligned with the pixels of the screen, each screen pixel blends between multiple texture pixels, and you wind up with a blurry appearance.\u00a0 I line up the pixels by ensuring that the text is placed at an integral position.\u00a0 That is, if I draw a letter at (1,1) or (2,2) or (203,112), it will be aligned with screen pixels.\u00a0 If I draw it at (1.5,1.0) or at (2,7.1), or at any other coordinate which contains a decimal point, it won’t be aligned, and so will result in blurry text.<\/p>\n

    The magic step I do to make everything render aligned to pixels is that before rendering 2D text, I chop off any fractional part in the matrix — the structure which says where on the screen the object is to be drawn.\u00a0 So if something had told me to draw the text at (1.5,1.5), I chop that off and actually draw it at (1,1), for the sake of aligning with pixels.\u00a0 This means that even if a font model is located at (0,0) relative to its parent, but its window has somehow been moved to (0.5,0.5), we round off that fractional amount when it comes time to draw the font.\u00a0 So it shouldn’t be possible to render text unaligned from pixels, no matter what the outside world does, right?<\/p>\n

    Except that here I had an example where text was still blurry for some reason.\u00a0 Not all the time, but sometimes.<\/p>\n

    Well, I finally found the issue;\u00a0 the problem was that in this particular font at this particular size, “Level 1 Inn” happens to be \u00a0 61 pixels wide.\u00a0 And since I centered the rectangles for those glyphs, that meant that they all had a baked-in 30.5-pixel offset;\u00a0 in effect, the blur wasn’t in the screen alignment at all — it was in the model for the text itself!<\/p>\n

    Fixing that — snapping the amount the model is moved around in order to center it — resulted in the fixed, non-blurred appearance (visible beneath the blurry one).\u00a0 Note the crisper vertical lines of the ‘L’ and ‘l’ in Level, and the ‘I’ in Inn, particularly.\u00a0 It makes a surprisingly large difference to legibility, at normal size.<\/p>\n

    Here’s a screenshot where you can see the problem in situ (click for full-size):<\/p>\n

    \"InfoWindow\"<\/a>Note how the centered “Hero” string at the top of the window is blurry, but the right-justified one on the right side of the window appears sharp.\u00a0 That’s precisely this issue.<\/p>\n

    For me, it’s hugely satisfying to find this sort of problem.\u00a0 Apparently, it’s satisfying enough that I’ll abort a post I was going to write about an exciting new window and game features, and will instead post a technical post-mortem on a code-fix which is so subtle it requires zooming in on pixels to make the bug visible at all to a casual glance.<\/p>\n

    I’ll get back to talking about the exciting new window, and the other things that I’ve been up to tomorrow.\u00a0 :)<\/p>\n","protected":false},"excerpt":{"rendered":"

    I was going to post about various new features I’ve been adding to MMORPG Tycoon 2, but at the very last minute I noticed something very odd in my current build;\u00a0 in some of the small text strings in one of the new windows, I was getting blurry text.\u00a0 The sort of blurry text that…<\/p>\n","protected":false},"author":1,"featured_media":3595,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":""},"categories":[4,3],"tags":[],"jetpack_featured_media_url":"https:\/\/www.vectorstorm.com.au\/wp-content\/uploads\/2015\/01\/Screen-Shot-2015-01-04-at-7.52.32-pm.png","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/po9WK-VX","_links":{"self":[{"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/posts\/3593"}],"collection":[{"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/comments?post=3593"}],"version-history":[{"count":3,"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/posts\/3593\/revisions"}],"predecessor-version":[{"id":3598,"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/posts\/3593\/revisions\/3598"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/media\/3595"}],"wp:attachment":[{"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/media?parent=3593"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/categories?post=3593"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vectorstorm.com.au\/wp-json\/wp\/v2\/tags?post=3593"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}