Week 3 ― Images!

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’s source code to compile under ScummVM and read their file contents through ScummVM’s OSystem. With that done, we have now opened up the doors for various developments to follow:

  • Displaying images
  • Receiving input
  • Running scripts
  • Playing audio

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:

Displaying Graphics

Displaying images within ScummVM is simple. We mostly rely on OSystem::copyRectToScreen. This method takes in as parameters the image source data (as a pointer of bytes), the image pitch, it’s size and position.

So the question is: how do we get an image source data? You can go about this in two ways:

  1. Fix each step of the event loop and one day you will (most likely) see something popping up.
  2. Search through the source code for functions relating to graphics and observing its parameters.

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.

While I was searching for a possible image source data candidate, my mentor gave me a very much appreciated hint to look for window decorations. An example being autoMapDecorations, defined in the following way:

WindowDecoration autoMapDecorations[numAutoMapPanels] = {
	{ WindowDecoration(autoMapPanelRects[0], autoMapTopPanelResID) },
	{ WindowDecoration(autoMapPanelRects[1], autoMapMidPanelResID) },
	{ WindowDecoration(autoMapPanelRects[2], autoMapBotPanelResID) }
};

Looking at the code related to this variable, I found the following in automap.cpp:

pAutoMap->setDecorations(autoMapDecorations,
                         elementsof(autoMapDecorations),
                         decRes, 'M', 'A', 'P');

We may now look at what setDecorations does:

void DecoratedWindow::setDecorations(
    WindowDecoration *dec,
    int16           count,
    hResContext     *con) {
	int16           i;

	decorations = dec;
	numDecorations = count;

	//  For each "decorative panel" within the frame of the window
	for (i = 0; i < numDecorations; i++, dec++) {

		// request an image pointer from the imageCache

		dec->image = ImageCache.requestImage(con,
		                                     MKTAG('B', 'R', 'D', dec->imageNumber));
	}
}

Anything catch your eye here?

dec->image = ImageCache.requestImage(con, MKTAG('B', 'R', 'D', dec->imageNumber));

Aha, looks like we found our candidate for a image pointer.

Checking what requestImage does, we can see that it (basically) reduces to this call:

image = LoadResource(con, resID, "CImageNode Allocation");

So our first lead is to try loading this data with LoadResource.

For testing purposes, I introduced the testOpenImage function within main.cpp (and called it through the saga2 initialization method):

void testOpenImage() {
	hResContext     *decRes;

	decRes = resFile->newContext(MKTAG('A', 'M', 'A', 'P'), "Automap Resources");

	WindowDecoration *dec = &autoMapDecorations[1];
	dec->image = LoadResource(decRes, MKTAG('M', 'A', 'P', 1), "MAP1");
	Point16 pos(0, 0);
	drawCompressedImage(mainPort, pos, dec->image);
}

We then blitted it to the screen through drawCompressedImage in the following way:

map.data = (uint8 *)malloc(map.bytes());
if (map.data == NULL) return;
unpackImage(&map, map.size.x, map.size.y, hdr->data);

Graphics::Surface sur;
sur.create(map.size.x, map.size.y, Graphics::PixelFormat::createFormatCLUT8());
sur.setPixels(map.data);
sur.debugPrint();
g_system->copyRectToScreen(sur.getPixels(), sur.pitch, 0, 0, sur.w, sur.h);

However, you may notice the unpackImage in the code above. Sometimes images come packed (compressed), and we have to unpack them in order to display them correctly. The unpackImage routine was originally implemented in assembly, but it was also thankfully written in C.1 Making use of that, we were able to finally see some progress:

You may be asking yourself about the big logo in the center. No, that’s not the image we’re trying to draw right now. It’s part of the loading screen that was implemented by my mentor. The thing on the top-left corner though? Now that’s progress.


And that’s the start of the journey, in my opinion. This time’s post was short, but to make up for that I’ll try to start posting more than once per week! (Who knows how that’s going to go…)

Next time I’ll continue talking about graphics. Particularly, drawing tiles.


1: In truth, before noticing that unpackImage had a implementation in C, we tried using SAGA’s version of that, not to much success.


Leave a Reply

Your email address will not be published.