{"id":79,"date":"2013-08-30T17:25:24","date_gmt":"2013-08-30T17:25:24","guid":{"rendered":"https:\/\/blogs.scummvm.org\/t0by\/?p=79"},"modified":"2022-05-24T17:26:58","modified_gmt":"2022-05-24T17:26:58","slug":"tiled-surfaces","status":"publish","type":"post","link":"https:\/\/blogs.scummvm.org\/t0by\/2013\/08\/30\/tiled-surfaces\/","title":{"rendered":"Tiled Surfaces"},"content":{"rendered":"<p>Okay, today\u2019s entry is about optimizing tiled surfaces by caching them.<br \/>\nHere\u2019s the deal \u2013 we have tiled surfaces, surfaces where a little square is repeated all over.<\/p>\n<p>It\u2019s great for backgrounds, as people who had a Geocities page in 1999 know (if you did not: <a href=\"http:\/\/wonder-tonic.com\/geocitiesizer\/index.php\" rel=\"nofollow\">http:\/\/wonder-tonic.com\/geocitiesizer\/index.php<\/a>)<\/p>\n<p>An example of a tiled image is the default system menu:<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-81\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1.jpg\" alt=\"\" width=\"413\" height=\"391\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1.jpg 413w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/1-300x284.jpg 300w\" sizes=\"auto, (max-width: 413px) 100vw, 413px\" \/><\/a>Another is dialogue balloons in Rosemary:<\/p>\n<p><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/21.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-82\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/21.jpg\" alt=\"\" width=\"543\" height=\"535\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/21.jpg 543w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/21-300x296.jpg 300w\" sizes=\"auto, (max-width: 543px) 100vw, 543px\" \/><\/a><a href=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/tiled-balloon1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-83\" src=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/tiled-balloon1.jpg\" alt=\"\" width=\"480\" height=\"323\" srcset=\"https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/tiled-balloon1.jpg 480w, https:\/\/blogs.scummvm.org\/t0by\/wp-content\/uploads\/sites\/43\/2013\/08\/tiled-balloon1-300x202.jpg 300w\" sizes=\"auto, (max-width: 480px) 100vw, 480px\" \/><\/a>They are heavy.<\/p>\n<p>Each tile is handled more or less as a stand alone surface at every redraw, which means: huge overhead.<\/p>\n<p>The fix is: cache them.<\/p>\n<p>This involves hacking the renderer a bit so that it draws to a \u201cdummy\u201d surface and changing the UITIledImage code accordingly:<\/p>\n<pre>bool BaseRenderOSystem::startSpriteBatch(bool swap, int width, int height) {\r\n    if (swap) {\r\n        _swapped = true;\r\n        _auxSurface = _renderSurface;\r\n        _renderSurface = new\r\n \r\n Graphics::Surface();\r\n        _renderSurface-&gt;create(width, height, _auxSurface-&gt;format);\r\n    }\r\n    _spriteBatch = true;\r\n    _batchNum = 1;\r\n    return STATUS_OK;\r\n}\r\n \r\nbool BaseRenderOSystem::endSpriteBatch(bool swap) {\r\n    if (_swapped) {\r\n        _swapped = false;\r\n        Graphics::Surface *temp;\r\n        temp = _renderSurface;\r\n        _renderSurface = _auxSurface;\r\n        _auxSurface = temp;\r\n    }\r\n    _spriteBatch = false;\r\n    _batchNum = 0;\r\n    return STATUS_OK;\r\n}\r\n \r\n\/\/ ....\r\n \r\nbool UITiledImage::display(int x, int y, int width, int height) {\r\n \r\n    int tileWidth = _middleMiddle.right - _middleMiddle.left;\r\n    int tileHeight = _middleMiddle.bottom - _middleMiddle.top;\r\n \r\n    int nuColumns = (width - (_middleLeft.right - _middleLeft.left) - (_middleRight.right - _middleRight.left)) \/ tileWidth;\r\n    int nuRows = (height - (_upMiddle.bottom - _upMiddle.top) - (_downMiddle.bottom - _downMiddle.top)) \/ tileHeight;\r\n \r\n    int col, row;\r\n \r\n    assert (width != 0);\r\n    assert (height != 0);\r\n \r\n    \/\/ Below is the new if block, which is executed only once:\r\n \r\n    if (_cache == nullptr || width != _width || height != _height) {\r\n \r\n        \/\/ This as a side effect enables the special \"dummy\" rendering mode\r\n        _gameRef-&gt;_renderer-&gt;startSpriteBatch(true, width, height);\r\n \r\n        int x = 0;\r\n        int y = 0;\r\n        _width = width;\r\n        _height = height;\r\n        \/\/ top left\/right\r\n        _image-&gt;_surface-&gt;displayTrans(x,                                                       y, _upLeft);\r\n        _image-&gt;_surface-&gt;displayTrans(x + (_upLeft.right - _upLeft.left) + nuColumns * tileWidth, y, _upRight);\r\n \r\n        \/\/ Etc, same for SW, NW, NE tiles\r\n \r\n        \/\/ tiles\r\n        if (nuRows &gt; 0 &amp;&amp; nuColumns &gt; 0) {\r\n            yyy = y + (_upMiddle.bottom - _upMiddle.top);\r\n            xxx = x + (_upLeft.right - _upLeft.left);\r\n            _image-&gt;_surface-&gt;displayTrans(xxx, yyy, _middleMiddle);\r\n            _image-&gt;_surface-&gt;repeatLastDisplayOp(tileWidth, tileWidth, nuColumns, nuRows);\r\n        }\r\n \r\n        _gameRef-&gt;_renderer-&gt;endSpriteBatch(false);\r\n \r\n        \/\/ This is where we retrieve the complete image\r\n        _cache = _gameRef-&gt;_renderer-&gt;getAuxSurface();\r\n    }\r\n \r\n    Rect32 dst;\r\n    dst.top = 0;\r\n    dst.left = 0;\r\n    dst.setWidth(width);\r\n    dst.setHeight(height);\r\n    _cache-&gt;displayTrans(x, y, dst);\r\n    return STATUS_OK;\r\n}\r\n<\/pre>\n<p>Then we store that surface and when we need to redraw the UITiledImage we simply use the cached version: single drawing call, less overhead.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Okay, today\u2019s entry is about optimizing tiled surfaces by caching them. Here\u2019s the deal \u2013 we have tiled surfaces, surfaces where a little square is repeated all over. It\u2019s great for backgrounds, as people who had a Geocities page in 1999 know (if you did not: http:\/\/wonder-tonic.com\/geocitiesizer\/index.php) An example of a tiled image is the [&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-79","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/posts\/79","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=79"}],"version-history":[{"count":3,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/posts\/79\/revisions"}],"predecessor-version":[{"id":85,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/posts\/79\/revisions\/85"}],"wp:attachment":[{"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/media?parent=79"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/categories?post=79"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/t0by\/wp-json\/wp\/v2\/tags?post=79"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}