{"id":21,"date":"2021-06-20T19:45:32","date_gmt":"2021-06-20T19:45:32","guid":{"rendered":"https:\/\/blogs.scummvm.org\/ayyg\/?p=21"},"modified":"2022-05-26T15:11:19","modified_gmt":"2022-05-26T06:11:19","slug":"week-3-%e2%80%95-images","status":"publish","type":"post","link":"https:\/\/blogs.scummvm.org\/ayyg\/2021\/06\/20\/week-3-%e2%80%95-images\/","title":{"rendered":"Week 3 \u2015 Images!"},"content":{"rendered":"\r\n<p>Hello. ayyg from Week 5 here about to talk about events from two (three?) weeks ago.<\/p>\r\n\r\n\r\n\r\n<p><em>Disclaimer: The following will be a summary of the events. I will not detail everything, but rather convey the gist of the whole process.<\/em><\/p>\r\n\r\n\r\n<hr class=\"wp-block-separator\" \/>\r\n\r\n\r\n<p>During the first two weeks we mostly focused on getting the FTA2&#8217;s source code to compile under ScummVM and read their file contents through ScummVM&#8217;s OSystem. With that done, we have now opened up the doors for various developments to follow:<\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li>Displaying images<\/li>\r\n<li>Receiving input<\/li>\r\n<li>Running scripts<\/li>\r\n<li>Playing audio<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<p>Among various other things. We will end up implementing all of them, as they are all necessary components of the final game, but our first milestone shall be this:<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Displaying Graphics<\/h2>\r\n\r\n\r\n\r\n<p>Displaying images within ScummVM is simple. We mostly rely on <code>OSystem::copyRectToScreen<\/code>. This method takes in as parameters the image source data (as a pointer of bytes), the image pitch, it&#8217;s size and position.<\/p>\r\n\r\n\r\n\r\n<p>So the question is: how do we get an image source data? You can go about this in two ways:<\/p>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\">\r\n<li>Fix each step of the event loop and one day you will (most likely) see something popping up.<\/li>\r\n<li>Search through the source code for functions relating to graphics and observing its parameters.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<p>Since we want to keep a tight eye on our progress, we want to make sure each system is working individually before proceeding on to tackle the event loop. Therefore, we chose the second option.<\/p>\r\n\r\n\r\n\r\n<p>While I was searching for a possible image source data candidate, my mentor gave me a very much appreciated hint to look for <em>window decorations<\/em>. An example being <code>autoMapDecorations<\/code>, defined in the following way:<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>WindowDecoration autoMapDecorations[numAutoMapPanels] = {\r\n\t{ WindowDecoration(autoMapPanelRects[0], autoMapTopPanelResID) },\r\n\t{ WindowDecoration(autoMapPanelRects[1], autoMapMidPanelResID) },\r\n\t{ WindowDecoration(autoMapPanelRects[2], autoMapBotPanelResID) }\r\n};<\/code><\/pre>\r\n\r\n\r\n\r\n<p>Looking at the code related to this variable, I found the following in <code>automap.cpp<\/code>:<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>pAutoMap-&gt;setDecorations(autoMapDecorations,\r\n                         elementsof(autoMapDecorations),\r\n                         decRes, 'M', 'A', 'P');\r\n<\/code><\/pre>\r\n\r\n\r\n\r\n<p>We may now look at what <code>setDecorations<\/code> does:<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>void DecoratedWindow::setDecorations(\r\n    WindowDecoration *dec,\r\n    int16           count,\r\n    hResContext     *con) {\r\n\tint16           i;\r\n\r\n\tdecorations = dec;\r\n\tnumDecorations = count;\r\n\r\n\t\/\/  For each \"decorative panel\" within the frame of the window\r\n\tfor (i = 0; i &lt; numDecorations; i++, dec++) {\r\n\r\n\t\t\/\/ request an image pointer from the imageCache\r\n\r\n\t\tdec-&gt;image = ImageCache.requestImage(con,\r\n\t\t                                     MKTAG('B', 'R', 'D', dec-&gt;imageNumber));\r\n\t}\r\n}\r\n<\/code><\/pre>\r\n\r\n\r\n\r\n<p>Anything catch your eye here?<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>dec-&gt;image = ImageCache.requestImage(con, MKTAG('B', 'R', 'D', dec-&gt;imageNumber));<\/code><\/pre>\r\n\r\n\r\n\r\n<p><em>Aha<\/em>, looks like we found our candidate for a image pointer.<\/p>\r\n\r\n\r\n\r\n<p>Checking what <code>requestImage<\/code> does, we can see that it (basically) reduces to this call:<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>image = LoadResource(con, resID, \"CImageNode Allocation\");<\/code><\/pre>\r\n\r\n\r\n\r\n<p>So our first lead is to try loading this data with LoadResource.<\/p>\r\n\r\n\r\n\r\n<p>For testing purposes, I introduced the <code>testOpenImage<\/code> function within main.cpp (and called it through the saga2 initialization method):<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>void testOpenImage() {\r\n\thResContext     *decRes;\r\n\r\n\tdecRes = resFile-&gt;newContext(MKTAG('A', 'M', 'A', 'P'), \"Automap Resources\");\r\n\r\n\tWindowDecoration *dec = &amp;autoMapDecorations[1];\r\n\tdec-&gt;image = LoadResource(decRes, MKTAG('M', 'A', 'P', 1), \"MAP1\");\r\n\tPoint16 pos(0, 0);\r\n\tdrawCompressedImage(mainPort, pos, dec-&gt;image);\r\n}<\/code><\/pre>\r\n\r\n\r\n\r\n<p>We then blitted it to the screen through drawCompressedImage in the following way:<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-code\"><code>map.data = (uint8 *)malloc(map.bytes());\r\nif (map.data == NULL) return;\r\nunpackImage(&amp;map, map.size.x, map.size.y, hdr-&gt;data);\r\n\r\nGraphics::Surface sur;\r\nsur.create(map.size.x, map.size.y, Graphics::PixelFormat::createFormatCLUT8());\r\nsur.setPixels(map.data);\r\nsur.debugPrint();\r\ng_system-&gt;copyRectToScreen(sur.getPixels(), sur.pitch, 0, 0, sur.w, sur.h);<\/code><\/pre>\r\n\r\n\r\n\r\n<p>However, you may notice the <code>unpackImage<\/code> in the code above. Sometimes images come packed (compressed), and we have to unpack them in order to display them correctly. The <code>unpackImage<\/code> routine was originally implemented in assembly, but it was also thankfully written in C.<sup>1<\/sup> Making use of that, we were able to finally see some progress:<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image\"><a href=\"https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/06\/unknown.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-103\" src=\"https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/06\/unknown.png\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/06\/unknown.png 640w, https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/06\/unknown-300x225.png 300w, https:\/\/blogs.scummvm.org\/ayyg\/wp-content\/uploads\/sites\/7\/2021\/06\/unknown-480x360.png 480w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><\/figure>\r\n\r\n\r\n\r\n<p>You may be asking yourself about the big logo in the center. No, that&#8217;s not the image we&#8217;re trying to draw right now. It&#8217;s part of the loading screen that was implemented by my mentor. The thing on the top-left corner though? Now that&#8217;s progress.<\/p>\r\n\r\n\r\n<hr class=\"wp-block-separator\" \/>\r\n\r\n\r\n<p>And that&#8217;s the start of the journey, in my opinion. This time&#8217;s post was short, but to make up for that I&#8217;ll try to start posting more than once per week! (<em>Who knows how that&#8217;s going to go&#8230;<\/em>)<\/p>\r\n\r\n\r\n\r\n<p>Next time I&#8217;ll continue talking about graphics. Particularly, drawing tiles.<\/p>\r\n\r\n\r\n<hr class=\"wp-block-separator\" \/>\r\n\r\n\r\n<p>1: In truth, before noticing that unpackImage had a implementation in C, we tried using SAGA&#8217;s version of that, not to much success.<\/p>\r\n","protected":false},"excerpt":{"rendered":"<p>Hello. ayyg from Week 5 here about to talk about events from two (three?) weeks ago. Disclaimer: The following will be a summary of the events. I will not detail everything, but rather convey the gist of the whole process. During the first two weeks we mostly focused on getting the FTA2&#8217;s source code to [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-21","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts\/21","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/comments?post=21"}],"version-history":[{"count":6,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts\/21\/revisions"}],"predecessor-version":[{"id":105,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/posts\/21\/revisions\/105"}],"wp:attachment":[{"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/media?parent=21"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/categories?post=21"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.scummvm.org\/ayyg\/wp-json\/wp\/v2\/tags?post=21"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}