{"id":62,"date":"2013-08-14T17:17:16","date_gmt":"2013-08-14T17:17:16","guid":{"rendered":"https:\/\/blogs.scummvm.org\/t0by\/?p=62"},"modified":"2022-05-24T17:23:04","modified_gmt":"2022-05-24T17:23:04","slug":"the-dreaded-rosemary-bug","status":"publish","type":"post","link":"https:\/\/blogs.scummvm.org\/t0by\/2013\/08\/14\/the-dreaded-rosemary-bug\/","title":{"rendered":"The Dreaded Rosemary Bug"},"content":{"rendered":"<p>The Rosemary Bug, as we call it, is the first bug I\u2019ve run into in ScummVM.<\/p>\n<p>That means \u2013 after 10 years I found a bug in an unsupported, unstable, unreleased (in builds) piece of code, which must mean something about the QA at ScummVM.<\/p>\n<p>It caused the main character to appear \u201cjigsawed\u201d when looking east AND you crossed her with the mouse pointer.<br \/>\nLike this:<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/broken1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-64\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/broken1.png\" alt=\"\" width=\"800\" height=\"615\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/broken1.png 800w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/broken1-300x231.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/broken1-768x590.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/p>\n<p>Not pretty, huh?<\/p>\n<p>This is due to the dirty rect system.<br \/>\nBasically, the idea is that normally you don\u2019t need to redraw ALL of the rectangle containing the sprite, but just the little square where the cursor was and is no more.<br \/>\nThis applies not only to the cursor, of course, but to ANY need that may arise to redraw part of a sprite that\u2019s been obscured by something smaller without redrawing the rest, which stays unchanged.<\/p>\n<p><strong>E.g. if your game had a lunar eclipse, when it\u2019s over you would need to redraw the moon, not the whole sky.<\/strong><\/p>\n<p>Now, there is a problem.<\/p>\n<p>Consider this example:<\/p>\n<p>1) Our background sprite, painted in our viewport:<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-65\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1.png\" alt=\"\" width=\"1722\" height=\"786\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1.png 1722w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1-300x137.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1-1024x467.png 1024w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1-768x351.png 768w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1-1536x701.png 1536w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1-1200x548.png 1200w\" sizes=\"auto, (max-width: 1722px) 100vw, 1722px\" \/><\/a>2) An eclipse! Another sprite (the black disc) is drawn on top of the first one.<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-66\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/2.png\" alt=\"\" width=\"1722\" height=\"786\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/2.png 1722w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/2-300x137.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/2-1024x467.png 1024w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/2-768x351.png 768w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/2-1536x701.png 1536w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/2-1200x548.png 1200w\" sizes=\"auto, (max-width: 1722px) 100vw, 1722px\" \/><\/a>3) For the eclipse to be over, we only need redraw the bit \u201cruined\u201d by the black disc; everything else is *already* on the viewport.<br \/>\nWe take the area that corresponds to the pink square from the original sprite and paint it over:<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/3.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-67\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/3.png\" alt=\"\" width=\"1722\" height=\"786\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/3.png 1722w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/3-300x137.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/3-1024x467.png 1024w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/3-768x351.png 768w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/3-1536x701.png 1536w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/3-1200x548.png 1200w\" sizes=\"auto, (max-width: 1722px) 100vw, 1722px\" \/><\/a>4) All is fine!<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/4.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-68\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/4.png\" alt=\"\" width=\"1722\" height=\"786\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/4.png 1722w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/4-300x137.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/4-1024x467.png 1024w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/4-768x351.png 768w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/4-1536x701.png 1536w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/4-1200x548.png 1200w\" sizes=\"auto, (max-width: 1722px) 100vw, 1722px\" \/><\/a>Everything is okay, but what if a sprite is mirrored \u2013 that is , it has a bit set that tells the engine \u201calways draw this flipped\u201d?<br \/>\nLook what happens if we don\u2019t take special measures:<\/p>\n<p>1) We draw the original texture FLIPPED.<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/5.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-69\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/5.png\" alt=\"\" width=\"1722\" height=\"786\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/5.png 1722w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/5-300x137.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/5-1024x467.png 1024w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/5-768x351.png 768w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/5-1536x701.png 1536w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/5-1200x548.png 1200w\" sizes=\"auto, (max-width: 1722px) 100vw, 1722px\" \/><\/a>2)<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/6.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-70\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/6.png\" alt=\"\" width=\"1722\" height=\"786\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/6.png 1722w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/6-300x137.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/6-1024x467.png 1024w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/6-768x351.png 768w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/6-1536x701.png 1536w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/6-1200x548.png 1200w\" sizes=\"auto, (max-width: 1722px) 100vw, 1722px\" \/><\/a>3) Now, as before, we take the area that corresponds to the pink square from the original texture (which we had drawn flipped before)<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/7.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-71\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/7.png\" alt=\"\" width=\"1722\" height=\"786\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/7.png 1722w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/7-300x137.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/7-1024x467.png 1024w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/7-768x351.png 768w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/7-1536x701.png 1536w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/7-1200x548.png 1200w\" sizes=\"auto, (max-width: 1722px) 100vw, 1722px\" \/><\/a>4)<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/8.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-72\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/8.png\" alt=\"\" width=\"1722\" height=\"786\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/8.png 1722w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/8-300x137.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/8-1024x467.png 1024w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/8-768x351.png 768w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/8-1536x701.png 1536w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/8-1200x548.png 1200w\" sizes=\"auto, (max-width: 1722px) 100vw, 1722px\" \/><\/a>Uh, oh.<\/p>\n<p>Mike Oldfield is not happy.<\/p>\n<p>We need to \u201cmirror\u201d the offsets too for dirty rects to work with mirrored sprites, of course.<\/p>\n<p>That\u2019s what was happening with Rosemary, in transparent_surface.cpp:<\/p>\n<pre>Common::Rect TransparentSurface::blit(Graphics::Surface &amp;target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height) {\r\n    int ca = (color &gt;&gt; 24) &amp; 0xff;\r\n \r\n    Common::Rect retSize;\r\n    retSize.top = 0;\r\n    retSize.left = 0;\r\n    retSize.setWidth(0);\r\n    retSize.setHeight(0);\r\n    \/\/ Check if we need to draw anything at all\r\n    if (ca == 0)\r\n        return retSize;\r\n \r\n    int cr = (color &gt;&gt; 16) &amp; 0xff;\r\n    int cg = (color &gt;&gt; 8) &amp; 0xff;\r\n    int cb = (color &gt;&gt; 0) &amp; 0xff;\r\n \r\n    \/\/ Compensate for transparency. Since we're coming\r\n    \/\/ down to 255 alpha, we just compensate for the colors here\r\n    if (ca != 255) {\r\n        cr = cr * ca &gt;&gt; 8;\r\n        cg = cg * ca &gt;&gt; 8;\r\n        cb = cb * ca &gt;&gt; 8;\r\n    }\r\n \r\n    \/\/ Create an encapsulating surface for the data\r\n    TransparentSurface srcImage(*this, false);\r\n    \/\/ TODO: Is the data really in the screen format?\r\n    if (format.bytesPerPixel != 4) {\r\n        warning(\"TransparentSurface can only blit 32 bpp images\");\r\n        return retSize;\r\n    }\r\n \r\n    if (pPartRect) {\r\n        srcImage.pixels = getBasePtr(pPartRect-&gt;left, pPartRect-&gt;top);\r\n        srcImage.w = pPartRect-&gt;width();\r\n        srcImage.h = pPartRect-&gt;height();\r\n    }\r\n \r\n    if (width == -1)\r\n        width = srcImage.w;\r\n    if (height == -1)\r\n        height = srcImage.h;\r\n \r\n    Graphics::Surface *img = nullptr;\r\n    Graphics::Surface *imgScaled = nullptr;\r\n    byte *savedPixels = nullptr;\r\n        \/*\r\n         * et cetera\r\n         * ...\r\n         *\/\r\n    }\r\n}\r\n<\/pre>\n<p>This is how it\u2019s been fixed:<\/p>\n<pre>if (pPartRect) {\r\n \r\n    int xOffset = pPartRect-&gt;left;\r\n    int yOffset = pPartRect-&gt;top;\r\n \r\n    if (flipping &amp; FLIP_V) {\r\n        yOffset = srcImage.h - pPartRect-&gt;bottom;\r\n    }\r\n \r\n    if (flipping &amp; FLIP_H) {\r\n        xOffset = srcImage.w - pPartRect-&gt;right;\r\n    }\r\n \r\n    srcImage.pixels = getBasePtr(xOffset, yOffset);\r\n    srcImage.w = pPartRect-&gt;width();\r\n    srcImage.h = pPartRect-&gt;height();\r\n}\r\n<\/pre>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/fixed.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-73\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/fixed.png\" alt=\"\" width=\"800\" height=\"615\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/fixed.png 800w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/fixed-300x231.png 300w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/fixed-768x590.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a>You can now move the cursor over Rosemary all you want \u2013 it\u2019s not gonna break ?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Rosemary Bug, as we call it, is the first bug I\u2019ve run into in ScummVM. That means \u2013 after 10 years I found a bug in an unsupported, unstable, unreleased (in builds) piece of code, which must mean something about the QA at ScummVM. It caused the main character to appear \u201cjigsawed\u201d when looking [&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-62","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/posts\/62","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/comments?post=62"}],"version-history":[{"count":2,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/posts\/62\/revisions"}],"predecessor-version":[{"id":74,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/posts\/62\/revisions\/74"}],"wp:attachment":[{"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/media?parent=62"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/categories?post=62"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/tags?post=62"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}