{"id":166,"date":"2014-07-15T18:50:11","date_gmt":"2014-07-15T18:50:11","guid":{"rendered":"https:\/\/blogs.scummvm.org\/josejx\/?p=166"},"modified":"2022-05-21T18:53:40","modified_gmt":"2022-05-21T18:53:40","slug":"positioning-textobjects","status":"publish","type":"post","link":"https:\/\/blogs.scummvm.org\/josejx\/2014\/07\/15\/positioning-textobjects\/","title":{"rendered":"Positioning textObjects"},"content":{"rendered":"<p>There are a lot of differences with the positioning of <i>textObjects<\/i> between the retail version of EMI and ResdiualVM&#8217;s implementation. Let&#8217;s take the scene <i>wed<\/i> and compare the text positions. First, here&#8217;s the scene in the retail version:<\/p>\n<figure id=\"attachment_168\" aria-describedby=\"caption-attachment-168\" style=\"width: 640px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/RetailText.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-168\" src=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/RetailText.png\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/RetailText.png 640w, https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/RetailText-300x225.png 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-168\" class=\"wp-caption-text\">Retail screen shot from the set wed<\/figcaption><\/figure>\n<p>And here&#8217;s the same scene in ResidualVM:<\/p>\n<figure id=\"attachment_169\" aria-describedby=\"caption-attachment-169\" style=\"width: 640px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/ResidualText.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-169\" src=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/ResidualText.png\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/ResidualText.png 640w, https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/ResidualText-300x225.png 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-169\" class=\"wp-caption-text\">ResidualVM screen shot from the set wed<\/figcaption><\/figure>\n<p>And finally, here&#8217;s the difference between the two:<\/p>\n<figure id=\"attachment_170\" aria-describedby=\"caption-attachment-170\" style=\"width: 640px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/DifferenceText.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-170\" src=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/DifferenceText.png\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/DifferenceText.png 640w, https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/DifferenceText-300x225.png 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-170\" class=\"wp-caption-text\">Difference between the two images<\/figcaption><\/figure>\n<p>We can ignore the ship in the background, since it&#8217;s moving, and I didn&#8217;t capture it in exactly the same place. We also can ignore the shadows, Akz has <a href=\"https:\/\/github.com\/residualvm\/residualvm\/pull\/956\" target=\"_blank\" rel=\"noopener\">already addressed<\/a> that problem. That leaves us with the text errors, exactly what we&#8217;re trying to work out!<\/p>\n<p>While it&#8217;s obvious to the eye that the text <i>&#8220;There&#8217;s an enemy pirate over there.&#8221;<\/i> is in the wrong place and has a different wrapping point, there&#8217;s also a mismatch between where the text is placed for <i>&#8220;Look at enemy pirate&#8221;<\/i>.<\/p>\n<p>Additionally, in some cut scenes, with subtitles on, the text is placed in the wrong location. A good example of this problem is the scene during travel to Jambalaya Island, where the exclamations of the crew are drawn right on top of each other! Another common issue is that the text is placed in the wrong place, obscuring the game play. A good example of this is when reading the directions to get to Pegnose Pete&#8217;s house.<\/p>\n<p>In ResidualVM, text elements are drawn using a <i>textObject<\/i>. In the Lua scripts, <i>textObjects<\/i> are created by calling the Lua\/C function <i>MakeTextObject<\/i>. The parameters for the <i>textObject<\/i> are the string that&#8217;s going to be displayed and a parameters table, with various options for configuring the text. We can remove this <i>textObject<\/i> from the screen by calling <i>KillTextObject<\/i> and passing the handle that was returned by <i>MakeTextObject<\/i>.\u00a0 Let&#8217;s try drawing some text with the retail version of EMI and observe the behavior. Let&#8217;s start by just writing some text to the 0, 0 coordinate position:<\/p>\n<pre>textObj = MakeTextObject(\"Hello Blog Readers!\", { x = 0.0, y = 0.0, font = verb_font, fgcolor = White })<\/pre>\n<p>Here&#8217;s the output of running that command:<\/p>\n<figure id=\"attachment_171\" aria-describedby=\"caption-attachment-171\" style=\"width: 640px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/HelloBlogReaders.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-171\" src=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/HelloBlogReaders.png\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/HelloBlogReaders.png 640w, https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/HelloBlogReaders-300x225.png 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-171\" class=\"wp-caption-text\">There&#8217;s the text!<\/figcaption><\/figure>\n<p>An interesting aspect to the positioning of the text is that it appears to be using a coordinate system with a basis in the center of the screen. Next, lets try exploring the extents of the text placement. Do negative values work? (Yes!) What is the highest and lowest X and Y value for placing text that still appears on the screen? (It appears that -1, -1 is the lower left corner and 1,1 is the upper right corner). Is this mechanism the only way text is added to the screen? (Nope, there&#8217;s also <i>SayLine<\/i>, <i>PrintLine<\/i> and other methods, so when debugging, the method used will be important).<\/p>\n<p>With this information in hand, I started by rebasing <a href=\"https:\/\/github.com\/Botje\/residualvm\/commit\/3f61dc793f8ebf81dcdc9b954d171c23030cf31e\" target=\"_blank\" rel=\"noopener\">Botje&#8217;s changes<\/a> (to allow the X and Y values to be passed as floats) against the current master. These changes, made the text appear more correct for scenes where the X and Y values are passed from the Lua, such as the directions to Pegnose Pete&#8217;s House, but this change didn&#8217;t effect most of the erroneous text placement.<\/p>\n<p>I then inspected the <i>SayLine<\/i> Lua\/C function and found that it sets a variable when X and Y aren&#8217;t passed in from the Lua script, which has the actor set the position relative to the actor&#8217;s bounding box. Simply using the other side of the bounding box for the Y position moves the actor&#8217;s speech to a much more correct location:<\/p>\n<figure id=\"attachment_172\" aria-describedby=\"caption-attachment-172\" style=\"width: 640px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/AfterBoxFix.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-172\" src=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/AfterBoxFix.png\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/AfterBoxFix.png 640w, https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/AfterBoxFix-300x225.png 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-172\" class=\"wp-caption-text\">After the bounding box side switch<\/figcaption><\/figure>\n<p>The next task I tackled was the incorrect word wrapping, as seen in the speech bubble, <i>&#8220;There&#8217;s an enemy pirate fighting over there.&#8221;<\/i>. Although the ResidualVM version actually looks a little bit better than the retail version here, there are other scenes where the word wrapping is worse, so let&#8217;s try to fix it!<\/p>\n<p>The word wrapping is done in the function <i>setupText<\/i>, which is found in the <i>textobject.cpp<\/i> file. Inside this function, the line width is computed by adding each character width in the line together. Strangely, this uses the maximum value between the character <i>width<\/i> and something called the <i>dataWidth<\/i>. Without a comment, it&#8217;s hard to tell what <i>dataWidth<\/i> actually means, so, I first started by identifying when this code was added to ResidualVM. This was a harder task than anticipated because the file was moved twice over the course of development. To trace its history, I first reset git to the first commit that moved the file and then, pushed the <i>HEAD<\/i> of the repository back one more commit. This restored the original version of the moved file and let me explore its history further. After one more file move, I found that <a href=\"https:\/\/github.com\/residualvm\/residualvm\/commit\/69e7550e1d89181aafed4f701dac770951eeae10\" target=\"_blank\" rel=\"noopener\">this was the commit<\/a> that added the <i>dataWidth<\/i> field. Unfortunately, there wasn&#8217;t much information in the commit message either, so I decided to try to test some strings in the retail version and measure what the width of the displayed text in pixels.<\/p>\n<p>So, it appears that the <i>dataWidth<\/i> is the actual width of the character, but the <i>width<\/i> includes adjustments to the spacing (or <a href=\"http:\/\/en.wikipedia.org\/wiki\/Kerning\" target=\"_blank\" rel=\"noopener\">kerning<\/a>) between the letters to make them look nice. As an example, let&#8217;s look at a simple string, <i>&#8220;Wa&#8221;<\/i>:<\/p>\n<pre>MakeTextObject(\"Wa\", { x = 0.0, y = 0.0, fgcolor = White))<\/pre>\n<p>Which results in:<\/p>\n<figure id=\"attachment_173\" aria-describedby=\"caption-attachment-173\" style=\"width: 215px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/Kerning.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-173\" src=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/Kerning.png\" alt=\"\" width=\"215\" height=\"206\" \/><\/a><figcaption id=\"caption-attachment-173\" class=\"wp-caption-text\">Demonstrating the font kerning<\/figcaption><\/figure>\n<p>As can be seen, the letter <i>&#8220;a&#8221;<\/i> actually overlaps with the letter W by two pixels. It appears that ResidualVM gets this right and does use the correct values for drawing the characters as this matches perfectly with the retail version. So, our issue is with determining when to word wrap, which depends on the width of the rendered text. Let&#8217;s examine the width variables to figure out what combination results in the correct width being calculated.<\/p>\n<p>For each font character, there&#8217;s the <i>dataWidth<\/i> and <i>width<\/i> sizes, which of these is the actual character width and which is the kerned width? Here&#8217;s the <i>dataWidth<\/i> and <i>width<\/i> values for <i>&#8220;W&#8221;<\/i> and <i>&#8220;a&#8221;<\/i>:<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"2\" align=\"center\">\n<tbody>\n<tr>\n<th>Value<\/th>\n<th>\u00a0\u00a0\u00a0\u00a0\u00a0 W<\/th>\n<\/tr>\n<tr>\n<td>width<\/td>\n<td>18<\/td>\n<\/tr>\n<tr>\n<td>dataWidth<\/td>\n<td>21<\/td>\n<\/tr>\n<tr>\n<th>Value<\/th>\n<th>a<\/th>\n<\/tr>\n<tr>\n<td>width<\/td>\n<td>7<\/td>\n<\/tr>\n<tr>\n<td>dataWidth<\/td>\n<td>9<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>So, it appears that the &#8220;width&#8221; value is the kerned value, while dataWidth is the actual size of the font bitmap image. Checking this against the image above shows that the <i>dataWidth<\/i> values match the pixel size of the letters exactly. So, if we add the <i>dataWidth<\/i> values together, our characters will be wider than what&#8217;s actually displayed to the screen. We can fix this by always using the width value instead of the maximum of the two as is done now.<\/p>\n<p>So, let&#8217;s take a look at the result difference after this change, when Guybrush is speaking the line &#8220;There&#8217;s an enemy pirate fighting over there.&#8221;:<\/p>\n<figure id=\"attachment_174\" aria-describedby=\"caption-attachment-174\" style=\"width: 640px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/AfterLineWidthFix.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-174\" src=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/AfterLineWidthFix.png\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/AfterLineWidthFix.png 640w, https:\/\/blogs.scummvm.org\/josejx\/wp-content\/uploads\/sites\/23\/2014\/07\/AfterLineWidthFix-300x225.png 300w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-174\" class=\"wp-caption-text\">Getting closer!<\/figcaption><\/figure>\n<p>We can see now that the lines are the same length now, and appear to be in the correct location on the X axis, but shifted in the Y axis. So, first, is there a common shift between all of these lines? Or in other words, are the lines shifted by a constant value? Unfortunately, it appears that this isn&#8217;t the case. The top line of Guybrush&#8217;s speech is 1 pixel too far to the right and 7 pixels too far towards the bottom of the screen, while the bottom line is offset by 1 pixel to the right and 13 pixels too far towards the bottom of the screen. The text <i>&#8220;Look at enemy pirate&#8221;<\/i> is also offset by 14 pixels too high towards the top of the screen.<\/p>\n<p>Let&#8217;s look into the difference in line spacing between the two lines for Guybrush&#8217;s speech. It turns out that in ResidualVM, the height of the font is modified when loaded if the character is taller than the specified font height. As before, this is intentional because of kerning. We do want some of the characters to sink lower or rise higher than the rest because it&#8217;s pleasing to the eye. Simply commenting the section of code that modifies the height results in the correct behavior, so I looked up why that work around was inserted in the first place, which led to <a href=\"https:\/\/github.com\/residualvm\/residualvm\/commit\/29badcec9ae4d1736586cd158ae67abb1969d73a\" target=\"_blank\" rel=\"noopener\">this commit<\/a>. So, it appears that there was a crash bug associated with the height. I suspect that the problem would be fixed if the renderer uses the <i>dataHeight<\/i> instead of the <i>height<\/i> to draw the text.<\/p>\n<p>As this blog post is getting long and I need to check with the other developers about this code, we&#8217;ll wrap it up here for now. I&#8217;ll continue in the next blog post with fixing the remaining font issues. All of the changes in this post can be found in <a href=\"https:\/\/github.com\/residualvm\/residualvm\/pull\/964\" target=\"_blank\" rel=\"noopener\">PR #964<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are a lot of differences with the positioning of textObjects between the retail version of EMI and ResdiualVM&#8217;s implementation. Let&#8217;s take the scene wed and compare the text positions. First, here&#8217;s the scene in the retail version: And here&#8217;s the same scene in ResidualVM: And finally, here&#8217;s the difference between the two: We can [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-166","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/posts\/166","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/comments?post=166"}],"version-history":[{"count":2,"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/posts\/166\/revisions"}],"predecessor-version":[{"id":175,"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/posts\/166\/revisions\/175"}],"wp:attachment":[{"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/media?parent=166"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/categories?post=166"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/josejx\/wp-json\/wp\/v2\/tags?post=166"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}